diff options
Diffstat (limited to 'ospf6d')
60 files changed, 22971 insertions, 0 deletions
diff --git a/ospf6d/.cvsignore b/ospf6d/.cvsignore new file mode 100644 index 000000000..cec4061cd --- /dev/null +++ b/ospf6d/.cvsignore @@ -0,0 +1,8 @@ +Makefile +*.o +*.patch +ospf6d +ospf6d.conf +tags +TAGS +.deps diff --git a/ospf6d/ChangeLog b/ospf6d/ChangeLog new file mode 100644 index 000000000..b7871c137 --- /dev/null +++ b/ospf6d/ChangeLog @@ -0,0 +1,809 @@ +2002-11-09 Vincent Jardin <jardin@6wind.com> + + * ospf6_interface.c: update link-local address on interface creation. + +2002-11-09 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_asbr.c: apply MinLSInterval to AS-External-LSA origination. + * ospf6_lsa.c: change not to issue flooding caused by expire event + when the received LSA is (already) MaxAge. + * ospf6_spf.c: fix a bug which is that ospf6d calculates + wrong nexthop when failed to find Link-LSA for the neighbor. + * ospf6_damp.c ospf6_dbex.c ospf6_neighbor.c ospf6_spf.c: + some clean up + * version: 0.9.6o + +2002-10-04 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_asbr.c: bug of failing ASE lsa refresh fixed. + * version: 0.9.6n + +2002-10-01 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_asbr.c: AS-External-LSA origination function + is re-written. + * ospf6_damp.[ch]: New feature that damps flaps is added. + * version: 0.9.6m + +2002-07-14 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_spf.c: unwanted assert() in ospf6_spf_nexthop_calculation() + is deleted. + * version: 0.9.6l + +2002-07-14 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_dbex.c: bug that ospf6d fails to refresh self-originated + LSA if he have not the LSA before has been fixed. + * ospf6_asbr.c: bug of failing removing ASE LSA when remove + message arrived from zebra has been fixed. + * version: 0.9.6k + +2002-07-13 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_zebra.c: bug reported [zebra 14642] fixed. + The bug was related to the synchronization between zebra + and ospf6d. Now synchronization will be correctly done. + * version: 0.9.6j + +2002-07-07 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_lsdb.c: bug fixed in ospf6_lsdb_type_router (). + * ospf6_dbex.c: because of retrans list structure changed + due to LSDB change, removal of old instance from retrans-list + is not necessary anymore. this caused crash but now fixed. + * version: 0.9.6i + +2002-07-07 Kunihiro Ishiguro <kunihiro@ipinfusion.com> + + * zebra-0.93 released. + +2002-07-07 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_lsdb.c: entirely rewritten. now ospf6d uses + radix tree by using lib/table.[ch] for LSDB lookup. + * ospf6_abr.c, ospf6_asbr.c, ospf6_intra.c: hook changed + due to rewriting of lsdb module. + * ospf6_neighbor.c: lack of check existence and find correct + instance of the LSA which is going to be removed from neighbor's + retransmission was filled. + * version: 0.9.6h + +2002-07-07 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_intra.c: bug fix for Intra-route deletion. + * ospf6_route.c: bug fix for path comparison. + * version: 0.9.6g + +2002-06-28 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_route.c: some logs trying to find the situation + when assert occur are added. route duration statistics + added. + * ospf6_zebra.c: trying to fix the problem reported by + [zebra 14318] but not yet sure. + * version: 0.9.6f + +2002-06-25 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_intra.c: new file for management of intra-prefix LSA. + * ospf6_abr.c: inter area route calculation code added. + * version: 0.9.6e + +2002-06-22 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_asbr.c: All AS-External route was removed when + one of the ASBR path was gone, but the route from other ASBR + path should stay remained. this bug is fixed. + * version: 0.9.6d + +2002-06-22 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_route.c: route table calculation bug fixed. [zebra 14105] + * ospf6_spf.c, ospf6_route.c, etc.: log message cleaned up. + * version: 0.9.6c + +2002-04-27 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_route.c: [zebra 13514] bug fix. + thanks to Harald Koch. + * version: 0.9.6b + +2002-04-22 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_dump.c: fix bug of log function + * ospf6_area.c: fix bug of intra route deletion + * version: 0.9.6a + +2002-04-20 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * merged with "current" version. + * version: 0.9.6 + +2001-03-11 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_lsdb.c ospf6_spf.c: log message changed for debug. + +2001-02-20 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * version: 0.9.5i + + * ospf6_asbr.c: Added code that finds alternative + AS-External route when remove AS-External route. + This is temporary fix ... + + * ospf6_redistribute.c: remove redistributed routes + immediately when 'no redistribute ...' + +2001-02-20 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * version: 0.9.5h + + * ospf6_spf.c, ospf6_lsa.c: Change to originate Link-LSA on + point-to-point links. + + * ospf6_message.c: Bug of log messages of self-originated + Hello packet fixed. + +2001-02-09 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * version: 0.9.5g + * ospf6_asbr.c: fix for the bug that AS-External route + is not get removed. + +2001-02-09 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_lsdb.c: crash bug while receiving wrong LSA scope bit + has been temporarily fixed + +2001-12-20 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_asbr.[ch]: The byte order bug in encoding/decoding + the bits/metric field in AS-External-LSA fixed. + Fixed to update E-bit in Router-LSA of itself. + Reported by Taisuke Sasaki ([zebra 11548]). + + * README: updated. + + * version: 0.9.5f + +2001-11-21 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_prefix.c: Intra-prefix-LSA bug fixed. + * ospf6_abr.[ch]: added (only just placeholder yet) + +2001-11-20 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_route.c: fix to overwrite a prefix when another + addition to the prefix is given. freeze function changed + not to remove routes by default. + + * version: 0.9.5e + +2001-11-19 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * version: 0.9.5d + + * ospf6_lsa.c ospf6_spf.c: SPF Calculations are now + scheduled by hook. + + * ospf6_route.c: ospf6_route_add bug fix, + ospf6_route_remove_all corrected. + +2001-11-15 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_hook.[ch]: added. + * Almost half of the code has been rewritten. + especially, ospf6_route.[ch]. Hook call has been injected + much. + * ospf6_asbr.[ch]: added. + +2001-10-17 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_dbex.c: ospf6d was wrong to omit reoriginating + of LSA when the self-originated LSA was received from others. + fixed. + * ospf6d.h: version: 0.9.5c + +2001-10-16 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_lsa.c: 'force-prefix' was not executed. fixed. + * ospf6d.h: version: 0.9.5b + +2001-10-13 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_interface.c: 'passive-interface' is now moved to + 'ipv6 ospf6 passive' in INTERFACE NODE. 'prefix-list' which + specifies the filter prefix for connected address prefix also + moved to INTERFACE NODE as 'ipv6 ospf6 advertise prefix-list WORD'. + The old obsoleted commands are still acceptable though. New command + 'ipv6 ospf6 advertise force-prefix' added, which which tells ospf6d + to advertise rather prefix than stub local-address even on loopback + or pointopoint interfaces. + + * ospf6_dump.c: 'ospf6 debug hello' -> 'ospf6 debug message hello'. + same for other message type. The older is still acceptable. + + * ospf6_lsa.c: Changed AS-External generation to new one which uses + LSA hooks. Delete old garbage. + +2001-10-02 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6d.c: turn off and turn on sequence with + 'no interface' 'interface' cmds was not work. fixed. + + * ospf6_lsa.c: generating Intra-Area-Prefix-LSA for stub + did not care duplicate prefixes. fixed. + +2001-09-07 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_message.c: There was a bug that prevent LSDB + to syncronize. It was a DbDesc packet bug that Slave + sends two different DbDesc packet on the same sequence + number. This cause many LSAs are dropped when Exchanging + LSDB, because the latter DbDesc packet that have the same + sequence number will be ignored as duplicate packet. + This seems to be exist at least before 0.9.4 version. + Now this is the most stable candidate. + + * ospf6d.h: version 0.9.5a + +2001-09-06 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_zebra.c ospf6_spf.c ospf6_lsa.c : + delete nexthop check to certify the nexthop is Link-local address. + Suppress Link-LSA origination on links other than Broadcast. + SPF's nexthop calculation first checks linklocal address + in Link-LSA, then checks source address of neighbor's packets. + + * ospf6_interface.c ospf6_ism.c ospf6_lsa.c ospf6_nsm.c: + intra-area-prefix-lsa origination func moved to new one. + + * ospf6_interface.h ospf6d.[ch] ospf6_lsa.c: + interface_area_cmd now changed to have 'passive' + and 'prefix-list' option. + + * ospf6_prefix.c: + clean up. + +2001-09-04 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_dbex.c ospf6_interface.c ospf6_ism.c ospf6_lsa.[ch]: + clean up and new LSA origination functions added. + + * ospf6_route.c ospf6_lsdb.c: make vty function more + clean/understandable. + + * ospf6d.h: version 0.9.5 + +2001-08-24 Kunihiro Ishiguro <kunihiro@ipinfusion.com> + + * ospf6_lsdb.c: Use IS_LSA_MAXAGE macro instead of + ospf6_lsa_is_maxage. + + * ospf6_lsa.h (IS_LSA_MAXAGE): Add new macro to check MaxAge. + +2001-08-21 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_lsdb.c: if There's no previous prefix + ospf6d was wrongly not calculate the prefix. + this reported by (v6 16029) is fixed. + + * ospf6_neighbor.c: Instance of LSA Summary included + in DbDesc packet was wrongly freed. The bug cause + malformed DbDesc, ExChange <-> ExStart flapping, + and then crash. + + * ospf6d.h: version 0.9.4 + +2001-08-21 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_route.[ch]: Showing format is changed. + 'show ipv6 route ospf6' -> 'show ipv6 ospf6 route' + 'show ipv6 route ospf6 external' -> + 'show ipv6 ospf6 route redistribute' + + * ospf6_lsdb.c ospf6_lsa.c ospf6_neighbor.c ospf6_interface.c: + memory leak in LS list fixed. + + * all: clean up + + * ospf6d.h: version 0.9.3 + +2001-08-20 Kunihiro Ishiguro <kunihiro@ipinfusion.com> + + * ospf6d.c (ospf6_timeval_sub_equal): Remove function. + + * ospf6_spf.c (ospf6_timeval_cmp): Rewrite ospf6_timeval_cmp(). + (ospf6_timeval_add_equal): Function moved from ospf6d.c + +2001-08-19 Kunihiro Ishiguro <kunihiro@ipinfusion.com> + + * zebra-0.92a released. + +2001-08-15 Kunihiro Ishiguro <kunihiro@ipinfusion.com> + + * zebra-0.92 released. + +2001-08-09 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_lsdb.c ospf6_neighbor.c: + LSDB function/structure and LS list function has been rewritten. + memory leak has been decreased. + + * ospf6_lsa.[ch] ospf6_dbex.c: garbage code has been deleted. + + * ospf6d.h: version 0.9.2 + +2001-08-07 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_dbex.c ospf6_lsdb.c: + Retransmition list had a critical bug that breaks LSDB + synchronization. When new LSA be added to retrans-list, + old must be removed, but it was not. So new LSA dropped, + and LSA Acknowledgement did not work. The bug was fixed. + + * ospf6d.h: version 0.9.1 + +2001-06-20 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_spf.c: crash bug fix in temporary treat code for + Router-LSA whose LS-ID != 0 + + * ospf6_dbex.c: RFC2328 13.(4) was wrongly coded. + (4) Else if the LSA's LS age is equal to MaxAge, and there is + currently *NO* instance of the LSA in the router's link state + ... + + * ospf6_lsa.c: RFC2328 13.1 checksum tie breaker + had been neglected, and has just added now. + + * ospf6d.h: version 0.9.0 + ospf6d expected to work with hitachi gr2000 from these fixes. + +2001-06-12 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_lsa.c: Fix bug in creating Intra-Area-Prefix-LSA. + DR was mis-include others prefixes advertised by their Link-LSA. + + * ospf6_route.c: Fix bug in calculating intra area routes. + Not all prefixes in Intra-Area-Prefix-LSA was calculated. + + * ospf6_spf.c: + Changed to quit when a error occured in calculating SPF tree. + Very messy hack for the bug reported by [zebra 8807]. This + is not tested yet. + Changed to quit SPF calculation when a nexthop calculation + errors. + + * ospf6_zebra.c: + Support for interface address deletion. + + * ospf6d.h: + version: 0.8.y + +2001-04-18 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6d.h + Due to previous change (DR Election algorithm changed), + backward compatibility will be lost from this version. + version: 0.8.x + +2001-04-18 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_message.c ospf6_ism.c: + Bug of router_id comparison + +2001-04-17 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_dbex.c: ospf6_dbex_is_maxage_to_be_dropped() had + some bug causing Loading state lasts long. + version: 0.8.v + +2001-04-08 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_route.c: BUG in AS-External route calculation fixed. + It was using OLD LSDB... + Version: 0.8.u- + +2001-04-08 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_area.c, ospf6_dbex.c, ospf6_interface.c, + ospf6_lsa.c, ospf6_lsdb.c, ospf6_lsdb.h, ospf6_message.c, + ospf6_neighbor.c, ospf6_neighbor.h, ospf6_nsm.c, + ospf6_redistribute.c, ospf6_route.c, ospf6_spf.c: + Delete old LSDB function. + + * ospf6d.h: + Version: 0.8.u + +2001-04-05 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_area.c, ospf6_area.h, ospf6_dbex.c, ospf6_interface.c, + ospf6_interface.h, ospf6_lsa.c, ospf6_lsdb.c, ospf6_lsdb.h, + ospf6_message.c, ospf6_nsm.c, ospf6_redistribute.c, ospf6_route.c, + ospf6_spf.c, ospf6_top.c, ospf6_top.h, ospf6d.h: + Changed to use New LSDB. + Version: 0.8.t + +2001-04-02 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_lsa.c: + Interface stub check in Intra-Area-Prefix-LSA origination + was wrong. - fixed. + + * ospf6_area.h, ospf6_dbex.c, ospf6_interface.c, + ospf6_interface.h, ospf6_lsa.c, ospf6_lsa.h, ospf6_lsdb.c, + ospf6_message.c, ospf6_neighbor.c, ospf6_nsm.c, + ospf6_redistribute.c, ospf6_top.c, ospf6_top.h, ospf6d.c: + New LSDB functions, but not changed to be used. + + * ospf6d.h: + Version: 0.8.s + +2001-03-28 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_area.c ospf6_area.h ospf6_dbex.c ospf6_dump.c + ospf6_interface.c ospf6_interface.h ospf6_lsa.c + ospf6_message.c ospf6_redistribute.c ospf6_spf.c ospf6_top.c + ospf6_top.h ospf6_zebra.c ospf6d.c ospf6d.h: cleaning. + +2001-03-24 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6d.h: + version: 0.8.r + + * ospf6_neighbor.[ch], ospf6_lsa.[ch]: + just clean up and log clearify. + + * ospf6_message.[ch]: + Packet receiving function and dumping OSPFv3 packet has been + changed simple and clean. + + * ospf6_dbex.[ch], ospf6_interface.[ch], ospf6_lsdb.[ch], + ospf6_neighbor.[ch], ospf6_nsm.[ch]: + LSList(i.e. summary list, request list, retrans list, etc) have + been rewritten based on new LSDB module. The main LSDB have not + yet shifted to this new module, but will shift eventually. + This change expected to resolve the problem that the ospf6d keeps + on sending redundant LSUpdate/LSAck. + + * ospf6_interface.c: changed default MTU from 1500 to 1280. + It was possible that the ospf6d could not send packet (e.g. + LSUpdate in response to LSReq in my case) when the packet + size accidentally reached near 1500 (I was forget about IP + header :p). It is a bit illegal to set MTU 1280 constantly, + but I failed once with I/F MTU from kernel (through zebra), + and thinks that 1280 is more stable than kernel variable. + Comments will be appriciated. + +2001-03-15 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_dbex.c, ospf6_interface.c, ospf6_ism.c, ospf6_lsdb.[ch], + ospf6_neighbor.c, ospf6_spf.c, ospf6d.c: + Fix for crash. ospf6d has ever been crashing when + 'no interface' command executed, and when starting up with + the configuration which does not include 'router ospf6'. + these has been fixed. + +2001-02-24 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_lsa.c, ospf6_message.c: + LSA summary (exchanged while Adjacency bring up) may expire + (may reach MaxAge). Handling this has been added but + it's a little bit quick hack. + + * ospf6_message.c: + Thread chain bug fixed. Read network thread chain has been cut + when receive packets on not-enabled interface. this was wrong + and fixed. + +2001-02-24 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_message.c: + I/F MTU check part on sending packet had some bug, and it's fixed. + Ospf6d has believed a value from zebra as I/F MTU, but from now + I/F MTU is set to constant 1500. This is workaround for ATM. + +2001-02-01 Kunihiro Ishiguro <kunihiro@zebra.org> + + * zebra-0.91 is released. + +2001-01-04 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * just code clean up of almost all module. + * ospf6_dump.c, ospf6_lsa.c: file dependency. + * ospf6_mesg.[ch]: changed filename to ospf6_message.[ch] + +2001-01-09 Kunihiro Ishiguro <kunihiro@zebra.org> + + * zebra-0.90 is released. + +2001-01-04 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_mesg.c,ospf6_lsa.c: doubly cancel thread bug fixed. + version 0.8.k CRASHed for this. + * ospf6_lsa.c: bug of logging fixed. + version: 0.8.l + +2001-01-04 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_neighbor.c: fix typo when trying to delete + MaxAge AS-External LSA. MaxAge LSA remaining bug is expected + to be fixed. + version: 0.8.k + +2001-01-04 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_mesg.c: add I/F Mtu check for sending LS Update. + + * ospf6_dbex.c, ospf6_mesg.c, ospf6_neighbor.c, ospf6_neighbor.h, + ospf6_spf.c: Changed type of hisaddr field in ospf6_neighbor + structure, from sockaddr_in6 to in6_addr. No protocol/processing + changed. + +2001-01-04 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_mesg.c, ospf6_neighbor.[ch]: Speed up of + Database Exchange. + version: 0.8.j + + Because the LS Request list was checked only when attempt + to send (retransmit) LS Request packet, Loading state lasted + long (for RxmtInterval) unexpectedly. This was fixed; LS Request + packet will be send as soon as one received a LS Update packet. + +2001-01-01 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ospf6d.h (OSPF6_VTYSH_PATH): Change "/tmp/ospf6d" to + /tmp/.ospf6d". + +2000-12-29 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_dump.[ch]: simplified. + +2000-12-19 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_route.c: Fix bug of using unavailable route. + version: 0.8.d + +2000-11-30 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_spf.c: calculate statistics. version: 0.8.d + +2000-11-26 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_mesg.c, ospf6_nsm.c: LSDB sync bug fixed. + version: 0.8.c + +2000-11-26 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_dbex.c: Start debugging and cleaning. + + * ospf6_area.c, ospf6_dbex.c, ospf6_interface.c, ospf6_lsa.c, + ospf6_proto.c, ospf6_top.c: add some function to clarify codes. + +2000-11-26 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_spf.c: Delete old garbage (which was enclosed by #if 0) + + * ospf6_redistribute.c: "redistribute ospf6" was generated in + "router ospf6" in config file. It is a bug, and fixed. + wrong warning message was deleted. + + * ospf6_main.c: If daemon mode, ospf6d was silent even if + the config file was wrong. It is a bug, and fixed. + + * ospf6_route.c, ospf6_zebra.c: Zebra syncronization method + has been changed. delete garbages. allow nexthop of :: in case + of connected route. + + * ospf6_dbex.c: Delete annoying log messages. + + * ospf6_lsa.c: Changed string for LSA log. + +2000-11-21 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_spf.c: some careless bug fixed. + + * ospf6_route.c: changed not to send garbage route + whose nexthop is not linklocal address. + +2000-11-09 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_rtable.c: renamed to ospf6_route.c + whole functionality has been rewritten as new code. + new functions not yet installs routes; the old + functions still remains. cleaning log messages. + + * ospf6_spf.c: whole functionality has been rewritten + as new code. new command "show ipv6 ospf6 spf node", + "show ipv6 ospf6 spf tree", "show ipv6 ospf6 spf table" + has been added. Memory leak was fixed. cleaning log messages. + + * ospf6d version: 0.7.c + +2000-10-02 Kunihiro Ishiguro <kunihiro@zebra.org> + + * zebra-0.89 is released. + +2000-09-10 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ospf6_lsdb.c (ospf6_lsdb_remove_maxage_lsa): Fix compile + warnings. + +2000-08-17 Kunihiro Ishiguro <kunihiro@zebra.org> + + * zebra-0.88 is released. + +2000-08-06 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ospf6_rtable.h (struct ospf6_nexthop): Change ifindex type from + unsigned long to unsigned int. + +2000-04-28 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ospf6d.h: Include some headers for avoid warning. + + * ospf6_routemap.h: Add newfile. + +1999-11-21 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ospf6_network.c: Respect IPV6_JOIN_GROUP and IPV6_LEAVE_GROUP + rather than RFC2133. + +1999-10-21 Jun-ichiro itojun Hagino <itojun@itojun.org> + + * ospf6_network.c (ospf6_ipv6_decode_ipv4): Fix bug of conversion + from IPv4 Mapped Address to IPv4 address. + +1999-08-08 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ospf6_lsa.c (construct_link_lsa): Enclose KAME specific part by + #ifdef/#endif. + +1999-07-29 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_mesg.c: add new message process function. + +1999-07-25 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ospf6_main.c (sighup): Call of log_rotate() removed. + +1999-07-24 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + ospf6_dbex.{c,h}: variable "acknowledge" has been deleted. + +1999-07-22 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * *.{c,h}: lsa data structure has been drastically + changed. + +1999-07-16 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * *.{c,h}: bug of updating LSA's which is self + originated has been fixed. + +1999-07-14 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * *.{c,h} : log clean up. + +1999-07-05 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ospf6d.c (ospf6_init): Change to use install_default. + +1999-07-03 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_rtable.c (nexthop_*): added some function that handles + new nexthop structure. + +1999-07-01 Rick Payne <rickp@rossfell.co.uk> + + * ospf6_zebra.c (ospf6_zebra_init): Install standard commands to + ZEBRA_NODE. + +1999-06-09 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_rtable.h: added for new routing table of ospf6d + +1999-05-14 Stephen R. van den Berg <srb@cuci.nl> + + * ospf6_main.c (signal_init): SIGTERM call sigint. + (sigint): Loggging more better message. + +1999-05-13 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + *ospf6_spf.c (get_prefix_lsa_of_vertex): bug fix about network vertex. + +1999-05-08 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ospf6_network.c (send_linkstate_ack): Check HAVE_SIN6_SCOPE_ID + is defined. + * ospf6_mesg.c (make_hello): Likewise. + * ospf6_lsa.c (lsa_flood): Likewise. + +1999-05-07 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_spf.c, etc: Many bug fix. + intra-area-prefix-LSA treatment changed. + network byte order of neighbor ifid changed. + +1999-05-07 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ospf6_zebra.h (struct zebra): Add hitory entry to structure. + +1999-05-05 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ospf6_main.c (main): Add KAME check for binding vty socket. + (main): Delete old interface get routine garbage. + + * ospf6d.c: Change all `show ip6' statement to `show ipv6'. + (show_ipv6_ospf6_requestlist): Add description. + +1999-05-04 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * ospf6_lsa.c, etc: Many bug fix, now two routers + on the same segment can become FULL neighbor state + each other. + +1999-05-03 Kunihiro Ishiguro <kunihiro@zebra.org> + + * Makefile.am: Add file dependency. + (depend): Add target. + +1999-05-02 Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + + * Clean up and fix have been almost done. This code + now testing stage of Intra area routing. + + * Configuration Vty become more similar to Cisco. + +1999-04-22 Kunihiro Ishiguro <kunihiro@zebra.org> + + * Trim training newline from zlog format arguemnt. + + * ospf6_dump.c (ospf6_err): Commented out ospf6_err and + ospf6_warn. Same kind of function should be implemented as + zlog_err or zlog_warn or someting. + + * ospf6d.c: Change OSPF_NODE to OSPF6_NODE. + Change OSPF_DEFAULT_CONFIG to OSPF6_DEFAULT_CONFIG. + + +1999-04-21 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ospf6_mesg.c (make_hello): Add check of SIN6_LEN + +1999-04-16 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ospf6_neighbor.c: Change list_clear_all to list_delete_all_node. + Remove list_delete_all fuction and use lib/linklist.c's one. + +1999-04-14 Kunihiro Ishiguro <kunihiro@zebra.org> + + * mcast_join(),mcast_leave()'s argument socket length is removed. + +1999-04-08 <kunihiro@zebra.org> + + * ospf6_zebra.h (ospf_zebra_read): Fix typo. + + * ospf6_interface.h: Tempolary add struct rt_addrinfo. + +1999-03-05 Kunihiro Ishiguro <kunihiro@zebra.org> + + * Merge from ospfd-zebra-990303 codes. + +1999-02-23 Kunihiro Ishiguro <kunihiro@zebra.org> + + * Makefile.in: add new file. + + * Makefile.am: @INCLUDES@ is added for OS/library specific IPv6 + directory search. + + * Import files from Yasuhiro Ohara <yasu@sfc.wide.ad.jp>'s ospfd. + Impterted files are: + Makefile.am, ospf_area.h, ospf_dump.c, ospf_interface.c, + ospf_interface.h, ospf_lsa.c, ospf_lsa.h, ospf_main.c, + ospf_mesg.c, ospf_mesg.h, ospf_neighbor.c, + ospf_neighbor.h,ospf_network.c, ospf_network.h, ospf_proto.h, + ospf_spf.c, ospf_spf.h, ospf_types.h, ospfd.c, ospfd.h diff --git a/ospf6d/Makefile.am b/ospf6d/Makefile.am new file mode 100644 index 000000000..e1b78cbc0 --- /dev/null +++ b/ospf6d/Makefile.am @@ -0,0 +1,48 @@ +## Process this file with automake to produce Makefile.in. + +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib +DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" +INSTALL_SDATA=@INSTALL@ -m 600 + +noinst_LIBRARIES = libospf6.a +sbin_PROGRAMS = ospf6d + +libospf6_a_SOURCES = \ + ospf6_dump.c ospf6d.c ospf6_interface.c ospf6_network.c \ + ospf6_neighbor.c ospf6_message.c ospf6_lsa.c ospf6_spf.c \ + ospf6_route.c ospf6_zebra.c ospf6_ism.c ospf6_dbex.c \ + ospf6_lsdb.c ospf6_prefix.c ospf6_top.c ospf6_area.c ospf6_nsm.c \ + ospf6_routemap.c ospf6_proto.c \ + ospf6_hook.c ospf6_asbr.c ospf6_bintree.c ospf6_linklist.c \ + ospf6_abr.c ospf6_intra.c ospf6_damp.c + +noinst_HEADERS = \ + ospf6_area.h ospf6_dump.h ospf6_interface.h ospf6_lsa.h \ + ospf6_message.h ospf6_neighbor.h ospf6_network.h ospf6_proto.h \ + ospf6_spf.h ospf6_route.h ospf6_types.h ospf6_zebra.h ospf6d.h \ + ospf6_ism.h ospf6_dbex.h ospf6_lsdb.h ospf6_prefix.h \ + ospf6_top.h ospf6_nsm.h ospf6_routemap.h \ + ospf6_hook.h ospf6_asbr.h ospf6_bintree.h ospf6_linklist.h \ + ospf6_abr.h ospf6_intra.h ospf6_damp.h + +ospf6d_SOURCES = \ + ospf6_main.c $(libospf6_a_SOURCES) + +ospf6d_LDADD = ../lib/libzebra.a + +sysconf_DATA = ospf6d.conf.sample + +EXTRA_DIST = $(sysconf_DATA) + +install-sysconfDATA: $(sysconf_DATA) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sysconfdir) + @list='$(sysconf_DATA)'; for p in $$list; do \ + if test -f $(srcdir)/$$p; then \ + echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \ + else if test -f $$p; then \ + echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \ + fi; fi; \ + done diff --git a/ospf6d/Makefile.in b/ospf6d/Makefile.in new file mode 100644 index 000000000..fed57d955 --- /dev/null +++ b/ospf6d/Makefile.in @@ -0,0 +1,549 @@ +# Makefile.in generated by automake 1.7 from Makefile.am. +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 +# Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. + +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_triplet = @host@ +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BGPD = @BGPD@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CURSES = @CURSES@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +IF_METHOD = @IF_METHOD@ +IF_PROC = @IF_PROC@ + +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IPFORWARD = @IPFORWARD@ +KERNEL_METHOD = @KERNEL_METHOD@ +LDFLAGS = @LDFLAGS@ +LIBPAM = @LIBPAM@ +LIBS = @LIBS@ +LIB_IPV6 = @LIB_IPV6@ +LIB_REGEX = @LIB_REGEX@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MULTIPATH_NUM = @MULTIPATH_NUM@ +OBJEXT = @OBJEXT@ +OSPF6D = @OSPF6D@ +OSPFD = @OSPFD@ +OTHER_METHOD = @OTHER_METHOD@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +RIPD = @RIPD@ +RIPNGD = @RIPNGD@ +RTREAD_METHOD = @RTREAD_METHOD@ +RT_METHOD = @RT_METHOD@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +VTYSH = @VTYSH@ +ZEBRA = @ZEBRA@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__include = @am__include@ +am__quote = @am__quote@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +INSTALL_SDATA = @INSTALL@ -m 600 + +noinst_LIBRARIES = libospf6.a +sbin_PROGRAMS = ospf6d + +libospf6_a_SOURCES = \ + ospf6_dump.c ospf6d.c ospf6_interface.c ospf6_network.c \ + ospf6_neighbor.c ospf6_message.c ospf6_lsa.c ospf6_spf.c \ + ospf6_route.c ospf6_zebra.c ospf6_ism.c ospf6_dbex.c \ + ospf6_lsdb.c ospf6_prefix.c ospf6_top.c ospf6_area.c ospf6_nsm.c \ + ospf6_routemap.c ospf6_proto.c \ + ospf6_hook.c ospf6_asbr.c ospf6_bintree.c ospf6_linklist.c \ + ospf6_abr.c ospf6_intra.c ospf6_damp.c + + +noinst_HEADERS = \ + ospf6_area.h ospf6_dump.h ospf6_interface.h ospf6_lsa.h \ + ospf6_message.h ospf6_neighbor.h ospf6_network.h ospf6_proto.h \ + ospf6_spf.h ospf6_route.h ospf6_types.h ospf6_zebra.h ospf6d.h \ + ospf6_ism.h ospf6_dbex.h ospf6_lsdb.h ospf6_prefix.h \ + ospf6_top.h ospf6_nsm.h ospf6_routemap.h \ + ospf6_hook.h ospf6_asbr.h ospf6_bintree.h ospf6_linklist.h \ + ospf6_abr.h ospf6_intra.h ospf6_damp.h + + +ospf6d_SOURCES = \ + ospf6_main.c $(libospf6_a_SOURCES) + + +ospf6d_LDADD = ../lib/libzebra.a + +sysconf_DATA = ospf6d.conf.sample + +EXTRA_DIST = $(sysconf_DATA) +subdir = ospf6d +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +LIBRARIES = $(noinst_LIBRARIES) + +libospf6_a_AR = $(AR) cru +libospf6_a_LIBADD = +am_libospf6_a_OBJECTS = ospf6_dump.$(OBJEXT) ospf6d.$(OBJEXT) \ + ospf6_interface.$(OBJEXT) ospf6_network.$(OBJEXT) \ + ospf6_neighbor.$(OBJEXT) ospf6_message.$(OBJEXT) \ + ospf6_lsa.$(OBJEXT) ospf6_spf.$(OBJEXT) ospf6_route.$(OBJEXT) \ + ospf6_zebra.$(OBJEXT) ospf6_ism.$(OBJEXT) ospf6_dbex.$(OBJEXT) \ + ospf6_lsdb.$(OBJEXT) ospf6_prefix.$(OBJEXT) ospf6_top.$(OBJEXT) \ + ospf6_area.$(OBJEXT) ospf6_nsm.$(OBJEXT) \ + ospf6_routemap.$(OBJEXT) ospf6_proto.$(OBJEXT) \ + ospf6_hook.$(OBJEXT) ospf6_asbr.$(OBJEXT) \ + ospf6_bintree.$(OBJEXT) ospf6_linklist.$(OBJEXT) \ + ospf6_abr.$(OBJEXT) ospf6_intra.$(OBJEXT) ospf6_damp.$(OBJEXT) +libospf6_a_OBJECTS = $(am_libospf6_a_OBJECTS) +sbin_PROGRAMS = ospf6d$(EXEEXT) +PROGRAMS = $(sbin_PROGRAMS) + +am__objects_1 = ospf6_dump.$(OBJEXT) ospf6d.$(OBJEXT) \ + ospf6_interface.$(OBJEXT) ospf6_network.$(OBJEXT) \ + ospf6_neighbor.$(OBJEXT) ospf6_message.$(OBJEXT) \ + ospf6_lsa.$(OBJEXT) ospf6_spf.$(OBJEXT) ospf6_route.$(OBJEXT) \ + ospf6_zebra.$(OBJEXT) ospf6_ism.$(OBJEXT) ospf6_dbex.$(OBJEXT) \ + ospf6_lsdb.$(OBJEXT) ospf6_prefix.$(OBJEXT) ospf6_top.$(OBJEXT) \ + ospf6_area.$(OBJEXT) ospf6_nsm.$(OBJEXT) \ + ospf6_routemap.$(OBJEXT) ospf6_proto.$(OBJEXT) \ + ospf6_hook.$(OBJEXT) ospf6_asbr.$(OBJEXT) \ + ospf6_bintree.$(OBJEXT) ospf6_linklist.$(OBJEXT) \ + ospf6_abr.$(OBJEXT) ospf6_intra.$(OBJEXT) ospf6_damp.$(OBJEXT) +am_ospf6d_OBJECTS = ospf6_main.$(OBJEXT) $(am__objects_1) +ospf6d_OBJECTS = $(am_ospf6d_OBJECTS) +ospf6d_DEPENDENCIES = ../lib/libzebra.a +ospf6d_LDFLAGS = + +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/ospf6_abr.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_area.Po ./$(DEPDIR)/ospf6_asbr.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_bintree.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_damp.Po ./$(DEPDIR)/ospf6_dbex.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_dump.Po ./$(DEPDIR)/ospf6_hook.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_interface.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_intra.Po ./$(DEPDIR)/ospf6_ism.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_linklist.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_lsa.Po ./$(DEPDIR)/ospf6_lsdb.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_main.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_message.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_neighbor.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_network.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_nsm.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_prefix.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_proto.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_route.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_routemap.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_spf.Po ./$(DEPDIR)/ospf6_top.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_zebra.Po ./$(DEPDIR)/ospf6d.Po +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DIST_SOURCES = $(libospf6_a_SOURCES) $(ospf6d_SOURCES) +DATA = $(sysconf_DATA) + +HEADERS = $(noinst_HEADERS) + +DIST_COMMON = README $(noinst_HEADERS) ChangeLog Makefile.am \ + Makefile.in +SOURCES = $(libospf6_a_SOURCES) $(ospf6d_SOURCES) + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign ospf6d/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libospf6.a: $(libospf6_a_OBJECTS) $(libospf6_a_DEPENDENCIES) + -rm -f libospf6.a + $(libospf6_a_AR) libospf6.a $(libospf6_a_OBJECTS) $(libospf6_a_LIBADD) + $(RANLIB) libospf6.a +sbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +install-sbinPROGRAMS: $(sbin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sbindir) + @list='$(sbin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f"; \ + $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f || exit 1; \ + else :; fi; \ + done + +uninstall-sbinPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(sbin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f $(DESTDIR)$(sbindir)/$$f"; \ + rm -f $(DESTDIR)$(sbindir)/$$f; \ + done + +clean-sbinPROGRAMS: + -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS) +ospf6d$(EXEEXT): $(ospf6d_OBJECTS) $(ospf6d_DEPENDENCIES) + @rm -f ospf6d$(EXEEXT) + $(LINK) $(ospf6d_LDFLAGS) $(ospf6d_OBJECTS) $(ospf6d_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) core *.core + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_abr.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_area.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_asbr.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_bintree.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_damp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_dbex.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_dump.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_hook.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_interface.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_intra.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_ism.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_linklist.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_lsa.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_lsdb.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_message.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_neighbor.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_network.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_nsm.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_prefix.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_proto.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_route.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_routemap.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_spf.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_top.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_zebra.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6d.Po@am__quote@ + +distclean-depend: + -rm -rf ./$(DEPDIR) + +.c.o: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCC_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ +@am__fastdepCC_TRUE@ then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCC_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$< + +.c.obj: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCC_TRUE@ -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'`; \ +@am__fastdepCC_TRUE@ then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCC_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'` +uninstall-info-am: +sysconfDATA_INSTALL = $(INSTALL_DATA) + +uninstall-sysconfDATA: + @$(NORMAL_UNINSTALL) + @list='$(sysconf_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f $(DESTDIR)$(sysconfdir)/$$f"; \ + rm -f $(DESTDIR)$(sysconfdir)/$$f; \ + done + +ETAGS = etags +ETAGSFLAGS = + +CTAGS = ctags +CTAGSFLAGS = + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = .. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkinstalldirs) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(PROGRAMS) $(DATA) $(HEADERS) + +installdirs: + $(mkinstalldirs) $(DESTDIR)$(sbindir) $(DESTDIR)$(sysconfdir) + +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES clean-sbinPROGRAMS \ + mostlyclean-am + +distclean: distclean-am + +distclean-am: clean-am distclean-compile distclean-depend \ + distclean-generic distclean-tags + +dvi: dvi-am + +dvi-am: + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: install-sbinPROGRAMS install-sysconfDATA + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am uninstall-sbinPROGRAMS \ + uninstall-sysconfDATA + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES clean-sbinPROGRAMS ctags distclean \ + distclean-compile distclean-depend distclean-generic \ + distclean-tags distdir dvi dvi-am info info-am install \ + install-am install-data install-data-am install-exec \ + install-exec-am install-info install-info-am install-man \ + install-sbinPROGRAMS install-strip install-sysconfDATA \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-info-am uninstall-sbinPROGRAMS \ + uninstall-sysconfDATA + + +install-sysconfDATA: $(sysconf_DATA) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sysconfdir) + @list='$(sysconf_DATA)'; for p in $$list; do \ + if test -f $(srcdir)/$$p; then \ + echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \ + else if test -f $$p; then \ + echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \ + fi; fi; \ + done +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/ospf6d/README b/ospf6d/README new file mode 100644 index 000000000..b3b4d16d0 --- /dev/null +++ b/ospf6d/README @@ -0,0 +1,85 @@ + + Zebra OSPF daemon for IPv6 network + + 2001/12/20 + +Zebra OSPF6d is OSPF version 3 daemon which is specified by +"OSPF for IPv6" (RFC 2740). + +*** NOTE *** + Zebra ospf6d is in development yet. It may lack some functionalities, + and may have some bugs. Use the latest version from the anoncvs + repository (http://www.zebra.org/cvs.html) ! + +This file README is like memo yet, so please feel free to ask +<yasu@sfc.wide.ad.jp> by E-mail. Patches will be appriciated. + +ospf6d's vty port was default to 2606/tcp. +Use commands below. + +VIEW NODE: + show ipv6 ospf6 + To see Router-ID, uptime of ospf6d, some statistics. + + show ipv6 ospf6 database ... + This command shows LSA database. You can specify + LS-type/LS-ID/Advertising-Router of LSAs. '*' is recognized. + + show ipv6 ospf6 interface ... + To see the status of the OSPF interface, and the configuration + like interface costs. + + show ipv6 ospf6 neighbor ... + Shows state of neighbors and choosed (Backup) DR on the I/F. + + show ipv6 ospf6 route (X::X) + This command shows internal routing table of the ospf6d. + Routes not calculated by OSPFv3 (like connected routes) + are not shown. If Address is specified (X::X), shows the route + that the address matches. + + show ipv6 ospf6 route redistribute (X::X) + Shows the routes advertised as AS-External routes by the router + itself. If Address is specified (X::X), shows the route + that the address matches. + +CONFIG NODE: + interface NAME + To enter INTERFACE NODE + + router ospf6 ... + To enter OSPF6 NODE + +INTERFACE NODE: + ipv6 ospf6 cost COST + Sets the interface's output cost. default 1 + + ipv6 ospf6 hello-interval HELLOINTERVAL + Sets the interface's Hello Interval. default 10 + + ipv6 ospf6 dead-interval DEADINTERVAL + Sets the interface's Router Dead Interval. default 40 + + ipv6 ospf6 retransmit-interval RETRANSMITINTERVAL + Sets the interface's Rxmt Interval. default 5 + + ipv6 ospf6 priority PRIORITY + Sets the interface's Router Priority. default 1 + + ipv6 ospf6 transmit-delay TRANSMITDELAY + Sets the interface's Inf-Trans-Delay. default 1 + +OSPF6 NODE: + router-id A.B.C.D + Sets the router's Router-ID + + interface NAME area AREA + Binds interface to specified Area, and start + sending OSPFv3 packets. + +Sample configuration is in ospf6d.conf.sample. + +-- +Yasuhiro Ohara <yasu@sfc.wide.ad.jp> +Kunihiro Ishiguro <kunihiro@zebra.org> + diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c new file mode 100644 index 000000000..864e0c23a --- /dev/null +++ b/ospf6d/ospf6_abr.c @@ -0,0 +1,655 @@ +/* + * Copyright (C) 2001 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "ospf6d.h" + +#include "ospf6_dump.h" +#include "ospf6_abr.h" + +static int abr_index; +#define IS_OSPF6_DUMP_ABR (ospf6_dump_is_on (abr_index)) + +#define ADD 0 +#define CHANGE 1 +#define REMOVE 2 + +/* Inter-Area-Prefix-LSA Calculation */ + +static struct ospf6_route_req * +ospf6_abr_entry_lookup (struct ospf6_route_req *abr_entry, + u_int32_t router_id, struct ospf6_area *area) +{ + struct prefix_ls abr_id; + char router_string[32]; + + inet_ntop (AF_INET, &router_id, router_string, sizeof (router_string)); + + //zlog_info ("ABR: Finding router %s in area %s", router_string, area->str); + + memset (&abr_id, 0, sizeof (abr_id)); + abr_id.family = AF_UNSPEC; + abr_id.prefixlen = 64; /* xxx */ + abr_id.id.s_addr = htonl (0); + abr_id.adv_router.s_addr = router_id; + + ospf6_route_lookup (abr_entry, (struct prefix *) &abr_id, + area->table_topology); + + if (ospf6_route_end (abr_entry)) + { + if (IS_OSPF6_DUMP_ABR) + zlog_info ("ABR: Router %s not found in area %s", + router_string, area->str); + return NULL; + } + + if (abr_entry->path.area_id != area->area_id) + { + if (IS_OSPF6_DUMP_ABR) + zlog_info ("ABR: ABR area id mismatch"); + return NULL; + } + + if (! CHECK_FLAG (abr_entry->path.router_bits, OSPF6_ROUTER_LSA_BIT_B)) + { + if (IS_OSPF6_DUMP_ABR) + zlog_info ("ABR: ABR entry's B bit off"); + return NULL; + } + + return abr_entry; +} + +static int +ospf6_abr_prefix_lsa_to_route (struct ospf6_lsa *lsa, + struct ospf6_route_req *request) +{ + struct ospf6_inter_area_prefix_lsa *iep; + struct ospf6_route_req abr_entry; + + if (lsa->header->type != htons (OSPF6_LSA_TYPE_INTER_PREFIX)) + { + if (IS_OSPF6_DUMP_ABR) + zlog_info ("ABR: LSA type mismatch"); + return -1; + } + + if (IS_LSA_MAXAGE (lsa)) + { + if (IS_OSPF6_DUMP_ABR) + zlog_info ("ABR: LSA MaxAge"); + return -1; + } + + if (! ospf6_abr_entry_lookup (&abr_entry, lsa->header->adv_router, + (struct ospf6_area *) lsa->scope)) + { + if (IS_OSPF6_DUMP_ABR) + zlog_info ("ABR: ABR check failed"); + return -1; + } + + iep = OSPF6_LSA_HEADER_END (lsa->header); + + memset (request, 0, sizeof (struct ospf6_route_req)); + request->route.type = OSPF6_DEST_TYPE_NETWORK; + request->route.prefix.family = AF_INET6; + request->route.prefix.prefixlen = iep->prefix.prefix_length; + ospf6_prefix_in6_addr (&iep->prefix, &request->route.prefix.u.prefix6); + + request->path.cost = abr_entry.path.cost + + (ntohl (iep->metric) & ntohl (0x000fffff)); + request->path.type = OSPF6_PATH_TYPE_INTER; + request->path.origin.type = lsa->header->type; + request->path.origin.id = lsa->header->id; + request->path.origin.adv_router = lsa->header->adv_router; + memcpy (&request->nexthop.address, &abr_entry.nexthop.address, + sizeof (request->nexthop.address)); + request->nexthop.ifindex = abr_entry.nexthop.ifindex; + + return 0; +} + +void +ospf6_abr_prefix_lsa_add (struct ospf6_lsa *lsa) +{ + struct ospf6_route_req request; + int ret; + + if (IS_OSPF6_DUMP_ABR) + zlog_info ("ABR: Calculate %s", lsa->str); + + ret = ospf6_abr_prefix_lsa_to_route (lsa, &request); + if (ret < 0) + return; + + if (IS_OSPF6_DUMP_ABR) + zlog_info ("ABR: Inter Area Route add for %s", lsa->str); + + ospf6_route_add (&request, ospf6->route_table); +} + +void +ospf6_abr_prefix_lsa_remove (struct ospf6_lsa *lsa) +{ + struct ospf6_inter_area_prefix_lsa *iep; + struct prefix_ipv6 prefix6; + struct ospf6_route_req request; + + iep = OSPF6_LSA_HEADER_END (lsa->header); + + prefix6.family = AF_INET6; + prefix6.prefixlen = iep->prefix.prefix_length; + ospf6_prefix_in6_addr (&iep->prefix, &prefix6.prefix); + + if (IS_OSPF6_DUMP_ABR) + zlog_info ("ABR: Inter Area Route remove for %s", lsa->str); + + for (ospf6_route_lookup (&request, (struct prefix *) &prefix6, + ospf6->route_table); + ! ospf6_route_end (&request); + ospf6_route_next (&request)) + { + if (memcmp (&prefix6, &request.route.prefix, sizeof (prefix6))) + break; + if (request.path.origin.type != htons (OSPF6_LSA_TYPE_INTER_PREFIX) || + request.path.origin.adv_router != lsa->header->adv_router || + request.path.origin.id != lsa->header->id) + continue; + + ospf6_route_remove (&request, ospf6->route_table); + } +} + +static int +ospf6_abr_router_lsa_to_route (struct ospf6_lsa *lsa, + struct ospf6_route_req *request) +{ + struct ospf6_inter_area_router_lsa *ier; + struct ospf6_route_req abr_entry; + + if (lsa->header->type != htons (OSPF6_LSA_TYPE_INTER_ROUTER)) + { + if (IS_OSPF6_DUMP_ABR) + zlog_info ("ABR: LSA type mismatch"); + return -1; + } + + if (IS_LSA_MAXAGE (lsa)) + { + if (IS_OSPF6_DUMP_ABR) + zlog_info ("ABR: LSA MaxAge"); + return -1; + } + + if (! ospf6_abr_entry_lookup (&abr_entry, lsa->header->adv_router, + (struct ospf6_area *) lsa->scope)) + { + if (IS_OSPF6_DUMP_ABR) + zlog_info ("ABR: Advertising router check failed"); + return -1; + } + + ier = OSPF6_LSA_HEADER_END (lsa->header); + + memset (request, 0, sizeof (struct ospf6_route_req)); + request->route.type = OSPF6_DEST_TYPE_ROUTER; + request->route.prefix.family = AF_UNSPEC; + request->route.prefix.prefixlen = 64; /* XXX */ + ((struct prefix_ls *) &request->route.prefix)->adv_router.s_addr + = ier->router_id; + + request->path.cost = abr_entry.path.cost + + (ntohl (ier->metric & htonl (0x000fffff))); + request->path.type = OSPF6_PATH_TYPE_INTER; + request->path.origin.type = lsa->header->type; + request->path.origin.id = lsa->header->id; + request->path.origin.adv_router = lsa->header->adv_router; + SET_FLAG (request->path.router_bits, OSPF6_ROUTER_LSA_BIT_E); + request->path.capability[0] = ier->options[0]; + request->path.capability[1] = ier->options[1]; + request->path.capability[2] = ier->options[2]; + + memcpy (&request->nexthop.address, &abr_entry.nexthop.address, + sizeof (request->nexthop.address)); + request->nexthop.ifindex = abr_entry.nexthop.ifindex; + + return 0; +} + +void +ospf6_abr_router_lsa_add (struct ospf6_lsa *lsa) +{ + struct ospf6_route_req request; + int ret; + + if (IS_OSPF6_DUMP_ABR) + zlog_info ("ABR: Calculate %s", lsa->str); + + ret = ospf6_abr_router_lsa_to_route (lsa, &request); + if (ret < 0) + return; + + if (IS_OSPF6_DUMP_ABR) + zlog_info ("ABR: Inter Area Router add for %s", lsa->str); + + ospf6_route_add (&request, ospf6->topology_table); +} + +void +ospf6_abr_router_lsa_remove (struct ospf6_lsa *lsa) +{ + struct ospf6_inter_area_router_lsa *ier; + struct prefix_ls prefix_ls; + struct ospf6_route_req request; + + ier = OSPF6_LSA_HEADER_END (lsa->header); + + memset (&prefix_ls, 0, sizeof (prefix_ls)); + prefix_ls.family = AF_INET6; + prefix_ls.prefixlen = 64; /* XXX */ + prefix_ls.adv_router.s_addr = ier->router_id; + + if (IS_OSPF6_DUMP_ABR) + zlog_info ("ABR: Inter Area Route remove for %s", lsa->str); + + for (ospf6_route_lookup (&request, (struct prefix *) &prefix_ls, + ospf6->route_table); + ! ospf6_route_end (&request); + ospf6_route_next (&request)) + { + if (memcmp (&prefix_ls, &request.route.prefix, sizeof (prefix_ls))) + break; + if (request.path.origin.type != htons (OSPF6_LSA_TYPE_INTER_ROUTER) || + request.path.origin.adv_router != lsa->header->adv_router || + request.path.origin.id != lsa->header->id) + continue; + + ospf6_route_remove (&request, ospf6->route_table); + } +} + + +void +ospf6_abr_abr_entry_add (struct ospf6_route_req *abr_entry) +{ + struct ospf6_lsdb_node node; + struct prefix_ls *abr_id; + struct ospf6_route_req request; + struct ospf6_area *area; + + if (IS_OSPF6_DUMP_ABR) + zlog_info ("ABR: New Area Border Router found"); + + area = ospf6_area_lookup (abr_entry->path.area_id, ospf6); + if (! area) + { + if (IS_OSPF6_DUMP_ABR) + zlog_info ("ABR: Can't find associated area"); + return; + } + + abr_id = (struct prefix_ls *) &abr_entry->route.prefix; + if (! ospf6_abr_entry_lookup (&request, abr_id->adv_router.s_addr, area)) + { + if (IS_OSPF6_DUMP_ABR) + zlog_info ("ABR: back check failed"); + return; + } + + /* for each inter-prefix LSA this ABR originated */ + for (ospf6_lsdb_type_router (&node, htons (OSPF6_LSA_TYPE_INTER_PREFIX), + abr_id->adv_router.s_addr, area->lsdb); + ! ospf6_lsdb_is_end (&node); + ospf6_lsdb_next (&node)) + ospf6_abr_prefix_lsa_add (node.lsa); + + /* for each inter-router LSA this ABR originated */ + for (ospf6_lsdb_type_router (&node, htons (OSPF6_LSA_TYPE_INTER_ROUTER), + abr_id->adv_router.s_addr, area->lsdb); + ! ospf6_lsdb_is_end (&node); + ospf6_lsdb_next (&node)) + ospf6_abr_router_lsa_add (node.lsa); +} + +void +ospf6_abr_abr_entry_remove (struct ospf6_route_req *abr_entry) +{ + struct ospf6_lsdb_node node; + struct prefix_ls *abr_id; + struct ospf6_area *area; + + if (IS_OSPF6_DUMP_ABR) + zlog_info ("ABR: Area Border Router removed"); + + abr_id = (struct prefix_ls *) &abr_entry->route.prefix; + + area = ospf6_area_lookup (abr_entry->path.area_id, ospf6); + if (! area) + { + if (IS_OSPF6_DUMP_ABR) + zlog_info ("ABR: Can't find associated area"); + return; + } + + /* for each inter-prefix LSA this ABR originated */ + for (ospf6_lsdb_type_router (&node, htons (OSPF6_LSA_TYPE_INTER_PREFIX), + abr_id->adv_router.s_addr, area->lsdb); + ! ospf6_lsdb_is_end (&node); + ospf6_lsdb_next (&node)) + ospf6_abr_prefix_lsa_remove (node.lsa); + + /* for each inter-router LSA this ABR originated */ + for (ospf6_lsdb_type_router (&node, htons (OSPF6_LSA_TYPE_INTER_ROUTER), + abr_id->adv_router.s_addr, area->lsdb); + ! ospf6_lsdb_is_end (&node); + ospf6_lsdb_next (&node)) + ospf6_abr_router_lsa_remove (node.lsa); +} + +/* Inter-Area-Prefix-LSA Origination */ + +static void +ospf6_abr_prefix_lsa_update_add (struct ospf6_route_req *request, + struct ospf6_area *area) +{ + char buffer [MAXLSASIZE]; + u_int16_t size; + struct ospf6_inter_area_prefix_lsa *iep; + char *p; + + if (IS_OSPF6_DUMP_ABR) + zlog_info ("Update Inter-Prefix for %s: ID: %lu", + area->str, (u_long) ntohl (request->route_id)); + + /* prepare buffer */ + memset (buffer, 0, sizeof (buffer)); + size = sizeof (struct ospf6_inter_area_prefix_lsa); + iep = (struct ospf6_inter_area_prefix_lsa *) buffer; + p = (char *) (iep + 1); + + /* prefixlen */ + iep->prefix.prefix_length = request->route.prefix.prefixlen; + + /* PrefixOptions */ + iep->prefix.prefix_options = request->path.prefix_options; + + /* set Prefix */ + memcpy (p, &request->route.prefix.u.prefix6, + OSPF6_PREFIX_SPACE (request->route.prefix.prefixlen)); + ospf6_prefix_apply_mask (&iep->prefix); + size += OSPF6_PREFIX_SPACE (request->route.prefix.prefixlen); + + ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_INTER_PREFIX), + htonl (request->route_id), ospf6->router_id, + (char *) iep, size, area); +} + +static void +ospf6_abr_prefix_lsa_update_remove (struct ospf6_route_req *request, + struct ospf6_area *area) +{ + struct ospf6_lsa *lsa; + lsa = ospf6_lsdb_lookup_lsdb (htons (OSPF6_LSA_TYPE_INTER_PREFIX), + htonl (request->route_id), + ospf6->router_id, area->lsdb); + if (lsa) + ospf6_lsa_premature_aging (lsa); +} + +static void +ospf6_abr_prefix_lsa_update (int type, struct ospf6_route_req *request) +{ + struct ospf6_route_req route, target; + listnode node; + struct ospf6_area *area; + struct ospf6_interface *o6i; + + if (request->route.type != OSPF6_DEST_TYPE_NETWORK) + return; + + /* assert this is best path; if not, return */ + ospf6_route_lookup (&route, &request->route.prefix, request->table); + if (memcmp (&route.path, &request->path, sizeof (route.path))) + return; + + if (target.path.cost >= LS_INFINITY || + target.path.cost_e2 >= LS_INFINITY) + { + if (IS_OSPF6_DUMP_ABR) + zlog_info ("ABR: Exceeds LS Infinity, ignore"); + return; + } + + ospf6_route_lookup (&target, &request->route.prefix, request->table); + if (type == REMOVE) + { + ospf6_route_next (&route); + if (! memcmp (&route.route, &request->route, sizeof (route.route))) + { + type = ADD; + ospf6_route_next (&target); + } + } + + for (node = listhead (ospf6->area_list); node; nextnode (node)) + { + area = getdata (node); + + if (target.path.area_id == area->area_id) + continue; + + o6i = ospf6_interface_lookup_by_index (target.nexthop.ifindex); + if (o6i && o6i->area && o6i->area->area_id == area->area_id) + { + zlog_info ("ABR: Logical equivalent of split horizon, skip for %s", + area->str); + continue; + } + + if (area->area_id == ntohs (0) && /* Backbone */ + target.path.type != OSPF6_PATH_TYPE_INTRA) + continue; + + /* XXX, stub area check */ + + /* XXX, aggregate */ + /* if either the area of the route or the area trying to + advertise is backbone, do not aggregate */ + + if (type == ADD) + ospf6_abr_prefix_lsa_update_add (&target, area); + else + ospf6_abr_prefix_lsa_update_remove (&target, area); + } +} + +void +ospf6_abr_route_add (struct ospf6_route_req *request) +{ + ospf6_abr_prefix_lsa_update (ADD, request); +} + +void +ospf6_abr_route_remove (struct ospf6_route_req *request) +{ + ospf6_abr_prefix_lsa_update (REMOVE, request); +} + +int +ospf6_abr_prefix_lsa_refresh (void *data) +{ + struct ospf6_lsa *lsa = data; + struct ospf6_inter_area_prefix_lsa *ier; + struct prefix_ipv6 prefix6; + struct ospf6_route_req route; + + ier = OSPF6_LSA_HEADER_END (lsa->header); + memset (&prefix6, 0, sizeof (prefix6)); + prefix6.family = AF_INET6; + prefix6.prefixlen = ier->prefix.prefix_length; + ospf6_prefix_in6_addr (&ier->prefix, &prefix6.prefix); + + ospf6_route_lookup (&route, (struct prefix *) &prefix6, + ospf6->route_table); + assert (! ospf6_route_end (&route)); + + ospf6_abr_prefix_lsa_update (ADD, &route); + return 0; +} + +int +ospf6_abr_prefix_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) +{ + struct ospf6_inter_area_prefix_lsa *ier; + char prefix[128]; + + assert (lsa->header); + ier = OSPF6_LSA_HEADER_END (lsa->header); + + ospf6_prefix_string (&ier->prefix, prefix, sizeof (prefix)); + + vty_out (vty, " Metric: %d%s", + ntohl (ier->metric & htonl (0x000fffff)), VTY_NEWLINE); + vty_out (vty, " Prefix: %s%s", prefix, VTY_NEWLINE); + + return 0; +} + +int +ospf6_abr_prefix_lsa_hook_add (void *data) +{ + struct ospf6_lsa *lsa = data; + ospf6_abr_prefix_lsa_add (lsa); + return 0; +} + +int +ospf6_abr_prefix_lsa_hook_remove (void *data) +{ + struct ospf6_lsa *lsa = data; + ospf6_abr_prefix_lsa_remove (lsa); + return 0; +} + +void +ospf6_abr_database_hook_inter_prefix (struct ospf6_lsa *old, + struct ospf6_lsa *new) +{ + if (old) + ospf6_abr_prefix_lsa_hook_remove (old); + if (new && ! IS_LSA_MAXAGE (new)) + ospf6_abr_prefix_lsa_hook_add (new); +} + +void +ospf6_abr_register_inter_prefix () +{ + struct ospf6_lsa_slot slot; + + memset (&slot, 0, sizeof (slot)); + slot.type = htons (OSPF6_LSA_TYPE_INTER_PREFIX); + slot.name = "Inter-Prefix"; + slot.func_show = ospf6_abr_prefix_lsa_show; + slot.func_refresh = ospf6_abr_prefix_lsa_refresh; + ospf6_lsa_slot_register (&slot); + + ospf6_lsdb_hook[OSPF6_LSA_TYPE_INTER_PREFIX & OSPF6_LSTYPE_CODE_MASK].hook = + ospf6_abr_database_hook_inter_prefix; +} + +int +ospf6_abr_router_lsa_hook_add (void *data) +{ + struct ospf6_lsa *lsa = data; + ospf6_abr_router_lsa_add (lsa); + return 0; +} + +int +ospf6_abr_router_lsa_hook_remove (void *data) +{ + struct ospf6_lsa *lsa = data; + ospf6_abr_router_lsa_remove (lsa); + return 0; +} + +int +ospf6_abr_router_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) +{ + return 0; +} + +int +ospf6_abr_router_lsa_refresh (void *data) +{ + return 0; +} + +void +ospf6_abr_database_hook_inter_router (struct ospf6_lsa *old, + struct ospf6_lsa *new) +{ + if (old) + ospf6_abr_router_lsa_hook_remove (old); + if (new && ! IS_LSA_MAXAGE (new)) + ospf6_abr_router_lsa_hook_add (new); +} + +void +ospf6_abr_register_inter_router () +{ + struct ospf6_lsa_slot slot; + + memset (&slot, 0, sizeof (slot)); + slot.type = htons (OSPF6_LSA_TYPE_INTER_ROUTER); + slot.name = "Inter-Router"; + slot.func_show = ospf6_abr_router_lsa_show; + slot.func_refresh = ospf6_abr_router_lsa_refresh; + ospf6_lsa_slot_register (&slot); + + ospf6_lsdb_hook[OSPF6_LSA_TYPE_INTER_ROUTER & OSPF6_LSTYPE_CODE_MASK].hook = + ospf6_abr_database_hook_inter_router; +} + +void +ospf6_abr_inter_route_calculation (struct ospf6_area *area) +{ + struct ospf6_lsdb_node node; + + /* for each inter-prefix LSA */ + for (ospf6_lsdb_type (&node, htons (OSPF6_LSA_TYPE_INTER_PREFIX), + area->lsdb); + ! ospf6_lsdb_is_end (&node); + ospf6_lsdb_next (&node)) + ospf6_abr_prefix_lsa_add (node.lsa); +} + +void +ospf6_abr_init () +{ + abr_index = ospf6_dump_install ("abr", "Area Border Router Function\n"); + + ospf6_abr_register_inter_prefix (); + ospf6_abr_register_inter_router (); +} + + diff --git a/ospf6d/ospf6_abr.h b/ospf6d/ospf6_abr.h new file mode 100644 index 000000000..510532e85 --- /dev/null +++ b/ospf6d/ospf6_abr.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2001 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF6_ABR_H +#define OSPF6_ABR_H + +/* Inter-Area-Prefix-LSA */ +struct ospf6_inter_area_prefix_lsa +{ + u_int32_t metric; /* 12bits reserved, 20bits metric */ + struct ospf6_prefix prefix; /* followed by one address prefix */ +}; + +/* Inter-Area-Router-LSA */ +struct ospf6_inter_area_router_lsa +{ + u_char reserved; + u_char options[3]; /* Optional Capability */ + u_int32_t metric; /* 12bits reserved, 20bits metric */ + u_int32_t router_id; /* Destination Router ID */ +}; + +void ospf6_abr_prefix_lsa_add (struct ospf6_lsa *); +void ospf6_abr_prefix_lsa_remove (struct ospf6_lsa *); +void ospf6_abr_prefix_lsa_change (struct ospf6_lsa *, struct ospf6_lsa *); + +void ospf6_abr_abr_entry_add (struct ospf6_route_req *); +void ospf6_abr_abr_entry_remove (struct ospf6_route_req *); + +void ospf6_abr_route_add (struct ospf6_route_req *); +void ospf6_abr_route_remove (struct ospf6_route_req *); + +void ospf6_abr_inter_route_calculation (struct ospf6_area *); + +void ospf6_abr_init (); + +#endif /* OSPF6_ABR_H */ + diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c new file mode 100644 index 000000000..51af5080d --- /dev/null +++ b/ospf6d/ospf6_area.c @@ -0,0 +1,332 @@ +/* + * OSPF6 Area Data Structure + * Copyright (C) 1999-2002 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "ospf6d.h" + +static int area_index; +#define IS_OSPF6_DUMP_AREA (ospf6_dump_is_on (area_index)) + +static void +ospf6_area_foreach_interface (struct ospf6_area *o6a, void *arg, int val, + void (*func) (void *, int, void *)) +{ + listnode node; + struct ospf6_interface *o6i; + + for (node = listhead (o6a->if_list); node; nextnode (node)) + { + o6i = (struct ospf6_interface *) getdata (node); + (*func) (arg, val, o6i); + } +} + +static void +ospf6_area_foreach_neighbor (struct ospf6_area *o6a, void *arg, int val, + void (*func) (void *, int, void *)) +{ + listnode node; + struct ospf6_interface *o6i; + + for (node = listhead (o6a->if_list); node; nextnode (node)) + { + o6i = (struct ospf6_interface *) getdata (node); + (*o6i->foreach_nei) (o6i, arg, val, func); + } +} + +static int +ospf6_area_maxage_remover (struct thread *t) +{ + int count; + struct ospf6_area *o6a = (struct ospf6_area *) THREAD_ARG (t); + + o6a->maxage_remover = (struct thread *) NULL; + + count = 0; + o6a->foreach_nei (o6a, &count, NBS_EXCHANGE, ospf6_count_state); + o6a->foreach_nei (o6a, &count, NBS_LOADING, ospf6_count_state); + if (count != 0) + return 0; + + ospf6_lsdb_remove_maxage (o6a->lsdb); + return 0; +} + +void +ospf6_area_schedule_maxage_remover (void *arg, int val, void *obj) +{ + struct ospf6_area *o6a = (struct ospf6_area *) obj; + + if (o6a->maxage_remover != NULL) + return; + + o6a->maxage_remover = + thread_add_event (master, ospf6_area_maxage_remover, o6a, 0); +} + +int +ospf6_area_is_stub (struct ospf6_area *o6a) +{ + if (OSPF6_OPT_ISSET (o6a->options, OSPF6_OPT_E)) + return 0; + return 1; +} + +int +ospf6_area_is_transit (struct ospf6_area *o6a) +{ + return 0; +} + + + +void +ospf6_area_route_add (void *data) +{ + struct ospf6_route_req *route = data; + struct in6_addr local; + + inet_pton (AF_INET6, "::1", &local); + if (! memcmp (&route->nexthop.address, &local, sizeof (struct in6_addr))) + { + if (IS_OSPF6_DUMP_AREA) + zlog_info ("AREA: Self-originated route add, ignore"); + return; + } + + ospf6_route_add (route, ospf6->route_table); +} + +void +ospf6_area_route_remove (void *data) +{ + struct ospf6_route_req *route = data; + struct in6_addr local; + + inet_pton (AF_INET6, "::1", &local); + if (! memcmp (&route->nexthop.address, &local, sizeof (struct in6_addr))) + { + if (IS_OSPF6_DUMP_AREA) + zlog_info ("AREA: Self-originated route remove, ignore"); + return; + } + + ospf6_route_remove (route, ospf6->route_table); +} + +/* Make new area structure */ +struct ospf6_area * +ospf6_area_create (u_int32_t area_id) +{ + struct ospf6_area *o6a; + char namebuf[64]; + + /* allocate memory */ + o6a = XCALLOC (MTYPE_OSPF6_AREA, sizeof (struct ospf6_area)); + + /* initialize */ + inet_ntop (AF_INET, &area_id, o6a->str, sizeof (o6a->str)); + o6a->area_id = area_id; + o6a->if_list = list_new (); + + o6a->lsdb = ospf6_lsdb_create (); + o6a->spf_tree = ospf6_spftree_create (); + + snprintf (namebuf, sizeof (namebuf), "Area %s's route table", o6a->str); + o6a->route_table = ospf6_route_table_create (namebuf); + o6a->route_table->hook_add = ospf6_area_route_add; + o6a->route_table->hook_change = ospf6_area_route_add; + o6a->route_table->hook_remove = ospf6_area_route_remove; + + snprintf (namebuf, sizeof (namebuf), "Area %s's topology table", o6a->str); + o6a->table_topology = ospf6_route_table_create (namebuf); + o6a->table_topology->hook_add = ospf6_intra_topology_add; + o6a->table_topology->hook_change = ospf6_intra_topology_add; + o6a->table_topology->hook_remove = ospf6_intra_topology_remove; + + /* xxx, set options */ + OSPF6_OPT_SET (o6a->options, OSPF6_OPT_V6); + OSPF6_OPT_SET (o6a->options, OSPF6_OPT_E); + OSPF6_OPT_SET (o6a->options, OSPF6_OPT_R); + + o6a->foreach_if = ospf6_area_foreach_interface; + o6a->foreach_nei = ospf6_area_foreach_neighbor; + + return o6a; +} + +void +ospf6_area_bind_top (struct ospf6_area *o6a, struct ospf6 *o6) +{ + o6a->ospf6 = o6; + CALL_CHANGE_HOOK (&area_hook, o6a); + return; +} + +void +ospf6_area_delete (struct ospf6_area *o6a) +{ + listnode n; + struct ospf6_interface *o6i; + + CALL_REMOVE_HOOK (&area_hook, o6a); + + /* ospf6 interface list */ + for (n = listhead (o6a->if_list); n; nextnode (n)) + { + o6i = (struct ospf6_interface *) getdata (n); + /* ospf6_interface_delete (o6i); */ + } + list_delete (o6a->if_list); + + /* terminate LSDB */ + ospf6_lsdb_remove_all (o6a->lsdb); + + /* spf tree terminate */ + /* xxx */ + + /* threads */ + if (o6a->spf_calc) + thread_cancel (o6a->spf_calc); + o6a->spf_calc = (struct thread *) NULL; + if (o6a->route_calc) + thread_cancel (o6a->route_calc); + o6a->route_calc = (struct thread *) NULL; + + /* new */ + ospf6_route_table_delete (o6a->route_table); + + ospf6_spftree_delete (o6a->spf_tree); + ospf6_route_table_delete (o6a->table_topology); + + /* free area */ + XFREE (MTYPE_OSPF6_AREA, o6a); +} + +struct ospf6_area * +ospf6_area_lookup (u_int32_t area_id, struct ospf6 *o6) +{ + struct ospf6_area *o6a; + listnode n; + + for (n = listhead (o6->area_list); n; nextnode (n)) + { + o6a = (struct ospf6_area *) getdata (n); + if (o6a->area_id == area_id) + return o6a; + } + + return (struct ospf6_area *) NULL; +} + +void +ospf6_area_show (struct vty *vty, struct ospf6_area *o6a) +{ + listnode i; + struct ospf6_interface *o6i; + + vty_out (vty, " Area %s%s", o6a->str, VTY_NEWLINE); + vty_out (vty, " Number of Area scoped LSAs is %u%s", + o6a->lsdb->count, VTY_NEWLINE); + + ospf6_spf_statistics_show (vty, o6a->spf_tree); + + vty_out (vty, " Interface attached to this area:"); + for (i = listhead (o6a->if_list); i; nextnode (i)) + { + o6i = (struct ospf6_interface *) getdata (i); + vty_out (vty, " %s", o6i->interface->name); + } + vty_out (vty, "%s", VTY_NEWLINE); + + for (i = listhead (o6a->if_list); i; nextnode (i)) + { + o6i = (struct ospf6_interface *) getdata (i); + if (listcount (o6i->neighbor_list) != 0) + ospf6_interface_statistics_show (vty, o6i); + } +} + +void +ospf6_area_statistics_show (struct vty *vty, struct ospf6_area *o6a) +{ +#if 0 + listnode node; + struct ospf6_interface *o6i; + + vty_out (vty, " Statistics of Area %s%s", o6a->str, VTY_NEWLINE); +#endif +} + +DEFUN (show_ipv6_ospf6_area_route, + show_ipv6_ospf6_area_route_cmd, + "show ipv6 ospf6 area A.B.C.D route", + SHOW_STR + IP6_STR + OSPF6_STR + OSPF6_AREA_STR + OSPF6_AREA_ID_STR + ROUTE_STR + ) +{ + struct ospf6_area *o6a; + u_int32_t area_id; + + OSPF6_CMD_CHECK_RUNNING (); + + inet_pton (AF_INET, argv[0], &area_id); + o6a = ospf6_area_lookup (area_id, ospf6); + + if (! o6a) + return CMD_SUCCESS; + + argc -= 1; + argv += 1; + + return ospf6_route_table_show (vty, argc, argv, o6a->route_table); +} + +ALIAS (show_ipv6_ospf6_area_route, + show_ipv6_ospf6_area_route_prefix_cmd, + "show ipv6 ospf6 area A.B.C.D route (X::X|detail)", + SHOW_STR + IP6_STR + OSPF6_STR + OSPF6_AREA_STR + OSPF6_AREA_ID_STR + ROUTE_STR + "Specify IPv6 address\n" + "Detailed information\n" + ) + +void +ospf6_area_init () +{ + area_index = ospf6_dump_install ("area", "Area information\n"); + + install_element (VIEW_NODE, &show_ipv6_ospf6_area_route_cmd); + install_element (VIEW_NODE, &show_ipv6_ospf6_area_route_prefix_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_area_route_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_area_route_prefix_cmd); +} + + diff --git a/ospf6d/ospf6_area.h b/ospf6d/ospf6_area.h new file mode 100644 index 000000000..068446463 --- /dev/null +++ b/ospf6d/ospf6_area.h @@ -0,0 +1,90 @@ +/* + * OSPF6 Area Data Structure + * Copyright (C) 1999 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF_AREA_H +#define OSPF_AREA_H + +/* This file defines area parameters and data structures. */ + +#define OSPF6_AREA_RANGE_ADVERTISE 0 +#define OSPF6_AREA_RANGE_NOT_ADVERTISE 1 + +#include "ospf6_spf.h" +#include "ospf6_top.h" + +struct ospf6_area +{ + char str[16]; + + struct ospf6 *ospf6; /* back pointer */ + u_int32_t area_id; + u_char options[3]; /* OSPF Option including ExternalCapability */ + + list if_list; /* OSPF interface to this area */ + + struct ospf6_lsdb *lsdb; + + struct thread *spf_calc; + struct thread *route_calc; + int stat_spf_execed; + int stat_route_execed; + + struct route_table *table; /* new route table */ + + struct prefix_ipv6 area_range; + struct ospf6_spftree *spf_tree; + + struct ospf6_route_table *route_table; + struct ospf6_route_table *table_topology; + + void (*foreach_if) (struct ospf6_area *, void *, int, + void (*func) (void *, int, void *)); + void (*foreach_nei) (struct ospf6_area *, void *, int, + void (*func) (void *, int, void *)); + + struct thread *maxage_remover; + + struct thread *thread_router_lsa; +}; + + +/* prototypes */ + +int +ospf6_area_count_neighbor_in_state (u_char state, struct ospf6_area *o6a); + +void +ospf6_area_schedule_maxage_remover (void *arg, int val, void *obj); + +int ospf6_area_is_stub (struct ospf6_area *o6a); +int ospf6_area_is_transit (struct ospf6_area *o6a); +struct ospf6_area *ospf6_area_lookup (u_int32_t, struct ospf6 *); +struct ospf6_area *ospf6_area_create (u_int32_t); +void ospf6_area_delete (struct ospf6_area *); +void ospf6_area_show (struct vty *, struct ospf6_area *); +void +ospf6_area_statistics_show (struct vty *vty, struct ospf6_area *o6a); + +void ospf6_area_init (); + +#endif /* OSPF_AREA_H */ + diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c new file mode 100644 index 000000000..00a2b66c0 --- /dev/null +++ b/ospf6d/ospf6_asbr.c @@ -0,0 +1,1040 @@ +/* + * Copyright (C) 2001-2002 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <zebra.h> + +#include "log.h" +#include "memory.h" +#include "prefix.h" +#include "command.h" +#include "vty.h" +#include "routemap.h" +#include "table.h" +#include "plist.h" +#include "thread.h" + +#include "ospf6_prefix.h" /* xxx for ospf6_asbr.h */ +#include "ospf6_lsa.h" /* xxx for ospf6_asbr.h */ +#include "ospf6_route.h" /* xxx for ospf6_asbr.h, ospf6_zebra.h */ +#include "ospf6_zebra.h" +#include "ospf6_asbr.h" +#include "ospf6_damp.h" +#include "ospf6_top.h" +#include "ospf6_lsdb.h" +#include "ospf6_proto.h" + +extern struct thread_master *master; + +struct route_table *external_table; +struct +{ + char *name; + struct route_map *map; +} rmap [ZEBRA_ROUTE_MAX]; + +static u_int32_t link_state_id = 0; + +char * +zroute_name[] = +{ + "system", "kernel", "connected", "static", + "rip", "ripng", "ospf", "ospf6", "bgp", "unknown" +}; +char * +zroute_abname[] = +{ + "X", "K", "C", "S", "R", "R", "O", "O", "B", "?" +}; + +#define ZROUTE_NAME(x) \ + (0 < (x) && (x) < ZEBRA_ROUTE_MAX ? \ + zroute_name[(x)] : zroute_name[ZEBRA_ROUTE_MAX]) + +#define ZROUTE_ABNAME(x) \ + (0 < (x) && (x) < ZEBRA_ROUTE_MAX ? \ + zroute_abname[(x)] : zroute_abname[ZEBRA_ROUTE_MAX]) + +/* redistribute function */ +void +ospf6_asbr_routemap_set (int type, char *mapname) +{ + if (rmap[type].name) + free (rmap[type].name); + + rmap[type].name = strdup (mapname); + rmap[type].map = route_map_lookup_by_name (mapname); +} + +void +ospf6_asbr_routemap_unset (int type) +{ + if (rmap[type].name) + free (rmap[type].name); + rmap[type].name = NULL; + rmap[type].map = NULL; +} + +void +ospf6_asbr_routemap_update () +{ + int i; + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + { + if (rmap[i].name) + rmap[i].map = route_map_lookup_by_name (rmap[i].name); + else + rmap[i].map = NULL; + } +} + +DEFUN (ospf6_redistribute, + ospf6_redistribute_cmd, + "redistribute (static|kernel|connected|ripng|bgp)", + "Redistribute\n" + "Static route\n" + "Kernel route\n" + "Connected route\n" + "RIPng route\n" + "BGP route\n" + ) +{ + int type = 0; + + if (strncmp (argv[0], "sta", 3) == 0) + type = ZEBRA_ROUTE_STATIC; + else if (strncmp (argv[0], "ker", 3) == 0) + type = ZEBRA_ROUTE_KERNEL; + else if (strncmp (argv[0], "con", 3) == 0) + type = ZEBRA_ROUTE_CONNECT; + else if (strncmp (argv[0], "rip", 3) == 0) + type = ZEBRA_ROUTE_RIPNG; + else if (strncmp (argv[0], "bgp", 3) == 0) + type = ZEBRA_ROUTE_BGP; + + ospf6_zebra_no_redistribute (type); + ospf6_asbr_routemap_unset (type); + ospf6_zebra_redistribute (type); + return CMD_SUCCESS; +} + +DEFUN (ospf6_redistribute_routemap, + ospf6_redistribute_routemap_cmd, + "redistribute (static|kernel|connected|ripng|bgp) route-map WORD", + "Redistribute\n" + "Static routes\n" + "Kernel route\n" + "Connected route\n" + "RIPng route\n" + "BGP route\n" + "Route map reference\n" + "Route map name\n" + ) +{ + int type = 0; + + if (strncmp (argv[0], "sta", 3) == 0) + type = ZEBRA_ROUTE_STATIC; + else if (strncmp (argv[0], "ker", 3) == 0) + type = ZEBRA_ROUTE_KERNEL; + else if (strncmp (argv[0], "con", 3) == 0) + type = ZEBRA_ROUTE_CONNECT; + else if (strncmp (argv[0], "rip", 3) == 0) + type = ZEBRA_ROUTE_RIPNG; + else if (strncmp (argv[0], "bgp", 3) == 0) + type = ZEBRA_ROUTE_BGP; + + ospf6_zebra_no_redistribute (type); + ospf6_asbr_routemap_set (type, argv[1]); + ospf6_zebra_redistribute (type); + return CMD_SUCCESS; +} + +DEFUN (no_ospf6_redistribute, + no_ospf6_redistribute_cmd, + "no redistribute (static|kernel|connected|ripng|bgp)", + NO_STR + "Redistribute\n" + "Static route\n" + "Kernel route\n" + "Connected route\n" + "RIPng route\n" + "BGP route\n" + ) +{ + int type = 0; + struct route_node *node; + struct ospf6_external_route *route; + struct ospf6_external_info *info, *info_next = NULL; + + if (strncmp (argv[0], "sta", 3) == 0) + type = ZEBRA_ROUTE_STATIC; + else if (strncmp (argv[0], "ker", 3) == 0) + type = ZEBRA_ROUTE_KERNEL; + else if (strncmp (argv[0], "con", 3) == 0) + type = ZEBRA_ROUTE_CONNECT; + else if (strncmp (argv[0], "rip", 3) == 0) + type = ZEBRA_ROUTE_RIPNG; + else if (strncmp (argv[0], "bgp", 3) == 0) + type = ZEBRA_ROUTE_BGP; + + ospf6_zebra_no_redistribute (type); + ospf6_asbr_routemap_unset (type); + + /* remove redistributed route */ + for (node = route_top (external_table); node; node = route_next (node)) + { + route = node->info; + if (! route) + continue; + for (info = route->info_head; info; info = info_next) + { + info_next = info->next; + if (info->type != type) + continue; + ospf6_asbr_route_remove (info->type, info->ifindex, + &route->prefix); + } + } + + return CMD_SUCCESS; +} + + +int +ospf6_redistribute_config_write (struct vty *vty) +{ + int i; + + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + { + if (i == ZEBRA_ROUTE_OSPF6) + continue; + + if (! ospf6_zebra_is_redistribute (i)) + continue; + + if (rmap[i].map) + vty_out (vty, " redistribute %s route-map %s%s", + ZROUTE_NAME(i), rmap[i].name, VTY_NEWLINE); + else + vty_out (vty, " redistribute %s%s", + ZROUTE_NAME(i), VTY_NEWLINE); + } + + return 0; +} + +void +ospf6_redistribute_show_config (struct vty *vty) +{ + int i; + + if (! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_SYSTEM) && + ! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_KERNEL) && + ! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_STATIC) && + ! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_RIPNG) && + ! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_BGP)) + return; + + vty_out (vty, " Redistributing External Routes from,%s", VTY_NEWLINE); + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + { + if (i == ZEBRA_ROUTE_OSPF6) + continue; + if (! ospf6_zebra_is_redistribute (i)) + continue; + + if (rmap[i].map) + vty_out (vty, " %s with route-map %s%s", + ZROUTE_NAME(i), rmap[i].name, VTY_NEWLINE); + else + vty_out (vty, " %s%s", ZROUTE_NAME(i), VTY_NEWLINE); + } +} + +/* AS External LSA origination */ +int +ospf6_asbr_external_lsa_originate (struct thread *thread) +{ + struct ospf6_external_info *info; + char buffer [MAXLSASIZE]; + struct ospf6_lsa_as_external *e; + char *p; + + info = THREAD_ARG (thread); + + /* clear thread */ + info->thread_originate = NULL; + + if (info->is_removed) + { + if (IS_OSPF6_DUMP_ASBR) + { + char pbuf[64]; + prefix2str (&info->route->prefix, pbuf, sizeof (pbuf)); + zlog_info ("ASBR: quit redistribution %s: state is down", + pbuf); + } + return 0; + } + + /* prepare buffer */ + memset (buffer, 0, sizeof (buffer)); + e = (struct ospf6_lsa_as_external *) buffer; + p = (char *) (e + 1); + + if (info->metric_type == 2) + SET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_E); /* type2 */ + else + UNSET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_E); /* type1, default */ + + /* forwarding address */ + if (! IN6_IS_ADDR_UNSPECIFIED (&info->forwarding)) + SET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_F); + else + UNSET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_F); + + /* external route tag */ + UNSET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_T); + + /* set metric. note: related to E bit */ + OSPF6_ASBR_METRIC_SET (e, info->metric); + + /* prefixlen */ + e->prefix.prefix_length = info->route->prefix.prefixlen; + + /* PrefixOptions */ + e->prefix.prefix_options = info->prefix_options; + + /* don't use refer LS-type */ + e->prefix.prefix_refer_lstype = htons (0); + + /* set Prefix */ + memcpy (p, &info->route->prefix.u.prefix6, + OSPF6_PREFIX_SPACE (info->route->prefix.prefixlen)); + ospf6_prefix_apply_mask (&e->prefix); + p += OSPF6_PREFIX_SPACE (info->route->prefix.prefixlen); + + /* Forwarding address */ + if (CHECK_FLAG (e->bits_metric, OSPF6_ASBR_BIT_F)) + { + memcpy (p, &info->forwarding, sizeof (struct in6_addr)); + p += sizeof (struct in6_addr); + } + + /* External Route Tag */ + if (CHECK_FLAG (e->bits_metric, OSPF6_ASBR_BIT_T)) + { + /* xxx */ + } + + ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_AS_EXTERNAL), + htonl (info->id), ospf6->router_id, + (char *) buffer, p - buffer, ospf6); + return 0; +} + +int +ospf6_asbr_schedule_external (void *data) +{ + struct ospf6_external_info *info = data; + u_long elasped_time, time = 0; + + if (info->thread_originate) + { + if (IS_OSPF6_DUMP_ASBR) + { + char pbuf[64]; + prefix2str (&info->route->prefix, pbuf, sizeof (pbuf)); + zlog_info ("ASBR: schedule redistribution %s: another thread", + pbuf); + } + return 0; + } + + elasped_time = + ospf6_lsa_has_elasped (htons (OSPF6_LSA_TYPE_AS_EXTERNAL), + htonl (info->id), ospf6->router_id, ospf6); + if (elasped_time < OSPF6_MIN_LS_INTERVAL) + time = OSPF6_MIN_LS_INTERVAL - elasped_time; + else + time = 0; + + //if (IS_OSPF6_DUMP_ASBR) + { + char pbuf[64]; + prefix2str (&info->route->prefix, pbuf, sizeof (pbuf)); + zlog_info ("ASBR: schedule redistribution %s as LS-ID %ld after %lu sec", + pbuf, (u_long) info->id, time); + } + + if (time) + info->thread_originate = + thread_add_timer (master, ospf6_asbr_external_lsa_originate, info, time); + else + info->thread_originate = + thread_add_timer (master, ospf6_asbr_external_lsa_originate, info, 0); + + return 0; +} + +int +ospf6_asbr_external_lsa_flush (void *data) +{ + struct ospf6_lsa *lsa = data; + if (lsa) + ospf6_lsa_premature_aging (lsa); + return 0; +} + +int +ospf6_asbr_external_lsa_refresh (void *data) +{ + struct ospf6_lsa *lsa = data; + struct ospf6_lsa_as_external *e; + struct prefix prefix; + struct route_node *node; + struct ospf6_external_route *route; + struct ospf6_external_info *info; + + if (IS_OSPF6_DUMP_ASBR) + zlog_info ("ASBR: refresh %s", lsa->str); + + e = (struct ospf6_lsa_as_external *) (lsa->header + 1); + ospf6_prefix_in6_addr (&e->prefix, &prefix.u.prefix6); + prefix.prefixlen = e->prefix.prefix_length; + prefix.family = AF_INET6; + apply_mask_ipv6 ((struct prefix_ipv6 *) &prefix); + + node = route_node_lookup (external_table, &prefix); + if (! node || ! node->info) + { + char pname[64]; + + prefix2str (&prefix, pname, sizeof (pname)); + if (IS_OSPF6_DUMP_ASBR) + zlog_info ("ASBR: could not find %s: premature age", pname); + ospf6_lsa_premature_aging (lsa); + return 0; + } + + /* find external_info */ + route = node->info; + for (info = route->info_head; info; info = info->next) + { + if (lsa->header->id == htonl (info->id)) + break; + } + + if (info) + ospf6_asbr_schedule_external (info); + else + ospf6_lsa_premature_aging (lsa); + + return 0; +} + +void +ospf6_asbr_route_add (int type, int ifindex, struct prefix *prefix, + u_int nexthop_num, struct in6_addr *nexthop) +{ + int ret; + struct route_node *node; + struct ospf6_external_route *route; + struct ospf6_external_info *info, tinfo; + + if (! ospf6_zebra_is_redistribute (type)) + return; + + /* apply route-map */ + memset (&tinfo, 0, sizeof (struct ospf6_external_info)); + if (rmap[type].map) + { + ret = route_map_apply (rmap[type].map, prefix, RMAP_OSPF6, &tinfo); + if (ret == RMAP_DENYMATCH) + { + if (IS_OSPF6_DUMP_ASBR) + zlog_info ("ASBR: denied by route-map %s", rmap[type].name); + return; + } + } + + node = route_node_get (external_table, prefix); + route = node->info; + + if (! route) + { + route = XMALLOC (MTYPE_OSPF6_EXTERNAL_INFO, + sizeof (struct ospf6_external_route)); + memset (route, 0, sizeof (struct ospf6_external_route)); + + memcpy (&route->prefix, prefix, sizeof (struct prefix)); + + node->info = route; + route->node = node; + } + + for (info = route->info_head; info; info = info->next) + { + if (info->type == type && info->ifindex == ifindex) + break; + } + + if (! info) + { + info = XMALLOC (MTYPE_OSPF6_EXTERNAL_INFO, + sizeof (struct ospf6_external_info)); + memset (info, 0, sizeof (struct ospf6_external_info)); + + info->route = route; + /* add tail */ + info->prev = route->info_tail; + if (route->info_tail) + route->info_tail->next = info; + else + route->info_head = info; + route->info_tail = info; + + info->id = link_state_id++; + } + + /* copy result of route-map */ + info->metric_type = tinfo.metric_type; + info->metric = tinfo.metric; + memcpy (&info->forwarding, &tinfo.forwarding, + sizeof (struct in6_addr)); + + info->type = type; + info->ifindex = ifindex; + + if (nexthop_num && nexthop) + { + info->nexthop_num = nexthop_num; + + if (info->nexthop) + XFREE (MTYPE_OSPF6_EXTERNAL_INFO, info->nexthop); + + info->nexthop = (struct in6_addr *) + XMALLOC (MTYPE_OSPF6_EXTERNAL_INFO, + nexthop_num * sizeof (struct in6_addr)); + memcpy (info->nexthop, nexthop, + nexthop_num * sizeof (struct in6_addr)); + } + + info->is_removed = 0; + + //if (IS_OSPF6_DUMP_ASBR) + { + char pbuf[64]; + struct timeval now; + prefix2str (&info->route->prefix, pbuf, sizeof (pbuf)); + gettimeofday (&now, NULL); + zlog_info ("ASBR: start redistributing %s as LS-ID %ld: %ld.%06ld", + pbuf, (u_long) info->id, now.tv_sec, now.tv_usec); + } + +#ifdef HAVE_OSPF6_DAMP + ospf6_damp_event_up (OSPF6_DAMP_TYPE_ROUTE, prefix, + ospf6_asbr_schedule_external, info); +#else /*HAVE_OSPF6_DAMP*/ + ospf6_asbr_schedule_external (info); +#endif /*HAVE_OSPF6_DAMP*/ +} + +void +ospf6_asbr_route_remove (int type, int ifindex, struct prefix *prefix) +{ + struct route_node *node; + struct ospf6_external_route *route; + struct ospf6_external_info *info; + struct ospf6_lsa *lsa; + + node = route_node_get (external_table, prefix); + route = node->info; + + if (! route) + return; + + for (info = route->info_head; info; info = info->next) + { + if (info->type == type && info->ifindex == ifindex) + break; + } + + if (! info) + return; + + //if (IS_OSPF6_DUMP_ASBR) + { + char pbuf[64]; + struct timeval now; + prefix2str (&info->route->prefix, pbuf, sizeof (pbuf)); + gettimeofday (&now, NULL); + zlog_info ("ASBR: quit redistributing %s as LS-ID %ld: %ld.%06ld", + pbuf, (u_long) info->id, now.tv_sec, now.tv_usec); + } + + if (info->thread_originate) + thread_cancel (info->thread_originate); + info->thread_originate = NULL; + + lsa = ospf6_lsdb_lookup (htons (OSPF6_LSA_TYPE_AS_EXTERNAL), + htonl (info->id), ospf6->router_id, ospf6); +#ifdef HAVE_OSPF6_DAMP + ospf6_damp_event_down (OSPF6_DAMP_TYPE_ROUTE, &info->route->prefix, + ospf6_asbr_external_lsa_flush, lsa); +#else /*HAVE_OSPF6_DAMP*/ + ospf6_asbr_external_lsa_flush (lsa); +#endif /*HAVE_OSPF6_DAMP*/ + +#if 1 + info->is_removed = 1; +#else + /* remove from route */ + if (info->prev) + info->prev->next = info->next; + else + info->route->info_head = info->next; + if (info->next) + info->next->prev = info->prev; + else + info->route->info_tail = info->prev; + + /* if no info, free route */ + if (! info->route->info_head && ! info->route->info_tail) + { + info->route->node->info = NULL; + free (info->route); + } + + if (info->nexthop) + free (info->nexthop); + free (info); +#endif /*0*/ +} + +void +ospf6_asbr_external_lsa_add (struct ospf6_lsa *lsa) +{ + struct ospf6_lsa_as_external *external; + struct prefix_ls asbr_id; + struct ospf6_route_req asbr_entry; + struct ospf6_route_req request; + + external = OSPF6_LSA_HEADER_END (lsa->header); + + if (IS_LSA_MAXAGE (lsa)) + { + if (IS_OSPF6_DUMP_ASBR) + zlog_info ("ASBR: maxage external lsa: %s seq: %lx", + lsa->str, (u_long)ntohl (lsa->header->seqnum)); + ospf6_asbr_external_lsa_remove (lsa); + return; + } + + if (IS_OSPF6_DUMP_ASBR) + zlog_info ("ASBR: new external lsa: %s seq: %lx", + lsa->str, (u_long)ntohl (lsa->header->seqnum)); + + if (lsa->header->adv_router == ospf6->router_id) + { + if (IS_OSPF6_DUMP_ASBR) + zlog_info ("ASBR: my external LSA, ignore"); + return; + } + + if (OSPF6_ASBR_METRIC (external) == LS_INFINITY) + { + if (IS_OSPF6_DUMP_ASBR) + zlog_info ("ASBR: metric is infinity, ignore"); + return; + } + + memset (&asbr_id, 0, sizeof (asbr_id)); + asbr_id.family = AF_UNSPEC; + asbr_id.prefixlen = 64; /* xxx */ + asbr_id.adv_router.s_addr = lsa->header->adv_router; + + ospf6_route_lookup (&asbr_entry, (struct prefix *) &asbr_id, + ospf6->topology_table); + + if (ospf6_route_end (&asbr_entry)) + { + if (IS_OSPF6_DUMP_ASBR) + { + char buf[64]; + inet_ntop (AF_INET, &asbr_id.adv_router, buf, sizeof (buf)); + zlog_info ("ASBR: router %s not found, ignore", buf); + } + return; + } + + memset (&request, 0, sizeof (request)); + request.route.type = OSPF6_DEST_TYPE_NETWORK; + request.route.prefix.family = AF_INET6; + request.route.prefix.prefixlen = external->prefix.prefix_length; + memcpy (&request.route.prefix.u.prefix6, (char *)(external + 1), + OSPF6_PREFIX_SPACE (request.route.prefix.prefixlen)); + + request.path.area_id = asbr_entry.path.area_id; + request.path.origin.type = htons (OSPF6_LSA_TYPE_AS_EXTERNAL); + request.path.origin.id = lsa->header->id; + request.path.origin.adv_router = lsa->header->adv_router; + if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_E)) + { + request.path.type = OSPF6_PATH_TYPE_EXTERNAL2; + request.path.metric_type = 2; + request.path.cost = asbr_entry.path.cost; + request.path.cost_e2 = OSPF6_ASBR_METRIC (external); + } + else + { + request.path.type = OSPF6_PATH_TYPE_EXTERNAL1; + request.path.metric_type = 1; + request.path.cost = asbr_entry.path.cost + + OSPF6_ASBR_METRIC (external); + request.path.cost_e2 = 0; + } + request.path.prefix_options = external->prefix.prefix_options; + + while (((struct prefix_ls *)&asbr_entry.route.prefix)->adv_router.s_addr == + asbr_id.adv_router.s_addr && + asbr_entry.route.type == OSPF6_DEST_TYPE_ROUTER) + { + memcpy (&request.nexthop, &asbr_entry.nexthop, + sizeof (struct ospf6_nexthop)); + if (IS_OSPF6_DUMP_ASBR) + { + char buf[64], nhop[64], ifname[IFNAMSIZ]; + prefix2str (&request.route.prefix, buf, sizeof (buf)); + inet_ntop (AF_INET6, &request.nexthop.address, nhop, sizeof (nhop)); + if_indextoname (request.nexthop.ifindex, ifname); + zlog_info ("ASBR: add route: %s %s%%%s", buf, nhop, ifname); + } + ospf6_route_add (&request, ospf6->route_table); + ospf6_route_next (&asbr_entry); + } +} + +void +ospf6_asbr_external_lsa_remove (struct ospf6_lsa *lsa) +{ + struct ospf6_lsa_as_external *external; + struct prefix dest; + char buf[64]; + struct ospf6_route_req request; + + if (IS_OSPF6_DUMP_ASBR) + zlog_info ("ASBR: withdraw external lsa: %s seq: %lx", + lsa->str, (u_long)ntohl (lsa->header->seqnum)); + + if (lsa->header->adv_router == ospf6->router_id) + { + if (IS_OSPF6_DUMP_ASBR) + zlog_info ("ASBR: my external LSA, ignore"); + return; + } + + external = OSPF6_LSA_HEADER_END (lsa->header); + memset (&dest, 0, sizeof (dest)); + dest.family = AF_INET6; + dest.prefixlen = external->prefix.prefix_length; + memcpy (&dest.u.prefix6, (char *)(external + 1), + OSPF6_PREFIX_SPACE (dest.prefixlen)); + + ospf6_route_lookup (&request, &dest, ospf6->route_table); + if (ospf6_route_end (&request)) + { + if (IS_OSPF6_DUMP_ASBR) + { + prefix2str (&dest, buf, sizeof (buf)); + zlog_info ("ASBR: %s not found", buf); + } + return; + } + + while (request.path.origin.id != lsa->header->id || + request.path.origin.adv_router != lsa->header->adv_router) + { + if (prefix_same (&request.route.prefix, &dest) != 1) + { + if (IS_OSPF6_DUMP_ASBR) + zlog_info ("ASBR: Can't find the entry matches the origin"); + return; + } + ospf6_route_next (&request); + } + assert (request.path.origin.id == lsa->header->id); + assert (request.path.origin.adv_router == request.path.origin.adv_router); + + while (request.path.origin.id == lsa->header->id && + request.path.origin.adv_router == lsa->header->adv_router && + prefix_same (&request.route.prefix, &dest) == 1) + { + if (IS_OSPF6_DUMP_ASBR) + { + char nhop[64], ifname[IFNAMSIZ]; + prefix2str (&dest, buf, sizeof (buf)); + inet_ntop (AF_INET6, &request.nexthop.address, nhop, sizeof (nhop)); + if_indextoname (request.nexthop.ifindex, ifname); + zlog_info ("ASBR: remove route: %s %s%%%s", buf, nhop, ifname); + } + + ospf6_route_remove (&request, ospf6->route_table); + ospf6_route_next (&request); + } +} + +void +ospf6_asbr_external_lsa_change (struct ospf6_lsa *old, struct ospf6_lsa *new) +{ + assert (old || new); + + if (old == NULL) + ospf6_asbr_external_lsa_add (new); + else if (new == NULL) + ospf6_asbr_external_lsa_remove (old); + else + { + ospf6_route_table_freeze (ospf6->route_table); + ospf6_asbr_external_lsa_remove (old); + ospf6_asbr_external_lsa_add (new); + ospf6_route_table_thaw (ospf6->route_table); + } +} + +void +ospf6_asbr_asbr_entry_add (struct ospf6_route_req *topo_entry) +{ + struct ospf6_lsdb_node node; + + struct prefix_ls *inter_router; + u_int32_t id, adv_router; + + inter_router = (struct prefix_ls *) &topo_entry->route.prefix; + id = inter_router->id.s_addr; + adv_router = inter_router->adv_router.s_addr; + + if (IS_OSPF6_DUMP_ASBR) + { + char buf[64]; + inet_ntop (AF_INET, &inter_router->adv_router, buf, sizeof (buf)); + zlog_info ("ASBR: new router found: %s", buf); + } + + if (ntohl (id) != 0 || + ! OSPF6_OPT_ISSET (topo_entry->path.capability, OSPF6_OPT_E)) + { + zlog_warn ("ASBR: Inter topology table malformed"); + return; + } + + for (ospf6_lsdb_type_router (&node, htons (OSPF6_LSA_TYPE_AS_EXTERNAL), + adv_router, ospf6->lsdb); + ! ospf6_lsdb_is_end (&node); + ospf6_lsdb_next (&node)) + ospf6_asbr_external_lsa_add (node.lsa); +} + +void +ospf6_asbr_asbr_entry_remove (struct ospf6_route_req *topo_entry) +{ + struct prefix_ls *inter_router; + u_int32_t id, adv_router; + struct ospf6_route_req request; + + inter_router = (struct prefix_ls *) &topo_entry->route.prefix; + id = inter_router->id.s_addr; + adv_router = inter_router->adv_router.s_addr; + + if (IS_OSPF6_DUMP_ASBR) + { + char buf[64]; + inet_ntop (AF_INET, &inter_router->adv_router, buf, sizeof (buf)); + zlog_info ("ASBR: router disappearing: %s", buf); + } + + if (ntohl (id) != 0 || + ! OSPF6_OPT_ISSET (topo_entry->path.capability, OSPF6_OPT_E)) + { + zlog_warn ("ASBR: Inter topology table malformed"); + } + + for (ospf6_route_head (&request, ospf6->route_table); + ! ospf6_route_end (&request); + ospf6_route_next (&request)) + { + if (request.path.type != OSPF6_PATH_TYPE_EXTERNAL1 && + request.path.type != OSPF6_PATH_TYPE_EXTERNAL2) + continue; + if (request.path.area_id != topo_entry->path.area_id) + continue; + if (request.path.origin.adv_router != topo_entry->path.origin.adv_router) + continue; + if (memcmp (&topo_entry->nexthop, &request.nexthop, + sizeof (struct ospf6_nexthop))) + continue; + + ospf6_route_remove (&request, ospf6->route_table); + } +} + +int +ospf6_asbr_external_show (struct vty *vty, struct ospf6_lsa *lsa) +{ + struct ospf6_lsa_as_external *external; + char buf[128], *ptr; + struct in6_addr in6; + + assert (lsa->header); + external = (struct ospf6_lsa_as_external *)(lsa->header + 1); + + /* bits */ + snprintf (buf, sizeof (buf), "%s%s%s", + (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_E) ? + "E" : "-"), + (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F) ? + "F" : "-"), + (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_T) ? + "T" : "-")); + + vty_out (vty, " Bits: %s%s", buf, VTY_NEWLINE); + vty_out (vty, " Metric: %5lu%s", (u_long)OSPF6_ASBR_METRIC (external), + VTY_NEWLINE); + + ospf6_prefix_options_str (external->prefix.prefix_options, + buf, sizeof (buf)); + vty_out (vty, " Prefix Options: %s%s", buf, VTY_NEWLINE); + + vty_out (vty, " Referenced LSType: %d%s", + ntohs (external->prefix.prefix_refer_lstype), VTY_NEWLINE); + + ospf6_prefix_in6_addr (&external->prefix, &in6); + inet_ntop (AF_INET6, &in6, buf, sizeof (buf)); + vty_out (vty, " Prefix: %s/%d%s", + buf, external->prefix.prefix_length, VTY_NEWLINE); + + /* Forwarding-Address */ + if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F)) + { + ptr = ((char *)(external + 1)) + + OSPF6_PREFIX_SPACE (external->prefix.prefix_length); + inet_ntop (AF_INET6, (struct in6_addr *) ptr, buf, sizeof (buf)); + vty_out (vty, " Forwarding-Address: %s%s", buf, VTY_NEWLINE); + } + + return 0; +} + +void +ospf6_asbr_database_hook (struct ospf6_lsa *old, struct ospf6_lsa *new) +{ + if (old) + ospf6_asbr_external_lsa_remove (old); + if (new && ! IS_LSA_MAXAGE (new)) + ospf6_asbr_external_lsa_add (new); +} + +void +ospf6_asbr_register_as_external () +{ + struct ospf6_lsa_slot slot; + + memset (&slot, 0, sizeof (slot)); + slot.type = htons (OSPF6_LSA_TYPE_AS_EXTERNAL); + slot.name = "AS-External"; + slot.func_show = ospf6_asbr_external_show; + slot.func_refresh = ospf6_asbr_external_lsa_refresh; + ospf6_lsa_slot_register (&slot); + + ospf6_lsdb_hook[OSPF6_LSA_TYPE_AS_EXTERNAL & OSPF6_LSTYPE_CODE_MASK].hook = + ospf6_asbr_database_hook; +} + +void +ospf6_asbr_external_info_show (struct vty *vty, + struct ospf6_external_info *info) +{ + char prefix_buf[64], id_buf[16]; + struct in_addr id; + + if (info->is_removed) + return; + + id.s_addr = ntohl (info->id); + inet_ntop (AF_INET, &id, id_buf, sizeof (id_buf)); + prefix2str (&info->route->prefix, prefix_buf, sizeof (prefix_buf)); + vty_out (vty, "%s %-32s %3d %-15s %3d %lu(type-%d)%s", + ZROUTE_ABNAME(info->type), prefix_buf, info->ifindex, id_buf, + info->nexthop_num, (u_long) info->metric, info->metric_type, + VTY_NEWLINE); +} + +void +ospf6_asbr_external_route_show (struct vty *vty, + struct ospf6_external_route *route) +{ + struct ospf6_external_info *info; + for (info = route->info_head; info; info = info->next) + ospf6_asbr_external_info_show (vty, info); +} + +DEFUN (show_ipv6_route_ospf6_external, + show_ipv6_route_ospf6_external_cmd, + "show ipv6 ospf6 route redistribute", + SHOW_STR + IP6_STR + ROUTE_STR + OSPF6_STR + "redistributing External information\n" + ) +{ + struct route_node *node; + struct ospf6_external_route *route; + + vty_out (vty, "%s %-32s %3s %-15s %3s %s%s", + " ", "Prefix", "I/F", "LS-Id", "#NH", "Metric", + VTY_NEWLINE); + for (node = route_top (external_table); node; node = route_next (node)) + { + route = node->info; + if (route) + ospf6_asbr_external_route_show (vty, route); + } + return CMD_SUCCESS; +} + +void +ospf6_asbr_init () +{ + external_table = route_table_init (); + link_state_id = 0; + + ospf6_asbr_register_as_external (); + + install_element (VIEW_NODE, &show_ipv6_route_ospf6_external_cmd); + install_element (ENABLE_NODE, &show_ipv6_route_ospf6_external_cmd); + install_element (OSPF6_NODE, &ospf6_redistribute_cmd); + install_element (OSPF6_NODE, &ospf6_redistribute_routemap_cmd); + install_element (OSPF6_NODE, &no_ospf6_redistribute_cmd); +} + + diff --git a/ospf6d/ospf6_asbr.h b/ospf6d/ospf6_asbr.h new file mode 100644 index 000000000..153ed21eb --- /dev/null +++ b/ospf6d/ospf6_asbr.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2001 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF6_ASBR_H +#define OSPF6_ASBR_H + +#include "thread.h" + +struct ospf6_external_info +{ + int is_removed; + struct thread *thread_originate; + + struct ospf6_external_route *route; + + struct ospf6_external_info *prev; + struct ospf6_external_info *next; + + /* external route type */ + int type; + + /* external route ifindex */ + int ifindex; + + /* LS-ID */ + u_int32_t id; + + /* nexthops */ + u_int nexthop_num; + struct in6_addr *nexthop; + + u_int8_t prefix_options; + + u_int8_t metric_type; + u_int32_t metric; + struct in6_addr forwarding; + /* u_int32_t tag; */ +}; + +struct ospf6_external_route +{ + struct route_node *node; + + /* prefix */ + struct prefix prefix; + + /* external information */ + struct ospf6_external_info *info_head; + struct ospf6_external_info *info_tail; +}; + +/* AS-External-LSA */ +struct ospf6_lsa_as_external +{ + u_int32_t bits_metric; + + struct ospf6_prefix prefix; + /* followed by none or one forwarding address */ + /* followed by none or one external route tag */ + /* followed by none or one referenced LS-ID */ +}; + +#define OSPF6_ASBR_BIT_T ntohl (0x01000000) +#define OSPF6_ASBR_BIT_F ntohl (0x02000000) +#define OSPF6_ASBR_BIT_E ntohl (0x04000000) + +#define OSPF6_ASBR_METRIC(E) (ntohl ((E)->bits_metric & htonl (0x00ffffff))) +#define OSPF6_ASBR_METRIC_SET(E,C) \ + { (E)->bits_metric &= htonl (0xff000000); \ + (E)->bits_metric |= htonl (0x00ffffff) & htonl (C); } + +void ospf6_asbr_routemap_update (); + +int ospf6_redistribute_config_write (struct vty *vty); +void ospf6_redistribute_show_config (struct vty *vty); + +void +ospf6_asbr_route_add (int type, int ifindex, struct prefix *prefix, + u_int nexthop_num, struct in6_addr *nexthop); +void +ospf6_asbr_route_remove (int type, int ifindex, struct prefix *prefix); + +void ospf6_asbr_external_lsa_add (struct ospf6_lsa *lsa); +void ospf6_asbr_external_lsa_remove (struct ospf6_lsa *lsa); +void ospf6_asbr_external_lsa_change (struct ospf6_lsa *old, + struct ospf6_lsa *new); + +void ospf6_asbr_asbr_entry_add (struct ospf6_route_req *topo_entry); +void ospf6_asbr_asbr_entry_remove (struct ospf6_route_req *topo_entry); + +void ospf6_asbr_init (); + +#endif /* OSPF6_ASBR_H */ + diff --git a/ospf6d/ospf6_bintree.c b/ospf6d/ospf6_bintree.c new file mode 100644 index 000000000..c1e9e5584 --- /dev/null +++ b/ospf6d/ospf6_bintree.c @@ -0,0 +1,436 @@ + +#include <zebra.h> +#include "ospf6_bintree.h" + +static struct bintree_node * +bintree_lookup_node_min (struct bintree_node *subroot) +{ + struct bintree_node *node; + + if (subroot == NULL) + return NULL; + + node = subroot; + while (node->bl_left) + node = node->bl_left; + return node; +} + +static struct bintree_node * +bintree_lookup_node_max (struct bintree_node *subroot) +{ + struct bintree_node *node; + + assert (subroot != NULL); + node = subroot; + while (node->bl_right) + node = node->bl_right; + return node; +} + +void * +bintree_lookup (void *data, struct bintree *tree) +{ + int cmp; + struct bintree_node *node; + + node = tree->root; + + while (node) + { + if (tree->cmp) + cmp = (*tree->cmp) (node->data, data); + else + cmp = (node->data - data); + + if (cmp == 0) + break; + + if (cmp > 0) + node = node->bl_left; + else /* if (cmp < 0) */ + node = node->bl_right; + } + + if (node) + return node->data; + + return NULL; +} + +void * +bintree_lookup_min (struct bintree *tree) +{ + struct bintree_node *node; + node = bintree_lookup_node_min (tree->root); + if (node == NULL) + return NULL; + return node->data; +} + +void * +bintree_lookup_max (struct bintree *tree) +{ + struct bintree_node *node; + node = bintree_lookup_node_max (tree->root); + if (node == NULL) + return NULL; + return node->data; +} + +int +bintree_add (void *data, struct bintree *tree) +{ + int cmp = 0; + struct bintree_node *node, *parent; + + node = tree->root; + parent = NULL; + + while (node) + { + if (tree->cmp) + cmp = (*tree->cmp) (node->data, data); + else + cmp = (node->data - data); + + if (cmp == 0) + break; + + parent = node; + if (cmp > 0) + node = node->bl_left; + else /* if (cmp < 0) */ + node = node->bl_right; + } + + if (node) + return -1; + + node = malloc (sizeof (struct bintree_node)); + memset (node, 0, sizeof (struct bintree_node)); + node->tree = tree; + node->data = data; + + if (parent) + { + node->parent = parent; + + assert (cmp != 0); + if (cmp > 0) + { + node->parent_link = BL_LEFT; + parent->bl_left = node; + } + else /* if (cmp < 0) */ + { + node->parent_link = BL_RIGHT; + parent->bl_right = node; + } + } + else + tree->root = node; + + tree->count++; + return 0; +} + +static void +bintree_remove_nochild (struct bintree_node *node) +{ + assert (node->bl_left == NULL && node->bl_right == NULL); + + if (node->parent == NULL) + node->tree->root = NULL; + else + node->parent->link[node->parent_link] = NULL; +} + +static void +bintree_remove_onechild (struct bintree_node *node) +{ + assert ((node->bl_left == NULL && node->bl_right != NULL) || + (node->bl_left != NULL && node->bl_right == NULL)); + + if (node->bl_left) + { + if (node->parent == NULL) + { + node->tree->root = node->bl_left; + node->bl_left->parent = NULL; + } + else + { + node->parent->link[node->parent_link] = node->bl_left; + node->bl_left->parent = node->parent; + node->bl_left->parent_link = node->parent_link; + } + } + else if (node->bl_right) + { + if (node->parent == NULL) + { + node->tree->root = node->bl_right; + node->bl_right->parent = NULL; + } + else + { + node->parent->link[node->parent_link] = node->bl_right; + node->bl_right->parent = node->parent; + node->bl_right->parent_link = node->parent_link; + } + } + else + assert (0); +} + +int +bintree_remove (void *data, struct bintree *tree) +{ + int cmp; + struct bintree_node *node; + + node = tree->root; + + while (node) + { + if (tree->cmp) + cmp = (*tree->cmp) (node->data, data); + else + cmp = (node->data - data); + + if (cmp == 0) + break; + + if (cmp > 0) + node = node->bl_left; + else /* if (cmp < 0) */ + node = node->bl_right; + } + + if (node == NULL) + return -1; + + if (node->bl_left == NULL && node->bl_right == NULL) + { + bintree_remove_nochild (node); + free (node); + tree->count--; + return 0; + } + + if ((node->bl_left == NULL && node->bl_right != NULL) || + (node->bl_left != NULL && node->bl_right == NULL)) + { + bintree_remove_onechild (node); + free (node); + tree->count--; + return 0; + } + + if (node->bl_left != NULL && node->bl_right != NULL) + { + struct bintree_node *successor; + + /* find successor of the removing node */ + successor = bintree_lookup_node_min (node->bl_right); + + /* remove successor from tree */ + if (successor->bl_right) + bintree_remove_onechild (successor); + else + bintree_remove_nochild (successor); + + /* swap removing node with successor */ + successor->parent = node->parent; + successor->parent_link = node->parent_link; + successor->bl_left = node->bl_left; + successor->bl_right = node->bl_right; + + /* if the successor was the node->bl_right itself, + bintree_remove_**child may touch node->bl_right, + so only the successor->bl_right may be NULL + by above assignment */ + successor->bl_left->parent = successor; + if (successor->bl_right) + successor->bl_right->parent = successor; + + if (successor->parent == NULL) + tree->root = successor; + else + successor->parent->link[successor->parent_link] = successor; + + free (node); + tree->count--; + return 0; + } + + /* not reached */ + return -1; +} + +/* in-order traversal */ + +void +bintree_head (struct bintree *tree, struct bintree_node *node) +{ + struct bintree_node *head; + + head = bintree_lookup_node_min (tree->root); + if (head == NULL) + { + node->parent = NULL; + node->bl_left = NULL; + node->bl_right = NULL; + node->data = NULL; + return; + } + + node->tree = head->tree; + node->parent = head->parent; + node->parent_link = head->parent_link; + node->bl_left = head->bl_left; + node->bl_right = head->bl_right; + node->data = head->data; +} + +int +bintree_end (struct bintree_node *node) +{ + if (node->parent || node->bl_left || node->bl_right || node->data) + return 0; + return 1; +} + +#define GOTO_PROCED_SUBTREE_TOP(node) \ + while (node->parent && node->parent->bl_right && \ + node->parent->bl_right->data == node->data) \ + { \ + node->data = node->parent->data; \ + node->bl_left = node->parent->bl_left; \ + node->bl_right = node->parent->bl_right; \ + node->parent_link = node->parent->parent_link; \ + node->parent = node->parent->parent; \ + } + +void +bintree_next (struct bintree_node *node) +{ + struct bintree_node *next = NULL; + + /* if node have just been removed, current point should have just been + replaced with its successor. that certainly will not be processed + yet, so process it */ + if (node->parent == NULL) + { + if (node->tree->root == NULL) + { + assert (node->tree->count == 0); + node->parent = NULL; + node->bl_left = NULL; + node->bl_right = NULL; + node->data = NULL; + return; + } + else if (node->tree->root->data != node->data) + next = node->tree->root; + } + else if (node->parent->link[node->parent_link] == NULL) + { + if (node->parent_link == BL_LEFT) + next = node->parent; + else + { + GOTO_PROCED_SUBTREE_TOP (node); + next = node->parent; + } + } + else if (node->parent->link[node->parent_link]->data != node->data) + next = node->parent->link[node->parent_link]; + + if (next == NULL) + { + if (node->bl_right) + next = bintree_lookup_node_min (node->bl_right); + else + { + GOTO_PROCED_SUBTREE_TOP (node); + next = node->parent; + } + } + + if (next) + { + node->tree = next->tree; + node->parent = next->parent; + node->parent_link = next->parent_link; + node->bl_left = next->bl_left; + node->bl_right = next->bl_right; + node->data = next->data; + } + else + { + node->parent = NULL; + node->bl_left = NULL; + node->bl_right = NULL; + node->data = NULL; + } +} + +struct bintree * +bintree_create () +{ + struct bintree *tree; + + tree = malloc (sizeof (struct bintree)); + memset (tree, 0, sizeof (struct bintree)); + + return tree; +} + +void +bintree_delete (struct bintree *tree) +{ + struct bintree_node node; + + for (bintree_head (tree, &node); ! bintree_end (&node); + bintree_next (&node)) + bintree_remove (node.data, tree); + + assert (tree->count == 0); + free (tree); +} + +int indent_num = 0; + +void +bintree_print_sub (void (*print) (int, void *), struct bintree_node *subroot) +{ + if (subroot == NULL) + return; + + if (subroot->bl_right) + { + indent_num++; + bintree_print_sub (print, subroot->bl_right); + indent_num--; + } + + (*print) (indent_num, subroot->data); + + if (subroot->bl_left) + { + indent_num++; + bintree_print_sub (print, subroot->bl_left); + indent_num--; + } +} + +void +bintree_print (void (*print) (int, void *), struct bintree *tree) +{ + indent_num = 0; + bintree_print_sub (print, tree->root); +} + + diff --git a/ospf6d/ospf6_bintree.h b/ospf6d/ospf6_bintree.h new file mode 100644 index 000000000..fad8bbdd4 --- /dev/null +++ b/ospf6d/ospf6_bintree.h @@ -0,0 +1,47 @@ + +#ifndef _BINTREE_H_ +#define _BINTREE_H_ + +struct bintree_node +{ + struct bintree *tree; + + struct bintree_node *parent; + int parent_link; + +#define BL_LEFT 0 +#define BL_RIGHT 1 +#define BL_MAX 2 + struct bintree_node *link[BL_MAX]; +#define bl_left link[BL_LEFT] +#define bl_right link[BL_RIGHT] + + void *data; +}; + +struct bintree +{ + int count; + struct bintree_node *root; + + int (*cmp) (void *, void *); +}; + +void *bintree_lookup (void *data, struct bintree *tree); +void *bintree_lookup_min (struct bintree *tree); +void *bintree_lookup_max (struct bintree *tree); + +int bintree_add (void *data, struct bintree *tree); +int bintree_remove (void *data, struct bintree *tree); + +void bintree_head (struct bintree *tree, struct bintree_node *node); +int bintree_end (struct bintree_node *node); +void bintree_next (struct bintree_node *node); + +struct bintree *bintree_create (); +void bintree_delete (struct bintree *); + +void bintree_print (void (*print) (int, void *), struct bintree *); + +#endif /*_BINTREE_H_*/ + diff --git a/ospf6d/ospf6_damp.c b/ospf6d/ospf6_damp.c new file mode 100644 index 000000000..4e807a70e --- /dev/null +++ b/ospf6d/ospf6_damp.c @@ -0,0 +1,748 @@ +/* + * OSPF flap dampening by Manav Bhatia + * Copyright (C) 2002 + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> +#include <math.h> + +#include "log.h" +#include "prefix.h" +#include "thread.h" +#include "table.h" +#include "command.h" +#include "vty.h" + +extern struct thread_master *master; + +#include "ospf6_damp.h" + +#ifdef HAVE_OSPF6_DAMP + +#define DELTA_REUSE 10 /* Time granularity for reuse lists */ +#define DELTA_T 5 /* Time granularity for decay arrays */ +#define DEFAULT_HALF_LIFE 60 /* (sec) 1 min */ + +#define DEFAULT_PENALTY 1000 +#define DEFAULT_REUSE 750 +#define DEFAULT_SUPPRESS 2000 + +#define REUSE_LIST_SIZE 256 +#define REUSE_ARRAY_SIZE 1024 + +/* Global variable to access damping configuration */ +struct ospf6_damp_config damp_config; +struct ospf6_damp_config *dc = &damp_config; +u_int reuse_array_offset = 0; +struct route_table *damp_info_table[OSPF6_DAMP_TYPE_MAX]; +struct thread *ospf6_reuse_thread = NULL; + +int ospf6_damp_debug = 0; +#define IS_OSPF6_DEBUG_DAMP (ospf6_damp_debug) + +static struct ospf6_damp_info * +ospf6_damp_lookup (u_short type, struct prefix *name) +{ + struct route_node *node; + + node = route_node_lookup (damp_info_table[type], name); + if (node && node->info) + return (struct ospf6_damp_info *) node->info; + return NULL; +} + +static struct ospf6_damp_info * +ospf6_damp_create (u_short type, struct prefix *name) +{ + struct route_node *node; + struct ospf6_damp_info *di; + char namebuf[64]; + + di = ospf6_damp_lookup (type, name); + if (di) + return di; + + if (IS_OSPF6_DEBUG_DAMP) + { + prefix2str (name, namebuf, sizeof (namebuf)); + zlog_info ("DAMP: create: type: %d, name: %s", type, namebuf); + } + + di = (struct ospf6_damp_info *) + malloc (sizeof (struct ospf6_damp_info)); + memset (di, 0, sizeof (struct ospf6_damp_info)); + di->type = type; + prefix_copy (&di->name, name); + + node = route_node_get (damp_info_table[type], name); + node->info = di; + + return di; +} + +static void +ospf6_damp_delete (u_short type, struct prefix *name) +{ + struct route_node *node; + struct ospf6_damp_info *di; + char namebuf[64]; + + node = route_node_lookup (damp_info_table[type], name); + if (! node || ! node->info) + return; + + di = node->info; + + if (IS_OSPF6_DEBUG_DAMP) + { + prefix2str (&di->name, namebuf, sizeof (namebuf)); + zlog_info ("DAMP: delete: type: %d, name: %s", + di->type, namebuf); + } + + node->info = NULL; + free (di); +} + +/* compute and fill the configuration parameter */ +void +ospf6_damp_init_config (u_int half_life, u_int reuse, + u_int suppress, u_int t_hold) +{ + int i; + double max_ratio, max_ratio1, max_ratio2; + + dc->half_life = half_life ? half_life : DEFAULT_HALF_LIFE; + dc->reuse = reuse ? reuse : DEFAULT_REUSE; + dc->suppress = suppress ? suppress : DEFAULT_SUPPRESS; + dc->t_hold = t_hold ? t_hold : 4 * dc->half_life; + + /* Initialize system-wide params */ + dc->delta_t = DELTA_T; + dc->delta_reuse = DELTA_REUSE; + dc->default_penalty = DEFAULT_PENALTY; + dc->reuse_index_array_size = REUSE_ARRAY_SIZE; + + /* ceiling is the maximum penalty a route may attain */ + /* ceiling = reuse * 2^(T-hold/half-life) */ + dc->ceiling = (int) + (dc->reuse * (pow (2, (double) dc->t_hold / dc->half_life))); + + /* Decay-array computations */ + /* decay_array_size = decay memory/time granularity */ + dc->decay_array_size = ceil ((double) dc->t_hold / dc->delta_t); + dc->decay_array = malloc (sizeof (double) * (dc->decay_array_size)); + + /* Each i-th element is per tick delay raised to the i-th power */ + dc->decay_array[0] = 1.0; + dc->decay_array[1] = exp ((1.0 / (dc->half_life / dc->delta_t)) * log (0.5)); + for (i = 2; i < dc->decay_array_size; i++) + dc->decay_array[i] = dc->decay_array[i - 1] * dc->decay_array[1]; + + /* Reuse-list computations (reuse queue head array ?) */ + dc->reuse_list_size = ceil ((double) dc->t_hold / dc->delta_reuse) + 1; + if (dc->reuse_list_size == 0 || dc->reuse_list_size > REUSE_LIST_SIZE) + dc->reuse_list_size = REUSE_LIST_SIZE; + dc->reuse_list_array = (struct ospf6_damp_info **) + malloc (dc->reuse_list_size * sizeof (struct ospf6_reuse_list *)); + memset (dc->reuse_list_array, 0x00, + dc->reuse_list_size * sizeof (struct ospf6_reuse_list *)); + + /* Reuse-array computations */ + dc->reuse_index_array = malloc (sizeof (int) * dc->reuse_index_array_size); + + /* + * This is the maximum ratio between the current value of the penalty and + * the reuse value which can be indexed by the reuse array. It will be + * limited by the ceiling or by the amount of time that the reuse list + * covers + */ + max_ratio1 = (double) dc->ceiling / dc->reuse; + max_ratio2 = exp ((double) dc->t_hold / dc->half_life) * log10 (2.0); + max_ratio = (max_ratio2 != 0 && max_ratio2 < max_ratio1 ? + max_ratio2 : max_ratio1); + + /* + * reuse array is just an estimator and we need something + * to use the full array + */ + dc->scale_factor = (double) dc->reuse_index_array_size / (max_ratio - 1); + + for (i = 0; i < dc->reuse_index_array_size; i++) + { + dc->reuse_index_array[i] = (int) + (((double) dc->half_life / dc->delta_reuse) * + log10 (1.0 / (dc->reuse * (1.0 + ((double) i / dc->scale_factor)))) + / log10 (0.5)); + } + + dc->enabled = ON; +} + +static double +ospf6_damp_decay (time_t tdiff) +{ + int index = tdiff / dc->delta_t; + + if (index >= dc->decay_array_size) + return 0; + + return dc->decay_array[index]; +} + +static int +ospf6_damp_reuse_index (int penalty) +{ + int index; + + index = (int) (((double) penalty / dc->reuse - 1.0) * dc->scale_factor); + + if (index >= dc->reuse_index_array_size) + index = dc->reuse_index_array_size - 1; + + return (dc->reuse_index_array[index] - dc->reuse_index_array[0]); +} + +static int +ospf6_reuse_list_lookup (struct ospf6_damp_info *di) +{ + struct ospf6_damp_info *info; + + for (info = dc->reuse_list_array[di->index]; info; info = info->next) + { + if (info == di) + return 1; + } + return 0; +} + +static void +ospf6_reuse_list_remove (struct ospf6_damp_info *di) +{ + if (di->prev) + di->prev->next = di->next; + else + dc->reuse_list_array[di->index] = di->next; + if (di->next) + di->next->prev = di->prev; + + di->index = -1; + di->prev = NULL; + di->next = NULL; +} + +static void +ospf6_reuse_list_add (struct ospf6_damp_info *di) +{ + /* set the index of reuse-array */ + di->index = (reuse_array_offset + (ospf6_damp_reuse_index (di->penalty))) + % dc->reuse_list_size; + + /* insert to the head of the reuse list */ + di->next = dc->reuse_list_array[di->index]; + if (di->next) + di->next->prev = di; + di->prev = NULL; + dc->reuse_list_array[di->index] = di; +} + +/* When we quit damping for a target, we should execute proper event + which have been postponed during damping */ +static void +ospf6_damp_stop (struct ospf6_damp_info *di) +{ + time_t t_now; + char namebuf[64]; + struct timeval now; + + if (IS_OSPF6_DEBUG_DAMP) + { + t_now = time (NULL); + prefix2str (&di->name, namebuf, sizeof (namebuf)); + gettimeofday (&now, NULL); + zlog_info ("DAMP: %lu.%06lu stop damping: %ld: type: %d, name: %s", + now.tv_sec, now.tv_usec, + t_now, di->type, namebuf); + } + + /* set flag indicates that we're damping this target */ + di->damping = OFF; + + /* if the target's current status differ from that it should be, + execute the proper event to repair his status */ + if (di->target_status != di->event_type) + { + (*(di->event)) (di->target); + di->target_status = di->event_type; + + di->event = NULL; + di->event_type = event_none; + } +} + +/* ospf6_reuse_timer is called every DELTA_REUSE seconds. + Each route in the current reuse-list is evaluated + and is used or requeued */ +int +ospf6_damp_reuse_timer (struct thread *t) +{ + struct ospf6_damp_info *di, *next; + time_t t_now, t_diff; + char namebuf[64]; + struct timeval now; + + /* Restart the reuse timer */ + ospf6_reuse_thread = + thread_add_timer (master, ospf6_damp_reuse_timer, NULL, dc->delta_reuse); + + t_now = time (NULL); + + /* get the damp info list head */ + di = dc->reuse_list_array[reuse_array_offset]; + dc->reuse_list_array[reuse_array_offset] = NULL; + + /* rotate the circular reuse list head array */ + reuse_array_offset = (reuse_array_offset + 1) % dc->reuse_list_size; + + /* for each damp info */ + while (di) + { + next = di->next; + di->next = NULL; + + /* Update penalty */ + t_diff = t_now - di->t_updated; + di->t_updated = t_now; + di->penalty = (int) + ((double) di->penalty * ospf6_damp_decay (t_diff)); + /* configration of ceiling may be just changed */ + if (di->penalty > dc->ceiling) + di->penalty = dc->ceiling; + + if (IS_OSPF6_DEBUG_DAMP) + { + prefix2str (&di->name, namebuf, sizeof (namebuf)); + gettimeofday (&now, NULL); + zlog_info ("DAMP: %lu.%06lu update penalty: type: %d, name: %s, penalty: %d", + now.tv_sec, now.tv_usec, + di->type, namebuf, di->penalty); + } + + /* If the penalty becomes under reuse, + call real event that we have been postponed. */ + if (di->penalty < dc->reuse && di->damping == ON) + ospf6_damp_stop (di); + + /* If the penalty becomes less than the half of the + reuse value, this damp info will be freed from reuse-list, + by assuming that it is considered to be stable enough already, + and there's no need to maintain flapping history for this. */ + if (di->penalty <= dc->reuse / 2) + { + ospf6_damp_delete (di->type, &di->name); + di = next; + continue; + } + + /* re-insert to the reuse-list */ + ospf6_reuse_list_add (di); + + di = next; + } + + return 0; +} + +static void +ospf6_damp_event (damp_event_t event_type, + u_short type, struct prefix *name, + int (*event) (void *), void *target) +{ + time_t t_now, t_diff; + struct ospf6_damp_info *di; + char namebuf[64]; + struct timeval now; + + if (dc->enabled == OFF) + { + (*event) (target); + return; + } + + di = ospf6_damp_lookup (type, name); + if (! di) + di = ospf6_damp_create (type, name); + + t_now = time (NULL); + + di->event = event; + di->target = target; + di->event_type = event_type; + + if (! ospf6_reuse_list_lookup (di)) + di->t_start = t_now; + else + { + ospf6_reuse_list_remove (di); + + t_diff = t_now - di->t_updated; + di->penalty = (int) (di->penalty * ospf6_damp_decay (t_diff)); + } + + /* penalty only on down event */ + if (event_type == event_down) + { + di->flap++; + di->penalty += dc->default_penalty; + } + + /* limit penalty up to ceiling */ + if (di->penalty > dc->ceiling) + di->penalty = dc->ceiling; + + if (IS_OSPF6_DEBUG_DAMP) + { + prefix2str (&di->name, namebuf, sizeof (namebuf)); + gettimeofday (&now, NULL); + zlog_info ("DAMP: %lu.%06lu update penalty: type: %d, name: %s, penalty: %d", + now.tv_sec, now.tv_usec, + di->type, namebuf, di->penalty); + } + + /* if penalty < reuse, stop damping here */ + if (di->penalty < dc->reuse && di->damping == ON) + { + if (IS_OSPF6_DEBUG_DAMP) + { + prefix2str (&di->name, namebuf, sizeof (namebuf)); + gettimeofday (&now, NULL); + zlog_info ("DAMP: %lu.%06lu stop damping: %ld: type: %d, name: %s", + now.tv_sec, now.tv_usec, + t_now, di->type, namebuf); + } + di->damping = OFF; + } + + /* if event == up and if penalty >= suppress , start damping here */ + if (di->event_type == event_up && di->penalty >= dc->suppress && + di->damping == OFF) + { + if (IS_OSPF6_DEBUG_DAMP) + { + prefix2str (&di->name, namebuf, sizeof (namebuf)); + gettimeofday (&now, NULL); + zlog_info ("DAMP: %lu.%06lu start damping: %ld: type: %d, name: %s", + now.tv_sec, now.tv_usec, + t_now, type, namebuf); + } + di->damping = ON; + } + + /* execute event if we're not damping */ + if (di->damping == OFF) + { + (*(di->event)) (di->target); + di->target_status = di->event_type; + } + + /* if the penalty goes beyond suppress value, start damping */ + if (di->penalty >= dc->suppress && di->damping == OFF) + { + if (IS_OSPF6_DEBUG_DAMP) + { + prefix2str (name, namebuf, sizeof (namebuf)); + gettimeofday (&now, NULL); + zlog_info ("DAMP: %lu.%06lu start damping: %ld: type: %d, name: %s", + now.tv_sec, now.tv_usec, + t_now, type, namebuf); + } + di->damping = ON; + } + + /* update last-updated-time field */ + di->t_updated = t_now; + + /* Insert it into the reuse list */ + ospf6_reuse_list_add (di); +} + +void +ospf6_damp_event_up (u_short type, struct prefix *name, + int (*event) (void *), void *target) +{ + struct timeval now; + + gettimeofday (&now, NULL); + if (IS_OSPF6_DEBUG_DAMP) + zlog_info ("DAMP: Up Event at %lu.%06lu", now.tv_sec, now.tv_usec); + + ospf6_damp_event (event_up, type, name, event, target); +} + +void +ospf6_damp_event_down (u_short type, struct prefix *name, + int (*event) (void *), void *target) +{ + struct timeval now; + + gettimeofday (&now, NULL); + if (IS_OSPF6_DEBUG_DAMP) + zlog_info ("DAMP: Down Event at %lu.%06lu", now.tv_sec, now.tv_usec); + + ospf6_damp_event (event_down, type, name, event, target); +} + +int +ospf6_damp_debug_thread (struct thread *thread) +{ + int i; + struct ospf6_damp_info *di; + char buf[256]; + time_t t_now; + struct timeval now; + + for (i = 0; i < dc->reuse_list_size; i++) + { + for (di = dc->reuse_list_array[i]; di; di = di->next) + { + t_now = time (NULL); + gettimeofday (&now, NULL); + prefix2str (&di->name, buf, sizeof (buf)); + zlog_info ("DAMP: %lu.%06lu %c %-32s penalty %7u", + now.tv_sec, now.tv_usec, + (di->damping == ON ? 'D' : 'A'), buf, + (u_int) (di->penalty * + ospf6_damp_decay (t_now - di->t_updated))); + } + } + thread_add_timer (master, ospf6_damp_debug_thread, NULL, 1); + return 0; +} + +DEFUN (show_ipv6_ospf6_route_flapping, + show_ipv6_ospf6_route_flapping_cmd, + "show ipv6 ospf6 route flapping", + SHOW_STR + IP6_STR + OSPF6_STR) +{ + int i; + struct ospf6_damp_info *di; + char buf[256]; + time_t t_now; + + t_now = time (NULL); + vty_out (vty, "%c %-32s %7s%s", ' ', "Prefix", "penalty", VTY_NEWLINE); + + for (i = 0; i < dc->reuse_list_size; i++) + { + for (di = dc->reuse_list_array[i]; di; di = di->next) + { + prefix2str (&di->name, buf, sizeof (buf)); + vty_out (vty, "%c %-32s %7u%s", + (di->damping == ON ? 'D' : ' '), buf, + (u_int) (di->penalty * + ospf6_damp_decay (t_now - di->t_updated)), + VTY_NEWLINE); + } + } + + return CMD_SUCCESS; +} + +DEFUN (flap_damping_route, + flap_damping_route_cmd, + "flap-damping route <0-4294967295> <0-4294967295> " + "<0-4294967295> <0-4294967295>", + "enable flap dampening\n" + "enable route flap dampening\n" + "half-life in second\n" + "reuse value\n" + "suppress value\n" + "t-hold in second (maximum time that the target can be damped)\n" + ) +{ + u_int half_life, reuse, suppress, t_hold; + + if (argc) + { + half_life = (u_int) strtoul (argv[0], NULL, 10); + reuse = (u_int) strtoul (argv[1], NULL, 10); + suppress = (u_int) strtoul (argv[2], NULL, 10); + t_hold = (u_int) strtoul (argv[3], NULL, 10); + } + else + { + half_life = (u_int) DEFAULT_HALF_LIFE; + reuse = (u_int) DEFAULT_REUSE; + suppress = (u_int) DEFAULT_SUPPRESS; + t_hold = (u_int) DEFAULT_HALF_LIFE * 4; + } + + if (reuse && suppress && reuse >= suppress) + { + vty_out (vty, "reuse value exceeded suppress value, failed%s\n", + VTY_NEWLINE); + return CMD_SUCCESS; + } + + if (half_life && t_hold && half_life >= t_hold) + { + vty_out (vty, "half-life exceeded t-hold, failed%s\n", VTY_NEWLINE); + return CMD_SUCCESS; + } + + ospf6_damp_init_config (half_life, reuse, suppress, t_hold); + + if (ospf6_reuse_thread == NULL) + ospf6_reuse_thread = + thread_add_timer (master, ospf6_damp_reuse_timer, NULL, dc->delta_reuse); + + return CMD_SUCCESS; +} + +DEFUN (show_ipv6_ospf6_damp_config, + show_ipv6_ospf6_camp_config_cmd, + "show ipv6 ospf6 damp config", + SHOW_STR + IP6_STR + OSPF6_STR + "Flap-dampening information\n" + "shows dampening configuration\n" + ) +{ + int i; + + vty_out (vty, "%10s %10s %10s %10s%s", + "Half life", "Suppress", "Reuse", "T-hold", + VTY_NEWLINE); + vty_out (vty, "%10u %10u %10u %10u%s", + dc->half_life, dc->suppress, dc->reuse, dc->t_hold, + VTY_NEWLINE); + vty_out (vty, "%s", VTY_NEWLINE); + + vty_out (vty, "Delta-t = %u%s", dc->delta_t, VTY_NEWLINE); + vty_out (vty, "Delta-Reuse = %u%s", dc->delta_reuse, VTY_NEWLINE); + vty_out (vty, "Default-Penalty = %u%s", dc->default_penalty, VTY_NEWLINE); + vty_out (vty, "Ceiling = %u%s", dc->ceiling, VTY_NEWLINE); + vty_out (vty, "ScaleFactor = %f%s", dc->scale_factor, VTY_NEWLINE); + + vty_out (vty, "DecayArray(%d) =%s", dc->decay_array_size, VTY_NEWLINE); + for (i = 0; i < dc->decay_array_size; i++) + { + if (i % 10 == 0) + vty_out (vty, " "); + vty_out (vty, " %f", dc->decay_array[i]); + if (i % 10 == 0) + vty_out (vty, "%s", VTY_NEWLINE); + } + vty_out (vty, "%s", VTY_NEWLINE); + + vty_out (vty, "ReuseIndexArray(%d) =%s", + dc->reuse_index_array_size, VTY_NEWLINE); + for (i = 0; i < dc->reuse_index_array_size; i++) + { + if (i % 10 == 0) + vty_out (vty, " "); + vty_out (vty, " %d", dc->reuse_index_array[i]); + if (i % 10 == 0) + vty_out (vty, "%s", VTY_NEWLINE); + } + vty_out (vty, "%s", VTY_NEWLINE); + + return CMD_SUCCESS; +} + +void +ospf6_damp_config_write (struct vty *vty) +{ + if (dc->enabled == ON) + { + vty_out (vty, " flap-damping route %u %u %u %u%s", + dc->half_life, dc->reuse, dc->suppress, dc->t_hold, + VTY_NEWLINE); + } +} + +DEFUN (debug_ospf6_damp, + debug_ospf6_damp_cmd, + "debug ospf6 damp", + DEBUG_STR + OSPF6_STR + "Flap-dampening information\n" + ) +{ + ospf6_damp_debug = 1; + return CMD_SUCCESS; +} + +DEFUN (no_debug_ospf6_damp, + no_debug_ospf6_damp_cmd, + "no debug ospf6 damp", + NO_STR + DEBUG_STR + OSPF6_STR + "Flap-dampening information\n" + ) +{ + ospf6_damp_debug = 0; + return CMD_SUCCESS; +} + +DEFUN (show_debug_ospf6_damp, + show_debug_ospf6_damp_cmd, + "show debugging ospf6 damp", + SHOW_STR + DEBUG_STR + OSPF6_STR + "Flap-dampening information\n" + ) +{ + vty_out (vty, "debugging ospf6 damp is "); + if (IS_OSPF6_DEBUG_DAMP) + vty_out (vty, "enabled."); + else + vty_out (vty, "disabled."); + vty_out (vty, "%s", VTY_NEWLINE); + return CMD_SUCCESS; +} + +void +ospf6_damp_init () +{ + int i; + for (i = 0; i < OSPF6_DAMP_TYPE_MAX; i++) + damp_info_table[i] = route_table_init (); + + install_element (VIEW_NODE, &show_ipv6_ospf6_route_flapping_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_route_flapping_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_camp_config_cmd); + install_element (OSPF6_NODE, &flap_damping_route_cmd); + + install_element (ENABLE_NODE, &show_debug_ospf6_damp_cmd); + install_element (CONFIG_NODE, &debug_ospf6_damp_cmd); + install_element (CONFIG_NODE, &no_debug_ospf6_damp_cmd); + + thread_add_event (master, ospf6_damp_debug_thread, NULL, 0); +} + +#endif /* HAVE_OSPF6_DAMP */ + + diff --git a/ospf6d/ospf6_damp.h b/ospf6d/ospf6_damp.h new file mode 100644 index 000000000..19bdbc7af --- /dev/null +++ b/ospf6d/ospf6_damp.h @@ -0,0 +1,109 @@ +/* + * OSPF flap dampening by Manav Bhatia + * Copyright (C) 2002 + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +/* + * Flap Damping (target e.g. link/route) + */ + +#define HAVE_OSPF6_DAMP + +typedef enum +{ + OFF, + ON, +} onoff_t; + +typedef enum +{ + event_none, + event_up, + event_down, +} damp_event_t; + +/* Structure maintained per target basis */ +struct ospf6_damp_info +{ + /* identifier to decide which target */ + u_short type; + struct prefix name; + + /* do we damping this info */ + onoff_t damping; + + u_int penalty; + u_int flap; + time_t t_start; /* First flap (down event) time */ + time_t t_updated; /* Last time the penalty was updated */ + + /* index and double-link for reuse list */ + int index; + struct ospf6_damp_info *next; + struct ospf6_damp_info *prev; + + /* the last event that we are avoiding */ + int (*event) (void *target); + void *target; + damp_event_t event_type; + damp_event_t target_status; +}; + +#define OSPF6_DAMP_TYPE_ROUTE 0 +#define OSPF6_DAMP_TYPE_MAX 1 + +/* Global Configuration Parameters */ +struct ospf6_damp_config +{ + /* is damping enabled ? */ + onoff_t enabled; + + /* configurable parameters */ + u_int half_life; + u_int suppress; + u_int reuse; + u_int t_hold; /* Maximum hold down time */ + + /* Non configurable parameters */ + u_int delta_t; + u_int delta_reuse; + u_int default_penalty; + u_int ceiling; /* Max value a penalty can attain */ + double scale_factor; + + int decay_array_size; /* Calculated using config parameters */ + double *decay_array; /* Storage for decay values */ + + int reuse_index_array_size; /* Size of reuse index array */ + int *reuse_index_array; + + int reuse_list_size; /* Number of reuse lists */ + struct ospf6_damp_info **reuse_list_array; +}; + +int ospf6_damp_reuse_timer (struct thread *); +void ospf6_damp_event_up (u_short type, struct prefix *name, + int (*exec_up) (void *), void *target); +void ospf6_damp_event_down (u_short type, struct prefix *name, + int (*exec_down) (void *), void *target); + +void ospf6_damp_config_write (struct vty *); +void ospf6_damp_init (); + diff --git a/ospf6d/ospf6_dbex.c b/ospf6d/ospf6_dbex.c new file mode 100644 index 000000000..b10d9aebb --- /dev/null +++ b/ospf6d/ospf6_dbex.c @@ -0,0 +1,704 @@ +/* + * Copyright (C) 1999 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "ospf6d.h" + +/* check validity and put lsa in reqestlist if needed. */ +/* returns -1 if SeqNumMismatch required. */ +int +ospf6_dbex_check_dbdesc_lsa_header (struct ospf6_lsa_header *lsa_header, + struct ospf6_neighbor *from) +{ + struct ospf6_lsa *received = NULL; + struct ospf6_lsa *have = NULL; + + received = ospf6_lsa_summary_create + ((struct ospf6_lsa_header__ *) lsa_header); + + /* case when received is AS-External though neighbor belongs stub area */ + if (lsa_header->type == htons (OSPF6_LSA_TYPE_AS_EXTERNAL) && + ospf6_area_is_stub (from->ospf6_interface->area)) + { + zlog_err ("DbDesc %s receive from %s", from->str, received->str); + zlog_err (" E-bit mismatch: %s", received->str); + ospf6_lsa_delete (received); + return -1; + } + + /* if already have newer database copy, check next LSA */ + have = ospf6_lsdb_lookup (lsa_header->type, lsa_header->ls_id, + lsa_header->advrtr, + ospf6_lsa_get_scope (lsa_header->type, + from->ospf6_interface)); + if (! have) + { + /* if we don't have database copy, add request */ + if (IS_OSPF6_DUMP_DBEX) + zlog_info ("Have no database copy, Request"); + ospf6_neighbor_request_add (received, from); + } + else if (have) + { + /* if database copy is less recent, add request */ + if (ospf6_lsa_check_recent (received, have) < 0) + { + if (IS_OSPF6_DUMP_DBEX) + zlog_info ("Database copy less recent, Request"); + ospf6_neighbor_request_add (received, from); + } + } + + return 0; +} + +/* Direct acknowledgement */ +static void +ospf6_dbex_acknowledge_direct (struct ospf6_lsa *lsa, + struct ospf6_neighbor *o6n) +{ + struct iovec directack[MAXIOVLIST]; + assert (lsa); + + if (IS_OSPF6_DUMP_DBEX) + zlog_info ("DBEX: [%s:%s] direct ack %s ", + o6n->str, o6n->ospf6_interface->interface->name, + lsa->str); + + /* clear pointers to fragments of packet for direct acknowledgement */ + iov_clear (directack, MAXIOVLIST); + + /* set pointer of LSA to send */ + OSPF6_MESSAGE_ATTACH (directack, lsa->header, + sizeof (struct ospf6_lsa_header)); + + /* age update and add InfTransDelay */ + ospf6_lsa_age_update_to_send (lsa, o6n->ospf6_interface->transdelay); + + /* send unicast packet to neighbor's ipaddress */ + ospf6_message_send (OSPF6_MESSAGE_TYPE_LSACK, directack, &o6n->hisaddr, + o6n->ospf6_interface->if_id); +} + +/* Delayed acknowledgement */ +void +ospf6_dbex_acknowledge_delayed (struct ospf6_lsa *lsa, + struct ospf6_interface *o6i) +{ + assert (o6i); + + if (IS_OSPF6_DUMP_DBEX) + zlog_info ("DBEX: [%s] delayed ack %s", o6i->interface->name, lsa->str); + + /* attach delayed acknowledge list */ + ospf6_lsa_age_current (lsa); + ospf6_interface_delayed_ack_add (lsa, o6i); + + /* if not yet, schedule delayed acknowledge RxmtInterval later. + timers should be *less than* RxmtInterval + or needless retrans will ensue */ + if (o6i->thread_send_lsack_delayed == NULL) + o6i->thread_send_lsack_delayed + = thread_add_timer (master, ospf6_send_lsack_delayed, + o6i, o6i->rxmt_interval - 1); + + return; +} + +/* RFC2328 section 13 (4): + if MaxAge LSA and if we have no instance, and no neighbor + is in states Exchange or Loading */ +/* returns 1 if match this case, else returns 0 */ +static int +ospf6_dbex_is_maxage_to_be_dropped (struct ospf6_lsa *received, + struct ospf6_neighbor *from) +{ + int count; + + if (! IS_LSA_MAXAGE (received)) + return 0; + + if (ospf6_lsdb_lookup (received->header->type, received->header->id, + received->header->adv_router, + ospf6_lsa_get_scope (received->header->type, + from->ospf6_interface))) + return 0; + + if (OSPF6_LSA_IS_SCOPE_LINKLOCAL (ntohs (received->header->type))) + { + count = 0; + (*from->ospf6_interface->foreach_nei) + (from->ospf6_interface, &count, NBS_EXCHANGE, ospf6_count_state); + (*from->ospf6_interface->foreach_nei) + (from->ospf6_interface, &count, NBS_LOADING, ospf6_count_state); + if (count) + return 0; + } + else if (OSPF6_LSA_IS_SCOPE_AREA (ntohs (received->header->type))) + { + count = 0; + (*from->ospf6_interface->area->foreach_nei) + (from->ospf6_interface->area, &count, NBS_EXCHANGE, ospf6_count_state); + (*from->ospf6_interface->area->foreach_nei) + (from->ospf6_interface->area, &count, NBS_LOADING, ospf6_count_state); + if (count) + return 0; + } + else if (OSPF6_LSA_IS_SCOPE_AS (ntohs (received->header->type))) + { + count = 0; + (*from->ospf6_interface->area->ospf6->foreach_nei) + (from->ospf6_interface->area->ospf6, &count, NBS_EXCHANGE, + ospf6_count_state); + (*from->ospf6_interface->area->ospf6->foreach_nei) + (from->ospf6_interface->area->ospf6, &count, NBS_LOADING, + ospf6_count_state); + if (count) + return 0; + } + + return 1; +} + +static void +ospf6_dbex_remove_retrans (void *arg, int val, void *obj) +{ + struct ospf6_lsa *rem; + struct ospf6_neighbor *nei = (struct ospf6_neighbor *) obj; + struct ospf6_lsa *lsa = (struct ospf6_lsa *) arg; + + rem = ospf6_lsdb_lookup_lsdb (lsa->header->type, lsa->header->id, + lsa->header->adv_router, nei->retrans_list); + if (rem) + { + ospf6_neighbor_retrans_remove (rem, nei); + ospf6_maxage_remover (); + } +} + +void +ospf6_dbex_remove_from_all_retrans_list (struct ospf6_lsa *lsa) +{ + struct ospf6_interface *o6i; + struct ospf6_area *o6a; + + if (OSPF6_LSA_IS_SCOPE_LINKLOCAL (htons (lsa->header->type))) + { + o6i = lsa->scope; + (*o6i->foreach_nei) (o6i, lsa, 0, ospf6_dbex_remove_retrans); + } + else if (OSPF6_LSA_IS_SCOPE_AREA (htons (lsa->header->type))) + { + o6a = lsa->scope; + (*o6a->foreach_nei) (o6a, lsa, 0, ospf6_dbex_remove_retrans); + } + else if (OSPF6_LSA_IS_SCOPE_AS (htons (lsa->header->type))) + { + (*ospf6->foreach_nei) (ospf6, lsa, 0, ospf6_dbex_remove_retrans); + } +} + +/* RFC2328 section 13 */ +void +ospf6_dbex_receive_lsa (struct ospf6_lsa_header *lsa_header, + struct ospf6_neighbor *from) +{ + struct ospf6_lsa *received, *have, *rem; + struct timeval now; + int ismore_recent, acktype; + unsigned short cksum; + struct ospf6_lsa_slot *slot; + + received = have = (struct ospf6_lsa *)NULL; + ismore_recent = -1; + recent_reason = "no instance"; + + zlog_info ("Receive LSA (header -> %p)", lsa_header); + + /* make lsa structure for received lsa */ + received = ospf6_lsa_create (lsa_header); + + /* set LSA scope */ + if (OSPF6_LSA_IS_SCOPE_LINKLOCAL (htons (lsa_header->type))) + received->scope = from->ospf6_interface; + else if (OSPF6_LSA_IS_SCOPE_AREA (htons (lsa_header->type))) + received->scope = from->ospf6_interface->area; + else if (OSPF6_LSA_IS_SCOPE_AS (htons (lsa_header->type))) + received->scope = from->ospf6_interface->area->ospf6; + + /* (1) LSA Checksum */ + cksum = ntohs (lsa_header->checksum); + if (ntohs (ospf6_lsa_checksum (lsa_header)) != cksum) + { + if (IS_OSPF6_DUMP_DBEX) + zlog_info ("DBEX: received %s from %s%%%s" + ": wrong checksum, drop", + received->str, from->str, + from->ospf6_interface->interface->name); + ospf6_lsa_delete (received); + return; + } + + /* (3) Ebit Missmatch: AS-External-LSA */ + if (lsa_header->type == htons (OSPF6_LSA_TYPE_AS_EXTERNAL) && + ospf6_area_is_stub (from->ospf6_interface->area)) + { + if (IS_OSPF6_DUMP_DBEX) + zlog_info ("DBEX: received %s from %s%%%s" + ": E-bit mismatch, drop", + received->str, from->str, + from->ospf6_interface->interface->name); + ospf6_lsa_delete (received); + return; + } + + /* (4) if MaxAge LSA and if we have no instance, and no neighbor + is in states Exchange or Loading */ + if (ospf6_dbex_is_maxage_to_be_dropped (received, from)) + { + /* log */ + if (IS_OSPF6_DUMP_DBEX) + zlog_info ("DBEX: received %s from %s%%%s" + ": MaxAge, no instance, no neighbor exchange, drop", + received->str, from->str, + from->ospf6_interface->interface->name); + + /* a) Acknowledge back to neighbor (13.5) */ + /* Direct Acknowledgement */ + ospf6_dbex_acknowledge_direct (received, from); + + /* b) Discard */ + ospf6_lsa_delete (received); + return; + } + + /* (5) */ + /* lookup the same database copy in lsdb */ + have = ospf6_lsdb_lookup (lsa_header->type, lsa_header->ls_id, + lsa_header->advrtr, + ospf6_lsa_get_scope (lsa_header->type, + from->ospf6_interface)); + if (have) + { + ismore_recent = ospf6_lsa_check_recent (received, have); + if (ntohl (received->header->seqnum) == ntohl (have->header->seqnum)) + SET_FLAG (received->flag, OSPF6_LSA_FLAG_DUPLICATE); + } + + /* if no database copy or received is more recent */ + if (!have || ismore_recent < 0) + { + /* in case we have no database copy */ + ismore_recent = -1; + + /* (a) MinLSArrival check */ + gettimeofday (&now, (struct timezone *)NULL); + if (have && SEC_TVDIFF (&now, &have->installed) < OSPF6_MIN_LS_ARRIVAL) + { + //if (IS_OSPF6_DUMP_DBEX) + zlog_info ("DBEX: Receive new LSA from %s: %s seq: %#x age: %d " + "within MinLSArrival, drop: %ld.%06ld", + from->str, received->str, + ntohl (received->header->seqnum), + ntohs (received->header->age), + now.tv_sec, now.tv_usec); + + /* this will do free this lsa */ + ospf6_lsa_delete (received); + return; /* examin next lsa */ + } + + //if (IS_OSPF6_DUMP_DBEX) + zlog_info ("DBEX: Receive new LSA from %s: %s seq: %#x age: %d: " + "%ld.%06ld", + from->str, received->str, + ntohl (received->header->seqnum), + ntohs (received->header->age), + now.tv_sec, now.tv_usec); + + /* (b) immediately flood */ + ospf6_dbex_flood (received, from); + +#if 0 + /* Because New LSDB do not permit two LSA having the same identifier + exist in a LSDB list, above ospf6_dbex_flood() will remove + the old instance automatically. thus bellow is not needed. */ + /* (c) remove database copy from all neighbor's retranslist */ + if (have) + ospf6_dbex_remove_from_all_retrans_list (have); +#endif + + /* (d), installing lsdb, which may cause routing + table calculation (replacing database copy) */ + ospf6_lsdb_install (received); + + /* (e) possibly acknowledge */ + acktype = ack_type (received, ismore_recent, from); + if (acktype == DIRECT_ACK) + { + if (IS_OSPF6_DUMP_DBEX) + zlog_info ("DBEX: Direct Ack to %s", from->str); + ospf6_dbex_acknowledge_direct (received, from); + } + else if (acktype == DELAYED_ACK) + { + if (IS_OSPF6_DUMP_DBEX) + zlog_info ("DBEX: Delayed Ack to %s", from->str); + ospf6_dbex_acknowledge_delayed (received, from->ospf6_interface); + } + else + { + if (IS_OSPF6_DUMP_DBEX) + zlog_info ("DBEX: No Ack to %s", from->str); + } + + /* (f) */ + /* Self Originated LSA, section 13.4 */ + if (received->lsa_hdr->lsh_advrtr == ospf6->router_id + && (! have || ismore_recent < 0)) + { + /* we're going to make new lsa or to flush this LSA. */ + if (IS_OSPF6_DUMP_DBEX) + zlog_info ("DBEX: Self-originated LSA %s from %s:%s", + received->str, from->str, + from->ospf6_interface->interface->name); + if (IS_OSPF6_DUMP_DBEX) + zlog_info ("DBEX: %s: Make new one/Flush", received->str); + + SET_FLAG (received->flag, OSPF6_LSA_FLAG_REFRESH); + slot = ospf6_lsa_slot_get (received->header->type); + if (slot && slot->func_refresh) + { + (*slot->func_refresh) (received); + return; + } + + zlog_warn ("Can't Refresh LSA: Unknown type: %#x, Flush", + ntohs (received->header->type)); + ospf6_lsa_premature_aging (received); + return; + } + } + else if (ospf6_lsdb_lookup_lsdb (received->header->type, + received->header->id, + received->header->adv_router, + from->request_list)) + /* (6) if there is instance on sending neighbor's request list */ + { + /* if no database copy, should go above state (5) */ + assert (have); + + zlog_warn ("DBEX: [%s:%s] received LSA %s is not newer," + " and is on his requestlist: Generate BadLSReq", + from->str, from->ospf6_interface->interface->name, + received->str); + + /* BadLSReq */ + thread_add_event (master, bad_lsreq, from, 0); + + ospf6_lsa_delete (received); + } + else if (ismore_recent == 0) /* (7) if neither is more recent */ + { + /* (a) if on retranslist, Treat this LSA as an Ack: Implied Ack */ + rem = ospf6_lsdb_lookup_lsdb (received->header->type, + received->header->id, + received->header->adv_router, + from->retrans_list); + if (rem) + { + if (IS_OSPF6_DUMP_DBEX) + zlog_info ("DBEX: Implied Ack from %s, (remove retrans)", + from->str); + SET_FLAG (received->flag, OSPF6_LSA_FLAG_IMPLIEDACK); + ospf6_neighbor_retrans_remove (rem, from); + } + + /* (b) possibly acknowledge */ + acktype = ack_type (received, ismore_recent, from); + if (acktype == DIRECT_ACK) + { + if (IS_OSPF6_DUMP_DBEX) + zlog_info ("DBEX: Direct Ack to %s", from->str); + ospf6_dbex_acknowledge_direct (received, from); + } + else if (acktype == DELAYED_ACK) + { + if (IS_OSPF6_DUMP_DBEX) + zlog_info ("DBEX: Delayed Ack to %s", from->str); + ospf6_dbex_acknowledge_delayed (received, from->ospf6_interface); + } + else + { + if (IS_OSPF6_DUMP_DBEX) + zlog_info ("DBEX: No Ack to %s", from->str); + } + ospf6_lsa_delete (received); + } + else /* (8) previous database copy is more recent */ + { + /* If Seqnumber Wrapping, simply discard + Otherwise, Send database copy of this LSA to this neighbor */ + if (! IS_LSA_MAXAGE (received) || + received->lsa_hdr->lsh_seqnum != MAX_SEQUENCE_NUMBER) + { + if (IS_OSPF6_DUMP_DBEX) + zlog_info ("DBEX: database is more recent: send back to %s", + from->str); + ospf6_send_lsupdate_direct (have, from); + } + ospf6_lsa_delete (received); + } +} + +/* RFC2328: Table 19: Sending link state acknowledgements. */ +int +ack_type (struct ospf6_lsa *newp, int ismore_recent, + struct ospf6_neighbor *from) +{ + struct ospf6_interface *ospf6_interface; + struct ospf6_lsa *have; + int count; + + assert (from && from->ospf6_interface); + ospf6_interface = from->ospf6_interface; + + if (CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_FLOODBACK)) + return NO_ACK; + + if (ismore_recent < 0) + { + if (ospf6_interface->state != IFS_BDR) + return DELAYED_ACK; + + if (ospf6_interface->dr == from->router_id) + return DELAYED_ACK; + return NO_ACK; + } + + if (CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_DUPLICATE) && + CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_IMPLIEDACK)) + { + if (ospf6_interface->state != IFS_BDR) + return NO_ACK; + + if (ospf6_interface->dr == from->router_id) + return DELAYED_ACK; + + return NO_ACK; + } + + if (CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_DUPLICATE) && + ! CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_IMPLIEDACK)) + return DIRECT_ACK; + + have = ospf6_lsdb_lookup (newp->header->type, newp->header->id, + newp->header->adv_router, + ospf6_lsa_get_scope (newp->header->type, + from->ospf6_interface)); + + count = 0; + ospf6->foreach_nei (ospf6, &count, NBS_EXCHANGE, ospf6_count_state); + ospf6->foreach_nei (ospf6, &count, NBS_LOADING, ospf6_count_state); + + if (IS_LSA_MAXAGE (newp) && have == NULL && count == 0) + return DIRECT_ACK; + + return NO_ACK; +} + +static void +ospf6_dbex_flood_linklocal (struct ospf6_lsa *lsa, struct ospf6_interface *o6i, + struct ospf6_neighbor *from) +{ + struct ospf6_neighbor *o6n = (struct ospf6_neighbor *) NULL; + int ismore_recent, addretrans = 0; + listnode n; + struct ospf6_lsa *req; + + /* (1) for each neighbor */ + for (n = listhead (o6i->neighbor_list); n; nextnode (n)) + { + o6n = (struct ospf6_neighbor *) getdata (n); + + /* (a) */ + if (o6n->state < NBS_EXCHANGE) + continue; /* examin next neighbor */ + + /* (b) */ + if (o6n->state == NBS_EXCHANGE + || o6n->state == NBS_LOADING) + { + req = ospf6_lsdb_lookup_lsdb (lsa->header->type, + lsa->header->id, + lsa->header->adv_router, + o6n->request_list); + if (req) + { + ismore_recent = ospf6_lsa_check_recent (lsa, req); + if (ismore_recent > 0) + { + continue; /* examin next neighbor */ + } + else if (ismore_recent == 0) + { + ospf6_neighbor_request_remove (req, o6n); + continue; /* examin next neighbor */ + } + else /* ismore_recent < 0 (the new LSA is more recent) */ + { + ospf6_neighbor_request_remove (req, o6n); + } + } + } + + /* (c) */ + if (from && from->router_id == o6n->router_id) + continue; /* examin next neighbor */ + + /* (d) add retranslist */ + if (IS_OSPF6_DUMP_DBEX) + zlog_info ("DBEX: schedule flooding [%s:%s]: %s", + o6n->str, o6n->ospf6_interface->interface->name, + lsa->str); + ospf6_neighbor_retrans_add (lsa, o6n); + addretrans++; + if (o6n->send_update == (struct thread *) NULL) + o6n->send_update = + thread_add_timer (master, ospf6_send_lsupdate_rxmt, o6n, + o6n->ospf6_interface->rxmt_interval); + } + + /* (2) */ + if (addretrans == 0) + return; /* examin next interface */ + + if (from && from->ospf6_interface == o6i) + { + if (IS_OSPF6_DUMP_DBEX) + zlog_info ("DBEX: flood back %s to %s", + lsa->str, o6i->interface->name); + /* note occurence of floodback */ + SET_FLAG (lsa->flag, OSPF6_LSA_FLAG_FLOODBACK); + } + + /* (3) */ + if (from && from->ospf6_interface == o6i) + { + /* if from DR or BDR, don't need to flood this interface */ + if (from->router_id == from->ospf6_interface->dr || + from->router_id == from->ospf6_interface->bdr) + return; /* examin next interface */ + } + + /* (4) if I'm BDR, DR will flood this interface */ + if (from && from->ospf6_interface == o6i + && o6i->state == IFS_BDR) + return; /* examin next interface */ + + if (IS_OSPF6_DUMP_DBEX) + zlog_info ("Flood to interface %s", o6i->interface->name); + + /* (5) send LinkState Update */ + ospf6_send_lsupdate_flood (lsa, o6i); + + return; +} + +/* RFC2328 section 13.3 */ +static void +ospf6_dbex_flood_area (struct ospf6_lsa *lsa, struct ospf6_area *area, + struct ospf6_neighbor *from) +{ + listnode n; + struct ospf6_interface *ospf6_interface; + + assert (lsa && lsa->lsa_hdr && area); + + /* for each eligible ospf_ifs */ + for (n = listhead (area->if_list); n; nextnode (n)) + { + ospf6_interface = (struct ospf6_interface *) getdata (n); + ospf6_dbex_flood_linklocal (lsa, ospf6_interface, from); + } +} + +static void +ospf6_dbex_flood_as (struct ospf6_lsa *lsa, struct ospf6 *ospf6, + struct ospf6_neighbor *from) +{ + listnode n; + struct ospf6_area *o6a; + + assert (lsa && lsa->lsa_hdr && ospf6); + + /* for each attached area */ + for (n = listhead (ospf6->area_list); n; nextnode (n)) + { + o6a = (struct ospf6_area *) getdata (n); + ospf6_dbex_flood_area (lsa, o6a, from); + } +} + +/* flood ospf6_lsa within appropriate scope */ +void +ospf6_dbex_flood (struct ospf6_lsa *lsa, struct ospf6_neighbor *from) +{ + struct ospf6_area *o6a; + struct ospf6_interface *o6i; + struct ospf6 *o6; + struct ospf6_lsa_header *lsa_header; + + lsa_header = (struct ospf6_lsa_header *) lsa->lsa_hdr; + + if (OSPF6_LSA_IS_SCOPE_LINKLOCAL (ntohs (lsa_header->type))) + { + o6i = (struct ospf6_interface *) lsa->scope; + assert (o6i); + + if (IS_OSPF6_DUMP_DBEX) + zlog_info ("Flood Linklocal: %s", o6i->interface->name); + ospf6_dbex_flood_linklocal (lsa, o6i, from); + } + else if (OSPF6_LSA_IS_SCOPE_AREA (ntohs (lsa_header->type))) + { + o6a = (struct ospf6_area *) lsa->scope; + assert (o6a); + + if (IS_OSPF6_DUMP_DBEX) + zlog_info ("Flood Area: %s", o6a->str); + ospf6_dbex_flood_area (lsa, o6a, from); + } + else if (OSPF6_LSA_IS_SCOPE_AS (ntohs (lsa_header->type))) + { + o6 = (struct ospf6 *) lsa->scope; + assert (o6); + + if (IS_OSPF6_DUMP_DBEX) + zlog_info ("Flood AS"); + ospf6_dbex_flood_as (lsa, o6, from); + } + else + { + zlog_warn ("Can't Flood %s: scope unknown", lsa->str); + } +} + + diff --git a/ospf6d/ospf6_dbex.h b/ospf6d/ospf6_dbex.h new file mode 100644 index 000000000..fbb7dc5eb --- /dev/null +++ b/ospf6d/ospf6_dbex.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 1999 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF6_DBEX_H +#define OSPF6_DBEX_H + +/* for ack_type() */ +#define NO_ACK 0 +#define DELAYED_ACK 1 +#define DIRECT_ACK 2 + +/* Function Prototypes */ +void +ospf6_add_delayed_ack (struct ospf6_lsa *, struct ospf6_interface *); +void +ospf6_remove_delayed_ack (struct ospf6_lsa *, struct ospf6_interface *); +void ospf6_lsa_delayed_ack_remove_all (struct ospf6_lsa *lsa); + +void ospf6_dbex_prepare_summary (struct ospf6_neighbor *); + +int +ospf6_dbex_check_dbdesc_lsa_header (struct ospf6_lsa_header *lsa_header, + struct ospf6_neighbor *from); + +void +ospf6_dbex_acknowledge_delayed (struct ospf6_lsa *lsa, + struct ospf6_interface *o6i); + +void +ospf6_dbex_receive_lsa (struct ospf6_lsa_header *, + struct ospf6_neighbor *); + +int ack_type (struct ospf6_lsa *, int, struct ospf6_neighbor *); + +void ospf6_dbex_flood (struct ospf6_lsa *, struct ospf6_neighbor *); + +void +ospf6_dbex_remove_from_all_retrans_list (struct ospf6_lsa *lsa); + +#endif /* OSPF6_DBEX_H */ + diff --git a/ospf6d/ospf6_dump.c b/ospf6d/ospf6_dump.c new file mode 100644 index 000000000..e950ec8cb --- /dev/null +++ b/ospf6d/ospf6_dump.c @@ -0,0 +1,314 @@ +/* + * Logging function + * Copyright (C) 1999-2002 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <zebra.h> + +/* Include other stuffs */ +#include "log.h" +#include "command.h" +#include "ospf6_dump.h" + +#define CMD_SHOW 0 +#define CMD_ENABLE 1 +#define CMD_DISABLE 2 +#define CMD_MAX 3 + +struct ospf6_dump +{ + struct cmd_element cmd[CMD_MAX]; + char *name; + int config; +}; + +#define DUMP_MAX 512 +struct ospf6_dump *ospf6_dump[DUMP_MAX]; +unsigned int dump_size = 0; + +static int +ospf6_dump_index (struct cmd_element *cmd, int command) +{ + int i; + + for (i = 0; i < DUMP_MAX; i++) + { + if (cmd != &ospf6_dump[i]->cmd[command]) + continue; + break; + } + + if (i == DUMP_MAX) + return -1; + return i; +} + +int +ospf6_dump_is_on (int index) +{ + if (ospf6_dump[index] == NULL) + return 0; + + return ospf6_dump[index]->config; +} + +int +ospf6_dump_show (struct cmd_element *cmd, + struct vty *vty, int argc, char **argv) +{ + int index; + + index = ospf6_dump_index (cmd, CMD_SHOW); + assert (index != -1); + + vty_out (vty, " %-16s: %s%s", ospf6_dump[index]->name, + (ospf6_dump[index]->config ? "on" : "off"), + VTY_NEWLINE); + return CMD_SUCCESS; +} + +int +ospf6_dump_enable (struct cmd_element *cmd, + struct vty *vty, int argc, char **argv) +{ + int index; + + index = ospf6_dump_index (cmd, CMD_ENABLE); + assert (index != -1); + + ospf6_dump[index]->config = 1; + return CMD_SUCCESS; +} + +int +ospf6_dump_disable (struct cmd_element *cmd, + struct vty *vty, int argc, char **argv) +{ + int index; + + index = ospf6_dump_index (cmd, CMD_DISABLE); + assert (index != -1); + + ospf6_dump[index]->config = 0; + return CMD_SUCCESS; +} + +int +ospf6_dump_install (char *name, char *help) +{ + struct cmd_element *cmd; + char string[256]; + char helpstring[256]; + + if (dump_size + 1 >= DUMP_MAX) + return -1; + + ospf6_dump[dump_size] = malloc (sizeof (struct ospf6_dump)); + if (ospf6_dump[dump_size] == NULL) + return -1; + memset (ospf6_dump[dump_size], 0, sizeof (struct ospf6_dump)); + + ospf6_dump[dump_size]->name = strdup (name); + + cmd = &ospf6_dump[dump_size]->cmd[CMD_SHOW]; + snprintf (string, sizeof (string), "show debugging ospf6 %s", name); + snprintf (helpstring, sizeof (helpstring), "%s%s%s%s", + SHOW_STR, DEBUG_STR, OSPF6_STR, help); + memset (cmd, 0, sizeof (struct cmd_element)); + cmd->string = strdup (string); + cmd->func = ospf6_dump_show; + cmd->doc = strdup (helpstring); + install_element (VIEW_NODE, cmd); + install_element (ENABLE_NODE, cmd); + + cmd = &ospf6_dump[dump_size]->cmd[CMD_ENABLE]; + snprintf (string, sizeof (string), "debug ospf6 %s", name); + snprintf (helpstring, sizeof (helpstring), "%s%s%s", + DEBUG_STR, OSPF6_STR, help); + memset (cmd, 0, sizeof (struct cmd_element)); + cmd->string = strdup (string); + cmd->func = ospf6_dump_enable; + cmd->doc = strdup (helpstring); + install_element (CONFIG_NODE, cmd); + + cmd = &ospf6_dump[dump_size]->cmd[CMD_DISABLE]; + snprintf (string, sizeof (string), "no debug ospf6 %s", name); + snprintf (helpstring, sizeof (helpstring), "%s%s%s%s", + NO_STR, DEBUG_STR, OSPF6_STR, help); + memset (cmd, 0, sizeof (struct cmd_element)); + cmd->string = strdup (string); + cmd->func = ospf6_dump_disable; + cmd->doc = strdup (helpstring); + install_element (CONFIG_NODE, cmd); + + return dump_size++; +} + +DEFUN(show_debug_ospf6, + show_debug_ospf6_cmd, + "show debugging ospf6", + SHOW_STR + DEBUG_STR + OSPF6_STR) +{ + int i; + + vty_out (vty, "OSPF6 debugging status:%s", VTY_NEWLINE); + + for (i = 0; i < DUMP_MAX; i++) + { + if (ospf6_dump[i] == NULL) + continue; + ospf6_dump_show (&ospf6_dump[i]->cmd[CMD_SHOW], vty, 0, NULL); + } + + return CMD_SUCCESS; +} + +DEFUN (debug_ospf6_all, + debug_ospf6_all_cmd, + "debug ospf6 all", + DEBUG_STR + OSPF6_STR + "Turn on ALL OSPFv3 debugging\n") +{ + int i; + + for (i = 0; i < DUMP_MAX; i++) + { + if (ospf6_dump[i] == NULL) + continue; + ospf6_dump_enable (&ospf6_dump[i]->cmd[CMD_ENABLE], vty, 0, NULL); + } + + return CMD_SUCCESS; +} + +DEFUN (no_debug_ospf6_all, + no_debug_ospf6_all_cmd, + "no debug ospf6 all", + NO_STR + DEBUG_STR + OSPF6_STR + "Turn off ALL OSPFv3 debugging\n") +{ + int i; + + for (i = 0; i < DUMP_MAX; i++) + { + if (ospf6_dump[i] == NULL) + continue; + ospf6_dump_disable (&ospf6_dump[i]->cmd[CMD_DISABLE], vty, 0, NULL); + } + + return CMD_SUCCESS; +} + +struct cmd_node debug_node = +{ + DEBUG_NODE, + "" +}; + +int +ospf6_dump_config_write (struct vty *vty) +{ + int i; + + for (i = 0; i < dump_size; i++) + { + if (ospf6_dump[i] == NULL) + continue; + + if (ospf6_dump[i]->config == 0) + continue; + + vty_out (vty, "debug ospf6 %s%s", ospf6_dump[i]->name, VTY_NEWLINE); + } + + vty_out (vty, "!%s", VTY_NEWLINE); + return 0; +} + +char dump_index[OSPF6_DUMP_MAX]; + +void +ospf6_dump_init () +{ + memset (ospf6_dump, 0, sizeof (ospf6_dump)); + + install_node (&debug_node, ospf6_dump_config_write); + + install_element (VIEW_NODE, &show_debug_ospf6_cmd); + install_element (ENABLE_NODE, &show_debug_ospf6_cmd); + + install_element (CONFIG_NODE, &debug_ospf6_all_cmd); + install_element (CONFIG_NODE, &no_debug_ospf6_all_cmd); + + /* bellow is for backward compatibility + should be moved to each modules */ + +#define MESSAGE_STR "OSPFv3 Messages\n" + + dump_index[OSPF6_DUMP_HELLO] = + ospf6_dump_install ("message hello", + MESSAGE_STR "Hello\n"); + dump_index[OSPF6_DUMP_DBDESC] = + ospf6_dump_install ("message dbdesc", + MESSAGE_STR "Database Description\n"); + dump_index[OSPF6_DUMP_LSREQ] = + ospf6_dump_install ("message lsreq", + MESSAGE_STR "Link State Request\n"); + dump_index[OSPF6_DUMP_LSUPDATE] = + ospf6_dump_install ("message lsupdate", + MESSAGE_STR "Link State Update\n"); + dump_index[OSPF6_DUMP_LSACK] = + ospf6_dump_install ("message lsack", + MESSAGE_STR "Link State Acknowledge\n"); + dump_index[OSPF6_DUMP_NEIGHBOR] = + ospf6_dump_install ("neighbor", "Neighbors\n"); + dump_index[OSPF6_DUMP_INTERFACE] = + ospf6_dump_install ("interface", "Interfaces\n"); + dump_index[OSPF6_DUMP_LSA] = + ospf6_dump_install ("lsa", "Link State Advertisement\n"); + dump_index[OSPF6_DUMP_ZEBRA] = + ospf6_dump_install ("zebra", "Communication with zebra\n"); + dump_index[OSPF6_DUMP_CONFIG] = + ospf6_dump_install ("config", "Configuration Changes\n"); + dump_index[OSPF6_DUMP_DBEX] = + ospf6_dump_install ("dbex", "Database Exchange/Flooding\n"); + dump_index[OSPF6_DUMP_SPF] = + ospf6_dump_install ("spf", "SPF Calculation\n"); + dump_index[OSPF6_DUMP_ROUTE] = + ospf6_dump_install ("route", "Route Calculation\n"); + dump_index[OSPF6_DUMP_LSDB] = + ospf6_dump_install ("lsdb", "Link State Database\n"); + dump_index[OSPF6_DUMP_REDISTRIBUTE] = + ospf6_dump_install ("redistribute", + "Route Exchange with other protocols\n"); + dump_index[OSPF6_DUMP_HOOK] = + ospf6_dump_install ("hook", "Hooks\n"); + dump_index[OSPF6_DUMP_ASBR] = + ospf6_dump_install ("asbr", "AS Boundary Router function\n"); + dump_index[OSPF6_DUMP_PREFIX] = + ospf6_dump_install ("prefix", "Prefix\n"); +} + + diff --git a/ospf6d/ospf6_dump.h b/ospf6d/ospf6_dump.h new file mode 100644 index 000000000..18a6e4660 --- /dev/null +++ b/ospf6d/ospf6_dump.h @@ -0,0 +1,95 @@ +/* + * Logging function + * Copyright (C) 1999-2002 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF6_DUMP_H +#define OSPF6_DUMP_H + +enum ospf6_dump_type +{ + OSPF6_DUMP_HELLO, + OSPF6_DUMP_DBDESC, + OSPF6_DUMP_LSREQ, + OSPF6_DUMP_LSUPDATE, + OSPF6_DUMP_LSACK, + OSPF6_DUMP_NEIGHBOR, + OSPF6_DUMP_INTERFACE, + OSPF6_DUMP_AREA, + OSPF6_DUMP_LSA, + OSPF6_DUMP_ZEBRA, + OSPF6_DUMP_CONFIG, + OSPF6_DUMP_DBEX, + OSPF6_DUMP_SPF, + OSPF6_DUMP_ROUTE, + OSPF6_DUMP_LSDB, + OSPF6_DUMP_REDISTRIBUTE, + OSPF6_DUMP_HOOK, + OSPF6_DUMP_ASBR, + OSPF6_DUMP_PREFIX, + OSPF6_DUMP_ABR, + OSPF6_DUMP_MAX +}; + +#define IS_OSPF6_DUMP_HELLO \ + (ospf6_dump_is_on (dump_index[OSPF6_DUMP_HELLO])) +#define IS_OSPF6_DUMP_DBDESC \ + (ospf6_dump_is_on (dump_index[OSPF6_DUMP_DBDESC])) +#define IS_OSPF6_DUMP_LSREQ \ + (ospf6_dump_is_on (dump_index[OSPF6_DUMP_LSREQ])) +#define IS_OSPF6_DUMP_LSUPDATE \ + (ospf6_dump_is_on (dump_index[OSPF6_DUMP_LSUPDATE])) +#define IS_OSPF6_DUMP_LSACK \ + (ospf6_dump_is_on (dump_index[OSPF6_DUMP_LSACK])) +#define IS_OSPF6_DUMP_NEIGHBOR \ + (ospf6_dump_is_on (dump_index[OSPF6_DUMP_NEIGHBOR])) +#define IS_OSPF6_DUMP_INTERFACE \ + (ospf6_dump_is_on (dump_index[OSPF6_DUMP_INTERFACE])) +#define IS_OSPF6_DUMP_LSA \ + (ospf6_dump_is_on (dump_index[OSPF6_DUMP_LSA])) +#define IS_OSPF6_DUMP_ZEBRA \ + (ospf6_dump_is_on (dump_index[OSPF6_DUMP_ZEBRA])) +#define IS_OSPF6_DUMP_CONFIG \ + (ospf6_dump_is_on (dump_index[OSPF6_DUMP_CONFIG])) +#define IS_OSPF6_DUMP_DBEX \ + (ospf6_dump_is_on (dump_index[OSPF6_DUMP_DBEX])) +#define IS_OSPF6_DUMP_SPF \ + (ospf6_dump_is_on (dump_index[OSPF6_DUMP_SPF])) +#define IS_OSPF6_DUMP_ROUTE \ + (ospf6_dump_is_on (dump_index[OSPF6_DUMP_ROUTE])) +#define IS_OSPF6_DUMP_LSDB \ + (ospf6_dump_is_on (dump_index[OSPF6_DUMP_LSDB])) +#define IS_OSPF6_DUMP_REDISTRIBUTE \ + (ospf6_dump_is_on (dump_index[OSPF6_DUMP_REDISTRIBUTE])) +#define IS_OSPF6_DUMP_HOOK \ + (ospf6_dump_is_on (dump_index[OSPF6_DUMP_HOOK])) +#define IS_OSPF6_DUMP_ASBR \ + (ospf6_dump_is_on (dump_index[OSPF6_DUMP_ASBR])) +#define IS_OSPF6_DUMP_PREFIX \ + (ospf6_dump_is_on (dump_index[OSPF6_DUMP_PREFIX])) + +extern char dump_index[OSPF6_DUMP_MAX]; + +void ospf6_dump_init (); +int ospf6_dump_is_on (int index); +int ospf6_dump_install (char *name, char *help); + +#endif /* OSPF6_DUMP_H */ + diff --git a/ospf6d/ospf6_hook.c b/ospf6d/ospf6_hook.c new file mode 100644 index 000000000..fc9e185db --- /dev/null +++ b/ospf6d/ospf6_hook.c @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2001 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <zebra.h> + +#include "log.h" +#include "memory.h" + +#include "ospf6_hook.h" + +struct ospf6_hook_master neighbor_hook; +struct ospf6_hook_master interface_hook; +struct ospf6_hook_master area_hook; +struct ospf6_hook_master top_hook; +struct ospf6_hook_master database_hook; +struct ospf6_hook_master intra_topology_hook; +struct ospf6_hook_master inter_topology_hook; +struct ospf6_hook_master route_hook; +struct ospf6_hook_master redistribute_hook; + +static struct ospf6_hook * +ospf6_hook_create () +{ + struct ospf6_hook *new; + new = XMALLOC (MTYPE_OSPF6_OTHER, sizeof (struct ospf6_hook)); + if (new == NULL) + return NULL; + memset (new, 0, sizeof (struct ospf6_hook)); + return new; +} + +static void +ospf6_hook_delete (struct ospf6_hook *hook) +{ + XFREE (MTYPE_OSPF6_OTHER, hook); +} + +static int +ospf6_hook_issame (struct ospf6_hook *hook1, struct ospf6_hook *hook2) +{ + if (hook1->name && hook2->name && + strcmp (hook1->name, hook2->name) != 0) + return 0; + if (hook1->hook_add != hook2->hook_add) + return 0; + if (hook1->hook_change != hook2->hook_change) + return 0; + if (hook1->hook_remove != hook2->hook_remove) + return 0; + return 1; +} + +void +ospf6_hook_register (struct ospf6_hook *hook, + struct ospf6_hook_master *master) +{ + struct ospf6_hook *new; + + new = ospf6_hook_create (); + + if (hook->name) + new->name = strdup (hook->name); + new->hook_add = hook->hook_add; + new->hook_change = hook->hook_change; + new->hook_remove = hook->hook_remove; + + new->prev = master->tail; + if (master->tail) + master->tail->next = new; + + master->tail = new; + if (! master->head) + master->head = new; + + master->count++; + + if (IS_OSPF6_DUMP_HOOK) + { + zlog_info ("HOOK: Register hook%s%s%s%s", + (hook->name ? " " : ""), + (hook->name ? hook->name : ""), + (master->name ? " to " : ""), + (master->name ? master->name : "")); + } +} + +void +ospf6_hook_unregister (struct ospf6_hook *req, + struct ospf6_hook_master *master) +{ + struct ospf6_hook *hook; + + for (hook = master->head; hook; hook = hook->next) + { + if (ospf6_hook_issame (hook, req)) + break; + } + if (! hook) + return; + + if (hook->prev) + hook->prev->next = hook->next; + if (hook->next) + hook->next->prev = hook->prev; + if (master->head == hook) + master->head = hook->next; + if (master->tail == hook) + master->tail = hook->prev; + + master->count--; + + if (IS_OSPF6_DUMP_HOOK) + { + zlog_info ("HOOK: Unregister hook%s%s%s%s", + (hook->name ? " " : ""), + (hook->name ? hook->name : ""), + (master->name ? " to " : ""), + (master->name ? master->name : "")); + } + + if (hook->name) + free (hook->name); + ospf6_hook_delete (hook); +} + +void +ospf6_hook_unregister_all (struct ospf6_hook_master *master) +{ + struct ospf6_hook *hook, *next; + + for (hook = master->head; hook; hook = next) + { + next = hook->next; + ospf6_hook_delete (hook); + } + + master->head = NULL; + master->tail = NULL; + master->count = 0; +} + + +void +ospf6_hook_init () +{ + neighbor_hook.name = "Neighbor Hooklist"; + interface_hook.name = "Interface Hooklist"; + area_hook.name = "Area Hooklist"; + top_hook.name = "Top Hooklist"; + database_hook.name = "Database Hooklist"; + intra_topology_hook.name = "IntraTopology Hooklist"; + inter_topology_hook.name = "InterTopology Hooklist"; + route_hook.name = "Route Hooklist"; +} + + diff --git a/ospf6d/ospf6_hook.h b/ospf6d/ospf6_hook.h new file mode 100644 index 000000000..fa882a53e --- /dev/null +++ b/ospf6d/ospf6_hook.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2001 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF6_HOOK_H +#define OSPF6_HOOK_H + +#include "ospf6_dump.h" + +struct ospf6_hook +{ + struct ospf6_hook *prev; + struct ospf6_hook *next; + + char *name; + int (*hook_add) (void *); + int (*hook_change) (void *); + int (*hook_remove) (void *); +}; + +struct ospf6_hook_master +{ + char *name; + struct ospf6_hook *head; + struct ospf6_hook *tail; + int count; +}; + +#define CALL_HOOKS(master,hookname,hookstr,data) \ + {\ + struct ospf6_hook *hook;\ + for (hook = (master)->head; hook; hook = hook->next)\ + {\ + if (hook->hookname)\ + {\ + if (IS_OSPF6_DUMP_HOOK)\ + zlog_info ("HOOK: Call %s hook: %s", (hookstr), hook->name);\ + (*(hook->hookname)) (data);\ + }\ + }\ + } +#define CALL_ADD_HOOK(master,data) \ + { CALL_HOOKS ((master), hook_add, "ADD", (data)) } +#define CALL_CHANGE_HOOK(master,data) \ + { CALL_HOOKS ((master), hook_change, "CHANGE", (data)) } +#define CALL_REMOVE_HOOK(master,data) \ + { CALL_HOOKS ((master), hook_remove, "REMOVE", (data)) } + +#define IS_HOOK_SET(hook) \ + ((hook)->hook_add || (hook)->hook_change || (hook)->hook_remove) + +extern struct ospf6_hook_master neighbor_hook; +extern struct ospf6_hook_master interface_hook; +extern struct ospf6_hook_master area_hook; +extern struct ospf6_hook_master top_hook; +extern struct ospf6_hook_master database_hook; +extern struct ospf6_hook_master intra_topology_hook; +extern struct ospf6_hook_master inter_topology_hook; +extern struct ospf6_hook_master route_hook; +extern struct ospf6_hook_master redistribute_hook; + +void ospf6_hook_register (struct ospf6_hook *, + struct ospf6_hook_master *); +void ospf6_hook_unregister (struct ospf6_hook *, + struct ospf6_hook_master *); +void ospf6_hook_unregister_all (struct ospf6_hook_master *); +void ospf6_hook_init (); + +#endif /*OSPF6_HOOK_H*/ + diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c new file mode 100644 index 000000000..d394f21bc --- /dev/null +++ b/ospf6d/ospf6_interface.c @@ -0,0 +1,1028 @@ +/* + * Copyright (C) 1999 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "ospf6d.h" + +#include "if.h" +#include "log.h" +#include "command.h" + +#include "ospf6_lsdb.h" + +#include "ospf6_top.h" +#include "ospf6_area.h" +#include "ospf6_interface.h" + +char *ospf6_interface_state_string[] = +{ + "None", "Down", "Loopback", "Waiting", "PointToPoint", + "DROther", "BDR", "DR", NULL +}; + +static void +ospf6_interface_foreach_neighbor (struct ospf6_interface *o6i, + void *arg, int val, + void (*func) (void *, int, void *)) +{ + listnode node; + struct ospf6_neighbor *nei; + + for (node = listhead (o6i->neighbor_list); node; nextnode (node)) + { + nei = (struct ospf6_neighbor *) getdata (node); + (*func) (arg, val, nei); + } +} + +static int +ospf6_interface_maxage_remover (struct thread *t) +{ + int count; + struct ospf6_interface *o6i = (struct ospf6_interface *) THREAD_ARG (t); + + o6i->maxage_remover = (struct thread *) NULL; + + count = 0; + o6i->foreach_nei (o6i, &count, NBS_EXCHANGE, ospf6_count_state); + o6i->foreach_nei (o6i, &count, NBS_LOADING, ospf6_count_state); + if (count != 0) + return 0; + + ospf6_lsdb_remove_maxage (o6i->lsdb); + return 0; +} + +void +ospf6_interface_schedule_maxage_remover (void *arg, int val, void *obj) +{ + struct ospf6_interface *o6i = (struct ospf6_interface *) obj; + + if (o6i->maxage_remover != NULL) + return; + + o6i->maxage_remover = + thread_add_event (master, ospf6_interface_maxage_remover, o6i, 0); +} + +/* Create new ospf6 interface structure */ +struct ospf6_interface * +ospf6_interface_create (struct interface *ifp) +{ + struct ospf6_interface *o6i; + + o6i = (struct ospf6_interface *) + XMALLOC (MTYPE_OSPF6_IF, sizeof (struct ospf6_interface)); + + if (o6i) + memset (o6i, 0, sizeof (struct ospf6_interface)); + else + { + zlog_err ("Can't malloc ospf6_interface for ifindex %d", ifp->ifindex); + return (struct ospf6_interface *) NULL; + } + + o6i->instance_id = 0; + o6i->if_id = ifp->ifindex; + o6i->lladdr = (struct in6_addr *) NULL; + o6i->area = (struct ospf6_area *) NULL; + o6i->state = IFS_DOWN; + o6i->flag = 0; + o6i->neighbor_list = list_new (); + + o6i->ack_list = ospf6_lsdb_create (); + o6i->lsdb = ospf6_lsdb_create (); + + o6i->transdelay = 1; + o6i->priority = 1; + o6i->hello_interval = 10; + o6i->dead_interval = 40; + o6i->rxmt_interval = 5; + o6i->cost = 1; + o6i->ifmtu = 1280; + + o6i->foreach_nei = ospf6_interface_foreach_neighbor; + + /* link both */ + o6i->interface = ifp; + ifp->info = o6i; + + CALL_ADD_HOOK (&interface_hook, o6i); + + /* Get the interface's link-local if any */ + ospf6_interface_address_update(ifp); + + return o6i; +} + +void +ospf6_interface_delete (struct ospf6_interface *o6i) +{ + listnode n; + struct ospf6_neighbor *o6n; + + CALL_REMOVE_HOOK (&interface_hook, o6i); + + for (n = listhead (o6i->neighbor_list); n; nextnode (n)) + { + o6n = (struct ospf6_neighbor *) getdata (n); + ospf6_neighbor_delete (o6n); + } + list_delete (o6i->neighbor_list); + + if (o6i->thread_send_hello) + { + thread_cancel (o6i->thread_send_hello); + o6i->thread_send_hello = NULL; + } + if (o6i->thread_send_lsack_delayed) + { + thread_cancel (o6i->thread_send_lsack_delayed); + o6i->thread_send_lsack_delayed = NULL; + } + + ospf6_lsdb_delete (o6i->ack_list); + ospf6_lsdb_remove_all (o6i->lsdb); + ospf6_lsdb_delete (o6i->lsdb); + + /* cut link */ + o6i->interface->info = NULL; + + /* plist_name */ + if (o6i->plist_name) + XFREE (MTYPE_PREFIX_LIST_STR, o6i->plist_name); + + XFREE (MTYPE_OSPF6_IF, o6i); +} + +static struct in6_addr * +ospf6_interface_update_linklocal_address (struct interface *ifp) +{ + listnode n; + struct connected *c; + struct in6_addr *l = (struct in6_addr *) NULL; + + /* for each connected address */ + for (n = listhead (ifp->connected); n; nextnode (n)) + { + c = (struct connected *) getdata (n); + + /* if family not AF_INET6, ignore */ + if (c->address->family != AF_INET6) + continue; + + /* linklocal scope check */ + if (IN6_IS_ADDR_LINKLOCAL (&c->address->u.prefix6)) + l = &c->address->u.prefix6; + } + return l; +} + +void +ospf6_interface_if_add (struct interface *ifp) +{ + struct ospf6_interface *o6i; + + o6i = (struct ospf6_interface *) ifp->info; + if (!o6i) + return; + + o6i->if_id = ifp->ifindex; + + ospf6_interface_address_update (ifp); + + /* interface start */ + if (o6i->area) + thread_add_event (master, interface_up, o6i, 0); +} + +void +ospf6_interface_if_del (struct interface *ifp) +{ + struct ospf6_interface *o6i; + + o6i = (struct ospf6_interface *) ifp->info; + if (!o6i) + return; + + /* interface stop */ + if (o6i->area) + thread_execute (master, interface_down, o6i, 0); + + listnode_delete (o6i->area->if_list, o6i); + o6i->area = (struct ospf6_area *) NULL; + + /* cut link */ + o6i->interface = NULL; + ifp->info = NULL; + + ospf6_interface_delete (o6i); +} + +void +ospf6_interface_state_update (struct interface *ifp) +{ + struct ospf6_interface *o6i; + + o6i = (struct ospf6_interface *) ifp->info; + if (! o6i) + return; + if (! o6i->area) + return; + + if (if_is_up (ifp)) + thread_add_event (master, interface_up, o6i, 0); + else + thread_add_event (master, interface_down, o6i, 0); + + return; +} + +void +ospf6_interface_address_update (struct interface *ifp) +{ + struct ospf6_interface *o6i; + + o6i = (struct ospf6_interface *) ifp->info; + if (! o6i) + return; + + /* reset linklocal pointer */ + o6i->lladdr = ospf6_interface_update_linklocal_address (ifp); + + /* if area is null, can't make link-lsa */ + if (! o6i->area) + return; + + /* create new Link-LSA */ + CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, o6i); + + CALL_CHANGE_HOOK (&interface_hook, o6i); +} + +struct ospf6_interface * +ospf6_interface_lookup_by_index (int ifindex) +{ + struct ospf6_interface *o6i; + struct interface *ifp; + + ifp = if_lookup_by_index (ifindex); + + if (! ifp) + return (struct ospf6_interface *) NULL; + + o6i = (struct ospf6_interface *) ifp->info; + return o6i; +} + +struct ospf6_interface * +ospf6_interface_lookup_by_name (char *ifname) +{ + struct ospf6_interface *o6i; + struct interface *ifp; + + ifp = if_lookup_by_name (ifname); + + if (! ifp) + return (struct ospf6_interface *) NULL; + + o6i = (struct ospf6_interface *) ifp->info; + return o6i; +} + +int +ospf6_interface_count_neighbor_in_state (u_char state, + struct ospf6_interface *o6i) +{ + listnode n; + struct ospf6_neighbor *o6n; + int count = 0; + + for (n = listhead (o6i->neighbor_list); n; nextnode (n)) + { + o6n = (struct ospf6_neighbor *) getdata (n); + if (o6n->state == state) + count++; + } + return count; +} + +int +ospf6_interface_count_full_neighbor (struct ospf6_interface *o6i) +{ + listnode n; + struct ospf6_neighbor *o6n; + int count = 0; + + for (n = listhead (o6i->neighbor_list); n; nextnode (n)) + { + o6n = (struct ospf6_neighbor *) getdata (n); + if (o6n->state == NBS_FULL) + count++; + } + return count; +} + +int +ospf6_interface_is_enabled (unsigned int ifindex) +{ + struct ospf6_interface *o6i; + + o6i = ospf6_interface_lookup_by_index (ifindex); + if (! o6i) + return 0; + + if (! o6i->area) + return 0; + + if (o6i->state <= IFS_DOWN) + return 0; + + return 1; +} + +void +ospf6_interface_delayed_ack_add (struct ospf6_lsa *lsa, + struct ospf6_interface *o6i) +{ + struct ospf6_lsa *summary; + summary = ospf6_lsa_summary_create (lsa->header); + ospf6_lsdb_add (summary, o6i->ack_list); +} + +void +ospf6_interface_delayed_ack_remove (struct ospf6_lsa *lsa, + struct ospf6_interface *o6i) +{ + struct ospf6_lsa *summary; + summary = ospf6_lsdb_lookup_lsdb (lsa->header->type, lsa->header->id, + lsa->header->adv_router, o6i->ack_list); + ospf6_lsdb_remove (summary, o6i->ack_list); +} + +/* show specified interface structure */ +int +ospf6_interface_show (struct vty *vty, struct interface *iface) +{ + struct ospf6_interface *ospf6_interface; + struct connected *c; + struct prefix *p; + listnode i; + char strbuf[64], dr[32], bdr[32]; + char *updown[3] = {"down", "up", NULL}; + char *type; + + /* check physical interface type */ + if (if_is_loopback (iface)) + type = "LOOPBACK"; + else if (if_is_broadcast (iface)) + type = "BROADCAST"; + else if (if_is_pointopoint (iface)) + type = "POINTOPOINT"; + else + type = "UNKNOWN"; + + vty_out (vty, "%s is %s, type %s%s", + iface->name, updown[if_is_up (iface)], type, + VTY_NEWLINE); + vty_out (vty, " Interface ID: %d%s", iface->ifindex, VTY_NEWLINE); + + if (iface->info == NULL) + { + vty_out (vty, " OSPF not enabled on this interface%s", VTY_NEWLINE); + return 0; + } + else + ospf6_interface = (struct ospf6_interface *) iface->info; + + vty_out (vty, " Internet Address:%s", VTY_NEWLINE); + for (i = listhead (iface->connected); i; nextnode (i)) + { + c = (struct connected *)getdata (i); + p = c->address; + prefix2str (p, strbuf, sizeof (strbuf)); + switch (p->family) + { + case AF_INET: + vty_out (vty, " inet : %s%s", strbuf, + VTY_NEWLINE); + break; + case AF_INET6: + vty_out (vty, " inet6: %s%s", strbuf, + VTY_NEWLINE); + break; + default: + vty_out (vty, " ??? : %s%s", strbuf, + VTY_NEWLINE); + break; + } + } + + if (ospf6_interface->area) + { + inet_ntop (AF_INET, &ospf6_interface->area->ospf6->router_id, + strbuf, sizeof (strbuf)); + vty_out (vty, " Instance ID %d, Router ID %s%s", + ospf6_interface->instance_id, strbuf, + VTY_NEWLINE); + inet_ntop (AF_INET, &ospf6_interface->area->area_id, + strbuf, sizeof (strbuf)); + vty_out (vty, " Area ID %s, Cost %hu%s", strbuf, + ospf6_interface->cost, VTY_NEWLINE); + } + else + vty_out (vty, " Not Attached to Area%s", VTY_NEWLINE); + + vty_out (vty, " State %s, Transmit Delay %d sec, Priority %d%s", + ospf6_interface_state_string[ospf6_interface->state], + ospf6_interface->transdelay, + ospf6_interface->priority, + VTY_NEWLINE); + vty_out (vty, " Timer intervals configured:%s", VTY_NEWLINE); + vty_out (vty, " Hello %d, Dead %d, Retransmit %d%s", + ospf6_interface->hello_interval, + ospf6_interface->dead_interval, + ospf6_interface->rxmt_interval, + VTY_NEWLINE); + + inet_ntop (AF_INET, &ospf6_interface->dr, dr, sizeof (dr)); + inet_ntop (AF_INET, &ospf6_interface->bdr, bdr, sizeof (bdr)); + vty_out (vty, " DR:%s BDR:%s%s", dr, bdr, VTY_NEWLINE); + + vty_out (vty, " Number of I/F scoped LSAs is %u%s", + ospf6_interface->lsdb->count, VTY_NEWLINE); + vty_out (vty, " %-16s %5d times, %-16s %5d times%s", + "DRElection", ospf6_interface->ospf6_stat_dr_election, + "DelayedLSAck", ospf6_interface->ospf6_stat_delayed_lsack, + VTY_NEWLINE); + + return 0; +} + +void +ospf6_interface_statistics_show (struct vty *vty, struct ospf6_interface *o6i) +{ + struct timeval now, uptime; + u_long recv_total, send_total; + u_long bps_total_avg, bps_tx_avg, bps_rx_avg; + int i; + + gettimeofday (&now, (struct timezone *) NULL); + ospf6_timeval_sub (&now, &ospf6->starttime, &uptime); + + recv_total = send_total = 0; + for (i = 0; i < OSPF6_MESSAGE_TYPE_MAX; i++) + { + recv_total += o6i->message_stat[i].recv_octet; + send_total += o6i->message_stat[i].send_octet; + } + bps_total_avg = (recv_total + send_total) * 8 / uptime.tv_sec; + bps_tx_avg = send_total * 8 / uptime.tv_sec; + bps_rx_avg = recv_total * 8 / uptime.tv_sec; + + vty_out (vty, " Statistics of interface %s%s", + o6i->interface->name, VTY_NEWLINE); + vty_out (vty, " Number of Neighbor: %d%s", + listcount (o6i->neighbor_list), VTY_NEWLINE); + + vty_out (vty, " %-8s %6s %6s %8s %8s%s", + "Type", "tx", "rx", "tx-byte", "rx-byte", VTY_NEWLINE); + for (i = 0; i < OSPF6_MESSAGE_TYPE_MAX; i++) + { + vty_out (vty, " %-8s %6d %6d %8d %8d%s", + ospf6_message_type_string[i], + o6i->message_stat[i].send, + o6i->message_stat[i].recv, + o6i->message_stat[i].send_octet, + o6i->message_stat[i].recv_octet, + VTY_NEWLINE); + } + + vty_out (vty, " Average Link bandwidth: %ldbps" + " (Tx: %ldbps Rx: %ldbps)%s", + bps_total_avg, bps_tx_avg, bps_rx_avg, VTY_NEWLINE); +} + +/* show interface */ +DEFUN (show_ipv6_ospf6_interface, + show_ipv6_ospf6_interface_ifname_cmd, + "show ipv6 ospf6 interface IFNAME", + SHOW_STR + IP6_STR + OSPF6_STR + INTERFACE_STR + IFNAME_STR + ) +{ + struct interface *ifp; + listnode i; + + if (argc) + { + ifp = if_lookup_by_name (argv[0]); + if (!ifp) + { + vty_out (vty, "No such Interface: %s%s", argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + ospf6_interface_show (vty, ifp); + } + else + { + for (i = listhead (iflist); i; nextnode (i)) + { + ifp = (struct interface *)getdata (i); + ospf6_interface_show (vty, ifp); + } + } + return CMD_SUCCESS; +} + +ALIAS (show_ipv6_ospf6_interface, + show_ipv6_ospf6_interface_cmd, + "show ipv6 ospf6 interface", + SHOW_STR + IP6_STR + OSPF6_STR + INTERFACE_STR + ) + +/* interface variable set command */ +DEFUN (ipv6_ospf6_cost, + ipv6_ospf6_cost_cmd, + "ipv6 ospf6 cost COST", + IP6_STR + OSPF6_STR + "Interface cost\n" + "<1-65535> Cost\n" + ) +{ + struct ospf6_interface *o6i; + struct interface *ifp; + + ifp = (struct interface *)vty->index; + assert (ifp); + + o6i = (struct ospf6_interface *)ifp->info; + if (!o6i) + o6i = ospf6_interface_create (ifp); + assert (o6i); + + if (o6i->cost == strtol (argv[0], NULL, 10)) + return CMD_SUCCESS; + + o6i->cost = strtol (argv[0], NULL, 10); + + /* execute LSA hooks */ + CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, o6i); + + CALL_CHANGE_HOOK (&interface_hook, o6i); + + return CMD_SUCCESS; +} + +/* interface variable set command */ +DEFUN (ipv6_ospf6_hellointerval, + ipv6_ospf6_hellointerval_cmd, + "ipv6 ospf6 hello-interval HELLO_INTERVAL", + IP6_STR + OSPF6_STR + "Time between HELLO packets\n" + SECONDS_STR + ) +{ + struct ospf6_interface *ospf6_interface; + struct interface *ifp; + + ifp = (struct interface *) vty->index; + assert (ifp); + ospf6_interface = (struct ospf6_interface *) ifp->info; + if (!ospf6_interface) + ospf6_interface = ospf6_interface_create (ifp); + assert (ospf6_interface); + + ospf6_interface->hello_interval = strtol (argv[0], NULL, 10); + return CMD_SUCCESS; +} + +/* interface variable set command */ +DEFUN (ipv6_ospf6_deadinterval, + ipv6_ospf6_deadinterval_cmd, + "ipv6 ospf6 dead-interval ROUTER_DEAD_INTERVAL", + IP6_STR + OSPF6_STR + "Interval after which a neighbor is declared dead\n" + SECONDS_STR + ) +{ + struct ospf6_interface *ospf6_interface; + struct interface *ifp; + + ifp = (struct interface *) vty->index; + assert (ifp); + ospf6_interface = (struct ospf6_interface *) ifp->info; + if (!ospf6_interface) + ospf6_interface = ospf6_interface_create (ifp); + assert (ospf6_interface); + + ospf6_interface->dead_interval = strtol (argv[0], NULL, 10); + return CMD_SUCCESS; +} + +/* interface variable set command */ +DEFUN (ipv6_ospf6_transmitdelay, + ipv6_ospf6_transmitdelay_cmd, + "ipv6 ospf6 transmit-delay TRANSMITDELAY", + IP6_STR + OSPF6_STR + "Link state transmit delay\n" + SECONDS_STR + ) +{ + struct ospf6_interface *ospf6_interface; + struct interface *ifp; + + ifp = (struct interface *) vty->index; + assert (ifp); + ospf6_interface = (struct ospf6_interface *) ifp->info; + if (!ospf6_interface) + ospf6_interface = ospf6_interface_create (ifp); + assert (ospf6_interface); + + ospf6_interface->transdelay = strtol (argv[0], NULL, 10); + return CMD_SUCCESS; +} + +/* interface variable set command */ +DEFUN (ipv6_ospf6_retransmitinterval, + ipv6_ospf6_retransmitinterval_cmd, + "ipv6 ospf6 retransmit-interval RXMTINTERVAL", + IP6_STR + OSPF6_STR + "Time between retransmitting lost link state advertisements\n" + SECONDS_STR + ) +{ + struct ospf6_interface *ospf6_interface; + struct interface *ifp; + + ifp = (struct interface *) vty->index; + assert (ifp); + ospf6_interface = (struct ospf6_interface *) ifp->info; + if (!ospf6_interface) + ospf6_interface = ospf6_interface_create (ifp); + assert (ospf6_interface); + + ospf6_interface->rxmt_interval = strtol (argv[0], NULL, 10); + return CMD_SUCCESS; +} + +/* interface variable set command */ +DEFUN (ipv6_ospf6_priority, + ipv6_ospf6_priority_cmd, + "ipv6 ospf6 priority PRIORITY", + IP6_STR + OSPF6_STR + "Router priority\n" + "<0-255> Priority\n" + ) +{ + struct ospf6_interface *ospf6_interface; + struct interface *ifp; + + ifp = (struct interface *) vty->index; + assert (ifp); + ospf6_interface = (struct ospf6_interface *) ifp->info; + if (!ospf6_interface) + ospf6_interface = ospf6_interface_create (ifp); + assert (ospf6_interface); + + ospf6_interface->priority = strtol (argv[0], NULL, 10); + + if (ospf6_interface->area) + ifs_change (dr_election (ospf6_interface), "Priority reconfigured", + ospf6_interface); + + return CMD_SUCCESS; +} + +DEFUN (ipv6_ospf6_instance, + ipv6_ospf6_instance_cmd, + "ipv6 ospf6 instance-id INSTANCE", + IP6_STR + OSPF6_STR + "Instance ID\n" + "<0-255> Instance ID\n" + ) +{ + struct ospf6_interface *ospf6_interface; + struct interface *ifp; + + ifp = (struct interface *)vty->index; + assert (ifp); + + ospf6_interface = (struct ospf6_interface *)ifp->info; + if (!ospf6_interface) + ospf6_interface = ospf6_interface_create (ifp); + assert (ospf6_interface); + + ospf6_interface->instance_id = strtol (argv[0], NULL, 10); + return CMD_SUCCESS; +} + +DEFUN (ipv6_ospf6_passive, + ipv6_ospf6_passive_cmd, + "ipv6 ospf6 passive", + IP6_STR + OSPF6_STR + "passive interface: No Adjacency will be formed on this I/F\n" + ) +{ + struct ospf6_interface *o6i; + struct interface *ifp; + listnode node; + struct ospf6_neighbor *o6n; + + ifp = (struct interface *) vty->index; + assert (ifp); + o6i = (struct ospf6_interface *) ifp->info; + if (! o6i) + o6i = ospf6_interface_create (ifp); + assert (o6i); + + SET_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_PASSIVE); + if (o6i->thread_send_hello) + { + thread_cancel (o6i->thread_send_hello); + o6i->thread_send_hello = (struct thread *) NULL; + } + + for (node = listhead (o6i->neighbor_list); node; nextnode (node)) + { + o6n = getdata (node); + if (o6n->inactivity_timer) + thread_cancel (o6n->inactivity_timer); + thread_execute (master, inactivity_timer, o6n, 0); + } + + return CMD_SUCCESS; +} + +DEFUN (no_ipv6_ospf6_passive, + no_ipv6_ospf6_passive_cmd, + "no ipv6 ospf6 passive", + NO_STR + IP6_STR + OSPF6_STR + "passive interface: No Adjacency will be formed on this I/F\n" + ) +{ + struct ospf6_interface *o6i; + struct interface *ifp; + + ifp = (struct interface *) vty->index; + assert (ifp); + o6i = (struct ospf6_interface *) ifp->info; + if (! o6i) + o6i = ospf6_interface_create (ifp); + assert (o6i); + + UNSET_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_PASSIVE); + if (o6i->thread_send_hello == NULL) + thread_add_event (master, ospf6_send_hello, o6i, 0); + + return CMD_SUCCESS; +} + + +DEFUN (ipv6_ospf6_advertise_force_prefix, + ipv6_ospf6_advertise_force_prefix_cmd, + "ipv6 ospf6 advertise force-prefix", + IP6_STR + OSPF6_STR + "Advertising options\n" + "Force advertising prefix, applicable if Loopback or P-to-P\n" + ) +{ + struct ospf6_interface *o6i; + struct interface *ifp; + + ifp = (struct interface *) vty->index; + assert (ifp); + o6i = (struct ospf6_interface *) ifp->info; + if (! o6i) + o6i = ospf6_interface_create (ifp); + assert (o6i); + + if (! if_is_loopback (ifp) && ! if_is_pointopoint (ifp)) + { + vty_out (vty, "Interface not Loopback nor PointToPoint%s", + VTY_NEWLINE); + return CMD_ERR_NOTHING_TODO; + } + + SET_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_FORCE_PREFIX); + + /* execute LSA hooks */ + CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, o6i); + + CALL_CHANGE_HOOK (&interface_hook, o6i); + + return CMD_SUCCESS; +} + +DEFUN (no_ipv6_ospf6_advertise_force_prefix, + no_ipv6_ospf6_advertise_force_prefix_cmd, + "no ipv6 ospf6 advertise force-prefix", + NO_STR + IP6_STR + OSPF6_STR + "Advertising options\n" + "Force to advertise prefix, applicable if Loopback or P-to-P\n" + ) +{ + struct ospf6_interface *o6i; + struct interface *ifp; + + ifp = (struct interface *) vty->index; + assert (ifp); + o6i = (struct ospf6_interface *) ifp->info; + if (! o6i) + o6i = ospf6_interface_create (ifp); + assert (o6i); + + UNSET_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_FORCE_PREFIX); + + /* execute LSA hooks */ + CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, o6i); + + CALL_CHANGE_HOOK (&interface_hook, o6i); + + return CMD_SUCCESS; +} + +DEFUN (ipv6_ospf6_advertise_prefix_list, + ipv6_ospf6_advertise_prefix_list_cmd, + "ipv6 ospf6 advertise prefix-list WORD", + IP6_STR + OSPF6_STR + "Advertising options\n" + "Filter prefix using prefix-list\n" + "Prefix list name\n" + ) +{ + struct ospf6_interface *o6i; + struct interface *ifp; + + ifp = (struct interface *) vty->index; + assert (ifp); + o6i = (struct ospf6_interface *) ifp->info; + if (! o6i) + o6i = ospf6_interface_create (ifp); + assert (o6i); + + if (o6i->plist_name) + XFREE (MTYPE_PREFIX_LIST_STR, o6i->plist_name); + o6i->plist_name = XSTRDUP (MTYPE_PREFIX_LIST_STR, argv[0]); + + /* execute LSA hooks */ + CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, o6i); + + CALL_CHANGE_HOOK (&interface_hook, o6i); + + return CMD_SUCCESS; +} + +DEFUN (no_ipv6_ospf6_advertise_prefix_list, + no_ipv6_ospf6_advertise_prefix_list_cmd, + "no ipv6 ospf6 advertise prefix-list", + NO_STR + IP6_STR + OSPF6_STR + "Advertising options\n" + "Filter prefix using prefix-list\n" + ) +{ + struct ospf6_interface *o6i; + struct interface *ifp; + + ifp = (struct interface *) vty->index; + assert (ifp); + o6i = (struct ospf6_interface *) ifp->info; + if (! o6i) + o6i = ospf6_interface_create (ifp); + assert (o6i); + + if (o6i->plist_name) + { + XFREE (MTYPE_PREFIX_LIST_STR, o6i->plist_name); + o6i->plist_name = NULL; + } + + /* execute LSA hooks */ + CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, o6i); + + CALL_CHANGE_HOOK (&interface_hook, o6i); + + return CMD_SUCCESS; +} + +int +ospf6_interface_config_write (struct vty *vty) +{ + listnode i; + struct ospf6_interface *o6i; + struct interface *ifp; + + for (i = listhead (iflist); i; nextnode (i)) + { + ifp = (struct interface *) getdata (i); + o6i = (struct ospf6_interface *) ifp->info; + if (! o6i) + continue; + + vty_out (vty, "interface %s%s", + o6i->interface->name, VTY_NEWLINE); + vty_out (vty, " ipv6 ospf6 cost %d%s", + o6i->cost, VTY_NEWLINE); + vty_out (vty, " ipv6 ospf6 hello-interval %d%s", + o6i->hello_interval, VTY_NEWLINE); + vty_out (vty, " ipv6 ospf6 dead-interval %d%s", + o6i->dead_interval, VTY_NEWLINE); + vty_out (vty, " ipv6 ospf6 retransmit-interval %d%s", + o6i->rxmt_interval, VTY_NEWLINE); + vty_out (vty, " ipv6 ospf6 priority %d%s", + o6i->priority, VTY_NEWLINE); + vty_out (vty, " ipv6 ospf6 transmit-delay %d%s", + o6i->transdelay, VTY_NEWLINE); + vty_out (vty, " ipv6 ospf6 instance-id %d%s", + o6i->instance_id, VTY_NEWLINE); + + if (CHECK_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_FORCE_PREFIX)) + vty_out (vty, " ipv6 ospf6 advertise force-prefix%s", VTY_NEWLINE); + if (o6i->plist_name) + vty_out (vty, " ipv6 ospf6 advertise prefix-list %s%s", + o6i->plist_name, VTY_NEWLINE); + + if (CHECK_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_PASSIVE)) + vty_out (vty, " ipv6 ospf6 passive%s", VTY_NEWLINE); + + vty_out (vty, "!%s", VTY_NEWLINE); + } + return 0; +} + +struct cmd_node interface_node = +{ + INTERFACE_NODE, + "%s(config-if)# ", +}; + +void +ospf6_interface_init () +{ + /* Install interface node. */ + install_node (&interface_node, ospf6_interface_config_write); + + install_element (VIEW_NODE, &show_ipv6_ospf6_interface_cmd); + install_element (VIEW_NODE, &show_ipv6_ospf6_interface_ifname_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_ifname_cmd); + + install_default (INTERFACE_NODE); + install_element (INTERFACE_NODE, &interface_desc_cmd); + install_element (INTERFACE_NODE, &no_interface_desc_cmd); + install_element (INTERFACE_NODE, &ipv6_ospf6_cost_cmd); + install_element (INTERFACE_NODE, &ipv6_ospf6_deadinterval_cmd); + install_element (INTERFACE_NODE, &ipv6_ospf6_hellointerval_cmd); + install_element (INTERFACE_NODE, &ipv6_ospf6_priority_cmd); + install_element (INTERFACE_NODE, &ipv6_ospf6_retransmitinterval_cmd); + install_element (INTERFACE_NODE, &ipv6_ospf6_transmitdelay_cmd); + install_element (INTERFACE_NODE, &ipv6_ospf6_instance_cmd); + install_element (INTERFACE_NODE, &ipv6_ospf6_advertise_force_prefix_cmd); + install_element (INTERFACE_NODE, &no_ipv6_ospf6_advertise_force_prefix_cmd); + install_element (INTERFACE_NODE, &ipv6_ospf6_advertise_prefix_list_cmd); + install_element (INTERFACE_NODE, &no_ipv6_ospf6_advertise_prefix_list_cmd); + install_element (INTERFACE_NODE, &ipv6_ospf6_passive_cmd); + install_element (INTERFACE_NODE, &no_ipv6_ospf6_passive_cmd); +} + + diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h new file mode 100644 index 000000000..a96ef25a7 --- /dev/null +++ b/ospf6d/ospf6_interface.h @@ -0,0 +1,153 @@ +/* + * Copyright (C) 1999 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF6_INTERFACE_H +#define OSPF6_INTERFACE_H + +#include "ospf6_message.h" + +/* This file defines interface data structure. */ + +struct ospf6_interface +{ + /* IF info from zebra */ + struct interface *interface; + + /* back pointer */ + struct ospf6_area *area; + + /* list of ospf6 neighbor */ + list neighbor_list; + + /* linklocal address of this I/F */ + struct in6_addr *lladdr; + + /* Interface ID; same as ifindex */ + u_int32_t if_id; + + /* ospf6 instance id */ + u_char instance_id; + + /* I/F transmission delay */ + u_int32_t transdelay; + + /* Router Priority */ + u_char priority; + + /* Timers */ + u_int16_t hello_interval; + u_int16_t dead_interval; + u_int32_t rxmt_interval; + + /* Cost */ + u_int32_t cost; + + /* I/F MTU */ + u_int32_t ifmtu; + + /* Interface State */ + u_char state; + + /* OSPF6 Interface flag */ + char flag; + + /* Decision of DR Election */ + u_int32_t dr; + u_int32_t bdr; + u_int32_t prevdr; + u_int32_t prevbdr; + + /* Ongoing Tasks */ + struct thread *thread_send_hello; + struct thread *thread_send_lsack_delayed; + + /* LSAs to Delayed Acknowledge */ + struct ospf6_lsdb *ack_list; + + /* Linklocal LSA Database: includes Link-LSA */ + struct ospf6_lsdb *lsdb; + + /* statistics */ + u_int ospf6_stat_dr_election; + u_int ospf6_stat_delayed_lsack; + + struct ospf6_message_stat message_stat[OSPF6_MESSAGE_TYPE_MAX]; + + void (*foreach_nei) (struct ospf6_interface *, void *, int, + void (*func) (void *, int, void *)); + + struct thread *maxage_remover; + + /* route-map to filter connected prefix */ + char *plist_name; +}; + +extern char *ospf6_interface_state_string[]; + +#define OSPF6_INTERFACE_FLAG_PASSIVE 0x01 +#define OSPF6_INTERFACE_FLAG_FORCE_PREFIX 0x02 + + +/* Function Prototypes */ + +void +ospf6_interface_schedule_maxage_remover (void *arg, int val, void *obj); + +struct ospf6_interface * +ospf6_interface_create (struct interface *); +void +ospf6_interface_delete (struct ospf6_interface *); + +struct ospf6_interface * +ospf6_interface_lookup_by_index (int); +struct ospf6_interface * +ospf6_interface_lookup_by_name (char *); + +void ospf6_interface_if_add (struct interface *); +void ospf6_interface_if_del (struct interface *); +void ospf6_interface_state_update (struct interface *); +void ospf6_interface_address_update (struct interface *); + +void ospf6_interface_init (); + +#if 0 +int +ospf6_interface_count_neighbor_in_state (u_char state, + struct ospf6_interface *o6i); +int +ospf6_interface_count_full_neighbor (struct ospf6_interface *); +#endif + +int ospf6_interface_is_enabled (u_int32_t ifindex); + +void +ospf6_interface_delayed_ack_add (struct ospf6_lsa *lsa, + struct ospf6_interface *o6i); +void +ospf6_interface_delayed_ack_remove (struct ospf6_lsa *lsa, + struct ospf6_interface *o6i); + +void +ospf6_interface_statistics_show (struct vty *vty, + struct ospf6_interface *o6i); + +#endif /* OSPF6_INTERFACE_H */ + diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c new file mode 100644 index 000000000..b9c9ebd06 --- /dev/null +++ b/ospf6d/ospf6_intra.c @@ -0,0 +1,896 @@ +/* + * Copyright (C) 2002 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "ospf6d.h" + +static int intra_index; +#define IS_OSPF6_DUMP_INTRA (ospf6_dump_is_on (intra_index)) + +#define ADD 0 +#define REMOVE 1 + +static void +ospf6_intra_route_calculate (int type, struct ospf6_lsa *lsa, + struct ospf6_route_req *topo_entry) +{ + struct ospf6_intra_area_prefix_lsa *intra_prefix; + char *start, *end; + struct ospf6_prefix *ospf6_prefix; + struct ospf6_route_req request; + struct ospf6_area *area; + + if (IS_OSPF6_DUMP_INTRA) + { + char buf[64]; + struct prefix_ls *p_ls; + p_ls = (struct prefix_ls *) &topo_entry->route.prefix; + inet_ntop (AF_INET, &p_ls->adv_router, buf, sizeof (buf)); + zlog_info ("INTRA: Calculate [%s] %s and %s", + (type == ADD ? "add" : "remove"), lsa->str, buf); + } + + intra_prefix = OSPF6_LSA_HEADER_END (lsa->header); + + area = lsa->scope; + assert (area); + + start = (char *) (intra_prefix + 1); + end = (char *) lsa->header + ntohs (lsa->header->length); + for (ospf6_prefix = (struct ospf6_prefix *) start; + (char *) ospf6_prefix < end; + ospf6_prefix = OSPF6_NEXT_PREFIX (ospf6_prefix)) + { + memset (&request, 0, sizeof (request)); + + request.route.type = OSPF6_DEST_TYPE_NETWORK; + request.route.prefix.family = AF_INET6; + request.route.prefix.prefixlen = ospf6_prefix->prefix_length; + ospf6_prefix_in6_addr (ospf6_prefix, &request.route.prefix.u.prefix6); + + request.path.type = OSPF6_PATH_TYPE_INTRA; + request.path.area_id = area->area_id; + request.path.origin.type = lsa->header->type; + request.path.origin.id = lsa->header->id; + request.path.origin.adv_router = lsa->header->adv_router; + request.path.cost = topo_entry->path.cost + + ntohs (ospf6_prefix->prefix_metric); + request.path.capability[0] = topo_entry->path.capability[0]; + request.path.capability[1] = topo_entry->path.capability[1]; + request.path.capability[2] = topo_entry->path.capability[2]; + + memcpy (&request.nexthop.address, &topo_entry->nexthop.address, + sizeof (request.nexthop.address)); + request.nexthop.ifindex = topo_entry->nexthop.ifindex; + + if (type == ADD) + ospf6_route_add (&request, area->route_table); + else if (type == REMOVE) + ospf6_route_remove (&request, area->route_table); + else + assert (0); + } +} + +int +ospf6_intra_prefix_database_hook_remove (void *data) +{ + struct ospf6_lsa *lsa = data; + struct ospf6_area *area; + struct ospf6_intra_area_prefix_lsa *iap; + struct prefix_ls prefix_ls; + struct ospf6_route_req topo_entry; + + if (lsa->header->type != htons (OSPF6_LSA_TYPE_INTRA_PREFIX)) + return 0; + + area = (struct ospf6_area *) lsa->scope; + assert (area); + + if (IS_OSPF6_DUMP_INTRA) + zlog_info ("INTRA: area %s remove: %s", area->str, lsa->str); + + iap = OSPF6_LSA_HEADER_END (lsa->header); + memset (&prefix_ls, 0, sizeof (prefix_ls)); + prefix_ls.prefixlen = 64; + prefix_ls.adv_router.s_addr = iap->refer_advrtr; + prefix_ls.id.s_addr = iap->refer_lsid; + + if (iap->refer_lstype == htons (OSPF6_LSA_TYPE_ROUTER) && + iap->refer_lsid != htonl (0)) + { + zlog_warn ("SPF: Malformed ID %lu of Router reference in %s", + (u_long) ntohl (iap->refer_lsid), lsa->str); + prefix_ls.id.s_addr = htonl (0); + } + + ospf6_route_lookup (&topo_entry, (struct prefix *) &prefix_ls, + area->table_topology); + + while (iap->refer_lstype == topo_entry.path.origin.type && + iap->refer_lsid == topo_entry.path.origin.id && + iap->refer_advrtr == topo_entry.path.origin.adv_router) + { + ospf6_intra_route_calculate (REMOVE, lsa, &topo_entry); + ospf6_route_next (&topo_entry); + } + return 0; +} + +int +ospf6_intra_prefix_database_hook_add (void *data) +{ + struct ospf6_lsa *lsa = data; + struct ospf6_area *area; + struct ospf6_intra_area_prefix_lsa *iap; + struct prefix_ls prefix_ls; + struct ospf6_route_req topo_entry; + + if (lsa->header->type != htons (OSPF6_LSA_TYPE_INTRA_PREFIX)) + return 0; + + area = (struct ospf6_area *) lsa->scope; + assert (area); + + if (IS_LSA_MAXAGE (lsa)) + { + ospf6_intra_prefix_database_hook_remove (lsa); + return 0; + } + + if (IS_OSPF6_DUMP_INTRA) + zlog_info ("INTRA: area %s add: %s", area->str, lsa->str); + + iap = OSPF6_LSA_HEADER_END (lsa->header); + + memset (&prefix_ls, 0, sizeof (struct prefix_ls)); + prefix_ls.prefixlen = 64; + prefix_ls.adv_router.s_addr = iap->refer_advrtr; + prefix_ls.id.s_addr = iap->refer_lsid; + + if (iap->refer_lstype == htons (OSPF6_LSA_TYPE_ROUTER) && + iap->refer_lsid != htonl (0)) + { + zlog_warn ("INTRA: Malformed ID %lu of Router reference in %s", + (u_long) ntohl (iap->refer_lsid), lsa->str); + prefix_ls.id.s_addr = htonl (0); + } + + ospf6_route_lookup (&topo_entry, (struct prefix *) &prefix_ls, + area->table_topology); + + while (iap->refer_lstype == topo_entry.path.origin.type && + iap->refer_lsid == topo_entry.path.origin.id && + iap->refer_advrtr == topo_entry.path.origin.adv_router) + { + ospf6_intra_route_calculate (ADD, lsa, &topo_entry); + ospf6_route_next (&topo_entry); + } + return 0; +} + +void +ospf6_intra_topology_add (void *data) +{ + struct ospf6_route_req *topo_entry = data; + struct ospf6_area *area; + struct ospf6_intra_area_prefix_lsa *iap; + struct ospf6_lsdb_node node; + + area = ospf6_area_lookup (topo_entry->path.area_id, ospf6); + if (! area) + return; + + if (topo_entry->route.type == OSPF6_DEST_TYPE_ROUTER && + (CHECK_FLAG (topo_entry->path.router_bits, OSPF6_ROUTER_LSA_BIT_B) || + CHECK_FLAG (topo_entry->path.router_bits, OSPF6_ROUTER_LSA_BIT_E))) + ospf6_route_add (topo_entry, ospf6->topology_table); + + for (ospf6_lsdb_type (&node, htons (OSPF6_LSA_TYPE_INTRA_PREFIX), + area->lsdb); + ! ospf6_lsdb_is_end (&node); + ospf6_lsdb_next (&node)) + { + if (IS_LSA_MAXAGE (node.lsa)) + continue; + + iap = OSPF6_LSA_HEADER_END (node.lsa->header); + + if (iap->refer_lstype == htons (OSPF6_LSA_TYPE_ROUTER) && + iap->refer_lsid != htonl (0)) + { + zlog_warn ("INTRA: Malformed ID %lu of Router reference in %s", + (u_long) ntohl (iap->refer_lsid), node.lsa->str); + } + + if (iap->refer_lstype != topo_entry->path.origin.type || + iap->refer_lsid != topo_entry->path.origin.id || + iap->refer_advrtr != topo_entry->path.origin.adv_router) + continue; + + ospf6_intra_route_calculate (ADD, node.lsa, topo_entry); + } +} + +void +ospf6_intra_topology_remove (void *data) +{ + struct ospf6_route_req *topo_entry = data; + struct ospf6_area *area; + struct ospf6_intra_area_prefix_lsa *iap; + struct ospf6_lsdb_node node; + + area = ospf6_area_lookup (topo_entry->path.area_id, ospf6); + if (! area) + return; + + if (topo_entry->route.type == OSPF6_DEST_TYPE_ROUTER && + (CHECK_FLAG (topo_entry->path.router_bits, OSPF6_ROUTER_LSA_BIT_B) || + CHECK_FLAG (topo_entry->path.router_bits, OSPF6_ROUTER_LSA_BIT_E))) + ospf6_route_remove (topo_entry, ospf6->topology_table); + + for (ospf6_lsdb_type (&node, htons (OSPF6_LSA_TYPE_INTRA_PREFIX), + area->lsdb); + ! ospf6_lsdb_is_end (&node); + ospf6_lsdb_next (&node)) + { + if (IS_LSA_MAXAGE (node.lsa)) + continue; + + iap = OSPF6_LSA_HEADER_END (node.lsa->header); + + if (iap->refer_lstype == htons (OSPF6_LSA_TYPE_ROUTER) && + iap->refer_lsid != htonl (0)) + zlog_warn ("SPF: Malformed ID %lu of Router reference in %s", + (u_long) ntohl (iap->refer_lsid), node.lsa->str); + + if (iap->refer_lstype != topo_entry->path.origin.type || + iap->refer_lsid != topo_entry->path.origin.id || + iap->refer_advrtr != topo_entry->path.origin.adv_router) + continue; + + ospf6_intra_route_calculate (REMOVE, node.lsa, topo_entry); + } +} + + +/*****************************************/ +/* RFC2740 3.4.3.7 Intra-Area-Prefix-LSA */ +/*****************************************/ + +#define CONTINUE_IF_ADDRESS_LINKLOCAL(addr)\ + if (IN6_IS_ADDR_LINKLOCAL (&(addr)->u.prefix6))\ + {\ + char buf[64];\ + prefix2str (addr, buf, sizeof (buf));\ + if (IS_OSPF6_DUMP_PREFIX)\ + zlog_info (" Filter out Linklocal: %s", buf);\ + continue;\ + } + +#define CONTINUE_IF_ADDRESS_UNSPECIFIED(addr)\ + if (IN6_IS_ADDR_UNSPECIFIED (&(addr)->u.prefix6))\ + {\ + char buf[64];\ + prefix2str (addr, buf, sizeof (buf));\ + if (IS_OSPF6_DUMP_PREFIX)\ + zlog_info (" Filter out Unspecified: %s", buf);\ + continue;\ + } + +#define CONTINUE_IF_ADDRESS_LOOPBACK(addr)\ + if (IN6_IS_ADDR_LOOPBACK (&(addr)->u.prefix6))\ + {\ + char buf[64];\ + prefix2str (addr, buf, sizeof (buf));\ + if (IS_OSPF6_DUMP_PREFIX)\ + zlog_info (" Filter out Loopback: %s", buf);\ + continue;\ + } + +#define CONTINUE_IF_ADDRESS_V4COMPAT(addr)\ + if (IN6_IS_ADDR_V4COMPAT (&(addr)->u.prefix6))\ + {\ + char buf[64];\ + prefix2str (addr, buf, sizeof (buf));\ + if (IS_OSPF6_DUMP_PREFIX)\ + zlog_info (" Filter out V4Compat: %s", buf);\ + continue;\ + } + +#define CONTINUE_IF_ADDRESS_V4MAPPED(addr)\ + if (IN6_IS_ADDR_V4MAPPED (&(addr)->u.prefix6))\ + {\ + char buf[64];\ + prefix2str (addr, buf, sizeof (buf));\ + if (IS_OSPF6_DUMP_PREFIX)\ + zlog_info (" Filter out V4Mapped: %s", buf);\ + continue;\ + } + + +int +ospf6_lsa_intra_prefix_show (struct vty *vty, struct ospf6_lsa *lsa) +{ + struct ospf6_intra_area_prefix_lsa *iap_lsa; + struct ospf6_prefix *prefix; + unsigned short prefixnum; + char buf[128], type[32], id[32], adv_router[32]; + struct in6_addr in6; + char *start, *end, *current; + + assert (lsa->header); + iap_lsa = (struct ospf6_intra_area_prefix_lsa *) (lsa->header + 1); + + prefixnum = ntohs (iap_lsa->prefix_number); + ospf6_lsa_type_string (iap_lsa->refer_lstype, type, sizeof (type)); + inet_ntop (AF_INET, &iap_lsa->refer_lsid, id, sizeof (id)); + inet_ntop (AF_INET, &iap_lsa->refer_advrtr, adv_router, + sizeof (adv_router)); + + vty_out (vty, " Number of Prefix: %d%s", prefixnum, VTY_NEWLINE); + vty_out (vty, " Referenced LS Type: %s%s", type, VTY_NEWLINE); + vty_out (vty, " Referenced LS ID: %s%s", id, VTY_NEWLINE); + vty_out (vty, " Referenced Advertising Router: %s%s", adv_router, + VTY_NEWLINE); + + start = (char *) lsa->header + sizeof (struct ospf6_lsa_header) + + sizeof (struct ospf6_intra_area_prefix_lsa); + end = (char *) lsa->header + ntohs (lsa->header->length); + + for (current = start; current < end; current += OSPF6_PREFIX_SIZE (prefix)) + { + prefix = (struct ospf6_prefix *) current; + if (current + OSPF6_PREFIX_SIZE (prefix) > end) + { + vty_out (vty, " Trailing %d byte garbage ... Malformed%s", + end - current, VTY_NEWLINE); + return -1; + } + + ospf6_prefix_options_str (prefix->prefix_options, buf, sizeof (buf)); + vty_out (vty, " Prefix Options: %s%s", buf, VTY_NEWLINE); + + ospf6_prefix_in6_addr (prefix, &in6); + inet_ntop (AF_INET6, &in6, buf, sizeof (buf)); + vty_out (vty, " Prefix: %s/%d%s", + buf, prefix->prefix_length, VTY_NEWLINE); + } + + return 0; +} + +void +ospf6_lsa_intra_prefix_update_transit (char *ifname) +{ + char buffer [MAXLSASIZE]; + u_int16_t size; + struct ospf6_lsa *old; + struct interface *ifp; + struct ospf6_interface *o6i; + struct ospf6_neighbor *o6n; + + struct ospf6_intra_area_prefix_lsa *iap; + struct ospf6_lsdb_node n; + listnode node; + char *start, *end, *current; + struct ospf6_prefix *prefix, *dup, *src, *dst; + struct ospf6_link_lsa *link; + char buf[128]; + int count, prefix_num; + + list adv_list; + + ifp = if_lookup_by_name (ifname); + if (! ifp) + { + zlog_warn ("Update Intra-Prefix (Transit): No such Interface: %s", + ifname); + return; + } + + o6i = (struct ospf6_interface *) ifp->info; + if (! o6i || ! o6i->area) + { + zlog_warn ("Update Intra-Prefix (Transit): Interface not enabled: %s", + ifname); + return; + } + + /* find previous LSA */ + old = ospf6_lsdb_lookup (htons (OSPF6_LSA_TYPE_INTRA_PREFIX), + htonl (o6i->if_id), ospf6->router_id, + o6i->area); + + /* Don't originate Network-LSA if not DR */ + if (o6i->state != IFS_DR) + { + if (old) + { + if (IS_OSPF6_DUMP_PREFIX) + zlog_info ("Update Intra-Prefix (Transit): %s not DR", + o6i->interface->name); + ospf6_lsa_premature_aging (old); + } + return; + } + + /* If none of neighbor is adjacent to us */ + count = 0; + o6i->foreach_nei (o6i, &count, NBS_FULL, ospf6_count_state); + if (count == 0) + { + if (IS_OSPF6_DUMP_PREFIX) + zlog_info ("Update Intra-Prefix (Transit): %s is Stub", + o6i->interface->name); + if (old) + ospf6_lsa_premature_aging (old); + return; + } + + if (IS_OSPF6_DUMP_PREFIX) + zlog_info ("Update Intra-Prefix (Transit): Interface %s", + o6i->interface->name); + + adv_list = list_new (); + + /* foreach Link-LSA associated with this Link */ + for (ospf6_lsdb_type (&n, htons (OSPF6_LSA_TYPE_LINK), o6i->lsdb); + ! ospf6_lsdb_is_end (&n); ospf6_lsdb_next (&n)) + { + if (IS_LSA_MAXAGE (n.lsa)) + continue; + + if (IS_OSPF6_DUMP_PREFIX) + zlog_info ("Update Intra-Prefix (Transit): Checking %s", + n.lsa->str); + + /* Check status of the advertising router */ + if (n.lsa->header->adv_router != o6i->area->ospf6->router_id) + { + o6n = ospf6_neighbor_lookup (n.lsa->header->adv_router, o6i); + if (! o6n) + { + if (IS_OSPF6_DUMP_PREFIX) + zlog_info ("Update Intra-Prefix (Transit): neighbor not found"); + continue; + } + + if (o6n->state != NBS_FULL) + { + if (IS_OSPF6_DUMP_PREFIX) + zlog_info ("Update Intra-Prefix (Transit): %s not FULL", + o6n->str); + continue; + } + } + + /* For each Prefix in this Link-LSA */ + link = (struct ospf6_link_lsa *) (n.lsa->header + 1); + prefix_num = ntohl (link->llsa_prefix_num); + + if (IS_OSPF6_DUMP_PREFIX) + zlog_info (" Prefix #%d", prefix_num); + + start = (char *) (link + 1); + end = (char *) (n.lsa->header) + ntohs (n.lsa->header->length); + prefix = (struct ospf6_prefix *) start; + for (current = start; current < end; + current += OSPF6_PREFIX_SIZE (prefix)) + { + prefix = (struct ospf6_prefix *) current; + ospf6_prefix_string (prefix, buf, sizeof (buf)); + + /* Check duplicate prefix */ + dup = ospf6_prefix_lookup (adv_list, prefix); + if (dup) + { + if (IS_OSPF6_DUMP_PREFIX) + zlog_info (" Duplicate %s", buf); + dup->prefix_options |= prefix->prefix_options; + continue; + } + + if (prefix_num <= 0) + { + zlog_warn (" Wong prefix number ..."); + break; + } + + if (IS_OSPF6_DUMP_PREFIX) + zlog_info (" Prefix %s", buf); + + /* copy prefix to advertise list */ + ospf6_prefix_add (adv_list, prefix); + + prefix_num --; + } + } + + /* if no prefix to advertise, return */ + if (listcount (adv_list) == 0) + { + if (IS_OSPF6_DUMP_PREFIX) + zlog_info (" No Prefix to advertise"); + if (old) + ospf6_lsa_premature_aging (old); + return; + } + + /* prepare buffer */ + memset (buffer, 0, sizeof (buffer)); + size = sizeof (struct ospf6_intra_area_prefix_lsa); + iap = (struct ospf6_intra_area_prefix_lsa *) buffer; + + /* Set Referenced LSA field */ + iap->refer_lstype = htons (OSPF6_LSA_TYPE_NETWORK); + iap->refer_lsid = htonl (o6i->if_id); + iap->refer_advrtr = o6i->area->ospf6->router_id; + + dst = (struct ospf6_prefix *) (iap + 1); + for (node = listhead (adv_list); node; nextnode (node)) + { + src = (struct ospf6_prefix *) getdata (node); + + memcpy (dst, src, OSPF6_PREFIX_SIZE (src)); + + size += OSPF6_PREFIX_SIZE (dst); + dst = OSPF6_NEXT_PREFIX (dst); + } + iap->prefix_number = htons (listcount (adv_list)); + + while ((node = listhead (adv_list)) != NULL) + { + prefix = getdata (node); + ospf6_prefix_delete (prefix); + listnode_delete (adv_list, prefix); + } + list_delete (adv_list); + + ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_INTRA_PREFIX), + htonl (o6i->if_id), ospf6->router_id, + buffer, size, o6i->area); +} + +void +ospf6_lsa_intra_prefix_update_stub (u_int32_t area_id) +{ + char buffer [MAXLSASIZE]; + u_int16_t size; + struct ospf6_lsa *old; + struct ospf6_area *o6a; + int count; + + struct ospf6_intra_area_prefix_lsa *iap; + listnode i,j; + struct ospf6_interface *o6i = NULL; + struct ospf6_prefix *prefix, *dst, *src; + struct connected *c; + char buf[128]; + + list adv_list; + listnode node; + char prefix_buf[sizeof (struct ospf6_prefix) + sizeof (struct in6_addr)]; + + o6a = ospf6_area_lookup (area_id, ospf6); + if (! o6a) + { + char tmp[16]; + inet_ntop (AF_INET, &area_id, tmp, sizeof (tmp)); + zlog_warn ("Update Intra-Prefix (Stub): No such area: %s", tmp); + return; + } + else if (IS_OSPF6_DUMP_PREFIX) + { + zlog_info ("Update Intra-Prefix (Stub): area: %s", o6a->str); + } + + /* find previous LSA */ + old = ospf6_lsdb_lookup (htons (OSPF6_LSA_TYPE_INTRA_PREFIX), + htonl (0), ospf6->router_id, + o6a); /* xxx, ls-id */ + + adv_list = list_new (); + + /* Examin for each interface */ + for (i = listhead (o6a->if_list); i; nextnode (i)) + { + o6i = (struct ospf6_interface *) getdata (i); + + if (o6i->state == IFS_DOWN) + { + if (IS_OSPF6_DUMP_PREFIX) + zlog_info (" Interface %s: down", o6i->interface->name); + continue; + } + + count = 0; + o6i->foreach_nei (o6i, &count, NBS_FULL, ospf6_count_state); + if (o6i->state != IFS_LOOPBACK && o6i->state != IFS_PTOP && + count != 0) + { + /* This interface's prefix will be included in DR's */ + if (IS_OSPF6_DUMP_PREFIX) + zlog_info (" Interface %s: not stub", o6i->interface->name); + continue; + } + + if (IS_OSPF6_DUMP_PREFIX) + zlog_info (" Interface %s:", o6i->interface->name); + + /* copy foreach address prefix */ + for (j = listhead (o6i->interface->connected); j; nextnode (j)) + { + c = (struct connected *) getdata (j); + + /* filter prefix not IPv6 */ + if (c->address->family != AF_INET6) + continue; + + /* for log */ + prefix2str (c->address, buf, sizeof (buf)); + + CONTINUE_IF_ADDRESS_LINKLOCAL (c->address); + CONTINUE_IF_ADDRESS_UNSPECIFIED (c->address); + CONTINUE_IF_ADDRESS_LOOPBACK (c->address); + CONTINUE_IF_ADDRESS_V4COMPAT (c->address); + CONTINUE_IF_ADDRESS_V4MAPPED (c->address); + + /* filter prefix specified by configuration */ + if (o6i->plist_name) + { + struct prefix_list *plist; + enum prefix_list_type result = PREFIX_PERMIT; + + plist = prefix_list_lookup (AFI_IP6, o6i->plist_name); + if (plist) + result = prefix_list_apply (plist, c->address); + else + zlog_warn ("Update Intra-Prefix (Stub): " + "Prefix list \"%s\" not found", + o6i->plist_name); + + if (result == PREFIX_DENY) + { + if (IS_OSPF6_DUMP_PREFIX) + zlog_info (" %s: Filtered by %s", + buf, o6i->plist_name); + continue; + } + } + + /* initialize buffer for ospf6 prefix */ + memset (prefix_buf, 0, sizeof (prefix_buf)); + prefix = (struct ospf6_prefix *) prefix_buf; + + /* set ospf6 prefix according to its state */ + /* xxx, virtual links */ + if (! CHECK_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_FORCE_PREFIX) && + (o6i->state == IFS_LOOPBACK || o6i->state == IFS_PTOP + /* xxx, PoinToMultiPoint I/F type */ )) + { + prefix->prefix_length = 128; + prefix->prefix_options = OSPF6_PREFIX_OPTION_LA; + prefix->prefix_metric = htons (0); + memcpy (prefix + 1, &c->address->u.prefix6, + OSPF6_PREFIX_SPACE (prefix->prefix_length)); + } + else + { + struct prefix_ipv6 prefix_ipv6; + /* apply mask */ + prefix_copy ((struct prefix *) &prefix_ipv6, c->address); + apply_mask_ipv6 (&prefix_ipv6); + + prefix->prefix_length = prefix_ipv6.prefixlen; + prefix->prefix_options = 0; /* xxx, no options yet */ + prefix->prefix_metric = htons (o6i->cost); + memcpy (prefix + 1, &prefix_ipv6.prefix, + OSPF6_PREFIX_SPACE (prefix->prefix_length)); + } + + ospf6_prefix_string (prefix, buf, sizeof (buf)); + if (IS_OSPF6_DUMP_PREFIX) + zlog_info (" Advertise %s", buf); + + /* check in the prefix to advertising prefix list */ + ospf6_prefix_add (adv_list, prefix); + } + } + + /* If no prefix to advertise */ + if (listcount (adv_list) == 0) + { + if (IS_OSPF6_DUMP_PREFIX) + zlog_info (" No prefix to advertise"); + if (old) + ospf6_lsa_premature_aging (old); + return; + } + + /* prepare buffer */ + memset (buffer, 0, sizeof (buffer)); + size = sizeof (struct ospf6_intra_area_prefix_lsa); + iap = (struct ospf6_intra_area_prefix_lsa *) buffer; + + /* Set Referenced LSA field */ + iap->refer_lstype = htons (OSPF6_LSA_TYPE_ROUTER); + iap->refer_lsid = htonl (0); + iap->refer_advrtr = o6a->ospf6->router_id; + + dst = (struct ospf6_prefix *) (iap + 1); + for (node = listhead (adv_list); node; nextnode (node)) + { + src = (struct ospf6_prefix *) getdata (node); + + memcpy (dst, src, OSPF6_PREFIX_SIZE (src)); + + size += OSPF6_PREFIX_SIZE (dst); + dst = OSPF6_NEXT_PREFIX (dst); + } + iap->prefix_number = htons (listcount (adv_list)); + + while ((node = listhead (adv_list)) != NULL) + { + prefix = getdata (node); + ospf6_prefix_delete (prefix); + listnode_delete (adv_list, prefix); + } + list_delete (adv_list); + + ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_INTRA_PREFIX), + htonl (0) /* xxx */, ospf6->router_id, + buffer, size, o6a); +} + +int +ospf6_lsa_intra_prefix_hook_interface (void *interface) +{ + struct ospf6_interface *o6i = interface; + if (o6i->area) + { + ospf6_lsa_intra_prefix_update_transit (o6i->interface->name); + ospf6_lsa_intra_prefix_update_stub (o6i->area->area_id); + } + return 0; +} + +int +ospf6_lsa_intra_prefix_hook_neighbor (void *neighbor) +{ + struct ospf6_neighbor *o6n = neighbor; + if (o6n->ospf6_interface->area) + { + ospf6_lsa_intra_prefix_update_transit (o6n->ospf6_interface->interface->name); + ospf6_lsa_intra_prefix_update_stub (o6n->ospf6_interface->area->area_id); + } + return 0; +} + +int +ospf6_intra_prefix_link_database_hook (void *new) +{ + struct ospf6_lsa *lsa = new; + struct ospf6_interface *o6i; + + if (lsa->header->type != htons (OSPF6_LSA_TYPE_LINK)) + return 0; + + o6i = lsa->scope; + if (o6i->state != IFS_DR) + return 0; + + ospf6_lsa_intra_prefix_update_transit (o6i->interface->name); + ospf6_lsa_intra_prefix_update_stub (o6i->area->area_id); + return 0; +} + +int +ospf6_lsa_intra_prefix_refresh (void *old) +{ + struct ospf6_lsa *lsa = old; + struct ospf6_interface *o6i; + struct ospf6_area *o6a; + u_int32_t id; + + id = ntohl (lsa->header->id); + if (id) + { + o6i = ospf6_interface_lookup_by_index (id); + if (o6i) + ospf6_lsa_intra_prefix_update_transit (o6i->interface->name); + else + ospf6_lsa_premature_aging (lsa); + } + else + { + o6a = lsa->scope; + ospf6_lsa_intra_prefix_update_stub (o6a->area_id); + } + + return 0; +} + +void +ospf6_intra_prefix_register () +{ + struct ospf6_lsa_slot slot, *sp; + struct ospf6_hook hook; + + memset (&slot, 0, sizeof (struct ospf6_lsa_slot)); + slot.type = htons (OSPF6_LSA_TYPE_INTRA_PREFIX); + slot.name = "Intra-Prefix"; + slot.func_show = ospf6_lsa_intra_prefix_show; + slot.func_refresh = ospf6_lsa_intra_prefix_refresh; + ospf6_lsa_slot_register (&slot); + + memset (&hook, 0, sizeof (hook)); + hook.name = "OriginateIntraPrefix"; + hook.hook_add = ospf6_lsa_intra_prefix_hook_interface; + hook.hook_change = ospf6_lsa_intra_prefix_hook_interface; + hook.hook_remove = NULL; /* XXX */ + ospf6_hook_register (&hook, &interface_hook); + + memset (&hook, 0, sizeof (hook)); + hook.name = "OriginateIntraPrefix"; + hook.hook_add = ospf6_lsa_intra_prefix_hook_neighbor; + hook.hook_change = ospf6_lsa_intra_prefix_hook_neighbor; + hook.hook_remove = ospf6_lsa_intra_prefix_hook_neighbor; + ospf6_hook_register (&hook, &neighbor_hook); + + sp = ospf6_lsa_slot_get (htons (OSPF6_LSA_TYPE_INTRA_PREFIX)); + hook.name = "CalculateIntraPrefix"; + hook.hook_add = ospf6_intra_prefix_database_hook_add; + hook.hook_change = ospf6_intra_prefix_database_hook_add; + hook.hook_remove = ospf6_intra_prefix_database_hook_remove; + ospf6_hook_register (&hook, &sp->database_hook); +} + +void +ospf6_intra_database_hook_intra_prefix (struct ospf6_lsa *old, + struct ospf6_lsa *new) +{ + if (old) + ospf6_intra_prefix_database_hook_remove (old); + if (new && ! IS_LSA_MAXAGE (new)) + ospf6_intra_prefix_database_hook_add (new); +} + +void +ospf6_intra_database_hook_link (struct ospf6_lsa *old, + struct ospf6_lsa *new) +{ + ospf6_intra_prefix_link_database_hook (new); + ospf6_spf_database_hook (old, new); +} + +void +ospf6_intra_init () +{ + ospf6_lsdb_hook[OSPF6_LSA_TYPE_INTRA_PREFIX & OSPF6_LSTYPE_CODE_MASK].hook = + ospf6_intra_database_hook_intra_prefix; + ospf6_lsdb_hook[OSPF6_LSA_TYPE_LINK & OSPF6_LSTYPE_CODE_MASK].hook = + ospf6_intra_database_hook_link; + + intra_index = ospf6_dump_install ("intra-area", "Intra-area calculation\n"); + ospf6_intra_prefix_register (); +} + + diff --git a/ospf6d/ospf6_intra.h b/ospf6d/ospf6_intra.h new file mode 100644 index 000000000..4fb68e955 --- /dev/null +++ b/ospf6d/ospf6_intra.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2001 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF6_INTRA_H +#define OSPF6_INTRA_H + +void ospf6_intra_topology_add (void *); +void ospf6_intra_topology_remove (void *); + +void ospf6_intra_init (); + +#endif /* OSPF6_INTRA_H */ + diff --git a/ospf6d/ospf6_ism.c b/ospf6d/ospf6_ism.c new file mode 100644 index 000000000..d13be127f --- /dev/null +++ b/ospf6d/ospf6_ism.c @@ -0,0 +1,519 @@ +/* + * Copyright (C) 1999 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* Interface State Machine */ + +#include "ospf6d.h" + +int +ifs_change (state_t ifs_next, char *reason, struct ospf6_interface *o6i) +{ + state_t ifs_prev; + + ifs_prev = o6i->state; + + if (ifs_prev == ifs_next) + return 0; + + if (IS_OSPF6_DUMP_INTERFACE) + zlog_info ("I/F: %s: %s -> %s (%s)", + o6i->interface->name, + ospf6_interface_state_string[ifs_prev], + ospf6_interface_state_string[ifs_next], reason); + + if ((ifs_prev == IFS_DR || ifs_prev == IFS_BDR) && + (ifs_next != IFS_DR && ifs_next != IFS_BDR)) + ospf6_leave_alldrouters (o6i->interface->ifindex); + else if ((ifs_prev != IFS_DR && ifs_prev != IFS_BDR) && + (ifs_next == IFS_DR || ifs_next == IFS_BDR)) + ospf6_join_alldrouters (o6i->interface->ifindex); + + o6i->state = ifs_next; + + if (o6i->prevdr != o6i->dr || o6i->prevbdr != o6i->bdr) + { + if (IS_OSPF6_DUMP_INTERFACE) + { + char dr[16], bdr[16], prevdr[16], prevbdr[16]; + inet_ntop (AF_INET, &o6i->prevdr, prevdr, sizeof (prevdr)); + inet_ntop (AF_INET, &o6i->prevbdr, prevbdr, sizeof (prevbdr)); + inet_ntop (AF_INET, &o6i->dr, dr, sizeof (dr)); + inet_ntop (AF_INET, &o6i->bdr, bdr, sizeof (bdr)); + zlog_info ("I/F: %s: DR: %s -> %s", o6i->interface->name, + prevdr, dr); + zlog_info ("I/F: %s: BDR: %s -> %s", o6i->interface->name, + prevbdr, bdr); + } + } + + CALL_CHANGE_HOOK (&interface_hook, o6i); + return 0; +} + + +/* Interface State Machine */ +int +interface_up (struct thread *thread) +{ + struct ospf6_interface *ospf6_interface; + + ospf6_interface = (struct ospf6_interface *)THREAD_ARG (thread); + + assert (ospf6_interface); + assert (ospf6_interface->interface); + + if (IS_OSPF6_DUMP_INTERFACE) + zlog_info ("I/F: %s: InterfaceUp", + ospf6_interface->interface->name); + + /* check physical interface is up */ + if (!if_is_up (ospf6_interface->interface)) + { + if (IS_OSPF6_DUMP_INTERFACE) + zlog_warn (" interface %s down, can't execute InterfaceUp", + ospf6_interface->interface->name); + return -1; + } + + /* if already enabled, do nothing */ + if (ospf6_interface->state > IFS_DOWN) + { + zlog_warn ("Interface %s already up", + ospf6_interface->interface->name); + return 0; + } + + /* ifid of this interface */ + ospf6_interface->if_id = ospf6_interface->interface->ifindex; + + /* Join AllSPFRouters */ + ospf6_join_allspfrouters (ospf6_interface->interface->ifindex); + + /* set socket options */ + ospf6_set_reuseaddr (); + ospf6_reset_mcastloop (); + ospf6_set_pktinfo (); + ospf6_set_checksum (); + + /* Schedule Hello */ + if (! CHECK_FLAG (ospf6_interface->flag, OSPF6_INTERFACE_FLAG_PASSIVE)) + thread_add_event (master, ospf6_send_hello, ospf6_interface, 0); + + /* decide next interface state */ + if (if_is_pointopoint (ospf6_interface->interface)) + ifs_change (IFS_PTOP, "IF Type PointToPoint", ospf6_interface); + else if (ospf6_interface->priority == 0) + ifs_change (IFS_DROTHER, "Router Priority = 0", ospf6_interface); + else + { + ifs_change (IFS_WAITING, "Priority > 0", ospf6_interface); + thread_add_timer (master, wait_timer, ospf6_interface, + ospf6_interface->dead_interval); + } + + CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, ospf6_interface); + + return 0; +} + +int +wait_timer (struct thread *thread) +{ + struct ospf6_interface *ospf6_interface; + + ospf6_interface = (struct ospf6_interface *)THREAD_ARG (thread); + assert (ospf6_interface); + + if (ospf6_interface->state != IFS_WAITING) + return 0; + + if (IS_OSPF6_DUMP_INTERFACE) + zlog_info ("I/F: %s: WaitTimer", ospf6_interface->interface->name); + + ifs_change (dr_election (ospf6_interface), + "WaitTimer:DR Election", ospf6_interface); + return 0; +} + +int backup_seen (struct thread *thread) +{ + struct ospf6_interface *ospf6_interface; + + ospf6_interface = (struct ospf6_interface *)THREAD_ARG (thread); + assert (ospf6_interface); + + if (IS_OSPF6_DUMP_INTERFACE) + zlog_info ("I/F: %s: BackupSeen", ospf6_interface->interface->name); + + if (ospf6_interface->state == IFS_WAITING) + ifs_change (dr_election (ospf6_interface), + "BackupSeen:DR Election", ospf6_interface); + + return 0; +} + +int neighbor_change (struct thread *thread) +{ + struct ospf6_interface *ospf6_interface; + + ospf6_interface = (struct ospf6_interface *)THREAD_ARG (thread); + assert (ospf6_interface); + + if (ospf6_interface->state != IFS_DROTHER && + ospf6_interface->state != IFS_BDR && + ospf6_interface->state != IFS_DR) + return 0; + + if (IS_OSPF6_DUMP_INTERFACE) + zlog_info ("I/F: %s: NeighborChange", ospf6_interface->interface->name); + + ifs_change (dr_election (ospf6_interface), + "NeighborChange:DR Election", ospf6_interface); + + return 0; +} + +int +loopind (struct thread *thread) +{ + struct ospf6_interface *ospf6_interface; + + ospf6_interface = (struct ospf6_interface *)THREAD_ARG (thread); + assert (ospf6_interface); + + if (IS_OSPF6_DUMP_INTERFACE) + zlog_info ("I/F: %s: LoopInd", ospf6_interface->interface->name); + + /* XXX not yet */ + + return 0; +} + +int +interface_down (struct thread *thread) +{ + struct ospf6_interface *ospf6_interface; + + ospf6_interface = (struct ospf6_interface *) THREAD_ARG (thread); + assert (ospf6_interface); + + if (IS_OSPF6_DUMP_INTERFACE) + zlog_info ("I/F: %s: InterfaceDown", ospf6_interface->interface->name); + + if (ospf6_interface->state == IFS_NONE) + return 1; + + /* Leave AllSPFRouters */ + if (ospf6_interface_is_enabled (ospf6_interface->interface->ifindex)) + ospf6_leave_allspfrouters (ospf6_interface->interface->ifindex); + + ifs_change (IFS_DOWN, "Configured", ospf6_interface); + + return 0; +} + + +/* 9.4 of RFC2328 */ +int +dr_election (struct ospf6_interface *ospf6_interface) +{ + list candidate_list = list_new (); + listnode i, j, n; + ifid_t prevdr, prevbdr, dr = 0, bdr; + struct ospf6_neighbor *nbpi, *nbpj, myself, *nbr; + int declare = 0; + int gofive = 0; + + /* statistics */ + ospf6_interface->ospf6_stat_dr_election++; + + /* pseudo neighbor "myself" */ + memset (&myself, 0, sizeof (myself)); + myself.state = NBS_TWOWAY; + myself.dr = ospf6_interface->dr; + myself.bdr = ospf6_interface->bdr; + myself.priority = ospf6_interface->priority; + myself.ifid = ospf6_interface->if_id; + myself.router_id = ospf6_interface->area->ospf6->router_id; + +/* step_one: */ + + ospf6_interface->prevdr = prevdr = ospf6_interface->dr; + ospf6_interface->prevbdr = prevbdr = ospf6_interface->bdr; + +step_two: + + /* Calculate Backup Designated Router. */ + /* Make Candidate list */ + if (!list_isempty (candidate_list)) + list_delete_all_node (candidate_list); + declare = 0; + for (i = listhead (ospf6_interface->neighbor_list); i; nextnode (i)) + { + nbpi = (struct ospf6_neighbor *)getdata (i); + if (nbpi->priority == 0) + continue; + if (nbpi->state < NBS_TWOWAY) + continue; + if (nbpi->dr == nbpi->router_id) + continue; + if (nbpi->bdr == nbpi->router_id) + declare++; + listnode_add (candidate_list, nbpi); + } + + if (myself.priority) + { + if (myself.dr != myself.router_id) + { + if (myself.bdr == myself.router_id) + declare++; + listnode_add (candidate_list, &myself); + } + } + + /* Elect BDR */ + for (i = listhead (candidate_list); + candidate_list->count > 1; + i = listhead (candidate_list)) + { + j = i; + nextnode(j); + assert (j); + nbpi = (struct ospf6_neighbor *)getdata (i); + nbpj = (struct ospf6_neighbor *)getdata (j); + if (declare) + { + int deleted = 0; + if (nbpi->bdr != nbpi->router_id) + { + listnode_delete (candidate_list, nbpi); + deleted++; + } + if (nbpj->bdr != nbpj->router_id) + { + listnode_delete (candidate_list, nbpj); + deleted++; + } + if (deleted) + continue; + } + if (nbpi->priority > nbpj->priority) + { + listnode_delete (candidate_list, nbpj); + continue; + } + else if (nbpi->priority < nbpj->priority) + { + listnode_delete (candidate_list, nbpi); + continue; + } + else /* equal, case of tie */ + { + if (ntohl (nbpi->router_id) > ntohl (nbpj->router_id)) + { + listnode_delete (candidate_list, nbpj); + continue; + } + else if (ntohl (nbpi->router_id) < ntohl (nbpj->router_id)) + { + listnode_delete (candidate_list, nbpi); + continue; + } + else + assert (0); + } + } + + if (!list_isempty (candidate_list)) + { + assert (candidate_list->count == 1); + n = listhead (candidate_list); + nbr = (struct ospf6_neighbor *)getdata (n); + bdr = nbr->router_id; + } + else + bdr = 0; + +/* step_three: */ + + /* Calculate Designated Router. */ + /* Make Candidate list */ + if (!list_isempty (candidate_list)) + list_delete_all_node (candidate_list); + declare = 0; + for (i = listhead (ospf6_interface->neighbor_list); i; nextnode (i)) + { + nbpi = (struct ospf6_neighbor *)getdata (i); + if (nbpi->priority == 0) + continue; + if (nbpi->state < NBS_TWOWAY) + continue; + if (nbpi->dr == nbpi->router_id) + { + declare++; + listnode_add (candidate_list, nbpi); + } + } + if (myself.priority) + { + if (myself.dr == myself.router_id) + { + declare++; + listnode_add (candidate_list, &myself); + } + } + + /* Elect DR */ + if (declare == 0) + { + assert (list_isempty (candidate_list)); + /* No one declare but candidate_list not empty */ + dr = bdr; + } + else + { + assert (!list_isempty (candidate_list)); + for (i = listhead (candidate_list); + candidate_list->count > 1; + i = listhead (candidate_list)) + { + j = i; + nextnode (j); + assert (j); + nbpi = (struct ospf6_neighbor *)getdata (i); + nbpj = (struct ospf6_neighbor *)getdata (j); + + if (nbpi->dr != nbpi->router_id) + { + list_delete_node (candidate_list, i); + continue; + } + if (nbpj->dr != nbpj->router_id) + { + list_delete_node (candidate_list, j); + continue; + } + + if (nbpi->priority > nbpj->priority) + { + list_delete_node (candidate_list, j); + continue; + } + else if (nbpi->priority < nbpj->priority) + { + list_delete_node (candidate_list, i); + continue; + } + else /* equal, case of tie */ + { + if (nbpi->router_id > nbpj->router_id) + { + list_delete_node (candidate_list, j); + continue; + } + else if (nbpi->router_id < nbpj->router_id) + { + list_delete_node (candidate_list, i); + continue; + } + else + { + zlog_warn ("!!!THE SAME ROUTER ID FOR DIFFERENT NEIGHBOR"); + zlog_warn ("!!!MISCONFIGURATION?"); + list_delete_node (candidate_list, i); + continue; + } + } + } + if (!list_isempty (candidate_list)) + { + assert (candidate_list->count == 1); + n = listhead (candidate_list); + nbr = (struct ospf6_neighbor *)getdata (n); + dr = nbr->router_id; + } + else + assert (0); + } + +/* step_four: */ + + if (gofive) + goto step_five; + + if (dr != prevdr) + { + if ((dr == myself.router_id || prevdr == myself.router_id) + && !(dr == myself.router_id && prevdr == myself.router_id)) + { + myself.dr = dr; + myself.bdr = bdr; + gofive++; + goto step_two; + } + } + if (bdr != prevbdr) + { + if ((bdr == myself.router_id || prevbdr == myself.router_id) + && !(bdr == myself.router_id && prevbdr == myself.router_id)) + { + myself.dr = dr; + myself.bdr = bdr; + gofive++; + goto step_two; + } + } + +step_five: + + ospf6_interface->dr = dr; + ospf6_interface->bdr = bdr; + + if (prevdr != dr || prevbdr != bdr) + { + for (i = listhead (ospf6_interface->neighbor_list); i; nextnode (i)) + { + nbpi = getdata (i); + if (nbpi->state < NBS_TWOWAY) + continue; + /* Schedule or Execute AdjOK. which does "invoke" mean? */ + thread_add_event (master, adj_ok, nbpi, 0); + } + } + + list_delete (candidate_list); + + if (dr == myself.router_id) + { + assert (bdr != myself.router_id); + return IFS_DR; + } + else if (bdr == myself.router_id) + { + assert (dr != myself.router_id); + return IFS_BDR; + } + else + return IFS_DROTHER; +} + + diff --git a/ospf6d/ospf6_ism.h b/ospf6d/ospf6_ism.h new file mode 100644 index 000000000..12470d988 --- /dev/null +++ b/ospf6d/ospf6_ism.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 1999 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF6_ISM_H +#define OSPF6_ISM_H + +/* interface state */ +#define IFS_NONE 0 +#define IFS_DOWN 1 +#define IFS_LOOPBACK 2 +#define IFS_WAITING 3 +#define IFS_PTOP 4 +#define IFS_DROTHER 5 +#define IFS_BDR 6 +#define IFS_DR 7 +#define IFS_MAX 8 + + + +/* Function Prototypes */ +/* interface event */ +int interface_up (struct thread *); +int interface_down (struct thread *); +int wait_timer (struct thread *); +int backup_seen (struct thread *); +int neighbor_change (struct thread *); + + +#include "ospf6_types.h" + +int dr_change (struct ospf6_interface *); +int ifs_change (state_t, char *, struct ospf6_interface *); + +#endif /* OSPF6_ISM_H */ + diff --git a/ospf6d/ospf6_linklist.c b/ospf6d/ospf6_linklist.c new file mode 100644 index 000000000..8c1793592 --- /dev/null +++ b/ospf6d/ospf6_linklist.c @@ -0,0 +1,193 @@ + +#include <zebra.h> + +#include "ospf6_linklist.h" + +static struct linklist_node * +linklist_lookup_node (void *data, struct linklist *linklist) +{ + struct linklist_node *node; + + for (node = linklist->head; node; node = node->next) + { + if (linklist->cmp && (*linklist->cmp) (node->data, data) == 0) + return node; + if (node->data == data) + return node; + } + + return NULL; +} + +void * +linklist_lookup (void *data, struct linklist *linklist) +{ + struct linklist_node *node; + + node = linklist_lookup_node (data, linklist); + if (node) + return node->data; + return NULL; +} + +int +linklist_add (void *data, struct linklist *linklist) +{ + struct linklist_node *node = NULL, *add; + + if (linklist_lookup_node (data, linklist)) + return -1; + + add = malloc (sizeof (struct linklist_node)); + if (add == NULL) + return -1; + memset (add, 0, sizeof (struct linklist_node)); + add->data = data; + + if (linklist->cmp) + { + for (node = linklist->head; node; node = node->next) + { + if ((*linklist->cmp) (node->data, add->data) > 0) + break; + } + } + + if (! node) + { + /* add to tail */ + if (linklist->tail) + { + linklist->tail->next = add; + add->prev = linklist->tail; + } + else + { + linklist->head = add; + add->prev = NULL; + } + + linklist->tail = add; + add->next = NULL; + } + else + { + /* insert just before 'node' */ + if (node->prev) + { + node->prev->next = add; + add->prev = node->prev; + } + else + { + linklist->head = add; + add->prev = NULL; + } + + add->next = node; + node->prev = add; + } + + linklist->count++; + return 0; +} + +int +linklist_remove (void *data, struct linklist *linklist) +{ + struct linklist_node *rem; + + rem = linklist_lookup_node (data, linklist); + if (rem == NULL) + return -1; + + if (rem->prev) + rem->prev->next = rem->next; + else + linklist->head = rem->next; + + if (rem->next) + rem->next->prev = rem->prev; + else + linklist->tail = rem->prev; + + free (rem); + linklist->count--; + return 0; +} + +void +linklist_head (struct linklist *linklist, struct linklist_node *node) +{ + if (linklist->head == NULL) + { + node->prev = NULL; + node->next = NULL; + node->data = NULL; + return; + } + + node->prev = linklist->head->prev; + node->next = linklist->head->next; + node->data = linklist->head->data; +} + +int +linklist_end (struct linklist_node *node) +{ + if (node->data == NULL && node->next == NULL) + return 1; + return 0; +} + +void +linklist_next (struct linklist_node *node) +{ + if (node->next == NULL) + { + node->prev = NULL; + node->next = NULL; + node->data = NULL; + return; + } + + node->data = node->next->data; + node->prev = node->next->prev; + node->next = node->next->next; +} + +struct linklist * +linklist_create () +{ + struct linklist *linklist; + + linklist = malloc (sizeof (struct linklist)); + if (linklist == NULL) + return NULL; + memset (linklist, 0, sizeof (struct linklist)); + + return linklist; +} + +void +linklist_remove_all (struct linklist *linklist) +{ + struct linklist_node node; + + for (linklist_head (linklist, &node); ! linklist_end (&node); + linklist_next (&node)) + linklist_remove (node.data, linklist); +} + +void +linklist_delete (struct linklist *linklist) +{ + linklist_remove_all (linklist); + assert (linklist->count == 0); + assert (linklist->head == NULL); + assert (linklist->tail == NULL); + + free (linklist); +} + + diff --git a/ospf6d/ospf6_linklist.h b/ospf6d/ospf6_linklist.h new file mode 100644 index 000000000..6d9789998 --- /dev/null +++ b/ospf6d/ospf6_linklist.h @@ -0,0 +1,35 @@ + +#ifndef _LINKLIST_H_ +#define _LINKLIST_H_ + +struct linklist_node +{ + struct linklist_node *prev; + struct linklist_node *next; + + void *data; +}; + +struct linklist +{ + int count; + struct linklist_node *head; + struct linklist_node *tail; + + int (*cmp) (void *, void *); +}; + +void *linklist_lookup (void *data, struct linklist *linklist); +int linklist_add (void *data, struct linklist *linklist); +int linklist_remove (void *data, struct linklist *linklist); +void linklist_remove_all (struct linklist *linklist); + +void linklist_head (struct linklist *linklist, struct linklist_node *node); +int linklist_end (struct linklist_node *node); +void linklist_next (struct linklist_node *node); + +struct linklist *linklist_create (); +void linklist_delete (struct linklist *); + +#endif /*_LINKLIST_H_*/ + diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c new file mode 100644 index 000000000..b14979ffa --- /dev/null +++ b/ospf6d/ospf6_lsa.c @@ -0,0 +1,1926 @@ +/* + * LSA function + * Copyright (C) 1999 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <zebra.h> + +/* Include other stuffs */ +#include "version.h" +#include "log.h" +#include "getopt.h" +#include "linklist.h" +#include "thread.h" +#include "command.h" +#include "memory.h" +#include "sockunion.h" +#include "if.h" +#include "prefix.h" +#include "stream.h" +#include "thread.h" +#include "filter.h" +#include "zclient.h" +#include "table.h" +#include "plist.h" + +#include "ospf6_proto.h" +#include "ospf6_prefix.h" +#include "ospf6_lsa.h" +#include "ospf6_lsdb.h" +#include "ospf6_message.h" +#include "ospf6_dump.h" + +#include "ospf6_top.h" +#include "ospf6_area.h" +#include "ospf6_interface.h" +#include "ospf6_neighbor.h" +#include "ospf6_ism.h" +#include "ospf6_nsm.h" +#include "ospf6_dbex.h" + +#define HEADER_DEPENDENCY +#include "ospf6d.h" +#undef HEADER_DEPENDENCY + +/* test LSAs identity */ +static int +ospf6_lsa_issame (struct ospf6_lsa_header__ *lsh1, + struct ospf6_lsa_header__ *lsh2) +{ + assert (lsh1 && lsh2); + + if (lsh1->adv_router != lsh2->adv_router) + return 0; + + if (lsh1->id != lsh2->id) + return 0; + + if (lsh1->type != lsh2->type) + return 0; + + return 1; +} + +/* RFC2328: Section 13.2 */ +int +ospf6_lsa_differ (struct ospf6_lsa *lsa1, + struct ospf6_lsa *lsa2) +{ + int diff, cmplen; + + if (! ospf6_lsa_issame (lsa1->header, lsa2->header)) + return 1; + + /* check Options field */ + /* xxx */ + + ospf6_lsa_age_current (lsa1); + ospf6_lsa_age_current (lsa2); + if (ntohs (lsa1->header->age) == MAXAGE && + ntohs (lsa2->header->age) != MAXAGE) + return 1; + if (ntohs (lsa1->header->age) != MAXAGE && + ntohs (lsa2->header->age) == MAXAGE) + return 1; + + /* compare body */ + if (ntohs (lsa1->header->length) != ntohs (lsa2->header->length)) + return 1; + + cmplen = ntohs (lsa1->header->length) - sizeof (struct ospf6_lsa_header); + diff = memcmp (lsa1->header + 1, lsa2->header + 1, cmplen); + + return diff; +} + +int +ospf6_lsa_match (u_int16_t type, u_int32_t id, u_int32_t adv_router, + struct ospf6_lsa_header *lsh) +{ + if (lsh->advrtr != adv_router) + return 0; + + if (lsh->ls_id != id) + return 0; + + if (lsh->type != type) + return 0; + + return 1; +} + +/* ospf6 age functions */ +/* calculate birth and set expire timer */ +static void +ospf6_lsa_age_set (struct ospf6_lsa *lsa) +{ + struct timeval now; + + assert (lsa && lsa->header); + + if (gettimeofday (&now, (struct timezone *)NULL) < 0) + zlog_warn ("LSA: gettimeofday failed, may fail LSA AGEs: %s", + strerror (errno)); + + lsa->birth.tv_sec = now.tv_sec - ntohs (lsa->header->age); + lsa->birth.tv_usec = now.tv_usec; + if (ntohs (lsa->header->age) != MAXAGE) + lsa->expire = thread_add_timer (master, ospf6_lsa_expire, lsa, + lsa->birth.tv_sec + MAXAGE - now.tv_sec); + else + lsa->expire = NULL; + return; +} + +/* this function calculates current age from its birth, + then update age field of LSA header. return value is current age */ +u_int16_t +ospf6_lsa_age_current (struct ospf6_lsa *lsa) +{ + struct timeval now; + u_int32_t ulage; + u_int16_t age; + + assert (lsa); + assert (lsa->header); + + /* current time */ + if (gettimeofday (&now, (struct timezone *)NULL) < 0) + zlog_warn ("LSA: gettimeofday failed, may fail ages: %s", + strerror (errno)); + + /* calculate age */ + ulage = now.tv_sec - lsa->birth.tv_sec; + + /* if over MAXAGE, set to it */ + if (ulage > MAXAGE) + age = MAXAGE; + else + age = ulage; + + lsa->header->age = htons (age); + return age; +} + +/* update age field of LSA header with adding InfTransDelay */ +void +ospf6_lsa_age_update_to_send (struct ospf6_lsa *lsa, u_int32_t transdelay) +{ + unsigned short age; + + age = ospf6_lsa_age_current (lsa) + transdelay; + if (age > MAXAGE) + age = MAXAGE; + lsa->header->age = htons (age); + return; +} + +void +ospf6_lsa_premature_aging (struct ospf6_lsa *lsa) +{ + /* log */ + if (IS_OSPF6_DUMP_LSA) + zlog_info ("LSA: Premature aging: %s", lsa->str); + + if (lsa->expire) + thread_cancel (lsa->expire); + lsa->expire = (struct thread *) NULL; + if (lsa->refresh) + thread_cancel (lsa->refresh); + lsa->refresh = (struct thread *) NULL; + + memset (&lsa->birth, 0, sizeof (struct timeval)); + thread_execute (master, ospf6_lsa_expire, lsa, 0); +} + +/* check which is more recent. if a is more recent, return -1; + if the same, return 0; otherwise(b is more recent), return 1 */ +int +ospf6_lsa_check_recent (struct ospf6_lsa *a, struct ospf6_lsa *b) +{ + signed long seqnuma, seqnumb; + u_int16_t cksuma, cksumb; + u_int16_t agea, ageb; + + assert (a && a->header); + assert (b && b->header); + assert (ospf6_lsa_issame (a->header, b->header)); + + seqnuma = ((signed long) ntohl (a->header->seqnum)) + - (signed long) INITIAL_SEQUENCE_NUMBER; + seqnumb = ((signed long) ntohl (b->header->seqnum)) + - (signed long) INITIAL_SEQUENCE_NUMBER; + + /* compare by sequence number */ + /* xxx, care about LS sequence number wrapping */ + recent_reason = "seqnum"; + if (seqnuma > seqnumb) + return -1; + else if (seqnuma < seqnumb) + return 1; + + /* Checksum */ + cksuma = ntohs (a->header->checksum); + cksumb = ntohs (b->header->checksum); + if (cksuma > cksumb) + return -1; + if (cksuma < cksumb) + return 0; + + /* Age check */ + agea = ospf6_lsa_age_current (a); + ageb = ospf6_lsa_age_current (b); + + /* MaxAge check */ + recent_reason = "max age"; + if (agea == OSPF6_LSA_MAXAGE && ageb != OSPF6_LSA_MAXAGE) + return -1; + else if (agea != OSPF6_LSA_MAXAGE && ageb == OSPF6_LSA_MAXAGE) + return 1; + + recent_reason = "age differ"; + if (agea > ageb && agea - ageb >= OSPF6_LSA_MAXAGEDIFF) + return 1; + else if (agea < ageb && ageb - agea >= OSPF6_LSA_MAXAGEDIFF) + return -1; + + /* neither recent */ + recent_reason = "the same instance"; + return 0; +} + +int +ospf6_lsa_lsd_num (struct ospf6_lsa_header *lsa_header) +{ + int ldnum = 0; + u_int16_t len; + + len = ntohs (lsa_header->length); + len -= sizeof (struct ospf6_lsa_header); + if (lsa_header->type == htons (OSPF6_LSA_TYPE_ROUTER)) + { + len -= sizeof (struct ospf6_router_lsa); + ldnum = len / sizeof (struct ospf6_router_lsd); + } + else /* (lsa_header->type == htons (OSPF6_LSA_TYPE_NETWORK)) */ + { + len -= sizeof (struct ospf6_network_lsa); + ldnum = len / sizeof (u_int32_t); + } + + return ldnum; +} + +void * +ospf6_lsa_lsd_get (int index, struct ospf6_lsa_header *lsa_header) +{ + void *p; + struct ospf6_router_lsa *router_lsa; + struct ospf6_router_lsd *router_lsd; + struct ospf6_network_lsa *network_lsa; + struct ospf6_network_lsd *network_lsd; + + if (lsa_header->type == htons (OSPF6_LSA_TYPE_ROUTER)) + { + router_lsa = (struct ospf6_router_lsa *) (lsa_header + 1); + router_lsd = (struct ospf6_router_lsd *) (router_lsa + 1); + router_lsd += index; + p = (void *) router_lsd; + } + else if (lsa_header->type == htons (OSPF6_LSA_TYPE_NETWORK)) + { + network_lsa = (struct ospf6_network_lsa *) (lsa_header + 1); + network_lsd = (struct ospf6_network_lsd *) (network_lsa + 1); + network_lsd += index; + p = (void *) network_lsd; + } + else + { + p = (void *) NULL; + } + + return p; +} + +/* network_lsd <-> router_lsd */ +static int +ospf6_lsa_lsd_network_reference_match (struct ospf6_network_lsd *network_lsd1, + struct ospf6_lsa_header *lsa_header1, + struct ospf6_router_lsd *router_lsd2, + struct ospf6_lsa_header *lsa_header2) +{ + if (network_lsd1->adv_router != lsa_header2->advrtr) + return 0; + if (router_lsd2->type != OSPF6_ROUTER_LSD_TYPE_TRANSIT_NETWORK) + return 0; + if (router_lsd2->neighbor_router_id != lsa_header1->advrtr) + return 0; + if (router_lsd2->neighbor_interface_id != lsa_header1->ls_id) + return 0; + return 1; +} + +/* router_lsd <-> router_lsd */ +static int +ospf6_lsa_lsd_router_reference_match (struct ospf6_router_lsd *router_lsd1, + struct ospf6_lsa_header *lsa_header1, + struct ospf6_router_lsd *router_lsd2, + struct ospf6_lsa_header *lsa_header2) +{ + if (router_lsd1->type != OSPF6_ROUTER_LSD_TYPE_POINTTOPOINT) + return 0; + if (router_lsd2->type != OSPF6_ROUTER_LSD_TYPE_POINTTOPOINT) + return 0; + if (router_lsd1->neighbor_router_id != lsa_header2->advrtr) + return 0; + if (router_lsd2->neighbor_router_id != lsa_header1->advrtr) + return 0; + if (router_lsd1->neighbor_interface_id != router_lsd2->interface_id) + return 0; + if (router_lsd2->neighbor_interface_id != router_lsd1->interface_id) + return 0; + return 1; +} + +int +ospf6_lsa_lsd_is_refer_ok (int index1, struct ospf6_lsa_header *lsa_header1, + int index2, struct ospf6_lsa_header *lsa_header2) +{ + struct ospf6_router_lsd *r1, *r2; + struct ospf6_network_lsd *n; + + r1 = (struct ospf6_router_lsd *) NULL; + r2 = (struct ospf6_router_lsd *) NULL; + n = (struct ospf6_network_lsd *) NULL; + if (lsa_header1->type == htons (OSPF6_LSA_TYPE_ROUTER)) + r1 = (struct ospf6_router_lsd *) ospf6_lsa_lsd_get (index1, lsa_header1); + else + n = (struct ospf6_network_lsd *) ospf6_lsa_lsd_get (index1, lsa_header1); + + if (lsa_header2->type == htons (OSPF6_LSA_TYPE_ROUTER)) + r2 = (struct ospf6_router_lsd *) ospf6_lsa_lsd_get (index2, lsa_header2); + else + n = (struct ospf6_network_lsd *) ospf6_lsa_lsd_get (index2, lsa_header2); + + if (r1 && r2) + return ospf6_lsa_lsd_router_reference_match (r1, lsa_header1, + r2, lsa_header2); + else if (r1 && n) + return ospf6_lsa_lsd_network_reference_match (n, lsa_header2, + r1, lsa_header1); + else if (n && r2) + return ospf6_lsa_lsd_network_reference_match (n, lsa_header1, + r2, lsa_header2); + return 0; +} + +void +ospf6_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) +{ + char adv_router[64], id[64], type[32]; + + assert (lsa); + assert (lsa->header); + + ospf6_lsa_type_string (lsa->header->type, type, sizeof (type)); + inet_ntop (AF_INET, &lsa->header->id, id, sizeof (id)); + inet_ntop (AF_INET, &lsa->header->adv_router, + adv_router, sizeof (adv_router)); + + vty_out (vty, "%s", VTY_NEWLINE); + vty_out (vty, "Age: %4hu Type: %s%s", ospf6_lsa_age_current (lsa), + type, VTY_NEWLINE); + vty_out (vty, "Link State ID: %s%s", id, VTY_NEWLINE); + vty_out (vty, "Advertising Router: %s%s", adv_router, VTY_NEWLINE); + vty_out (vty, "LS Sequence Number: %#lx%s", (u_long)ntohl (lsa->header->seqnum), + VTY_NEWLINE); + vty_out (vty, "CheckSum: %#hx Length: %hu%s", ntohs (lsa->header->checksum), + ntohs (lsa->header->length), VTY_NEWLINE); + + { + struct ospf6_lsa_slot *slot; + slot = ospf6_lsa_slot_get (lsa->header->type); + if (slot) + { + (*slot->func_show) (vty, lsa); + vty_out (vty, "%s", VTY_NEWLINE); + return; + } + } + + vty_out (vty, "%sUnknown LSA type ...%s", VTY_NEWLINE, VTY_NEWLINE); +} + +void +ospf6_lsa_show_summary_header (struct vty *vty) +{ + vty_out (vty, "%-12s %-15s %-15s %4s %8s %4s %4s %-8s%s", + "Type", "LSId", "AdvRouter", "Age", "SeqNum", + "Cksm", "Len", "Duration", VTY_NEWLINE); +} + +void +ospf6_lsa_show_summary (struct vty *vty, struct ospf6_lsa *lsa) +{ + char adv_router[16], id[16], type[16]; + struct timeval now, res; + char duration[16]; + + assert (lsa); + assert (lsa->header); + + memset (type, 0, sizeof (type)); + ospf6_lsa_type_string (lsa->header->type, type, 13); + inet_ntop (AF_INET, &lsa->header->id, id, sizeof (id)); + inet_ntop (AF_INET, &lsa->header->adv_router, adv_router, + sizeof (adv_router)); + + gettimeofday (&now, NULL); + ospf6_timeval_sub (&now, &lsa->installed, &res); + ospf6_timeval_string_summary (&res, duration, sizeof (duration)); + + vty_out (vty, "%-12s %-15s %-15s %4hu %8lx %04hx %4hu %8s%s", + type, id, adv_router, ospf6_lsa_age_current (lsa), + (u_long) ntohl (lsa->header->seqnum), + ntohs (lsa->header->checksum), ntohs (lsa->header->length), + duration, VTY_NEWLINE); +} + +void +ospf6_lsa_show_dump (struct vty *vty, struct ospf6_lsa *lsa) +{ + u_char *start, *end, *current; + char byte[4]; + + start = (char *) lsa->header; + end = (char *) lsa->header + ntohs (lsa->header->length); + + vty_out (vty, "%s", VTY_NEWLINE); + vty_out (vty, "%s:%s", lsa->str, VTY_NEWLINE); + + for (current = start; current < end; current ++) + { + if ((current - start) % 16 == 0) + vty_out (vty, "%s ", VTY_NEWLINE); + else if ((current - start) % 4 == 0) + vty_out (vty, " "); + + snprintf (byte, sizeof (byte), "%02x", *current); + vty_out (vty, "%s", byte); + } + + vty_out (vty, "%s%s", VTY_NEWLINE, VTY_NEWLINE); +} + +/* OSPFv3 LSA creation/deletion function */ + +/* calculate LS sequence number for my new LSA. + return value is network byte order */ +static signed long +ospf6_lsa_seqnum_new (u_int16_t type, u_int32_t id, u_int32_t adv_router, + void *scope) +{ + struct ospf6_lsa *lsa; + signed long seqnum; + + /* get current database copy */ + lsa = ospf6_lsdb_lookup (type, id, adv_router, scope); + + /* if current database copy not found, return InitialSequenceNumber */ + if (!lsa) + seqnum = INITIAL_SEQUENCE_NUMBER; + else + seqnum = (signed long) ntohl (lsa->header->seqnum) + 1; + + return (htonl (seqnum)); +} + +#if 0 +static void +ospf6_lsa_header_set (u_int16_t type, u_int32_t ls_id, u_int32_t advrtr, + struct ospf6_lsa_header *lsa_header, int bodysize) +{ + /* fill LSA header */ + lsa_header->age = 0; + lsa_header->type = type; + lsa_header->ls_id = ls_id; + lsa_header->advrtr = advrtr; + lsa_header->seqnum = + ospf6_lsa_seqnum_new (lsa_header->type, lsa_header->ls_id, + lsa_header->advrtr); + lsa_header->length = htons (sizeof (struct ospf6_lsa_header) + bodysize); + + /* LSA checksum */ + ospf6_lsa_checksum (lsa_header); +} +#endif /*0*/ + +struct ospf6_lsa * +ospf6_lsa_create (struct ospf6_lsa_header *source) +{ + struct ospf6_lsa *lsa = NULL; + struct ospf6_lsa_header *lsa_header = NULL; + u_int16_t lsa_size = 0; + char buf_router[16], buf_id[16], typebuf[32]; + + /* whole length of this LSA */ + lsa_size = ntohs (source->length); + + /* allocate memory for this LSA */ + lsa_header = (struct ospf6_lsa_header *) + XMALLOC (MTYPE_OSPF6_LSA, lsa_size); + if (! lsa_header) + { + zlog_err ("Can't allocate memory for LSA Header"); + return (struct ospf6_lsa *) NULL; + } + memset (lsa_header, 0, lsa_size); + + /* copy LSA from source */ + memcpy (lsa_header, source, lsa_size); + + /* LSA information structure */ + /* allocate memory */ + lsa = (struct ospf6_lsa *) + XMALLOC (MTYPE_OSPF6_LSA, sizeof (struct ospf6_lsa)); + memset (lsa, 0, sizeof (struct ospf6_lsa)); + + lsa->lsa_hdr = (struct ospf6_lsa_hdr *) lsa_header; + lsa->header = (struct ospf6_lsa_header__ *) lsa_header; + + lsa->summary = 0; /* this is not LSA summary */ + + /* dump string */ + inet_ntop (AF_INET, &lsa->header->id, buf_id, sizeof (buf_id)); + inet_ntop (AF_INET, &lsa->header->adv_router, buf_router, + sizeof (buf_router)); + snprintf (lsa->str, sizeof (lsa->str), "[%s ID=%s Adv=%s]", + ospf6_lsa_type_string (lsa_header->type, typebuf, + sizeof (typebuf)), + buf_id, buf_router); + + /* calculate birth, expire and refresh of this lsa */ + ospf6_lsa_age_set (lsa); + +#ifdef DEBUG + if (IS_OSPF6_DUMP_LSA) + zlog_info ("Create: %s (%p/%p)", lsa->str, lsa, lsa->header); +#endif /*DEBUG*/ + + return lsa; +} + +struct ospf6_lsa * +ospf6_lsa_summary_create (struct ospf6_lsa_header__ *source) +{ + struct ospf6_lsa *lsa = NULL; + struct ospf6_lsa_header *lsa_header = NULL; + u_int16_t lsa_size = 0; + char buf_router[16], buf_id[16], typebuf[16]; + + /* LSA summary contains LSA Header only */ + lsa_size = sizeof (struct ospf6_lsa_header); + + /* allocate memory for this LSA */ + lsa_header = (struct ospf6_lsa_header *) + XMALLOC (MTYPE_OSPF6_LSA_SUMMARY, lsa_size); + memset (lsa_header, 0, lsa_size); + + /* copy LSA from source */ + memcpy (lsa_header, source, lsa_size); + + /* LSA information structure */ + /* allocate memory */ + lsa = (struct ospf6_lsa *) + XMALLOC (MTYPE_OSPF6_LSA_SUMMARY, sizeof (struct ospf6_lsa)); + memset (lsa, 0, sizeof (struct ospf6_lsa)); + + lsa->lsa_hdr = (struct ospf6_lsa_hdr *) lsa_header; + lsa->header = (struct ospf6_lsa_header__ *) lsa_header; + lsa->summary = 1; /* this is LSA summary */ + + /* dump string */ + inet_ntop (AF_INET, &lsa->header->id, buf_id, sizeof (buf_id)); + inet_ntop (AF_INET, &lsa->header->adv_router, buf_router, + sizeof (buf_router)); + snprintf (lsa->str, sizeof (lsa->str), "[%s Summary ID=%s Adv=%s]", + ospf6_lsa_type_string (lsa->header->type, typebuf, + sizeof (typebuf)), + buf_id, buf_router); + + /* calculate birth, expire and refresh of this lsa */ + ospf6_lsa_age_set (lsa); + +#ifdef DEBUG + if (IS_OSPF6_DUMP_LSA) + zlog_info ("Create: %s (%p/%p)", lsa->str, lsa, lsa->header); +#endif /*DEBUG*/ + + return lsa; +} + +void +ospf6_lsa_delete (struct ospf6_lsa *lsa) +{ + /* just to make sure */ + if (lsa->lock != 0) + { + zlog_err ("Can't delete %s: lock: %ld", lsa->str, lsa->lock); + return; + } + + /* cancel threads */ + if (lsa->expire) + thread_cancel (lsa->expire); + lsa->expire = (struct thread *) NULL; + if (lsa->refresh) + thread_cancel (lsa->refresh); + lsa->refresh = (struct thread *) NULL; + +#ifdef DEBUG + if (IS_OSPF6_DUMP_LSA) + zlog_info ("Delete %s (%p/%p)", lsa->str, lsa, lsa->header); +#endif /*DEBUG*/ + + /* do free */ + if (lsa->summary) + XFREE (MTYPE_OSPF6_LSA_SUMMARY, lsa->header); + else + XFREE (MTYPE_OSPF6_LSA, lsa->header); + lsa->header = NULL; + + if (lsa->summary) + XFREE (MTYPE_OSPF6_LSA_SUMMARY, lsa); + else + XFREE (MTYPE_OSPF6_LSA, lsa); +} + +/* increment reference counter of struct ospf6_lsa */ +void +ospf6_lsa_lock (struct ospf6_lsa *lsa) +{ + lsa->lock++; + return; +} + +/* decrement reference counter of struct ospf6_lsa */ +void +ospf6_lsa_unlock (struct ospf6_lsa *lsa) +{ + /* decrement reference counter */ + if (lsa->lock > 0) + lsa->lock--; + else + zlog_warn ("Can't unlock %s: already no lock", lsa->str); + + if (lsa->lock == 0) + ospf6_lsa_delete (lsa); +} + +void +ospf6_lsa_originate (u_int16_t type, u_int32_t id, u_int32_t adv_router, + char *data, int data_len, void *scope) +{ + char buffer[MAXLSASIZE]; + struct ospf6_lsa_header *lsa_header; + struct ospf6_lsa *lsa; + struct ospf6_lsa *old; + + assert (data_len <= sizeof (buffer) - sizeof (struct ospf6_lsa_header)); + + lsa_header = (struct ospf6_lsa_header *) buffer; + + /* Copy LSA Body */ + memcpy (buffer + sizeof (struct ospf6_lsa_header), data, data_len); + + /* Fill LSA Header */ + lsa_header->age = 0; + lsa_header->type = type; + lsa_header->ls_id = id; + lsa_header->advrtr = adv_router; + lsa_header->seqnum = + ospf6_lsa_seqnum_new (lsa_header->type, lsa_header->ls_id, + lsa_header->advrtr, scope); + lsa_header->length = htons (sizeof (struct ospf6_lsa_header) + data_len); + + /* LSA checksum */ + ospf6_lsa_checksum (lsa_header); + + /* create LSA */ + lsa = ospf6_lsa_create ((struct ospf6_lsa_header *) buffer); + lsa->scope = scope; + + /* find previous LSA */ + old = ospf6_lsdb_lookup (lsa->header->type, lsa->header->id, + lsa->header->adv_router, lsa->scope); + if (old) + { + /* Check if this is neither different instance nor refresh, return */ + if (! CHECK_FLAG (old->flag, OSPF6_LSA_FLAG_REFRESH) && + ! ospf6_lsa_differ (lsa, old)) + { + if (IS_OSPF6_DUMP_LSA) + zlog_info ("LSA: Suppress updating %s", lsa->str); + ospf6_lsa_delete (lsa); + return; + } + } + + lsa->refresh = thread_add_timer (master, ospf6_lsa_refresh, lsa, + OSPF6_LS_REFRESH_TIME); + gettimeofday (&lsa->originated, NULL); + + //if (IS_OSPF6_DUMP_LSA) + zlog_info ("LSA: originate %s seq: %#x age: %hu %ld.%06ld", + lsa->str, ntohl (lsa->header->seqnum), + ospf6_lsa_age_current (lsa), + lsa->originated.tv_sec, lsa->originated.tv_usec); + + ospf6_dbex_remove_from_all_retrans_list (lsa); + ospf6_dbex_flood (lsa, NULL); + ospf6_lsdb_install (lsa); +} + + +/* ospf6_lsa expired */ +int +ospf6_lsa_expire (struct thread *thread) +{ + struct ospf6_lsa *lsa; + struct ospf6_lsdb *lsdb = NULL; + void (*hook) (struct ospf6_lsa *, struct ospf6_lsa *); + + lsa = (struct ospf6_lsa *) THREAD_ARG (thread); + assert (lsa && lsa->lsa_hdr); + + /* assertion */ + assert (IS_LSA_MAXAGE (lsa)); + assert (!lsa->refresh); + + lsa->expire = (struct thread *) NULL; + + /* log */ + if (IS_OSPF6_DUMP_LSA) + zlog_info ("LSA: Expire: %s", lsa->str); + + if (!lsa->summary) + { + /* reflood lsa */ + ospf6_dbex_flood (lsa, NULL); + + /* get scoped lsdb, call remove hook */ + if (OSPF6_LSA_IS_SCOPE_LINKLOCAL (ntohs (lsa->header->type))) + lsdb = ((struct ospf6_interface *) lsa->scope)->lsdb; + else if (OSPF6_LSA_IS_SCOPE_AREA (ntohs (lsa->header->type))) + lsdb = ((struct ospf6_area *) lsa->scope)->lsdb; + else if (OSPF6_LSA_IS_SCOPE_AS (ntohs (lsa->header->type))) + lsdb = ((struct ospf6 *) lsa->scope)->lsdb; + else + assert (0); + + /* call LSDB hook to re-process LSA */ + hook = ospf6_lsdb_hook[ntohs (lsa->header->type) & + OSPF6_LSTYPE_CODE_MASK].hook; + if (hook) + (*hook) (NULL, lsa); + + /* do not free LSA, and do nothing about lslists. + wait event (ospf6_lsdb_check_maxage) */ + } + + return 0; +} + +int +ospf6_lsa_refresh (struct thread *thread) +{ + struct ospf6_lsa *lsa; + struct ospf6_lsa_slot *slot; + + assert (thread); + lsa = (struct ospf6_lsa *) THREAD_ARG (thread); + assert (lsa && lsa->lsa_hdr); + + /* this will be used later as flag to decide really originate */ + lsa->refresh = (struct thread *) NULL; + SET_FLAG (lsa->flag, OSPF6_LSA_FLAG_REFRESH); + + /* log */ + if (IS_OSPF6_DUMP_LSA) + zlog_info ("LSA Refresh: %s", lsa->str); + + slot = ospf6_lsa_slot_get (lsa->header->type); + if (slot) + { + zlog_info ("LSA Refresh: %s", slot->name); + (*slot->func_refresh) (lsa); + return 0; + } + + zlog_warn ("Can't Refresh LSA: Unknown type: %#x", + ntohs (lsa->header->type)); + return 1; +} + + + +/* enhanced Fletcher checksum algorithm, RFC1008 7.2 */ +#define MODX 4102 +#define LSA_CHECKSUM_OFFSET 15 + +unsigned short +ospf6_lsa_checksum (struct ospf6_lsa_header *lsa_header) +{ + u_char *sp, *ep, *p, *q; + int c0 = 0, c1 = 0; + int x, y; + u_int16_t length; + + lsa_header->checksum = 0; + length = ntohs (lsa_header->length) - 2; + sp = (char *) &lsa_header->type; + + for (ep = sp + length; sp < ep; sp = q) + { + q = sp + MODX; + if (q > ep) + q = ep; + for (p = sp; p < q; p++) + { + c0 += *p; + c1 += c0; + } + c0 %= 255; + c1 %= 255; + } + + /* r = (c1 << 8) + c0; */ + x = ((length - LSA_CHECKSUM_OFFSET) * c0 - c1) % 255; + if (x <= 0) + x += 255; + y = 510 - c0 - x; + if (y > 255) + y -= 255; + + lsa_header->checksum = htons ((x << 8) + y); + + return (lsa_header->checksum); +} + +int +ospf6_lsa_is_known_type (struct ospf6_lsa_header *lsa_header) +{ + struct ospf6_lsa_slot *slot; + + slot = ospf6_lsa_slot_get (lsa_header->type); + if (slot) + return 1; + return 0; +} + +struct ospf6_lsa_slot *slot_head = NULL; + +struct ospf6_lsa_slot * +ospf6_lsa_slot_get (u_int16_t type) +{ + struct ospf6_lsa_slot *slot; + + for (slot = slot_head; slot; slot = slot->next) + { + if (slot->type == type) + return slot; + } + + return NULL; +} + +int +ospf6_lsa_slot_register (struct ospf6_lsa_slot *src) +{ + struct ospf6_lsa_slot *new, *slot; + + slot = ospf6_lsa_slot_get (src->type); + if (slot) + { + if (IS_OSPF6_DUMP_LSA) + zlog_info ("LSA: Slot register: already exists: %#x %s", + slot->type, slot->name); + return -1; + } + + new = (struct ospf6_lsa_slot *) + XMALLOC (MTYPE_OSPF6_LSA, sizeof (struct ospf6_lsa_slot)); + if (! new) + { + zlog_err ("Can't allocate memory for LSA slot: %s", strerror (errno)); + return -1; + } + memset (new, 0, sizeof (struct ospf6_lsa_slot)); + memcpy (new, src, sizeof (struct ospf6_lsa_slot)); + + if (IS_OSPF6_DUMP_LSA) + zlog_info ("LSA: Slot register: %#x %s", slot->type, slot->name); + + if (slot_head == NULL) + { + new->prev = NULL; + new->next = NULL; + slot_head = new; + return 0; + } + + slot = slot_head; + while (slot->next) + slot = slot->next; + + slot->next = new; + new->prev = slot; + + return 0; +} + +int +ospf6_lsa_slot_unregister (u_int16_t type) +{ + struct ospf6_lsa_slot *slot; + + slot = ospf6_lsa_slot_get (type); + if (slot == NULL) + { + if (IS_OSPF6_DUMP_LSA) + zlog_info ("Registering LSA slot: no such slot: %#x", type); + return -1; + } + + if (IS_OSPF6_DUMP_LSA) + zlog_info ("Unregistering LSA Slot: %#x %s", slot->type, slot->name); + + if (slot->prev) + slot->prev->next = slot->next; + if (slot->next) + slot->next->prev = slot->prev; + + if (slot_head == slot) + slot_head = slot->next; + + XFREE (MTYPE_OSPF6_LSA, slot); + return 0; +} + +char * +ospf6_lsa_type_string (u_int16_t type, char *buf, int bufsize) +{ + struct ospf6_lsa_slot *slot; + + slot = ospf6_lsa_slot_get (type); + if (slot) + snprintf (buf, bufsize, "%s", slot->name); + else + snprintf (buf, bufsize, "Type=0x%04x", ntohs (type)); + + return buf; +} + + +/*******************/ +/* LSA Origination */ +/*******************/ + +#define CONTINUE_IF_ADDRESS_LINKLOCAL(addr)\ + if (IN6_IS_ADDR_LINKLOCAL (&(addr)->u.prefix6))\ + {\ + char buf[64];\ + prefix2str (addr, buf, sizeof (buf));\ + if (IS_OSPF6_DUMP_LSA)\ + zlog_info (" Filter out Linklocal: %s", buf);\ + continue;\ + } + +#define CONTINUE_IF_ADDRESS_UNSPECIFIED(addr)\ + if (IN6_IS_ADDR_UNSPECIFIED (&(addr)->u.prefix6))\ + {\ + char buf[64];\ + prefix2str (addr, buf, sizeof (buf));\ + if (IS_OSPF6_DUMP_LSA)\ + zlog_info (" Filter out Unspecified: %s", buf);\ + continue;\ + } + +#define CONTINUE_IF_ADDRESS_LOOPBACK(addr)\ + if (IN6_IS_ADDR_LOOPBACK (&(addr)->u.prefix6))\ + {\ + char buf[64];\ + prefix2str (addr, buf, sizeof (buf));\ + if (IS_OSPF6_DUMP_LSA)\ + zlog_info (" Filter out Loopback: %s", buf);\ + continue;\ + } + +#define CONTINUE_IF_ADDRESS_V4COMPAT(addr)\ + if (IN6_IS_ADDR_V4COMPAT (&(addr)->u.prefix6))\ + {\ + char buf[64];\ + prefix2str (addr, buf, sizeof (buf));\ + if (IS_OSPF6_DUMP_LSA)\ + zlog_info (" Filter out V4Compat: %s", buf);\ + continue;\ + } + +#define CONTINUE_IF_ADDRESS_V4MAPPED(addr)\ + if (IN6_IS_ADDR_V4MAPPED (&(addr)->u.prefix6))\ + {\ + char buf[64];\ + prefix2str (addr, buf, sizeof (buf));\ + if (IS_OSPF6_DUMP_LSA)\ + zlog_info (" Filter out V4Mapped: %s", buf);\ + continue;\ + } + +/******************************/ +/* RFC2740 3.4.3.1 Router-LSA */ +/******************************/ + +char * +ospf6_lsa_router_bits_string (u_char router_bits, char *buf, int size) +{ + char w, v, e, b; + + w = (router_bits & OSPF6_ROUTER_LSA_BIT_W ? 'W' : '-'); + v = (router_bits & OSPF6_ROUTER_LSA_BIT_V ? 'V' : '-'); + e = (router_bits & OSPF6_ROUTER_LSA_BIT_E ? 'E' : '-'); + b = (router_bits & OSPF6_ROUTER_LSA_BIT_B ? 'B' : '-'); + snprintf (buf, size, "----%c%c%c%c", w, v, e, b); + return buf; +} + +int +ospf6_lsa_router_show (struct vty *vty, struct ospf6_lsa *lsa) +{ + char *start, *end, *current; + char buf[32], name[32], bits[32], options[32]; + struct ospf6_router_lsa *router_lsa; + struct ospf6_router_lsd *lsdesc; + + assert (lsa->header); + + router_lsa = (struct ospf6_router_lsa *) + ((char *) lsa->header + sizeof (struct ospf6_lsa_header)); + + ospf6_lsa_router_bits_string (router_lsa->bits, bits, sizeof (bits)); + ospf6_options_string (router_lsa->options, options, sizeof (options)); + vty_out (vty, " Bits: %s Options: %s%s", bits, options, VTY_NEWLINE); + + start = (char *) router_lsa + sizeof (struct ospf6_router_lsa); + end = (char *) lsa->header + ntohs (lsa->header->length); + for (current = start; current + sizeof (struct ospf6_router_lsd) <= end; + current += sizeof (struct ospf6_router_lsd)) + { + lsdesc = (struct ospf6_router_lsd *) current; + + if (lsdesc->type == OSPF6_ROUTER_LSD_TYPE_POINTTOPOINT) + snprintf (name, sizeof (name), "Point-To-Point"); + else if (lsdesc->type == OSPF6_ROUTER_LSD_TYPE_TRANSIT_NETWORK) + snprintf (name, sizeof (name), "Transit-Network"); + else if (lsdesc->type == OSPF6_ROUTER_LSD_TYPE_STUB_NETWORK) + snprintf (name, sizeof (name), "Stub-Network"); + else if (lsdesc->type == OSPF6_ROUTER_LSD_TYPE_VIRTUAL_LINK) + snprintf (name, sizeof (name), "Virtual-Link"); + else + snprintf (name, sizeof (name), "Unknown (%#x)", lsdesc->type); + + vty_out (vty, " Type: %s Metric: %d%s", + name, ntohs (lsdesc->metric), VTY_NEWLINE); + vty_out (vty, " Interface ID: %s%s", + inet_ntop (AF_INET, &lsdesc->interface_id, + buf, sizeof (buf)), VTY_NEWLINE); + vty_out (vty, " Neighbor Interface ID: %s%s", + inet_ntop (AF_INET, &lsdesc->neighbor_interface_id, + buf, sizeof (buf)), VTY_NEWLINE); + vty_out (vty, " Neighbor Router ID: %s%s", + inet_ntop (AF_INET, &lsdesc->neighbor_router_id, + buf, sizeof (buf)), VTY_NEWLINE); + } + return 0; +} + +u_long +ospf6_lsa_has_elasped (u_int16_t type, u_int32_t id, + u_int32_t adv_router, void *scope) +{ + struct ospf6_lsa *old; + struct timeval now; + + if (adv_router != ospf6->router_id) + zlog_info ("LSA: Router-ID changed ?"); + + old = ospf6_lsdb_lookup (type, id, adv_router, scope); + if (! old) + return OSPF6_LSA_MAXAGE; + + gettimeofday (&now, NULL); + return ((u_long) SEC_TVDIFF (&now, &old->originated)); +} + +int +ospf6_lsa_originate_router (struct thread *thread) +{ + char buffer [MAXLSASIZE]; + u_int16_t size; + struct ospf6_area *o6a; + int count; + u_int32_t area_id; + + struct ospf6_router_lsa *router_lsa; + struct ospf6_router_lsd *router_lsd; + listnode i; + struct ospf6_interface *o6i; + struct ospf6_neighbor *o6n = NULL; + + area_id = (u_int32_t) THREAD_ARG (thread); + + o6a = ospf6_area_lookup (area_id, ospf6); + if (! o6a) + { + inet_ntop (AF_INET, &area_id, buffer, sizeof (buffer)); + if (IS_OSPF6_DUMP_LSA) + zlog_info ("LSA: Update Router-LSA: No such area: %s", buffer); + return 0; + } + + /* clear thread */ + o6a->thread_router_lsa = NULL; + + if (IS_OSPF6_DUMP_LSA) + zlog_info ("LSA: originate Router-LSA for Area %s", o6a->str); + + size = sizeof (struct ospf6_router_lsa); + memset (buffer, 0, sizeof (buffer)); + router_lsa = (struct ospf6_router_lsa *) buffer; + + OSPF6_OPT_CLEAR_ALL (router_lsa->options); + OSPF6_OPT_SET (router_lsa->options, OSPF6_OPT_V6); + OSPF6_OPT_SET (router_lsa->options, OSPF6_OPT_E); + OSPF6_OPT_CLEAR (router_lsa->options, OSPF6_OPT_MC); + OSPF6_OPT_CLEAR (router_lsa->options, OSPF6_OPT_N); + OSPF6_OPT_SET (router_lsa->options, OSPF6_OPT_R); + OSPF6_OPT_CLEAR (router_lsa->options, OSPF6_OPT_DC); + + OSPF6_ROUTER_LSA_CLEAR_ALL_BITS (router_lsa); + OSPF6_ROUTER_LSA_CLEAR (router_lsa, OSPF6_ROUTER_LSA_BIT_B); + + if (ospf6_is_asbr (o6a->ospf6)) + OSPF6_ROUTER_LSA_SET (router_lsa, OSPF6_ROUTER_LSA_BIT_E); + else + OSPF6_ROUTER_LSA_CLEAR (router_lsa, OSPF6_ROUTER_LSA_BIT_E); + + OSPF6_ROUTER_LSA_CLEAR (router_lsa, OSPF6_ROUTER_LSA_BIT_V); + OSPF6_ROUTER_LSA_CLEAR (router_lsa, OSPF6_ROUTER_LSA_BIT_W); + + /* describe links for each interfaces */ + router_lsd = (struct ospf6_router_lsd *) (router_lsa + 1); + for (i = listhead (o6a->if_list); i; nextnode (i)) + { + o6i = (struct ospf6_interface *) getdata (i); + assert (o6i); + + /* Interfaces in state Down or Loopback are not described */ + if (o6i->state == IFS_DOWN || o6i->state == IFS_LOOPBACK) + continue; + + /* Nor are interfaces without any full adjacencies described */ + count = 0; + o6i->foreach_nei (o6i, &count, NBS_FULL, ospf6_count_state); + if (count == 0) + continue; + + /* Point-to-Point interfaces */ + if (if_is_pointopoint (o6i->interface)) + { + if (listcount (o6i->neighbor_list) == 0) + continue; + + if (listcount (o6i->neighbor_list) != 1) + zlog_warn ("LSA: Multiple neighbors on PoinToPoint: %s", + o6i->interface->name); + + o6n = (struct ospf6_neighbor *) + getdata (listhead (o6i->neighbor_list)); + assert (o6n); + + router_lsd->type = OSPF6_ROUTER_LSD_TYPE_POINTTOPOINT; + router_lsd->metric = htons (o6i->cost); + router_lsd->interface_id = htonl (o6i->if_id); + router_lsd->neighbor_interface_id = htonl (o6n->ifid); + router_lsd->neighbor_router_id = o6n->router_id; + + size += sizeof (struct ospf6_router_lsd); + router_lsd ++; + + continue; + } + + /* Broadcast and NBMA interfaces */ + if (if_is_broadcast (o6i->interface)) + { + /* If this router is not DR, + and If this router not fully adjacent with DR, + this interface is not transit yet: ignore. */ + if (o6i->state != IFS_DR) + { + o6n = ospf6_neighbor_lookup (o6i->dr, o6i); /* find DR */ + if (o6n == NULL || o6n->state != NBS_FULL) + continue; + } + else + { + count = 0; + o6i->foreach_nei (o6i, &count, NBS_FULL, ospf6_count_state); + if (count == 0) + continue; + } + + router_lsd->type = OSPF6_ROUTER_LSD_TYPE_TRANSIT_NETWORK; + router_lsd->metric = htons (o6i->cost); + router_lsd->interface_id = htonl (o6i->if_id); + if (o6i->state != IFS_DR) + { + router_lsd->neighbor_interface_id = htonl (o6n->ifid); + router_lsd->neighbor_router_id = o6n->router_id; + } + else + { + router_lsd->neighbor_interface_id = htonl (o6i->if_id); + router_lsd->neighbor_router_id = o6i->area->ospf6->router_id; + } + + size += sizeof (struct ospf6_router_lsd); + router_lsd ++; + + continue; + } + + /* Virtual links */ + /* xxx */ + /* Point-to-Multipoint interfaces */ + /* xxx */ + } + + ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_ROUTER), + htonl (0), o6a->ospf6->router_id, + (char *) router_lsa, size, o6a); + return 0; +} + +void +ospf6_lsa_schedule_router (struct ospf6_area *area) +{ + u_long elasped_time, time = 0; + + if (area->thread_router_lsa) + { + if (IS_OSPF6_DUMP_LSA) + zlog_info ("LSA: schedule: Router-LSA for Area %s: another thread", + area->str); + return; + } + + elasped_time = + ospf6_lsa_has_elasped (htons (OSPF6_LSA_TYPE_ROUTER), htonl (0), + area->ospf6->router_id, area); + if (elasped_time < OSPF6_MIN_LS_INTERVAL) + time = (u_long) (OSPF6_MIN_LS_INTERVAL - elasped_time); + else + time = 0; + + if (IS_OSPF6_DUMP_LSA) + zlog_info ("LSA: schedule: Router-LSA for Area %s after %lu sec", + area->str, time); + + if (time) + area->thread_router_lsa = + thread_add_timer (master, ospf6_lsa_originate_router, + (void *) area->area_id, time); + else + area->thread_router_lsa = + thread_add_event (master, ospf6_lsa_originate_router, + (void *) area->area_id, 0); +} + +int +ospf6_lsa_router_hook_neighbor (void *neighbor) +{ + struct ospf6_neighbor *o6n = neighbor; + if (o6n->ospf6_interface->area) + ospf6_lsa_schedule_router (o6n->ospf6_interface->area); + return 0; +} + +int +ospf6_lsa_router_hook_interface (void *interface) +{ + struct ospf6_interface *o6i = interface; + if (o6i->area) + ospf6_lsa_schedule_router (o6i->area); + return 0; +} + +int +ospf6_lsa_router_hook_area (void *area) +{ + struct ospf6_area *o6a = area; + ospf6_lsa_schedule_router (o6a); + return 0; +} + +int +ospf6_lsa_router_hook_top (void *ospf6) +{ + struct ospf6 *o6 = ospf6; + struct ospf6_area *o6a; + listnode node; + + for (node = listhead (o6->area_list); node; nextnode (node)) + { + o6a = getdata (node); + ospf6_lsa_schedule_router (o6a); + } + return 0; +} + +int +ospf6_lsa_router_refresh (void *old) +{ + struct ospf6_lsa *lsa = old; + struct ospf6_area *o6a; + + o6a = lsa->scope; + ospf6_lsa_schedule_router (o6a); + return 0; +} + +void +ospf6_lsa_slot_register_router () +{ + struct ospf6_lsa_slot slot; + struct ospf6_hook hook; + + memset (&slot, 0, sizeof (struct ospf6_lsa_slot)); + slot.type = htons (OSPF6_LSA_TYPE_ROUTER); + slot.name = "Router"; + slot.func_show = ospf6_lsa_router_show; + slot.func_refresh = ospf6_lsa_router_refresh; + ospf6_lsa_slot_register (&slot); + + ospf6_lsdb_hook[OSPF6_LSA_TYPE_ROUTER & OSPF6_LSTYPE_CODE_MASK].hook = + ospf6_spf_database_hook; + + memset (&hook, 0, sizeof (hook)); + hook.name = "OriginateRouter"; + hook.hook_change = ospf6_lsa_router_hook_neighbor; + ospf6_hook_register (&hook, &neighbor_hook); + + memset (&hook, 0, sizeof (hook)); + hook.name = "OriginateRouter"; + hook.hook_change = ospf6_lsa_router_hook_interface; + ospf6_hook_register (&hook, &interface_hook); + + memset (&hook, 0, sizeof (hook)); + hook.name = "OriginateRouter"; + hook.hook_change = ospf6_lsa_router_hook_area; + ospf6_hook_register (&hook, &area_hook); + + memset (&hook, 0, sizeof (hook)); + hook.name = "OriginateRouter"; + hook.hook_change = ospf6_lsa_router_hook_top; + ospf6_hook_register (&hook, &top_hook); +} + +/*******************************/ +/* RFC2740 3.4.3.2 Network-LSA */ +/*******************************/ + +int +ospf6_lsa_network_show (struct vty *vty, struct ospf6_lsa *lsa) +{ + char *start, *end, *current; + struct ospf6_network_lsa *network_lsa; + u_int32_t *router_id; + char buf[128], options[32]; + + assert (lsa->header); + network_lsa = (struct ospf6_network_lsa *) (lsa->header + 1); + router_id = (u_int32_t *)(network_lsa + 1); + + ospf6_options_string (network_lsa->options, options, sizeof (options)); + vty_out (vty, " Options: %s%s", options, VTY_NEWLINE); + + start = (char *) network_lsa + sizeof (struct ospf6_network_lsa); + end = (char *) lsa->header + ntohs (lsa->header->length); + for (current = start; current + sizeof (u_int32_t) <= end; + current += sizeof (u_int32_t)) + { + router_id = (u_int32_t *) current; + inet_ntop (AF_INET, router_id, buf, sizeof (buf)); + vty_out (vty, " Attached Router: %s%s", buf, VTY_NEWLINE); + } + return 0; +} + +void +ospf6_lsa_network_update (char *ifname) +{ + char buffer [MAXLSASIZE]; + u_int16_t size; + struct ospf6_lsa *old; + struct interface *ifp; + struct ospf6_interface *o6i; + int count; + + struct ospf6_network_lsa *network_lsa; + struct ospf6_neighbor *o6n; + u_int32_t *router_id; + listnode node; + + ifp = if_lookup_by_name (ifname); + if (! ifp) + { + if (IS_OSPF6_DUMP_LSA) + zlog_warn ("Update Network: No such Interface: %s", ifname); + return; + } + + o6i = (struct ospf6_interface *) ifp->info; + if (! o6i || ! o6i->area) + { + if (IS_OSPF6_DUMP_LSA) + zlog_warn ("Update Network: Interface not enabled: %s", ifname); + return; + } + + /* find previous LSA */ + old = ospf6_lsdb_lookup (htons (OSPF6_LSA_TYPE_NETWORK), + htonl (o6i->if_id), + o6i->area->ospf6->router_id, o6i->area); + + /* Don't originate Network-LSA if not DR */ + if (o6i->state != IFS_DR) + { + if (IS_OSPF6_DUMP_LSA) + zlog_info ("Update Network: Interface %s is not DR", + o6i->interface->name); + if (old) + ospf6_lsa_premature_aging (old); + return; + } + + /* If none of neighbor is adjacent to us */ + count = 0; + o6i->foreach_nei (o6i, &count, NBS_FULL, ospf6_count_state); + if (count == 0) + { + if (IS_OSPF6_DUMP_LSA) + zlog_info ("Update Network: Interface %s is Stub", + o6i->interface->name); + if (old) + ospf6_lsa_premature_aging (old); + return; + } + + if (IS_OSPF6_DUMP_LSA) + zlog_info ("Update Network: Interface %s", o6i->interface->name); + + /* prepare buffer */ + memset (buffer, 0, sizeof (buffer)); + size = sizeof (struct ospf6_network_lsa); + network_lsa = (struct ospf6_network_lsa *) buffer; + router_id = (u_int32_t *)(network_lsa + 1); + + /* set fields of myself */ + *router_id++ = o6i->area->ospf6->router_id; + size += sizeof (u_int32_t); + network_lsa->options[0] |= o6i->area->options[0]; + network_lsa->options[1] |= o6i->area->options[1]; + network_lsa->options[2] |= o6i->area->options[2]; + + /* Walk through neighbors */ + for (node = listhead (o6i->neighbor_list); node; nextnode (node)) + { + o6n = (struct ospf6_neighbor *) getdata (node); + + if (o6n->state != NBS_FULL) + continue; + + /* set this neighbor's Router-ID to LSA */ + *router_id++ = o6n->router_id; + size += sizeof (u_int32_t); + + /* options field is logical OR */ + network_lsa->options[0] |= o6n->options[0]; + network_lsa->options[1] |= o6n->options[1]; + network_lsa->options[2] |= o6n->options[2]; + } + + ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_NETWORK), + htonl (o6i->if_id), o6i->area->ospf6->router_id, + (char *) network_lsa, size, o6i->area); +} + +int +ospf6_lsa_network_hook_neighbor (void *neighbor) +{ + struct ospf6_neighbor *o6n = neighbor; + ospf6_lsa_network_update (o6n->ospf6_interface->interface->name); + return 0; +} + +int +ospf6_lsa_network_hook_interface (void *interface) +{ + struct ospf6_interface *o6i = interface; + if (o6i->area) + ospf6_lsa_network_update (o6i->interface->name); + return 0; +} + +int +ospf6_lsa_network_refresh (void *old) +{ + struct ospf6_lsa *lsa = old; + struct interface *ifp; + + ifp = if_lookup_by_index (ntohl (lsa->header->id)); + if (! ifp) + ospf6_lsa_premature_aging (old); + else + ospf6_lsa_network_update (ifp->name); + + return 0; +} + +void +ospf6_lsa_slot_register_network () +{ + struct ospf6_lsa_slot slot; + struct ospf6_hook hook; + + memset (&slot, 0, sizeof (struct ospf6_lsa_slot)); + slot.type = htons (OSPF6_LSA_TYPE_NETWORK); + slot.name = "Network"; + slot.func_show = ospf6_lsa_network_show; + slot.func_refresh = ospf6_lsa_network_refresh; + ospf6_lsa_slot_register (&slot); + + ospf6_lsdb_hook[OSPF6_LSA_TYPE_NETWORK & OSPF6_LSTYPE_CODE_MASK].hook = + ospf6_spf_database_hook; + + memset (&hook, 0, sizeof (hook)); + hook.name = "OriginateNetwork"; + hook.hook_change = ospf6_lsa_network_hook_neighbor; + ospf6_hook_register (&hook, &neighbor_hook); + + memset (&hook, 0, sizeof (hook)); + hook.name = "OriginateNetwork"; + hook.hook_change = ospf6_lsa_network_hook_interface; + ospf6_hook_register (&hook, &interface_hook); +} + +/****************************/ +/* RFC2740 3.4.3.6 Link-LSA */ +/****************************/ + +int +ospf6_lsa_link_show (struct vty *vty, struct ospf6_lsa *lsa) +{ + char *start, *end, *current; + struct ospf6_link_lsa *link_lsa; + int prefixnum; + struct ospf6_prefix *prefix; + char buf[128]; + struct in6_addr in6; + + assert (lsa->header); + + link_lsa = (struct ospf6_link_lsa *) (lsa->header + 1); + prefixnum = ntohl (link_lsa->llsa_prefix_num); + + inet_ntop (AF_INET6, (void *)&link_lsa->llsa_linklocal, buf, sizeof (buf)); + vty_out (vty, " LinkLocal Address: %s%s", buf, VTY_NEWLINE); + vty_out (vty, " Number of Prefix: %d%s", prefixnum, VTY_NEWLINE); + + start = (char *) link_lsa + sizeof (struct ospf6_link_lsa); + end = (char *) lsa->header + ntohs (lsa->header->length); + for (current = start; current < end; current += OSPF6_PREFIX_SIZE (prefix)) + { + prefix = (struct ospf6_prefix *) current; + if (current + OSPF6_PREFIX_SIZE (prefix) > end) + { + vty_out (vty, " Trailing %d byte garbage ... Malformed%s", + end - current, VTY_NEWLINE); + return -1; + } + + ospf6_prefix_options_str (prefix->prefix_options, buf, sizeof (buf)); + vty_out (vty, " Prefix Options: %s%s", buf, VTY_NEWLINE); + ospf6_prefix_in6_addr (prefix, &in6); + inet_ntop (AF_INET6, &in6, buf, sizeof (buf)); + vty_out (vty, " Prefix: %s/%d%s", + buf, prefix->prefix_length, VTY_NEWLINE); + } + + return 0; +} + + +void +ospf6_lsa_link_update (char *ifname) +{ + char *cp, buffer [MAXLSASIZE], buf[32]; + u_int16_t size; + struct ospf6_lsa *old; + struct interface *ifp; + struct ospf6_interface *o6i; + + struct ospf6_link_lsa *link_lsa; + struct ospf6_prefix *p; + list prefix_connected; + listnode node; + struct connected *c; + + ifp = if_lookup_by_name (ifname); + if (! ifp) + { + if (IS_OSPF6_DUMP_LSA) + zlog_info ("Update Link: No such Interface: %s", ifname); + return; + } + + o6i = (struct ospf6_interface *) ifp->info; + if (! o6i || ! o6i->area) + { + if (IS_OSPF6_DUMP_LSA) + zlog_info ("Update Link: Interface not enabled: %s", ifname); + return; + } + +#if 0 + /* Link-LSA is on Broadcast or NBMA */ + if (! if_is_broadcast (o6i->interface) /* && ! NBMA xxx */) + { + return; + } +#endif /*0*/ + + /* find previous LSA */ + old = ospf6_lsdb_lookup (htons (OSPF6_LSA_TYPE_LINK), htonl (o6i->if_id), + ospf6->router_id, o6i->area); + + /* can't make Link-LSA if linklocal address not set */ + if (! o6i->lladdr) + { + if (IS_OSPF6_DUMP_LSA) + zlog_warn ("Update Link: No Linklocal Address: %s", + o6i->interface->name); + if (old) + ospf6_lsa_premature_aging (old); + return; + } + + if (IS_OSPF6_DUMP_LSA) + zlog_info ("Update Link: Interface %s", o6i->interface->name); + + if (! ospf6_interface_is_enabled (o6i->interface->ifindex)) + { + if (IS_OSPF6_DUMP_LSA) + zlog_info (" Interface %s not enabled", o6i->interface->name); + if (old) + ospf6_lsa_premature_aging (old); + return; + } + + /* check connected prefix */ + prefix_connected = list_new (); + for (node = listhead (o6i->interface->connected); node; nextnode (node)) + { + c = (struct connected *) getdata (node); + + /* filter prefix not IPv6 */ + if (c->address->family != AF_INET6) + continue; + + /* for log */ + prefix2str (c->address, buf, sizeof (buf)); + + CONTINUE_IF_ADDRESS_LINKLOCAL (c->address); + CONTINUE_IF_ADDRESS_UNSPECIFIED (c->address); + CONTINUE_IF_ADDRESS_LOOPBACK (c->address); + CONTINUE_IF_ADDRESS_V4COMPAT (c->address); + CONTINUE_IF_ADDRESS_V4MAPPED (c->address); + + /* filter prefix specified by configuration */ + if (o6i->plist_name) + { + struct prefix_list *plist; + enum prefix_list_type result = PREFIX_PERMIT; + + plist = prefix_list_lookup (AFI_IP6, o6i->plist_name); + if (plist) + result = prefix_list_apply (plist, c->address); + else if (IS_OSPF6_DUMP_LSA) + zlog_warn ("Update Intra-Prefix (Stub): " + "Prefix list \"%s\" not found", o6i->plist_name); + + if (result == PREFIX_DENY) + { + if (IS_OSPF6_DUMP_LSA) + zlog_info (" Filter out Prefix-list %s: %s", + o6i->plist_name, buf); + continue; + } + } + + if (IS_OSPF6_DUMP_LSA) + zlog_info (" Advertise %s", buf); + + /* hold prefix in list. duplicate is filtered in ospf6_prefix_add() */ + p = ospf6_prefix_create (0, 0, (struct prefix_ipv6 *) c->address); + ospf6_prefix_add (prefix_connected, p); + } + + /* Note: even if no prefix configured, still we have to create Link-LSA + for next-hop resolution */ + + memset (buffer, 0, sizeof (buffer)); + size = sizeof (struct ospf6_link_lsa); + link_lsa = (struct ospf6_link_lsa *) buffer; + + /* fill Link LSA and calculate size */ + link_lsa->llsa_rtr_pri = o6i->priority; + link_lsa->llsa_options[0] = o6i->area->options[0]; + link_lsa->llsa_options[1] = o6i->area->options[1]; + link_lsa->llsa_options[2] = o6i->area->options[2]; + + /* linklocal address */ + memcpy (&link_lsa->llsa_linklocal, o6i->lladdr, sizeof (struct in6_addr)); + +#ifdef KAME /* clear ifindex */ + if (link_lsa->llsa_linklocal.s6_addr[3] & 0x0f) + link_lsa->llsa_linklocal.s6_addr[3] &= ~((char)0x0f); +#endif /* KAME */ + + link_lsa->llsa_prefix_num = htonl (listcount (prefix_connected)); + cp = (char *)(link_lsa + 1); + for (node = listhead (prefix_connected); node; nextnode (node)) + { + p = (struct ospf6_prefix *) getdata (node); + size += OSPF6_PREFIX_SIZE (p); + memcpy (cp, p, OSPF6_PREFIX_SIZE (p)); + cp += OSPF6_PREFIX_SIZE (p); + } + + for (node = listhead (prefix_connected); node; nextnode (node)) + { + p = (struct ospf6_prefix *) getdata (node); + ospf6_prefix_delete (p); + } + list_delete (prefix_connected); + + ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_LINK), + htonl (o6i->if_id), o6i->area->ospf6->router_id, + (char *) link_lsa, size, o6i); +} + +int +ospf6_lsa_link_hook_interface (void *interface) +{ + struct ospf6_interface *o6i = interface; + if (o6i->area) + ospf6_lsa_link_update (o6i->interface->name); + return 0; +} + +int +ospf6_lsa_link_refresh (void *old) +{ + struct ospf6_lsa *lsa = old; + struct interface *ifp; + + ifp = if_lookup_by_index (ntohl (lsa->header->id)); + if (! ifp) + ospf6_lsa_premature_aging (old); + else + ospf6_lsa_link_update (ifp->name); + + return 0; +} + +void +ospf6_lsa_slot_register_link () +{ + struct ospf6_lsa_slot slot; + + memset (&slot, 0, sizeof (struct ospf6_lsa_slot)); + slot.type = htons (OSPF6_LSA_TYPE_LINK); + slot.name = "Link"; + slot.func_show = ospf6_lsa_link_show; + slot.func_refresh = ospf6_lsa_link_refresh; + slot.hook_interface.name = "OriginateLink"; + slot.hook_interface.hook_change = ospf6_lsa_link_hook_interface; + ospf6_lsa_slot_register (&slot); + + /* + * Link LSA handling will be shift in ospf6_intra.c + * Currently, only database hook only moved to ospf6_intra.c + */ +#if 0 + ospf6_lsdb_hook[OSPF6_LSA_TYPE_LINK & OSPF6_LSTYPE_CODE_MASK].hook = + ospf6_spf_database_hook; +#endif /*0*/ +} + +int +ospf6_lsa_add_hook (void *data) +{ + struct ospf6_lsa *lsa = data; + struct ospf6_lsa_slot *sp; + + sp = ospf6_lsa_slot_get (lsa->header->type); + if (sp) + { + CALL_CHANGE_HOOK (&sp->database_hook, lsa); + } + else + zlog_warn ("Unknown LSA added to database: %s", lsa->str); + return 0; +} + +int +ospf6_lsa_change_hook (void *data) +{ + struct ospf6_lsa *lsa = data; + struct ospf6_lsa_slot *sp; + + sp = ospf6_lsa_slot_get (lsa->header->type); + if (sp) + { + CALL_CHANGE_HOOK (&sp->database_hook, lsa); + } + else + zlog_warn ("Unknown LSA changed in database: %s", lsa->str); + return 0; +} + +int +ospf6_lsa_remove_hook (void *data) +{ + struct ospf6_lsa *lsa = data; + struct ospf6_lsa_slot *sp; + + sp = ospf6_lsa_slot_get (lsa->header->type); + if (sp) + { + CALL_REMOVE_HOOK (&sp->database_hook, lsa); + } + else + zlog_warn ("Unknown LSA removed from database: %s", lsa->str); + return 0; +} + +/* Initialize LSA slots */ +void +ospf6_lsa_init () +{ + struct ospf6_hook hook; + + slot_head = NULL; + ospf6_lsa_slot_register_router (); + ospf6_lsa_slot_register_network (); + ospf6_lsa_slot_register_link (); +#if 0 + ospf6_lsa_slot_register_intra_prefix (); + ospf6_lsa_slot_register_as_external (); +#endif /*0*/ + + hook.name = "LSADatabaseHook"; + hook.hook_add = ospf6_lsa_add_hook; + hook.hook_change = ospf6_lsa_change_hook; + hook.hook_remove = ospf6_lsa_remove_hook; + ospf6_hook_register (&hook, &database_hook); +} + diff --git a/ospf6d/ospf6_lsa.h b/ospf6d/ospf6_lsa.h new file mode 100644 index 000000000..02ad7c6f6 --- /dev/null +++ b/ospf6d/ospf6_lsa.h @@ -0,0 +1,426 @@ +/* + * LSA function + * Copyright (C) 1999 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF6_LSA_H +#define OSPF6_LSA_H + +#include "ospf6_hook.h" + +#define ONESECOND_USEC 1000000 +#define USEC_TVDIFF(tv2,tv1) \ + (((tv2)->tv_sec - (tv1)->tv_sec) * ONESECOND_USEC \ + + ((tv2)->tv_usec - (tv1)->tv_usec)) +#define SEC_TVDIFF(tv2,tv1) \ + (USEC_TVDIFF((tv2),(tv1)) / ONESECOND_USEC) + +/* LSA definition */ + +#define MAXLSASIZE 1024 + +#define OSPF6_LSA_MAXAGE 3600 /* 1 hour */ +#define OSPF6_LSA_CHECKAGE 300 /* 5 min */ +#define OSPF6_LSA_MAXAGEDIFF 900 /* 15 min */ + +/* Type */ +#define OSPF6_LSA_TYPE_NONE 0x0000 +#define OSPF6_LSA_TYPE_ROUTER 0x2001 +#define OSPF6_LSA_TYPE_NETWORK 0x2002 +#define OSPF6_LSA_TYPE_INTER_PREFIX 0x2003 +#define OSPF6_LSA_TYPE_INTER_ROUTER 0x2004 +#define OSPF6_LSA_TYPE_AS_EXTERNAL 0x4005 +#define OSPF6_LSA_TYPE_GROUP_MEMBERSHIP 0x2006 +#define OSPF6_LSA_TYPE_TYPE_7 0x2007 +#define OSPF6_LSA_TYPE_LINK 0x0008 +#define OSPF6_LSA_TYPE_INTRA_PREFIX 0x2009 +#define OSPF6_LSA_TYPE_MAX 0x000a +#define OSPF6_LSA_TYPE_SIZE 0x000b + +/* Masks for LS Type : RFC 2740 A.4.2.1 "LS type" */ +#define OSPF6_LSTYPE_UBIT_MASK 0x8000 +#define OSPF6_LSTYPE_SCOPE_MASK 0x6000 +#define OSPF6_LSTYPE_CODE_MASK 0x1fff + +#define OSPF6_LSA_TYPESW_MASK OSPF6_LSTYPE_CODE_MASK +#define OSPF6_LSA_TYPESW(x) (ntohs((x)) & OSPF6_LSA_TYPESW_MASK) +#define OSPF6_LSA_TYPESW_ISKNOWN(x) (OSPF6_LSA_TYPESW(x) < OSPF6_LSA_TYPE_MAX) + +/* lsa scope */ +#define OSPF6_LSA_SCOPE_LINKLOCAL 0x0000 +#define OSPF6_LSA_SCOPE_AREA 0x2000 +#define OSPF6_LSA_SCOPE_AS 0x4000 +#define OSPF6_LSA_SCOPE_RESERVED 0x6000 +#define OSPF6_LSA_IS_SCOPE_LINKLOCAL(x) \ + (((x) & OSPF6_LSTYPE_SCOPE_MASK) == OSPF6_LSA_SCOPE_LINKLOCAL) +#define OSPF6_LSA_IS_SCOPE_AREA(x) \ + (((x) & OSPF6_LSTYPE_SCOPE_MASK) == OSPF6_LSA_SCOPE_AREA) +#define OSPF6_LSA_IS_SCOPE_AS(x) \ + (((x) & OSPF6_LSTYPE_SCOPE_MASK) == OSPF6_LSA_SCOPE_AS) + +/* NOTE that all LSAs are kept NETWORK BYTE ORDER */ + +/* Router-LSA */ +struct ospf6_router_lsa +{ + u_char bits; + u_char options[3]; + /* followed by ospf6_router_lsd(s) */ +}; + +#define OSPF6_ROUTER_LSA_BIT_B (1 << 0) +#define OSPF6_ROUTER_LSA_BIT_E (1 << 1) +#define OSPF6_ROUTER_LSA_BIT_V (1 << 2) +#define OSPF6_ROUTER_LSA_BIT_W (1 << 3) + +#define OSPF6_ROUTER_LSA_SET(x,y) ((x)->bits |= (y)) +#define OSPF6_ROUTER_LSA_ISSET(x,y) ((x)->bits & (y)) +#define OSPF6_ROUTER_LSA_CLEAR(x,y) ((x)->bits &= ~(y)) +#define OSPF6_ROUTER_LSA_CLEAR_ALL_BITS(x) ((x)->bits = 0) + +/* Link State Description in Router-LSA */ +struct ospf6_router_lsd +{ + u_char type; + u_char reserved; + u_int16_t metric; /* output cost */ + u_int32_t interface_id; + u_int32_t neighbor_interface_id; + u_int32_t neighbor_router_id; +}; + +#define OSPF6_ROUTER_LSD_TYPE_POINTTOPOINT 1 +#define OSPF6_ROUTER_LSD_TYPE_TRANSIT_NETWORK 2 +#define OSPF6_ROUTER_LSD_TYPE_STUB_NETWORK 3 +#define OSPF6_ROUTER_LSD_TYPE_VIRTUAL_LINK 4 + +/* Network-LSA */ +struct ospf6_network_lsa +{ + u_char reserved; + u_char options[3]; + /* followed by ospf6_netowrk_lsd(s) */ +}; + +/* Link State Description in Router-LSA */ +struct ospf6_network_lsd +{ + u_int32_t adv_router; +}; + +/* Link-LSA */ +struct ospf6_link_lsa +{ + u_char llsa_rtr_pri; + u_char llsa_options[3]; + struct in6_addr llsa_linklocal; + u_int32_t llsa_prefix_num; + /* followed by prefix(es) */ +}; + +/* Intra-Area-Prefix-LSA */ +struct ospf6_intra_area_prefix_lsa +{ + u_int16_t prefix_number; + u_int16_t refer_lstype; + u_int32_t refer_lsid; + u_int32_t refer_advrtr; +}; + +/* AS-External-LSA */ +struct ospf6_as_external_lsa +{ + u_char ase_bits; + u_char ase_pre_metric; /* 1st byte of metric */ + u_int16_t ase_metric; /* 2nd, 3rd byte of metric */ +#if 1 + struct ospf6_prefix ospf6_prefix; +#else + u_char ase_prefix_len; + u_char ase_prefix_opt; + u_int16_t ase_refer_lstype; + /* followed by one address prefix */ +#endif + /* followed by none or one forwarding address */ + /* followed by none or one external route tag */ + /* followed by none or one referenced LS-ID */ +}; +#define ASE_LSA_BIT_T (1 << 0) +#define ASE_LSA_BIT_F (1 << 1) +#define ASE_LSA_BIT_E (1 << 2) + +#define ASE_LSA_SET(x,y) ((x)->ase_bits |= (y)) +#define ASE_LSA_ISSET(x,y) ((x)->ase_bits & (y)) +#define ASE_LSA_CLEAR(x,y) ((x)->ase_bits &= ~(y)) + +/* LSA Header */ +struct ospf6_lsa_hdr +{ + u_int16_t lsh_age; /* LS age */ + u_int16_t lsh_type; /* LS type */ + u_int32_t lsh_id; /* Link State ID */ + u_int32_t lsh_advrtr; /* Advertising Router */ + u_int32_t lsh_seqnum; /* LS sequence number */ + u_int16_t lsh_cksum; /* LS checksum */ + u_int16_t lsh_len; /* length */ +}; +struct ospf6_lsa_header +{ + u_int16_t age; /* LS age */ + u_int16_t type; /* LS type */ + u_int32_t ls_id; /* Link State ID */ + u_int32_t advrtr; /* Advertising Router */ + u_int32_t seqnum; /* LS sequence number */ + u_int16_t checksum; /* LS checksum */ + u_int16_t length; /* LSA length */ +}; +struct ospf6_lsa_header__ +{ + u_int16_t age; /* LS age */ + u_int16_t type; /* LS type */ + u_int32_t id; /* Link State ID */ + u_int32_t adv_router; /* Advertising Router */ + u_int32_t seqnum; /* LS sequence number */ + u_int16_t checksum; /* LS checksum */ + u_int16_t length; /* LSA length */ +}; + +#define OSPF6_LSA_NEXT(x) ((struct ospf6_lsa_header *) \ + ((char *)(x) + ntohs ((x)->length))) + +#define OSPF6_LSA_HEADER_END(header) \ + ((void *)((char *)(header) + sizeof (struct ospf6_lsa_header))) + +struct ospf6_lsa +{ + char str[256]; /* dump string */ + + u_long lock; /* reference counter */ + int summary; /* indicate this is LS header only */ + void *scope; /* pointer of scoped data structure */ + unsigned char flag; /* to decide ack type and refresh */ + struct timeval birth; /* tv_sec when LS age 0 */ + struct timeval installed; /* installed time */ + struct timeval originated; /* installed time */ + struct thread *expire; + struct thread *refresh; /* For self-originated LSA */ + u_int32_t from; /* from which neighbor */ + + /* lsa instance */ + struct ospf6_lsa_hdr *lsa_hdr; + struct ospf6_lsa_header__ *header; + + /* statistics */ + u_long turnover_num; + u_long turnover_total; + u_long turnover_min; + u_long turnover_max; +}; + +struct ospf6_lsa_slot +{ + struct ospf6_lsa_slot *prev; + struct ospf6_lsa_slot *next; + + u_int16_t type; + char *name; + + int (*func_print) (struct ospf6_lsa *lsa); + int (*func_show) (struct vty *vty, struct ospf6_lsa *lsa); + int (*func_refresh) (void *lsa); + + int (*database_add) (void *lsa); + int (*database_remove) (void *lsa); + + struct ospf6_hook_master database_hook; + + struct ospf6_hook hook_neighbor; + struct ospf6_hook hook_interface; + struct ospf6_hook hook_area; + struct ospf6_hook hook_top; + struct ospf6_hook hook_database; + struct ospf6_hook hook_route; +}; + +#define OSPF6_LSA_FLAG_FLOODBACK 0x01 +#define OSPF6_LSA_FLAG_DUPLICATE 0x02 +#define OSPF6_LSA_FLAG_IMPLIEDACK 0x04 +#define OSPF6_LSA_FLAG_REFRESH 0x08 + +/* Back pointer check, Is X's reference field bound to Y ? */ +#define x_ipl(x) ((struct intra_area_prefix_lsa *)LSH_NEXT((x)->lsa_hdr)) +#define is_reference_network_ok(x,y) \ + ((x_ipl(x))->intra_prefix_refer_lstype == (y)->lsa_hdr->lsh_type &&\ + (x_ipl(x))->intra_prefix_refer_lsid == (y)->lsa_hdr->lsh_id &&\ + (x_ipl(x))->intra_prefix_refer_advrtr == (y)->lsa_hdr->lsh_advrtr) + /* referencing router's ifid must be 0, + see draft-ietf-ospf-ospfv6-06.txt */ +#define is_reference_router_ok(x,y) \ + ((x_ipl(x))->intra_prefix_refer_lstype == (y)->lsa_hdr->lsh_type &&\ + (x_ipl(x))->intra_prefix_refer_lsid == htonl (0) &&\ + (x_ipl(x))->intra_prefix_refer_advrtr == (y)->lsa_hdr->lsh_advrtr) + +/* MaxAge check. */ +/* ospf6_lsa_is_maxage (struct ospf6_lsa *lsa) */ +#define IS_LSA_MAXAGE(L) (ospf6_lsa_age_current (L) == OSPF6_LSA_MAXAGE) + +struct ospf6_lsa_slot *ospf6_lsa_slot_get (u_int16_t type); +int ospf6_lsa_slot_register (struct ospf6_lsa_slot *src); +int ospf6_lsa_slot_unregister (u_int16_t type); + +extern struct ospf6_lsa_slot *slot_head; +#define CALL_FOREACH_LSA_HOOK(hook,func,data) \ + if (ospf6)\ + {\ + struct ospf6_lsa_slot *slot;\ + for (slot = slot_head; slot; slot = slot->next)\ + {\ + if (slot->hook.func)\ + (*slot->hook.func) (data);\ + }\ + } +#define CALL_LSA_FUNC(type,func,data) \ + if (ospf6)\ + {\ + struct ospf6_lsa_slot *slot;\ + slot = ospf6_lsa_slot_get (type);\ + if (slot && slot->func)\ + {\ + (*slot->func) (data);\ + }\ + else\ + {\ + zlog_warn ("LSA: No slot for type %#x: %s line:%d",\ + ntohs (type), __FILE__, __LINE__);\ + }\ + } + +#define CALL_LSA_DATABASE_ADD(type,data) \ + if (ospf6)\ + {\ + struct ospf6_lsa_slot *slot;\ + slot = ospf6_lsa_slot_get (type);\ + if (slot)\ + {\ + CALL_ADD_HOOK (&slot->database_hook, data);\ + }\ + else\ + {\ + zlog_warn ("LSA: No slot for type %#x: %s line:%d",\ + ntohs (type), __FILE__, __LINE__);\ + }\ + } +#define CALL_LSA_DATABASE_CHANGE(type,data) \ + if (ospf6)\ + {\ + struct ospf6_lsa_slot *slot;\ + slot = ospf6_lsa_slot_get (type);\ + if (slot)\ + {\ + CALL_CHANGE_HOOK (&slot->database_hook, data);\ + }\ + else\ + {\ + zlog_warn ("LSA: No slot for type %#x: %s line:%d",\ + ntohs (type), __FILE__, __LINE__);\ + }\ + } +#define CALL_LSA_DATABASE_REMOVE(type,data) \ + if (ospf6)\ + {\ + struct ospf6_lsa_slot *slot;\ + slot = ospf6_lsa_slot_get (type);\ + if (slot)\ + {\ + CALL_REMOVE_HOOK (&slot->database_hook, data);\ + }\ + else\ + {\ + zlog_warn ("LSA: No slot for type %#x: %s line:%d",\ + ntohs (type), __FILE__, __LINE__);\ + }\ + } + +void ospf6_lsa_init (); + +/* Function Prototypes */ + +struct router_lsd * +get_router_lsd (u_int32_t, struct ospf6_lsa *); +unsigned long get_ifindex_to_router (u_int32_t, struct ospf6_lsa *); + +int ospf6_lsa_differ (struct ospf6_lsa *lsa1, struct ospf6_lsa *lsa2); +int ospf6_lsa_match (u_int16_t, u_int32_t, u_int32_t, + struct ospf6_lsa_header *); + +void ospf6_lsa_show (struct vty *, struct ospf6_lsa *); +void ospf6_lsa_show_dump (struct vty *, struct ospf6_lsa *); +void ospf6_lsa_show_summary (struct vty *, struct ospf6_lsa *); +void ospf6_lsa_show_summary_header (struct vty *); + +struct ospf6_lsa * +ospf6_lsa_create (struct ospf6_lsa_header *); +struct ospf6_lsa * +ospf6_lsa_summary_create (struct ospf6_lsa_header__ *); +void +ospf6_lsa_delete (struct ospf6_lsa *); + +void ospf6_lsa_lock (struct ospf6_lsa *); +void ospf6_lsa_unlock (struct ospf6_lsa *); + +unsigned short ospf6_lsa_age_current (struct ospf6_lsa *); +int ospf6_lsa_is_maxage (struct ospf6_lsa *); +void ospf6_lsa_age_update_to_send (struct ospf6_lsa *, u_int32_t); +void ospf6_lsa_premature_aging (struct ospf6_lsa *); + +int ospf6_lsa_check_recent (struct ospf6_lsa *, struct ospf6_lsa *); + +int +ospf6_lsa_lsd_num (struct ospf6_lsa_header *lsa_header); +void * +ospf6_lsa_lsd_get (int index, struct ospf6_lsa_header *lsa_header); +int +ospf6_lsa_lsd_is_refer_ok (int index1, struct ospf6_lsa_header *lsa_header1, + int index2, struct ospf6_lsa_header *lsa_header2); + +int ospf6_lsa_expire (struct thread *); +int ospf6_lsa_refresh (struct thread *); + +u_short ospf6_lsa_checksum (struct ospf6_lsa_header *); + +void ospf6_lsa_update_network (char *ifname); +void ospf6_lsa_update_link (char *ifname); +void ospf6_lsa_update_as_external (u_int32_t ls_id); +void ospf6_lsa_update_intra_prefix_transit (char *ifname); +void ospf6_lsa_update_intra_prefix_stub (u_int32_t area_id); + +u_int16_t ospf6_lsa_get_scope_type (u_int16_t); +int ospf6_lsa_is_known_type (struct ospf6_lsa_header *lsa_header); + +char *ospf6_lsa_type_string (u_int16_t type, char *buf, int bufsize); +char *ospf6_lsa_router_bits_string (u_char router_bits, char *buf, int size); + +u_long +ospf6_lsa_has_elasped (u_int16_t, u_int32_t, u_int32_t, void *); +void +ospf6_lsa_originate (u_int16_t, u_int32_t, u_int32_t, char *, int, void *); + +#endif /* OSPF6_LSA_H */ + diff --git a/ospf6d/ospf6_lsdb.c b/ospf6d/ospf6_lsdb.c new file mode 100644 index 000000000..ad53eb4fd --- /dev/null +++ b/ospf6d/ospf6_lsdb.c @@ -0,0 +1,723 @@ +/* + * Copyright (C) 2002 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <zebra.h> + +#include "memory.h" +#include "log.h" +#include "command.h" +#include "if.h" + +#include "ospf6_dump.h" +#include "ospf6_lsdb.h" + +#include "ospf6_interface.h" +#include "ospf6_area.h" +#include "ospf6_top.h" + +#define OSPF6_LSDB_MATCH_TYPE 0x01 +#define OSPF6_LSDB_MATCH_ID 0x02 +#define OSPF6_LSDB_MATCH_ADV_ROUTER 0x04 +#define OSPF6_LSDB_SHOW_DUMP 0x08 +#define OSPF6_LSDB_SHOW_DETAIL 0x10 + +struct ospf6_lsdb_hook_t hooks[0x2000]; +struct ospf6_lsdb_hook_t *ospf6_lsdb_hook = hooks; + +struct ospf6_lsdb * +ospf6_lsdb_create () +{ + struct ospf6_lsdb *lsdb; + + lsdb = XCALLOC (MTYPE_OSPF6_LSDB, sizeof (struct ospf6_lsdb)); + if (lsdb == NULL) + { + zlog_warn ("Can't malloc lsdb"); + return NULL; + } + memset (lsdb, 0, sizeof (struct ospf6_lsdb)); + + lsdb->table = route_table_init (); + return lsdb; +} + +void +ospf6_lsdb_delete (struct ospf6_lsdb *lsdb) +{ + ospf6_lsdb_remove_all (lsdb); + route_table_finish (lsdb->table); + XFREE (MTYPE_OSPF6_LSDB, lsdb); +} + +static void +ospf6_lsdb_set_key (struct prefix_ipv6 *key, int flag, + u_int16_t type, u_int32_t id, u_int32_t adv_router) +{ + int len = 0; + memset (key, 0, sizeof (struct prefix_ipv6)); + + if (CHECK_FLAG (flag, OSPF6_LSDB_MATCH_TYPE)) + { + len += 2; + if (CHECK_FLAG (flag, OSPF6_LSDB_MATCH_ADV_ROUTER)) + { + len += 4; + if (CHECK_FLAG (flag, OSPF6_LSDB_MATCH_ID)) + len += 4; + } + } + + if (len > 0) + memcpy ((char *)&key->prefix, &type, 2); + if (len > 2) + memcpy ((char *)&key->prefix + 2, &adv_router, 4); + if (len > 6) + memcpy ((char *)&key->prefix + 6, &id, 4); + + key->family = AF_INET6; + key->prefixlen = len * 8; +} + +void +ospf6_lsdb_add (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb) +{ + int flag; + struct prefix_ipv6 key; + struct route_node *rn; + struct ospf6_lsa *old = NULL; + + flag = OSPF6_LSDB_MATCH_TYPE | OSPF6_LSDB_MATCH_ID | + OSPF6_LSDB_MATCH_ADV_ROUTER; + ospf6_lsdb_set_key (&key, flag, lsa->header->type, lsa->header->id, + lsa->header->adv_router); + + rn = route_node_get (lsdb->table, (struct prefix *) &key); + if (rn->info) + old = rn->info; + rn->info = lsa; + ospf6_lsa_lock (lsa); + + if (old) + ospf6_lsa_unlock (old); + else + lsdb->count++; +} + +void +ospf6_lsdb_remove (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb) +{ + int flag; + struct prefix_ipv6 key; + struct route_node *rn; + struct ospf6_lsa *old; + + flag = OSPF6_LSDB_MATCH_TYPE | OSPF6_LSDB_MATCH_ID | + OSPF6_LSDB_MATCH_ADV_ROUTER; + ospf6_lsdb_set_key (&key, flag, lsa->header->type, lsa->header->id, + lsa->header->adv_router); + + rn = route_node_lookup (lsdb->table, (struct prefix *) &key); + if (! rn || ! rn->info) + { + zlog_warn ("LSDB: Can't remove: no such LSA: %s", lsa->str); + return; + } + + old = rn->info; + if (old != lsa) + { + zlog_warn ("LSDB: Can't remove: different instance: %s (%p <-> %p) %s", + lsa->str, lsa, old, old->str); + return; + } + + rn->info = NULL; + ospf6_lsa_unlock (old); + lsdb->count--; +} + +static void +ospf6_lsdb_lookup_node (struct ospf6_lsdb_node *node, + u_int16_t type, u_int32_t id, u_int32_t adv_router, + struct ospf6_lsdb *lsdb) +{ + int flag; + struct route_node *rn; + + memset (node, 0, sizeof (struct ospf6_lsdb_node)); + + flag = OSPF6_LSDB_MATCH_TYPE | OSPF6_LSDB_MATCH_ID | + OSPF6_LSDB_MATCH_ADV_ROUTER; + ospf6_lsdb_set_key (&node->key, flag, type, id, adv_router); + + rn = route_node_lookup (lsdb->table, (struct prefix *) &node->key); + if (! rn || ! rn->info) + return; + + node->node = rn; + node->next = route_next (rn); + node->lsa = rn->info; + if (node->next != NULL) + route_unlock_node (node->next); +} + +struct ospf6_lsa * +ospf6_lsdb_lookup_lsdb (u_int16_t type, u_int32_t id, u_int32_t adv_router, + struct ospf6_lsdb *lsdb) +{ + struct ospf6_lsdb_node node; + ospf6_lsdb_lookup_node (&node, type, id, adv_router, lsdb); + return node.lsa; +} + +/* Iteration function */ +void +ospf6_lsdb_head (struct ospf6_lsdb_node *node, struct ospf6_lsdb *lsdb) +{ + struct route_node *rn; + + memset (node, 0, sizeof (struct ospf6_lsdb_node)); + + rn = route_top (lsdb->table); + if (rn == NULL) + return; + + while (rn && rn->info == NULL) + rn = route_next (rn); + + if (rn && rn->info) + { + node->node = rn; + node->next = route_next (rn); + node->lsa = rn->info; + if (node->next != NULL) + route_unlock_node (node->next); + } +} + +void +ospf6_lsdb_type (struct ospf6_lsdb_node *node, u_int16_t type, + struct ospf6_lsdb *lsdb) +{ + int flag; + struct route_node *rn; + + memset (node, 0, sizeof (struct ospf6_lsdb_node)); + + flag = OSPF6_LSDB_MATCH_TYPE; + ospf6_lsdb_set_key (&node->key, flag, type, 0, 0); + + /* get the closest radix node */ + rn = route_node_get (lsdb->table, (struct prefix *) &node->key); + + /* skip to the real existing lsdb entry */ + while (rn && rn->info == NULL && rn->p.prefixlen >= node->key.prefixlen && + prefix_match ((struct prefix *) &node->key, &rn->p)) + rn = route_next (rn); + + if (rn && rn->info) + { + node->node = rn; + node->next = route_next (rn); + node->lsa = rn->info; + if (node->next != NULL) + route_unlock_node (node->next); + } +} + +void +ospf6_lsdb_type_router (struct ospf6_lsdb_node *node, + u_int16_t type, u_int32_t adv_router, + struct ospf6_lsdb *lsdb) +{ + int flag; + struct route_node *rn; + + memset (node, 0, sizeof (struct ospf6_lsdb_node)); + + flag = OSPF6_LSDB_MATCH_TYPE | OSPF6_LSDB_MATCH_ADV_ROUTER; + ospf6_lsdb_set_key (&node->key, flag, type, 0, adv_router); + + /* get the closest radix node */ + rn = route_node_get (lsdb->table, (struct prefix *) &node->key); + + /* skip to the real existing lsdb entry */ + while (rn && rn->info == NULL && rn->p.prefixlen >= node->key.prefixlen && + prefix_match ((struct prefix *) &node->key, &rn->p)) + rn = route_next (rn); + + if (rn && rn->info) + { + node->node = rn; + node->next = route_next (rn); + node->lsa = rn->info; + if (node->next != NULL) + route_unlock_node (node->next); + } +} + +void +ospf6_lsdb_next (struct ospf6_lsdb_node *node) +{ + struct route_node *rn; + + route_lock_node (node->node); + rn = route_next (node->node); + + /* skip to the real existing lsdb entry */ + while (rn && rn->info == NULL && rn->p.prefixlen >= node->key.prefixlen && + prefix_match ((struct prefix *) &node->key, &rn->p)) + rn = route_next (rn); + + if (rn && rn->info && rn->p.prefixlen >= node->key.prefixlen && + prefix_match ((struct prefix *) &node->key, &rn->p)) + { + node->node = rn; + node->next = route_next (rn); + node->lsa = rn->info; + if (node->next != NULL) + route_unlock_node (node->next); + } + else + { + node->node = NULL; + node->next = NULL; + node->lsa = NULL; + } +} + +struct ospf6_lsa * +ospf6_lsdb_lookup (u_int16_t type, u_int32_t id, u_int32_t adv_router, + void *scope) +{ + struct ospf6_interface *o6i; + struct ospf6_area *o6a; + listnode i, j; + + if (scope == (void *) ospf6) + return ospf6_lsdb_lookup_lsdb (type, id, adv_router, ospf6->lsdb); + + for (i = listhead (ospf6->area_list); i; nextnode (i)) + { + o6a = getdata (i); + + if (scope == (void *) o6a) + return ospf6_lsdb_lookup_lsdb (type, id, adv_router, o6a->lsdb); + + for (j = listhead (o6a->if_list); j; nextnode (j)) + { + o6i = getdata (j); + + if (scope == (void *) o6i) + return ospf6_lsdb_lookup_lsdb (type, id, adv_router, o6i->lsdb); + } + } + + zlog_warn ("LSDB: Can't lookup: unknown scope, type %#hx", ntohs (type)); + return NULL; +} + +void +ospf6_lsdb_install (struct ospf6_lsa *new) +{ + struct ospf6_lsdb *lsdb; + struct ospf6_lsa *old; + int need_hook = 0; + void (*hook) (struct ospf6_lsa *, struct ospf6_lsa *); + + struct ospf6 *as = NULL; + struct ospf6_area *area = NULL; + struct ospf6_interface *linklocal = NULL; + hook = NULL; + + switch (ntohs (new->header->type) & OSPF6_LSTYPE_SCOPE_MASK) + { + case OSPF6_LSA_SCOPE_LINKLOCAL: + linklocal = (struct ospf6_interface *) new->scope; + lsdb = linklocal->lsdb; + break; + case OSPF6_LSA_SCOPE_AREA: + area = (struct ospf6_area *) new->scope; + lsdb = area->lsdb; + break; + case OSPF6_LSA_SCOPE_AS: + as = (struct ospf6 *) new->scope; + lsdb = as->lsdb; + break; + default: + zlog_warn ("LSDB: Can't install: scope unknown: %s", new->str); + return; + } + + /* whether schedule calculation or not */ + old = ospf6_lsdb_lookup_lsdb (new->header->type, new->header->id, + new->header->adv_router, lsdb); + + if (! old || ospf6_lsa_differ (old, new)) + need_hook++; + + /* log */ + if (IS_OSPF6_DUMP_LSDB) + zlog_info ("LSDB: Install: %s %s", new->str, + ((IS_LSA_MAXAGE (new)) ? "(MaxAge)" : "")); + + if (old) + ospf6_lsa_lock (old); + + ospf6_lsdb_add (new, lsdb); + gettimeofday (&new->installed, NULL); + + hook = ospf6_lsdb_hook[ntohs (new->header->type) & + OSPF6_LSTYPE_CODE_MASK].hook; + if (need_hook && hook) + (*hook) (old, new); + + /* old LSA should be freed here */ + if (old) + ospf6_lsa_unlock (old); +} + +void +ospf6_lsdb_remove_all (struct ospf6_lsdb *lsdb) +{ + struct ospf6_lsdb_node node; + for (ospf6_lsdb_head (&node, lsdb); ! ospf6_lsdb_is_end (&node); + ospf6_lsdb_next (&node)) + ospf6_lsdb_remove (node.lsa, lsdb); +} + +void +ospf6_lsdb_remove_maxage (struct ospf6_lsdb *lsdb) +{ + struct ospf6_lsdb_node node; + struct ospf6_lsa *lsa; + + for (ospf6_lsdb_head (&node, lsdb); ! ospf6_lsdb_is_end (&node); + ospf6_lsdb_next (&node)) + { + lsa = node.lsa; + + /* contiue if it's not MaxAge */ + if (! IS_LSA_MAXAGE (lsa)) + continue; + + /* continue if it's referenced by some retrans-lists */ + if (lsa->lock != 1) + continue; + + if (IS_OSPF6_DUMP_LSDB) + zlog_info ("Remove MaxAge LSA: %s", lsa->str); + + ospf6_lsdb_remove (lsa, lsdb); + } +} + + + +/* vty functions */ + +static int +ospf6_lsdb_match (int flag, u_int16_t type, u_int32_t id, + u_int32_t adv_router, struct ospf6_lsa *lsa) +{ + if (CHECK_FLAG (flag, OSPF6_LSDB_MATCH_TYPE) && + lsa->header->type != type) + return 0; + + if (CHECK_FLAG (flag, OSPF6_LSDB_MATCH_ID) && + lsa->header->id != id) + return 0; + + if (CHECK_FLAG (flag, OSPF6_LSDB_MATCH_ADV_ROUTER) && + lsa->header->adv_router != adv_router) + return 0; + + return 1; +} + +int +show_ipv6_ospf6_lsdb (struct vty *vty, int argc, char **argv, + struct ospf6_lsdb *lsdb) +{ + u_int flag; + u_int16_t type = 0; + u_int32_t id, adv_router; + int ret; + struct ospf6_lsdb_node node; + char invalid[32], *invalidp; + int l_argc = argc; + char **l_argv = argv; + + flag = 0; + memset (invalid, 0, sizeof (invalid)); + invalidp = invalid; + + /* chop tail if the words is 'dump' or 'summary' */ + if (l_argc > 0 && ! strcmp (l_argv[l_argc - 1], "dump")) + { + SET_FLAG (flag, OSPF6_LSDB_SHOW_DUMP); + l_argc --; + } + else if (l_argc > 0 && ! strcmp (l_argv[l_argc - 1], "detail")) + { + SET_FLAG (flag, OSPF6_LSDB_SHOW_DETAIL); + l_argc --; + } + + if (l_argc > 0) + { + SET_FLAG (flag, OSPF6_LSDB_MATCH_TYPE); + if (! strncmp (l_argv[0], "r", 1)) + type = htons (OSPF6_LSA_TYPE_ROUTER); + if (! strncmp (l_argv[0], "n", 1)) + type = htons (OSPF6_LSA_TYPE_NETWORK); + if (! strncmp (l_argv[0], "a", 1)) + type = htons (OSPF6_LSA_TYPE_AS_EXTERNAL); + if (! strcmp (l_argv[0], "intra-prefix")) + type = htons (OSPF6_LSA_TYPE_INTRA_PREFIX); + if (! strcmp (l_argv[0], "inter-router")) + type = htons (OSPF6_LSA_TYPE_INTER_ROUTER); + if (! strcmp (l_argv[0], "inter-prefix")) + type = htons (OSPF6_LSA_TYPE_INTER_PREFIX); + if (! strncmp (l_argv[0], "l", 1)) + type = htons (OSPF6_LSA_TYPE_LINK); + if (! strncmp (l_argv[0], "0x", 2) && strlen (l_argv[0]) == 6) + type = htons ((short) strtol (l_argv[0], (char **)NULL, 16)); + if (! strncmp (l_argv[0], "*", 1)) + UNSET_FLAG (flag, OSPF6_LSDB_MATCH_TYPE); + } + + if (l_argc > 1) + { + SET_FLAG (flag, OSPF6_LSDB_MATCH_ID); + if (! strncmp (l_argv[1], "*", 1)) + UNSET_FLAG (flag, OSPF6_LSDB_MATCH_ID); + else + { + ret = inet_pton (AF_INET, l_argv[1], &id); + if (ret != 1) + { + id = htonl (strtoul (l_argv[1], &invalidp, 10)); + if (invalid[0] != '\0') + { + vty_out (vty, "Link State ID is not parsable: %s%s", + l_argv[1], VTY_NEWLINE); + return CMD_SUCCESS; + } + } + } + } + + if (l_argc > 2) + { + SET_FLAG (flag, OSPF6_LSDB_MATCH_ADV_ROUTER); + if (! strncmp (l_argv[2], "*", 1)) + UNSET_FLAG (flag, OSPF6_LSDB_MATCH_ADV_ROUTER); + else + { + ret = inet_pton (AF_INET, l_argv[2], &adv_router); + if (ret != 1) + { + adv_router = htonl (strtoul (l_argv[2], &invalidp, 10)); + if (invalid[0] != '\0') + { + vty_out (vty, "Advertising Router is not parsable: %s%s", + l_argv[2], VTY_NEWLINE); + return CMD_SUCCESS; + } + } + } + } + + if (! CHECK_FLAG (flag, OSPF6_LSDB_SHOW_DETAIL)) + ospf6_lsa_show_summary_header (vty); + + for (ospf6_lsdb_head (&node, lsdb); ! ospf6_lsdb_is_end (&node); + ospf6_lsdb_next (&node)) + { + if (! ospf6_lsdb_match (flag, type, id, adv_router, node.lsa)) + continue; + + if (CHECK_FLAG (flag, OSPF6_LSDB_SHOW_DUMP)) + ospf6_lsa_show_dump (vty, node.lsa); + else if (CHECK_FLAG (flag, OSPF6_LSDB_SHOW_DETAIL)) + ospf6_lsa_show (vty, node.lsa); + else + ospf6_lsa_show_summary (vty, node.lsa); + } + + return CMD_SUCCESS; +} + +DEFUN (show_ipv6_ospf6_database, + show_ipv6_ospf6_database_cmd, + "show ipv6 ospf6 database", + SHOW_STR + IP6_STR + OSPF6_STR + "LSA Database\n" + ) +{ + struct ospf6_area *o6a; + struct ospf6_interface *o6i; + listnode i, j; + + /* call show function for each of LSAs in the LSDBs */ + + for (i = listhead (ospf6->area_list); i; nextnode (i)) + { + o6a = (struct ospf6_area *) getdata (i); + + /* LinkLocal LSDBs */ + for (j = listhead (o6a->if_list); j; nextnode (j)) + { + o6i = (struct ospf6_interface *) getdata (j); + + vty_out (vty, "%s", VTY_NEWLINE); + vty_out (vty, " Interface %s (Area: %s):%s", + o6i->interface->name, o6a->str, VTY_NEWLINE); + vty_out (vty, "%s", VTY_NEWLINE); + show_ipv6_ospf6_lsdb (vty, argc, argv, o6i->lsdb); + } + + /* Area LSDBs */ + vty_out (vty, "%s", VTY_NEWLINE); + vty_out (vty, " Area %s:%s", o6a->str, VTY_NEWLINE); + vty_out (vty, "%s", VTY_NEWLINE); + show_ipv6_ospf6_lsdb (vty, argc, argv, o6a->lsdb); + } + + /* AS LSDBs */ + vty_out (vty, "%s", VTY_NEWLINE); + vty_out (vty, " AS:%s", VTY_NEWLINE); + vty_out (vty, "%s", VTY_NEWLINE); + show_ipv6_ospf6_lsdb (vty, argc, argv, ospf6->lsdb); + + return CMD_SUCCESS; +} + +ALIAS (show_ipv6_ospf6_database, + show_ipv6_ospf6_database_type_cmd, + "show ipv6 ospf6 database (router|network|as-external|intra-prefix|inter-prefix|inter-router|link|*|HEX|dump|detail)", + SHOW_STR + IP6_STR + OSPF6_STR + "LSA Database\n" + "Router-LSA\n" + "Network-LSA\n" + "AS-External-LSA\n" + "Intra-Area-Prefix-LSA\n" + "Inter-Area-Router-LSA\n" + "Inter-Area-Prefix-LSA\n" + "Link-LSA\n" + "All LS Type\n" + "Specify LS Type by Hex\n" + "Dump raw LSA data in Hex\n" + "show detail of LSAs\n" + ) + +ALIAS (show_ipv6_ospf6_database, + show_ipv6_ospf6_database_type_id_cmd, + "show ipv6 ospf6 database (router|network|as-external|intra-prefix|inter-prefix|inter-router|link|*|HEX) (A.B.C.D|*|dump|detail)", + SHOW_STR + IP6_STR + OSPF6_STR + "LSA Database\n" + "Router-LSA\n" + "Network-LSA\n" + "AS-External-LSA\n" + "Intra-Area-Prefix-LSA\n" + "Inter-Area-Router-LSA\n" + "Inter-Area-Prefix-LSA\n" + "Link-LSA\n" + "All LS Type\n" + "Specify LS Type by Hex\n" + "Link State ID\n" + "All Link State ID\n" + "Dump raw LSA data in Hex\n" + "show detail of LSAs\n" + ) + +ALIAS (show_ipv6_ospf6_database, + show_ipv6_ospf6_database_type_id_adv_router_cmd, + "show ipv6 ospf6 database (router|network|as-external|intra-prefix|inter-prefix|inter-router|link|*|HEX) (A.B.C.D|*) (A.B.C.D|*|dump|detail)", + SHOW_STR + IP6_STR + OSPF6_STR + "LSA Database\n" + "Router-LSA\n" + "Network-LSA\n" + "AS-External-LSA\n" + "Intra-Area-Prefix-LSA\n" + "Inter-Area-Router-LSA\n" + "Inter-Area-Prefix-LSA\n" + "Link-LSA\n" + "All LS Type\n" + "Specify LS Type by Hex\n" + "Link State ID\n" + "All Link State ID\n" + "Advertising Router\n" + "All Advertising Router\n" + "Dump raw LSA data in Hex\n" + "show detail of LSAs\n" + ) + +ALIAS (show_ipv6_ospf6_database, + show_ipv6_ospf6_database_type_id_adv_router_dump_cmd, + "show ipv6 ospf6 database (router|network|as-external|intra-prefix|inter-prefix|inter-router|link|*|HEX) (A.B.C.D|*) (A.B.C.D|*) (dump|detail|)", + SHOW_STR + IP6_STR + OSPF6_STR + "LSA Database\n" + "Router-LSA\n" + "Network-LSA\n" + "AS-External-LSA\n" + "Intra-Area-Prefix-LSA\n" + "Inter-Area-Router-LSA\n" + "Inter-Area-Prefix-LSA\n" + "Link-LSA\n" + "All LS Type\n" + "Specify LS Type by Hex\n" + "Link State ID\n" + "All Link State ID\n" + "Advertising Router\n" + "All Advertising Router\n" + "Dump raw LSA data in Hex\n" + "show detail of LSAs\n" + ) + +void +ospf6_lsdb_init () +{ + install_element (VIEW_NODE, &show_ipv6_ospf6_database_cmd); + install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_cmd); + install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_id_cmd); + install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_id_adv_router_cmd); + install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_id_adv_router_dump_cmd); + + install_element (ENABLE_NODE, &show_ipv6_ospf6_database_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_id_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_id_adv_router_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_id_adv_router_dump_cmd); +} + + diff --git a/ospf6d/ospf6_lsdb.h b/ospf6d/ospf6_lsdb.h new file mode 100644 index 000000000..50eedc85f --- /dev/null +++ b/ospf6d/ospf6_lsdb.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2002 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF6_LSDB_H +#define OSPF6_LSDB_H + +#include "prefix.h" +#include "table.h" + +#include "ospf6_prefix.h" +#include "ospf6_lsa.h" + +struct ospf6_lsdb_node +{ + struct prefix_ipv6 key; + + struct route_node *node; + struct route_node *next; + + struct ospf6_lsa *lsa; +}; + +struct ospf6_lsdb +{ + struct route_table *table; + u_int32_t count; + void (*hook) (struct ospf6_lsa *); +}; + +/* int ospf6_lsdb_is_end (struct ospf6_lsdb_node *lsdb_node); */ +#define ospf6_lsdb_is_end(lsdb_node) ((lsdb_node)->node == NULL ? 1 : 0) + +/* global holding hooks for each LS type */ +struct ospf6_lsdb_hook_t +{ + void (*hook) (struct ospf6_lsa *old, struct ospf6_lsa *new); +}; +extern struct ospf6_lsdb_hook_t *ospf6_lsdb_hook; + +/* Function Prototypes */ +struct ospf6_lsdb * ospf6_lsdb_create (); +void ospf6_lsdb_delete (struct ospf6_lsdb *lsdb); + +void ospf6_lsdb_remove_maxage (struct ospf6_lsdb *lsdb); + +struct ospf6_lsa * +ospf6_lsdb_lookup (u_int16_t type, u_int32_t id, u_int32_t adv_router, + void *scope); + +void ospf6_lsdb_install (struct ospf6_lsa *new); + +void ospf6_lsdb_head (struct ospf6_lsdb_node *node, struct ospf6_lsdb *lsdb); +void ospf6_lsdb_type (struct ospf6_lsdb_node *node, u_int16_t type, + struct ospf6_lsdb *lsdb); +void ospf6_lsdb_type_router (struct ospf6_lsdb_node *node, u_int16_t type, + u_int32_t adv_router, struct ospf6_lsdb *lsdb); +void ospf6_lsdb_next (struct ospf6_lsdb_node *node); + +void ospf6_lsdb_add (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb); +void ospf6_lsdb_remove (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb); +void ospf6_lsdb_remove_all (struct ospf6_lsdb *lsdb); + +struct ospf6_lsa * +ospf6_lsdb_lookup_lsdb (u_int16_t type, u_int32_t id, u_int32_t adv_router, + struct ospf6_lsdb *lsdb); + +void ospf6_lsdb_init (); + +#endif /* OSPF6_LSDB_H */ + diff --git a/ospf6d/ospf6_main.c b/ospf6d/ospf6_main.c new file mode 100644 index 000000000..5ab517f36 --- /dev/null +++ b/ospf6d/ospf6_main.c @@ -0,0 +1,326 @@ +/* + * Copyright (C) 1999 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <zebra.h> +#include "getopt.h" +#include "thread.h" +#include "log.h" +#include "version.h" +#include "command.h" +#include "vty.h" +#include "memory.h" + +#include "ospf6d.h" +#include "ospf6_network.h" + +void ospf6_init (); +void ospf6_terminate (); +void nexthop_init (); +int ospf6_receive (struct thread *); + +extern int ospf6_sock; + +/* Default configuration file name for ospf6d. */ +#define OSPF6_DEFAULT_CONFIG "ospf6d.conf" +/* Default port values. */ +#define OSPF6_VTY_PORT 2606 + +/* ospf6d options, we use GNU getopt library. */ +struct option longopts[] = +{ + { "daemon", no_argument, NULL, 'd'}, + { "config_file", required_argument, NULL, 'f'}, + { "pid_file", required_argument, NULL, 'i'}, + { "vty_addr", required_argument, NULL, 'A'}, + { "vty_port", required_argument, NULL, 'P'}, + { "version", no_argument, NULL, 'v'}, + { "help", no_argument, NULL, 'h'}, + { 0 } +}; + +/* Configuration file and directory. */ +char config_current[] = OSPF6_DEFAULT_CONFIG; +char config_default[] = SYSCONFDIR OSPF6_DEFAULT_CONFIG; + +/* ospf6d program name. */ + +/* is daemon? */ +int daemon_mode = 0; + +/* Master of threads. */ +struct thread_master *master; + +/* Process ID saved for use by init system */ +char *pid_file = PATH_OSPF6D_PID; + +/* for reload */ +char _cwd[64]; +char _progpath[64]; +int _argc; +char **_argv; +char **_envp; + +/* Help information display. */ +static void +usage (char *progname, int status) +{ + if (status != 0) + fprintf (stderr, "Try `%s --help' for more information.\n", progname); + else + { + printf ("Usage : %s [OPTION...]\n\n\ +Daemon which manages OSPF version 3.\n\n\ +-d, --daemon Runs in daemon mode\n\ +-f, --config_file Set configuration file name\n\ +-i, --pid_file Set process identifier file name\n\ +-A, --vty_addr Set vty's bind address\n\ +-P, --vty_port Set vty's port number\n\ +-v, --version Print program version\n\ +-h, --help Display this help and exit\n\ +\n\ +Report bugs to yasu@sfc.wide.ad.jp\n", progname); + } + + exit (status); +} + + +void +_reload () +{ + zlog_notice ("OSPF6d (Zebra-%s ospf6d-%s) reloaded", + ZEBRA_VERSION, OSPF6_DAEMON_VERSION); + ospf6_zebra_finish (); + vty_finish (); + execve (_progpath, _argv, _envp); +} + +void +terminate (int i) +{ + ospf6_delete (ospf6); + unlink (PATH_OSPF6D_PID); + zlog_notice ("OSPF6d (Zebra-%s ospf6d-%s) terminated", + ZEBRA_VERSION, OSPF6_DAEMON_VERSION); + exit (i); +} + +/* SIGHUP handler. */ +void +sighup (int sig) +{ + zlog_info ("SIGHUP received"); + _reload (); +} + +/* SIGINT handler. */ +void +sigint (int sig) +{ + zlog_info ("SIGINT received"); + terminate (0); +} + +/* SIGTERM handler. */ +void +sigterm (int sig) +{ + zlog_info ("SIGTERM received"); + terminate (0); +} + +/* SIGUSR1 handler. */ +void +sigusr1 (int sig) +{ + zlog_info ("SIGUSR1 received"); + zlog_rotate (NULL); +} + +/* Signale wrapper. */ +RETSIGTYPE * +signal_set (int signo, void (*func)(int)) +{ + int ret; + struct sigaction sig; + struct sigaction osig; + + sig.sa_handler = func; + sigemptyset (&sig.sa_mask); + sig.sa_flags = 0; +#ifdef SA_RESTART + sig.sa_flags |= SA_RESTART; +#endif /* SA_RESTART */ + + ret = sigaction (signo, &sig, &osig); + + if (ret < 0) + return (SIG_ERR); + else + return (osig.sa_handler); +} + +/* Initialization of signal handles. */ +void +signal_init () +{ + signal_set (SIGHUP, sighup); + signal_set (SIGINT, sigint); + signal_set (SIGTERM, sigterm); + signal_set (SIGPIPE, SIG_IGN); +#ifdef SIGTSTP + signal_set (SIGTSTP, SIG_IGN); +#endif +#ifdef SIGTTIN + signal_set (SIGTTIN, SIG_IGN); +#endif +#ifdef SIGTTOU + signal_set (SIGTTOU, SIG_IGN); +#endif + signal_set (SIGUSR1, sigusr1); +} + +/* Main routine of ospf6d. Treatment of argument and start ospf finite + state machine is handled here. */ +int +main (int argc, char *argv[], char *envp[]) +{ + char *p; + int opt; + char *vty_addr = NULL; + int vty_port = 0; + char *config_file = NULL; + char *progname; + struct thread thread; + int flag; + + /* Set umask before anything for security */ + umask (0027); + + /* Preserve name of myself. */ + progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); + + /* for reload */ + _argc = argc; + _argv = argv; + _envp = envp; + getcwd (_cwd, sizeof (_cwd)); + if (*argv[0] == '.') + snprintf (_progpath, sizeof (_progpath), "%s/%s", _cwd, _argv[0]); + else + snprintf (_progpath, sizeof (_progpath), "%s", argv[0]); + + /* Command line argument treatment. */ + while (1) + { + opt = getopt_long (argc, argv, "df:hp:A:P:v", longopts, 0); + + if (opt == EOF) + break; + + switch (opt) + { + case 0: + break; + case 'd': + daemon_mode = 1; + break; + case 'f': + config_file = optarg; + break; + case 'A': + vty_addr = optarg; + break; + case 'i': + pid_file = optarg; + break; + case 'P': + vty_port = atoi (optarg); + break; + case 'v': + print_version (progname); + exit (0); + break; + case 'h': + usage (progname, 0); + break; + default: + usage (progname, 1); + break; + } + } + + /* thread master */ + master = thread_master_create (); + + /* Initializations. */ + if (! daemon_mode) + flag = ZLOG_STDOUT; + else + flag = 0; + + zlog_default = openzlog (progname, flag, ZLOG_OSPF6, + LOG_CONS|LOG_NDELAY|LOG_PERROR|LOG_PID, + LOG_DAEMON); + signal_init (); + cmd_init (1); + vty_init (); + ospf6_init (); + memory_init (); + sort_node (); + + /* parse config file */ + vty_read_config (config_file, config_current, config_default); + + if (daemon_mode) + daemon (0, 0); + + /* pid file create */ +#if 0 + pid_output_lock (pid_file); +#else + pid_output (pid_file); +#endif + + /* Make ospf protocol socket. */ + ospf6_serv_sock (); + thread_add_read (master, ospf6_receive, NULL, ospf6_sock); + + /* Make ospf vty socket. */ + vty_serv_sock (vty_addr, + vty_port ? vty_port : OSPF6_VTY_PORT, OSPF6_VTYSH_PATH); + + /* Print start message */ + zlog_notice ("OSPF6d (Zebra-%s ospf6d-%s) starts", + ZEBRA_VERSION, OSPF6_DAEMON_VERSION); + + /* Start finite state machine, here we go! */ + while (thread_fetch (master, &thread)) + thread_call (&thread); + + /* Log in case thread failed */ + zlog_warn ("Thread failed"); + terminate (0); + + /* Not reached. */ + exit (0); +} + diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c new file mode 100644 index 000000000..f6577a99c --- /dev/null +++ b/ospf6d/ospf6_message.c @@ -0,0 +1,1972 @@ +/* + * Copyright (C) 1999 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "ospf6d.h" + +int +is_ospf6_message_dump (u_char type) +{ + if (type > OSPF6_MESSAGE_TYPE_LSACK) + type = OSPF6_MESSAGE_TYPE_UNKNOWN; + + switch (type) + { + case OSPF6_MESSAGE_TYPE_UNKNOWN: + return 1; + break; + case OSPF6_MESSAGE_TYPE_HELLO: + if (IS_OSPF6_DUMP_HELLO) + return 1; + break; + case OSPF6_MESSAGE_TYPE_DBDESC: + if (IS_OSPF6_DUMP_DBDESC) + return 1; + break; + case OSPF6_MESSAGE_TYPE_LSREQ: + if (IS_OSPF6_DUMP_LSREQ) + return 1; + break; + case OSPF6_MESSAGE_TYPE_LSUPDATE: + if (IS_OSPF6_DUMP_LSUPDATE) + return 1; + break; + case OSPF6_MESSAGE_TYPE_LSACK: + if (IS_OSPF6_DUMP_LSACK) + return 1; + break; + default: + break; + } + return 0; +} +#define IS_OSPF6_DUMP_MESSAGE(x) (is_ospf6_message_dump(x)) + +char *ospf6_message_type_string[] = +{ + "Unknown", "Hello", "DbDesc", "LSReq", "LSUpdate", "LSAck", NULL +}; + +void +ospf6_message_log_lsa_header (struct ospf6_lsa_header *lsa_header) +{ + char buf_id[16], buf_router[16], typebuf[32]; + + inet_ntop (AF_INET, &lsa_header->advrtr, buf_router, sizeof (buf_router)); + inet_ntop (AF_INET, &lsa_header->ls_id, buf_id, sizeof (buf_id)); + zlog_info (" [%s ID=%s Adv=%s]", + ospf6_lsa_type_string (lsa_header->type, typebuf, + sizeof (typebuf)), + buf_id, buf_router); + zlog_info (" Age=%hu SeqNum=%#lx Cksum=%#hx Len=%hu", + ntohs (lsa_header->age), (u_long)ntohl (lsa_header->seqnum), + ntohs (lsa_header->checksum), ntohs (lsa_header->length)); +} + +static void +ospf6_message_log_unknown (struct iovec *message) +{ + zlog_info ("Message: Unknown"); +} + +static void +ospf6_message_log_hello (struct iovec *message) +{ + struct ospf6_header *ospf6_header; + u_int16_t length_left; + struct ospf6_hello *hello; + char dr_str[16], bdr_str[16]; + char *start, *end, *current; + + /* calculate length */ + ospf6_header = (struct ospf6_header *) message[0].iov_base; + length_left = ntohs (ospf6_header->len) - sizeof (struct ospf6_header); + length_left = (length_left < iov_totallen (message) - sizeof (struct ospf6_header) ? + length_left : iov_totallen (message) - sizeof (struct ospf6_header)); + + hello = (struct ospf6_hello *) message[1].iov_base; + + inet_ntop (AF_INET, &hello->dr, dr_str, sizeof (dr_str)); + inet_ntop (AF_INET, &hello->bdr, bdr_str, sizeof (bdr_str)); + + zlog_info (" IFID:%ld Priority:%d Option:%s", + (u_long)ntohl (hello->interface_id), hello->rtr_pri, "xxx"); + zlog_info (" HelloInterval:%hu Deadinterval:%hu", + ntohs (hello->hello_interval), + ntohs (hello->router_dead_interval)); + zlog_info (" DR:%s BDR:%s", dr_str, bdr_str); + + start = (char *) (hello + 1); + if (start >= (char *) message[1].iov_base + message[1].iov_len) + start = message[2].iov_base; + end = (char *) start + (length_left - sizeof (struct ospf6_hello)); + + for (current = start; current < end; current += sizeof (u_int32_t)) + { + char neighbor[16]; + inet_ntop (AF_INET, current, neighbor, sizeof (neighbor)); + zlog_info (" Neighbor: %s", neighbor); + } +} + +static void +ospf6_message_log_dbdesc (struct iovec *message) +{ + struct ospf6_header *ospf6_header; + u_int16_t length_left; + struct ospf6_dbdesc *dbdesc; + int i; + char buffer[16]; + struct ospf6_lsa_header *lsa_header; + + /* calculate length */ + ospf6_header = (struct ospf6_header *) message[0].iov_base; + length_left = ntohs (ospf6_header->len) - sizeof (struct ospf6_header); + length_left = (length_left < iov_totallen (message) - sizeof (struct ospf6_header) ? + length_left : iov_totallen (message) - sizeof (struct ospf6_header)); + + dbdesc = (struct ospf6_dbdesc *) message[1].iov_base; + ospf6_options_string (dbdesc->options, buffer, sizeof (buffer)); + + zlog_info (" Option:%s IFMTU:%hu", buffer, ntohs (dbdesc->ifmtu)); + zlog_info (" Bits:%s%s%s SeqNum:%#lx", + (DD_IS_IBIT_SET (dbdesc->bits) ? "I" : "-"), + (DD_IS_MBIT_SET (dbdesc->bits) ? "M" : "-"), + (DD_IS_MSBIT_SET (dbdesc->bits) ? "m" : "s"), + (u_long)ntohl (dbdesc->seqnum)); + + for (lsa_header = (struct ospf6_lsa_header *) (dbdesc + 1); + (char *)(lsa_header + 1) <= (char *)(message[1].iov_base + message[1].iov_len) && + (char *)(lsa_header + 1) <= (char *)dbdesc + length_left; + lsa_header++) + ospf6_message_log_lsa_header (lsa_header); + + length_left -= message[1].iov_len; + for (i = 2; message[i].iov_base; i++) + { + for (lsa_header = (struct ospf6_lsa_header *) message[i].iov_base; + (char *)(lsa_header + 1) <= (char *) (message[i].iov_base + + message[i].iov_len) && + (char *)(lsa_header + 1) <= (char *) (message[i].iov_base + length_left); + lsa_header++) + ospf6_message_log_lsa_header (lsa_header); + length_left -= message[i].iov_len; + } +} + +static void +ospf6_message_log_lsreq (struct iovec *message) +{ + struct ospf6_header *ospf6_header; + u_int16_t length_left; + int i; + struct ospf6_lsreq *lsreq; + char buf_router[16], buf_id[16], buf_type[16]; + + /* calculate length */ + ospf6_header = (struct ospf6_header *) message[0].iov_base; + length_left = ntohs (ospf6_header->len) - sizeof (struct ospf6_header); + length_left = (length_left < iov_totallen (message) - sizeof (struct ospf6_header) ? + length_left : iov_totallen (message) - sizeof (struct ospf6_header)); + + for (i = 1; message[i].iov_base; i++) + { + for (lsreq = (struct ospf6_lsreq *) message[i].iov_base; + (char *)(lsreq + 1) <= (char *) (message[i].iov_base + message[i].iov_len) && + (char *)(lsreq + 1) <= (char *) (message[i].iov_base + length_left); + lsreq++) + { + inet_ntop (AF_INET, &lsreq->adv_router, buf_router, sizeof (buf_router)); + inet_ntop (AF_INET, &lsreq->id, buf_id, sizeof (buf_id)); + zlog_info (" [%s ID=%s Adv=%s]", + ospf6_lsa_type_string (lsreq->type, buf_type, + sizeof (buf_type)), + buf_id, buf_router); + } + length_left -= message[i].iov_len; + } +} + +static void +ospf6_message_log_lsupdate (struct iovec *message) +{ + struct ospf6_header *ospf6_header; + u_int16_t length_left; + int i, lsanum; + struct ospf6_lsupdate *lsupdate; + struct ospf6_lsa_header *lsa_header; + + /* calculate length */ + ospf6_header = (struct ospf6_header *) message[0].iov_base; + length_left = ntohs (ospf6_header->len) - sizeof (struct ospf6_header); + length_left = (length_left < iov_totallen (message) - sizeof (struct ospf6_header) ? + length_left : iov_totallen (message) - sizeof (struct ospf6_header)); + + lsupdate = (struct ospf6_lsupdate *) message[1].iov_base; + lsanum = ntohl (lsupdate->lsupdate_num); + + zlog_info (" Number of LSA: #%d", lsanum); + + for (lsa_header = (struct ospf6_lsa_header *) (lsupdate + 1); + (char *)lsa_header < (char *)(message[1].iov_base + message[1].iov_len) && + (char *)lsa_header < (char *)(message[1].iov_base + length_left); + lsa_header = OSPF6_LSA_NEXT (lsa_header)) + ospf6_message_log_lsa_header (lsa_header); + length_left -= message[1].iov_len; + + for (i = 2; message[i].iov_base; i++) + { + + for (lsa_header = (struct ospf6_lsa_header *) message[i].iov_base; + (char *)lsa_header < (char *) (message[i].iov_base + message[i].iov_len) && + (char *)lsa_header < (char *) (message[i].iov_base + length_left); + lsa_header = OSPF6_LSA_NEXT (lsa_header)) + ospf6_message_log_lsa_header (lsa_header); + length_left -= message[i].iov_len; + } +} + +static void +ospf6_message_log_lsack (struct iovec *message) +{ + struct ospf6_header *ospf6_header; + u_int16_t length_left; + struct ospf6_lsa_header *lsa_header; + int i; + + /* calculate length */ + ospf6_header = (struct ospf6_header *) message[0].iov_base; + length_left = ntohs (ospf6_header->len) - sizeof (struct ospf6_header); + length_left = (length_left < iov_totallen (message) - sizeof (struct ospf6_header) ? + length_left : iov_totallen (message) - sizeof (struct ospf6_header)); + + for (i = 1; message[i].iov_base; i++) + { + for (lsa_header = (struct ospf6_lsa_header *) message[i].iov_base; + (char *)(lsa_header + 1) <= (char *) (message[i].iov_base + + message[i].iov_len) && + (char *)(lsa_header + 1) <= (char *) (message[i].iov_base + length_left); + lsa_header++) + ospf6_message_log_lsa_header (lsa_header); + length_left -= message[i].iov_len; + } +} + +struct { + void (*message_log) (struct iovec *); +} ospf6_message_log_body [] = +{ + {ospf6_message_log_unknown}, + {ospf6_message_log_hello}, + {ospf6_message_log_dbdesc}, + {ospf6_message_log_lsreq}, + {ospf6_message_log_lsupdate}, + {ospf6_message_log_lsack}, +}; + +static void +ospf6_message_log (struct iovec *message) +{ + struct ospf6_header *o6h; + char router_id[16], area_id[16]; + u_char type; + + assert (message[0].iov_len == sizeof (struct ospf6_header)); + o6h = (struct ospf6_header *) message[0].iov_base; + + inet_ntop (AF_INET, &o6h->router_id, router_id, sizeof (router_id)); + inet_ntop (AF_INET, &o6h->area_id, area_id, sizeof (area_id)); + + zlog_info (" OSPFv%d Type:%d Len:%hu RouterID:%s", + o6h->version, o6h->type, ntohs (o6h->len), router_id); + zlog_info (" AreaID:%s Cksum:%hx InstanceID:%d", + area_id, ntohs (o6h->cksum), o6h->instance_id); + + type = (OSPF6_MESSAGE_TYPE_UNKNOWN < o6h->type && + o6h->type <= OSPF6_MESSAGE_TYPE_LSACK ? + o6h->type : OSPF6_MESSAGE_TYPE_UNKNOWN); + (* ospf6_message_log_body[type].message_log) (&message[0]); +} + +int +ospf6_opt_is_mismatch (unsigned char opt, char *options1, char *options2) +{ + return (OSPF6_OPT_ISSET (options1, opt) ^ OSPF6_OPT_ISSET (options2, opt)); +} + + +void +ospf6_process_unknown (struct iovec *message, + struct in6_addr *src, + struct in6_addr *dst, + struct ospf6_interface *o6i, + u_int32_t router_id) +{ + zlog_warn ("unknown message type, drop"); +} + +void +ospf6_process_hello (struct iovec *message, + struct in6_addr *src, + struct in6_addr *dst, + struct ospf6_interface *o6i, + u_int32_t router_id) +{ + struct ospf6_header *ospf6_header; + u_int16_t length; + struct ospf6_hello *hello; + char changes = 0; +#define CHANGE_RTRPRI (1 << 0) +#define CHANGE_DR (1 << 1) +#define CHANGE_BDR (1 << 2) + int twoway = 0, backupseen = 0, nbchange = 0; + u_int32_t *router_id_ptr; + int i, seenrtrnum = 0, router_id_space = 0; + char strbuf[64]; + struct ospf6_neighbor *o6n = NULL; + + /* assert interface */ + assert (o6i); + + /* caluculate length */ + ospf6_header = (struct ospf6_header *) message[0].iov_base; + length = ntohs (ospf6_header->len) - sizeof (struct ospf6_header); + length = (length < message[1].iov_len ? length : message[1].iov_len); + + /* set hello pointer */ + hello = (struct ospf6_hello *) message[1].iov_base; + + /* find neighbor. if cannot be found, create */ + o6n = ospf6_neighbor_lookup (router_id, o6i); + if (!o6n) + { + o6n = ospf6_neighbor_create (router_id, o6i); + o6n->ifid = ntohl (hello->interface_id); + o6n->prevdr = o6n->dr = hello->dr; + o6n->prevbdr = o6n->bdr = hello->bdr; + o6n->priority = hello->rtr_pri; + memcpy (&o6n->hisaddr, src, sizeof (struct in6_addr)); + } + + /* HelloInterval check */ + if (ntohs (hello->hello_interval) != o6i->hello_interval) + { + zlog_warn ("HelloInterval mismatch with %s", o6n->str); + return; + } + + /* RouterDeadInterval check */ + if (ntohs (hello->router_dead_interval) + != o6i->dead_interval) + { + zlog_warn ("RouterDeadInterval mismatch with %s", o6n->str); + return; + } + + /* check options */ + /* Ebit */ + if (ospf6_opt_is_mismatch (OSPF6_OPT_E, hello->options, o6i->area->options)) + { + zlog_warn ("Ebit mismatch with %s", o6n->str); + return; + } + + /* RouterPriority set */ + if (o6n->priority != hello->rtr_pri) + { + o6n->priority = hello->rtr_pri; + if (IS_OSPF6_DUMP_HELLO) + zlog_info ("%s: RouterPriority changed", o6n->str); + changes |= CHANGE_RTRPRI; + } + + /* DR set */ + if (o6n->dr != hello->dr) + { + /* save previous dr, set current */ + o6n->prevdr = o6n->dr; + o6n->dr = hello->dr; + inet_ntop (AF_INET, &o6n->dr, strbuf, sizeof (strbuf)); + if (IS_OSPF6_DUMP_HELLO) + zlog_info ("%s declare %s as DR", o6n->str, strbuf); + changes |= CHANGE_DR; + } + + /* BDR set */ + if (o6n->bdr != hello->bdr) + { + /* save previous bdr, set current */ + o6n->prevbdr = o6n->bdr; + o6n->bdr = hello->bdr; + inet_ntop (AF_INET, &o6n->bdr, strbuf, sizeof (strbuf)); + if (IS_OSPF6_DUMP_HELLO) + zlog_info ("%s declare %s as BDR", o6n->str, strbuf); + changes |= CHANGE_BDR; + } + + /* TwoWay check */ + router_id_space = length - sizeof (struct ospf6_hello); + seenrtrnum = router_id_space / sizeof (u_int32_t); + router_id_ptr = (u_int32_t *) (hello + 1); + for (i = 0; i < seenrtrnum; i++) + { + if (*router_id_ptr == o6i->area->ospf6->router_id) + twoway++; + router_id_ptr++; + } + + /* execute neighbor events */ + thread_execute (master, hello_received, o6n, 0); + if (twoway) + thread_execute (master, twoway_received, o6n, 0); + else + thread_execute (master, oneway_received, o6n, 0); + + /* BackupSeen check */ + if (o6i->state == IFS_WAITING) + { + if (hello->dr == hello->bdr && + hello->dr == o6n->router_id) + zlog_warn ("*** DR Election of %s is illegal", o6n->str); + + if (hello->bdr == o6n->router_id) + backupseen++; + else if (hello->dr == o6n->router_id && hello->bdr == 0) + backupseen++; + } + + /* NeighborChange check */ + if (changes & CHANGE_RTRPRI) + nbchange++; + if (changes & CHANGE_DR) + if (o6n->prevdr == o6n->router_id || o6n->dr == o6n->router_id) + nbchange++; + if (changes & CHANGE_BDR) + if (o6n->prevbdr == o6n->router_id || o6n->bdr == o6n->router_id) + nbchange++; + + /* schedule interface events */ + if (backupseen) + thread_add_event (master, backup_seen, o6i, 0); + if (nbchange) + thread_add_event (master, neighbor_change, o6i, 0); + + return; +} + +int +ospf6_dbdesc_is_master (struct ospf6_neighbor *o6n) +{ + char buf[128]; + + if (o6n->router_id == ospf6->router_id) + { + inet_ntop (AF_INET6, &o6n->hisaddr, buf, sizeof (buf)); + zlog_warn ("Message: Neighbor router-id conflicts: %s: %s", + o6n->str, buf); + return -1; + } + else if (ntohl (o6n->router_id) > ntohl (ospf6->router_id)) + return 0; + return 1; +} + +int +ospf6_dbdesc_is_duplicate (struct ospf6_dbdesc *received, + struct ospf6_dbdesc *last_received) +{ + if (memcmp (received->options, last_received->options, 3) != 0) + return 0; + if (received->ifmtu != last_received->ifmtu) + return 0; + if (received->bits != last_received->bits) + return 0; + if (received->seqnum != last_received->seqnum) + return 0; + return 1; +} + +void +ospf6_process_dbdesc_master (struct iovec *message, struct ospf6_neighbor *o6n) +{ + struct ospf6_header *ospf6_header; + u_int16_t length, lsa_count; + struct ospf6_dbdesc *dbdesc; + struct ospf6_lsa_header *lsa_header; + + /* caluculate length */ + ospf6_header = (struct ospf6_header *) message[0].iov_base; + length = ntohs (ospf6_header->len) - sizeof (struct ospf6_header); + length = (length < message[1].iov_len ? length : message[1].iov_len); + + /* set database description pointer */ + dbdesc = (struct ospf6_dbdesc *) message[1].iov_base; + + switch (o6n->state) + { + case NBS_DOWN: + case NBS_ATTEMPT: + case NBS_TWOWAY: + if (IS_OSPF6_DUMP_DBDESC) + zlog_info ("DbDesc from %s Ignored: state less than Init", + o6n->str); + return; + + case NBS_INIT: + thread_execute (master, twoway_received, o6n, 0); + if (o6n->state != NBS_EXSTART) + { + if (IS_OSPF6_DUMP_DBDESC) + zlog_info ("DbDesc from %s Ignored: state less than ExStart", + o6n->str); + return; + } + /* else fall through to ExStart */ + case NBS_EXSTART: + if (DDBIT_IS_SLAVE (dbdesc->bits) && + !DDBIT_IS_INITIAL (dbdesc->bits) && + ntohl (dbdesc->seqnum) == o6n->dbdesc_seqnum) + { + ospf6_neighbor_dbex_init (o6n); + + if (o6n->thread_rxmt_dbdesc) + thread_cancel (o6n->thread_rxmt_dbdesc); + o6n->thread_rxmt_dbdesc = (struct thread *) NULL; + + thread_add_event (master, negotiation_done, o6n, 0); + } + else + { + if (IS_OSPF6_DUMP_DBDESC) + zlog_info (" negotiation failed with %s", o6n->str); + return; + } + break; + + case NBS_EXCHANGE: + /* duplicate dbdesc dropped by master */ + if (!memcmp (dbdesc, &o6n->last_dd, + sizeof (struct ospf6_dbdesc))) + { + if (IS_OSPF6_DUMP_DBDESC) + zlog_info (" duplicate dbdesc, drop"); + return; + } + + /* check Initialize bit and Master/Slave bit */ + if (DDBIT_IS_INITIAL (dbdesc->bits)) + { + if (IS_OSPF6_DUMP_DBDESC) + zlog_info ("Initialize bit mismatch"); + thread_add_event (master, seqnumber_mismatch, o6n, 0); + return; + } + if (DDBIT_IS_MASTER (dbdesc->bits)) + { + if (IS_OSPF6_DUMP_DBDESC) + zlog_info ("Master/Slave bit mismatch"); + thread_add_event (master, seqnumber_mismatch, o6n, 0); + return; + } + + /* dbdesc option check */ + if (memcmp (dbdesc->options, o6n->last_dd.options, + sizeof (dbdesc->options))) + { + if (IS_OSPF6_DUMP_DBDESC) + zlog_info ("dbdesc option field changed"); + thread_add_event (master, seqnumber_mismatch, o6n, 0); + return; + } + + /* dbdesc sequence number check */ + if (ntohl (dbdesc->seqnum) != o6n->dbdesc_seqnum) + { + if (IS_OSPF6_DUMP_DBDESC) + zlog_warn ("*** dbdesc seqnumber mismatch: %d expected", + o6n->dbdesc_seqnum); + thread_add_event (master, seqnumber_mismatch, o6n, 0); + return; + } + break; + + case NBS_LOADING: + case NBS_FULL: + /* duplicate dbdesc dropped by master */ + if (ospf6_dbdesc_is_duplicate (dbdesc, &o6n->last_dd)) + { + if (IS_OSPF6_DUMP_DBDESC) + zlog_info (" duplicate dbdesc, drop"); + return; + } + else + { + if (IS_OSPF6_DUMP_DBDESC) + zlog_info (" not duplicate dbdesc in state %s", + ospf6_neighbor_state_string[o6n->state]); + thread_add_event (master, seqnumber_mismatch, o6n, 0); + return; + } + break; /* not reached */ + + default: + assert (0); + break; /* not reached */ + } + + /* process LSA headers */ + lsa_count = 0; + for (lsa_header = (struct ospf6_lsa_header *) (dbdesc + 1); + (char *)(lsa_header + 1) <= (char *)dbdesc + length; + lsa_header++) + { + if (ospf6_dbex_check_dbdesc_lsa_header (lsa_header, o6n) < 0) + { + thread_add_event (master, seqnumber_mismatch, o6n, 0); + return; + } + lsa_count ++; + } + + /* increment dbdesc seqnum */ + o6n->dbdesc_seqnum++; + + /* cancel transmission/retransmission thread */ + if (o6n->thread_send_dbdesc) + thread_cancel (o6n->thread_send_dbdesc); + o6n->thread_send_dbdesc = (struct thread *) NULL; + if (o6n->thread_rxmt_dbdesc) + thread_cancel (o6n->thread_rxmt_dbdesc); + o6n->thread_rxmt_dbdesc = (struct thread *) NULL; + + /* more bit check */ + if (!DD_IS_MBIT_SET (dbdesc->bits) && !DD_IS_MBIT_SET (o6n->dbdesc_bits)) + thread_add_event (master, exchange_done, o6n, 0); + else + o6n->thread_send_dbdesc = + thread_add_event (master, ospf6_send_dbdesc, o6n, 0); + + /* save last received dbdesc */ + memcpy (&o6n->last_dd, dbdesc, sizeof (struct ospf6_dbdesc)); + + /* statistics */ + o6n->lsa_receive[OSPF6_MESSAGE_TYPE_DBDESC] += lsa_count; + + return; +} + +void +ospf6_process_dbdesc_slave (struct iovec *message, struct ospf6_neighbor *o6n) +{ + struct ospf6_header *ospf6_header; + u_int16_t length, lsa_count; + struct ospf6_dbdesc *dbdesc; + struct ospf6_lsa_header *lsa_header; + + /* caluculate length */ + ospf6_header = (struct ospf6_header *) message[0].iov_base; + length = ntohs (ospf6_header->len) - sizeof (struct ospf6_header); + length = (length < message[1].iov_len ? length : message[1].iov_len); + + /* set database description pointer */ + dbdesc = (struct ospf6_dbdesc *) message[1].iov_base; + + switch (o6n->state) + { + case NBS_DOWN: + case NBS_ATTEMPT: + case NBS_TWOWAY: + return; + case NBS_INIT: + thread_execute (master, twoway_received, o6n, 0); + if (o6n->state != NBS_EXSTART) + { + return; + } + /* else fall through to ExStart */ + case NBS_EXSTART: + if (DD_IS_IBIT_SET (dbdesc->bits) && + DD_IS_MBIT_SET (dbdesc->bits) && + DD_IS_MSBIT_SET (dbdesc->bits)) + { + /* Master/Slave bit set to slave */ + DD_MSBIT_CLEAR (o6n->dbdesc_bits); + /* Initialize bit clear */ + DD_IBIT_CLEAR (o6n->dbdesc_bits); + /* sequence number set to master's */ + o6n->dbdesc_seqnum = ntohl (dbdesc->seqnum); + ospf6_neighbor_dbex_init (o6n); + + if (o6n->thread_rxmt_dbdesc) + thread_cancel (o6n->thread_rxmt_dbdesc); + o6n->thread_rxmt_dbdesc = (struct thread *) NULL; + + thread_add_event (master, negotiation_done, o6n, 0); + } + else + { + if (IS_OSPF6_DUMP_DBDESC) + zlog_info ("negotiation failed"); + return; + } + break; + + case NBS_EXCHANGE: + /* duplicate dbdesc dropped by master */ + if (!memcmp (dbdesc, &o6n->last_dd, + sizeof (struct ospf6_dbdesc))) + { + if (IS_OSPF6_DUMP_DBDESC) + zlog_info (" duplicate dbdesc, retransmit dbdesc"); + + if (o6n->thread_rxmt_dbdesc) + thread_cancel (o6n->thread_rxmt_dbdesc); + o6n->thread_rxmt_dbdesc = + thread_add_event (master, ospf6_send_dbdesc_rxmt, o6n, 0); + + return; + } + + /* check Initialize bit and Master/Slave bit */ + if (DDBIT_IS_INITIAL (dbdesc->bits)) + { + if (IS_OSPF6_DUMP_DBDESC) + zlog_info ("Initialize bit mismatch"); + thread_add_event (master, seqnumber_mismatch, o6n, 0); + return; + } + if (DDBIT_IS_SLAVE (dbdesc->bits)) + { + if (IS_OSPF6_DUMP_DBDESC) + zlog_info ("Master/Slave bit mismatch"); + thread_add_event (master, seqnumber_mismatch, o6n, 0); + return; + } + + /* dbdesc option check */ + if (memcmp (dbdesc->options, o6n->last_dd.options, + sizeof (dbdesc->options))) + { + if (IS_OSPF6_DUMP_DBDESC) + zlog_info ("dbdesc option field changed"); + thread_add_event (master, seqnumber_mismatch, o6n, 0); + return; + } + + /* dbdesc sequence number check */ + if (ntohl (dbdesc->seqnum) != o6n->dbdesc_seqnum + 1) + { + if (IS_OSPF6_DUMP_DBDESC) + zlog_warn ("*** dbdesc seqnumber mismatch: %d expected", + o6n->dbdesc_seqnum + 1); + thread_add_event (master, seqnumber_mismatch, o6n, 0); + return; + } + break; + + case NBS_LOADING: + case NBS_FULL: + /* duplicate dbdesc cause slave to retransmit */ + if (ospf6_dbdesc_is_duplicate (dbdesc, &o6n->last_dd)) + { + if (IS_OSPF6_DUMP_DBDESC) + zlog_info (" duplicate dbdesc, retransmit"); + + if (o6n->thread_rxmt_dbdesc) + thread_cancel (o6n->thread_rxmt_dbdesc); + o6n->thread_rxmt_dbdesc = + thread_add_event (master, ospf6_send_dbdesc_rxmt, o6n, 0); + + return; + } + else + { + if (IS_OSPF6_DUMP_DBDESC) + zlog_info (" not duplicate dbdesc in state %s", + ospf6_neighbor_state_string[o6n->state]); + thread_add_event (master, seqnumber_mismatch, o6n, 0); + return; + } + break; /* not reached */ + + default: + assert (0); + break; /* not reached */ + } + + /* process LSA headers */ + lsa_count = 0; + for (lsa_header = (struct ospf6_lsa_header *) (dbdesc + 1); + (char *)(lsa_header + 1) <= (char *)dbdesc + length; + lsa_header++) + { + if (ospf6_dbex_check_dbdesc_lsa_header (lsa_header, o6n) < 0) + { + thread_add_event (master, seqnumber_mismatch, o6n, 0); + return; + } + lsa_count ++; + } + + /* set dbdesc seqnum to master's */ + o6n->dbdesc_seqnum = ntohl (dbdesc->seqnum); + + if (o6n->thread_send_dbdesc) + thread_cancel (o6n->thread_send_dbdesc); + o6n->thread_send_dbdesc = + thread_add_event (master, ospf6_send_dbdesc, o6n, 0); + + /* save last received dbdesc */ + memcpy (&o6n->last_dd, dbdesc, sizeof (struct ospf6_dbdesc)); + + /* statistics */ + o6n->lsa_receive[OSPF6_MESSAGE_TYPE_DBDESC] += lsa_count; + + return; +} + +void +ospf6_process_dbdesc (struct iovec *message, + struct in6_addr *src, + struct in6_addr *dst, + struct ospf6_interface *o6i, + u_int32_t router_id) +{ + struct ospf6_header *ospf6_header; + u_int16_t length; + struct ospf6_neighbor *o6n; + struct ospf6_dbdesc *dbdesc; + int Im_master = 0; + + /* assert interface */ + assert (o6i); + + /* caluculate length */ + ospf6_header = (struct ospf6_header *) message[0].iov_base; + length = ntohs (ospf6_header->len) - sizeof (struct ospf6_header); + length = (length < message[1].iov_len ? length : message[1].iov_len); + + /* set database description pointer */ + dbdesc = (struct ospf6_dbdesc *) message[1].iov_base; + + /* find neighbor. if cannot be found, reject this message */ + o6n = ospf6_neighbor_lookup (router_id, o6i); + if (!o6n) + { + if (IS_OSPF6_DUMP_DBDESC) + zlog_info ("neighbor not found, reject"); + return; + } + + if (memcmp (src, &o6n->hisaddr, sizeof (struct in6_addr))) + { + if (IS_OSPF6_DUMP_MESSAGE (ospf6_header->type)) + zlog_info ("From Secondary I/F of the neighbor: ignore"); + return; + } + + /* interface mtu check */ + /* xxx */ + + /* check am I master */ + Im_master = ospf6_dbdesc_is_master (o6n); + if (Im_master < 0) + { + return; /* can't decide which is master, return */ + } + + if (Im_master) + ospf6_process_dbdesc_master (message, o6n); + else + ospf6_process_dbdesc_slave (message, o6n); + + return; +} + +void +ospf6_process_lsreq (struct iovec *message, + struct in6_addr *src, + struct in6_addr *dst, + struct ospf6_interface *o6i, + u_int32_t router_id) +{ + struct ospf6_header *ospf6_header; + u_int16_t length; + struct ospf6_neighbor *o6n; + struct ospf6_lsreq *lsreq; + struct iovec response[OSPF6_MESSAGE_IOVEC_SIZE]; + struct ospf6_lsa *lsa; + unsigned long lsanum = 0; + struct ospf6_lsupdate lsupdate; + char buf_id[16], buf_router[16], buf_type[16]; + + /* assert interface */ + assert (o6i); + + /* caluculate length */ + ospf6_header = (struct ospf6_header *) message[0].iov_base; + length = ntohs (ospf6_header->len) - sizeof (struct ospf6_header); + length = (length < message[1].iov_len ? length : message[1].iov_len); + + /* find neighbor. if cannot be found, reject this message */ + o6n = ospf6_neighbor_lookup (router_id, o6i); + if (!o6n) + { + if (IS_OSPF6_DUMP_LSREQ) + zlog_info (" neighbor not found, reject"); + return; + } + + if (memcmp (src, &o6n->hisaddr, sizeof (struct in6_addr))) + { + if (IS_OSPF6_DUMP_MESSAGE (ospf6_header->type)) + zlog_info ("From Secondary I/F of the neighbor: ignore"); + return; + } + + /* In states other than ExChange, Loading, or Full, the packet + should be ignored. */ + if (o6n->state != NBS_EXCHANGE && o6n->state != NBS_LOADING + && o6n->state != NBS_FULL) + { + if (IS_OSPF6_DUMP_LSREQ) + zlog_info (" neighbor state less than Exchange, reject"); + return; + } + + /* Initialize response LSUpdate packet */ + OSPF6_MESSAGE_CLEAR (response); + memset (&lsupdate, 0, sizeof (struct ospf6_lsupdate)); + OSPF6_MESSAGE_ATTACH (response, &lsupdate, sizeof (struct ospf6_lsupdate)); + + /* process each request */ + lsanum = 0; + for (lsreq = (struct ospf6_lsreq *) message[1].iov_base; + (char *)(lsreq + 1) <= (char *)(message[1].iov_base + length); + lsreq++) + { + inet_ntop (AF_INET, &lsreq->adv_router, buf_router, sizeof (buf_router)); + inet_ntop (AF_INET, &lsreq->id, buf_id, sizeof (buf_id)); + + /* find instance of database copy */ + lsa = ospf6_lsdb_lookup (lsreq->type, lsreq->id, lsreq->adv_router, + ospf6_lsa_get_scope (lsreq->type, o6i)); + + if (!lsa) + { + if (IS_OSPF6_DUMP_LSREQ) + zlog_info ("BadLSReq: %s requests [%s ID=%s Adv=%s] not found", + o6n->str, ospf6_lsa_type_string (lsreq->type, buf_type, + sizeof (buf_type)), + buf_id, buf_router); + thread_add_event (master, bad_lsreq, o6n, 0); + return; + } + + /* I/F MTU check */ + if (sizeof (struct ospf6_header) + sizeof (struct ospf6_lsupdate) + + iov_totallen (response) + ntohs (lsa->header->length) + > o6i->ifmtu) + break; + + OSPF6_MESSAGE_ATTACH (response, lsa->header, ntohs (lsa->header->length)); + lsanum++; + } + + /* send response LSUpdate to this request */ + if (lsanum) + { + lsupdate.lsupdate_num = htonl (lsanum); + + ospf6_message_send (OSPF6_MESSAGE_TYPE_LSUPDATE, response, + &o6n->hisaddr, o6i->if_id); + } + + /* statistics */ + o6n->lsa_receive[OSPF6_MESSAGE_TYPE_LSREQ] + += length / sizeof (struct ospf6_lsreq); +} + +void +ospf6_process_lsupdate (struct iovec *message, + struct in6_addr *src, + struct in6_addr *dst, + struct ospf6_interface *o6i, + u_int32_t router_id) +{ + struct ospf6_header *ospf6_header; + u_int16_t length; + struct ospf6_lsupdate *lsupdate; + struct ospf6_neighbor *o6n; + unsigned long lsanum; + struct ospf6_lsa_header *lsa_header; + + /* assert interface */ + assert (o6i); + + /* caluculate length */ + ospf6_header = (struct ospf6_header *) message[0].iov_base; + length = ntohs (ospf6_header->len) - sizeof (struct ospf6_header); + length = (length < message[1].iov_len ? length : message[1].iov_len); + + /* find neighbor. if cannot be found, reject this message */ + o6n = ospf6_neighbor_lookup (router_id, o6i); + if (! o6n) + { + if (IS_OSPF6_DUMP_LSUPDATE) + zlog_info (" neighbor not found, reject"); + return; + } + + if (memcmp (src, &o6n->hisaddr, sizeof (struct in6_addr))) + { + if (IS_OSPF6_DUMP_MESSAGE (ospf6_header->type)) + zlog_info ("From Secondary I/F of the neighbor: ignore"); + return; + } + + /* if neighbor state less than ExChange, reject this message */ + if (o6n->state < NBS_EXCHANGE) + { + if (IS_OSPF6_DUMP_LSUPDATE) + zlog_info (" neighbor state less than Exchange, reject"); + return; + } + + /* set linkstate update pointer */ + lsupdate = (struct ospf6_lsupdate *) message[1].iov_base; + + /* save linkstate update info */ + lsanum = ntohl (lsupdate->lsupdate_num); + + /* statistics */ + o6n->ospf6_stat_received_lsa += lsanum; + o6n->ospf6_stat_received_lsupdate++; + + /* RFC2328 Section 10.9: When the neighbor responds to these requests + with the proper Link State Update packet(s), the Link state request + list is truncated and a new Link State Request packet is sent. */ + + /* process LSAs */ + for (lsa_header = (struct ospf6_lsa_header *) (lsupdate + 1); + lsanum && (char *)lsa_header < (char *)lsupdate + length; + lsanum--) + { + ospf6_dbex_receive_lsa (lsa_header, o6n); + lsa_header = OSPF6_LSA_NEXT (lsa_header); + } + + /* send new Link State Request packet if this LS Update packet + can be recognized as a response to our previous LS request */ + if (! IN6_IS_ADDR_MULTICAST(dst) && + (o6n->state == NBS_EXCHANGE || o6n->state == NBS_LOADING)) + thread_add_event (master, ospf6_send_lsreq, o6n, 0); + + return; +} + +void +ospf6_process_lsack (struct iovec *message, + struct in6_addr *src, + struct in6_addr *dst, + struct ospf6_interface *o6i, + u_int32_t router_id) +{ + struct ospf6_header *ospf6_header; + u_int16_t length; + struct ospf6_neighbor *o6n; + struct ospf6_lsa_header *lsa_header; + struct ospf6_lsa *lsa, *copy, *rem; + + /* assert interface */ + assert (o6i); + + /* caluculate length */ + ospf6_header = (struct ospf6_header *) message[0].iov_base; + length = ntohs (ospf6_header->len) - sizeof (struct ospf6_header); + length = (length < message[1].iov_len ? length : message[1].iov_len); + + /* find neighbor. if cannot be found, reject this message */ + o6n = ospf6_neighbor_lookup (router_id, o6i); + if (!o6n) + { + if (IS_OSPF6_DUMP_LSACK) + zlog_info ("LSACK: neighbor not found, reject"); + return; + } + + if (memcmp (src, &o6n->hisaddr, sizeof (struct in6_addr))) + { + if (IS_OSPF6_DUMP_LSACK) + zlog_info ("LSACK: From Secondary I/F of the neighbor: ignore"); + return; + } + + /* if neighbor state less than ExChange, reject this message */ + if (o6n->state < NBS_EXCHANGE) + { + if (IS_OSPF6_DUMP_LSACK) + zlog_info ("LSACK: neighbor state less than Exchange, reject"); + return; + } + + /* process each LSA header */ + for (lsa_header = (struct ospf6_lsa_header *) message[1].iov_base; + (char *)(lsa_header + 1) <= (char *)(message[1].iov_base + length); + lsa_header++) + { + /* find database copy */ + copy = ospf6_lsdb_lookup (lsa_header->type, lsa_header->ls_id, + lsa_header->advrtr, + ospf6_lsa_get_scope (lsa_header->type, o6i)); + + /* if no database copy */ + if (!copy) + { + if (IS_OSPF6_DUMP_LSACK) + zlog_info ("LSACK: no database copy, ignore"); + continue; + } + + /* if not on his retrans list */ + rem = ospf6_lsdb_lookup_lsdb (copy->header->type, copy->header->id, + copy->header->adv_router, + o6n->retrans_list); + if (rem == NULL) + { + if (IS_OSPF6_DUMP_LSACK) + zlog_info ("LSACK: not on %s's retranslist, ignore", o6n->str); + continue; + } + + /* create temporary LSA from Ack message */ + lsa = ospf6_lsa_summary_create ((struct ospf6_lsa_header__ *) lsa_header); + + /* if the same instance, remove from retrans list. + else, log and ignore */ + if (ospf6_lsa_check_recent (lsa, copy) == 0) + ospf6_neighbor_retrans_remove (rem, o6n); + else + { + /* Log the questionable acknowledgement, + and examine the next one. */ + zlog_info ("LSACK: questionable acknowledge: %s", copy->str); + zlog_info ("LSACK: received: seq: %#x age: %hu", + ntohl (lsa->header->seqnum), + ntohs (lsa->header->age)); + zlog_info ("LSACK: instance: seq: %#x age: %hu", + ntohl (copy->header->seqnum), + ospf6_lsa_age_current (copy)); + } + + /* release temporary LSA from Ack message */ + ospf6_lsa_delete (lsa); + } + + ospf6_maxage_remover (); + return; +} + +struct { + void (*process) (struct iovec *, struct in6_addr *, struct in6_addr *, + struct ospf6_interface *, u_int32_t); +} ospf6_message_process_type [] = +{ + {ospf6_process_unknown}, + {ospf6_process_hello}, + {ospf6_process_dbdesc}, + {ospf6_process_lsreq}, + {ospf6_process_lsupdate}, + {ospf6_process_lsack} +}; + +/* process ospf6 protocol header. then, call next process function + for each message type */ +static void +ospf6_message_process (struct iovec *message, + struct in6_addr *src, + struct in6_addr *dst, + struct ospf6_interface *o6i) +{ + struct ospf6_header *ospf6_header = NULL; + u_char type; + u_int32_t router_id; + char srcname[64]; + + assert (o6i); + assert (src); + assert (dst); + + /* set ospf6_hdr pointer to head of buffer */ + ospf6_header = (struct ospf6_header *) message[0].iov_base; + + /* version check */ + if (ospf6_header->version != OSPF6_VERSION) + { + if (IS_OSPF6_DUMP_MESSAGE (ospf6_header->type)) + zlog_info ("version mismatch, drop"); + return; + } + + /* area id check */ + if (ospf6_header->area_id != o6i->area->area_id) + { + if (ospf6_header->area_id == 0) + { + if (IS_OSPF6_DUMP_MESSAGE (ospf6_header->type)) + zlog_info ("virtual link not yet, drop"); + return; + } + + if (IS_OSPF6_DUMP_MESSAGE (ospf6_header->type)) + zlog_info ("area id mismatch, drop"); + return; + } + + /* instance id check */ + if (ospf6_header->instance_id != o6i->instance_id) + { + if (IS_OSPF6_DUMP_MESSAGE (ospf6_header->type)) + zlog_info ("instance id mismatch, drop"); + return; + } + + /* message type check */ + type = (ospf6_header->type >= OSPF6_MESSAGE_TYPE_MAX ? + OSPF6_MESSAGE_TYPE_UNKNOWN : ospf6_header->type); + + /* log */ + if (IS_OSPF6_DUMP_MESSAGE (type)) + { + char srcname[64], dstname[64]; + inet_ntop (AF_INET6, dst, dstname, sizeof (dstname)); + inet_ntop (AF_INET6, src, srcname, sizeof (srcname)); + zlog_info ("Receive %s on %s", + ospf6_message_type_string[type], o6i->interface->name); + zlog_info (" %s -> %s", srcname, dstname); + ospf6_message_log (message); + } + + /* router id check */ + router_id = ospf6_header->router_id; + if (ospf6_header->router_id == o6i->area->ospf6->router_id) + { + inet_ntop (AF_INET6, src, srcname, sizeof (srcname)); + zlog_warn ("*** Router-ID mismatch: from %s on %s", + srcname, o6i->interface->name); + return; + } + + /* octet statistics relies on some asumption: + on ethernet, no IPv6 Extention header, etc */ +#define OSPF6_IP6_HEADER_SIZE 40 +#define OSPF6_ETHER_HEADER_SIZE 14 + o6i->message_stat[type].recv++; + o6i->message_stat[type].recv_octet += ntohs (ospf6_header->len) + + OSPF6_IP6_HEADER_SIZE + OSPF6_ETHER_HEADER_SIZE; + + /* futher process */ + (*ospf6_message_process_type[type].process) (&message[0], src, dst, o6i, router_id); + + return; +} + +int +ospf6_receive (struct thread *thread) +{ + int sockfd; + struct in6_addr src, dst; + unsigned int ifindex; + struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE]; + struct ospf6_header ospf6_header; + char buffer[OSPF6_MESSAGE_RECEIVE_BUFSIZE]; + struct ospf6_interface *o6i; + unsigned char type; + + /* get socket */ + sockfd = THREAD_FD (thread); + + /* add next read thread */ + thread_add_read (master, ospf6_receive, NULL, sockfd); + + /* initialize */ + OSPF6_MESSAGE_CLEAR (message); + memset (&ospf6_header, 0, sizeof (struct ospf6_header)); + + OSPF6_MESSAGE_ATTACH (message, &ospf6_header, sizeof (struct ospf6_header)); + OSPF6_MESSAGE_ATTACH (message, buffer, OSPF6_MESSAGE_RECEIVE_BUFSIZE); + + /* receive message */ + ospf6_recvmsg (&src, &dst, &ifindex, message); + + type = (OSPF6_MESSAGE_TYPE_UNKNOWN < ospf6_header.type && + ospf6_header.type <= OSPF6_MESSAGE_TYPE_LSACK ? + ospf6_header.type : OSPF6_MESSAGE_TYPE_UNKNOWN); + o6i = ospf6_interface_lookup_by_index (ifindex); + if (!o6i || !o6i->area) + { + //zlog_warn ("*** received interface ospf6 disabled"); + return 0; + } + + /* if not passive, process message */ + if (! CHECK_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_PASSIVE)) + ospf6_message_process (message, &src, &dst, o6i); + else if (IS_OSPF6_DUMP_MESSAGE (type)) + zlog_info ("Ignore message on passive interface %s", + o6i->interface->name); + + return 0; +} + + +/* send section */ +int +ospf6_message_length (struct iovec *message) +{ + int i, length = 0; + for (i = 0; i < OSPF6_MESSAGE_IOVEC_SIZE; i++) + { + if (message[i].iov_base == NULL && message[i].iov_len == 0) + break; + length += message[i].iov_len; + } + return length; +} +#define OSPF6_MESSAGE_LENGTH(msg) \ +(ospf6_message_length (msg)) + +void +ospf6_message_send (unsigned char type, struct iovec *msg, + struct in6_addr *dst, u_int ifindex) +{ + struct ospf6_interface *o6i; + struct ospf6_header ospf6_header; + char dst_name[64], src_name[64]; + struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE]; + int msg_len; + + /* ospf6 interface lookup */ + o6i = ospf6_interface_lookup_by_index (ifindex); + assert (o6i); + + msg_len = OSPF6_MESSAGE_LENGTH (msg); + + /* I/F MTU check */ +#if 0 + if (msg_len + sizeof (struct ospf6_header) >= o6i->interface->mtu) +#else + if (msg_len + sizeof (struct ospf6_header) >= o6i->ifmtu) +#endif + { + /* If Interface MTU is 0, save the case + since zebra had been failed to get MTU from Kernel */ + if (o6i->interface->mtu != 0) + { + zlog_warn ("Message: Send failed on %s: exceeds I/F MTU", + o6i->interface->name); + zlog_warn ("Message: while sending %s: Len:%d MTU:%d", + ospf6_message_type_string[type], + msg_len + sizeof (struct ospf6_header), + o6i->ifmtu); + return; + } + else + { + zlog_warn ("Message: I/F MTU check ignored on %s", + o6i->interface->name); + } + } + + /* Initialize */ + OSPF6_MESSAGE_CLEAR (message); + + /* set OSPF header */ + memset (&ospf6_header, 0, sizeof (ospf6_header)); + ospf6_header.version = OSPF6_VERSION; + ospf6_header.type = type; + ospf6_header.len = htons (msg_len + sizeof (struct ospf6_header)); + ospf6_header.router_id = ospf6->router_id; + ospf6_header.area_id = o6i->area->area_id; + /* checksum is calculated by kernel */ + ospf6_header.instance_id = o6i->instance_id; + ospf6_header.reserved = 0; + OSPF6_MESSAGE_ATTACH (message, &ospf6_header, sizeof (struct ospf6_header)); + + /* Attach rest to message */ + OSPF6_MESSAGE_JOIN (message, msg); + + /* statistics */ + if (type >= OSPF6_MESSAGE_TYPE_MAX) + type = OSPF6_MESSAGE_TYPE_UNKNOWN; + o6i->message_stat[type].send++; + o6i->message_stat[type].send_octet += ntohs (ospf6_header.len); + + /* log */ + if (IS_OSPF6_DUMP_MESSAGE (type)) + { + inet_ntop (AF_INET6, dst, dst_name, sizeof (dst_name)); + if (o6i->lladdr) + inet_ntop (AF_INET6, o6i->lladdr, src_name, sizeof (src_name)); + else + memcpy (src_name, "Unknown", sizeof (src_name)); + zlog_info ("Send %s on %s", + ospf6_message_type_string[type], o6i->interface->name); + zlog_info (" %s -> %s", src_name, dst_name); + ospf6_message_log (message); + } + + /* send message */ + ospf6_sendmsg (o6i->lladdr, dst, &ifindex, message); +} + + +int +ospf6_send_hello (struct thread *thread) +{ + listnode n; + struct ospf6_interface *o6i; + struct ospf6_neighbor *o6n; + struct in6_addr dst; + struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE]; + struct ospf6_hello hello; + char router_buffer[1024]; /* xxx */ + u_int router_size; + + /* which ospf6 interface to send */ + o6i = (struct ospf6_interface *) THREAD_ARG (thread); + o6i->thread_send_hello = (struct thread *) NULL; + + /* assure interface is up */ + if (o6i->state <= IFS_DOWN) + { + if (IS_OSPF6_DUMP_HELLO) + zlog_warn ("Send HELLO Failed: Interface not enabled: %s", + o6i->interface->name); + return 0; + } + + /* clear message buffer */ + OSPF6_MESSAGE_CLEAR (message); + + /* set Hello fields */ + hello.interface_id = htonl (o6i->if_id); + hello.rtr_pri = o6i->priority; + memcpy (hello.options, o6i->area->options, sizeof (hello.options)); + hello.hello_interval = htons (o6i->hello_interval); + hello.router_dead_interval = htons (o6i->dead_interval); + hello.dr = o6i->dr; + hello.bdr = o6i->bdr; + OSPF6_MESSAGE_ATTACH (message, &hello, sizeof (struct ospf6_hello)); + + /* set neighbor router id */ + router_size = 0; + for (n = listhead (o6i->neighbor_list); n; nextnode (n)) + { + o6n = (struct ospf6_neighbor *) getdata (n); + + if (o6n->state < NBS_INIT) + continue; + + if (router_size + sizeof (o6n->router_id) > sizeof (router_buffer)) + { + zlog_warn ("Send HELLO: Buffer shortage on %s", + o6i->interface->name); + break; + } + + /* Copy Router-ID to Buffer */ + memcpy (router_buffer + router_size, &o6n->router_id, + sizeof (o6n->router_id)); + router_size += sizeof (o6n->router_id); + } + OSPF6_MESSAGE_ATTACH (message, router_buffer, router_size); + + /* set destionation */ + inet_pton (AF_INET6, ALLSPFROUTERS6, &dst); + + /* send hello */ + ospf6_message_send (OSPF6_MESSAGE_TYPE_HELLO, message, &dst, + o6i->interface->ifindex); + + /* set next timer thread */ + o6i->thread_send_hello = thread_add_timer (master, ospf6_send_hello, + o6i, o6i->hello_interval); + + return 0; +} + +void +ospf6_dbdesc_seqnum_init (struct ospf6_neighbor *o6n) +{ + struct timeval tv; + + if (gettimeofday (&tv, (struct timezone *) NULL) < 0) + tv.tv_sec = 1; + + o6n->dbdesc_seqnum = tv.tv_sec; + + if (IS_OSPF6_DUMP_DBDESC) + zlog_info ("set dbdesc seqnum %d for %s", o6n->dbdesc_seqnum, o6n->str); +} + +int +ospf6_send_dbdesc_rxmt (struct thread *thread) +{ + struct ospf6_lsdb_node node; + struct ospf6_neighbor *o6n; + struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE]; + struct ospf6_lsa *lsa; + struct ospf6_lsa_header *lsa_header; + struct ospf6_dbdesc dbdesc; + + o6n = (struct ospf6_neighbor *) THREAD_ARG (thread); + assert (o6n); + + /* clear thread */ + o6n->thread_rxmt_dbdesc = (struct thread *) NULL; + + /* if state less than ExStart, do nothing */ + if (o6n->state < NBS_EXSTART) + return 0; + + OSPF6_MESSAGE_CLEAR (message); + + /* set dbdesc */ + memcpy (dbdesc.options, o6n->ospf6_interface->area->options, + sizeof (dbdesc.options)); + dbdesc.ifmtu = htons (o6n->ospf6_interface->interface->mtu); + dbdesc.bits = o6n->dbdesc_bits; + dbdesc.seqnum = htonl (o6n->dbdesc_seqnum); + OSPF6_MESSAGE_ATTACH (message, &dbdesc, sizeof (struct ospf6_dbdesc)); + + /* if this is not initial, set LSA summary to dbdesc */ + if (! DD_IS_IBIT_SET (o6n->dbdesc_bits)) + { + for (ospf6_lsdb_head (&node, o6n->dbdesc_list); + ! ospf6_lsdb_is_end (&node); ospf6_lsdb_next (&node)) + { + lsa = node.lsa; + + /* xxx, no MTU check: no support for Dynamic MTU change */ + + /* set age and add InfTransDelay */ + ospf6_lsa_age_update_to_send (lsa, o6n->ospf6_interface->transdelay); + + /* set LSA summary to send buffer */ + lsa_header = (struct ospf6_lsa_header *) lsa->lsa_hdr; + OSPF6_MESSAGE_ATTACH (message, lsa_header, + sizeof (struct ospf6_lsa_header)); + } + } + + /* send dbdesc */ + ospf6_message_send (OSPF6_MESSAGE_TYPE_DBDESC, message, &o6n->hisaddr, + o6n->ospf6_interface->interface->ifindex); + + /* if master, set futher retransmission */ + if (DD_IS_MSBIT_SET (o6n->dbdesc_bits)) + o6n->thread_rxmt_dbdesc = + thread_add_timer (master, ospf6_send_dbdesc_rxmt, + o6n, o6n->ospf6_interface->rxmt_interval); + + /* statistics */ + o6n->ospf6_stat_retrans_dbdesc++; + + return 0; +} + +int +ospf6_send_dbdesc (struct thread *thread) +{ + struct ospf6_neighbor *o6n; + struct ospf6_lsa *lsa; + struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE]; + struct ospf6_dbdesc dbdesc; + struct ospf6_lsdb_node node; + + o6n = (struct ospf6_neighbor *) THREAD_ARG (thread); + assert (o6n); + + /* clear thread */ + o6n->thread_send_dbdesc = (struct thread *) NULL; + if (o6n->thread_rxmt_dbdesc) + thread_cancel (o6n->thread_rxmt_dbdesc); + o6n->thread_rxmt_dbdesc = (struct thread *) NULL; + + /* if state less than ExStart, do nothing */ + if (o6n->state < NBS_EXSTART) + return 0; + + OSPF6_MESSAGE_CLEAR (message); + OSPF6_MESSAGE_ATTACH (message, &dbdesc, sizeof (struct ospf6_dbdesc)); + + /* clear previous LSA summary sent */ + ospf6_lsdb_remove_all (o6n->dbdesc_list); + assert (o6n->dbdesc_list->count == 0); + + /* if this is not initial, set LSA summary to dbdesc */ + if (! DD_IS_IBIT_SET (o6n->dbdesc_bits)) + { + for (ospf6_lsdb_head (&node, o6n->summary_list); + ! ospf6_lsdb_is_end (&node); + ospf6_lsdb_next (&node)) + { + lsa = node.lsa; + + /* MTU check */ + if (OSPF6_MESSAGE_LENGTH (message) + + sizeof (struct ospf6_lsa_header) + + sizeof (struct ospf6_header) + > o6n->ospf6_interface->ifmtu) + break; + + /* debug */ + if (IS_OSPF6_DUMP_DBDESC) + zlog_info ("Include DbDesc: %s", lsa->str); + + /* attach to dbdesclist */ + ospf6_neighbor_dbdesc_add (lsa, o6n); + /* detach from summarylist */ + ospf6_neighbor_summary_remove (lsa, o6n); + + /* set age and add InfTransDelay */ + ospf6_lsa_age_update_to_send (lsa, o6n->ospf6_interface->transdelay); + + /* set LSA summary to send buffer */ + OSPF6_MESSAGE_ATTACH (message, lsa->header, + sizeof (struct ospf6_lsa_header)); + } + + if (o6n->summary_list->count == 0) + { + /* Clear more bit */ + DD_MBIT_CLEAR (o6n->dbdesc_bits); + + /* slave must schedule ExchangeDone on sending, here */ + if (! DD_IS_MSBIT_SET (o6n->dbdesc_bits)) + { + if (! DD_IS_MBIT_SET (o6n->dbdesc_bits) && + ! DD_IS_MBIT_SET (o6n->last_dd.bits)) + thread_add_event (master, exchange_done, o6n, 0); + } + } + } + + /* if this is initial, set seqnum */ + if (DDBIT_IS_INITIAL (o6n->dbdesc_bits)) + ospf6_dbdesc_seqnum_init (o6n); + + /* set dbdesc */ + memcpy (dbdesc.options, o6n->ospf6_interface->area->options, + sizeof (dbdesc.options)); + dbdesc.ifmtu = htons (o6n->ospf6_interface->interface->mtu); + dbdesc.bits = o6n->dbdesc_bits; + dbdesc.seqnum = htonl (o6n->dbdesc_seqnum); + + /* send dbdesc */ + ospf6_message_send (OSPF6_MESSAGE_TYPE_DBDESC, message, &o6n->hisaddr, + o6n->ospf6_interface->interface->ifindex); + + /* if master, set retransmission */ + if (DD_IS_MSBIT_SET (o6n->dbdesc_bits)) + o6n->thread_rxmt_dbdesc = + thread_add_timer (master, ospf6_send_dbdesc_rxmt, + o6n, o6n->ospf6_interface->rxmt_interval); + + /* statistics */ + o6n->lsa_send[OSPF6_MESSAGE_TYPE_DBDESC] += o6n->dbdesc_list->count; + + return 0; +} + +int +ospf6_send_lsreq_rxmt (struct thread *thread) +{ + struct ospf6_neighbor *o6n; + + o6n = (struct ospf6_neighbor *) THREAD_ARG (thread); + assert (o6n); + + o6n->thread_rxmt_lsreq = (struct thread *) NULL; + o6n->thread_send_lsreq = thread_add_event (master, ospf6_send_lsreq, o6n, 0); + return 0; +} + +int +ospf6_send_lsreq (struct thread *thread) +{ + struct ospf6_neighbor *o6n; + struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE]; + struct ospf6_lsreq lsreq[OSPF6_MESSAGE_IOVEC_SIZE]; + struct ospf6_lsa *lsa; + struct ospf6_lsdb_node node; + int i; + + o6n = (struct ospf6_neighbor *) THREAD_ARG (thread); + assert (o6n); + + /* LSReq will be send only in ExStart or Loading */ + if (o6n->state != NBS_EXCHANGE && o6n->state != NBS_LOADING) + return 0; + + /* clear thread */ + o6n->thread_send_lsreq = (struct thread *) NULL; + if (o6n->thread_rxmt_lsreq) + thread_cancel (o6n->thread_rxmt_lsreq); + o6n->thread_rxmt_lsreq = (struct thread *) NULL; + + /* schedule loading_done if request list is empty */ + if (o6n->request_list->count == 0) + { + thread_add_event (master, loading_done, o6n, 0); + return 0; + } + + /* clear message buffer */ + OSPF6_MESSAGE_CLEAR (message); + + i = 0; + for (ospf6_lsdb_head (&node, o6n->request_list); + ! ospf6_lsdb_is_end (&node); ospf6_lsdb_next (&node)) + { + lsa = node.lsa; + + /* Buffer Overflow */ + if (i >= OSPF6_MESSAGE_IOVEC_SIZE) + break; + + /* I/F MTU check */ + if (OSPF6_MESSAGE_LENGTH (message) + + sizeof (struct ospf6_lsreq) + + sizeof (struct ospf6_header) + > o6n->ospf6_interface->ifmtu) + break; + + lsreq[i].mbz = 0; + lsreq[i].type = lsa->header->type; + lsreq[i].id = lsa->header->id; + lsreq[i].adv_router = lsa->header->adv_router; + + OSPF6_MESSAGE_ATTACH (message, &lsreq[i], sizeof (struct ospf6_lsreq)); + i++; + } + + ospf6_message_send (OSPF6_MESSAGE_TYPE_LSREQ, message, &o6n->hisaddr, + o6n->ospf6_interface->interface->ifindex); + + /* set retransmit thread */ + o6n->thread_rxmt_lsreq = + thread_add_timer (master, ospf6_send_lsreq_rxmt, + o6n, o6n->ospf6_interface->rxmt_interval); + + /* statistics */ + o6n->lsa_send[OSPF6_MESSAGE_TYPE_LSREQ] += i; + + return 0; +} + +/* Send LSUpdate directly to the neighbor, from his retransmission list */ +int +ospf6_send_lsupdate_rxmt (struct thread *thread) +{ + struct ospf6_neighbor *o6n; + struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE]; + struct ospf6_lsupdate lsupdate; + struct ospf6_lsa *lsa; + struct ospf6_lsdb_node node; + + o6n = (struct ospf6_neighbor *) THREAD_ARG (thread); + assert (o6n); + + o6n->send_update = (struct thread *) NULL; + + if (o6n->ospf6_interface->state <= IFS_WAITING) + return -1; + + /* clear message buffer */ + OSPF6_MESSAGE_CLEAR (message); + + /* set lsupdate header */ + lsupdate.lsupdate_num = 0; /* set gradually */ + OSPF6_MESSAGE_ATTACH (message, &lsupdate, sizeof (struct ospf6_lsupdate)); + + /* for each LSA listed on retransmission-list */ + for (ospf6_lsdb_head (&node, o6n->retrans_list); + ! ospf6_lsdb_is_end (&node); + ospf6_lsdb_next (&node)) + { + lsa = node.lsa; + + /* I/F MTU check */ + if (OSPF6_MESSAGE_LENGTH (message) + + sizeof (struct ospf6_lsupdate) + + sizeof (struct ospf6_header) + + ntohs (lsa->header->length) + > o6n->ospf6_interface->ifmtu) + break; + + ospf6_lsa_age_update_to_send (lsa, o6n->ospf6_interface->transdelay); + OSPF6_MESSAGE_ATTACH (message, lsa->header, ntohs (lsa->header->length)); + lsupdate.lsupdate_num++; + } + + /* check and correct lsupdate */ + if (lsupdate.lsupdate_num == 0) + return 0; + lsupdate.lsupdate_num = htonl (lsupdate.lsupdate_num); + + if (IS_OSPF6_DUMP_LSUPDATE) + zlog_info ("MESSAGE: retrsnsmit LSUpdate to %s", o6n->str); + + /* statistics */ + o6n->ospf6_stat_retrans_lsupdate++; + + ospf6_message_send (OSPF6_MESSAGE_TYPE_LSUPDATE, message, + &o6n->hisaddr, o6n->ospf6_interface->if_id); + + o6n->send_update = thread_add_timer (master, ospf6_send_lsupdate_rxmt, o6n, + o6n->ospf6_interface->rxmt_interval); + return 0; +} + +/* Send LSUpdate containing one LSA directly to the neighbor. + This is "implied acknowledgement" */ +void +ospf6_send_lsupdate_direct (struct ospf6_lsa *lsa, struct ospf6_neighbor *o6n) +{ + struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE]; + struct ospf6_lsupdate lsupdate; + int lsa_len; + + /* clear message buffer */ + OSPF6_MESSAGE_CLEAR (message); + + /* set lsupdate header */ + lsupdate.lsupdate_num = ntohl (1); + OSPF6_MESSAGE_ATTACH (message, &lsupdate, sizeof (struct ospf6_lsupdate)); + + /* set one LSA */ + lsa_len = ntohs (lsa->lsa_hdr->lsh_len); + ospf6_lsa_age_update_to_send (lsa, o6n->ospf6_interface->transdelay); + OSPF6_MESSAGE_ATTACH (message, lsa->lsa_hdr, lsa_len); + + ospf6_message_send (OSPF6_MESSAGE_TYPE_LSUPDATE, message, &o6n->hisaddr, + o6n->ospf6_interface->if_id); +} + +/* Send LSUpdate containing one LSA by multicast. + On non-broadcast link, send it to each neighbor by unicast. + This is ordinary flooding */ +void +ospf6_send_lsupdate_flood (struct ospf6_lsa *lsa, struct ospf6_interface *o6i) +{ + struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE]; + struct ospf6_lsupdate lsupdate; + struct in6_addr dst; + int lsa_len; + + /* clear message buffer */ + OSPF6_MESSAGE_CLEAR (message); + + /* set lsupdate header */ + lsupdate.lsupdate_num = ntohl (1); + OSPF6_MESSAGE_ATTACH (message, &lsupdate, sizeof (struct ospf6_lsupdate)); + + /* set one LSA */ + lsa_len = ntohs (lsa->lsa_hdr->lsh_len); + ospf6_lsa_age_update_to_send (lsa, o6i->transdelay); + OSPF6_MESSAGE_ATTACH (message, lsa->lsa_hdr, lsa_len); + + if (if_is_broadcast (o6i->interface)) + { + /* set destination */ + if (o6i->state == IFS_DR || o6i->state == IFS_BDR) + inet_pton (AF_INET6, ALLSPFROUTERS6, &dst); + else + inet_pton (AF_INET6, ALLDROUTERS6, &dst); + } + else + { + /* IPv6 relies on link local multicast */ + inet_pton (AF_INET6, ALLSPFROUTERS6, &dst); + } + + ospf6_message_send (OSPF6_MESSAGE_TYPE_LSUPDATE, message, &dst, + o6i->if_id); +} + +int +ospf6_send_lsack_delayed (struct thread *thread) +{ + struct ospf6_interface *o6i; + struct iovec message[MAXIOVLIST]; + struct ospf6_lsa *lsa; + struct ospf6_lsdb_node node; + + o6i = THREAD_ARG (thread); + assert (o6i); + + if (IS_OSPF6_DUMP_LSACK) + zlog_info ("LSACK: Delayed LSAck for %s\n", o6i->interface->name); + + o6i->thread_send_lsack_delayed = (struct thread *) NULL; + + if (o6i->state <= IFS_WAITING) + return 0; + + if (o6i->ack_list->count == 0) + return 0; + + iov_clear (message, MAXIOVLIST); + + for (ospf6_lsdb_head (&node, o6i->ack_list); + ! ospf6_lsdb_is_end (&node); + ospf6_lsdb_next (&node)) + { + lsa = node.lsa; + if (IS_OVER_MTU (message, o6i->ifmtu, sizeof (struct ospf6_lsa_hdr))) + break; + + OSPF6_MESSAGE_ATTACH (message, lsa->header, + sizeof (struct ospf6_lsa_header)); + ospf6_interface_delayed_ack_remove (lsa, o6i); + } + + /* statistics */ + o6i->ospf6_stat_delayed_lsack++; + + switch (o6i->state) + { + case IFS_DR: + case IFS_BDR: + ospf6_message_send (OSPF6_MESSAGE_TYPE_LSACK, message, + &allspfrouters6.sin6_addr, o6i->if_id); + break; + default: + ospf6_message_send (OSPF6_MESSAGE_TYPE_LSACK, message, + &alldrouters6.sin6_addr, o6i->if_id); + break; + } + + iov_clear (message, MAXIOVLIST); + return 0; +} + diff --git a/ospf6d/ospf6_message.h b/ospf6d/ospf6_message.h new file mode 100644 index 000000000..105cb4f0c --- /dev/null +++ b/ospf6d/ospf6_message.h @@ -0,0 +1,202 @@ +/* + * Copyright (C) 1999 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF6_MESSAGE_H +#define OSPF6_MESSAGE_H + +#include "ospf6_prefix.h" +#include "ospf6_lsa.h" + +/* Type */ +#define OSPF6_MESSAGE_TYPE_NONE 0x0 +#define OSPF6_MESSAGE_TYPE_UNKNOWN 0x0 +#define OSPF6_MESSAGE_TYPE_HELLO 0x1 /* Discover/maintain neighbors */ +#define OSPF6_MESSAGE_TYPE_DBDESC 0x2 /* Summarize database contents */ +#define OSPF6_MESSAGE_TYPE_LSREQ 0x3 /* Database download */ +#define OSPF6_MESSAGE_TYPE_LSUPDATE 0x4 /* Database update */ +#define OSPF6_MESSAGE_TYPE_LSACK 0x5 /* Flooding acknowledgment */ +#define OSPF6_MESSAGE_TYPE_MAX 0x6 + +/* OSPFv3 packet header */ +struct ospf6_header +{ + u_char version; + u_char type; + u_int16_t len; + u_int32_t router_id; + u_int32_t area_id; + u_int16_t cksum; + u_char instance_id; + u_char reserved; +}; + +/* Hello */ +#define MAXLISTEDNBR 64 +struct ospf6_hello +{ + u_int32_t interface_id; + u_char rtr_pri; + u_char options[3]; + u_int16_t hello_interval; + u_int16_t router_dead_interval; + u_int32_t dr; + u_int32_t bdr; +}; + +/* Database Description */ +struct ospf6_dbdesc +{ + u_char mbz1; + u_char options[3]; + u_int16_t ifmtu; + u_char mbz2; + u_char bits; + u_int32_t seqnum; + /* Followed by LSAs */ +}; +#define DEFAULT_INTERFACE_MTU 1500 + +#define DD_IS_MSBIT_SET(x) ((x) & (1 << 0)) +#define DD_MSBIT_SET(x) ((x) |= (1 << 0)) +#define DD_MSBIT_CLEAR(x) ((x) &= ~(1 << 0)) +#define DD_IS_MBIT_SET(x) ((x) & (1 << 1)) +#define DD_MBIT_SET(x) ((x) |= (1 << 1)) +#define DD_MBIT_CLEAR(x) ((x) &= ~(1 << 1)) +#define DD_IS_IBIT_SET(x) ((x) & (1 << 2)) +#define DD_IBIT_SET(x) ((x) |= (1 << 2)) +#define DD_IBIT_CLEAR(x) ((x) &= ~(1 << 2)) + +#define DDBIT_IS_MASTER(x) ((x) & (1 << 0)) +#define DDBIT_IS_SLAVE(x) (!((x) & (1 << 0))) +#define DDBIT_SET_MASTER(x) ((x) |= (1 << 0)) +#define DDBIT_SET_SLAVE(x) ((x) |= ~(1 << 0)) +#define DDBIT_IS_MORE(x) ((x) & (1 << 1)) +#define DDBIT_SET_MORE(x) ((x) |= (1 << 1)) +#define DDBIT_CLR_MORE(x) ((x) |= ~(1 << 1)) +#define DDBIT_IS_INITIAL(x) ((x) & (1 << 2)) +#define DDBIT_SET_INITIAL(x) ((x) |= (1 << 2)) +#define DDBIT_CLR_INITIAL(x) ((x) |= ~(1 << 2)) + +#define OSPF6_DBDESC_BIT_MASTER 0x01 +#define OSPF6_DBDESC_BIT_MORE 0x02 +#define OSPF6_DBDESC_BIT_INITIAL 0x04 + +/* Link State Request */ +struct ospf6_lsreq +{ + u_int16_t mbz; /* Must Be Zero */ + u_int16_t type; /* LS type */ + u_int32_t id; /* Link State ID */ + u_int32_t adv_router; /* Advertising Router */ +}; + +/* Link State Update */ +struct ospf6_lsupdate +{ + u_int32_t lsupdate_num; +}; + +/* Link State Acknowledgement */ + /* no need for structure, + it will include only LSA header in the packet body.*/ + +/* definition for ospf6_message.c */ +#define OSPF6_MESSAGE_RECEIVE_BUFSIZE 5120 +#define OSPF6_MESSAGE_IOVEC_END 1024 + +#define IS_OVER_MTU(message,mtu,addsize) \ + (iov_totallen(message)+(addsize) >= \ + (mtu)-sizeof(struct ospf6_header)) + +#define OSPF6_MESSAGE_IOVEC_SIZE 1024 +#define OSPF6_MESSAGE_CLEAR(msg) \ +do { \ + int x; \ + for (x = 0; x < OSPF6_MESSAGE_IOVEC_SIZE; x++) \ + { \ + (msg)[x].iov_base = NULL; \ + (msg)[x].iov_len = 0; \ + } \ +} while (0) + +#define OSPF6_MESSAGE_ATTACH(msg,buf,bufsize) \ +do { \ + int x; \ + for (x = 0; x < OSPF6_MESSAGE_IOVEC_SIZE; x++) \ + if ((msg)[x].iov_base == (void *)NULL && (msg)[x].iov_len == 0) \ + break; \ + if (x < OSPF6_MESSAGE_IOVEC_SIZE - 1) \ + { \ + (msg)[x].iov_base = (void *)(buf); \ + (msg)[x].iov_len = (bufsize); \ + } \ +} while (0) + +#define OSPF6_MESSAGE_JOIN(msg,join) \ +do { \ + int x,y; \ + for (x = 0; x < OSPF6_MESSAGE_IOVEC_SIZE; x++) \ + if ((msg)[x].iov_base == NULL && (msg)[x].iov_len == 0) \ + break; \ + for (y = x; y < OSPF6_MESSAGE_IOVEC_SIZE; y++) \ + { \ + (msg)[y].iov_base = (join)[y - x].iov_base; \ + (msg)[y].iov_len = (join)[y - x].iov_len; \ + } \ +} while (0) + + +/* Statistics */ +struct ospf6_message_stat +{ + u_int32_t send; + u_int32_t send_octet; + u_int32_t recv; + u_int32_t recv_octet; +}; + +/* Type string */ +extern char *ospf6_message_type_string[]; + +/* Function Prototypes */ +int ospf6_receive (struct thread *); + +int ospf6_send_hello (struct thread *); +int ospf6_send_dbdesc_rxmt (struct thread *); +int ospf6_send_dbdesc (struct thread *); +int ospf6_send_lsreq (struct thread *); + +struct ospf6_neighbor; +struct ospf6_interface; +int +ospf6_send_lsupdate_rxmt (struct thread *); +void +ospf6_send_lsupdate_direct (struct ospf6_lsa *, struct ospf6_neighbor *); +void +ospf6_send_lsupdate_flood (struct ospf6_lsa *, struct ospf6_interface *); + +int ospf6_send_lsack_delayed (struct thread *); +int ospf6_send_lsack_direct (struct thread *); + +void ospf6_message_send (u_char, struct iovec *, struct in6_addr *, u_int); + +#endif /* OSPF6_MESSAGE_H */ + diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c new file mode 100644 index 000000000..72735d5d7 --- /dev/null +++ b/ospf6d/ospf6_neighbor.c @@ -0,0 +1,602 @@ +/* + * Copyright (C) 1999 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "ospf6d.h" + +#include <zebra.h> + +#include "log.h" +#include "thread.h" +#include "linklist.h" +#include "vty.h" +#include "command.h" + +#include "ospf6_lsa.h" +#include "ospf6_message.h" +#include "ospf6_neighbor.h" +#include "ospf6_nsm.h" +#include "ospf6_lsa.h" +#include "ospf6_lsdb.h" + +char *ospf6_neighbor_state_string[] = +{ + "None", "Down", "Attempt", "Init", "Twoway", + "ExStart", "ExChange", "Loading", "Full", NULL +}; + +int +ospf6_neighbor_last_dbdesc_release (struct thread *thread) +{ + struct ospf6_neighbor *o6n; + + o6n = (struct ospf6_neighbor *) THREAD_ARG (thread); + assert (o6n); + memset (&o6n->last_dd, 0, sizeof (struct ospf6_dbdesc)); + return 0; +} + + + +void +ospf6_neighbor_thread_cancel_all (struct ospf6_neighbor *o6n) +{ + if (o6n->inactivity_timer) + thread_cancel (o6n->inactivity_timer); + o6n->inactivity_timer = (struct thread *) NULL; + + if (o6n->send_update) + thread_cancel (o6n->send_update); + o6n->send_update = (struct thread *) NULL; + + if (o6n->thread_send_dbdesc) + thread_cancel (o6n->thread_send_dbdesc); + o6n->thread_send_dbdesc = (struct thread *) NULL; + if (o6n->thread_rxmt_dbdesc) + thread_cancel (o6n->thread_rxmt_dbdesc); + o6n->thread_rxmt_dbdesc = (struct thread *) NULL; + + if (o6n->thread_rxmt_lsreq) + thread_cancel (o6n->thread_rxmt_lsreq); + o6n->thread_rxmt_lsreq = (struct thread *) NULL; +} + +void +ospf6_neighbor_lslist_clear (struct ospf6_neighbor *nei) +{ + ospf6_lsdb_remove_all (nei->summary_list); + ospf6_lsdb_remove_all (nei->request_list); + ospf6_lsdb_remove_all (nei->retrans_list); + ospf6_lsdb_remove_all (nei->dbdesc_list); +} + +void +ospf6_neighbor_summary_add (struct ospf6_lsa *lsa, + struct ospf6_neighbor *nei) +{ + struct ospf6_lsa *summary; + + if (IS_OSPF6_DUMP_NEIGHBOR) + { + zlog_info ("Neighbor %s summary-list:", nei->str); + zlog_info (" Add %s", lsa->str); + } + + ospf6_lsa_age_current (lsa); + summary = ospf6_lsa_summary_create (lsa->header); + ospf6_lsdb_add (summary, nei->summary_list); +} + +void +ospf6_neighbor_summary_remove (struct ospf6_lsa *lsa, + struct ospf6_neighbor *nei) +{ + struct ospf6_lsa *summary; + + if (IS_OSPF6_DUMP_NEIGHBOR) + { + zlog_info ("Neighbor %s summary-list:", nei->str); + zlog_info (" Remove %s", lsa->str); + } + + summary = ospf6_lsdb_lookup_lsdb (lsa->header->type, lsa->header->id, + lsa->header->adv_router, nei->summary_list); + ospf6_lsdb_remove (summary, nei->summary_list); +} + +void +ospf6_neighbor_request_add (struct ospf6_lsa *lsa, + struct ospf6_neighbor *nei) +{ + struct ospf6_lsa *summary; + + if (IS_OSPF6_DUMP_NEIGHBOR) + { + zlog_info ("Neighbor %s request-list:", nei->str); + zlog_info (" Add %s", lsa->str); + } + + ospf6_lsa_age_current (lsa); + summary = ospf6_lsa_summary_create (lsa->header); + ospf6_lsdb_add (summary, nei->request_list); +} + +void +ospf6_neighbor_request_remove (struct ospf6_lsa *lsa, + struct ospf6_neighbor *nei) +{ + struct ospf6_lsa *summary; + + if (IS_OSPF6_DUMP_NEIGHBOR) + { + zlog_info ("Neighbor %s request-list:", nei->str); + zlog_info (" Remove %s", lsa->str); + } + + summary = ospf6_lsdb_lookup_lsdb (lsa->header->type, lsa->header->id, + lsa->header->adv_router, nei->request_list); + ospf6_lsdb_remove (summary, nei->request_list); +} + +void +ospf6_neighbor_retrans_add (struct ospf6_lsa *lsa, + struct ospf6_neighbor *nei) +{ + if (IS_OSPF6_DUMP_NEIGHBOR) + { + zlog_info ("Neighbor %s retrans-list:", nei->str); + zlog_info (" Add %s", lsa->str); + } + + ospf6_lsdb_add (lsa, nei->retrans_list); +} + +void +ospf6_neighbor_retrans_remove (struct ospf6_lsa *lsa, + struct ospf6_neighbor *nei) +{ + if (IS_OSPF6_DUMP_NEIGHBOR) + { + zlog_info ("Neighbor %s retrans-list:", nei->str); + zlog_info (" Remove %s", lsa->str); + } + + ospf6_lsdb_remove (lsa, nei->retrans_list); + + if (nei->retrans_list->count == 0) + { + if (nei->send_update) + thread_cancel (nei->send_update); + nei->send_update = NULL; + } +} + +void +ospf6_neighbor_dbdesc_add (struct ospf6_lsa *lsa, + struct ospf6_neighbor *nei) +{ + if (IS_OSPF6_DUMP_NEIGHBOR) + { + zlog_info ("Neighbor %s dbdesc-list:", nei->str); + zlog_info (" Add %s", lsa->str); + } + + ospf6_lsdb_add (lsa, nei->dbdesc_list); +} + +void +ospf6_neighbor_dbdesc_remove (struct ospf6_lsa *lsa, + struct ospf6_neighbor *nei) +{ + if (IS_OSPF6_DUMP_NEIGHBOR) + { + zlog_info ("Neighbor %s dbdesc-list:", nei->str); + zlog_info (" Remove %s", lsa->str); + } + + ospf6_lsdb_remove (lsa, nei->dbdesc_list); +} + + +/* prepare summary-list of his neighbor structure */ +void +ospf6_neighbor_dbex_init (struct ospf6_neighbor *nei) +{ + struct ospf6_lsdb_node node; + + /* clear ls-list */ + ospf6_neighbor_lslist_clear (nei); + + /* AS scope LSAs */ + for (ospf6_lsdb_head (&node, nei->ospf6_interface->area->ospf6->lsdb); + ! ospf6_lsdb_is_end (&node); ospf6_lsdb_next (&node)) + { + if (IS_LSA_MAXAGE (node.lsa)) + ospf6_neighbor_retrans_add (node.lsa, nei); + else + ospf6_neighbor_summary_add (node.lsa, nei); + } + + /* AREA scope LSAs */ + for (ospf6_lsdb_head (&node, nei->ospf6_interface->area->lsdb); + ! ospf6_lsdb_is_end (&node); ospf6_lsdb_next (&node)) + { + if (IS_LSA_MAXAGE (node.lsa)) + ospf6_neighbor_retrans_add (node.lsa, nei); + else + ospf6_neighbor_summary_add (node.lsa, nei); + } + + /* INTERFACE scope LSAs */ + for (ospf6_lsdb_head (&node, nei->ospf6_interface->lsdb); + ! ospf6_lsdb_is_end (&node); ospf6_lsdb_next (&node)) + { + if (IS_LSA_MAXAGE (node.lsa)) + ospf6_neighbor_retrans_add (node.lsa, nei); + else + ospf6_neighbor_summary_add (node.lsa, nei); + } +} + +/* create ospf6_neighbor */ +struct ospf6_neighbor * +ospf6_neighbor_create (u_int32_t router_id, struct ospf6_interface *o6i) +{ + struct ospf6_neighbor *new; + char buf[32]; + + new = (struct ospf6_neighbor *) + XMALLOC (MTYPE_OSPF6_NEIGHBOR, sizeof (struct ospf6_neighbor)); + if (new == NULL) + { + zlog_warn ("neighbor: malloc failed"); + return NULL; + } + + memset (new, 0, sizeof (struct ospf6_neighbor)); + + new->state = OSPF6_NEIGHBOR_STATE_DOWN; + + new->router_id = router_id; + inet_ntop (AF_INET, &router_id, buf, sizeof (buf)); + snprintf (new->str, sizeof (new->str), "%s%%%s", buf, o6i->interface->name); + new->inactivity_timer = (struct thread *) NULL; + + new->summary_list = ospf6_lsdb_create (); + new->request_list = ospf6_lsdb_create (); + new->retrans_list = ospf6_lsdb_create (); + new->dbdesc_list = ospf6_lsdb_create (); + + listnode_add (o6i->neighbor_list, new); + new->ospf6_interface = o6i; + + CALL_ADD_HOOK (&neighbor_hook, new); + + return new; +} + +void +ospf6_neighbor_delete (struct ospf6_neighbor *o6n) +{ + CALL_REMOVE_HOOK (&neighbor_hook, o6n); + + ospf6_neighbor_thread_cancel_all (o6n); + ospf6_neighbor_lslist_clear (o6n); + + list_free (o6n->dbdesc_lsa); + + ospf6_lsdb_delete (o6n->summary_list); + ospf6_lsdb_delete (o6n->request_list); + ospf6_lsdb_delete (o6n->retrans_list); + ospf6_lsdb_delete (o6n->dbdesc_list); + + XFREE (MTYPE_OSPF6_NEIGHBOR, o6n); +} + +struct ospf6_neighbor * +ospf6_neighbor_lookup (u_int32_t router_id, + struct ospf6_interface *o6i) +{ + listnode n; + struct ospf6_neighbor *o6n; + + for (n = listhead (o6i->neighbor_list); n; nextnode (n)) + { + o6n = (struct ospf6_neighbor *) getdata (n); + if (o6n->router_id == router_id) + return o6n; + } + return (struct ospf6_neighbor *) NULL; +} + + +/* vty functions */ +/* show neighbor structure */ +void +ospf6_neighbor_show_summary (struct vty *vty, struct ospf6_neighbor *o6n) +{ + char router_id[16]; + char dr[16], bdr[16]; + char duration[16]; + struct timeval now, res; + +/* + vty_out (vty, "%-15s %6s/%-11s %-15s %-15s %s[%s]%s", + "RouterID", "State", "Duration", "DR", "BDR", "I/F", + "State", VTY_NEWLINE); +*/ + + inet_ntop (AF_INET, &o6n->router_id, router_id, sizeof (router_id)); + inet_ntop (AF_INET, &o6n->dr, dr, sizeof (dr)); + inet_ntop (AF_INET, &o6n->bdr, bdr, sizeof (bdr)); + + gettimeofday (&now, NULL); + ospf6_timeval_sub (&now, &o6n->last_changed, &res); + ospf6_timeval_string_summary (&res, duration, sizeof (duration)); + + vty_out (vty, "%-15s %6s/%-11s %-15s %-15s %s[%s]%s", + router_id, ospf6_neighbor_state_string[o6n->state], + duration, dr, bdr, o6n->ospf6_interface->interface->name, + ospf6_interface_state_string[o6n->ospf6_interface->state], + VTY_NEWLINE); +} + +void +ospf6_neighbor_show (struct vty *vty, struct ospf6_neighbor *o6n) +{ + char hisaddr[64], timestring[32]; + struct timeval now, res; + + inet_ntop (AF_INET6, &o6n->hisaddr, hisaddr, sizeof (hisaddr)); + vty_out (vty, " Neighbor %s, interface address %s%s", + o6n->str, hisaddr, VTY_NEWLINE); + vty_out (vty, " Area %s via interface %s (ifindex %d)%s", + o6n->ospf6_interface->area->str, + o6n->ospf6_interface->interface->name, + o6n->ospf6_interface->interface->ifindex, + VTY_NEWLINE); + vty_out (vty, " Priority: %d, State: %s, %d state changes%s", + o6n->priority, ospf6_neighbor_state_string[o6n->state], + o6n->ospf6_stat_state_changed, VTY_NEWLINE); + + gettimeofday (&now, NULL); + ospf6_timeval_sub (&now, &o6n->last_changed, &res); + ospf6_timeval_string_summary (&res, timestring, sizeof (timestring)); + vty_out (vty, " Last state changed: %s ago%s", timestring, VTY_NEWLINE); +} + +void +ospf6_neighbor_show_detail (struct vty *vty, struct ospf6_neighbor *o6n) +{ + char hisdr[16], hisbdr[16]; + + ospf6_neighbor_show (vty, o6n); + + inet_ntop (AF_INET, &o6n->dr, hisdr, sizeof (hisdr)); + inet_ntop (AF_INET, &o6n->bdr, hisbdr, sizeof (hisbdr)); + + vty_out (vty, " His Ifindex of myside: %d%s", + o6n->ifid, VTY_NEWLINE); + vty_out (vty, " His DR Election: DR %s, BDR %s%s", + hisdr, hisbdr, VTY_NEWLINE); + + vty_out (vty, " Last received DbDesc: opt:%s" + " ifmtu:%hu bit:%s%s%s seqnum:%ld%s", + "xxx", ntohs (o6n->last_dd.ifmtu), + (DD_IS_IBIT_SET (o6n->last_dd.bits) ? "I" : "-"), + (DD_IS_MBIT_SET (o6n->last_dd.bits) ? "M" : "-"), + (DD_IS_MSBIT_SET (o6n->last_dd.bits) ? "m" : "s"), + (u_long)ntohl (o6n->last_dd.seqnum), VTY_NEWLINE); + vty_out (vty, " My DbDesc bit for this neighbor: %s%s%s%s", + (DD_IS_IBIT_SET (o6n->dbdesc_bits) ? "I" : "-"), + (DD_IS_MBIT_SET (o6n->dbdesc_bits) ? "M" : "-"), + (DD_IS_MSBIT_SET (o6n->dbdesc_bits) ? "m" : "s"), + VTY_NEWLINE); + + vty_out (vty, " %-16s %5d times, %-16s %5d times%s", + "SeqnumMismatch", o6n->ospf6_stat_seqnum_mismatch, + "BadLSReq", o6n->ospf6_stat_bad_lsreq, VTY_NEWLINE); + vty_out (vty, " %-16s %5d times, %-16s %5d times%s", + "OnewayReceived", o6n->ospf6_stat_oneway_received, + "InactivityTimer", o6n->ospf6_stat_inactivity_timer, + VTY_NEWLINE); + vty_out (vty, " %-16s %5d times, %-16s %5d times%s", + "DbDescRetrans", o6n->ospf6_stat_retrans_dbdesc, + "LSReqRetrans", o6n->ospf6_stat_retrans_lsreq, + VTY_NEWLINE); + vty_out (vty, " %-16s %5d times%s", + "LSUpdateRetrans", o6n->ospf6_stat_retrans_lsupdate, + VTY_NEWLINE); + vty_out (vty, " %-16s %5d times, %-16s %5d times%s", + "LSAReceived", o6n->ospf6_stat_received_lsa, + "LSUpdateReceived", o6n->ospf6_stat_received_lsupdate, + VTY_NEWLINE); + + vty_out (vty, " %-12s %-12s %-12s%s", + "Message", "DbDesc", "LSReq", VTY_NEWLINE); + vty_out (vty, " %-12s %12d %12d%s", "LSA Send", + o6n->lsa_send[OSPF6_MESSAGE_TYPE_DBDESC], + o6n->lsa_send[OSPF6_MESSAGE_TYPE_LSREQ], VTY_NEWLINE); + vty_out (vty, " %-12s %12d %12d%s", "LSA Receive", + o6n->lsa_receive[OSPF6_MESSAGE_TYPE_DBDESC], + o6n->lsa_receive[OSPF6_MESSAGE_TYPE_LSREQ], VTY_NEWLINE); + vty_out (vty, "%s", VTY_NEWLINE); +} + +void +ospf6_neighbor_timestamp_hello (struct ospf6_neighbor *o6n) +{ + struct timeval now, interval; + gettimeofday (&now, (struct timezone *) NULL); + if (o6n->tv_last_hello_received.tv_sec) + { + ospf6_timeval_sub (&now, &o6n->tv_last_hello_received, &interval); + zlog_info ("Hello Interval %s : %ld msec", + o6n->str, interval.tv_sec * 1000 + interval.tv_usec % 1000); + } + o6n->tv_last_hello_received.tv_sec = now.tv_sec; + o6n->tv_last_hello_received.tv_usec = now.tv_usec; +} + +DEFUN (show_ipv6_ospf6_neighbor_routerid, + show_ipv6_ospf6_neighbor_routerid_cmd, + "show ipv6 ospf6 neighbor A.B.C.D", + SHOW_STR + IP6_STR + OSPF6_STR + "Neighbor list\n" + "OSPF6 neighbor Router ID in IP address format\n" + ) +{ + u_int32_t router_id; + struct ospf6_neighbor *o6n; + struct ospf6_interface *o6i; + struct ospf6_area *o6a; + listnode nodei, nodej, nodek; + + OSPF6_CMD_CHECK_RUNNING (); + + if (argc == 0) + vty_out (vty, "%-15s %6s/%-11s %-15s %-15s %s[%s]%s", + "RouterID", "State", "Duration", "DR", "BDR", "I/F", + "State", VTY_NEWLINE); + else if (inet_pton (AF_INET, argv[0], &router_id) != 1) + { + vty_out (vty, "Malformed Router-ID: %s%s", argv[0], VTY_NEWLINE); + return CMD_SUCCESS; + } + + for (nodei = listhead (ospf6->area_list); nodei; nextnode (nodei)) + { + o6a = getdata (nodei); + for (nodej = listhead (o6a->if_list); nodej; nextnode (nodej)) + { + o6i = getdata (nodej); + for (nodek = listhead (o6i->neighbor_list); nodek; nextnode (nodek)) + { + o6n = getdata (nodek); + if (argc == 0) + ospf6_neighbor_show_summary (vty, o6n); + else if (o6n->router_id == router_id) + ospf6_neighbor_show_detail (vty, o6n); + } + } + } + return CMD_SUCCESS; +} + +ALIAS (show_ipv6_ospf6_neighbor_routerid, + show_ipv6_ospf6_neighbor_cmd, + "show ipv6 ospf6 neighbor", + SHOW_STR + IP6_STR + OSPF6_STR + "Neighbor list\n" + ) + +DEFUN (show_ipv6_ospf6_neighborlist, + show_ipv6_ospf6_neighborlist_cmd, + "show ipv6 ospf6 (summary-list|request-list|retrans-list|dbdesc-list)", + SHOW_STR + IP6_STR + OSPF6_STR + "Link State summary list\n" + "Link State request list\n" + "Link State retransmission list\n" + "Link State Description list (Used to retrans DbDesc)\n" + ) +{ + struct ospf6_area *o6a; + struct ospf6_interface *o6i; + struct ospf6_neighbor *o6n; + listnode i, j, k, l; + struct ospf6_lsa *lsa; + struct ospf6_lsdb *lsdb = NULL; + char type[16], id[16], adv_router[16]; + struct ospf6_lsdb_node node; + u_int16_t age, cksum, len; + u_int32_t seqnum; + + OSPF6_CMD_CHECK_RUNNING (); + i = j = k = l = NULL; + + for (i = listhead (ospf6->area_list); i; nextnode (i)) + { + o6a = (struct ospf6_area *) getdata (i); + for (j = listhead (o6a->if_list); j; nextnode (j)) + { + o6i = (struct ospf6_interface *) getdata (j); + for (k = listhead (o6i->neighbor_list); k; nextnode (k)) + { + o6n = (struct ospf6_neighbor *) getdata (k); + + if (strncmp (argv[0], "sum", 3) == 0) + lsdb = o6n->summary_list; + else if (strncmp (argv[0], "req", 3) == 0) + lsdb = o6n->request_list; + else if (strncmp (argv[0], "ret", 3) == 0) + lsdb = o6n->retrans_list; + else if (strncmp (argv[0], "dbd", 3) == 0) + lsdb = o6n->dbdesc_list; + + vty_out (vty, "neighbor %s on interface %s: %d%s", o6n->str, + o6i->interface->name, lsdb->count, + VTY_NEWLINE); + for (ospf6_lsdb_head (&node, lsdb); ! ospf6_lsdb_is_end (&node); + ospf6_lsdb_next (&node)) + { + lsa = node.lsa; + ospf6_lsa_age_current (lsa); + + ospf6_lsa_type_string (lsa->header->type, type, + sizeof (type)); + inet_ntop (AF_INET, &lsa->header->id, id, sizeof (id)); + inet_ntop (AF_INET, &lsa->header->adv_router, adv_router, + sizeof (adv_router)); + age = ntohs (lsa->header->age); + seqnum = ntohl (lsa->header->seqnum); + cksum = ntohs (lsa->header->checksum); + len = ntohs (lsa->header->length); + + vty_out (vty, " %s-LSA ID=%s Adv=%s%s", + type, id, adv_router, VTY_NEWLINE); + vty_out (vty, " Age: %hu SeqNum: %#x Cksum: %hx Len: %hu%s", + age, seqnum, cksum, len, VTY_NEWLINE); + } + } + } + } + + return CMD_SUCCESS; +} + +void +ospf6_neighbor_init () +{ + install_element (VIEW_NODE, &show_ipv6_ospf6_neighbor_cmd); + install_element (VIEW_NODE, &show_ipv6_ospf6_neighbor_routerid_cmd); + install_element (VIEW_NODE, &show_ipv6_ospf6_neighborlist_cmd); + + install_element (ENABLE_NODE, &show_ipv6_ospf6_neighbor_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_neighbor_routerid_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_neighborlist_cmd); +} + + diff --git a/ospf6d/ospf6_neighbor.h b/ospf6d/ospf6_neighbor.h new file mode 100644 index 000000000..c3821c675 --- /dev/null +++ b/ospf6d/ospf6_neighbor.h @@ -0,0 +1,161 @@ +/* + * Copyright (C) 1999 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF6_NEIGHBOR_H +#define OSPF6_NEIGHBOR_H + +/* Neighbor structure */ +struct ospf6_neighbor +{ + /* Neighbor Router ID String */ + char str[32]; + + /* OSPFv3 Interface this neighbor belongs to */ + struct ospf6_interface *ospf6_interface; + + /* Neighbor state */ + u_char state; + struct timeval last_changed; + + /* Neighbor Router ID */ + u_int32_t router_id; + + /* Router Priority of this neighbor */ + u_char priority; + + u_int32_t ifid; + u_int32_t dr; + u_int32_t bdr; + u_int32_t prevdr; + u_int32_t prevbdr; + + /* Link-LSA's options field */ + char options[3]; + + /* IPaddr of I/F on our side link */ + struct in6_addr hisaddr; + + /* new */ + struct ospf6_lsdb *summary_list; + struct ospf6_lsdb *request_list; + struct ospf6_lsdb *retrans_list; + + /* For Database Exchange */ + u_char dbdesc_bits; + u_int32_t dbdesc_seqnum; + struct ospf6_dbdesc *dbdesc_previous; + + /* last received DD , including OSPF capability of this neighbor */ + struct ospf6_dbdesc last_dd; + + /* LSAs to retransmit to this neighbor */ + list dbdesc_lsa; + + /* placeholder for DbDesc */ + struct iovec dbdesc_last_send[1024]; + + struct thread *inactivity_timer; + + /* DbDesc */ + struct thread *thread_send_dbdesc; + struct thread *thread_rxmt_dbdesc; + list dbdesclist; + struct ospf6_lsdb *dbdesc_list; + + /* LSReq */ + struct thread *thread_send_lsreq; + struct thread *thread_rxmt_lsreq; + + /* LSUpdate */ + struct thread *send_update; + struct thread *thread_send_update; + struct thread *thread_rxmt_update; + + /* statistics */ + u_int message_send[OSPF6_MESSAGE_TYPE_MAX]; + u_int message_receive[OSPF6_MESSAGE_TYPE_MAX]; + u_int lsa_send[OSPF6_MESSAGE_TYPE_MAX]; + u_int lsa_receive[OSPF6_MESSAGE_TYPE_MAX]; + + u_int ospf6_stat_state_changed; + u_int ospf6_stat_seqnum_mismatch; + u_int ospf6_stat_bad_lsreq; + u_int ospf6_stat_oneway_received; + u_int ospf6_stat_inactivity_timer; + u_int ospf6_stat_dr_election; + u_int ospf6_stat_retrans_dbdesc; + u_int ospf6_stat_retrans_lsreq; + u_int ospf6_stat_retrans_lsupdate; + u_int ospf6_stat_received_lsa; + u_int ospf6_stat_received_lsupdate; + + struct timeval tv_last_hello_received; +}; + +extern char *ospf6_neighbor_state_string[]; + + +/* Function Prototypes */ +int +ospf6_neighbor_last_dbdesc_release (struct thread *); + +void +ospf6_neighbor_lslist_clear (struct ospf6_neighbor *); + +void +ospf6_neighbor_summary_add (struct ospf6_lsa *, struct ospf6_neighbor *); +void +ospf6_neighbor_summary_remove (struct ospf6_lsa *, struct ospf6_neighbor *); + +void +ospf6_neighbor_request_add (struct ospf6_lsa *, struct ospf6_neighbor *); +void +ospf6_neighbor_request_remove (struct ospf6_lsa *, struct ospf6_neighbor *); + +void +ospf6_neighbor_retrans_add (struct ospf6_lsa *, struct ospf6_neighbor *); +void +ospf6_neighbor_retrans_remove (struct ospf6_lsa *, struct ospf6_neighbor *); + +void +ospf6_neighbor_dbdesc_add (struct ospf6_lsa *lsa, + struct ospf6_neighbor *nei); +void +ospf6_neighbor_dbdesc_remove (struct ospf6_lsa *lsa, + struct ospf6_neighbor *nei); + +void +ospf6_neighbor_dbex_init (struct ospf6_neighbor *nei); + +void +ospf6_neighbor_thread_cancel_all (struct ospf6_neighbor *); + +struct ospf6_neighbor * +ospf6_neighbor_create (u_int32_t, struct ospf6_interface *); +void +ospf6_neighbor_delete (struct ospf6_neighbor *); +struct ospf6_neighbor * +ospf6_neighbor_lookup (u_int32_t, struct ospf6_interface *); + +void ospf6_neighbor_init (); + +#endif /* OSPF6_NEIGHBOR_H */ + diff --git a/ospf6d/ospf6_network.c b/ospf6d/ospf6_network.c new file mode 100644 index 000000000..041d829b5 --- /dev/null +++ b/ospf6d/ospf6_network.c @@ -0,0 +1,501 @@ +/* + * Copyright (C) 1999 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <zebra.h> +#include "memory.h" +#include "log.h" +#include "sockunion.h" + +#include "ospf6d.h" +#include "ospf6_proto.h" + +extern int errno; +extern struct sockaddr_in6 allspfrouters6; +extern struct sockaddr_in6 alldrouters6; +extern int ospf6_sock; +extern struct thread_master *master; + +/* iovec functions */ +void +iov_clear (struct iovec *iov, size_t iovlen) +{ + int i; + for (i = 0; i < iovlen; i++) + { + iov[i].iov_base = NULL; + iov[i].iov_len = 0; + } +} + +int +iov_count (struct iovec *iov) +{ + int i; + for (i = 0; iov[i].iov_base; i++) + ; + return i; +} + +int +iov_totallen (struct iovec *iov) +{ + int i; + int totallen = 0; + for (i = 0; iov[i].iov_base; i++) + totallen += iov[i].iov_len; + return totallen; +} + +void * +iov_prepend (int mtype, struct iovec *iov, size_t len) +{ + int i, iovlen; + void *base; + + base = (void *) XMALLOC (mtype, len); + if (!base) + { + zlog_warn ("Network: iov_prepend failed"); + return NULL; + } + memset (base, 0, len); + + iovlen = iov_count (iov); + for (i = iovlen; i; i--) + { + iov[i].iov_base = iov[i - 1].iov_base; + iov[i].iov_len = iov[i - 1].iov_len; + } + iov[0].iov_base = (char *)base; + iov[0].iov_len = len; + + return base; +} + +void * +iov_append (int mtype, struct iovec *iov, size_t len) +{ + int i; + void *base; + + base = (void *)XMALLOC (mtype, len); + if (!base) + { + zlog_warn ("Network: iov_append failed"); + return NULL; + } + memset (base, 0, len); + + /* proceed to the end */ + i = iov_count (iov); + + iov[i].iov_base = (char *)base; + iov[i].iov_len = len; + + return base; +} + +void * +iov_attach_last (struct iovec *iov, void *base, size_t len) +{ + int i; + i = iov_count (iov); + iov[i].iov_base = (char *)base; + iov[i].iov_len = len; + return base; +} + +void * +iov_detach_first (struct iovec *iov) +{ + int i, iovlen; + void *base; + size_t len; + + base = iov[0].iov_base; + len = iov[0].iov_len; + iovlen = iov_count (iov); + for (i = 0; i < iovlen; i++) + { + iov[i].iov_base = iov[i + 1].iov_base; + iov[i].iov_len = iov[i + 1].iov_len; + } + return base; +} + +int +iov_free (int mtype, struct iovec *iov, u_int begin, u_int end) +{ + int i; + + for (i = begin; i < end; i++) + { + XFREE (mtype, iov[i].iov_base); + iov[i].iov_base = NULL; + iov[i].iov_len = 0; + } + + return 0; +} + +void +iov_trim_head (int mtype, struct iovec *iov) +{ + void *base; + + base = iov_detach_first (iov); + XFREE (mtype, base); + return; +} + +void +iov_free_all (int mtype, struct iovec *iov) +{ + int i, end = iov_count (iov); + for (i = 0; i < end; i++) + { + XFREE (mtype, iov[i].iov_base); + iov[i].iov_base = NULL; + iov[i].iov_len = 0; + } +} + +void +iov_copy_all (struct iovec *dst, struct iovec *src, size_t size) +{ + int i; + for (i = 0; i < size; i++) + { + dst[i].iov_base = src[i].iov_base; + dst[i].iov_len = src[i].iov_len; + } +} + + +/* Make ospf6d's server socket. */ +int +ospf6_serv_sock () +{ + ospf6_sock = socket (AF_INET6, SOCK_RAW, IPPROTO_OSPFIGP); + if (ospf6_sock < 0) + { + zlog_warn ("Network: can't create OSPF6 socket."); + return -1; + } + sockopt_reuseaddr (ospf6_sock); + + /* setup global sockaddr_in6, allspf6 & alldr6 for later use */ + allspfrouters6.sin6_family = AF_INET6; + alldrouters6.sin6_family = AF_INET6; +#ifdef SIN6_LEN + allspfrouters6.sin6_len = sizeof (struct sockaddr_in6); + alldrouters6.sin6_len = sizeof (struct sockaddr_in6); +#endif /* SIN6_LEN */ + inet_pton (AF_INET6, ALLSPFROUTERS6, &allspfrouters6.sin6_addr); + inet_pton (AF_INET6, ALLDROUTERS6, &alldrouters6.sin6_addr); + + return 0; +} + +/* returns 0 if succeed, else returns -1 */ +int +ospf6_join_allspfrouters (u_int ifindex) +{ + struct ipv6_mreq mreq6; + int retval; + + assert (ifindex); + mreq6.ipv6mr_interface = ifindex; + memcpy (&mreq6.ipv6mr_multiaddr, &allspfrouters6.sin6_addr, + sizeof (struct in6_addr)); + + retval = setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, + &mreq6, sizeof (mreq6)); + + if (retval < 0) + zlog_err ("Network: Join AllSPFRouters on ifindex %d failed: %s", + ifindex, strerror (errno)); +#if 0 + else + zlog_info ("Network: Join AllSPFRouters on ifindex %d", ifindex); +#endif + + return retval; +} + +void +ospf6_leave_allspfrouters (u_int ifindex) +{ + struct ipv6_mreq mreq6; + + assert (ifindex); + mreq6.ipv6mr_interface = ifindex; + memcpy (&mreq6.ipv6mr_multiaddr, &allspfrouters6.sin6_addr, + sizeof (struct in6_addr)); + + if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, + &mreq6, sizeof (mreq6)) < 0) + zlog_warn ("Network: Leave AllSPFRouters on ifindex %d Failed: %s", + ifindex, strerror (errno)); +#if 0 + else + zlog_info ("Network: Leave AllSPFRouters on ifindex %d", ifindex); +#endif +} + +void +ospf6_join_alldrouters (u_int ifindex) +{ + struct ipv6_mreq mreq6; + + assert (ifindex); + mreq6.ipv6mr_interface = ifindex; + memcpy (&mreq6.ipv6mr_multiaddr, &alldrouters6.sin6_addr, + sizeof (struct in6_addr)); + + if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, + &mreq6, sizeof (mreq6)) < 0) + zlog_warn ("Network: Join AllDRouters on ifindex %d Failed: %s", + ifindex, strerror (errno)); +#if 0 + else + zlog_info ("Network: Join AllDRouters on ifindex %d", ifindex); +#endif +} + +void +ospf6_leave_alldrouters (u_int ifindex) +{ + struct ipv6_mreq mreq6; + + assert (ifindex); + mreq6.ipv6mr_interface = ifindex; + memcpy (&mreq6.ipv6mr_multiaddr, &alldrouters6.sin6_addr, + sizeof (struct in6_addr)); + + if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, + &mreq6, sizeof (mreq6)) < 0) + zlog_warn ("Network: Leave AllDRouters on ifindex %d Failed", ifindex); +#if 0 + else + zlog_info ("Network: Leave AllDRouters on ifindex %d", ifindex); +#endif +} + +/* setsockopt ReUseAddr to on */ +void +ospf6_set_reuseaddr () +{ + u_int on = 0; + if (setsockopt (ospf6_sock, SOL_SOCKET, SO_REUSEADDR, &on, + sizeof (u_int)) < 0) + zlog_warn ("Network: set SO_REUSEADDR failed: %s", strerror (errno)); +} + +/* setsockopt MulticastLoop to off */ +void +ospf6_reset_mcastloop () +{ + u_int off = 0; + if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, + &off, sizeof (u_int)) < 0) + zlog_warn ("Network: reset IPV6_MULTICAST_LOOP failed: %s", + strerror (errno)); +} + +void +ospf6_set_pktinfo () +{ + u_int on = 1; +#ifdef IPV6_RECVPKTINFO /*2292bis-01*/ + if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, + &on, sizeof (u_int)) < 0) + zlog_warn ("Network: set IPV6_RECVPKTINFO failed: %s", strerror (errno)); +#else /*RFC2292*/ + if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_PKTINFO, + &on, sizeof (u_int)) < 0) + zlog_warn ("Network: set IPV6_PKTINFO failed: %s", strerror (errno)); +#endif +} + +void +ospf6_set_checksum () +{ + int offset = 12; +#ifndef DISABLE_IPV6_CHECKSUM + if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_CHECKSUM, + &offset, sizeof (offset)) < 0) + zlog_warn ("Network: set IPV6_CHECKSUM failed: %s", strerror (errno)); +#else + zlog_warn ("Network: Don't set IPV6_CHECKSUM"); +#endif /* DISABLE_IPV6_CHECKSUM */ +} + +void +ospf6_sendmsg (struct in6_addr *src, struct in6_addr *dst, + unsigned int *ifindex, struct iovec *message) +{ + int retval; + struct msghdr smsghdr; + struct cmsghdr *scmsgp; + u_char cmsgbuf[CMSG_SPACE(sizeof (struct in6_pktinfo))]; + struct in6_pktinfo *pktinfo; + struct sockaddr_in6 dst_sin6; + + assert (dst); + assert (*ifindex); + + scmsgp = (struct cmsghdr *)cmsgbuf; + pktinfo = (struct in6_pktinfo *)(CMSG_DATA(scmsgp)); + memset (&dst_sin6, 0, sizeof (struct sockaddr_in6)); + + /* source address */ + pktinfo->ipi6_ifindex = *ifindex; + if (src) + memcpy (&pktinfo->ipi6_addr, src, sizeof (struct in6_addr)); + else + memset (&pktinfo->ipi6_addr, 0, sizeof (struct in6_addr)); + + /* destination address */ + dst_sin6.sin6_family = AF_INET6; +#ifdef SIN6_LEN + dst_sin6.sin6_len = sizeof (struct sockaddr_in6); +#endif /*SIN6_LEN*/ + memcpy (&dst_sin6.sin6_addr, dst, sizeof (struct in6_addr)); +#ifdef HAVE_SIN6_SCOPE_ID + dst_sin6.sin6_scope_id = *ifindex; +#endif + + /* send control msg */ + scmsgp->cmsg_level = IPPROTO_IPV6; + scmsgp->cmsg_type = IPV6_PKTINFO; + scmsgp->cmsg_len = CMSG_LEN (sizeof (struct in6_pktinfo)); + /* scmsgp = CMSG_NXTHDR (&smsghdr, scmsgp); */ + + /* send msg hdr */ + smsghdr.msg_iov = message; + smsghdr.msg_iovlen = iov_count (message); + smsghdr.msg_name = (caddr_t) &dst_sin6; + smsghdr.msg_namelen = sizeof (struct sockaddr_in6); + smsghdr.msg_control = (caddr_t) cmsgbuf; + smsghdr.msg_controllen = sizeof (cmsgbuf); + + retval = sendmsg (ospf6_sock, &smsghdr, 0); + if (retval != iov_totallen (message)) + zlog_warn ("Network: sendmsg (ifindex: %d) failed: %s(%d)", + *ifindex, strerror (errno), errno); +} + +void +ospf6_recvmsg (struct in6_addr *src, struct in6_addr *dst, + unsigned int *ifindex, struct iovec *message) +{ + int retval; + struct msghdr rmsghdr; + struct cmsghdr *rcmsgp; + u_char cmsgbuf[CMSG_SPACE(sizeof (struct in6_pktinfo))]; + struct in6_pktinfo *pktinfo; + struct sockaddr_in6 src_sin6; + + rcmsgp = (struct cmsghdr *)cmsgbuf; + pktinfo = (struct in6_pktinfo *)(CMSG_DATA(rcmsgp)); + memset (&src_sin6, 0, sizeof (struct sockaddr_in6)); + + /* receive control msg */ + rcmsgp->cmsg_level = IPPROTO_IPV6; + rcmsgp->cmsg_type = IPV6_PKTINFO; + rcmsgp->cmsg_len = CMSG_LEN (sizeof (struct in6_pktinfo)); + /* rcmsgp = CMSG_NXTHDR (&rmsghdr, rcmsgp); */ + + /* receive msg hdr */ + rmsghdr.msg_iov = message; + rmsghdr.msg_iovlen = iov_count (message); + rmsghdr.msg_name = (caddr_t) &src_sin6; + rmsghdr.msg_namelen = sizeof (struct sockaddr_in6); + rmsghdr.msg_control = (caddr_t) cmsgbuf; + rmsghdr.msg_controllen = sizeof (cmsgbuf); + + retval = recvmsg (ospf6_sock, &rmsghdr, 0); + if (retval < 0) + { + zlog_warn ("Network: recvmsg failed: %s", strerror (errno)); + } + else if (retval == iov_totallen (message)) + { + zlog_warn ("Network: possibly buffer shortage: %d received, buffer size: %d", + retval, iov_totallen (message)); + } + + /* source address */ + assert (src); + memcpy (src, &src_sin6.sin6_addr, sizeof (struct in6_addr)); + + /* destination address */ + if (ifindex) + *ifindex = pktinfo->ipi6_ifindex; + if (dst) + memcpy (dst, &pktinfo->ipi6_addr, sizeof (struct in6_addr)); +} + +void +ospf6_recvmsg_peek (struct in6_addr *src, struct in6_addr *dst, + unsigned int *ifindex, struct iovec *message) +{ + int retval; + struct msghdr rmsghdr; + struct cmsghdr *rcmsgp; + u_char cmsgbuf[CMSG_SPACE(sizeof (struct in6_pktinfo))]; + struct in6_pktinfo *pktinfo; + struct sockaddr_in6 src_sin6; + + rcmsgp = (struct cmsghdr *)cmsgbuf; + pktinfo = (struct in6_pktinfo *)(CMSG_DATA(rcmsgp)); + memset (&src_sin6, 0, sizeof (struct sockaddr_in6)); + + /* receive control msg */ + rcmsgp->cmsg_level = IPPROTO_IPV6; + rcmsgp->cmsg_type = IPV6_PKTINFO; + rcmsgp->cmsg_len = CMSG_LEN (sizeof (struct in6_pktinfo)); + /* rcmsgp = CMSG_NXTHDR (&rmsghdr, rcmsgp); */ + + /* receive msg hdr */ + rmsghdr.msg_iov = message; + rmsghdr.msg_iovlen = iov_count (message); + rmsghdr.msg_name = (caddr_t) &src_sin6; + rmsghdr.msg_namelen = sizeof (struct sockaddr_in6); + rmsghdr.msg_control = (caddr_t) cmsgbuf; + rmsghdr.msg_controllen = sizeof (cmsgbuf); + + retval = recvmsg (ospf6_sock, &rmsghdr, MSG_PEEK); + if (retval != iov_totallen (message)) + zlog_warn ("Network: recvmsg failed: %s", strerror (errno)); + + /* source address */ + assert (src); + memcpy (src, &src_sin6.sin6_addr, sizeof (struct in6_addr)); + + /* destination address */ + if (ifindex) + *ifindex = pktinfo->ipi6_ifindex; + if (dst) + memcpy (dst, &pktinfo->ipi6_addr, sizeof (struct in6_addr)); +} + diff --git a/ospf6d/ospf6_network.h b/ospf6d/ospf6_network.h new file mode 100644 index 000000000..934cce59f --- /dev/null +++ b/ospf6d/ospf6_network.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 1999 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF6_NETWORK_H +#define OSPF6_NETWORK_H + + + +/* Function Prototypes */ +void iov_clear (struct iovec *, size_t); +int iov_count (struct iovec *); +int iov_totallen (struct iovec *); +void *iov_prepend (int, struct iovec *, size_t); +void *iov_append (int, struct iovec *, size_t); +void *iov_attach_last (struct iovec *, void *, size_t); +void *iov_detach_first (struct iovec *); +int iov_free (int, struct iovec *, u_int, u_int); +void iov_trim_head (int, struct iovec *); +void iov_free_all (int, struct iovec *); +void iov_copy_all (struct iovec *, struct iovec *, size_t); + +int ospf6_serv_sock (); +int ospf6_join_allspfrouters (u_int); +void ospf6_leave_allspfrouters (u_int); +void ospf6_join_alldrouters (u_int); +void ospf6_leave_alldrouters (u_int); +void ospf6_set_reuseaddr (); +void ospf6_reset_mcastloop (); +void ospf6_set_pktinfo (); +void ospf6_set_checksum (); + +void ospf6_sendmsg (struct in6_addr *, struct in6_addr *, + unsigned int *, struct iovec *); +void ospf6_recvmsg (struct in6_addr *, struct in6_addr *, + unsigned int *, struct iovec *); +void ospf6_recvmsg_peek (struct in6_addr *, struct in6_addr *, + unsigned int *, struct iovec *); + +#endif /* OSPF6_NETWORK_H */ + diff --git a/ospf6d/ospf6_nsm.c b/ospf6d/ospf6_nsm.c new file mode 100644 index 000000000..aa08d40be --- /dev/null +++ b/ospf6d/ospf6_nsm.c @@ -0,0 +1,391 @@ +/* + * Copyright (C) 1999 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "ospf6d.h" + +static int +nbs_full_change (struct ospf6_interface *ospf6_interface) +{ + CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, ospf6_interface); + return 0; +} + +static int +nbs_change (state_t nbs_next, char *reason, struct ospf6_neighbor *o6n) +{ + state_t nbs_previous; + + nbs_previous = o6n->state; + o6n->state = nbs_next; + + if (nbs_previous == nbs_next) + return 0; + + /* statistics */ + o6n->ospf6_stat_state_changed++; + gettimeofday (&o6n->last_changed, NULL); + + /* log */ + if (IS_OSPF6_DUMP_NEIGHBOR) + { + if (reason) + zlog_info ("Neighbor status change %s: [%s]->[%s](%s)", + o6n->str, + ospf6_neighbor_state_string[nbs_previous], + ospf6_neighbor_state_string[nbs_next], + reason); + else + zlog_info ("Neighbor status change %s: [%s]->[%s]", + o6n->str, + ospf6_neighbor_state_string[nbs_previous], + ospf6_neighbor_state_string[nbs_next]); + } + + if (nbs_previous == NBS_FULL || nbs_next == NBS_FULL) + nbs_full_change (o6n->ospf6_interface); + + /* check for LSAs that already reached MaxAge */ + if ((nbs_previous == NBS_EXCHANGE || nbs_previous == NBS_LOADING) && + (nbs_next != NBS_EXCHANGE && nbs_next != NBS_LOADING)) + { + ospf6_maxage_remover (); + } + + CALL_CHANGE_HOOK (&neighbor_hook, o6n); + + return 0; +} + +/* RFC2328 section 10.4 */ +int +need_adjacency (struct ospf6_neighbor *o6n) +{ + + if (o6n->ospf6_interface->state == IFS_PTOP) + return 1; + if (o6n->ospf6_interface->state == IFS_DR) + return 1; + if (o6n->ospf6_interface->state == IFS_BDR) + return 1; + if (o6n->router_id == o6n->ospf6_interface->dr) + return 1; + if (o6n->router_id == o6n->ospf6_interface->bdr) + return 1; + + return 0; +} + +int +hello_received (struct thread *thread) +{ + struct ospf6_neighbor *o6n; + + o6n = (struct ospf6_neighbor *) THREAD_ARG (thread); + assert (o6n); + + if (IS_OSPF6_DUMP_NEIGHBOR) + zlog_info ("Neighbor Event %s: *HelloReceived*", o6n->str); + + if (o6n->inactivity_timer) + thread_cancel (o6n->inactivity_timer); + + o6n->inactivity_timer = thread_add_timer (master, inactivity_timer, o6n, + o6n->ospf6_interface->dead_interval); + if (o6n->state <= NBS_DOWN) + nbs_change (NBS_INIT, "HelloReceived", o6n); + return 0; +} + +int +twoway_received (struct thread *thread) +{ + struct ospf6_neighbor *o6n; + + o6n = (struct ospf6_neighbor *) THREAD_ARG (thread); + assert (o6n); + + if (o6n->state > NBS_INIT) + return 0; + + if (IS_OSPF6_DUMP_NEIGHBOR) + zlog_info ("Neighbor Event %s: *2Way-Received*", o6n->str); + + thread_add_event (master, neighbor_change, o6n->ospf6_interface, 0); + + if (!need_adjacency (o6n)) + { + nbs_change (NBS_TWOWAY, "No Need Adjacency", o6n); + return 0; + } + else + nbs_change (NBS_EXSTART, "Need Adjacency", o6n); + + DD_MSBIT_SET (o6n->dbdesc_bits); + DD_MBIT_SET (o6n->dbdesc_bits); + DD_IBIT_SET (o6n->dbdesc_bits); + + if (o6n->thread_send_dbdesc) + thread_cancel (o6n->thread_send_dbdesc); + o6n->thread_send_dbdesc = + thread_add_event (master, ospf6_send_dbdesc, o6n, 0); + if (o6n->thread_rxmt_dbdesc) + thread_cancel (o6n->thread_rxmt_dbdesc); + o6n->thread_rxmt_dbdesc = (struct thread *) NULL; + + return 0; +} + +int +negotiation_done (struct thread *thread) +{ + struct ospf6_neighbor *o6n; + + o6n = (struct ospf6_neighbor *) THREAD_ARG (thread); + assert (o6n); + + if (o6n->state != NBS_EXSTART) + return 0; + + if (IS_OSPF6_DUMP_NEIGHBOR) + zlog_info ("Neighbor Event %s: *NegotiationDone*", o6n->str); + + nbs_change (NBS_EXCHANGE, "NegotiationDone", o6n); + DD_IBIT_CLEAR (o6n->dbdesc_bits); + + return 0; +} + +int +exchange_done (struct thread *thread) +{ + struct ospf6_neighbor *o6n; + + o6n = (struct ospf6_neighbor *) THREAD_ARG (thread); + assert (o6n); + + if (o6n->state != NBS_EXCHANGE) + return 0; + + if (o6n->thread_rxmt_dbdesc) + thread_cancel (o6n->thread_rxmt_dbdesc); + o6n->thread_rxmt_dbdesc = (struct thread *) NULL; + + if (IS_OSPF6_DUMP_NEIGHBOR) + zlog_info ("Neighbor Event %s: *ExchangeDone*", o6n->str); + + ospf6_lsdb_remove_all (o6n->dbdesc_list); + + thread_add_timer (master, ospf6_neighbor_last_dbdesc_release, o6n, + o6n->ospf6_interface->dead_interval); + + if (o6n->request_list->count == 0) + nbs_change (NBS_FULL, "Requestlist Empty", o6n); + else + { + thread_add_event (master, ospf6_send_lsreq, o6n, 0); + nbs_change (NBS_LOADING, "Requestlist Not Empty", o6n); + } + return 0; +} + +int +loading_done (struct thread *thread) +{ + struct ospf6_neighbor *o6n; + + o6n = (struct ospf6_neighbor *) THREAD_ARG (thread); + assert (o6n); + + if (o6n->state != NBS_LOADING) + return 0; + + if (IS_OSPF6_DUMP_NEIGHBOR) + zlog_info ("Neighbor Event %s: *LoadingDone*", o6n->str); + + assert (o6n->request_list->count == 0); + + nbs_change (NBS_FULL, "LoadingDone", o6n); + + return 0; +} + +int +adj_ok (struct thread *thread) +{ + struct ospf6_neighbor *o6n; + + o6n = (struct ospf6_neighbor *) THREAD_ARG (thread); + assert (o6n); + + if (IS_OSPF6_DUMP_NEIGHBOR) + zlog_info ("Neighbor Event %s: *AdjOK?*", o6n->str); + + if (o6n->state == NBS_TWOWAY) + { + if (!need_adjacency (o6n)) + { + nbs_change (NBS_TWOWAY, "No Need Adjacency", o6n); + return 0; + } + else + nbs_change (NBS_EXSTART, "Need Adjacency", o6n); + + DD_MSBIT_SET (o6n->dbdesc_bits); + DD_MBIT_SET (o6n->dbdesc_bits); + DD_IBIT_SET (o6n->dbdesc_bits); + + if (o6n->thread_send_dbdesc) + thread_cancel (o6n->thread_send_dbdesc); + o6n->thread_send_dbdesc = + thread_add_event (master, ospf6_send_dbdesc, o6n, 0); + + return 0; + } + + if (o6n->state >= NBS_EXSTART) + { + if (need_adjacency (o6n)) + return 0; + else + { + nbs_change (NBS_TWOWAY, "No Need Adjacency", o6n); + ospf6_neighbor_lslist_clear (o6n); + } + } + return 0; +} + +int +seqnumber_mismatch (struct thread *thread) +{ + struct ospf6_neighbor *o6n; + + o6n = (struct ospf6_neighbor *) THREAD_ARG (thread); + assert (o6n); + + if (o6n->state < NBS_EXCHANGE) + return 0; + + /* statistics */ + o6n->ospf6_stat_seqnum_mismatch++; + + if (IS_OSPF6_DUMP_NEIGHBOR) + zlog_info ("Neighbor Event %s: *SeqNumberMismatch*", o6n->str); + + nbs_change (NBS_EXSTART, "SeqNumberMismatch", o6n); + + DD_MSBIT_SET (o6n->dbdesc_bits); + DD_MBIT_SET (o6n->dbdesc_bits); + DD_IBIT_SET (o6n->dbdesc_bits); + ospf6_neighbor_lslist_clear (o6n); + + if (o6n->thread_send_dbdesc) + thread_cancel (o6n->thread_send_dbdesc); + o6n->thread_send_dbdesc = + thread_add_event (master, ospf6_send_dbdesc, o6n, 0); + + return 0; +} + +int +bad_lsreq (struct thread *thread) +{ + struct ospf6_neighbor *o6n; + + o6n = (struct ospf6_neighbor *) THREAD_ARG (thread); + assert (o6n); + + if (o6n->state < NBS_EXCHANGE) + return 0; + + /* statistics */ + o6n->ospf6_stat_bad_lsreq++; + + if (IS_OSPF6_DUMP_NEIGHBOR) + zlog_info ("Neighbor Event %s: *BadLSReq*", o6n->str); + + nbs_change (NBS_EXSTART, "BadLSReq", o6n); + + DD_MSBIT_SET (o6n->dbdesc_bits); + DD_MBIT_SET (o6n->dbdesc_bits); + DD_IBIT_SET (o6n->dbdesc_bits); + ospf6_neighbor_lslist_clear (o6n); + + if (o6n->thread_send_dbdesc) + thread_cancel (o6n->thread_send_dbdesc); + o6n->thread_send_dbdesc = + thread_add_event (master, ospf6_send_dbdesc, o6n, 0); + + return 0; +} + +int +oneway_received (struct thread *thread) +{ + struct ospf6_neighbor *o6n; + + o6n = (struct ospf6_neighbor *) THREAD_ARG (thread); + assert (o6n); + + if (o6n->state < NBS_TWOWAY) + return 0; + + /* statistics */ + o6n->ospf6_stat_oneway_received++; + + if (IS_OSPF6_DUMP_NEIGHBOR) + zlog_info ("Neighbor Event %s: *1Way-Received*", o6n->str); + + nbs_change (NBS_INIT, "1Way-Received", o6n); + + thread_add_event (master, neighbor_change, o6n->ospf6_interface, 0); + + ospf6_neighbor_thread_cancel_all (o6n); + ospf6_neighbor_lslist_clear (o6n); + return 0; +} + +int +inactivity_timer (struct thread *thread) +{ + struct ospf6_neighbor *o6n; + + o6n = (struct ospf6_neighbor *) THREAD_ARG (thread); + assert (o6n); + + /* statistics */ + o6n->ospf6_stat_inactivity_timer++; + + if (IS_OSPF6_DUMP_NEIGHBOR) + zlog_info ("Neighbor Event %s: *InactivityTimer*", o6n->str); + + o6n->inactivity_timer = NULL; + o6n->dr = o6n->bdr = o6n->prevdr = o6n->prevbdr = 0; + nbs_change (NBS_DOWN, "InactivityTimer", o6n); + + thread_add_event (master, neighbor_change, o6n->ospf6_interface, 0); + + listnode_delete (o6n->ospf6_interface->neighbor_list, o6n); + ospf6_neighbor_delete (o6n); + + return 0; +} + diff --git a/ospf6d/ospf6_nsm.h b/ospf6d/ospf6_nsm.h new file mode 100644 index 000000000..d70f1e88d --- /dev/null +++ b/ospf6d/ospf6_nsm.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 1999 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF6_NSM_H +#define OSPF6_NSM_H + +/* Neighbor state */ +#define NBS_DOWN 1 +#define OSPF6_NEIGHBOR_STATE_DOWN 1 +#define NBS_ATTEMPT 2 +#define OSPF6_NEIGHBOR_STATE_ATTEMPT 2 +#define NBS_INIT 3 +#define OSPF6_NEIGHBOR_STATE_INIT 3 +#define NBS_TWOWAY 4 +#define OSPF6_NEIGHBOR_STATE_TWOWAY 4 +#define NBS_EXSTART 5 +#define OSPF6_NEIGHBOR_STATE_EXSTART 5 +#define NBS_EXCHANGE 6 +#define OSPF6_NEIGHBOR_STATE_EXCHANGE 6 +#define NBS_LOADING 7 +#define OSPF6_NEIGHBOR_STATE_LOADING 7 +#define NBS_FULL 8 +#define OSPF6_NEIGHBOR_STATE_FULL 8 + + + +/* Function Prototypes */ + +#include "ospf6_types.h" + +int need_adjacency (struct ospf6_neighbor *); + + +/* Neighbor event */ +int hello_received (struct thread *); +int twoway_received (struct thread *); +int negotiation_done (struct thread *); +int exchange_done (struct thread *); +int loading_done (struct thread *); +int adj_ok (struct thread *); +int seqnumber_mismatch (struct thread *); +int bad_lsreq (struct thread *); +int oneway_received (struct thread *); +int inactivity_timer (struct thread *); + +int dr_election (struct ospf6_interface *); + +#endif /* OSPF6_NSM_H */ + diff --git a/ospf6d/ospf6_prefix.c b/ospf6d/ospf6_prefix.c new file mode 100644 index 000000000..1542200ca --- /dev/null +++ b/ospf6d/ospf6_prefix.c @@ -0,0 +1,213 @@ +/* + * Copyright (C) 1999 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#if 0 + +#include <zebra.h> + +#include "log.h" +#include "prefix.h" +#include "memory.h" +#include "linklist.h" + +#include "ospf6_prefix.h" + +#else /*0*/ + +#include "ospf6d.h" + +#endif /*0*/ + +struct ospf6_prefix * +ospf6_prefix_create (u_int8_t options, u_int16_t metric, struct prefix_ipv6 *p) +{ + struct prefix_ipv6 prefix; + struct ospf6_prefix *o6p; + size_t size; + + /* copy prefix and apply mask */ + prefix_copy ((struct prefix *) &prefix, (struct prefix *) p); + apply_mask_ipv6 (&prefix); + + size = OSPF6_PREFIX_SPACE (prefix.prefixlen) + sizeof (struct ospf6_prefix); + o6p = (struct ospf6_prefix *) XMALLOC (MTYPE_OSPF6_PREFIX, size); + if (! o6p) + zlog_warn ("Can't allocate memory for ospf6 prefix: size: %d", size); + else + memset (o6p, 0, size); + + o6p->prefix_length = prefix.prefixlen; + o6p->prefix_options = options; + o6p->prefix_metric = htons (metric); + memcpy (o6p + 1, &prefix.prefix, OSPF6_PREFIX_SPACE (prefix.prefixlen)); + + return o6p; +} + +void +ospf6_prefix_delete (struct ospf6_prefix *p) +{ + XFREE (MTYPE_OSPF6_PREFIX, p); +} + +int +ospf6_prefix_issame (struct ospf6_prefix *p1, struct ospf6_prefix *p2) +{ + if (p1->prefix_length != p2->prefix_length) + return 0; + if (memcmp (&p1->u, &p2->u, sizeof (p1->u))) + return 0; + if (memcmp (p1 + 1, p2 + 1, OSPF6_PREFIX_SPACE (p1->prefix_length))) + return 0; + return 1; +} + +struct ospf6_prefix * +ospf6_prefix_lookup (list l, struct ospf6_prefix *p1) +{ + listnode node; + struct ospf6_prefix *p2; + for (node = listhead (l); node; nextnode (node)) + { + p2 = (struct ospf6_prefix *) getdata (node); + if (ospf6_prefix_issame (p1, p2)) + return p2; + } + return NULL; +} + +/* add a copy of given prefix to the list */ +void +ospf6_prefix_add (list l, struct ospf6_prefix *p) +{ + struct ospf6_prefix *add; + add = (struct ospf6_prefix *) XMALLOC (MTYPE_OSPF6_PREFIX, + OSPF6_PREFIX_SIZE (p)); + if (add == NULL) + { + zlog_warn ("Can't allocate memory for ospf6 prefix"); + return; + } + else + memcpy (add, p, OSPF6_PREFIX_SIZE (p)); + + if (ospf6_prefix_lookup (l, add)) + { + ospf6_prefix_delete (add); + return; + } + listnode_add (l, add); +} + +void +ospf6_prefix_remove (list l, struct ospf6_prefix *p) +{ + struct ospf6_prefix *rem; + rem = ospf6_prefix_lookup (l, p); + if (rem) + { + listnode_delete (l, rem); + ospf6_prefix_delete (rem); + } +} + +void +ospf6_prefix_in6_addr (struct ospf6_prefix *o6p, struct in6_addr *in6) +{ + memset (in6, 0, sizeof (struct in6_addr)); + memcpy (in6, o6p + 1, OSPF6_PREFIX_SPACE (o6p->prefix_length)); + return; +} + +char * +ospf6_prefix_options_str (u_int8_t opt, char *buf, size_t bufsize) +{ + char *p, *mc, *la, *nu; + + p = (CHECK_FLAG (opt, OSPF6_PREFIX_OPTION_P) ? "P" : "-"); + mc = (CHECK_FLAG (opt, OSPF6_PREFIX_OPTION_MC) ? "MC" : "--"); + la = (CHECK_FLAG (opt, OSPF6_PREFIX_OPTION_LA) ? "LA" : "--"); + nu = (CHECK_FLAG (opt, OSPF6_PREFIX_OPTION_NU) ? "NU" : "--"); + + snprintf (buf, bufsize, "%s|%s|%s|%s", p, mc, la, nu); + return buf; +} + +char * +ospf6_prefix_string (struct ospf6_prefix *prefix, char *buf, size_t size) +{ + struct in6_addr in6; + char s[64]; + + memset (&in6, 0, sizeof (in6)); + memcpy (&in6, prefix + 1, OSPF6_PREFIX_SPACE (prefix->prefix_length)); + inet_ntop (AF_INET6, &in6, s, sizeof (s)); + + snprintf (buf, size, "%s/%d", s, prefix->prefix_length); + return buf; +} + +void +ospf6_prefix_copy (struct ospf6_prefix *dst, struct ospf6_prefix *src, + size_t dstsize) +{ + size_t srcsize; + + memset (dst, 0, dstsize); + + srcsize = OSPF6_PREFIX_SIZE (src); + if (dstsize < srcsize) + memcpy (dst, src, dstsize); + else + memcpy (dst, src, srcsize); + + return; +} + +void +ospf6_prefix_apply_mask (struct ospf6_prefix *o6p) +{ + u_char *pnt, mask; + int index, offset; + + char buf[128]; + struct in6_addr in6; + ospf6_prefix_in6_addr (o6p, &in6); + inet_ntop (AF_INET6, &in6, buf, sizeof (buf)); + + pnt = (u_char *)(o6p + 1); + index = o6p->prefix_length / 8; + offset = o6p->prefix_length % 8; + mask = 0xff << (8 - offset); + + if (index >= 16) + return; + + pnt[index] &= mask; + index ++; + + while (index < OSPF6_PREFIX_SPACE (o6p->prefix_length)) + pnt[index++] = 0; + + ospf6_prefix_in6_addr (o6p, &in6); + inet_ntop (AF_INET6, &in6, buf, sizeof (buf)); +} + diff --git a/ospf6d/ospf6_prefix.h b/ospf6d/ospf6_prefix.h new file mode 100644 index 000000000..65a8cbc88 --- /dev/null +++ b/ospf6d/ospf6_prefix.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 1999 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF6_PREFIX_H +#define OSPF6_PREFIX_H + +#include "linklist.h" + +#define OSPF6_PREFIX_OPTION_NU (1 << 0) /* No Unicast */ +#define OSPF6_PREFIX_OPTION_LA (1 << 1) /* Local Address */ +#define OSPF6_PREFIX_OPTION_MC (1 << 2) /* MultiCast */ +#define OSPF6_PREFIX_OPTION_P (1 << 3) /* Propagate (NSSA) */ + +struct ospf6_prefix +{ + u_int8_t prefix_length; + u_int8_t prefix_options; + union { + u_int16_t _prefix_metric; + u_int16_t _prefix_referenced_lstype; + } u; +#define prefix_metric u._prefix_metric +#define prefix_refer_lstype u._prefix_referenced_lstype + /* followed by one address_prefix */ +}; + +/* size_t OSPF6_PREFIX_SPACE (int prefixlength); */ +#define OSPF6_PREFIX_SPACE(x) ((((x) + 31) / 32) * 4) + +/* size_t OSPF6_PREFIX_SIZE (struct ospf6_prefix *); */ +#define OSPF6_PREFIX_SIZE(x) \ + (OSPF6_PREFIX_SPACE ((x)->prefix_length) + sizeof (struct ospf6_prefix)) + +/* struct ospf6_prefix *OSPF6_NEXT_PREFIX (struct ospf6_prefix *); */ +#define OSPF6_NEXT_PREFIX(x) \ + ((struct ospf6_prefix *)((char *)(x) + OSPF6_PREFIX_SIZE (x))) + + + +/* Function Prototypes */ +struct ospf6_prefix * + ospf6_prefix_make (u_int8_t, u_int16_t, struct prefix_ipv6 *); +void ospf6_prefix_free (struct ospf6_prefix *); +void ospf6_prefix_in6_addr (struct ospf6_prefix *, struct in6_addr *); +void ospf6_prefix_copy (struct ospf6_prefix *, struct ospf6_prefix *, + size_t); + +void ospf6_prefix_apply_mask (struct ospf6_prefix *); +int ospf6_prefix_issame (struct ospf6_prefix *, struct ospf6_prefix *); + +char *ospf6_prefix_options_str (u_int8_t, char *, size_t); +char *ospf6_prefix_string (struct ospf6_prefix *, char *, size_t); + +struct ospf6_prefix * +ospf6_prefix_lookup (list l, struct ospf6_prefix *prefix); +void ospf6_prefix_add (list, struct ospf6_prefix *); + +struct ospf6_prefix * +ospf6_prefix_create (u_int8_t, u_int16_t, struct prefix_ipv6 *); +void ospf6_prefix_delete (struct ospf6_prefix *); + +void ospf6_prefix_init (); + +#endif /* OSPF6_PREFIX_H */ + diff --git a/ospf6d/ospf6_proto.c b/ospf6d/ospf6_proto.c new file mode 100644 index 000000000..71e575f1b --- /dev/null +++ b/ospf6d/ospf6_proto.c @@ -0,0 +1,40 @@ +/* + * Copyright (C) 1999 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <zebra.h> + +#include "ospf6_proto.h" + +char * +ospf6_options_string (u_char opt_capability[3], char *buffer, int size) +{ + char *dc, *r, *n, *mc, *e, *v6; + + dc = (OSPF6_OPT_ISSET (opt_capability, OSPF6_OPT_DC) ? "DC" : "--"); + r = (OSPF6_OPT_ISSET (opt_capability, OSPF6_OPT_R) ? "R" : "-"); + n = (OSPF6_OPT_ISSET (opt_capability, OSPF6_OPT_N) ? "N" : "-"); + mc = (OSPF6_OPT_ISSET (opt_capability, OSPF6_OPT_MC) ? "MC" : "--"); + e = (OSPF6_OPT_ISSET (opt_capability, OSPF6_OPT_E) ? "E" : "-"); + v6 = (OSPF6_OPT_ISSET (opt_capability, OSPF6_OPT_V6) ? "V6" : "--"); + snprintf (buffer, size, "%s|%s|%s|%s|%s|%s", dc, r, n, mc, e, v6); + return buffer; +} + diff --git a/ospf6d/ospf6_proto.h b/ospf6d/ospf6_proto.h new file mode 100644 index 000000000..9a95444a5 --- /dev/null +++ b/ospf6d/ospf6_proto.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 1999 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF6_PROTO_H +#define OSPF6_PROTO_H + +/* OSPF protocol version */ +#define OSPF6_VERSION 3 + +/* OSPF protocol number. */ +#ifndef IPPROTO_OSPFIGP +#define IPPROTO_OSPFIGP 89 +#endif + +/* TOS field normaly null */ +#define OSPF6_TOS_VALUE 0x0 + +/* Architectural Constants */ +#define OSPF6_LS_REFRESH_TIME 1800 /* 30 min */ +#define OSPF6_MIN_LS_INTERVAL 5 +#define OSPF6_MIN_LS_ARRIVAL 1 +#define MAXAGE 3600 /* 1 hour */ +#define CHECK_AGE 300 /* 5 min */ +#define MAX_AGE_DIFF 900 /* 15 min */ +#define LS_INFINITY 0xffffff /* 24-bit binary value */ +#define INITIAL_SEQUENCE_NUMBER 0x80000001 /* signed 32-bit integer */ +#define MAX_SEQUENCE_NUMBER 0x7fffffff /* signed 32-bit integer */ + +#define MAXOSPFMESSAGELEN 4096 + +#define ALLSPFROUTERS6 "ff02::5" +#define ALLDROUTERS6 "ff02::6" + +/* Configurable Constants */ + +#define DEFAULT_HELLO_INTERVAL 10 +#define DEFAULT_ROUTER_DEAD_TIMER 40 + +/* OSPF options */ +/* present in HELLO, DD, LSA */ +#define OSPF6_OPT_SET(x,opt) ((x)[2] |= (opt)) +#define OSPF6_OPT_ISSET(x,opt) ((x)[2] & (opt)) +#define OSPF6_OPT_CLEAR(x,opt) ((x)[2] &= ~(opt)) +#define OSPF6_OPT_CLEAR_ALL(x) ((x)[0] = (x)[1] = (x)[2] = 0) + +#define OSPF6_OPT_V6 (1 << 0) /* IPv6 forwarding Capability */ +#define OSPF6_OPT_E (1 << 1) /* AS External Capability */ +#define OSPF6_OPT_MC (1 << 2) /* Multicasting Capability */ +#define OSPF6_OPT_N (1 << 3) /* Handling Type-7 LSA Capability */ +#define OSPF6_OPT_R (1 << 4) /* Forwarding Capability (Any Protocol) */ +#define OSPF6_OPT_DC (1 << 5) /* Demand Circuit handling Capability */ + +char * +ospf6_options_string (u_char opt_capability[3], char *buffer, int size); + +#endif /* OSPF6_PROTO_H */ + diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c new file mode 100644 index 000000000..c35efa6e7 --- /dev/null +++ b/ospf6d/ospf6_route.c @@ -0,0 +1,1130 @@ +/* + * Copyright (C) 1999 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "ospf6d.h" + +char * +dtype_name[OSPF6_DEST_TYPE_MAX] = +{ + "Unknown", "Router", "Network", "Discard" +}; +#define DTYPE_NAME(x) \ + (0 < (x) && (x) < sizeof (dtype_name) ? \ + dtype_name[(x)] : dtype_name[0]) + +char * +dtype_abname[OSPF6_DEST_TYPE_MAX] = +{ + "?", "R", "N", "D" +}; +#define DTYPE_ABNAME(x) \ + (0 < (x) && (x) < sizeof (dtype_abname) ? \ + dtype_abname[(x)] : dtype_abname[0]) + +char * +ptype_name[OSPF6_PATH_TYPE_MAX] = +{ + "Unknown", "Intra", "Inter", "External-1", "External-2", + "System", "Kernel", "Connect", "Static", "RIP", "RIPng", + "OSPF", "OSPF6", "BGP" +}; +#define PTYPE_NAME(x) \ + (0 < (x) && (x) < sizeof (ptype_name) ? \ + ptype_name[(x)] : ptype_name[0]) + +char * +ptype_abname[OSPF6_PATH_TYPE_MAX] = +{ + "??", "Ia", "Ie", "E1", "E2", + "-X", "-K", "-C", "-S", "-R", "-R", + "-O", "-O", "-B" +}; +#define PTYPE_ABNAME(x) \ + (0 < (x) && (x) < sizeof (ptype_abname) ? \ + ptype_abname[(x)] : ptype_abname[0]) + + + +int +ospf6_path_cmp (void *arg1, void *arg2) +{ + struct ospf6_path_node *pn1 = arg1; + struct ospf6_path_node *pn2 = arg2; + struct ospf6_path *p1 = &pn1->path; + struct ospf6_path *p2 = &pn2->path; + + if (p1->type < p2->type) + return -1; + else if (p1->type > p2->type) + return 1; + + if (p1->type == OSPF6_PATH_TYPE_EXTERNAL2) + { + if (p1->cost_e2 < p2->cost_e2) + return -1; + else if (p1->cost_e2 > p2->cost_e2) + return 1; + } + + if (p1->cost < p2->cost) + return -1; + else if (p1->cost > p2->cost) + return 1; + + /* if from the same source, recognize as identical + (and treat this as update) */ + if (! memcmp (&p1->origin, &p2->origin, sizeof (struct ls_origin)) && + p1->area_id == p2->area_id) + return 0; + + /* else, always prefer left */ + return -1; +} + +int +ospf6_nexthop_cmp (void *arg1, void *arg2) +{ + int i, ret = 0; + struct ospf6_nexthop_node *nn1 = arg1; + struct ospf6_nexthop_node *nn2 = arg2; + struct ospf6_nexthop *n1 = &nn1->nexthop; + struct ospf6_nexthop *n2 = &nn2->nexthop; + + if (memcmp (n1, n2, sizeof (struct ospf6_nexthop)) == 0) + return 0; + + for (i = 0; i < sizeof (struct in6_addr); i++) + { + if (nn1->nexthop.address.s6_addr[i] != nn2->nexthop.address.s6_addr[i]) + { + ret = nn1->nexthop.address.s6_addr[i] - + nn2->nexthop.address.s6_addr[i]; + break; + } + } + + if (ret == 0) + ret = -1; + + return ret; +} + +static void +ospf6_route_request (struct ospf6_route_req *request, + struct ospf6_route_node *rn, + struct ospf6_path_node *pn, + struct ospf6_nexthop_node *nn) +{ + assert (request); + assert (rn && pn && nn); + + request->route_node = rn->route_node; + + linklist_head (rn->path_list, &request->path_lnode); + while (request->path_lnode.data != pn) + { + //assert (! linklist_end (&request->path_lnode)); + if (linklist_end (&request->path_lnode)) + { + struct linklist_node node; + + zlog_info ("rn: %p, pn: %p", rn, pn); + zlog_info ("origin: %hx %x %x bits: %x opt: %x%x%x popt: %x area: %x type: %d cost %d %d %d", + pn->path.origin.type, pn->path.origin.id, pn->path.origin.adv_router, (int)pn->path.router_bits, (int)pn->path.capability[0], + (int)pn->path.capability[1], (int)pn->path.capability[2], + (int)pn->path.prefix_options, pn->path.area_id, + pn->path.type, pn->path.metric_type, pn->path.cost, pn->path.cost_e2); + + for (linklist_head (rn->path_list, &node); ! linklist_end (&node); + linklist_next (&node)) + { + struct ospf6_path_node *pn2 = node.data; + + zlog_info (" %p: path data with pn(%p): %s", pn2, pn, + (memcmp (&pn->path, &pn2->path, + sizeof (struct ospf6_path)) ? + "different" : "same")); + + zlog_info (" origin: %hx %x %x bits: %x opt: %x%x%x popt: %x area: %x type: %d cost %d %d %d", + pn2->path.origin.type, pn2->path.origin.id, pn2->path.origin.adv_router, (int)pn2->path.router_bits, (int)pn2->path.capability[0], + (int)pn2->path.capability[1], (int)pn2->path.capability[2], + (int)pn2->path.prefix_options, pn2->path.area_id, + pn2->path.type, pn2->path.metric_type, pn2->path.cost, pn2->path.cost_e2); + + if (! memcmp (&pn->path, &pn2->path, sizeof (struct ospf6_path))) + { + pn = pn2; + request->nexthop_lnode.data = pn2; + } + } + break; + } + linklist_next (&request->path_lnode); + } + assert (request->path_lnode.data == pn); + + linklist_head (pn->nexthop_list, &request->nexthop_lnode); + while (request->nexthop_lnode.data != nn) + { + assert (! linklist_end (&request->nexthop_lnode)); + linklist_next (&request->nexthop_lnode); + } + assert (request->nexthop_lnode.data == nn); + + request->table = rn->table; + request->count = rn->count; + request->route_id = rn->route_id; + memcpy (&request->route, &rn->route, sizeof (struct ospf6_route)); + memcpy (&request->path, &pn->path, sizeof (struct ospf6_path)); + memcpy (&request->nexthop, &nn->nexthop, sizeof (struct ospf6_nexthop)); +} + +int +ospf6_route_count (struct ospf6_route_req *request) +{ + return request->count; +} + +int +ospf6_route_lookup (struct ospf6_route_req *request, + struct prefix *prefix, + struct ospf6_route_table *table) +{ + struct route_node *node; + struct ospf6_route_node *rn = NULL; + struct ospf6_path_node *pn = NULL; + struct ospf6_nexthop_node *nn = NULL; + struct linklist_node lnode; + + if (request) + memset ((void *) request, 0, sizeof (struct ospf6_route_req)); + + node = route_node_lookup (table->table, prefix); + if (! node) + return 0; + + rn = (struct ospf6_route_node *) node->info; + if (! rn) + return 0; + + if (request) + { + linklist_head (rn->path_list, &lnode); + pn = lnode.data; + linklist_head (pn->nexthop_list, &lnode); + nn = lnode.data; + + ospf6_route_request (request, rn, pn, nn); + } + + return 1; +} + +void +ospf6_route_head (struct ospf6_route_req *request, + struct ospf6_route_table *table) +{ + struct route_node *node; + struct ospf6_route_node *rn = NULL; + struct ospf6_path_node *pn = NULL; + struct ospf6_nexthop_node *nn = NULL; + struct linklist_node lnode; + + if (request) + memset (request, 0, sizeof (struct ospf6_route_req)); + + node = route_top (table->table); + if (! node) + return; + + while (node && node->info == NULL) + node = route_next (node); + if (! node) + return; + + rn = (struct ospf6_route_node *) node->info; + linklist_head (rn->path_list, &lnode); + pn = lnode.data; + linklist_head (pn->nexthop_list, &lnode); + nn = lnode.data; + + ospf6_route_request (request, rn, pn, nn); +} + +int +ospf6_route_end (struct ospf6_route_req *request) +{ + if (request->route_node == NULL && + linklist_end (&request->path_lnode) && + linklist_end (&request->nexthop_lnode) && + request->nexthop.ifindex == 0 && + IN6_IS_ADDR_UNSPECIFIED (&request->nexthop.address)) + return 1; + return 0; +} + +void +ospf6_route_next (struct ospf6_route_req *request) +{ + struct ospf6_route_node *route_node = NULL; + struct ospf6_path_node *path_node = NULL; + struct ospf6_nexthop_node *nexthop_node = NULL; + + linklist_next (&request->nexthop_lnode); + if (linklist_end (&request->nexthop_lnode)) + { + linklist_next (&request->path_lnode); + if (linklist_end (&request->path_lnode)) + { + request->route_node = route_next (request->route_node); + while (request->route_node && request->route_node->info == NULL) + request->route_node = route_next (request->route_node); + if (request->route_node) + { + route_node = request->route_node->info; + if (route_node) + linklist_head (route_node->path_list, &request->path_lnode); + } + } + + path_node = request->path_lnode.data; + if (path_node) + linklist_head (path_node->nexthop_list, &request->nexthop_lnode); + } + + nexthop_node = request->nexthop_lnode.data; + + if (nexthop_node == NULL) + { + assert (path_node == NULL); + assert (route_node == NULL); + + memset (&request->route, 0, sizeof (struct ospf6_route)); + memset (&request->path, 0, sizeof (struct ospf6_path)); + memset (&request->nexthop, 0, sizeof (struct ospf6_nexthop)); + } + else + { + path_node = request->path_lnode.data; + route_node = request->route_node->info; + + assert (path_node != NULL); + assert (route_node != NULL); + + memcpy (&request->route, &route_node->route, + sizeof (struct ospf6_route)); + memcpy (&request->path, &path_node->path, + sizeof (struct ospf6_path)); + memcpy (&request->nexthop, &nexthop_node->nexthop, + sizeof (struct ospf6_nexthop)); + } +} + +#define ADD 0 +#define CHANGE 1 +#define REMOVE 2 + +void +ospf6_route_hook_call (int type, + struct ospf6_route_req *request, + struct ospf6_route_table *table) +{ + struct linklist_node node; + void (*func) (struct ospf6_route_req *); + + for (linklist_head (table->hook_list[type], &node); + ! linklist_end (&node); + linklist_next (&node)) + { + func = node.data; + (*func) (request); + } +} + +void +ospf6_route_hook_register (void (*add) (struct ospf6_route_req *), + void (*change) (struct ospf6_route_req *), + void (*remove) (struct ospf6_route_req *), + struct ospf6_route_table *table) +{ + linklist_add (add, table->hook_list[ADD]); + linklist_add (change, table->hook_list[CHANGE]); + linklist_add (remove, table->hook_list[REMOVE]); +} + +void +ospf6_route_hook_unregister (void (*add) (struct ospf6_route_req *), + void (*change) (struct ospf6_route_req *), + void (*remove) (struct ospf6_route_req *), + struct ospf6_route_table *table) +{ + linklist_remove (add, table->hook_list[ADD]); + linklist_remove (change, table->hook_list[CHANGE]); + linklist_remove (remove, table->hook_list[REMOVE]); +} + + +int +prefix_ls2str (struct prefix *p, char *str, int size) +{ + char id[BUFSIZ], adv_router[BUFSIZ]; + struct prefix_ls *pl = (struct prefix_ls *) p; + + inet_ntop (AF_INET, &pl->id, id, BUFSIZ); + inet_ntop (AF_INET, &pl->adv_router, adv_router, BUFSIZ); + snprintf (str, size, "%s-%s", adv_router, id); + return 0; +} + +void +ospf6_route_log_request (char *what, char *where, + struct ospf6_route_req *request) +{ + char prefix[64]; + char area_id[16]; + char type[16], id[16], adv[16]; + char address[64], ifname[IFNAMSIZ]; + + if (request->route.prefix.family != AF_INET && + request->route.prefix.family != AF_INET6) + prefix_ls2str (&request->route.prefix, prefix, sizeof (prefix)); + else + prefix2str (&request->route.prefix, prefix, sizeof (prefix)); + + inet_ntop (AF_INET, &request->path.area_id, area_id, sizeof (area_id)); + + ospf6_lsa_type_string (request->path.origin.type, type, sizeof (type)); + inet_ntop (AF_INET, &request->path.origin.id, id, sizeof (id)); + inet_ntop (AF_INET, &request->path.origin.adv_router, adv, sizeof (adv)); + + inet_ntop (AF_INET6, &request->nexthop.address, address, sizeof (address)); + + zlog_info ("ROUTE: %s %s %s %s %s", + what, DTYPE_ABNAME (request->route.type), prefix, + ((strcmp ("Add", what) == 0) ? "to" : "from"), where); + zlog_info ("ROUTE: Area: %s type: %s cost: %lu (E2: %lu)", + area_id, PTYPE_NAME (request->path.type), + (u_long) request->path.cost, (u_long) request->path.cost_e2); + zlog_info ("ROUTE: Origin: Type: %s", type); + zlog_info ("ROUTE: Origin: Id: %s Adv: %s", id, adv); + zlog_info ("ROUTE: Nexthop: %s", address); + zlog_info ("ROUTE: Nexthop: Ifindex: %u (%s)", + request->nexthop.ifindex, + if_indextoname (request->nexthop.ifindex, ifname)); +} + +struct ospf6_path_node * +ospf6_route_find_path_node (struct ospf6_route_req *request, + struct ospf6_route_node *rn) +{ + struct linklist_node node; + + for (linklist_head (rn->path_list, &node); ! linklist_end (&node); + linklist_next (&node)) + { + struct ospf6_path_node *path_node = node.data; + + if (path_node->path.area_id == request->path.area_id && + path_node->path.origin.type == request->path.origin.type && + path_node->path.origin.id == request->path.origin.id && + path_node->path.origin.adv_router == request->path.origin.adv_router) + return path_node; + } + +#if 0 + zlog_info ("req path : area: %#x origin: type: %d, id: %d, adv_router: %#x", + request->path.area_id, request->path.origin.type, + request->path.origin.id, request->path.origin.adv_router); + for (linklist_head (rn->path_list, &node); ! linklist_end (&node); + linklist_next (&node)) + { + struct ospf6_path_node *path_node = node.data; + zlog_info (" path : area: %#x origin: type: %d, id: %d, adv_router: %#x", + path_node->path.area_id, path_node->path.origin.type, + path_node->path.origin.id, path_node->path.origin.adv_router); + } +#endif + + return NULL; +} + +struct ospf6_nexthop_node * +ospf6_route_find_nexthop_node (struct ospf6_route_req *request, + struct ospf6_path_node *pn) +{ + struct linklist_node node; + for (linklist_head (pn->nexthop_list, &node); ! linklist_end (&node); + linklist_next (&node)) + { + struct ospf6_nexthop_node *nexthop_node = node.data; + + if (! memcmp (&nexthop_node->nexthop, &request->nexthop, + sizeof (struct ospf6_nexthop))) + return nexthop_node; + } + return NULL; +} + +void +ospf6_route_add (struct ospf6_route_req *request, + struct ospf6_route_table *table) +{ + struct ospf6_route_node *rn; + struct ospf6_path_node *pn; + struct ospf6_nexthop_node *nn; + struct route_node *route_node; + + struct ospf6_route_req route; + + int route_change = 0; + int path_change = 0; + int nexthop_change = 0; + + /* find the requested route */ + route_node = route_node_get (table->table, &request->route.prefix); + rn = (struct ospf6_route_node *) route_node->info; + + if (rn) + { + if (memcmp (&rn->route, &request->route, sizeof (struct ospf6_route))) + { + memcpy (&rn->route, &request->route, sizeof (struct ospf6_route)); + route_change++; + } + } + else + { + rn = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_route_node)); + rn->table = table; + rn->route_node = route_node; + rn->route_id = table->route_id++; + rn->path_list = linklist_create (); + rn->path_list->cmp = ospf6_path_cmp; + memcpy (&rn->route, &request->route, sizeof (struct ospf6_route)); + route_node->info = rn; + } + + /* find the same path */ + pn = ospf6_route_find_path_node (request, rn); + + if (pn) + { + if (memcmp (&pn->path, &request->path, sizeof (struct ospf6_path))) + { + memcpy (&pn->path, &request->path, sizeof (struct ospf6_path)); + path_change++; + } + } + else + { + pn = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_path_node)); + pn->route_node = rn; + pn->nexthop_list = linklist_create (); + pn->nexthop_list->cmp = ospf6_nexthop_cmp; + memcpy (&pn->path, &request->path, sizeof (struct ospf6_path)); + linklist_add (pn, rn->path_list); + } + + /* find the same nexthop */ + nn = ospf6_route_find_nexthop_node (request, pn); + + if (nn) + { + if (memcmp (&nn->nexthop, &request->nexthop, + sizeof (struct ospf6_nexthop))) + { + memcpy (&nn->nexthop, &request->nexthop, + sizeof (struct ospf6_nexthop)); + nexthop_change++; + gettimeofday (&nn->installed, (struct timezone *) NULL); + } + } + else + { + nn = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_nexthop_node)); + nn->path_node = pn; + memcpy (&nn->nexthop, &request->nexthop, sizeof (struct ospf6_nexthop)); + linklist_add (nn, pn->nexthop_list); + rn->count++; + gettimeofday (&nn->installed, (struct timezone *) NULL); + } + + SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ADD); + if (route_change) + SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ROUTE_CHANGE); + if (path_change) + SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_PATH_CHANGE); + if (nexthop_change) + SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE); + + if (table->freeze) + return; + + if (IS_OSPF6_DUMP_ROUTE) + { + ospf6_route_log_request ("Add", table->name, request); + + if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ROUTE_CHANGE)) + zlog_info ("ROUTE: route attribute change"); + if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_PATH_CHANGE)) + zlog_info ("ROUTE: path attribute change"); + if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE)) + zlog_info ("ROUTE: nexthop attribute change"); + } + + if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ROUTE_CHANGE) || + CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_PATH_CHANGE)) + SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE); + + /* Call hooks */ + ospf6_route_request (&route, rn, pn, nn); + if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ADD)) + ospf6_route_hook_call (ADD, &route, table); + else if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE)) + ospf6_route_hook_call (CHANGE, &route, table); + + if (table->hook_add && + CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ADD)) + (*table->hook_add) (&route); + else if (table->hook_change && + CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE)) + (*table->hook_change) (&route); + + /* clear flag */ + nn->flag = 0; +} + +void +ospf6_route_remove (struct ospf6_route_req *request, + struct ospf6_route_table *table) +{ + struct ospf6_route_node *rn; + struct ospf6_path_node *pn; + struct ospf6_nexthop_node *nn; + struct route_node *route_node; + struct ospf6_route_req route; + + /* find the requested route */ + route_node = route_node_get (table->table, &request->route.prefix); + rn = (struct ospf6_route_node *) route_node->info; + + if (! rn) + { + if (IS_OSPF6_DUMP_ROUTE) + { + ospf6_route_log_request ("Remove", table->name, request); + zlog_info ("ROUTE: Can't remove: No such route"); + } + return; + } + + pn = ospf6_route_find_path_node (request, rn); + if (! pn) + { + if (IS_OSPF6_DUMP_ROUTE) + { + ospf6_route_log_request ("Remove", table->name, request); + zlog_info ("ROUTE: Can't remove: No such path"); + } + return; + } + + if (pn->path.area_id != request->path.area_id || + pn->path.origin.type != request->path.origin.type || + pn->path.origin.id != request->path.origin.id || + pn->path.origin.adv_router != request->path.origin.adv_router) + { + if (IS_OSPF6_DUMP_ROUTE) + { + ospf6_route_log_request ("Remove", table->name, request); + zlog_info ("ROUTE: Can't remove: Path differ"); + { + char *s, *e, *c; + char line[512], *p; + + p = line; + s = (char *) &pn->path; + e = s + sizeof (struct ospf6_path); + for (c = s; c < e; c++) + { + if ((c - s) % 4 == 0) + snprintf (p++, line + sizeof (line) - p, " "); + snprintf (p, line + sizeof (line) - p, "%02x", *c); + p += 2; + } + zlog_info ("ROUTE: path: %s", line); + + p = line; + s = (char *) &request->path; + e = s + sizeof (struct ospf6_path); + for (c = s; c < e; c++) + { + if ((c - s) % 4 == 0) + snprintf (p++, line + sizeof (line) - p, " "); + snprintf (p, line + sizeof (line) - p, "%02x", *c); + p += 2; + } + zlog_info ("ROUTE: req : %s", line); + + } + } + return; + } + + nn = ospf6_route_find_nexthop_node (request, pn); + if (! nn) + { + if (IS_OSPF6_DUMP_ROUTE) + { + ospf6_route_log_request ("Remove", table->name, request); + zlog_info ("ROUTE: Can't remove: No such nexthop"); + } + return; + } + + if (memcmp (&nn->nexthop, &request->nexthop, sizeof (struct ospf6_nexthop))) + { + if (IS_OSPF6_DUMP_ROUTE) + { + ospf6_route_log_request ("Remove", table->name, request); + zlog_info ("ROUTE: Can't remove: Nexthop differ"); + } + return; + } + + SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_REMOVE); + + if (table->freeze) + return; + + if (IS_OSPF6_DUMP_ROUTE) + ospf6_route_log_request ("Remove", table->name, request); + + ospf6_route_request (&route, rn, pn, nn); + ospf6_route_hook_call (REMOVE, &route, table); + if (table->hook_remove) + (*table->hook_remove) (&route); + + /* clear flag */ + nn->flag = 0; + + /* remove nexthop */ + linklist_remove (nn, pn->nexthop_list); + rn->count--; + XFREE (MTYPE_OSPF6_ROUTE, nn); + + /* remove path if there's no nexthop for the path */ + if (pn->nexthop_list->count != 0) + return; + linklist_remove (pn, rn->path_list); + linklist_delete (pn->nexthop_list); + XFREE (MTYPE_OSPF6_ROUTE, pn); + + /* remove route if there's no path for the route */ + if (rn->path_list->count != 0) + return; + route_node->info = NULL; + linklist_delete (rn->path_list); + XFREE (MTYPE_OSPF6_ROUTE, rn); +} + +void +ospf6_route_remove_all (struct ospf6_route_table *table) +{ + struct ospf6_route_req request; + + for (ospf6_route_head (&request, table); ! ospf6_route_end (&request); + ospf6_route_next (&request)) + ospf6_route_remove (&request, table); +} + + +struct ospf6_route_table * +ospf6_route_table_create (char *name) +{ + int i; + struct ospf6_route_table *new; + + new = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_route_table)); + snprintf (new->name, sizeof (new->name), "%s", name); + + new->table = route_table_init (); + for (i = 0; i < 3; i++) + new->hook_list[i] = linklist_create (); + + return new; +} + +void +ospf6_route_table_delete (struct ospf6_route_table *table) +{ + int i; + + ospf6_route_remove_all (table); + route_table_finish (table->table); + for (i = 0; i < 3; i++) + linklist_delete (table->hook_list[i]); + XFREE (MTYPE_OSPF6_ROUTE, table); +} + +void +ospf6_route_table_freeze (struct ospf6_route_table *route_table) +{ + if (IS_OSPF6_DUMP_ROUTE) + zlog_info ("ROUTE: Table freeze: %s", route_table->name); + assert (route_table->freeze == 0); + route_table->freeze = 1; +} + +void +ospf6_route_table_thaw (struct ospf6_route_table *route_table) +{ + struct route_node *node; + struct linklist_node pnode; + struct linklist_node nnode; + + struct ospf6_route_node *rn; + struct ospf6_path_node *pn; + struct ospf6_nexthop_node *nn; + + struct ospf6_route_req request; + + if (IS_OSPF6_DUMP_ROUTE) + zlog_info ("ROUTE: Table thaw: %s", route_table->name); + + assert (route_table->freeze == 1); + route_table->freeze = 0; + + for (node = route_top (route_table->table); node; + node = route_next (node)) + { + rn = node->info; + if (! rn) + continue; + + for (linklist_head (rn->path_list, &pnode); + ! linklist_end (&pnode); + linklist_next (&pnode)) + { + pn = pnode.data; + + for (linklist_head (pn->nexthop_list, &nnode); + ! linklist_end (&nnode); + linklist_next (&nnode)) + { + nn = nnode.data; + + /* if the add and remove flag set without change flag, + do nothing with this route */ + if (! CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE) && + CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ADD) && + CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_REMOVE)) + { + nn->flag = 0; + continue; + } + + memset (&request, 0, sizeof (request)); + memcpy (&request.route, &rn->route, sizeof (rn->route)); + memcpy (&request.path, &pn->path, sizeof (pn->path)); + memcpy (&request.nexthop, &nn->nexthop, sizeof (nn->nexthop)); + + if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ADD) || + CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE)) + ospf6_route_add (&request, route_table); + else if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_REMOVE)) + ospf6_route_remove (&request, route_table); + } + } + } +} + + +/* VTY commands */ + +void +ospf6_route_show (struct vty *vty, struct ospf6_route_node *rn) +{ + struct linklist_node pnode; + struct linklist_node nnode; + struct ospf6_path_node *pn; + struct ospf6_nexthop_node *nn; + + struct timeval now, res; + char duration[16]; + + u_int pc = 0; + u_int nc = 0; +#define HEAD (pc == 0 && nc == 0) + + char prefix[64], nexthop[64], ifname[IFNAMSIZ]; + + gettimeofday (&now, (struct timezone *) NULL); + + /* destination */ + if (rn->route.prefix.family == AF_INET || + rn->route.prefix.family == AF_INET6) + prefix2str (&rn->route.prefix, prefix, sizeof (prefix)); + else + prefix_ls2str (&rn->route.prefix, prefix, sizeof (prefix)); + + for (linklist_head (rn->path_list, &pnode); ! linklist_end (&pnode); + linklist_next (&pnode)) + { + pn = pnode.data; + + for (linklist_head (pn->nexthop_list, &nnode); ! linklist_end (&nnode); + linklist_next (&nnode)) + { + nn = nnode.data; + + inet_ntop (AF_INET6, &nn->nexthop.address, nexthop, + sizeof (nexthop)); + if (! if_indextoname (nn->nexthop.ifindex, ifname)) + snprintf (ifname, sizeof (ifname), "%d", nn->nexthop.ifindex); + + ospf6_timeval_sub (&now, &nn->installed, &res); + ospf6_timeval_string_summary (&res, duration, sizeof (duration)); + + vty_out (vty, "%c%1s %2s %-30s %-25s %6s %s%s", + (HEAD ? '*' : ' '), + DTYPE_ABNAME (rn->route.type), + PTYPE_ABNAME (pn->path.type), + prefix, nexthop, ifname, duration, VTY_NEWLINE); + + nc++; + } + pc++; + } +} + +void +ospf6_route_show_detail (struct vty *vty, struct ospf6_route_node *rn) +{ + struct linklist_node pnode; + struct linklist_node nnode; + struct ospf6_path_node *pn; + struct ospf6_nexthop_node *nn; + + u_int pc = 0; + u_int nc = 0; + + char prefix[64], nexthop[64], ifname[IFNAMSIZ]; + char area_id[16], type[16], id[16], adv[16]; + char capa[64]; + + /* destination */ + if (rn->route.prefix.family == AF_INET || + rn->route.prefix.family == AF_INET6) + prefix2str (&rn->route.prefix, prefix, sizeof (prefix)); + else + prefix_ls2str (&rn->route.prefix, prefix, sizeof (prefix)); + + vty_out (vty, "%s%s%s", VTY_NEWLINE, prefix, VTY_NEWLINE); + vty_out (vty, " Destination Type: %s%s", + DTYPE_NAME (rn->route.type), VTY_NEWLINE); + + for (linklist_head (rn->path_list, &pnode); ! linklist_end (&pnode); + linklist_next (&pnode)) + { + pn = pnode.data; + + inet_ntop (AF_INET, &pn->path.area_id, area_id, sizeof (area_id)); + ospf6_lsa_type_string (pn->path.origin.type, type, sizeof (type)); + inet_ntop (AF_INET, &pn->path.origin.id, id, sizeof (id)); + inet_ntop (AF_INET, &pn->path.origin.adv_router, adv, sizeof (adv)); + ospf6_options_string (pn->path.capability, capa, sizeof (capa)); + + vty_out (vty, " Path:%s", VTY_NEWLINE); + vty_out (vty, " Associated Area: %s%s", area_id, VTY_NEWLINE); + vty_out (vty, " LS Origin: %s ID: %s Adv: %s%s", + type, id, adv, VTY_NEWLINE); + vty_out (vty, " Path Type: %s%s", + PTYPE_NAME (pn->path.type), VTY_NEWLINE); + vty_out (vty, " Metric Type: %d%s", + pn->path.metric_type, VTY_NEWLINE); + vty_out (vty, " Cost: Type-1: %lu Type-2: %lu%s", + (u_long) pn->path.cost, (u_long) pn->path.cost_e2, + VTY_NEWLINE); + vty_out (vty, " Router Bits: %s|%s|%s|%s%s", + (CHECK_FLAG (pn->path.router_bits, OSPF6_ROUTER_LSA_BIT_W) ? + "W" : "-"), + (CHECK_FLAG (pn->path.router_bits, OSPF6_ROUTER_LSA_BIT_V) ? + "V" : "-"), + (CHECK_FLAG (pn->path.router_bits, OSPF6_ROUTER_LSA_BIT_E) ? + "E" : "-"), + (CHECK_FLAG (pn->path.router_bits, OSPF6_ROUTER_LSA_BIT_B) ? + "B" : "-"), VTY_NEWLINE); + vty_out (vty, " Optional Capabilities: %s%s", capa, VTY_NEWLINE); + vty_out (vty, " Prefix Options: %s%s", "xxx", VTY_NEWLINE); + vty_out (vty, " Next Hops:%s", VTY_NEWLINE); + + for (linklist_head (pn->nexthop_list, &nnode); ! linklist_end (&nnode); + linklist_next (&nnode)) + { + nn = nnode.data; + + inet_ntop (AF_INET6, &nn->nexthop.address, nexthop, + sizeof (nexthop)); + if (! if_indextoname (nn->nexthop.ifindex, ifname)) + snprintf (ifname, sizeof (ifname), "%d", nn->nexthop.ifindex); + + vty_out (vty, " %c%s%%%s%s", + (HEAD ? '*' : ' '), nexthop, ifname, VTY_NEWLINE); + + nc++; + } + pc++; + } + vty_out (vty, "%s", VTY_NEWLINE); +} + +int +ospf6_route_table_show (struct vty *vty, int argc, char **argv, + struct ospf6_route_table *table) +{ + int i, ret; + unsigned long ret_ul; + char *endptr; + struct prefix prefix; + int detail = 0; + int arg_ipv6 = 0; + int arg_ipv4 = 0; + int arg_digit = 0; + struct prefix_ipv6 *p6 = (struct prefix_ipv6 *) &prefix; + struct prefix_ls *pl = (struct prefix_ls *) &prefix; + struct route_node *node; + + u_int route_count = 0; + u_int path_count = 0; + u_int route_redundant = 0; + + memset (&prefix, 0, sizeof (struct prefix)); + + for (i = 0; i < argc; i++) + { + if (! strcmp (argv[i], "detail")) + { + detail++; + break; + } + + if (! arg_ipv6 && ! arg_ipv4 && ! arg_digit) + { + + if ((ret = inet_pton (AF_INET6, argv[i], &p6->prefix)) == 1) + { + p6->family = AF_INET6; + p6->prefixlen = 128; + arg_ipv6++; + continue; + } + else if ((ret = inet_pton (AF_INET, argv[i], &pl->adv_router)) == 1) + { + pl->family = AF_UNSPEC; + pl->prefixlen = 64; /* xxx */ + arg_ipv4++; + continue; + } + else + { + ret_ul = strtoul (argv[i], &endptr, 10); + if (*endptr == '\0') + { + pl->adv_router.s_addr = htonl (ret_ul); + pl->family = AF_UNSPEC; + pl->prefixlen = 64; /* xxx */ + arg_digit++; + continue; + } + else + { + vty_out (vty, "Malformed argument: %s%s", + argv[i], VTY_NEWLINE); + return CMD_SUCCESS; + } + } + } + + if (arg_ipv4 || arg_digit) + { + if ((ret = inet_pton (AF_INET, argv[i], &pl->id)) == 1) + { + arg_ipv4++; + } + else + { + ret_ul = strtoul (argv[i], &endptr, 10); + if (*endptr == '\0') + { + pl->id.s_addr = htonl (ret_ul); + arg_digit++; + } + else + { + vty_out (vty, "Malformed argument: %s%s", + argv[i], VTY_NEWLINE); + return CMD_SUCCESS; + } + } + } + } + + if (arg_ipv4 || arg_ipv6 || arg_digit) + { + node = route_node_match (table->table, &prefix); + if (node && node->info) + ospf6_route_show_detail (vty, node->info); + return CMD_SUCCESS; + } + + if (! detail) + { + vty_out (vty, "%s%c%1s %2s %-30s %-25s %6s%s", VTY_NEWLINE, + ' ', " ", " ", "Destination", "Gateway", "I/F", VTY_NEWLINE); + vty_out (vty, "---------------------------%s", VTY_NEWLINE); + } + + for (node = route_top (table->table); node; node = route_next (node)) + { + struct ospf6_route_node *route = node->info; + + if (! route) + continue; + + if (detail) + ospf6_route_show_detail (vty, route); + else + ospf6_route_show (vty, route); + + route_count++; + path_count += route->path_list->count; + if (route->path_list->count > 1) + route_redundant++; + } + + vty_out (vty, "===========%s", VTY_NEWLINE); + vty_out (vty, "Route: %d Path: %d Redundant: %d%s", + route_count, path_count, route_redundant, VTY_NEWLINE); + + return CMD_SUCCESS; +} + diff --git a/ospf6d/ospf6_route.h b/ospf6d/ospf6_route.h new file mode 100644 index 000000000..71b2562b0 --- /dev/null +++ b/ospf6d/ospf6_route.h @@ -0,0 +1,209 @@ +/* + * Copyright (C) 1999 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF6_ROUTE_H +#define OSPF6_ROUTE_H + +#include "ospf6_hook.h" +#include "ospf6_linklist.h" + +struct ospf6_route_table +{ + char name[128]; + + int freeze; + + /* radix tree */ + struct route_table *table; + + /* list of hooks */ + struct linklist *hook_list[3]; + void (*hook_add) (void *); + void (*hook_change) (void *); + void (*hook_remove) (void *); + + u_int32_t route_id; +}; + + + +struct ospf6_route +{ + /* Destination ID */ + struct prefix prefix; + + /* Destination Type */ + u_char type; +}; + +/* Path */ +struct ls_origin +{ + u_int16_t type; + u_int32_t id; + u_int32_t adv_router; +}; + +struct ospf6_path +{ + /* Link State Origin */ + struct ls_origin origin; + + /* Router bits */ + u_char router_bits; + + /* Optional Capabilities */ + u_char capability[3]; + + /* Prefix Options */ + u_char prefix_options; + + /* Associated Area */ + u_int32_t area_id; + + /* Path-type */ + u_char type; + + /* Cost */ + u_int8_t metric_type; + u_int32_t cost; + u_int32_t cost_e2; +}; + +/* Nexthop */ +struct ospf6_nexthop +{ + /* Interface index */ + unsigned int ifindex; + + /* IP address, if any */ + struct in6_addr address; +}; + +struct ospf6_route_node +{ + struct ospf6_route_table *table; + int count; + u_int32_t route_id; + + struct route_node *route_node; + struct ospf6_route route; + struct linklist *path_list; +}; + +struct ospf6_path_node +{ + struct ospf6_route_node *route_node; + struct ospf6_path path; + struct linklist *nexthop_list; +}; + +struct ospf6_nexthop_node +{ + int flag; + struct timeval installed; + + struct ospf6_path_node *path_node; + struct ospf6_nexthop nexthop; +}; + +struct ospf6_route_req +{ + struct ospf6_route_table *table; + struct route_node *route_node; + struct linklist_node path_lnode; + struct linklist_node nexthop_lnode; + u_int32_t route_id; + + int count; + struct ospf6_route route; + struct ospf6_path path; + struct ospf6_nexthop nexthop; +}; + +#define OSPF6_DEST_TYPE_NONE 0 +#define OSPF6_DEST_TYPE_ROUTER 1 +#define OSPF6_DEST_TYPE_NETWORK 2 +#define OSPF6_DEST_TYPE_DISCARD 3 +#define OSPF6_DEST_TYPE_MAX 4 + +#define OSPF6_PATH_TYPE_NONE 0 +#define OSPF6_PATH_TYPE_INTRA 1 +#define OSPF6_PATH_TYPE_INTER 2 +#define OSPF6_PATH_TYPE_EXTERNAL1 3 +#define OSPF6_PATH_TYPE_EXTERNAL2 4 +#define OSPF6_PATH_TYPE_ZOFFSET 5 +#define OSPF6_PATH_TYPE_ZSYSTEM (OSPF6_PATH_TYPE_ZOFFSET + ZEBRA_ROUTE_SYSTEM) +#define OSPF6_PATH_TYPE_ZKERNEL (OSPF6_PATH_TYPE_ZOFFSET + ZEBRA_ROUTE_KERNEL) +#define OSPF6_PATH_TYPE_ZCONNECT (OSPF6_PATH_TYPE_ZOFFSET + ZEBRA_ROUTE_CONNECT) +#define OSPF6_PATH_TYPE_ZSTATIC (OSPF6_PATH_TYPE_ZOFFSET + ZEBRA_ROUTE_STATIC) +#define OSPF6_PATH_TYPE_ZRIP (OSPF6_PATH_TYPE_ZOFFSET + ZEBRA_ROUTE_RIP) +#define OSPF6_PATH_TYPE_ZRIPNG (OSPF6_PATH_TYPE_ZOFFSET + ZEBRA_ROUTE_RIPNG) +#define OSPF6_PATH_TYPE_ZOSPF (OSPF6_PATH_TYPE_ZOFFSET + ZEBRA_ROUTE_OSPF) +#define OSPF6_PATH_TYPE_ZOSPF6 (OSPF6_PATH_TYPE_ZOFFSET + ZEBRA_ROUTE_OSPF6) +#define OSPF6_PATH_TYPE_ZBGP (OSPF6_PATH_TYPE_ZOFFSET + ZEBRA_ROUTE_BGP) +#define OSPF6_PATH_TYPE_MAX (OSPF6_PATH_TYPE_ZOFFSET + ZEBRA_ROUTE_MAX) + +#define OSPF6_ROUTE_FLAG_ROUTE_CHANGE 0x01 +#define OSPF6_ROUTE_FLAG_PATH_CHANGE 0x02 +#define OSPF6_ROUTE_FLAG_ADD 0x04 +#define OSPF6_ROUTE_FLAG_REMOVE 0x08 +#define OSPF6_ROUTE_FLAG_CHANGE 0x10 + +int ospf6_route_lookup (struct ospf6_route_req *request, + struct prefix *prefix, + struct ospf6_route_table *table); +void ospf6_route_head (struct ospf6_route_req *request, + struct ospf6_route_table *table); +int ospf6_route_end (struct ospf6_route_req *request); +void ospf6_route_next (struct ospf6_route_req *request); + +void ospf6_route_add (struct ospf6_route_req *, struct ospf6_route_table *); +void ospf6_route_remove (struct ospf6_route_req *, struct ospf6_route_table *); +void ospf6_route_remove_all (struct ospf6_route_table *); + +struct ospf6_route_table *ospf6_route_table_create (); +void ospf6_route_table_delete (struct ospf6_route_table *); + +void ospf6_route_table_freeze (struct ospf6_route_table *); +void ospf6_route_table_thaw (struct ospf6_route_table *); + +void ospf6_route_log_request (char *what, char *where, + struct ospf6_route_req *request); + +void +ospf6_route_hook_register (void (*add) (struct ospf6_route_req *), + void (*change) (struct ospf6_route_req *), + void (*remove) (struct ospf6_route_req *), + struct ospf6_route_table *table); +void +ospf6_route_hook_unregister (void (*add) (struct ospf6_route_req *), + void (*change) (struct ospf6_route_req *), + void (*remove) (struct ospf6_route_req *), + struct ospf6_route_table *table); + +void ospf6_route_init (); + +int ospf6_route_table_show (struct vty *, int, char **, + struct ospf6_route_table *); + +#endif /* OSPF6_ROUTE_H */ + diff --git a/ospf6d/ospf6_routemap.c b/ospf6d/ospf6_routemap.c new file mode 100644 index 000000000..14df7940c --- /dev/null +++ b/ospf6d/ospf6_routemap.c @@ -0,0 +1,359 @@ +/* + * OSPFv3 Route-Map + * Copyright (C) 1999 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <zebra.h> + +#include "log.h" +#include "memory.h" +#include "linklist.h" +#include "prefix.h" +#include "command.h" +#include "vty.h" +#include "routemap.h" +#include "table.h" +#include "plist.h" + +#include "ospf6_route.h" +#include "ospf6_prefix.h" +#include "ospf6_lsa.h" +#include "ospf6_asbr.h" + +route_map_result_t +ospf6_routemap_rule_match_address_prefixlist (void *rule, + struct prefix *prefix, + route_map_object_t type, + void *object) +{ + struct prefix_list *plist; + + if (type != RMAP_OSPF6) + return RMAP_NOMATCH; + + plist = prefix_list_lookup (AFI_IP6, (char *) rule); + + if (plist == NULL) + return RMAP_NOMATCH; + + return (prefix_list_apply (plist, prefix) == PREFIX_DENY ? + RMAP_NOMATCH : RMAP_MATCH); +} + +void * +ospf6_routemap_rule_match_address_prefixlist_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +void +ospf6_routemap_rule_match_address_prefixlist_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd +ospf6_routemap_rule_match_address_prefixlist_cmd = +{ + "ipv6 address prefix-list", + ospf6_routemap_rule_match_address_prefixlist, + ospf6_routemap_rule_match_address_prefixlist_compile, + ospf6_routemap_rule_match_address_prefixlist_free, +}; + +route_map_result_t +ospf6_routemap_rule_set_metric_type (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + char *metric_type = rule; + struct ospf6_external_info *info = object; + + if (type != RMAP_OSPF6) + return RMAP_OKAY; + + if (strcmp (metric_type, "type-2") == 0) + info->metric_type = 2; + else + info->metric_type = 1; + + return RMAP_OKAY; +} + +void * +ospf6_routemap_rule_set_metric_type_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +void +ospf6_routemap_rule_set_metric_type_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd +ospf6_routemap_rule_set_metric_type_cmd = +{ + "metric-type", + ospf6_routemap_rule_set_metric_type, + ospf6_routemap_rule_set_metric_type_compile, + ospf6_routemap_rule_set_metric_type_free, +}; + +route_map_result_t +ospf6_routemap_rule_set_metric (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + char *metric = rule; + struct ospf6_external_info *info = object; + + if (type != RMAP_OSPF6) + return RMAP_OKAY; + + info->metric = atoi (metric); + return RMAP_OKAY; +} + +void * +ospf6_routemap_rule_set_metric_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +void +ospf6_routemap_rule_set_metric_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd +ospf6_routemap_rule_set_metric_cmd = +{ + "metric", + ospf6_routemap_rule_set_metric, + ospf6_routemap_rule_set_metric_compile, + ospf6_routemap_rule_set_metric_free, +}; + +route_map_result_t +ospf6_routemap_rule_set_forwarding (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + char *forwarding = rule; + struct ospf6_external_info *info = object; + + if (type != RMAP_OSPF6) + return RMAP_OKAY; + + if (inet_pton (AF_INET6, forwarding, &info->forwarding) != 1) + { + memset (&info->forwarding, 0, sizeof (struct in6_addr)); + return RMAP_ERROR; + } + + return RMAP_OKAY; +} + +void * +ospf6_routemap_rule_set_forwarding_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +void +ospf6_routemap_rule_set_forwarding_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd +ospf6_routemap_rule_set_forwarding_cmd = +{ + "forwarding-address", + ospf6_routemap_rule_set_forwarding, + ospf6_routemap_rule_set_forwarding_compile, + ospf6_routemap_rule_set_forwarding_free, +}; + +int +route_map_command_status (struct vty *vty, int ret) +{ + if (! ret) + return CMD_SUCCESS; + + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "Can't find rule.%s", VTY_NEWLINE); + break; + case RMAP_COMPILE_ERROR: + vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE); + break; + default: + vty_out (vty, "route-map add set failed.%s", VTY_NEWLINE); + break; + } + return CMD_WARNING; +} + +/* add "match address" */ +DEFUN (ospf6_routemap_match_address_prefixlist, + ospf6_routemap_match_address_prefixlist_cmd, + "match ipv6 address prefix-list WORD", + "Match values\n" + IPV6_STR + "Match address of route\n" + "Match entries of prefix-lists\n" + "IPv6 prefix-list name\n") +{ + int ret = route_map_add_match ((struct route_map_index *) vty->index, + "ipv6 address prefix-list", argv[0]); + return route_map_command_status (vty, ret); +} + +/* delete "match address" */ +DEFUN (ospf6_routemap_no_match_address_prefixlist, + ospf6_routemap_no_match_address_prefixlist_cmd, + "no match ipv6 address prefix-list WORD", + NO_STR + "Match values\n" + IPV6_STR + "Match address of route\n" + "Match entries of prefix-lists\n" + "IPv6 prefix-list name\n") +{ + int ret = route_map_delete_match ((struct route_map_index *) vty->index, + "ipv6 address prefix-list", argv[0]); + return route_map_command_status (vty, ret); +} + +/* add "set metric-type" */ +DEFUN (ospf6_routemap_set_metric_type, + ospf6_routemap_set_metric_type_cmd, + "set metric-type (type-1|type-2)", + "Set value\n" + "Type of metric\n" + "OSPF6 external type 1 metric\n" + "OSPF6 external type 2 metric\n") +{ + int ret = route_map_add_set ((struct route_map_index *) vty->index, + "metric-type", argv[0]); + return route_map_command_status (vty, ret); +} + +/* delete "set metric-type" */ +DEFUN (ospf6_routemap_no_set_metric_type, + ospf6_routemap_no_set_metric_type_cmd, + "no set metric-type (type-1|type-2)", + NO_STR + "Set value\n" + "Type of metric\n" + "OSPF6 external type 1 metric\n" + "OSPF6 external type 2 metric\n") +{ + int ret = route_map_delete_set ((struct route_map_index *) vty->index, + "metric-type", argv[0]); + return route_map_command_status (vty, ret); +} + +/* add "set metric" */ +DEFUN (set_metric, + set_metric_cmd, + "set metric <0-4294967295>", + "Set value\n" + "Metric value\n" + "Metric value\n") +{ + int ret = route_map_add_set ((struct route_map_index *) vty->index, + "metric", argv[0]); + return route_map_command_status (vty, ret); +} + +/* delete "set metric" */ +DEFUN (no_set_metric, + no_set_metric_cmd, + "no set metric <0-4294967295>", + NO_STR + "Set value\n" + "Metric\n" + "METRIC value\n") +{ + int ret = route_map_delete_set ((struct route_map_index *) vty->index, + "metric", argv[0]); + return route_map_command_status (vty, ret); +} + +/* add "set forwarding-address" */ +DEFUN (ospf6_routemap_set_forwarding, + ospf6_routemap_set_forwarding_cmd, + "set forwarding-address X:X::X:X", + "Set value\n" + "Forwarding Address\n" + "IPv6 Address\n") +{ + int ret = route_map_add_set ((struct route_map_index *) vty->index, + "forwarding-address", argv[0]); + return route_map_command_status (vty, ret); +} + +/* delete "set forwarding-address" */ +DEFUN (ospf6_routemap_no_set_forwarding, + ospf6_routemap_no_set_forwarding_cmd, + "no set forwarding-address X:X::X:X", + NO_STR + "Set value\n" + "Forwarding Address\n" + "IPv6 Address\n") +{ + int ret = route_map_delete_set ((struct route_map_index *) vty->index, + "forwarding-address", argv[0]); + return route_map_command_status (vty, ret); +} + +void +ospf6_routemap_init () +{ + route_map_init (); + route_map_init_vty (); + route_map_add_hook (ospf6_asbr_routemap_update); + route_map_delete_hook (ospf6_asbr_routemap_update); + + route_map_install_match (&ospf6_routemap_rule_match_address_prefixlist_cmd); + route_map_install_set (&ospf6_routemap_rule_set_metric_type_cmd); + route_map_install_set (&ospf6_routemap_rule_set_metric_cmd); + route_map_install_set (&ospf6_routemap_rule_set_forwarding_cmd); + + /* Match address prefix-list */ + install_element (RMAP_NODE, &ospf6_routemap_match_address_prefixlist_cmd); + install_element (RMAP_NODE, &ospf6_routemap_no_match_address_prefixlist_cmd); + + /* ASE Metric Type (e.g. Type-1/Type-2) */ + install_element (RMAP_NODE, &ospf6_routemap_set_metric_type_cmd); + install_element (RMAP_NODE, &ospf6_routemap_no_set_metric_type_cmd); + + /* ASE Metric */ + install_element (RMAP_NODE, &set_metric_cmd); + install_element (RMAP_NODE, &no_set_metric_cmd); + + /* ASE Metric */ + install_element (RMAP_NODE, &ospf6_routemap_set_forwarding_cmd); + install_element (RMAP_NODE, &ospf6_routemap_no_set_forwarding_cmd); +} + diff --git a/ospf6d/ospf6_routemap.h b/ospf6d/ospf6_routemap.h new file mode 100644 index 000000000..c68e0ffc0 --- /dev/null +++ b/ospf6d/ospf6_routemap.h @@ -0,0 +1,27 @@ +/* + * OSPFv3 Route-Map + * Copyright (C) 2000 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF6_ROUTEMAP_H + +void ospf6_routemap_init (); + +#endif /* OSPF6_ROUTEMAP_H */ diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c new file mode 100644 index 000000000..fd7fc7798 --- /dev/null +++ b/ospf6d/ospf6_spf.c @@ -0,0 +1,1454 @@ +/* + * Copyright (C) 1999 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +/* Shortest Path First calculation for OSPFv3 */ + +#include "ospf6d.h" + +#include "linklist.h" +#include "prefix.h" +#include "table.h" + +#include "ospf6_proto.h" +#include "ospf6_lsa.h" +#include "ospf6_lsdb.h" +#include "ospf6_route.h" +#include "ospf6_spf.h" +#include "ospf6_neighbor.h" +#include "ospf6_interface.h" +#include "ospf6_area.h" + +#include "ospf6_bintree.h" +#include "ospf6_linklist.h" + +struct bintree *_candidate_list; +struct linklist *nexthop_list; + +struct ospf6_spf_candidate_node +{ + u_int32_t cost; + struct linklist *list; +}; + +int +ospf6_spf_candidate_node_cmp (void *a, void *b) +{ + struct ospf6_spf_candidate_node *ca = a; + struct ospf6_spf_candidate_node *cb = b; + return ca->cost - cb->cost; +} + +int +ospf6_spf_vertex_cmp (void *a, void *b) +{ + return 1; +} + +void +ospf6_spf_candidate_node_print (int indent_num, void *node) +{ + struct ospf6_spf_candidate_node *cn = node; + char format[256]; + + snprintf (format, sizeof (format), "%%%ds %%d (num: %%d)", + indent_num * 2 + 1); + zlog_info (format, " ", cn->cost, cn->list->count); +} + +void +ospf6_spf_candidate_init () +{ + _candidate_list = bintree_create (); + _candidate_list->cmp = ospf6_spf_candidate_node_cmp; +} + +u_int32_t +ospf6_spf_candidate_count () +{ + u_int32_t count = 0; + struct bintree_node node; + struct ospf6_spf_candidate_node *cnode; + + for (bintree_head (_candidate_list, &node); ! bintree_end (&node); + bintree_next (&node)) + { + cnode = node.data; + count += cnode->list->count; + } + + return count; +} + +void +ospf6_spf_candidate_print () +{ + zlog_info ("---------------------------"); + bintree_print (ospf6_spf_candidate_node_print, _candidate_list); + zlog_info ("---------------------------"); +} + +void +ospf6_spf_candidate_enqueue (struct ospf6_vertex *v) +{ + struct ospf6_spf_candidate_node req, *node; + + memset (&req, 0, sizeof (req)); + req.cost = v->distance; + node = bintree_lookup (&req, _candidate_list); + + if (node == NULL) + { + node = malloc (sizeof (struct ospf6_spf_candidate_node)); + node->cost = v->distance; + node->list = linklist_create (); + node->list->cmp = ospf6_spf_vertex_cmp; + bintree_add (node, _candidate_list); + } + + linklist_add (v, node->list); + +#if 0 + if (IS_OSPF6_DUMP_SPF) + ospf6_spf_candidate_print (); +#endif +} + +struct ospf6_vertex * +ospf6_spf_candidate_dequeue () +{ + struct ospf6_spf_candidate_node *node; + struct linklist_node lnode; + struct ospf6_vertex *ret; + + node = bintree_lookup_min (_candidate_list); + if (node == NULL) + return NULL; + + linklist_head (node->list, &lnode); + ret = lnode.data; + + linklist_remove (ret, node->list); + if (node->list->count == 0) + { + linklist_delete (node->list); + bintree_remove (node, _candidate_list); + } + +#if 0 + if (IS_OSPF6_DUMP_SPF) + ospf6_spf_candidate_print (); +#endif + + return ret; +} + +void +ospf6_spf_candidate_remove (struct ospf6_vertex *v) +{ + struct bintree_node node; + struct ospf6_spf_candidate_node *cnode = NULL; + + for (bintree_head (_candidate_list, &node); ! bintree_end (&node); + bintree_next (&node)) + { + cnode = node.data; + if (linklist_lookup (v, cnode->list)) + { + linklist_remove (v, cnode->list); + break; + } + } + + if (cnode->list->count == 0) + { + linklist_delete (cnode->list); + bintree_remove (cnode, _candidate_list); + } +} + + +#define TIMER_SEC_MICRO 1000000 + +/* timeval calculation */ +static void +ospf6_timeval_add (const struct timeval *t1, const struct timeval *t2, + struct timeval *result) +{ + long moveup = 0; + + result->tv_usec = t1->tv_usec + t2->tv_usec; + while (result->tv_usec > TIMER_SEC_MICRO) + { + result->tv_usec -= TIMER_SEC_MICRO; + moveup ++; + } + + result->tv_sec = t1->tv_sec + t2->tv_sec + moveup; +} + +static void +ospf6_timeval_add_equal (const struct timeval *t, struct timeval *result) +{ + struct timeval tmp; + ospf6_timeval_add (t, result, &tmp); + result->tv_sec = tmp.tv_sec; + result->tv_usec = tmp.tv_usec; +} + +/* Compare timeval a and b. It returns an integer less than, equal + to, or great than zero if a is found, respectively, to be less + than, to match, or be greater than b. */ +static int +ospf6_timeval_cmp (const struct timeval t1, const struct timeval t2) +{ + return (t1.tv_sec == t2.tv_sec + ? t1.tv_usec - t2.tv_usec : t1.tv_sec - t2.tv_sec); +} + + +static int +ospf6_spf_lsd_num (struct ospf6_vertex *V, struct ospf6_area *o6a) +{ + u_int16_t type; + u_int32_t id, adv_router; + struct ospf6_lsa *lsa; + + if (V->vertex_id.id.s_addr) + type = htons (OSPF6_LSA_TYPE_NETWORK); + else + type = htons (OSPF6_LSA_TYPE_ROUTER); + id = V->vertex_id.id.s_addr; + adv_router = V->vertex_id.adv_router.s_addr; + + lsa = ospf6_lsdb_lookup_lsdb (type, id, adv_router, o6a->lsdb); + if (! lsa) + { + zlog_err ("SPF: Can't find associated LSA for %s", V->string); + return 0; + } + + return ospf6_lsa_lsd_num ((struct ospf6_lsa_header *) lsa->header); +} + +/* RFC2328 section 16.1.1: + Check if there is at least one router in the path + from the root to this vertex. */ +static int +ospf6_spf_is_router_to_root (struct ospf6_vertex *c, + struct ospf6_spftree *spf_tree) +{ + listnode node; + struct ospf6_vertex *p; + + if (spf_tree->root == c) + return 0; + + for (node = listhead (c->parent_list); node; nextnode (node)) + { + p = (struct ospf6_vertex *) getdata (node); + + if (p == spf_tree->root) + return 0; + + if (p->vertex_id.id.s_addr == 0) /* this is router */ + continue; + else if (ospf6_spf_is_router_to_root (p, spf_tree)) + continue; + + return 0; + } + + return 1; +} + +static struct in6_addr * +ospf6_spf_get_ipaddr (u_int32_t id, u_int32_t adv_router, u_int32_t ifindex) +{ + char buf[64], nhbuf[64]; + struct ospf6_interface *o6i; + struct ospf6_neighbor *o6n; + struct ospf6_lsa *lsa; + struct ospf6_lsdb_node node; + + o6i = ospf6_interface_lookup_by_index (ifindex); + if (! o6i) + { + zlog_err ("SPF: Can't find interface: index %d", ifindex); + return (struct in6_addr *) NULL; + } + + /* Find Link-LSA of the vertex in question */ + lsa = NULL; + for (ospf6_lsdb_type_router (&node, htons (OSPF6_LSA_TYPE_LINK), + adv_router, o6i->lsdb); + ! ospf6_lsdb_is_end (&node); + ospf6_lsdb_next (&node)) + lsa = node.lsa; + + /* return Linklocal Address field if the Link-LSA exists */ + if (lsa && lsa->header->adv_router == adv_router) + { + struct ospf6_link_lsa *link_lsa; + link_lsa = (struct ospf6_link_lsa *) (lsa->header + 1); + return &link_lsa->llsa_linklocal; + } + + zlog_warn ("SPF: Can't find Link-LSA for %s", + inet_ntop (AF_INET, &adv_router, buf, sizeof (buf))); + + o6n = ospf6_neighbor_lookup (adv_router, o6i); + if (! o6n) + { + inet_ntop (AF_INET, &adv_router, buf, sizeof (buf)); + zlog_err ("SPF: Can't find neighbor %s in %s, " + "unable to find his linklocal address", + buf, o6i->interface->name); + return (struct in6_addr *) NULL; + } + + zlog_warn ("SPF: use packet's source address for %s's nexthop: %s", + inet_ntop (AF_INET, &adv_router, buf, sizeof (buf)), + inet_ntop (AF_INET6, &o6n->hisaddr, nhbuf, sizeof (nhbuf))); + + return &o6n->hisaddr; +} + +static int +ospf6_spf_nexthop_calculation (struct ospf6_vertex *W, + u_int32_t ifindex, + struct ospf6_vertex *V, + struct ospf6_spftree *spf_tree) +{ + struct ospf6_nexthop *nexthop, *n; + u_int32_t adv_router, id; + struct in6_addr nexthop_ipaddr, *ipaddr; + unsigned int nexthop_ifindex; + struct linklist_node node; + + /* until this, nexthop_list should be untouched */ + assert (list_isempty (W->nexthop_list)); + + /* If ther is at least one intervening router from root to W */ + if (ospf6_spf_is_router_to_root (W, spf_tree)) + { + /* Create no new nexthop, Inherit from the intervening router */ + for (linklist_head (V->nexthop_list, &node); ! linklist_end (&node); + linklist_next (&node)) + linklist_add (node.data, W->nexthop_list); + return 0; + } + + /* Create new nexthop */ + + adv_router = W->vertex_id.adv_router.s_addr; + id = W->vertex_id.id.s_addr; + + nexthop_ifindex = 0; + memset (&nexthop_ipaddr, 0, sizeof (struct in6_addr)); + if (spf_tree->root && V == spf_tree->root) + { + nexthop_ifindex = ifindex; + if (! id) /* xxx, if V is router */ + { + ipaddr = ospf6_spf_get_ipaddr (id, adv_router, ifindex); + if (! ipaddr) + { + /* xxx, should trigger error and quit SPF calculation... */ + memset (&nexthop_ipaddr, 0xff, sizeof (struct in6_addr)); + return -1; + } + else + memcpy (&nexthop_ipaddr, ipaddr, sizeof (struct in6_addr)); + } + } + else + { + /* V is broadcast network, W is router */ + assert (V->vertex_id.id.s_addr != 0); + assert (W->vertex_id.id.s_addr == 0); + + linklist_head (V->nexthop_list, &node); + n = (struct ospf6_nexthop *) node.data; + nexthop_ifindex = n->ifindex; + ipaddr = ospf6_spf_get_ipaddr (id, adv_router, n->ifindex); + if (! ipaddr) + { + /* xxx, should trigger error and quit SPF calculation... */ + memset (&nexthop_ipaddr, 0xff, sizeof (struct in6_addr)); + return -1; + } + else + memcpy (&nexthop_ipaddr, ipaddr, sizeof (struct in6_addr)); + } + + nexthop = XCALLOC (MTYPE_OSPF6_VERTEX, sizeof (struct ospf6_nexthop)); + nexthop->ifindex = nexthop_ifindex; + memcpy (&nexthop->address, &nexthop_ipaddr, sizeof (nexthop->address)); + + linklist_add (nexthop, W->nexthop_list); + + /* to hold malloced memory */ + linklist_add (nexthop, nexthop_list); + + return 0; +} + +static struct ospf6_vertex * +ospf6_spf_vertex_create (int index, struct ospf6_vertex *V, + struct ospf6_area *o6a) +{ + struct ospf6_lsa *lsa; + struct ospf6_router_lsa *router_lsa; + struct ospf6_router_lsd *router_lsd; + struct ospf6_network_lsa *network_lsa; + struct ospf6_network_lsd *network_lsd; + u_int32_t id, adv_router; + u_int16_t type; + void *lsd; + struct ospf6_vertex *W; + u_int16_t distance; + u_int32_t ifindex; + int backreference, lsdnum, i; + char buf_router[16], buf_id[16]; + + type = id = adv_router = 0; + + /* Get Linkstate description */ + lsd = ospf6_lsa_lsd_get (index, (struct ospf6_lsa_header *) V->lsa->header); + if (! lsd) + { + zlog_err ("SPF: Can't find %dth Link description from %s", + index, V->lsa->str); + return (struct ospf6_vertex *) NULL; + } + + /* Check Link state description */ + distance = 0; + ifindex = 0; + if (V->lsa->header->type == htons (OSPF6_LSA_TYPE_ROUTER)) + { + router_lsd = lsd; + if (router_lsd->type == OSPF6_ROUTER_LSD_TYPE_POINTTOPOINT) + { + type = htons (OSPF6_LSA_TYPE_ROUTER); + id = htonl (0); + } + else if (router_lsd->type == OSPF6_ROUTER_LSD_TYPE_TRANSIT_NETWORK) + { + type = htons (OSPF6_LSA_TYPE_NETWORK); + id = router_lsd->neighbor_interface_id; + } + adv_router = router_lsd->neighbor_router_id; + distance = ntohs (router_lsd->metric); + ifindex = ntohl (router_lsd->interface_id); + } + else if (V->lsa->header->type == htons (OSPF6_LSA_TYPE_NETWORK)) + { + network_lsd = lsd; + type = htons (OSPF6_LSA_TYPE_ROUTER); + id = htonl (0); + adv_router = network_lsd->adv_router; + } + + /* Avoid creating candidate of myself */ + if (adv_router == o6a->ospf6->router_id && + type == htons (OSPF6_LSA_TYPE_ROUTER)) + { + return (struct ospf6_vertex *) NULL; + } + + /* Find Associated LSA for W */ + lsa = ospf6_lsdb_lookup_lsdb (type, id, adv_router, o6a->lsdb); + + if (! lsa) + { + inet_ntop (AF_INET, &adv_router, buf_router, sizeof (buf_router)); + inet_ntop (AF_INET, &id, buf_id, sizeof (buf_id)); + + if (IS_OSPF6_DUMP_SPF) + { + if (type == htons (OSPF6_LSA_TYPE_ROUTER)) + zlog_info ("SPF: Can't find LSA for W (%s *): not found", + buf_router); + else + zlog_info ("SPF: Can't find LSA for W (%s %s): not found", + buf_router, buf_id); + } + return (struct ospf6_vertex *) NULL; + } + + if (IS_LSA_MAXAGE (lsa)) + { + if (IS_OSPF6_DUMP_SPF) + zlog_info ("SPF: Associated LSA for W is MaxAge: %s", lsa->str); + return (struct ospf6_vertex *) NULL; + } + + /* Check back reference from W's lsa to V's lsa */ + backreference = 0; + lsdnum = ospf6_lsa_lsd_num ((struct ospf6_lsa_header *) lsa->header); + for (i = 0; i < lsdnum; i++) + { + if (ospf6_lsa_lsd_is_refer_ok (i, (struct ospf6_lsa_header *) lsa->header, + index, (struct ospf6_lsa_header *) V->lsa->header)) + backreference++; + } + if (! backreference) + { + if (IS_OSPF6_DUMP_SPF) + zlog_info ("SPF: Back reference failed: V: %s, W: %s", + V->lsa->str, lsa->str); + return (struct ospf6_vertex *) NULL; + } + + /* Allocate new ospf6_vertex for W */ + W = (struct ospf6_vertex *) XMALLOC (MTYPE_OSPF6_VERTEX, + sizeof (struct ospf6_vertex)); + if (! W) + { + zlog_err ("SPF: Can't allocate memory for Vertex"); + return (struct ospf6_vertex *) NULL; + } + memset (W, 0, sizeof (struct ospf6_vertex)); + + /* Initialize */ + W->vertex_id.family = AF_UNSPEC; + W->vertex_id.prefixlen = 64; /* xxx */ + W->lsa = lsa; + if (type == htons (OSPF6_LSA_TYPE_ROUTER)) + W->vertex_id.id.s_addr = htonl (0); /* XXX */ + else + W->vertex_id.id.s_addr = W->lsa->header->id; + W->vertex_id.adv_router.s_addr = W->lsa->header->adv_router; + W->nexthop_list = linklist_create (); + W->path_list = list_new (); + W->parent_list = list_new (); + W->distance = V->distance + distance; + W->depth = V->depth + 1; + + inet_ntop (AF_INET, &W->vertex_id.adv_router.s_addr, + buf_router, sizeof (buf_router)); + inet_ntop (AF_INET, &W->vertex_id.id.s_addr, buf_id, sizeof (buf_id)); + snprintf (W->string, sizeof (W->string), "[%s-%s (%d)]", + buf_router, buf_id, W->distance); + + /* capability bits and optional capabilities */ + if (W->vertex_id.id.s_addr == 0) + { + router_lsa = (struct ospf6_router_lsa *) (W->lsa->header + 1); + W->capability_bits = router_lsa->bits; + memcpy (W->opt_capability, router_lsa->options, + sizeof (W->opt_capability)); + } + else + { + network_lsa = (struct ospf6_network_lsa *) (W->lsa->header + 1); + W->capability_bits = network_lsa->reserved; + memcpy (W->opt_capability, network_lsa->options, + sizeof (W->opt_capability)); + } + + /* Link to Parent node */ + listnode_add (W->parent_list, V); + + /* Nexthop Calculation */ + if (ospf6_spf_nexthop_calculation (W, ifindex, V, o6a->spf_tree) < 0) + return NULL; + + return W; +} + +static void +ospf6_spf_vertex_delete (struct ospf6_vertex *v) +{ + linklist_delete (v->nexthop_list); + list_delete (v->path_list); + list_delete (v->parent_list); + XFREE (MTYPE_OSPF6_VERTEX, v); +} + +static void +ospf6_spf_vertex_merge (struct ospf6_vertex *w, struct ospf6_vertex *x) +{ + listnode node; + struct linklist_node lnode; + + /* merge should be done on two nodes which are + almost the same */ + + /* these w and x should be both candidate. + candidate should not have any children */ + assert (list_isempty (w->path_list)); + assert (list_isempty (x->path_list)); + + /* merge parent list */ + for (node = listhead (w->parent_list); node; nextnode (node)) + { + if (listnode_lookup (x->parent_list, getdata (node))) + continue; + listnode_add (x->parent_list, getdata (node)); + } + + /* merge nexthop list */ + for (linklist_head (w->nexthop_list, &lnode); ! linklist_end (&lnode); + linklist_next (&lnode)) + linklist_add (lnode.data, x->nexthop_list); +} + +static void +ospf6_spf_initialize (list candidate_list, struct ospf6_area *o6a) +{ + listnode node; + struct ospf6_vertex *v; + struct ospf6_lsa *lsa; + u_int16_t type; + u_int32_t id, adv_router; + struct linklist_node lnode; + + struct ospf6_nexthop *nexthop; + struct interface *ifp; + char buf_router[64], buf_id[64]; + + /* delete topology routing table for this area */ + ospf6_route_remove_all (o6a->table_topology); + + /* Delete previous spf tree */ + for (node = listhead (o6a->spf_tree->list); node; nextnode (node)) + { + v = (struct ospf6_vertex *) getdata (node); + ospf6_spf_vertex_delete (v); + } + list_delete_all_node (o6a->spf_tree->list); + + for (linklist_head (nexthop_list, &lnode); ! linklist_end (&lnode); + linklist_next (&lnode)) + XFREE (MTYPE_OSPF6_VERTEX, lnode.data); + linklist_remove_all (nexthop_list); + + /* Find self originated Router-LSA */ + type = htons (OSPF6_LSA_TYPE_ROUTER); + id = htonl (0); + adv_router = ospf6->router_id; + + lsa = ospf6_lsdb_lookup_lsdb (type, id, adv_router, o6a->lsdb); + + if (! lsa) + { + if (IS_OSPF6_DUMP_SPF) + zlog_info ("SPF: Can't find self originated Router-LSA"); + return; + } + if (IS_LSA_MAXAGE (lsa)) + { + zlog_err ("SPF: MaxAge self originated Router-LSA"); + return; + } + + /* Create root vertex */ + v = (struct ospf6_vertex *) XMALLOC (MTYPE_OSPF6_VERTEX, + sizeof (struct ospf6_vertex)); + if (! v) + { + zlog_err ("SPF: Can't allocate memory for root vertex"); + return; + } + memset (v, 0, sizeof (struct ospf6_vertex)); + + v->vertex_id.family = AF_UNSPEC; /* XXX */ + v->vertex_id.prefixlen = 64; /* XXX */ + v->vertex_id.id.s_addr = htonl (0); + v->vertex_id.adv_router.s_addr = ospf6->router_id; + if (ospf6_is_asbr (ospf6)) + OSPF6_OPT_SET (v->opt_capability, OSPF6_OPT_E); + OSPF6_OPT_SET (v->opt_capability, OSPF6_OPT_V6); + OSPF6_OPT_SET (v->opt_capability, OSPF6_OPT_R); + v->nexthop_list = linklist_create (); + v->path_list = list_new (); + v->parent_list = list_new (); + v->distance = 0; + v->depth = 0; + v->lsa = lsa; + + inet_ntop (AF_INET, &v->vertex_id.adv_router.s_addr, + buf_router, sizeof (buf_router)); + inet_ntop (AF_INET, &v->vertex_id.id.s_addr, buf_id, sizeof (buf_id)); + snprintf (v->string, sizeof (v->string), "[%s-%s (%d)]", + buf_router, buf_id, v->distance); + + nexthop = XCALLOC (MTYPE_OSPF6_VERTEX, sizeof (struct ospf6_nexthop)); + ifp = if_lookup_by_name ("lo0"); + if (ifp) + nexthop->ifindex = ifp->ifindex; + inet_pton (AF_INET6, "::1", &nexthop->address); + linklist_add (nexthop, v->nexthop_list); + linklist_add (nexthop, nexthop_list); + + o6a->spf_tree->root = v; + listnode_add (candidate_list, v); + + ospf6_spf_candidate_enqueue (v); +} + +static struct ospf6_vertex * +ospf6_spf_get_closest_candidate (list candidate_list) +{ + listnode node; + struct ospf6_vertex *candidate, *closest; + + closest = (struct ospf6_vertex *) NULL; + for (node = listhead (candidate_list); node; nextnode (node)) + { + candidate = (struct ospf6_vertex *) getdata (node); + + if (closest && candidate->distance > closest->distance) + continue; + + /* always choose network vertices if those're the same cost */ + if (closest && candidate->distance == closest->distance + && closest->vertex_id.id.s_addr != 0) + continue; + + closest = candidate; + } + + return closest; +} + +static struct ospf6_vertex * +ospf6_spf_get_same_candidate (struct ospf6_vertex *w, list candidate_list) +{ + listnode node; + struct ospf6_vertex *c, *same; + + same = (struct ospf6_vertex *) NULL; + for (node = listhead (candidate_list); node; nextnode (node)) + { + c = (struct ospf6_vertex *) getdata (node); + if (w->vertex_id.adv_router.s_addr != c->vertex_id.adv_router.s_addr) + continue; + if (w->vertex_id.id.s_addr != c->vertex_id.id.s_addr) + continue; + + if (same) + zlog_warn ("SPF: duplicate candidates in candidate_list"); + + same = c; + } + + return same; +} + +static void +ospf6_spf_install (struct ospf6_vertex *vertex, struct ospf6_area *o6a) +{ + listnode node; + struct ospf6_vertex *parent; + struct ospf6_nexthop *nexthop; + struct ospf6_route_req request; + struct linklist_node lnode; + + struct ospf6_router_lsa *router_lsa; + struct ospf6_network_lsa *network_lsa; + + router_lsa = OSPF6_LSA_HEADER_END (vertex->lsa->header); + network_lsa = OSPF6_LSA_HEADER_END (vertex->lsa->header); + + if (IS_OSPF6_DUMP_SPF) + { + zlog_info ("SPF: Install: %s", vertex->string); + } + + listnode_add (o6a->spf_tree->list, vertex); + + for (node = listhead (vertex->parent_list); node; nextnode (node)) + { + parent = (struct ospf6_vertex *) getdata (node); + listnode_add (parent->path_list, vertex); + vertex->depth = parent->depth + 1; + } + +#if 0 + if (vertex == o6a->spf_tree->root) + return; +#endif /*0*/ + + /* install route to topology table */ + memset (&request, 0, sizeof (request)); + if (vertex->vertex_id.id.s_addr) /* xxx */ + request.route.type = OSPF6_DEST_TYPE_NETWORK; + else + request.route.type = OSPF6_DEST_TYPE_ROUTER; + memcpy (&request.route.prefix, &vertex->vertex_id, + sizeof (struct prefix)); + + request.path.area_id = o6a->area_id; + request.path.type = OSPF6_PATH_TYPE_INTRA; + request.path.cost = vertex->distance; + request.path.cost_e2 = 0; + request.path.origin.type = vertex->lsa->header->type; + request.path.origin.id = vertex->lsa->header->id; + request.path.origin.adv_router = vertex->lsa->header->adv_router; + if (vertex->lsa->header->type == htons (OSPF6_LSA_TYPE_ROUTER)) + request.path.router_bits = router_lsa->bits; + memcpy (&request.path.capability, vertex->opt_capability, + sizeof (request.path.capability)); + +#if 0 + if (IS_OSPF6_DUMP_SPF) + zlog_info ("SPF: install %d nexthops for %s", + listcount (vertex->nexthop_list), vertex->string); +#endif + + for (linklist_head (vertex->nexthop_list, &lnode); ! linklist_end (&lnode); + linklist_next (&lnode)) + { + nexthop = lnode.data; + + request.nexthop.ifindex = nexthop->ifindex; + memcpy (&request.nexthop.address, &nexthop->address, + sizeof (request.nexthop.address)); + + ospf6_route_add (&request, o6a->table_topology); + } +} + +struct ospf6_vertex * +ospf6_spf_lookup (struct ospf6_vertex *w, struct ospf6_area *o6a) +{ + listnode node; + struct ospf6_vertex *v; + + for (node = listhead (o6a->spf_tree->list); node; nextnode (node)) + { + v = (struct ospf6_vertex *) getdata (node); + + if (w->vertex_id.adv_router.s_addr != v->vertex_id.adv_router.s_addr) + continue; + if (w->vertex_id.id.s_addr != v->vertex_id.id.s_addr) + continue; + + return v; + } + + return (struct ospf6_vertex *) NULL; +} + +u_int32_t stat_node = 0; +u_int32_t stat_candidate = 0; +u_int32_t stat_candidate_max = 0; +u_int32_t stat_spf = 0; + + +/* RFC2328 section 16.1 , RFC2740 section 3.8.1 */ +static int +ospf6_spf_calculation (struct ospf6_area *o6a) +{ + list candidate_list; + struct ospf6_vertex *V, *W, *X; + int ldnum, i; + + if (! o6a || ! o6a->spf_tree) + { + zlog_err ("SPF: Can't calculate SPF tree: malformed area"); + return -1; + } + + stat_spf ++; + stat_node = 0; + stat_candidate = 0; + stat_candidate_max = 0; + + if (IS_OSPF6_DUMP_SPF) + zlog_info ("SPF: Calculation for area %s", o6a->str); + + ospf6_route_table_freeze (o6a->table_topology); + ospf6_route_remove_all (o6a->table_topology); + + /* (1): Initialize the algorithm's data structures */ + candidate_list = list_new (); + ospf6_spf_initialize (candidate_list, o6a); + stat_candidate ++; + + /* (3): Install closest from candidate list; if empty, break */ + while (listcount (candidate_list)) + { + V = ospf6_spf_get_closest_candidate (candidate_list); + listnode_delete (candidate_list, V); + + { + struct ospf6_vertex *V_; + + if (stat_candidate_max < ospf6_spf_candidate_count ()) + stat_candidate_max = ospf6_spf_candidate_count (); + + V_ = ospf6_spf_candidate_dequeue (); + +#if 0 + if (IS_OSPF6_DUMP_SPF) + { + zlog_info ("Candidate list count: %lu", + (u_long)ospf6_spf_candidate_count ()); + zlog_info ("*** Candidate %s: %p <-> %p", + (V == V_ ? "same" : "*** differ ***"), V, V_); + zlog_info (" %p: %s", V, V->string); + zlog_info (" %p: %s", V_, V_->string); + } +#endif + + } + + stat_node++; + ospf6_spf_install (V, o6a); + + /* (2): Examin LSA of just added vertex */ + ldnum = ospf6_spf_lsd_num (V, o6a); + for (i = 0; i < ldnum; i++) + { + /* (b): If no LSA, or MaxAge, or LinkBack fail, examin next */ + W = ospf6_spf_vertex_create (i, V, o6a); + if (! W) + continue; + + stat_candidate ++; + + /* (c) */ + if (ospf6_spf_lookup (W, o6a)) + { + if (IS_OSPF6_DUMP_SPF) + zlog_info ("SPF: %s: Already in SPF tree", W->string); + ospf6_spf_vertex_delete (W); + continue; + } + + /* (d) */ + X = ospf6_spf_get_same_candidate (W, candidate_list); + if (X && X->distance < W->distance) + { + if (IS_OSPF6_DUMP_SPF) + zlog_info ("SPF: %s: More closer found", W->string); + ospf6_spf_vertex_delete (W); + continue; + } + if (X && X->distance == W->distance) + { + if (IS_OSPF6_DUMP_SPF) + zlog_info ("SPF: %s: new ECMP candidate", W->string); + ospf6_spf_vertex_merge (W, X); + ospf6_spf_vertex_delete (W); + continue; + } + + if (X) + { + if (IS_OSPF6_DUMP_SPF) + zlog_info ("SPF: %s: Swap with old candidate", W->string); + listnode_delete (candidate_list, X); + ospf6_spf_candidate_remove (X); + ospf6_spf_vertex_delete (X); + } + else + { + if (IS_OSPF6_DUMP_SPF) + zlog_info ("SPF: %s: New Candidate", W->string); + } + + if (stat_candidate_max < ospf6_spf_candidate_count ()) + stat_candidate_max = ospf6_spf_candidate_count (); + + listnode_add (candidate_list, W); + ospf6_spf_candidate_enqueue (W); + } + } + + assert (listcount (candidate_list) == 0); + list_free (candidate_list); + assert (ospf6_spf_candidate_count () == 0); + + /* Clear thread timer */ + o6a->spf_tree->t_spf_calculation = (struct thread *) NULL; + + if (IS_OSPF6_DUMP_SPF) + { + zlog_info ("SPF: Calculation for area %s done", o6a->str); + zlog_info ("SPF: Statistics: %luth", (u_long)stat_spf); + zlog_info ("SPF: Node Number: %lu", (u_long)stat_node); + zlog_info ("SPF: Candidate Number: %lu Max: %lu", + (u_long) stat_candidate, (u_long) stat_candidate_max); + } + + ospf6_route_table_thaw (o6a->table_topology); + return 0; +} + +int +ospf6_spf_calculation_thread (struct thread *t) +{ + struct ospf6_area *o6a; + struct timeval start, end, runtime, interval; + + o6a = (struct ospf6_area *) THREAD_ARG (t); + if (! o6a) + { + zlog_err ("SPF: Thread error"); + return -1; + } + + if (! o6a->spf_tree) + { + zlog_err ("SPF: Can't find SPF Tree for area: %s", o6a->str); + return -1; + } + + /* execute SPF calculation */ + gettimeofday (&start, (struct timezone *) NULL); + ospf6_spf_calculation (o6a); + gettimeofday (&end, (struct timezone *) NULL); + + /* update statistics */ + o6a->spf_tree->timerun ++; + ospf6_timeval_sub (&end, &start, &runtime); + ospf6_timeval_add_equal (&runtime, &o6a->spf_tree->runtime_total); + + if (o6a->spf_tree->timerun == 1) + { + o6a->spf_tree->runtime_min.tv_sec = runtime.tv_sec; + o6a->spf_tree->runtime_min.tv_usec = runtime.tv_usec; + o6a->spf_tree->runtime_max.tv_sec = runtime.tv_sec; + o6a->spf_tree->runtime_max.tv_usec = runtime.tv_usec; + } + if (ospf6_timeval_cmp (o6a->spf_tree->runtime_min, runtime) > 0) + { + o6a->spf_tree->runtime_min.tv_sec = runtime.tv_sec; + o6a->spf_tree->runtime_min.tv_usec = runtime.tv_usec; + } + if (ospf6_timeval_cmp (runtime, o6a->spf_tree->runtime_max) > 0) + { + o6a->spf_tree->runtime_max.tv_sec = runtime.tv_sec; + o6a->spf_tree->runtime_max.tv_usec = runtime.tv_usec; + } + + if (o6a->spf_tree->timerun == 1) + { + ospf6_timeval_sub (&start, &ospf6->starttime, &interval); + ospf6_timeval_add_equal (&interval, &o6a->spf_tree->interval_total); + o6a->spf_tree->interval_min.tv_sec = interval.tv_sec; + o6a->spf_tree->interval_min.tv_usec = interval.tv_usec; + o6a->spf_tree->interval_max.tv_sec = interval.tv_sec; + o6a->spf_tree->interval_max.tv_usec = interval.tv_usec; + } + else + { + ospf6_timeval_sub (&start, &o6a->spf_tree->updated_time, &interval); + ospf6_timeval_add_equal (&interval, &o6a->spf_tree->interval_total); + if (ospf6_timeval_cmp (o6a->spf_tree->interval_min, interval) > 0) + { + o6a->spf_tree->interval_min.tv_sec = interval.tv_sec; + o6a->spf_tree->interval_min.tv_usec = interval.tv_usec; + } + if (ospf6_timeval_cmp (interval, o6a->spf_tree->interval_max) > 0) + { + o6a->spf_tree->interval_max.tv_sec = interval.tv_sec; + o6a->spf_tree->interval_max.tv_usec = interval.tv_usec; + } + } + o6a->spf_tree->updated_time.tv_sec = end.tv_sec; + o6a->spf_tree->updated_time.tv_usec = end.tv_usec; + + /* clear thread */ + o6a->spf_tree->t_spf_calculation = (struct thread *) NULL; + + return 0; +} + +void +ospf6_spf_database_hook (struct ospf6_lsa *old, struct ospf6_lsa *new) +{ + struct ospf6_area *o6a = NULL; + struct ospf6_interface *o6i = NULL; + + if (new->header->type == htons (OSPF6_LSA_TYPE_ROUTER) || + new->header->type == htons (OSPF6_LSA_TYPE_NETWORK)) + o6a = new->scope; + else if (new->header->type == htons (OSPF6_LSA_TYPE_LINK)) + { + o6i = new->scope; + o6a = o6i->area; + } + + if (o6a) + ospf6_spf_calculation_schedule (o6a->area_id); +} + +void +ospf6_spf_calculation_schedule (u_int32_t area_id) +{ + struct ospf6_area *o6a; + char buf[64]; + + o6a = ospf6_area_lookup (area_id, ospf6); + if (! o6a) + { + inet_ntop (AF_INET, &area_id, buf, sizeof (buf)); + zlog_err ("SPF: Can't find area: %s", buf); + return; + } + + if (! o6a->spf_tree) + { + zlog_err ("SPF: Can't find SPF Tree for area: %s", o6a->str); + return; + } + + if (o6a->spf_tree->t_spf_calculation) + return; + + o6a->spf_tree->t_spf_calculation = + thread_add_event (master, ospf6_spf_calculation_thread, o6a, 0); +} + +struct ospf6_spftree * +ospf6_spftree_create () +{ + struct ospf6_spftree *spf_tree; + spf_tree = (struct ospf6_spftree *) XMALLOC (MTYPE_OSPF6_SPFTREE, + sizeof (struct ospf6_spftree)); + if (! spf_tree) + { + zlog_err ("SPF: Can't allocate memory for SPF tree"); + return (struct ospf6_spftree *) NULL; + } + memset (spf_tree, 0, sizeof (spf_tree)); + + spf_tree->list = list_new (); + + return spf_tree; +} + +void +ospf6_spftree_delete (struct ospf6_spftree *spf_tree) +{ + listnode node; + struct ospf6_vertex *v; + + /* Delete spf tree */ + for (node = listhead (spf_tree->list); node; nextnode (node)) + { + v = (struct ospf6_vertex *) getdata (node); + ospf6_spf_vertex_delete (v); + } + list_delete_all_node (spf_tree->list); + + XFREE (MTYPE_OSPF6_SPFTREE, spf_tree); +} + +void +ospf6_nexthop_show (struct vty *vty, struct ospf6_nexthop *nexthop) +{ + char buf[128], *ifname; + struct ospf6_interface *o6i; + + ifname = NULL; + + o6i = ospf6_interface_lookup_by_index (nexthop->ifindex); + if (! o6i) + { + zlog_err ("Spf: invalid ifindex %d in nexthop", nexthop->ifindex); + } + else + ifname = o6i->interface->name; + + inet_ntop (AF_INET6, &nexthop->address, buf, sizeof (buf)); + vty_out (vty, " %s%%%s(%d)%s", buf, ifname, + nexthop->ifindex, VTY_NEWLINE); +} + +void +ospf6_vertex_show (struct vty *vty, struct ospf6_vertex *vertex) +{ + listnode node; + struct ospf6_vertex *v; + struct linklist_node lnode; + + vty_out (vty, "SPF node %s%s", vertex->string, VTY_NEWLINE); + vty_out (vty, " cost to this node: %d%s", vertex->distance, VTY_NEWLINE); + vty_out (vty, " hops to this node: %d%s", vertex->depth, VTY_NEWLINE); + + vty_out (vty, " nexthops reachable to this node:%s", VTY_NEWLINE); + for (linklist_head (vertex->nexthop_list, &lnode); + ! linklist_end (&lnode); + linklist_next (&lnode)) + ospf6_nexthop_show (vty, (struct ospf6_nexthop *) lnode.data); + + vty_out (vty, " parent nodes to this node:%s", VTY_NEWLINE); + if (! list_isempty (vertex->parent_list)) + vty_out (vty, " "); + for (node = listhead (vertex->parent_list); node; nextnode (node)) + { + v = (struct ospf6_vertex *) getdata (node); + vty_out (vty, "%s ", v->string); + } + if (! list_isempty (vertex->parent_list)) + vty_out (vty, "%s", VTY_NEWLINE); + + vty_out (vty, " child nodes to this node:%s", VTY_NEWLINE); + if (! list_isempty (vertex->path_list)) + vty_out (vty, " "); + for (node = listhead (vertex->path_list); node; nextnode (node)) + { + v = (struct ospf6_vertex *) getdata (node); + vty_out (vty, "%s ", v->string); + } + if (! list_isempty (vertex->path_list)) + vty_out (vty, "%s", VTY_NEWLINE); + + vty_out (vty, "%s", VTY_NEWLINE); +} + +void +ospf6_spf_statistics_show (struct vty *vty, struct ospf6_spftree *spf_tree) +{ + listnode node; + struct ospf6_vertex *vertex; + u_int router_count, network_count, maxdepth; + struct timeval runtime_avg, interval_avg, last_updated, now; + char rmin[64], rmax[64], ravg[64]; + char imin[64], imax[64], iavg[64]; + char last_updated_string[64]; + + maxdepth = router_count = network_count = 0; + for (node = listhead (spf_tree->list); node; nextnode (node)) + { + vertex = (struct ospf6_vertex *) getdata (node); + if (vertex->vertex_id.id.s_addr) + network_count++; + else + router_count++; + if (maxdepth < vertex->depth) + maxdepth = vertex->depth; + } + + ospf6_timeval_div (&spf_tree->runtime_total, spf_tree->timerun, + &runtime_avg); + ospf6_timeval_string (&spf_tree->runtime_min, rmin, sizeof (rmin)); + ospf6_timeval_string (&spf_tree->runtime_max, rmax, sizeof (rmax)); + ospf6_timeval_string (&runtime_avg, ravg, sizeof (ravg)); + + ospf6_timeval_div (&spf_tree->interval_total, spf_tree->timerun, + &interval_avg); + ospf6_timeval_string (&spf_tree->interval_min, imin, sizeof (imin)); + ospf6_timeval_string (&spf_tree->interval_max, imax, sizeof (imax)); + ospf6_timeval_string (&interval_avg, iavg, sizeof (iavg)); + + gettimeofday (&now, (struct timezone *) NULL); + ospf6_timeval_sub (&now, &spf_tree->updated_time, &last_updated); + ospf6_timeval_string (&last_updated, last_updated_string, + sizeof (last_updated_string)); + + vty_out (vty, " SPF algorithm executed %d times%s", + spf_tree->timerun, VTY_NEWLINE); + vty_out (vty, " Average time to run SPF: %s%s", + ravg, VTY_NEWLINE); + vty_out (vty, " Maximum time to run SPF: %s%s", + rmax, VTY_NEWLINE); + vty_out (vty, " Average interval of SPF: %s%s", + iavg, VTY_NEWLINE); + vty_out (vty, " SPF last updated: %s ago%s", + last_updated_string, VTY_NEWLINE); + vty_out (vty, " Current SPF node count: %d%s", + listcount (spf_tree->list), VTY_NEWLINE); + vty_out (vty, " Router: %d Network: %d%s", + router_count, network_count, VTY_NEWLINE); + vty_out (vty, " Maximum of Hop count to nodes: %d%s", + maxdepth, VTY_NEWLINE); +} + +DEFUN (show_ipv6_ospf6_area_spf_node, + show_ipv6_ospf6_area_spf_node_cmd, + "show ipv6 ospf6 area A.B.C.D spf node", + SHOW_STR + IP6_STR + OSPF6_STR + OSPF6_AREA_STR + OSPF6_AREA_ID_STR + "Shortest Path First caculation\n" + "vertex infomation\n" + ) +{ + listnode i; + u_int32_t area_id; + struct ospf6_area *o6a; + struct ospf6_vertex *vertex; + + OSPF6_CMD_CHECK_RUNNING (); + + inet_pton (AF_INET, argv[0], &area_id); + o6a = ospf6_area_lookup (area_id, ospf6); + if (! o6a) + return CMD_SUCCESS; + + for (i = listhead (o6a->spf_tree->list); i; nextnode (i)) + { + vertex = (struct ospf6_vertex *) getdata (i); + ospf6_vertex_show (vty, vertex); + } + + return CMD_SUCCESS; +} + +static void +ospf6_spftree_show (struct vty *vty, char *prefix, int current_rest, + struct ospf6_vertex *v) +{ + char *p; + int psize; + int restnum; + listnode node; + + vty_out (vty, "%s+-%s%s", prefix, v->string, VTY_NEWLINE); + + if (listcount (v->path_list) == 0) + return; + + psize = strlen (prefix) + 3; + p = malloc (psize); + if (!p) + { + vty_out (vty, "depth too long ...%s", VTY_NEWLINE); + return; + } + + restnum = listcount (v->path_list); + for (node = listhead (v->path_list); node; nextnode (node)) + { + --restnum; + snprintf (p, psize, "%s%s", prefix, (current_rest ? "| " : " ")); + ospf6_spftree_show (vty, p, restnum, + (struct ospf6_vertex *) getdata (node)); + } + + free (p); +} + +DEFUN (show_ipv6_ospf6_area_spf_tree, + show_ipv6_ospf6_area_spf_tree_cmd, + "show ipv6 ospf6 area A.B.C.D spf tree", + SHOW_STR + IP6_STR + OSPF6_STR + OSPF6_AREA_STR + OSPF6_AREA_ID_STR + "Shortest Path First caculation\n" + "Displays spf tree\n") +{ + u_int32_t area_id; + struct ospf6_area *o6a; + + OSPF6_CMD_CHECK_RUNNING (); + + inet_pton (AF_INET, argv[0], &area_id); + o6a = ospf6_area_lookup (area_id, ospf6); + if (! o6a) + return CMD_SUCCESS; + + vty_out (vty, "%s SPF tree for Area %s%s%s", + VTY_NEWLINE, o6a->str, VTY_NEWLINE, VTY_NEWLINE); + + if (! o6a->spf_tree->root) + return CMD_SUCCESS; + + ospf6_spftree_show (vty, "", 0, o6a->spf_tree->root); + return CMD_SUCCESS; +} + +DEFUN (show_ipv6_ospf6_area_topology, + show_ipv6_ospf6_area_topology_cmd, + "show ipv6 ospf6 area A.B.C.D topology", + SHOW_STR + IP6_STR + OSPF6_STR + OSPF6_AREA_STR + OSPF6_AREA_ID_STR + OSPF6_SPF_STR + "Displays SPF topology table\n") +{ + struct ospf6_area *o6a; + u_int32_t area_id; + + OSPF6_CMD_CHECK_RUNNING (); + + inet_pton (AF_INET, argv[0], &area_id); + o6a = ospf6_area_lookup (area_id, ospf6); + + if (! o6a) + return CMD_SUCCESS; + + argc -= 1; + argv += 1; + + return ospf6_route_table_show (vty, argc, argv, o6a->table_topology); +} + +ALIAS (show_ipv6_ospf6_area_topology, + show_ipv6_ospf6_area_topology_router_cmd, + "show ipv6 ospf6 area A.B.C.D topology (A.B.C.D|<0-4294967295>|detail)", + SHOW_STR + IP6_STR + OSPF6_STR + OSPF6_AREA_STR + OSPF6_AREA_ID_STR + OSPF6_SPF_STR + "Displays SPF topology table\n" + OSPF6_ROUTER_ID_STR + OSPF6_ROUTER_ID_STR + ) + +ALIAS (show_ipv6_ospf6_area_topology, + show_ipv6_ospf6_area_topology_router_lsid_cmd, + "show ipv6 ospf6 area A.B.C.D topology (A.B.C.D|<0-4294967295>) (A.B.C.D|<0-4294967295>)", + SHOW_STR + IP6_STR + OSPF6_STR + OSPF6_AREA_STR + OSPF6_AREA_ID_STR + OSPF6_SPF_STR + "Displays SPF topology table\n" + OSPF6_ROUTER_ID_STR + OSPF6_ROUTER_ID_STR + OSPF6_LS_ID_STR + OSPF6_LS_ID_STR + ) + +void +ospf6_spf_init () +{ + nexthop_list = linklist_create (); + ospf6_spf_candidate_init (); + install_element (VIEW_NODE, &show_ipv6_ospf6_area_spf_node_cmd); + install_element (VIEW_NODE, &show_ipv6_ospf6_area_spf_tree_cmd); + install_element (VIEW_NODE, &show_ipv6_ospf6_area_topology_cmd); + install_element (VIEW_NODE, &show_ipv6_ospf6_area_topology_router_cmd); + install_element (VIEW_NODE, &show_ipv6_ospf6_area_topology_router_lsid_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_area_spf_node_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_area_spf_tree_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_area_topology_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_area_topology_router_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_area_topology_router_lsid_cmd); +} + diff --git a/ospf6d/ospf6_spf.h b/ospf6d/ospf6_spf.h new file mode 100644 index 000000000..de50e94a8 --- /dev/null +++ b/ospf6d/ospf6_spf.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) 1999 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF6_SPF_H +#define OSPF6_SPF_H + +#include "prefix.h" + +/* Transit Vertex */ +struct ospf6_vertex +{ + /* type of this vertex */ + u_int8_t type; + + /* Vertex Identifier */ + struct prefix_ls vertex_id; + + /* Identifier String */ + char string[128]; + + /* Associated LSA */ + struct ospf6_lsa *lsa; + + /* Distance from Root (Cost) */ + u_int16_t distance; + + /* Depth of this node */ + u_char depth; + + /* nexthops to this node */ + struct linklist *nexthop_list; + + /* upper nodes in spf tree */ + list parent_list; + + /* lower nodes in spf tree */ + list path_list; + + /* capability bits */ + u_char capability_bits; + + /* Optional capabilities */ + u_char opt_capability[3]; +}; + +#define OSPF6_VERTEX_TYPE_ROUTER 0x01 +#define OSPF6_VERTEX_TYPE_NETWORK 0x02 + +struct ospf6_spftree +{ + /* calculation thread */ + struct thread *t_spf_calculation; + + /* root of this tree */ + struct ospf6_vertex *root; + + /* list for search */ + list list; + + /* statistics */ + u_int32_t timerun; + + struct timeval runtime_total; + struct timeval runtime_min; + struct timeval runtime_max; + + struct timeval updated_time; + struct timeval interval_total; + struct timeval interval_min; + struct timeval interval_max; +}; + +int ospf6_spf_calculate_route (void *); + +void +ospf6_spf_calculation_schedule (u_int32_t area_id); +struct ospf6_spftree *ospf6_spftree_create (); +void +ospf6_spf_statistics_show (struct vty *vty, struct ospf6_spftree *spf_tree); +void ospf6_spftree_delete (struct ospf6_spftree *spf_tree); + +void ospf6_spf_database_hook (struct ospf6_lsa *old, struct ospf6_lsa *new); + +void ospf6_spf_init (); + +#endif /* OSPF6_SPF_H */ + diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c new file mode 100644 index 000000000..a8a058f2c --- /dev/null +++ b/ospf6d/ospf6_top.c @@ -0,0 +1,401 @@ +/* + * OSPFv3 Top Level Data Structure + * Copyright (C) 1999 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <zebra.h> + +#include "log.h" +#include "memory.h" +#include "vty.h" +#include "linklist.h" +#include "prefix.h" +#include "table.h" +#include "thread.h" +#include "command.h" + +#include "ospf6_hook.h" +#include "ospf6_proto.h" +#include "ospf6_prefix.h" +#include "ospf6_lsa.h" +#include "ospf6_lsdb.h" + +#include "ospf6_message.h" +#include "ospf6_neighbor.h" +#include "ospf6_interface.h" +#include "ospf6_area.h" +#include "ospf6_top.h" + +#include "ospf6_route.h" +#include "ospf6_zebra.h" + +#include "ospf6_nsm.h" +#include "ospf6_asbr.h" +#include "ospf6_abr.h" + +#define HEADER_DEPENDENCY +#include "ospf6d.h" +#undef HEADER_DEPENDENCY + +/* global ospf6d variable */ +struct ospf6 *ospf6; + +static void +ospf6_top_foreach_area (struct ospf6 *o6, void *arg, int val, + void (*func) (void *, int, void *)) +{ + listnode node; + struct ospf6_area *o6a; + + for (node = listhead (o6->area_list); node; nextnode (node)) + { + o6a = (struct ospf6_area *) getdata (node); + (*func) (arg, val, o6a); + } +} + +static void +ospf6_top_foreach_interface (struct ospf6 *o6, void *arg, int val, + void (*func) (void *, int, void *)) +{ + listnode node; + struct ospf6_area *o6a; + + for (node = listhead (o6->area_list); node; nextnode (node)) + { + o6a = (struct ospf6_area *) getdata (node); + (*o6a->foreach_if) (o6a, arg, val, func); + } +} + +static void +ospf6_top_foreach_neighbor (struct ospf6 *o6, void *arg, int val, + void (*func) (void *, int, void *)) +{ + listnode node; + struct ospf6_area *o6a; + + for (node = listhead (o6->area_list); node; nextnode (node)) + { + o6a = (struct ospf6_area *) getdata (node); + (*o6a->foreach_nei) (o6a, arg, val, func); + } +} + +static int +ospf6_top_maxage_remover (struct thread *t) +{ + int count; + struct ospf6 *o6 = (struct ospf6 *) THREAD_ARG (t); + + o6->maxage_remover = (struct thread *) NULL; + + count = 0; + o6->foreach_nei (o6, &count, NBS_EXCHANGE, ospf6_count_state); + o6->foreach_nei (o6, &count, NBS_LOADING, ospf6_count_state); + if (count != 0) + return 0; + + ospf6_lsdb_remove_maxage (o6->lsdb); + return 0; +} + +void +ospf6_top_schedule_maxage_remover (void *arg, int val, struct ospf6 *o6) +{ + if (o6->maxage_remover != NULL) + return; + + o6->maxage_remover = + thread_add_event (master, ospf6_top_maxage_remover, o6, 0); +} + +void +ospf6_show (struct vty *vty) +{ + listnode n; + struct ospf6_area *area; + char id_string[32]; + unsigned long day, hour, min, sec; + struct timeval now, running; + + /* process id, router id */ + inet_ntop (AF_INET, &ospf6->router_id, id_string, sizeof (id_string)); + vty_out (vty, " Routing Process (%lu) with ID %s%s", + ospf6->process_id, id_string, VTY_NEWLINE); + + /* running time */ + gettimeofday (&now, (struct timezone *)NULL); + ospf6_timeval_sub (&now, &ospf6->starttime, &running); + ospf6_timeval_decode (&running, &day, &hour, &min, &sec, NULL, NULL); + vty_out (vty, " Running %ld days %ld hours %ld minutes %ld seconds%s", + day, hour, min, sec, VTY_NEWLINE); + + vty_out (vty, " Supports only single TOS(TOS0) routes%s", VTY_NEWLINE); + + /* Redistribute config */ + ospf6_redistribute_show_config (vty); + + /* LSAs */ + vty_out (vty, " Number of AS scoped LSAs is %u%s", + ospf6->lsdb->count, VTY_NEWLINE); + vty_out (vty, " Route calculation executed %d times%s", + ospf6->stat_route_calculation_execed, VTY_NEWLINE); + + /* Route Statistics */ +#if 0 + ospf6_route_statistics_show (vty, ospf6->route_table); +#endif + + /* Areas */ + vty_out (vty, " Number of areas in this router is %u%s", + listcount (ospf6->area_list), VTY_NEWLINE); + for (n = listhead (ospf6->area_list); n; nextnode (n)) + { + area = (struct ospf6_area *) getdata (n); + ospf6_area_show (vty, area); + } +} + +void +ospf6_statistics_show (struct vty *vty, struct ospf6 *o6) +{ + listnode node; + struct ospf6_area *o6a; + char running_time[128]; + struct timeval now, running; + + gettimeofday (&now, (struct timezone *) NULL); + ospf6_timeval_sub (&now, &o6->starttime, &running); + ospf6_timeval_string (&running, running_time, sizeof (running_time)); + + vty_out (vty, "Statistics of OSPF process %ld%s", + o6->process_id, VTY_NEWLINE); + vty_out (vty, " Running: %s%s", running_time, VTY_NEWLINE); + +#if 0 + ospf6_route_statistics_show (vty, o6->route_table); +#endif + + for (node = listhead (o6->area_list); node; nextnode (node)) + { + o6a = (struct ospf6_area *) getdata (node); + ospf6_area_statistics_show (vty, o6a); + } +} + +static struct ospf6 * +ospf6_new () +{ + struct ospf6 *new; + new = XMALLOC (MTYPE_OSPF6_TOP, sizeof (struct ospf6)); + if (new) + memset (new, 0, sizeof (struct ospf6)); + return new; +} + +void +ospf6_free (struct ospf6 *ospf6) +{ + XFREE (MTYPE_OSPF6_TOP, ospf6); +} + +void +ospf6_top_topology_add (struct ospf6_route_req *request) +{ + assert (request->route.type == OSPF6_DEST_TYPE_ROUTER); + if (CHECK_FLAG (request->path.router_bits, OSPF6_ROUTER_LSA_BIT_E)) + ospf6_asbr_asbr_entry_add (request); +} + +void +ospf6_top_topology_remove (struct ospf6_route_req *request) +{ + assert (request->route.type == OSPF6_DEST_TYPE_ROUTER); + if (CHECK_FLAG (request->path.router_bits, OSPF6_ROUTER_LSA_BIT_E)) + ospf6_asbr_asbr_entry_remove (request); +} + +struct ospf6 * +ospf6_create (unsigned long process_id) +{ + struct ospf6 *o6; + char namebuf[64]; + + o6 = ospf6_new (); + + /* initialize */ + gettimeofday (&o6->starttime, (struct timezone *)NULL); + o6->process_id = process_id; + o6->version = OSPF6_VERSION; + o6->area_list = list_new (); + + o6->lsdb = ospf6_lsdb_create (); + + o6->foreach_area = ospf6_top_foreach_area; + o6->foreach_if = ospf6_top_foreach_interface; + o6->foreach_nei = ospf6_top_foreach_neighbor; + + snprintf (namebuf, sizeof (namebuf), "InterTopology table"); + o6->topology_table = ospf6_route_table_create (namebuf); + ospf6_route_hook_register (ospf6_top_topology_add, + ospf6_top_topology_add, + ospf6_top_topology_remove, + o6->topology_table); + +#if 0 + snprintf (namebuf, sizeof (namebuf), "External table"); + o6->external_table = ospf6_route_table_create (namebuf); + ospf6_route_hook_register (ospf6_asbr_external_route_add, + ospf6_asbr_external_route_add, + ospf6_asbr_external_route_remove, + o6->external_table); +#endif /*0*/ + + snprintf (namebuf, sizeof (namebuf), "Top route table"); + o6->route_table = ospf6_route_table_create (namebuf); + ospf6_route_hook_register (ospf6_zebra_route_update_add, + ospf6_zebra_route_update_add, + ospf6_zebra_route_update_remove, + o6->route_table); + ospf6_route_hook_register (ospf6_abr_route_add, + ospf6_abr_route_add, + ospf6_abr_route_remove, + o6->route_table); + + return o6; +} + +void +ospf6_delete (struct ospf6 *ospf6) +{ + ospf6_route_remove_all (ospf6->route_table); + ospf6_free (ospf6); +} + +struct ospf6 * +ospf6_start () +{ + if (ospf6) + return ospf6; + + ospf6 = ospf6_create (0); + return ospf6; +} + +void +ospf6_stop () +{ + if (!ospf6) + return; + + ospf6_delete (ospf6); + ospf6 = NULL; +} + +int +ospf6_is_asbr (struct ospf6 *o6) +{ + int i = 0; + i |= ospf6_zebra_is_redistribute (ZEBRA_ROUTE_SYSTEM); + i |= ospf6_zebra_is_redistribute (ZEBRA_ROUTE_CONNECT); + i |= ospf6_zebra_is_redistribute (ZEBRA_ROUTE_STATIC); + i |= ospf6_zebra_is_redistribute (ZEBRA_ROUTE_KERNEL); + i |= ospf6_zebra_is_redistribute (ZEBRA_ROUTE_RIPNG); + i |= ospf6_zebra_is_redistribute (ZEBRA_ROUTE_BGP); + return (i); +} + +DEFUN (show_ipv6_ospf6_route, + show_ipv6_ospf6_route_cmd, + "show ipv6 ospf6 route", + SHOW_STR + IP6_STR + OSPF6_STR + "Routing table\n" + ) +{ + OSPF6_CMD_CHECK_RUNNING (); + return ospf6_route_table_show (vty, argc, argv, ospf6->route_table); +} + +ALIAS (show_ipv6_ospf6_route, + show_ipv6_ospf6_route_prefix_cmd, + "show ipv6 ospf6 route (X::X|detail)", + SHOW_STR + IP6_STR + OSPF6_STR + "Routing table\n" + "match IPv6 prefix\n" + ) + +DEFUN (show_ipv6_ospf6_topology, + show_ipv6_ospf6_topology_cmd, + "show ipv6 ospf6 topology", + SHOW_STR + IP6_STR + OSPF6_STR + "Inter Area topology information\n" + ) +{ + OSPF6_CMD_CHECK_RUNNING (); + return ospf6_route_table_show (vty, argc, argv, ospf6->topology_table); +} + +ALIAS (show_ipv6_ospf6_topology, + show_ipv6_ospf6_topology_router_cmd, + "show ipv6 ospf6 topology (A.B.C.D|<0-4294967295>|detail)", + SHOW_STR + IP6_STR + OSPF6_STR + "Inter Area topology information\n" + OSPF6_ROUTER_ID_STR + OSPF6_ROUTER_ID_STR + "Detailed information\n" + ) + +ALIAS (show_ipv6_ospf6_topology, + show_ipv6_ospf6_topology_router_lsid_cmd, + "show ipv6 ospf6 topology (A.B.C.D|<0-4294967295>) (A.B.C.D|<0-4294967295>)", + SHOW_STR + IP6_STR + OSPF6_STR + "Inter Area topology information\n" + OSPF6_ROUTER_ID_STR + OSPF6_ROUTER_ID_STR + OSPF6_LS_ID_STR + OSPF6_LS_ID_STR + ) + +void +ospf6_top_init () +{ + install_element (VIEW_NODE, &show_ipv6_ospf6_route_cmd); + install_element (VIEW_NODE, &show_ipv6_ospf6_route_prefix_cmd); + install_element (VIEW_NODE, &show_ipv6_ospf6_topology_cmd); + install_element (VIEW_NODE, &show_ipv6_ospf6_topology_router_cmd); + install_element (VIEW_NODE, &show_ipv6_ospf6_topology_router_lsid_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_route_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_route_prefix_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_topology_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_topology_router_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_topology_router_lsid_cmd); +} + diff --git a/ospf6d/ospf6_top.h b/ospf6d/ospf6_top.h new file mode 100644 index 000000000..4c687563a --- /dev/null +++ b/ospf6d/ospf6_top.h @@ -0,0 +1,96 @@ +/* + * OSPFv3 Top Level Data Structure + * Copyright (C) 1999 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF6_TOP_H +#define OSPF6_TOP_H + +#include "routemap.h" + +/* ospfv3 top level data structure */ +struct ospf6 +{ + /* process id */ + u_long process_id; + + /* start time */ + struct timeval starttime; + + /* ospf version must be 3 */ + unsigned char version; + + /* my router id */ + u_int32_t router_id; + + /* list of areas */ + list area_list; + + /* AS scope link state database */ + struct ospf6_lsdb *lsdb; + + /* redistribute route-map */ + struct + { + char *name; + struct route_map *map; + } rmap[ZEBRA_ROUTE_MAX]; + + struct thread *t_route_calculation; + u_int stat_route_calculation_execed; + + struct ospf6_route_table *route_table; + struct ospf6_route_table *topology_table; + struct ospf6_route_table *external_table; + + void (*foreach_area) (struct ospf6 *, void *arg, int val, + void (*func) (void *, int, void *)); + void (*foreach_if) (struct ospf6 *, void *arg, int val, + void (*func) (void *, int, void *)); + void (*foreach_nei) (struct ospf6 *, void *arg, int val, + void (*func) (void *, int, void *)); + + struct thread *maxage_remover; + + list nexthop_list; +}; + +extern struct ospf6 *ospf6; + +/* prototypes */ +int +ospf6_top_count_neighbor_in_state (u_char state, struct ospf6 *o6); + +void +ospf6_top_schedule_maxage_remover (void *arg, int val, struct ospf6 *o6); + +void ospf6_show (struct vty *); +void ospf6_statistics_show (struct vty *vty, struct ospf6 *o6); + +struct ospf6 *ospf6_start (); +void ospf6_stop (); + +void ospf6_delete (struct ospf6 *); +int ospf6_is_asbr (struct ospf6 *); + +void ospf6_top_init (); + +#endif /* OSPF6_TOP_H */ + diff --git a/ospf6d/ospf6_types.h b/ospf6d/ospf6_types.h new file mode 100644 index 000000000..574e2f354 --- /dev/null +++ b/ospf6d/ospf6_types.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 1999 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF6_TYPES_H +#define OSPF6_TYPES_H + +typedef unsigned char msgtype_t; +typedef unsigned char instance_id_t; +typedef unsigned char state_t; +typedef unsigned char vers_t; +typedef unsigned char opt_t; +typedef unsigned char rtr_pri_t; +typedef unsigned char prefixlen_t; +typedef unsigned char ddbits_t; +typedef unsigned long ddseqnum_t; +typedef unsigned long rtr_id_t; +typedef unsigned long ifid_t; +typedef unsigned long cost_t; +typedef unsigned long rxmt_int_t; +typedef unsigned short hello_int_t; +typedef unsigned short rtr_dead_int_t; +typedef unsigned long area_id_t; + +#endif /* OSPF6_TYPES_H */ + diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c new file mode 100644 index 000000000..7b8a8dcfb --- /dev/null +++ b/ospf6d/ospf6_zebra.c @@ -0,0 +1,727 @@ +/* + * Copyright (C) 1999 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "ospf6d.h" + +#include "ospf6_interface.h" +#include "ospf6_asbr.h" + +#include "ospf6_linklist.h" + +/* information about zebra. */ +struct zclient *zclient = NULL; + +/* redistribute function */ +void +ospf6_zebra_redistribute (int type) +{ + int top_change = 0; + + if (zclient->redist[type]) + return; + + if (! ospf6_is_asbr (ospf6)) + top_change = 1; + + zclient->redist[type] = 1; + + if (zclient->sock > 0) + zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient->sock, type); + + if (top_change) + CALL_CHANGE_HOOK (&top_hook, ospf6); +} + +void +ospf6_zebra_no_redistribute (int type) +{ + int top_change = 0; + + if (!zclient->redist[type]) + return; + + if (ospf6_is_asbr (ospf6)) + top_change = 1; + + zclient->redist[type] = 0; + + if (zclient->sock > 0) + zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient->sock, type); + + if (top_change) + CALL_CHANGE_HOOK (&top_hook, ospf6); +} + +int +ospf6_zebra_is_redistribute (int type) +{ + return zclient->redist[type]; +} + + +/* Inteface addition message from zebra. */ +int +ospf6_zebra_if_add (int command, struct zclient *zclient, zebra_size_t length) +{ + struct interface *ifp; + + ifp = zebra_interface_add_read (zclient->ibuf); + + /* log */ + if (IS_OSPF6_DUMP_ZEBRA) + zlog_info ("ZEBRA: I/F add: %s index %d mtu %d", + ifp->name, ifp->ifindex, ifp->mtu); + + ospf6_interface_if_add (ifp); + + return 0; +} + +int +ospf6_zebra_if_del (int command, struct zclient *zclient, zebra_size_t length) +{ +#if 0 + struct interface *ifp = NULL; + + ifp = zebra_interface_delete_read (zclient->ibuf); + + /* log */ + if (IS_OSPF6_DUMP_ZEBRA) + zlog_info ("ZEBRA: I/F delete: %s index %d mtu %d", + ifp->name, ifp->ifindex, ifp->mtu); + + ospf6_interface_if_del (ifp); +#endif + + return 0; +} + +int +ospf6_zebra_if_state_update (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct interface *ifp; + + ifp = zebra_interface_state_read (zclient->ibuf); + + /* log */ + if (IS_OSPF6_DUMP_ZEBRA) + zlog_info ("ZEBRA: I/F %s state change: index %d flags %ld metric %d mtu %d", + ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu); + + ospf6_interface_state_update (ifp); + return 0; +} + +int +ospf6_zebra_if_address_update_add (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct connected *c; + char buf[128]; + + c = zebra_interface_address_add_read (zclient->ibuf); + if (c == NULL) + return 0; + + if (IS_OSPF6_DUMP_ZEBRA) + zlog_info ("ZEBRA: I/F %s address add: %5s %s/%d", + c->ifp->name, prefix_family_str (c->address), + inet_ntop (c->address->family, &c->address->u.prefix, + buf, sizeof (buf)), c->address->prefixlen); + + if (c->address->family == AF_INET6) + ospf6_interface_address_update (c->ifp); + + return 0; +} + +int +ospf6_zebra_if_address_update_delete (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct connected *c; + char buf[128]; + + c = zebra_interface_address_delete_read (zclient->ibuf); + if (c == NULL) + return 0; + + if (IS_OSPF6_DUMP_ZEBRA) + zlog_info ("ZEBRA: I/F %s address del: %5s %s/%d", + c->ifp->name, prefix_family_str (c->address), + inet_ntop (c->address->family, &c->address->u.prefix, + buf, sizeof (buf)), c->address->prefixlen); + + if (c->address->family == AF_INET6) + ospf6_interface_address_update (c->ifp); + + return 0; +} + + + +const char *zebra_route_name[ZEBRA_ROUTE_MAX] = +{ + "System", + "Kernel", + "Connect", + "Static", + "RIP", + "RIPng", + "OSPF", + "OSPF6", + "BGP", +}; + +const char *zebra_route_abname[ZEBRA_ROUTE_MAX] = + { "X", "K", "C", "S", "r", "R", "o", "O", "B" }; + +int +ospf6_zebra_read_ipv6 (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct stream *s; + struct zapi_ipv6 api; + unsigned long ifindex; + struct prefix_ipv6 p; + struct in6_addr *nexthop; + char prefixstr[128], nexthopstr[128]; + + s = zclient->ibuf; + ifindex = 0; + nexthop = NULL; + memset (&api, 0, sizeof (api)); + + /* Type, flags, message. */ + api.type = stream_getc (s); + api.flags = stream_getc (s); + api.message = stream_getc (s); + + /* IPv6 prefix. */ + memset (&p, 0, sizeof (struct prefix_ipv6)); + p.family = AF_INET6; + p.prefixlen = stream_getc (s); + stream_get (&p.prefix, s, PSIZE (p.prefixlen)); + + /* Nexthop, ifindex, distance, metric. */ + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) + { + api.nexthop_num = stream_getc (s); + nexthop = (struct in6_addr *) + malloc (api.nexthop_num * sizeof (struct in6_addr)); + stream_get (nexthop, s, api.nexthop_num * sizeof (struct in6_addr)); + } + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) + { + api.ifindex_num = stream_getc (s); + ifindex = stream_getl (s); + } + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) + api.distance = stream_getc (s); + else + api.distance = 0; + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) + api.metric = stream_getl (s); + else + api.metric = 0; + + /* log */ + if (IS_OSPF6_DUMP_ZEBRA) + { + prefix2str ((struct prefix *)&p, prefixstr, sizeof (prefixstr)); + inet_ntop (AF_INET6, &nexthop, nexthopstr, sizeof (nexthopstr)); + + if (command == ZEBRA_IPV6_ROUTE_ADD) + zlog_info ("ZEBRA: Receive add %s route: %s nexthop:%s ifindex:%ld", + zebra_route_name [api.type], prefixstr, + nexthopstr, ifindex); + else + zlog_info ("ZEBRA: Receive remove %s route: %s nexthop:%s ifindex:%ld", + zebra_route_name [api.type], prefixstr, + nexthopstr, ifindex); + } + + if (command == ZEBRA_IPV6_ROUTE_ADD) + ospf6_asbr_route_add (api.type, ifindex, (struct prefix *) &p, + api.nexthop_num, nexthop); + else + ospf6_asbr_route_remove (api.type, ifindex, (struct prefix *) &p); + + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) + free (nexthop); + + return 0; +} + + +DEFUN (show_zebra, + show_zebra_cmd, + "show zebra", + SHOW_STR + "Zebra information\n") +{ + int i; + if (!zclient) + vty_out (vty, "Not connected to zebra%s", VTY_NEWLINE); + + vty_out (vty, "Zebra Infomation%s", VTY_NEWLINE); + vty_out (vty, " enable: %d%s", zclient->enable, VTY_NEWLINE); + vty_out (vty, " fail: %d%s", zclient->fail, VTY_NEWLINE); + vty_out (vty, " redistribute default: %d%s", zclient->redist_default, + VTY_NEWLINE); + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + vty_out (vty, " RouteType: %s - %s%s", zebra_route_name[i], + zclient->redist[i] ? "redistributed" : "not redistributed", + VTY_NEWLINE); + return CMD_SUCCESS; +} + +DEFUN (router_zebra, + router_zebra_cmd, + "router zebra", + "Enable a routing process\n" + "Make connection to zebra daemon\n") +{ + if (IS_OSPF6_DUMP_CONFIG) + zlog_info ("Config: router zebra"); + + vty->node = ZEBRA_NODE; + zclient->enable = 1; + zclient_start (zclient); + return CMD_SUCCESS; +} + +DEFUN (no_router_zebra, + no_router_zebra_cmd, + "no router zebra", + NO_STR + "Configure routing process\n" + "Disable connection to zebra daemon\n") +{ + if (IS_OSPF6_DUMP_CONFIG) + zlog_info ("no router zebra"); + + zclient->enable = 0; + zclient_stop (zclient); + return CMD_SUCCESS; +} + +/* Zebra configuration write function. */ +int +ospf6_zebra_config_write (struct vty *vty) +{ + if (! zclient->enable) + { + vty_out (vty, "no router zebra%s", VTY_NEWLINE); + return 1; + } + else if (! zclient->redist[ZEBRA_ROUTE_OSPF6]) + { + vty_out (vty, "router zebra%s", VTY_NEWLINE); + vty_out (vty, " no redistribute ospf6%s", VTY_NEWLINE); + return 1; + } + return 0; +} + +/* Zebra node structure. */ +struct cmd_node zebra_node = +{ + ZEBRA_NODE, + "%s(config-zebra)# ", +}; + +#define ADD 0 +#define CHANGE 1 +#define REMOVE 2 + +static void +ospf6_zebra_route_update (int type, struct ospf6_route_req *request) +{ + char buf[96], ifname[IFNAMSIZ]; + + struct zapi_ipv6 api; + struct ospf6_route_req route; + struct linklist *nexthop_list; + struct linklist_node node; + struct ospf6_nexthop *nexthop = NULL; + struct in6_addr **nexthops; + unsigned int *ifindexes; + struct prefix_ipv6 *p; + int i, ret = 0; + + if (IS_OSPF6_DUMP_ZEBRA) + { + prefix2str (&request->route.prefix, buf, sizeof (buf)); + if (type == REMOVE) + zlog_info ("ZEBRA: Send remove route: %s", buf); + else + zlog_info ("ZEBRA: Send add route: %s", buf); + } + + if (zclient->sock < 0) + { + if (IS_OSPF6_DUMP_ZEBRA) + zlog_info ("ZEBRA: failed: not connected to zebra"); + return; + } + + if (request->path.origin.adv_router == ospf6->router_id && + (request->path.type == OSPF6_PATH_TYPE_EXTERNAL1 || + request->path.type == OSPF6_PATH_TYPE_EXTERNAL2)) + { + if (IS_OSPF6_DUMP_ZEBRA) + zlog_info ("ZEBRA: self originated external route, ignore"); + return; + } + + /* Only the best path (i.e. the first path of the path-list + in 'struct ospf6_route') will be sent to zebra. */ + ospf6_route_lookup (&route, &request->route.prefix, request->table); + if (memcmp (&route.path, &request->path, sizeof (route.path))) + { + /* this is not preferred best route, ignore */ + if (IS_OSPF6_DUMP_ZEBRA) + zlog_info ("ZEBRA: not best path, ignore"); + return; + } + + nexthop_list = linklist_create (); + + /* for each nexthop */ + for (ospf6_route_lookup (&route, &request->route.prefix, request->table); + ! ospf6_route_end (&route); ospf6_route_next (&route)) + { + if (memcmp (&route.path, &request->path, sizeof (route.path))) + break; + + #define IN6_IS_ILLEGAL_NEXTHOP(a)\ + ((*(u_int32_t *)(void *)(&(a)->s6_addr[0]) == 0xffffffff) &&\ + (*(u_int32_t *)(void *)(&(a)->s6_addr[4]) == 0xffffffff) &&\ + (*(u_int32_t *)(void *)(&(a)->s6_addr[8]) == 0xffffffff) &&\ + (*(u_int32_t *)(void *)(&(a)->s6_addr[12]) == 0xffffffff)) + if (IN6_IS_ILLEGAL_NEXTHOP (&route.nexthop.address)) + { + zlog_warn ("ZEBRA: Illegal nexthop"); + continue; + } + + if (type == REMOVE && ! memcmp (&route.nexthop, &request->nexthop, + sizeof (struct ospf6_nexthop))) + continue; + + nexthop = XCALLOC (MTYPE_OSPF6_OTHER, sizeof (struct ospf6_nexthop)); + if (! nexthop) + { + zlog_warn ("ZEBRA: Can't update nexthop: malloc failed"); + continue; + } + + memcpy (nexthop, &route.nexthop, sizeof (struct ospf6_nexthop)); + linklist_add (nexthop, nexthop_list); + } + + if (type == REMOVE && nexthop_list->count != 0) + type = ADD; + else if (type == REMOVE && nexthop_list->count == 0) + { + if (IS_OSPF6_DUMP_ZEBRA) + zlog_info ("ZEBRA: all nexthop with the selected path has gone"); + + if (! memcmp (&request->route, &route.route, + sizeof (struct ospf6_route))) + { + /* send 'add' of alternative route */ + struct ospf6_path seconde_path; + + if (IS_OSPF6_DUMP_ZEBRA) + zlog_info ("ZEBRA: found alternative path to add"); + + memcpy (&seconde_path, &route.path, sizeof (struct ospf6_path)); + type = ADD; + + while (! memcmp (&seconde_path, &route.path, + sizeof (struct ospf6_path))) + { + nexthop = XCALLOC (MTYPE_OSPF6_OTHER, + sizeof (struct ospf6_nexthop)); + if (! nexthop) + zlog_warn ("ZEBRA: Can't update nexthop: malloc failed"); + else + { + memcpy (nexthop, &route.nexthop, + sizeof (struct ospf6_nexthop)); + linklist_add (nexthop, nexthop_list); + } + + ospf6_route_next (&route); + } + } + else + { + /* there is no alternative route. send 'remove' to zebra for + requested route */ + if (IS_OSPF6_DUMP_ZEBRA) + zlog_info ("ZEBRA: can't find alternative path, remove"); + + if (IS_OSPF6_DUMP_ZEBRA) + { + zlog_info ("ZEBRA: Debug: walk over the route ?"); + ospf6_route_log_request ("Debug route", "***", &route); + ospf6_route_log_request ("Debug request", "***", request); + } + + nexthop = XCALLOC (MTYPE_OSPF6_OTHER, + sizeof (struct ospf6_nexthop)); + if (! nexthop) + zlog_warn ("ZEBRA: Can't update nexthop: malloc failed"); + else + { + memcpy (nexthop, &request->nexthop, + sizeof (struct ospf6_nexthop)); + linklist_add (nexthop, nexthop_list); + } + } + } + + if (nexthop_list->count == 0) + { + if (IS_OSPF6_DUMP_ZEBRA) + zlog_info ("ZEBRA: no nexthop, ignore"); + linklist_delete (nexthop_list); + return; + } + + /* allocate memory for nexthop_list */ + nexthops = XCALLOC (MTYPE_OSPF6_OTHER, + nexthop_list->count * sizeof (struct in6_addr *)); + if (! nexthops) + { + zlog_warn ("ZEBRA: Can't update zebra route: malloc failed"); + for (linklist_head (nexthop_list, &node); !linklist_end (&node); + linklist_next (&node)) + XFREE (MTYPE_OSPF6_OTHER, node.data); + linklist_delete (nexthop_list); + return; + } + + /* allocate memory for ifindex_list */ + ifindexes = XCALLOC (MTYPE_OSPF6_OTHER, + nexthop_list->count * sizeof (unsigned int)); + if (! ifindexes) + { + zlog_warn ("ZEBRA: Can't update zebra route: malloc failed"); + for (linklist_head (nexthop_list, &node); !linklist_end (&node); + linklist_next (&node)) + XFREE (MTYPE_OSPF6_OTHER, node.data); + linklist_delete (nexthop_list); + XFREE (MTYPE_OSPF6_OTHER, nexthops); + return; + } + + i = 0; + for (linklist_head (nexthop_list, &node); ! linklist_end (&node); + linklist_next (&node)) + { + nexthop = node.data; + if (IS_OSPF6_DUMP_ZEBRA) + { + inet_ntop (AF_INET6, &nexthop->address, buf, sizeof (buf)); + if_indextoname (nexthop->ifindex, ifname); + zlog_info ("ZEBRA: nexthop: %s%%%s(%d)", + buf, ifname, nexthop->ifindex); + } + nexthops[i] = &nexthop->address; + ifindexes[i] = nexthop->ifindex; + i++; + } + + api.type = ZEBRA_ROUTE_OSPF6; + api.flags = 0; + api.message = 0; + SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); + SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX); + api.nexthop_num = nexthop_list->count; + api.nexthop = nexthops; + api.ifindex_num = nexthop_list->count; + api.ifindex = ifindexes; + + p = (struct prefix_ipv6 *) &request->route.prefix; + if (type == REMOVE && nexthop_list->count == 1) + ret = zapi_ipv6_delete (zclient, p, &api); + else + ret = zapi_ipv6_add (zclient, p, &api); + + if (ret < 0) + zlog_err ("ZEBRA: zapi_ipv6_add () failed: %s", strerror (errno)); + + for (linklist_head (nexthop_list, &node); !linklist_end (&node); + linklist_next (&node)) + XFREE (MTYPE_OSPF6_OTHER, node.data); + linklist_delete (nexthop_list); + XFREE (MTYPE_OSPF6_OTHER, nexthops); + XFREE (MTYPE_OSPF6_OTHER, ifindexes); + + return; +} + +void +ospf6_zebra_route_update_add (struct ospf6_route_req *request) +{ + ospf6_zebra_route_update (ADD, request); +} + +void +ospf6_zebra_route_update_remove (struct ospf6_route_req *request) +{ + ospf6_zebra_route_update (REMOVE, request); +} + +static void +ospf6_zebra_redistribute_ospf6 () +{ + struct route_node *node; + + for (node = route_top (ospf6->route_table->table); node; + node = route_next (node)) + { + if (! node || ! node->info) + continue; + ospf6_zebra_route_update_add (node->info); + } +} + +static void +ospf6_zebra_no_redistribute_ospf6 () +{ + struct route_node *node; + + if (! ospf6) + return; + + for (node = route_top (ospf6->route_table->table); node; + node = route_next (node)) + { + if (! node || ! node->info) + continue; + + ospf6_zebra_route_update_remove (node->info); + } +} + + +DEFUN (redistribute_ospf6, + redistribute_ospf6_cmd, + "redistribute ospf6", + "Redistribute control\n" + "OSPF6 route\n") +{ + /* log */ + if (IS_OSPF6_DUMP_CONFIG) + zlog_info ("Config: redistribute ospf6"); + + zclient->redist[ZEBRA_ROUTE_OSPF6] = 1; + + /* set zebra route table */ + ospf6_zebra_redistribute_ospf6 (); + + return CMD_SUCCESS; +} + +DEFUN (no_redistribute_ospf6, + no_redistribute_ospf6_cmd, + "no redistribute ospf6", + NO_STR + "Redistribute control\n" + "OSPF6 route\n") +{ + /* log */ + if (IS_OSPF6_DUMP_CONFIG) + zlog_info ("Config: no redistribute ospf6"); + + zclient->redist[ZEBRA_ROUTE_OSPF6] = 0; + + if (! ospf6) + return CMD_SUCCESS; + + /* clean up zebra route table */ + ospf6_zebra_no_redistribute_ospf6 (); + + ospf6_route_hook_unregister (ospf6_zebra_route_update_add, + ospf6_zebra_route_update_add, + ospf6_zebra_route_update_remove, + ospf6->route_table); + + return CMD_SUCCESS; +} + +void +ospf6_zebra_init () +{ + /* Allocate zebra structure. */ + zclient = zclient_new (); + zclient_init (zclient, ZEBRA_ROUTE_OSPF6); + zclient->interface_add = ospf6_zebra_if_add; + zclient->interface_delete = ospf6_zebra_if_del; + zclient->interface_up = ospf6_zebra_if_state_update; + zclient->interface_down = ospf6_zebra_if_state_update; + zclient->interface_address_add = ospf6_zebra_if_address_update_add; + zclient->interface_address_delete = ospf6_zebra_if_address_update_delete; + zclient->ipv4_route_add = NULL; + zclient->ipv4_route_delete = NULL; + zclient->ipv6_route_add = ospf6_zebra_read_ipv6; + zclient->ipv6_route_delete = ospf6_zebra_read_ipv6; + + /* redistribute connected route by default */ + /* ospf6_zebra_redistribute (ZEBRA_ROUTE_CONNECT); */ + + /* Install zebra node. */ + install_node (&zebra_node, ospf6_zebra_config_write); + + /* Install command element for zebra node. */ + install_element (VIEW_NODE, &show_zebra_cmd); + install_element (ENABLE_NODE, &show_zebra_cmd); + install_element (CONFIG_NODE, &router_zebra_cmd); + install_element (CONFIG_NODE, &no_router_zebra_cmd); + install_default (ZEBRA_NODE); + install_element (ZEBRA_NODE, &redistribute_ospf6_cmd); + install_element (ZEBRA_NODE, &no_redistribute_ospf6_cmd); + +#if 0 + hook.name = "ZebraRouteUpdate"; + hook.hook_add = ospf6_zebra_route_update_add; + hook.hook_change = ospf6_zebra_route_update_add; + hook.hook_remove = ospf6_zebra_route_update_remove; + ospf6_hook_register (&hook, &route_hook); +#endif + + return; +} + +void +ospf6_zebra_finish () +{ + zclient_stop (zclient); + zclient_free (zclient); + zclient = (struct zclient *) NULL; +} + diff --git a/ospf6d/ospf6_zebra.h b/ospf6d/ospf6_zebra.h new file mode 100644 index 000000000..d86b2db78 --- /dev/null +++ b/ospf6d/ospf6_zebra.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 1999 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF6_ZEBRA_H +#define OSPF6_ZEBRA_H + +extern struct zclient *zclient; + +void ospf6_zebra_redistribute (int); +void ospf6_zebra_no_redistribute (int); +int ospf6_zebra_is_redistribute (int); + +int ospf6_zebra_get_interface (int, struct zclient *, zebra_size_t); +int ospf6_zebra_read (struct thread *); +void ospf6_zebra_init (); +void ospf6_zebra_finish (); +void ospf6_zebra_start (); + +int ospf6_zebra_read_ipv6 (int, struct zclient *, zebra_size_t); + +extern const char *zebra_route_name[ZEBRA_ROUTE_MAX]; +extern const char *zebra_route_abname[ZEBRA_ROUTE_MAX]; + +void ospf6_zebra_route_update_add (struct ospf6_route_req *request); +void ospf6_zebra_route_update_remove (struct ospf6_route_req *request); + +#endif /*OSPF6_ZEBRA_H*/ + diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c new file mode 100644 index 000000000..dbe7a88f2 --- /dev/null +++ b/ospf6d/ospf6d.c @@ -0,0 +1,826 @@ +/* + * Copyright (C) 1999 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "ospf6d.h" + +#include "ospf6_damp.h" + +/* global ospf6d variable */ +int ospf6_sock; +list iflist; +list nexthoplist = NULL; +struct sockaddr_in6 allspfrouters6; +struct sockaddr_in6 alldrouters6; +char *recent_reason; /* set by ospf6_lsa_check_recent () */ +int proctitle_mode = 0; + +char ospf6_daemon_version[] = OSPF6_DAEMON_VERSION; + + +#define TIMER_SEC_MICRO 1000000 + +void +ospf6_timeval_sub (const struct timeval *t1, const struct timeval *t2, + struct timeval *result) +{ + long usec, movedown = 0; + + if (t1->tv_sec < t2->tv_sec || + (t1->tv_sec == t2->tv_sec && t1->tv_usec < t2->tv_usec)) + { + result->tv_sec = 0; + result->tv_usec = 0; + return; + } + + if (t1->tv_usec < t2->tv_usec) + { + usec = t1->tv_usec + TIMER_SEC_MICRO; + movedown++; + } + else + usec = t1->tv_usec; + result->tv_usec = usec - t2->tv_usec; + + result->tv_sec = t1->tv_sec - t2->tv_sec - movedown; +} + +void +ospf6_timeval_div (const struct timeval *t1, u_int by, + struct timeval *result) +{ + long movedown; + + if (by == 0) + { + result->tv_sec = 0; + result->tv_usec = 0; + return; + } + + movedown = t1->tv_sec % by; + result->tv_sec = t1->tv_sec / by; + result->tv_usec = (t1->tv_usec + movedown * TIMER_SEC_MICRO) / by; +} + +void +ospf6_timeval_decode (const struct timeval *t, long *dayp, long *hourp, + long *minp, long *secp, long *msecp, long *usecp) +{ + long day, hour, min, sec, msec, usec, left; + + left = t->tv_sec; + day = left / 86400; left -= day * 86400; + hour = left / 3600; left -= hour * 3600; + min = left / 60; left -= min * 60; + sec = left; + left = t->tv_usec; + msec = left / 1000; left -= msec * 1000; + usec = left; + + if (dayp) *dayp = day; + if (hourp) *hourp = hour; + if (minp) *minp = min; + if (secp) *secp = sec; + if (msecp) *msecp = msec; + if (usecp) *usecp = usec; +} + +void +ospf6_timeval_string (struct timeval *tv, char *buf, int size) +{ + char days[16], hours[16], mins[16], secs[16], msecs[16], usecs[16]; + long day, hour, min, sec, msec, usec; + + ospf6_timeval_decode (tv, &day, &hour, &min, &sec, &msec, &usec); + snprintf (days, sizeof (days), "%ld days ", day); + snprintf (hours, sizeof (hours), "%ld hours ", hour); + snprintf (mins, sizeof (mins), "%ld mins ", min); + snprintf (secs, sizeof (secs), "%ld secs ", sec); + snprintf (msecs, sizeof (msecs), "%ld msecs ", msec); + snprintf (usecs, sizeof (usecs), "%ld usecs ", usec); + + snprintf (buf, size, "%s%s%s%s%s%s", + (day ? days : ""), (hour ? hours : ""), + (min ? mins : ""), (sec ? secs : ""), + (msec ? msecs : ""), (usec ? usecs : "")); +} + +void +ospf6_timeval_string_summary (struct timeval *tv, char *buf, int size) +{ + char days[16], hours[16], mins[16], secs[16], msecs[16], usecs[16]; + long day, hour, min, sec, msec, usec; + + ospf6_timeval_decode (tv, &day, &hour, &min, &sec, &msec, &usec); + snprintf (days, sizeof (days), "%02ldd", day); + snprintf (hours, sizeof (hours), "%ldh", hour); + snprintf (mins, sizeof (mins), "%ldm", min); + snprintf (secs, sizeof (secs), "%lds", sec); + snprintf (msecs, sizeof (msecs), "%ldms", msec); + snprintf (usecs, sizeof (usecs), "%ldus", usec); + + snprintf (buf, size, "%s%02ld:%02ld:%02ld", + (day ? days : ""), hour, min, sec); +} + +/* foreach function */ +void +ospf6_count_state (void *arg, int val, void *obj) +{ + int *count = (int *) arg; + u_char state = val; + struct ospf6_neighbor *nei = (struct ospf6_neighbor *) obj; + + if (nei->state == state) + (*count)++; +} + +/* VTY commands. */ +DEFUN (reload, + reload_cmd, + "reload", + "Reloads\n") +{ + extern void _reload (); + _reload (); + return CMD_SUCCESS; +} + +DEFUN (garbage_collection, + garbage_collection_cmd, + "ipv6 ospf6 garbage collect", + IPV6_STR + OSPF6_STR + "garbage collection by hand\n" + "Remove Maxages if possible and recalculate routes\n") +{ + ospf6_maxage_remover (); +#if 0 + ospf6_route_calculation_schedule (); +#endif + return CMD_SUCCESS; +} + +/* Show version. */ +DEFUN (show_version_ospf6, + show_version_ospf6_cmd, + "show version ospf6", + SHOW_STR + "Displays ospf6d version\n") +{ + vty_out (vty, "Zebra OSPF6d Version: %s%s", + ospf6_daemon_version, VTY_NEWLINE); + + return CMD_SUCCESS; +} + +/* start ospf6 */ +DEFUN (router_ospf6, + router_ospf6_cmd, + "router ospf6", + OSPF6_ROUTER_STR + OSPF6_STR) +{ + if (ospf6 == NULL) + ospf6_start (); + + /* set current ospf point. */ + vty->node = OSPF6_NODE; + vty->index = ospf6; + + return CMD_SUCCESS; +} + +/* stop ospf6 */ +DEFUN (no_router_ospf6, + no_router_ospf6_cmd, + "no router ospf6", + NO_STR + OSPF6_ROUTER_STR) +{ + if (!ospf6) + vty_out (vty, "OSPFv3 is not running%s", VTY_NEWLINE); + else + ospf6_stop (); + + /* return to config node . */ + vty->node = CONFIG_NODE; + vty->index = NULL; + + return CMD_SUCCESS; +} + +/* show top level structures */ +DEFUN (show_ipv6_ospf6, + show_ipv6_ospf6_cmd, + "show ipv6 ospf6", + SHOW_STR + IP6_STR + OSPF6_STR) +{ + OSPF6_CMD_CHECK_RUNNING (); + + ospf6_show (vty); + return CMD_SUCCESS; +} + +DEFUN (show_ipv6_ospf6_nexthoplist, + show_ipv6_ospf6_nexthoplist_cmd, + "show ipv6 ospf6 nexthop-list", + SHOW_STR + IP6_STR + OSPF6_STR + "List of nexthop\n") +{ +#if 0 + listnode i; + struct ospf6_nexthop *nh; + char buf[128]; + for (i = listhead (nexthoplist); i; nextnode (i)) + { + nh = (struct ospf6_nexthop *) getdata (i); + nexthop_str (nh, buf, sizeof (buf)); + vty_out (vty, "%s%s", buf, + VTY_NEWLINE); + } +#endif + return CMD_SUCCESS; +} + +DEFUN (show_ipv6_ospf6_statistics, + show_ipv6_ospf6_statistics_cmd, + "show ipv6 ospf6 statistics", + SHOW_STR + IP6_STR + OSPF6_STR + "Statistics\n") +{ + OSPF6_CMD_CHECK_RUNNING (); + + ospf6_statistics_show (vty, ospf6); + return CMD_SUCCESS; +} + +/* change Router_ID commands. */ +DEFUN (router_id, + router_id_cmd, + "router-id ROUTER_ID", + "Configure ospf Router-ID.\n" + V4NOTATION_STR) +{ + int ret; + u_int32_t router_id; + + ret = inet_pton (AF_INET, argv[0], &router_id); + if (!ret) + { + vty_out (vty, "malformed ospf router identifier%s", VTY_NEWLINE); + vty_out (vty, "%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (IS_OSPF6_DUMP_CONFIG) + zlog_info ("CONFIG: router-id %s", argv[0]); + ospf6->router_id = router_id; + + return CMD_SUCCESS; +} + +int +ospf6_interface_bind_area (struct vty *vty, + char *if_name, char *area_name, + char *plist_name, int passive) +{ + struct interface *ifp; + struct ospf6_interface *o6i; + struct ospf6_area *o6a; + u_int32_t area_id; + + /* find/create ospf6 interface */ + ifp = if_get_by_name (if_name); + o6i = (struct ospf6_interface *) ifp->info; + if (! o6i) + o6i = ospf6_interface_create (ifp); + + /* parse Area-ID */ + if (inet_pton (AF_INET, area_name, &area_id) != 1) + { + vty_out (vty, "Invalid Area-ID: %s%s", area_name, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + /* find/create ospf6 area */ + o6a = ospf6_area_lookup (area_id, ospf6); + if (!o6a) + { + o6a = ospf6_area_create (area_id); + o6a->ospf6 = ospf6; + listnode_add (ospf6->area_list, o6a); + } + + if (o6i->area) + { + if (o6i->area != o6a) + { + vty_out (vty, "Aready attached to area %s%s", + o6i->area->str, VTY_NEWLINE); + return CMD_ERR_NOTHING_TODO; + } + } + else + { + listnode_add (o6a->if_list, o6i); + o6i->area = o6a; + } + + /* prefix-list name */ + if (plist_name) + { + if (o6i->plist_name) + XFREE (MTYPE_PREFIX_LIST_STR, o6i->plist_name); + o6i->plist_name = XSTRDUP (MTYPE_PREFIX_LIST_STR, plist_name); + } + else + { + if (o6i->plist_name) + XFREE (MTYPE_PREFIX_LIST_STR, o6i->plist_name); + o6i->plist_name = NULL; + } + + if (passive) + { + listnode node; + struct ospf6_neighbor *o6n; + + SET_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_PASSIVE); + if (o6i->thread_send_hello) + { + thread_cancel (o6i->thread_send_hello); + o6i->thread_send_hello = (struct thread *) NULL; + } + + for (node = listhead (o6i->neighbor_list); node; nextnode (node)) + { + o6n = getdata (node); + if (o6n->inactivity_timer) + thread_cancel (o6n->inactivity_timer); + thread_execute (master, inactivity_timer, o6n, 0); + } + } + else + { + UNSET_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_PASSIVE); + if (o6i->thread_send_hello == NULL) + thread_add_event (master, ospf6_send_hello, o6i, 0); + } + + /* enable I/F if it's not enabled still */ + if (! ospf6_interface_is_enabled (o6i->interface->ifindex)) + thread_add_event (master, interface_up, o6i, 0); + else + CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, o6i); + + CALL_CHANGE_HOOK (&interface_hook, o6i); + return CMD_SUCCESS; +} + +DEFUN (interface_area_plist, + interface_area_plist_cmd, + "interface IFNAME area A.B.C.D prefix-list WORD", + "Enable routing on an IPv6 interface\n" + IFNAME_STR + "Set the OSPF6 area ID\n" + "OSPF6 area ID in IPv4 address notation\n" + OSPF6_PREFIX_LIST_STR + "IPv6 prefix-list name\n" + ) +{ + if (IS_OSPF6_DUMP_CONFIG) + zlog_info ("CONFIG: interface %s area %s prefix-list %s", + argv[0], argv[1], argv[2]); + + return ospf6_interface_bind_area (vty, argv[0], argv[1], argv[2], 0); +} + +DEFUN (interface_area_plist_passive, + interface_area_plist_passive_cmd, + "interface IFNAME area A.B.C.D prefix-list WORD passive", + "Enable routing on an IPv6 interface\n" + IFNAME_STR + "Set the OSPF6 area ID\n" + "OSPF6 area ID in IPv4 address notation\n" + OSPF6_PREFIX_LIST_STR + "IPv6 prefix-list name\n" + "IPv6 prefix-list name\n" + OSPF6_PASSIVE_STR + ) +{ + if (IS_OSPF6_DUMP_CONFIG) + zlog_info ("CONFIG: interface %s area %s prefix-list %s passive", + argv[0], argv[1], argv[2]); + + return ospf6_interface_bind_area (vty, argv[0], argv[1], argv[2], 1); +} + +DEFUN (interface_area, + interface_area_cmd, + "interface IFNAME area A.B.C.D", + "Enable routing on an IPv6 interface\n" + IFNAME_STR + "Set the OSPF6 area ID\n" + "OSPF6 area ID in IPv4 address notation\n" + ) +{ + struct interface *ifp; + struct ospf6_interface *o6i; + int passive; + char *plist_name; + + if (IS_OSPF6_DUMP_CONFIG) + zlog_info ("CONFIG: interface %s area %s", + argv[0], argv[1]); + + ifp = if_get_by_name (argv[0]); + o6i = (struct ospf6_interface *) ifp->info; + if (o6i) + { + passive = CHECK_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_PASSIVE); + plist_name = o6i->plist_name; + } + else + { + passive = 0; + plist_name = NULL; + } + + return ospf6_interface_bind_area (vty, argv[0], argv[1], + plist_name, passive); +} + +DEFUN (interface_area_passive, + interface_area_passive_cmd, + "interface IFNAME area A.B.C.D passive", + "Enable routing on an IPv6 interface\n" + IFNAME_STR + "Set the OSPF6 area ID\n" + "OSPF6 area ID in IPv4 address notation\n" + OSPF6_PASSIVE_STR + ) +{ + if (IS_OSPF6_DUMP_CONFIG) + zlog_info ("CONFIG: interface %s area %s passive", + argv[0], argv[1]); + + return ospf6_interface_bind_area (vty, argv[0], argv[1], NULL, 1); +} + +DEFUN (no_interface_area, + no_interface_area_cmd, + "no interface IFNAME area A.B.C.D", + NO_STR + "Disable routing on an IPv6 interface\n" + IFNAME_STR) +{ + struct interface *ifp; + struct ospf6_interface *o6i; + struct ospf6 *o6; + u_int32_t area_id; + + o6 = (struct ospf6 *) vty->index; + + ifp = if_lookup_by_name (argv[0]); + if (!ifp) + return CMD_ERR_NO_MATCH; + + o6i = (struct ospf6_interface *) ifp->info; + if (!o6i) + return CMD_SUCCESS; + + /* parse Area-ID */ + if (inet_pton (AF_INET, argv[1], &area_id) != 1) + { + vty_out (vty, "Invalid Area-ID: %s%s", argv[1], VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + if (o6i->area->area_id != area_id) + { + vty_out (vty, "Wrong Area-ID: %s aready attached to area %s%s", + o6i->interface->name, o6i->area->str, VTY_NEWLINE); + return CMD_ERR_NOTHING_TODO; + } + + if (o6i->area) + thread_execute (master, interface_down, o6i, 0); + + listnode_delete (o6i->area->if_list, o6i); + o6i->area = (struct ospf6_area *) NULL; + + return CMD_SUCCESS; +} + +DEFUN (area_range, + area_range_cmd, + "area A.B.C.D range X:X::X:X/M", + "OSPFv3 area parameters\n" + "OSPFv3 area ID in IPv4 address format\n" + "Summarize routes matching address/mask (border routers only)\n" + "IPv6 address range\n") +{ + struct ospf6 *o6; + struct ospf6_area *o6a; + u_int32_t area_id; + int ret; + + o6 = (struct ospf6 *) vty->index; + inet_pton (AF_INET, argv[0], &area_id); + o6a = ospf6_area_lookup (area_id, o6); + if (! o6a) + { + vty_out (vty, "No such area%s", VTY_NEWLINE); + return CMD_ERR_NO_MATCH; + } + + ret = str2prefix_ipv6 (argv[1], &o6a->area_range); + if (ret <= 0) + { + vty_out (vty, "Malformed IPv6 address%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +DEFUN (passive_interface, + passive_interface_cmd, + "passive-interface IFNAME", + OSPF6_PASSIVE_STR + IFNAME_STR) +{ + struct interface *ifp; + struct ospf6_interface *o6i; + + ifp = if_get_by_name (argv[0]); + if (ifp->info) + o6i = (struct ospf6_interface *) ifp->info; + else + o6i = ospf6_interface_create (ifp); + + SET_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_PASSIVE); + + if (o6i->thread_send_hello) + { + thread_cancel (o6i->thread_send_hello); + o6i->thread_send_hello = (struct thread *) NULL; + } + + return CMD_SUCCESS; +} + +DEFUN (no_passive_interface, + no_passive_interface_cmd, + "no passive-interface IFNAME", + NO_STR + OSPF6_PASSIVE_STR + IFNAME_STR) +{ + struct interface *ifp; + struct ospf6_interface *o6i; + + ifp = if_lookup_by_name (argv[0]); + if (! ifp) + return CMD_ERR_NO_MATCH; + + o6i = (struct ospf6_interface *) ifp->info; + UNSET_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_PASSIVE); + if (o6i->thread_send_hello == NULL) + thread_add_event (master, ospf6_send_hello, o6i, 0); + + return CMD_SUCCESS; +} + +#ifdef HAVE_SETPROCTITLE +extern int _argc; +extern char **_argv; + +DEFUN (set_proctitle, + set_proctitle_cmd, + "set proctitle (version|normal|none)", + "Set command\n" + "Process title\n" + "Version information\n" + "Normal command-line options\n" + "Just program name\n") +{ + int i; + char buf[64], tmp[64]; + + if (strncmp (argv[0], "v", 1) == 0) + { + proctitle_mode = 1; + setproctitle ("%s Zebra: %s", OSPF6_DAEMON_VERSION, ZEBRA_VERSION); + } + else if (strncmp (argv[0], "nor", 3) == 0) + { + proctitle_mode = 0; + memset (tmp, 0, sizeof (tmp)); + memset (buf, 0, sizeof (buf)); + for (i = 0; i < _argc; i++) + { + snprintf (buf, sizeof (buf), "%s%s ", tmp, _argv[i]); + memcpy (&tmp, &buf, sizeof (tmp)); + } + setproctitle (buf); + } + else if (strncmp (argv[0], "non", 3) == 0) + { + proctitle_mode = -1; + setproctitle (NULL); + } + else + return CMD_ERR_NO_MATCH; + + return CMD_SUCCESS; +} +#endif /* HAVE_SETPROCTITLE */ + +/* OSPF configuration write function. */ +int +ospf6_config_write (struct vty *vty) +{ + listnode j, k; + char buf[64]; + struct ospf6_area *area; + struct ospf6_interface *o6i; + + if (proctitle_mode == 1) + vty_out (vty, "set proctitle version%s", VTY_NEWLINE); + else if (proctitle_mode == -1) + vty_out (vty, "set proctitle none%s", VTY_NEWLINE); + + vty_out (vty, "!%s", VTY_NEWLINE); + + if (! ospf6) + return 0; + + /* OSPFv6 configuration. */ + if (!ospf6) + return CMD_SUCCESS; + + inet_ntop (AF_INET, &ospf6->router_id, buf, sizeof (buf)); + vty_out (vty, "router ospf6%s", VTY_NEWLINE); + vty_out (vty, " router-id %s%s", buf, VTY_NEWLINE); + + ospf6_redistribute_config_write (vty); + ospf6_damp_config_write (vty); + + for (j = listhead (ospf6->area_list); j; nextnode (j)) + { + area = (struct ospf6_area *)getdata (j); + for (k = listhead (area->if_list); k; nextnode (k)) + { + o6i = (struct ospf6_interface *) getdata (k); + vty_out (vty, " interface %s area %s%s", + o6i->interface->name, area->str, VTY_NEWLINE); + } + } + vty_out (vty, "!%s", VTY_NEWLINE); + return 0; +} + +/* OSPF6 node structure. */ +struct cmd_node ospf6_node = +{ + OSPF6_NODE, + "%s(config-ospf6)# ", +}; + +/* Install ospf related commands. */ +void +ospf6_init () +{ + /* Install ospf6 top node. */ + install_node (&ospf6_node, ospf6_config_write); + + install_element (VIEW_NODE, &show_ipv6_ospf6_cmd); + install_element (VIEW_NODE, &show_version_ospf6_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_cmd); + install_element (ENABLE_NODE, &show_version_ospf6_cmd); + install_element (ENABLE_NODE, &reload_cmd); + install_element (CONFIG_NODE, &router_ospf6_cmd); + install_element (CONFIG_NODE, &interface_cmd); +#ifdef OSPF6_STATISTICS + install_element (VIEW_NODE, &show_ipv6_ospf6_statistics_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_statistics_cmd); +#endif /* OSPF6_STATISTICS */ +#ifdef OSPF6_GARBAGE_COLLECT + install_element (ENABLE_NODE, &garbage_collection_cmd); +#endif /* OSPF6_GARBAGE_COLLECT */ +#ifdef HAVE_SETPROCTITLE + install_element (CONFIG_NODE, &set_proctitle_cmd); +#endif /* HAVE_SETPROCTITLE */ + + install_default (OSPF6_NODE); + install_element (OSPF6_NODE, &router_id_cmd); + install_element (OSPF6_NODE, &interface_area_cmd); + install_element (OSPF6_NODE, &interface_area_passive_cmd); + install_element (OSPF6_NODE, &interface_area_plist_cmd); + install_element (OSPF6_NODE, &interface_area_plist_passive_cmd); + install_element (OSPF6_NODE, &no_interface_area_cmd); + install_element (OSPF6_NODE, &passive_interface_cmd); + install_element (OSPF6_NODE, &no_passive_interface_cmd); + install_element (OSPF6_NODE, &area_range_cmd); + + /* Make empty list of top list. */ + if_init (); + + /* Install access list */ + access_list_init (); + + /* Install prefix list */ + prefix_list_init (); + + ospf6_dump_init (); + +#ifdef HAVE_OSPF6_DAMP + ospf6_damp_init (); +#endif /*HAVE_OSPF6_DAMP*/ + + ospf6_hook_init (); + ospf6_lsa_init (); + + ospf6_top_init (); + ospf6_area_init (); + ospf6_interface_init (); + ospf6_neighbor_init (); + ospf6_zebra_init (); + + ospf6_routemap_init (); + ospf6_lsdb_init (); + + ospf6_spf_init (); + + ospf6_intra_init (); + ospf6_abr_init (); + ospf6_asbr_init (); +} + +void +ospf6_terminate () +{ + /* stop ospf6 */ + ospf6_stop (); + + /* log */ + zlog (NULL, LOG_INFO, "OSPF6d terminated"); +} + +void +ospf6_maxage_remover () +{ +#if 0 + if (IS_OSPF6_DUMP_LSDB) + zlog_info ("MaxAge Remover"); +#endif + + ospf6_top_schedule_maxage_remover (NULL, 0, ospf6); + (*ospf6->foreach_area) (ospf6, NULL, 0, + ospf6_area_schedule_maxage_remover); + (*ospf6->foreach_if) (ospf6, NULL, 0, + ospf6_interface_schedule_maxage_remover); +} + + + +void * +ospf6_lsa_get_scope (u_int16_t type, struct ospf6_interface *o6i) +{ + if (OSPF6_LSA_IS_SCOPE_LINKLOCAL (ntohs (type))) + return o6i; + else if (OSPF6_LSA_IS_SCOPE_AREA (ntohs (type))) + return o6i->area; + else if (OSPF6_LSA_IS_SCOPE_AS (ntohs (type))) + return o6i->area->ospf6; + else + return NULL; +} + diff --git a/ospf6d/ospf6d.conf.sample b/ospf6d/ospf6d.conf.sample new file mode 100644 index 000000000..71972f59f --- /dev/null +++ b/ospf6d/ospf6d.conf.sample @@ -0,0 +1,54 @@ +! +! Zebra configuration saved from vty +! 2000/05/11 02:09:37 +! +hostname ospf6d@yasu3380 +password zebra +log file /var/log/zebra-ospf6d.log +log stdout +! +debug ospf6 message dbdesc +debug ospf6 message lsreq +debug ospf6 message lsupdate +debug ospf6 message lsack +debug ospf6 neighbor +debug ospf6 spf +debug ospf6 interface +debug ospf6 area +debug ospf6 lsa +debug ospf6 zebra +debug ospf6 config +debug ospf6 dbex +debug ospf6 route +! +interface ed0 + ipv6 ospf6 cost 1 + ipv6 ospf6 hello-interval 10 + ipv6 ospf6 dead-interval 40 + ipv6 ospf6 retransmit-interval 5 + ipv6 ospf6 priority 1 + ipv6 ospf6 transmit-delay 1 + ipv6 ospf6 instance-id 0 +! +interface lo0 + ipv6 ospf6 cost 1 + ipv6 ospf6 hello-interval 10 + ipv6 ospf6 dead-interval 40 + ipv6 ospf6 retransmit-interval 5 + ipv6 ospf6 priority 1 + ipv6 ospf6 transmit-delay 1 + ipv6 ospf6 instance-id 0 +! +router ospf6 + router-id 0.0.0.1 + redistribute static route-map static-ospf6 + interface ed0 area 0.0.0.0 + interface lo0 area 0.0.0.0 +! +ipv6 prefix-list hostroute seq 10 permit 3ffe:501:100c:4380::/60 le 128 ge 128 +! +route-map static-ospf6 permit 50 + match ipv6 address prefix-list hostroute + set metric-type type-2 + set metric 30 +! diff --git a/ospf6d/ospf6d.h b/ospf6d/ospf6d.h new file mode 100644 index 000000000..e0d310a98 --- /dev/null +++ b/ospf6d/ospf6d.h @@ -0,0 +1,175 @@ +/* + * Copyright (C) 1999 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF6D_H +#define OSPF6D_H + +#include <zebra.h> +#include "linklist.h" + +#ifndef HEADER_DEPENDENCY +/* Include other stuffs */ +#include "version.h" +#include "log.h" +#include "getopt.h" +#include "thread.h" +#include "command.h" +#include "memory.h" +#include "sockunion.h" +#include "if.h" +#include "prefix.h" +#include "stream.h" +#include "thread.h" +#include "filter.h" +#include "zclient.h" +#include "table.h" +#include "plist.h" + +/* OSPF stuffs */ +#include "ospf6_hook.h" +#include "ospf6_types.h" +#include "ospf6_prefix.h" +#include "ospf6_lsa.h" +#include "ospf6_lsdb.h" + +#include "ospf6_message.h" +#include "ospf6_proto.h" +#include "ospf6_spf.h" +#include "ospf6_top.h" +#include "ospf6_area.h" +#include "ospf6_interface.h" +#include "ospf6_neighbor.h" +#include "ospf6_ism.h" +#include "ospf6_nsm.h" +#include "ospf6_route.h" +#include "ospf6_dbex.h" +#include "ospf6_network.h" +#include "ospf6_zebra.h" +#include "ospf6_dump.h" +#include "ospf6_routemap.h" +#include "ospf6_asbr.h" +#include "ospf6_abr.h" +#include "ospf6_intra.h" +#endif /*HEADER_DEPENDENCY*/ + +#define HASHVAL 64 +#define MAXIOVLIST 1024 + +#define OSPF6_DAEMON_VERSION "0.9.6o" + +#define AF_LINKSTATE 0xff + +/* global variables */ +extern char *progname; +extern int errno; +extern int daemon_mode; +extern struct thread_master *master; +extern list iflist; +extern list nexthoplist; +extern struct sockaddr_in6 allspfrouters6; +extern struct sockaddr_in6 alldrouters6; +extern int ospf6_sock; +extern char *recent_reason; + +/* Default configuration file name for ospfd. */ +#define OSPF6_DEFAULT_CONFIG "ospf6d.conf" + +/* Default port values. */ +#define OSPF6_VTY_PORT 2606 +#define OSPF6_VTYSH_PATH "/tmp/.ospf6d" + +#ifdef INRIA_IPV6 +#ifndef IPV6_PKTINFO +#define IPV6_PKTINFO IPV6_RECVPKTINFO +#endif /* IPV6_PKTINFO */ +#endif /* INRIA_IPV6 */ + +/* Historycal for KAME. */ +#ifndef IPV6_JOIN_GROUP +#ifdef IPV6_ADD_MEMBERSHIP +#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP +#endif /* IPV6_ADD_MEMBERSHIP. */ +#ifdef IPV6_JOIN_MEMBERSHIP +#define IPV6_JOIN_GROUP IPV6_JOIN_MEMBERSHIP +#endif /* IPV6_JOIN_MEMBERSHIP. */ +#endif /* ! IPV6_JOIN_GROUP*/ + +#ifndef IPV6_LEAVE_GROUP +#ifdef IPV6_DROP_MEMBERSHIP +#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP +#endif /* IPV6_DROP_MEMBERSHIP */ +#endif /* ! IPV6_LEAVE_GROUP */ + +#define OSPF6_CMD_CHECK_RUNNING() \ + if (ospf6 == NULL) \ + { \ + vty_out (vty, "OSPFv3 is not running%s", VTY_NEWLINE); \ + return CMD_SUCCESS; \ + } + +#define OSPF6_LEVEL_NONE 0 +#define OSPF6_LEVEL_NEIGHBOR 1 +#define OSPF6_LEVEL_INTERFACE 2 +#define OSPF6_LEVEL_AREA 3 +#define OSPF6_LEVEL_TOP 4 +#define OSPF6_LEVEL_MAX 5 + +#define OSPF6_PASSIVE_STR \ + "Suppress routing updates on an interface\n" +#define OSPF6_PREFIX_LIST_STR \ + "Advertise I/F Address only match entries of prefix-list\n" + +#define OSPF6_AREA_STR "Area information\n" +#define OSPF6_AREA_ID_STR "Area ID (as an IPv4 notation)\n" +#define OSPF6_SPF_STR "Shortest Path First tree information\n" +#define OSPF6_ROUTER_ID_STR "Specify Router-ID\n" +#define OSPF6_LS_ID_STR "Specify Link State ID\n" + + +/* Function Prototypes */ +void +ospf6_timeval_sub (const struct timeval *t1, const struct timeval *t2, + struct timeval *result); +void +ospf6_timeval_div (const struct timeval *t1, u_int by, + struct timeval *result); +void +ospf6_timeval_sub_equal (const struct timeval *t, struct timeval *result); +void +ospf6_timeval_decode (const struct timeval *t, long *dayp, long *hourp, + long *minp, long *secp, long *msecp, long *usecp); +void +ospf6_timeval_string (struct timeval *tv, char *buf, int size); +void +ospf6_timeval_string_summary (struct timeval *tv, char *buf, int size); + +void +ospf6_count_state (void *arg, int val, void *obj); + +void ospf6_init (); +void ospf6_terminate (); + +void ospf6_maxage_remover (); + +void *ospf6_lsa_get_scope (u_int16_t type, struct ospf6_interface *o6i); + +#endif /* OSPF6D_H */ + |