summaryrefslogtreecommitdiff
path: root/ospf6d
diff options
context:
space:
mode:
Diffstat (limited to 'ospf6d')
-rw-r--r--ospf6d/.cvsignore8
-rw-r--r--ospf6d/ChangeLog809
-rw-r--r--ospf6d/Makefile.am48
-rw-r--r--ospf6d/Makefile.in549
-rw-r--r--ospf6d/README85
-rw-r--r--ospf6d/ospf6_abr.c655
-rw-r--r--ospf6d/ospf6_abr.h56
-rw-r--r--ospf6d/ospf6_area.c332
-rw-r--r--ospf6d/ospf6_area.h90
-rw-r--r--ospf6d/ospf6_asbr.c1040
-rw-r--r--ospf6d/ospf6_asbr.h112
-rw-r--r--ospf6d/ospf6_bintree.c436
-rw-r--r--ospf6d/ospf6_bintree.h47
-rw-r--r--ospf6d/ospf6_damp.c748
-rw-r--r--ospf6d/ospf6_damp.h109
-rw-r--r--ospf6d/ospf6_dbex.c704
-rw-r--r--ospf6d/ospf6_dbex.h59
-rw-r--r--ospf6d/ospf6_dump.c314
-rw-r--r--ospf6d/ospf6_dump.h95
-rw-r--r--ospf6d/ospf6_hook.c174
-rw-r--r--ospf6d/ospf6_hook.h87
-rw-r--r--ospf6d/ospf6_interface.c1028
-rw-r--r--ospf6d/ospf6_interface.h153
-rw-r--r--ospf6d/ospf6_intra.c896
-rw-r--r--ospf6d/ospf6_intra.h31
-rw-r--r--ospf6d/ospf6_ism.c519
-rw-r--r--ospf6d/ospf6_ism.h53
-rw-r--r--ospf6d/ospf6_linklist.c193
-rw-r--r--ospf6d/ospf6_linklist.h35
-rw-r--r--ospf6d/ospf6_lsa.c1926
-rw-r--r--ospf6d/ospf6_lsa.h426
-rw-r--r--ospf6d/ospf6_lsdb.c723
-rw-r--r--ospf6d/ospf6_lsdb.h88
-rw-r--r--ospf6d/ospf6_main.c326
-rw-r--r--ospf6d/ospf6_message.c1972
-rw-r--r--ospf6d/ospf6_message.h202
-rw-r--r--ospf6d/ospf6_neighbor.c602
-rw-r--r--ospf6d/ospf6_neighbor.h161
-rw-r--r--ospf6d/ospf6_network.c501
-rw-r--r--ospf6d/ospf6_network.h58
-rw-r--r--ospf6d/ospf6_nsm.c391
-rw-r--r--ospf6d/ospf6_nsm.h67
-rw-r--r--ospf6d/ospf6_prefix.c213
-rw-r--r--ospf6d/ospf6_prefix.h83
-rw-r--r--ospf6d/ospf6_proto.c40
-rw-r--r--ospf6d/ospf6_proto.h75
-rw-r--r--ospf6d/ospf6_route.c1130
-rw-r--r--ospf6d/ospf6_route.h209
-rw-r--r--ospf6d/ospf6_routemap.c359
-rw-r--r--ospf6d/ospf6_routemap.h27
-rw-r--r--ospf6d/ospf6_spf.c1454
-rw-r--r--ospf6d/ospf6_spf.h105
-rw-r--r--ospf6d/ospf6_top.c401
-rw-r--r--ospf6d/ospf6_top.h96
-rw-r--r--ospf6d/ospf6_types.h43
-rw-r--r--ospf6d/ospf6_zebra.c727
-rw-r--r--ospf6d/ospf6_zebra.h46
-rw-r--r--ospf6d/ospf6d.c826
-rw-r--r--ospf6d/ospf6d.conf.sample54
-rw-r--r--ospf6d/ospf6d.h175
60 files changed, 22971 insertions, 0 deletions
diff --git a/ospf6d/.cvsignore b/ospf6d/.cvsignore
new file mode 100644
index 00000000..cec4061c
--- /dev/null
+++ b/ospf6d/.cvsignore
@@ -0,0 +1,8 @@
+Makefile
+*.o
+*.patch
+ospf6d
+ospf6d.conf
+tags
+TAGS
+.deps
diff --git a/ospf6d/ChangeLog b/ospf6d/ChangeLog
new file mode 100644
index 00000000..b7871c13
--- /dev/null
+++ b/ospf6d/ChangeLog
@@ -0,0 +1,809 @@
+2002-11-09 Vincent Jardin <jardin@6wind.com>
+
+ * ospf6_interface.c: update link-local address on interface creation.
+
+2002-11-09 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_asbr.c: apply MinLSInterval to AS-External-LSA origination.
+ * ospf6_lsa.c: change not to issue flooding caused by expire event
+ when the received LSA is (already) MaxAge.
+ * ospf6_spf.c: fix a bug which is that ospf6d calculates
+ wrong nexthop when failed to find Link-LSA for the neighbor.
+ * ospf6_damp.c ospf6_dbex.c ospf6_neighbor.c ospf6_spf.c:
+ some clean up
+ * version: 0.9.6o
+
+2002-10-04 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_asbr.c: bug of failing ASE lsa refresh fixed.
+ * version: 0.9.6n
+
+2002-10-01 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_asbr.c: AS-External-LSA origination function
+ is re-written.
+ * ospf6_damp.[ch]: New feature that damps flaps is added.
+ * version: 0.9.6m
+
+2002-07-14 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_spf.c: unwanted assert() in ospf6_spf_nexthop_calculation()
+ is deleted.
+ * version: 0.9.6l
+
+2002-07-14 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_dbex.c: bug that ospf6d fails to refresh self-originated
+ LSA if he have not the LSA before has been fixed.
+ * ospf6_asbr.c: bug of failing removing ASE LSA when remove
+ message arrived from zebra has been fixed.
+ * version: 0.9.6k
+
+2002-07-13 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_zebra.c: bug reported [zebra 14642] fixed.
+ The bug was related to the synchronization between zebra
+ and ospf6d. Now synchronization will be correctly done.
+ * version: 0.9.6j
+
+2002-07-07 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_lsdb.c: bug fixed in ospf6_lsdb_type_router ().
+ * ospf6_dbex.c: because of retrans list structure changed
+ due to LSDB change, removal of old instance from retrans-list
+ is not necessary anymore. this caused crash but now fixed.
+ * version: 0.9.6i
+
+2002-07-07 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * zebra-0.93 released.
+
+2002-07-07 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_lsdb.c: entirely rewritten. now ospf6d uses
+ radix tree by using lib/table.[ch] for LSDB lookup.
+ * ospf6_abr.c, ospf6_asbr.c, ospf6_intra.c: hook changed
+ due to rewriting of lsdb module.
+ * ospf6_neighbor.c: lack of check existence and find correct
+ instance of the LSA which is going to be removed from neighbor's
+ retransmission was filled.
+ * version: 0.9.6h
+
+2002-07-07 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_intra.c: bug fix for Intra-route deletion.
+ * ospf6_route.c: bug fix for path comparison.
+ * version: 0.9.6g
+
+2002-06-28 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_route.c: some logs trying to find the situation
+ when assert occur are added. route duration statistics
+ added.
+ * ospf6_zebra.c: trying to fix the problem reported by
+ [zebra 14318] but not yet sure.
+ * version: 0.9.6f
+
+2002-06-25 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_intra.c: new file for management of intra-prefix LSA.
+ * ospf6_abr.c: inter area route calculation code added.
+ * version: 0.9.6e
+
+2002-06-22 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_asbr.c: All AS-External route was removed when
+ one of the ASBR path was gone, but the route from other ASBR
+ path should stay remained. this bug is fixed.
+ * version: 0.9.6d
+
+2002-06-22 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_route.c: route table calculation bug fixed. [zebra 14105]
+ * ospf6_spf.c, ospf6_route.c, etc.: log message cleaned up.
+ * version: 0.9.6c
+
+2002-04-27 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_route.c: [zebra 13514] bug fix.
+ thanks to Harald Koch.
+ * version: 0.9.6b
+
+2002-04-22 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_dump.c: fix bug of log function
+ * ospf6_area.c: fix bug of intra route deletion
+ * version: 0.9.6a
+
+2002-04-20 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * merged with "current" version.
+ * version: 0.9.6
+
+2001-03-11 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_lsdb.c ospf6_spf.c: log message changed for debug.
+
+2001-02-20 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * version: 0.9.5i
+
+ * ospf6_asbr.c: Added code that finds alternative
+ AS-External route when remove AS-External route.
+ This is temporary fix ...
+
+ * ospf6_redistribute.c: remove redistributed routes
+ immediately when 'no redistribute ...'
+
+2001-02-20 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * version: 0.9.5h
+
+ * ospf6_spf.c, ospf6_lsa.c: Change to originate Link-LSA on
+ point-to-point links.
+
+ * ospf6_message.c: Bug of log messages of self-originated
+ Hello packet fixed.
+
+2001-02-09 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * version: 0.9.5g
+ * ospf6_asbr.c: fix for the bug that AS-External route
+ is not get removed.
+
+2001-02-09 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_lsdb.c: crash bug while receiving wrong LSA scope bit
+ has been temporarily fixed
+
+2001-12-20 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_asbr.[ch]: The byte order bug in encoding/decoding
+ the bits/metric field in AS-External-LSA fixed.
+ Fixed to update E-bit in Router-LSA of itself.
+ Reported by Taisuke Sasaki ([zebra 11548]).
+
+ * README: updated.
+
+ * version: 0.9.5f
+
+2001-11-21 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_prefix.c: Intra-prefix-LSA bug fixed.
+ * ospf6_abr.[ch]: added (only just placeholder yet)
+
+2001-11-20 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_route.c: fix to overwrite a prefix when another
+ addition to the prefix is given. freeze function changed
+ not to remove routes by default.
+
+ * version: 0.9.5e
+
+2001-11-19 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * version: 0.9.5d
+
+ * ospf6_lsa.c ospf6_spf.c: SPF Calculations are now
+ scheduled by hook.
+
+ * ospf6_route.c: ospf6_route_add bug fix,
+ ospf6_route_remove_all corrected.
+
+2001-11-15 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_hook.[ch]: added.
+ * Almost half of the code has been rewritten.
+ especially, ospf6_route.[ch]. Hook call has been injected
+ much.
+ * ospf6_asbr.[ch]: added.
+
+2001-10-17 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_dbex.c: ospf6d was wrong to omit reoriginating
+ of LSA when the self-originated LSA was received from others.
+ fixed.
+ * ospf6d.h: version: 0.9.5c
+
+2001-10-16 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_lsa.c: 'force-prefix' was not executed. fixed.
+ * ospf6d.h: version: 0.9.5b
+
+2001-10-13 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_interface.c: 'passive-interface' is now moved to
+ 'ipv6 ospf6 passive' in INTERFACE NODE. 'prefix-list' which
+ specifies the filter prefix for connected address prefix also
+ moved to INTERFACE NODE as 'ipv6 ospf6 advertise prefix-list WORD'.
+ The old obsoleted commands are still acceptable though. New command
+ 'ipv6 ospf6 advertise force-prefix' added, which which tells ospf6d
+ to advertise rather prefix than stub local-address even on loopback
+ or pointopoint interfaces.
+
+ * ospf6_dump.c: 'ospf6 debug hello' -> 'ospf6 debug message hello'.
+ same for other message type. The older is still acceptable.
+
+ * ospf6_lsa.c: Changed AS-External generation to new one which uses
+ LSA hooks. Delete old garbage.
+
+2001-10-02 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6d.c: turn off and turn on sequence with
+ 'no interface' 'interface' cmds was not work. fixed.
+
+ * ospf6_lsa.c: generating Intra-Area-Prefix-LSA for stub
+ did not care duplicate prefixes. fixed.
+
+2001-09-07 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_message.c: There was a bug that prevent LSDB
+ to syncronize. It was a DbDesc packet bug that Slave
+ sends two different DbDesc packet on the same sequence
+ number. This cause many LSAs are dropped when Exchanging
+ LSDB, because the latter DbDesc packet that have the same
+ sequence number will be ignored as duplicate packet.
+ This seems to be exist at least before 0.9.4 version.
+ Now this is the most stable candidate.
+
+ * ospf6d.h: version 0.9.5a
+
+2001-09-06 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_zebra.c ospf6_spf.c ospf6_lsa.c :
+ delete nexthop check to certify the nexthop is Link-local address.
+ Suppress Link-LSA origination on links other than Broadcast.
+ SPF's nexthop calculation first checks linklocal address
+ in Link-LSA, then checks source address of neighbor's packets.
+
+ * ospf6_interface.c ospf6_ism.c ospf6_lsa.c ospf6_nsm.c:
+ intra-area-prefix-lsa origination func moved to new one.
+
+ * ospf6_interface.h ospf6d.[ch] ospf6_lsa.c:
+ interface_area_cmd now changed to have 'passive'
+ and 'prefix-list' option.
+
+ * ospf6_prefix.c:
+ clean up.
+
+2001-09-04 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_dbex.c ospf6_interface.c ospf6_ism.c ospf6_lsa.[ch]:
+ clean up and new LSA origination functions added.
+
+ * ospf6_route.c ospf6_lsdb.c: make vty function more
+ clean/understandable.
+
+ * ospf6d.h: version 0.9.5
+
+2001-08-24 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * ospf6_lsdb.c: Use IS_LSA_MAXAGE macro instead of
+ ospf6_lsa_is_maxage.
+
+ * ospf6_lsa.h (IS_LSA_MAXAGE): Add new macro to check MaxAge.
+
+2001-08-21 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_lsdb.c: if There's no previous prefix
+ ospf6d was wrongly not calculate the prefix.
+ this reported by (v6 16029) is fixed.
+
+ * ospf6_neighbor.c: Instance of LSA Summary included
+ in DbDesc packet was wrongly freed. The bug cause
+ malformed DbDesc, ExChange <-> ExStart flapping,
+ and then crash.
+
+ * ospf6d.h: version 0.9.4
+
+2001-08-21 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_route.[ch]: Showing format is changed.
+ 'show ipv6 route ospf6' -> 'show ipv6 ospf6 route'
+ 'show ipv6 route ospf6 external' ->
+ 'show ipv6 ospf6 route redistribute'
+
+ * ospf6_lsdb.c ospf6_lsa.c ospf6_neighbor.c ospf6_interface.c:
+ memory leak in LS list fixed.
+
+ * all: clean up
+
+ * ospf6d.h: version 0.9.3
+
+2001-08-20 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * ospf6d.c (ospf6_timeval_sub_equal): Remove function.
+
+ * ospf6_spf.c (ospf6_timeval_cmp): Rewrite ospf6_timeval_cmp().
+ (ospf6_timeval_add_equal): Function moved from ospf6d.c
+
+2001-08-19 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * zebra-0.92a released.
+
+2001-08-15 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+
+ * zebra-0.92 released.
+
+2001-08-09 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_lsdb.c ospf6_neighbor.c:
+ LSDB function/structure and LS list function has been rewritten.
+ memory leak has been decreased.
+
+ * ospf6_lsa.[ch] ospf6_dbex.c: garbage code has been deleted.
+
+ * ospf6d.h: version 0.9.2
+
+2001-08-07 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_dbex.c ospf6_lsdb.c:
+ Retransmition list had a critical bug that breaks LSDB
+ synchronization. When new LSA be added to retrans-list,
+ old must be removed, but it was not. So new LSA dropped,
+ and LSA Acknowledgement did not work. The bug was fixed.
+
+ * ospf6d.h: version 0.9.1
+
+2001-06-20 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_spf.c: crash bug fix in temporary treat code for
+ Router-LSA whose LS-ID != 0
+
+ * ospf6_dbex.c: RFC2328 13.(4) was wrongly coded.
+ (4) Else if the LSA's LS age is equal to MaxAge, and there is
+ currently *NO* instance of the LSA in the router's link state
+ ...
+
+ * ospf6_lsa.c: RFC2328 13.1 checksum tie breaker
+ had been neglected, and has just added now.
+
+ * ospf6d.h: version 0.9.0
+ ospf6d expected to work with hitachi gr2000 from these fixes.
+
+2001-06-12 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_lsa.c: Fix bug in creating Intra-Area-Prefix-LSA.
+ DR was mis-include others prefixes advertised by their Link-LSA.
+
+ * ospf6_route.c: Fix bug in calculating intra area routes.
+ Not all prefixes in Intra-Area-Prefix-LSA was calculated.
+
+ * ospf6_spf.c:
+ Changed to quit when a error occured in calculating SPF tree.
+ Very messy hack for the bug reported by [zebra 8807]. This
+ is not tested yet.
+ Changed to quit SPF calculation when a nexthop calculation
+ errors.
+
+ * ospf6_zebra.c:
+ Support for interface address deletion.
+
+ * ospf6d.h:
+ version: 0.8.y
+
+2001-04-18 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6d.h
+ Due to previous change (DR Election algorithm changed),
+ backward compatibility will be lost from this version.
+ version: 0.8.x
+
+2001-04-18 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_message.c ospf6_ism.c:
+ Bug of router_id comparison
+
+2001-04-17 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_dbex.c: ospf6_dbex_is_maxage_to_be_dropped() had
+ some bug causing Loading state lasts long.
+ version: 0.8.v
+
+2001-04-08 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_route.c: BUG in AS-External route calculation fixed.
+ It was using OLD LSDB...
+ Version: 0.8.u-
+
+2001-04-08 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_area.c, ospf6_dbex.c, ospf6_interface.c,
+ ospf6_lsa.c, ospf6_lsdb.c, ospf6_lsdb.h, ospf6_message.c,
+ ospf6_neighbor.c, ospf6_neighbor.h, ospf6_nsm.c,
+ ospf6_redistribute.c, ospf6_route.c, ospf6_spf.c:
+ Delete old LSDB function.
+
+ * ospf6d.h:
+ Version: 0.8.u
+
+2001-04-05 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_area.c, ospf6_area.h, ospf6_dbex.c, ospf6_interface.c,
+ ospf6_interface.h, ospf6_lsa.c, ospf6_lsdb.c, ospf6_lsdb.h,
+ ospf6_message.c, ospf6_nsm.c, ospf6_redistribute.c, ospf6_route.c,
+ ospf6_spf.c, ospf6_top.c, ospf6_top.h, ospf6d.h:
+ Changed to use New LSDB.
+ Version: 0.8.t
+
+2001-04-02 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_lsa.c:
+ Interface stub check in Intra-Area-Prefix-LSA origination
+ was wrong. - fixed.
+
+ * ospf6_area.h, ospf6_dbex.c, ospf6_interface.c,
+ ospf6_interface.h, ospf6_lsa.c, ospf6_lsa.h, ospf6_lsdb.c,
+ ospf6_message.c, ospf6_neighbor.c, ospf6_nsm.c,
+ ospf6_redistribute.c, ospf6_top.c, ospf6_top.h, ospf6d.c:
+ New LSDB functions, but not changed to be used.
+
+ * ospf6d.h:
+ Version: 0.8.s
+
+2001-03-28 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_area.c ospf6_area.h ospf6_dbex.c ospf6_dump.c
+ ospf6_interface.c ospf6_interface.h ospf6_lsa.c
+ ospf6_message.c ospf6_redistribute.c ospf6_spf.c ospf6_top.c
+ ospf6_top.h ospf6_zebra.c ospf6d.c ospf6d.h: cleaning.
+
+2001-03-24 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6d.h:
+ version: 0.8.r
+
+ * ospf6_neighbor.[ch], ospf6_lsa.[ch]:
+ just clean up and log clearify.
+
+ * ospf6_message.[ch]:
+ Packet receiving function and dumping OSPFv3 packet has been
+ changed simple and clean.
+
+ * ospf6_dbex.[ch], ospf6_interface.[ch], ospf6_lsdb.[ch],
+ ospf6_neighbor.[ch], ospf6_nsm.[ch]:
+ LSList(i.e. summary list, request list, retrans list, etc) have
+ been rewritten based on new LSDB module. The main LSDB have not
+ yet shifted to this new module, but will shift eventually.
+ This change expected to resolve the problem that the ospf6d keeps
+ on sending redundant LSUpdate/LSAck.
+
+ * ospf6_interface.c: changed default MTU from 1500 to 1280.
+ It was possible that the ospf6d could not send packet (e.g.
+ LSUpdate in response to LSReq in my case) when the packet
+ size accidentally reached near 1500 (I was forget about IP
+ header :p). It is a bit illegal to set MTU 1280 constantly,
+ but I failed once with I/F MTU from kernel (through zebra),
+ and thinks that 1280 is more stable than kernel variable.
+ Comments will be appriciated.
+
+2001-03-15 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_dbex.c, ospf6_interface.c, ospf6_ism.c, ospf6_lsdb.[ch],
+ ospf6_neighbor.c, ospf6_spf.c, ospf6d.c:
+ Fix for crash. ospf6d has ever been crashing when
+ 'no interface' command executed, and when starting up with
+ the configuration which does not include 'router ospf6'.
+ these has been fixed.
+
+2001-02-24 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_lsa.c, ospf6_message.c:
+ LSA summary (exchanged while Adjacency bring up) may expire
+ (may reach MaxAge). Handling this has been added but
+ it's a little bit quick hack.
+
+ * ospf6_message.c:
+ Thread chain bug fixed. Read network thread chain has been cut
+ when receive packets on not-enabled interface. this was wrong
+ and fixed.
+
+2001-02-24 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_message.c:
+ I/F MTU check part on sending packet had some bug, and it's fixed.
+ Ospf6d has believed a value from zebra as I/F MTU, but from now
+ I/F MTU is set to constant 1500. This is workaround for ATM.
+
+2001-02-01 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra-0.91 is released.
+
+2001-01-04 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * just code clean up of almost all module.
+ * ospf6_dump.c, ospf6_lsa.c: file dependency.
+ * ospf6_mesg.[ch]: changed filename to ospf6_message.[ch]
+
+2001-01-09 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra-0.90 is released.
+
+2001-01-04 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_mesg.c,ospf6_lsa.c: doubly cancel thread bug fixed.
+ version 0.8.k CRASHed for this.
+ * ospf6_lsa.c: bug of logging fixed.
+ version: 0.8.l
+
+2001-01-04 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_neighbor.c: fix typo when trying to delete
+ MaxAge AS-External LSA. MaxAge LSA remaining bug is expected
+ to be fixed.
+ version: 0.8.k
+
+2001-01-04 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_mesg.c: add I/F Mtu check for sending LS Update.
+
+ * ospf6_dbex.c, ospf6_mesg.c, ospf6_neighbor.c, ospf6_neighbor.h,
+ ospf6_spf.c: Changed type of hisaddr field in ospf6_neighbor
+ structure, from sockaddr_in6 to in6_addr. No protocol/processing
+ changed.
+
+2001-01-04 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_mesg.c, ospf6_neighbor.[ch]: Speed up of
+ Database Exchange.
+ version: 0.8.j
+
+ Because the LS Request list was checked only when attempt
+ to send (retransmit) LS Request packet, Loading state lasted
+ long (for RxmtInterval) unexpectedly. This was fixed; LS Request
+ packet will be send as soon as one received a LS Update packet.
+
+2001-01-01 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf6d.h (OSPF6_VTYSH_PATH): Change "/tmp/ospf6d" to
+ /tmp/.ospf6d".
+
+2000-12-29 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_dump.[ch]: simplified.
+
+2000-12-19 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_route.c: Fix bug of using unavailable route.
+ version: 0.8.d
+
+2000-11-30 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_spf.c: calculate statistics. version: 0.8.d
+
+2000-11-26 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_mesg.c, ospf6_nsm.c: LSDB sync bug fixed.
+ version: 0.8.c
+
+2000-11-26 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_dbex.c: Start debugging and cleaning.
+
+ * ospf6_area.c, ospf6_dbex.c, ospf6_interface.c, ospf6_lsa.c,
+ ospf6_proto.c, ospf6_top.c: add some function to clarify codes.
+
+2000-11-26 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_spf.c: Delete old garbage (which was enclosed by #if 0)
+
+ * ospf6_redistribute.c: "redistribute ospf6" was generated in
+ "router ospf6" in config file. It is a bug, and fixed.
+ wrong warning message was deleted.
+
+ * ospf6_main.c: If daemon mode, ospf6d was silent even if
+ the config file was wrong. It is a bug, and fixed.
+
+ * ospf6_route.c, ospf6_zebra.c: Zebra syncronization method
+ has been changed. delete garbages. allow nexthop of :: in case
+ of connected route.
+
+ * ospf6_dbex.c: Delete annoying log messages.
+
+ * ospf6_lsa.c: Changed string for LSA log.
+
+2000-11-21 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_spf.c: some careless bug fixed.
+
+ * ospf6_route.c: changed not to send garbage route
+ whose nexthop is not linklocal address.
+
+2000-11-09 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_rtable.c: renamed to ospf6_route.c
+ whole functionality has been rewritten as new code.
+ new functions not yet installs routes; the old
+ functions still remains. cleaning log messages.
+
+ * ospf6_spf.c: whole functionality has been rewritten
+ as new code. new command "show ipv6 ospf6 spf node",
+ "show ipv6 ospf6 spf tree", "show ipv6 ospf6 spf table"
+ has been added. Memory leak was fixed. cleaning log messages.
+
+ * ospf6d version: 0.7.c
+
+2000-10-02 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra-0.89 is released.
+
+2000-09-10 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf6_lsdb.c (ospf6_lsdb_remove_maxage_lsa): Fix compile
+ warnings.
+
+2000-08-17 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * zebra-0.88 is released.
+
+2000-08-06 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf6_rtable.h (struct ospf6_nexthop): Change ifindex type from
+ unsigned long to unsigned int.
+
+2000-04-28 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf6d.h: Include some headers for avoid warning.
+
+ * ospf6_routemap.h: Add newfile.
+
+1999-11-21 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf6_network.c: Respect IPV6_JOIN_GROUP and IPV6_LEAVE_GROUP
+ rather than RFC2133.
+
+1999-10-21 Jun-ichiro itojun Hagino <itojun@itojun.org>
+
+ * ospf6_network.c (ospf6_ipv6_decode_ipv4): Fix bug of conversion
+ from IPv4 Mapped Address to IPv4 address.
+
+1999-08-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf6_lsa.c (construct_link_lsa): Enclose KAME specific part by
+ #ifdef/#endif.
+
+1999-07-29 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_mesg.c: add new message process function.
+
+1999-07-25 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf6_main.c (sighup): Call of log_rotate() removed.
+
+1999-07-24 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ ospf6_dbex.{c,h}: variable "acknowledge" has been deleted.
+
+1999-07-22 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * *.{c,h}: lsa data structure has been drastically
+ changed.
+
+1999-07-16 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * *.{c,h}: bug of updating LSA's which is self
+ originated has been fixed.
+
+1999-07-14 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * *.{c,h} : log clean up.
+
+1999-07-05 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf6d.c (ospf6_init): Change to use install_default.
+
+1999-07-03 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_rtable.c (nexthop_*): added some function that handles
+ new nexthop structure.
+
+1999-07-01 Rick Payne <rickp@rossfell.co.uk>
+
+ * ospf6_zebra.c (ospf6_zebra_init): Install standard commands to
+ ZEBRA_NODE.
+
+1999-06-09 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_rtable.h: added for new routing table of ospf6d
+
+1999-05-14 Stephen R. van den Berg <srb@cuci.nl>
+
+ * ospf6_main.c (signal_init): SIGTERM call sigint.
+ (sigint): Loggging more better message.
+
+1999-05-13 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ *ospf6_spf.c (get_prefix_lsa_of_vertex): bug fix about network vertex.
+
+1999-05-08 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf6_network.c (send_linkstate_ack): Check HAVE_SIN6_SCOPE_ID
+ is defined.
+ * ospf6_mesg.c (make_hello): Likewise.
+ * ospf6_lsa.c (lsa_flood): Likewise.
+
+1999-05-07 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_spf.c, etc: Many bug fix.
+ intra-area-prefix-LSA treatment changed.
+ network byte order of neighbor ifid changed.
+
+1999-05-07 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf6_zebra.h (struct zebra): Add hitory entry to structure.
+
+1999-05-05 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf6_main.c (main): Add KAME check for binding vty socket.
+ (main): Delete old interface get routine garbage.
+
+ * ospf6d.c: Change all `show ip6' statement to `show ipv6'.
+ (show_ipv6_ospf6_requestlist): Add description.
+
+1999-05-04 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * ospf6_lsa.c, etc: Many bug fix, now two routers
+ on the same segment can become FULL neighbor state
+ each other.
+
+1999-05-03 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Makefile.am: Add file dependency.
+ (depend): Add target.
+
+1999-05-02 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+ * Clean up and fix have been almost done. This code
+ now testing stage of Intra area routing.
+
+ * Configuration Vty become more similar to Cisco.
+
+1999-04-22 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Trim training newline from zlog format arguemnt.
+
+ * ospf6_dump.c (ospf6_err): Commented out ospf6_err and
+ ospf6_warn. Same kind of function should be implemented as
+ zlog_err or zlog_warn or someting.
+
+ * ospf6d.c: Change OSPF_NODE to OSPF6_NODE.
+ Change OSPF_DEFAULT_CONFIG to OSPF6_DEFAULT_CONFIG.
+
+
+1999-04-21 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf6_mesg.c (make_hello): Add check of SIN6_LEN
+
+1999-04-16 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * ospf6_neighbor.c: Change list_clear_all to list_delete_all_node.
+ Remove list_delete_all fuction and use lib/linklist.c's one.
+
+1999-04-14 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * mcast_join(),mcast_leave()'s argument socket length is removed.
+
+1999-04-08 <kunihiro@zebra.org>
+
+ * ospf6_zebra.h (ospf_zebra_read): Fix typo.
+
+ * ospf6_interface.h: Tempolary add struct rt_addrinfo.
+
+1999-03-05 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Merge from ospfd-zebra-990303 codes.
+
+1999-02-23 Kunihiro Ishiguro <kunihiro@zebra.org>
+
+ * Makefile.in: add new file.
+
+ * Makefile.am: @INCLUDES@ is added for OS/library specific IPv6
+ directory search.
+
+ * Import files from Yasuhiro Ohara <yasu@sfc.wide.ad.jp>'s ospfd.
+ Impterted files are:
+ Makefile.am, ospf_area.h, ospf_dump.c, ospf_interface.c,
+ ospf_interface.h, ospf_lsa.c, ospf_lsa.h, ospf_main.c,
+ ospf_mesg.c, ospf_mesg.h, ospf_neighbor.c,
+ ospf_neighbor.h,ospf_network.c, ospf_network.h, ospf_proto.h,
+ ospf_spf.c, ospf_spf.h, ospf_types.h, ospfd.c, ospfd.h
diff --git a/ospf6d/Makefile.am b/ospf6d/Makefile.am
new file mode 100644
index 00000000..e1b78cbc
--- /dev/null
+++ b/ospf6d/Makefile.am
@@ -0,0 +1,48 @@
+## Process this file with automake to produce Makefile.in.
+
+INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib
+DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
+INSTALL_SDATA=@INSTALL@ -m 600
+
+noinst_LIBRARIES = libospf6.a
+sbin_PROGRAMS = ospf6d
+
+libospf6_a_SOURCES = \
+ ospf6_dump.c ospf6d.c ospf6_interface.c ospf6_network.c \
+ ospf6_neighbor.c ospf6_message.c ospf6_lsa.c ospf6_spf.c \
+ ospf6_route.c ospf6_zebra.c ospf6_ism.c ospf6_dbex.c \
+ ospf6_lsdb.c ospf6_prefix.c ospf6_top.c ospf6_area.c ospf6_nsm.c \
+ ospf6_routemap.c ospf6_proto.c \
+ ospf6_hook.c ospf6_asbr.c ospf6_bintree.c ospf6_linklist.c \
+ ospf6_abr.c ospf6_intra.c ospf6_damp.c
+
+noinst_HEADERS = \
+ ospf6_area.h ospf6_dump.h ospf6_interface.h ospf6_lsa.h \
+ ospf6_message.h ospf6_neighbor.h ospf6_network.h ospf6_proto.h \
+ ospf6_spf.h ospf6_route.h ospf6_types.h ospf6_zebra.h ospf6d.h \
+ ospf6_ism.h ospf6_dbex.h ospf6_lsdb.h ospf6_prefix.h \
+ ospf6_top.h ospf6_nsm.h ospf6_routemap.h \
+ ospf6_hook.h ospf6_asbr.h ospf6_bintree.h ospf6_linklist.h \
+ ospf6_abr.h ospf6_intra.h ospf6_damp.h
+
+ospf6d_SOURCES = \
+ ospf6_main.c $(libospf6_a_SOURCES)
+
+ospf6d_LDADD = ../lib/libzebra.a
+
+sysconf_DATA = ospf6d.conf.sample
+
+EXTRA_DIST = $(sysconf_DATA)
+
+install-sysconfDATA: $(sysconf_DATA)
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(sysconfdir)
+ @list='$(sysconf_DATA)'; for p in $$list; do \
+ if test -f $(srcdir)/$$p; then \
+ echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \
+ $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \
+ else if test -f $$p; then \
+ echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \
+ $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \
+ fi; fi; \
+ done
diff --git a/ospf6d/Makefile.in b/ospf6d/Makefile.in
new file mode 100644
index 00000000..fed57d95
--- /dev/null
+++ b/ospf6d/Makefile.in
@@ -0,0 +1,549 @@
+# Makefile.in generated by automake 1.7 from Makefile.am.
+# @configure_input@
+
+# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
+# Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_triplet = @host@
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BGPD = @BGPD@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CURSES = @CURSES@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+IF_METHOD = @IF_METHOD@
+IF_PROC = @IF_PROC@
+
+INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPFORWARD = @IPFORWARD@
+KERNEL_METHOD = @KERNEL_METHOD@
+LDFLAGS = @LDFLAGS@
+LIBPAM = @LIBPAM@
+LIBS = @LIBS@
+LIB_IPV6 = @LIB_IPV6@
+LIB_REGEX = @LIB_REGEX@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MULTIPATH_NUM = @MULTIPATH_NUM@
+OBJEXT = @OBJEXT@
+OSPF6D = @OSPF6D@
+OSPFD = @OSPFD@
+OTHER_METHOD = @OTHER_METHOD@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+RIPD = @RIPD@
+RIPNGD = @RIPNGD@
+RTREAD_METHOD = @RTREAD_METHOD@
+RT_METHOD = @RT_METHOD@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+VTYSH = @VTYSH@
+ZEBRA = @ZEBRA@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__include = @am__include@
+am__quote = @am__quote@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+INSTALL_SDATA = @INSTALL@ -m 600
+
+noinst_LIBRARIES = libospf6.a
+sbin_PROGRAMS = ospf6d
+
+libospf6_a_SOURCES = \
+ ospf6_dump.c ospf6d.c ospf6_interface.c ospf6_network.c \
+ ospf6_neighbor.c ospf6_message.c ospf6_lsa.c ospf6_spf.c \
+ ospf6_route.c ospf6_zebra.c ospf6_ism.c ospf6_dbex.c \
+ ospf6_lsdb.c ospf6_prefix.c ospf6_top.c ospf6_area.c ospf6_nsm.c \
+ ospf6_routemap.c ospf6_proto.c \
+ ospf6_hook.c ospf6_asbr.c ospf6_bintree.c ospf6_linklist.c \
+ ospf6_abr.c ospf6_intra.c ospf6_damp.c
+
+
+noinst_HEADERS = \
+ ospf6_area.h ospf6_dump.h ospf6_interface.h ospf6_lsa.h \
+ ospf6_message.h ospf6_neighbor.h ospf6_network.h ospf6_proto.h \
+ ospf6_spf.h ospf6_route.h ospf6_types.h ospf6_zebra.h ospf6d.h \
+ ospf6_ism.h ospf6_dbex.h ospf6_lsdb.h ospf6_prefix.h \
+ ospf6_top.h ospf6_nsm.h ospf6_routemap.h \
+ ospf6_hook.h ospf6_asbr.h ospf6_bintree.h ospf6_linklist.h \
+ ospf6_abr.h ospf6_intra.h ospf6_damp.h
+
+
+ospf6d_SOURCES = \
+ ospf6_main.c $(libospf6_a_SOURCES)
+
+
+ospf6d_LDADD = ../lib/libzebra.a
+
+sysconf_DATA = ospf6d.conf.sample
+
+EXTRA_DIST = $(sysconf_DATA)
+subdir = ospf6d
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+
+libospf6_a_AR = $(AR) cru
+libospf6_a_LIBADD =
+am_libospf6_a_OBJECTS = ospf6_dump.$(OBJEXT) ospf6d.$(OBJEXT) \
+ ospf6_interface.$(OBJEXT) ospf6_network.$(OBJEXT) \
+ ospf6_neighbor.$(OBJEXT) ospf6_message.$(OBJEXT) \
+ ospf6_lsa.$(OBJEXT) ospf6_spf.$(OBJEXT) ospf6_route.$(OBJEXT) \
+ ospf6_zebra.$(OBJEXT) ospf6_ism.$(OBJEXT) ospf6_dbex.$(OBJEXT) \
+ ospf6_lsdb.$(OBJEXT) ospf6_prefix.$(OBJEXT) ospf6_top.$(OBJEXT) \
+ ospf6_area.$(OBJEXT) ospf6_nsm.$(OBJEXT) \
+ ospf6_routemap.$(OBJEXT) ospf6_proto.$(OBJEXT) \
+ ospf6_hook.$(OBJEXT) ospf6_asbr.$(OBJEXT) \
+ ospf6_bintree.$(OBJEXT) ospf6_linklist.$(OBJEXT) \
+ ospf6_abr.$(OBJEXT) ospf6_intra.$(OBJEXT) ospf6_damp.$(OBJEXT)
+libospf6_a_OBJECTS = $(am_libospf6_a_OBJECTS)
+sbin_PROGRAMS = ospf6d$(EXEEXT)
+PROGRAMS = $(sbin_PROGRAMS)
+
+am__objects_1 = ospf6_dump.$(OBJEXT) ospf6d.$(OBJEXT) \
+ ospf6_interface.$(OBJEXT) ospf6_network.$(OBJEXT) \
+ ospf6_neighbor.$(OBJEXT) ospf6_message.$(OBJEXT) \
+ ospf6_lsa.$(OBJEXT) ospf6_spf.$(OBJEXT) ospf6_route.$(OBJEXT) \
+ ospf6_zebra.$(OBJEXT) ospf6_ism.$(OBJEXT) ospf6_dbex.$(OBJEXT) \
+ ospf6_lsdb.$(OBJEXT) ospf6_prefix.$(OBJEXT) ospf6_top.$(OBJEXT) \
+ ospf6_area.$(OBJEXT) ospf6_nsm.$(OBJEXT) \
+ ospf6_routemap.$(OBJEXT) ospf6_proto.$(OBJEXT) \
+ ospf6_hook.$(OBJEXT) ospf6_asbr.$(OBJEXT) \
+ ospf6_bintree.$(OBJEXT) ospf6_linklist.$(OBJEXT) \
+ ospf6_abr.$(OBJEXT) ospf6_intra.$(OBJEXT) ospf6_damp.$(OBJEXT)
+am_ospf6d_OBJECTS = ospf6_main.$(OBJEXT) $(am__objects_1)
+ospf6d_OBJECTS = $(am_ospf6d_OBJECTS)
+ospf6d_DEPENDENCIES = ../lib/libzebra.a
+ospf6d_LDFLAGS =
+
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/ospf6_abr.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_area.Po ./$(DEPDIR)/ospf6_asbr.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_bintree.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_damp.Po ./$(DEPDIR)/ospf6_dbex.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_dump.Po ./$(DEPDIR)/ospf6_hook.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_interface.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_intra.Po ./$(DEPDIR)/ospf6_ism.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_linklist.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_lsa.Po ./$(DEPDIR)/ospf6_lsdb.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_main.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_message.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_neighbor.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_network.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_nsm.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_prefix.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_proto.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_route.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_routemap.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_spf.Po ./$(DEPDIR)/ospf6_top.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_zebra.Po ./$(DEPDIR)/ospf6d.Po
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+DIST_SOURCES = $(libospf6_a_SOURCES) $(ospf6d_SOURCES)
+DATA = $(sysconf_DATA)
+
+HEADERS = $(noinst_HEADERS)
+
+DIST_COMMON = README $(noinst_HEADERS) ChangeLog Makefile.am \
+ Makefile.in
+SOURCES = $(libospf6_a_SOURCES) $(ospf6d_SOURCES)
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .o .obj
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --foreign ospf6d/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)
+
+clean-noinstLIBRARIES:
+ -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+libospf6.a: $(libospf6_a_OBJECTS) $(libospf6_a_DEPENDENCIES)
+ -rm -f libospf6.a
+ $(libospf6_a_AR) libospf6.a $(libospf6_a_OBJECTS) $(libospf6_a_LIBADD)
+ $(RANLIB) libospf6.a
+sbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+install-sbinPROGRAMS: $(sbin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(sbindir)
+ @list='$(sbin_PROGRAMS)'; for p in $$list; do \
+ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ if test -f $$p \
+ ; then \
+ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f"; \
+ $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f || exit 1; \
+ else :; fi; \
+ done
+
+uninstall-sbinPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(sbin_PROGRAMS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " rm -f $(DESTDIR)$(sbindir)/$$f"; \
+ rm -f $(DESTDIR)$(sbindir)/$$f; \
+ done
+
+clean-sbinPROGRAMS:
+ -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS)
+ospf6d$(EXEEXT): $(ospf6d_OBJECTS) $(ospf6d_DEPENDENCIES)
+ @rm -f ospf6d$(EXEEXT)
+ $(LINK) $(ospf6d_LDFLAGS) $(ospf6d_OBJECTS) $(ospf6d_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT) core *.core
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_abr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_area.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_asbr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_bintree.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_damp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_dbex.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_dump.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_hook.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_interface.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_intra.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_ism.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_linklist.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_lsa.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_lsdb.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_message.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_neighbor.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_network.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_nsm.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_prefix.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_proto.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_route.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_routemap.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_spf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_top.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_zebra.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6d.Po@am__quote@
+
+distclean-depend:
+ -rm -rf ./$(DEPDIR)
+
+.c.o:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \
+@am__fastdepCC_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \
+@am__fastdepCC_TRUE@ then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \
+@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \
+@am__fastdepCC_TRUE@ fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$<
+
+.c.obj:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \
+@am__fastdepCC_TRUE@ -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'`; \
+@am__fastdepCC_TRUE@ then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \
+@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \
+@am__fastdepCC_TRUE@ fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'`
+uninstall-info-am:
+sysconfDATA_INSTALL = $(INSTALL_DATA)
+
+uninstall-sysconfDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(sysconf_DATA)'; for p in $$list; do \
+ f="`echo $$p | sed -e 's|^.*/||'`"; \
+ echo " rm -f $(DESTDIR)$(sysconfdir)/$$f"; \
+ rm -f $(DESTDIR)$(sysconfdir)/$$f; \
+ done
+
+ETAGS = etags
+ETAGSFLAGS =
+
+CTAGS = ctags
+CTAGSFLAGS =
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$tags$$unique" \
+ || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique
+
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+
+top_distdir = ..
+distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkinstalldirs) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LIBRARIES) $(PROGRAMS) $(DATA) $(HEADERS)
+
+installdirs:
+ $(mkinstalldirs) $(DESTDIR)$(sbindir) $(DESTDIR)$(sysconfdir)
+
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-noinstLIBRARIES clean-sbinPROGRAMS \
+ mostlyclean-am
+
+distclean: distclean-am
+
+distclean-am: clean-am distclean-compile distclean-depend \
+ distclean-generic distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am: install-sbinPROGRAMS install-sysconfDATA
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-sbinPROGRAMS \
+ uninstall-sysconfDATA
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-noinstLIBRARIES clean-sbinPROGRAMS ctags distclean \
+ distclean-compile distclean-depend distclean-generic \
+ distclean-tags distdir dvi dvi-am info info-am install \
+ install-am install-data install-data-am install-exec \
+ install-exec-am install-info install-info-am install-man \
+ install-sbinPROGRAMS install-strip install-sysconfDATA \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \
+ uninstall-am uninstall-info-am uninstall-sbinPROGRAMS \
+ uninstall-sysconfDATA
+
+
+install-sysconfDATA: $(sysconf_DATA)
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(sysconfdir)
+ @list='$(sysconf_DATA)'; for p in $$list; do \
+ if test -f $(srcdir)/$$p; then \
+ echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \
+ $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \
+ else if test -f $$p; then \
+ echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \
+ $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \
+ fi; fi; \
+ done
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/ospf6d/README b/ospf6d/README
new file mode 100644
index 00000000..b3b4d16d
--- /dev/null
+++ b/ospf6d/README
@@ -0,0 +1,85 @@
+
+ Zebra OSPF daemon for IPv6 network
+
+ 2001/12/20
+
+Zebra OSPF6d is OSPF version 3 daemon which is specified by
+"OSPF for IPv6" (RFC 2740).
+
+*** NOTE ***
+ Zebra ospf6d is in development yet. It may lack some functionalities,
+ and may have some bugs. Use the latest version from the anoncvs
+ repository (http://www.zebra.org/cvs.html) !
+
+This file README is like memo yet, so please feel free to ask
+<yasu@sfc.wide.ad.jp> by E-mail. Patches will be appriciated.
+
+ospf6d's vty port was default to 2606/tcp.
+Use commands below.
+
+VIEW NODE:
+ show ipv6 ospf6
+ To see Router-ID, uptime of ospf6d, some statistics.
+
+ show ipv6 ospf6 database ...
+ This command shows LSA database. You can specify
+ LS-type/LS-ID/Advertising-Router of LSAs. '*' is recognized.
+
+ show ipv6 ospf6 interface ...
+ To see the status of the OSPF interface, and the configuration
+ like interface costs.
+
+ show ipv6 ospf6 neighbor ...
+ Shows state of neighbors and choosed (Backup) DR on the I/F.
+
+ show ipv6 ospf6 route (X::X)
+ This command shows internal routing table of the ospf6d.
+ Routes not calculated by OSPFv3 (like connected routes)
+ are not shown. If Address is specified (X::X), shows the route
+ that the address matches.
+
+ show ipv6 ospf6 route redistribute (X::X)
+ Shows the routes advertised as AS-External routes by the router
+ itself. If Address is specified (X::X), shows the route
+ that the address matches.
+
+CONFIG NODE:
+ interface NAME
+ To enter INTERFACE NODE
+
+ router ospf6 ...
+ To enter OSPF6 NODE
+
+INTERFACE NODE:
+ ipv6 ospf6 cost COST
+ Sets the interface's output cost. default 1
+
+ ipv6 ospf6 hello-interval HELLOINTERVAL
+ Sets the interface's Hello Interval. default 10
+
+ ipv6 ospf6 dead-interval DEADINTERVAL
+ Sets the interface's Router Dead Interval. default 40
+
+ ipv6 ospf6 retransmit-interval RETRANSMITINTERVAL
+ Sets the interface's Rxmt Interval. default 5
+
+ ipv6 ospf6 priority PRIORITY
+ Sets the interface's Router Priority. default 1
+
+ ipv6 ospf6 transmit-delay TRANSMITDELAY
+ Sets the interface's Inf-Trans-Delay. default 1
+
+OSPF6 NODE:
+ router-id A.B.C.D
+ Sets the router's Router-ID
+
+ interface NAME area AREA
+ Binds interface to specified Area, and start
+ sending OSPFv3 packets.
+
+Sample configuration is in ospf6d.conf.sample.
+
+--
+Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+Kunihiro Ishiguro <kunihiro@zebra.org>
+
diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c
new file mode 100644
index 00000000..864e0c23
--- /dev/null
+++ b/ospf6d/ospf6_abr.c
@@ -0,0 +1,655 @@
+/*
+ * Copyright (C) 2001 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "ospf6d.h"
+
+#include "ospf6_dump.h"
+#include "ospf6_abr.h"
+
+static int abr_index;
+#define IS_OSPF6_DUMP_ABR (ospf6_dump_is_on (abr_index))
+
+#define ADD 0
+#define CHANGE 1
+#define REMOVE 2
+
+/* Inter-Area-Prefix-LSA Calculation */
+
+static struct ospf6_route_req *
+ospf6_abr_entry_lookup (struct ospf6_route_req *abr_entry,
+ u_int32_t router_id, struct ospf6_area *area)
+{
+ struct prefix_ls abr_id;
+ char router_string[32];
+
+ inet_ntop (AF_INET, &router_id, router_string, sizeof (router_string));
+
+ //zlog_info ("ABR: Finding router %s in area %s", router_string, area->str);
+
+ memset (&abr_id, 0, sizeof (abr_id));
+ abr_id.family = AF_UNSPEC;
+ abr_id.prefixlen = 64; /* xxx */
+ abr_id.id.s_addr = htonl (0);
+ abr_id.adv_router.s_addr = router_id;
+
+ ospf6_route_lookup (abr_entry, (struct prefix *) &abr_id,
+ area->table_topology);
+
+ if (ospf6_route_end (abr_entry))
+ {
+ if (IS_OSPF6_DUMP_ABR)
+ zlog_info ("ABR: Router %s not found in area %s",
+ router_string, area->str);
+ return NULL;
+ }
+
+ if (abr_entry->path.area_id != area->area_id)
+ {
+ if (IS_OSPF6_DUMP_ABR)
+ zlog_info ("ABR: ABR area id mismatch");
+ return NULL;
+ }
+
+ if (! CHECK_FLAG (abr_entry->path.router_bits, OSPF6_ROUTER_LSA_BIT_B))
+ {
+ if (IS_OSPF6_DUMP_ABR)
+ zlog_info ("ABR: ABR entry's B bit off");
+ return NULL;
+ }
+
+ return abr_entry;
+}
+
+static int
+ospf6_abr_prefix_lsa_to_route (struct ospf6_lsa *lsa,
+ struct ospf6_route_req *request)
+{
+ struct ospf6_inter_area_prefix_lsa *iep;
+ struct ospf6_route_req abr_entry;
+
+ if (lsa->header->type != htons (OSPF6_LSA_TYPE_INTER_PREFIX))
+ {
+ if (IS_OSPF6_DUMP_ABR)
+ zlog_info ("ABR: LSA type mismatch");
+ return -1;
+ }
+
+ if (IS_LSA_MAXAGE (lsa))
+ {
+ if (IS_OSPF6_DUMP_ABR)
+ zlog_info ("ABR: LSA MaxAge");
+ return -1;
+ }
+
+ if (! ospf6_abr_entry_lookup (&abr_entry, lsa->header->adv_router,
+ (struct ospf6_area *) lsa->scope))
+ {
+ if (IS_OSPF6_DUMP_ABR)
+ zlog_info ("ABR: ABR check failed");
+ return -1;
+ }
+
+ iep = OSPF6_LSA_HEADER_END (lsa->header);
+
+ memset (request, 0, sizeof (struct ospf6_route_req));
+ request->route.type = OSPF6_DEST_TYPE_NETWORK;
+ request->route.prefix.family = AF_INET6;
+ request->route.prefix.prefixlen = iep->prefix.prefix_length;
+ ospf6_prefix_in6_addr (&iep->prefix, &request->route.prefix.u.prefix6);
+
+ request->path.cost = abr_entry.path.cost +
+ (ntohl (iep->metric) & ntohl (0x000fffff));
+ request->path.type = OSPF6_PATH_TYPE_INTER;
+ request->path.origin.type = lsa->header->type;
+ request->path.origin.id = lsa->header->id;
+ request->path.origin.adv_router = lsa->header->adv_router;
+ memcpy (&request->nexthop.address, &abr_entry.nexthop.address,
+ sizeof (request->nexthop.address));
+ request->nexthop.ifindex = abr_entry.nexthop.ifindex;
+
+ return 0;
+}
+
+void
+ospf6_abr_prefix_lsa_add (struct ospf6_lsa *lsa)
+{
+ struct ospf6_route_req request;
+ int ret;
+
+ if (IS_OSPF6_DUMP_ABR)
+ zlog_info ("ABR: Calculate %s", lsa->str);
+
+ ret = ospf6_abr_prefix_lsa_to_route (lsa, &request);
+ if (ret < 0)
+ return;
+
+ if (IS_OSPF6_DUMP_ABR)
+ zlog_info ("ABR: Inter Area Route add for %s", lsa->str);
+
+ ospf6_route_add (&request, ospf6->route_table);
+}
+
+void
+ospf6_abr_prefix_lsa_remove (struct ospf6_lsa *lsa)
+{
+ struct ospf6_inter_area_prefix_lsa *iep;
+ struct prefix_ipv6 prefix6;
+ struct ospf6_route_req request;
+
+ iep = OSPF6_LSA_HEADER_END (lsa->header);
+
+ prefix6.family = AF_INET6;
+ prefix6.prefixlen = iep->prefix.prefix_length;
+ ospf6_prefix_in6_addr (&iep->prefix, &prefix6.prefix);
+
+ if (IS_OSPF6_DUMP_ABR)
+ zlog_info ("ABR: Inter Area Route remove for %s", lsa->str);
+
+ for (ospf6_route_lookup (&request, (struct prefix *) &prefix6,
+ ospf6->route_table);
+ ! ospf6_route_end (&request);
+ ospf6_route_next (&request))
+ {
+ if (memcmp (&prefix6, &request.route.prefix, sizeof (prefix6)))
+ break;
+ if (request.path.origin.type != htons (OSPF6_LSA_TYPE_INTER_PREFIX) ||
+ request.path.origin.adv_router != lsa->header->adv_router ||
+ request.path.origin.id != lsa->header->id)
+ continue;
+
+ ospf6_route_remove (&request, ospf6->route_table);
+ }
+}
+
+static int
+ospf6_abr_router_lsa_to_route (struct ospf6_lsa *lsa,
+ struct ospf6_route_req *request)
+{
+ struct ospf6_inter_area_router_lsa *ier;
+ struct ospf6_route_req abr_entry;
+
+ if (lsa->header->type != htons (OSPF6_LSA_TYPE_INTER_ROUTER))
+ {
+ if (IS_OSPF6_DUMP_ABR)
+ zlog_info ("ABR: LSA type mismatch");
+ return -1;
+ }
+
+ if (IS_LSA_MAXAGE (lsa))
+ {
+ if (IS_OSPF6_DUMP_ABR)
+ zlog_info ("ABR: LSA MaxAge");
+ return -1;
+ }
+
+ if (! ospf6_abr_entry_lookup (&abr_entry, lsa->header->adv_router,
+ (struct ospf6_area *) lsa->scope))
+ {
+ if (IS_OSPF6_DUMP_ABR)
+ zlog_info ("ABR: Advertising router check failed");
+ return -1;
+ }
+
+ ier = OSPF6_LSA_HEADER_END (lsa->header);
+
+ memset (request, 0, sizeof (struct ospf6_route_req));
+ request->route.type = OSPF6_DEST_TYPE_ROUTER;
+ request->route.prefix.family = AF_UNSPEC;
+ request->route.prefix.prefixlen = 64; /* XXX */
+ ((struct prefix_ls *) &request->route.prefix)->adv_router.s_addr
+ = ier->router_id;
+
+ request->path.cost = abr_entry.path.cost +
+ (ntohl (ier->metric & htonl (0x000fffff)));
+ request->path.type = OSPF6_PATH_TYPE_INTER;
+ request->path.origin.type = lsa->header->type;
+ request->path.origin.id = lsa->header->id;
+ request->path.origin.adv_router = lsa->header->adv_router;
+ SET_FLAG (request->path.router_bits, OSPF6_ROUTER_LSA_BIT_E);
+ request->path.capability[0] = ier->options[0];
+ request->path.capability[1] = ier->options[1];
+ request->path.capability[2] = ier->options[2];
+
+ memcpy (&request->nexthop.address, &abr_entry.nexthop.address,
+ sizeof (request->nexthop.address));
+ request->nexthop.ifindex = abr_entry.nexthop.ifindex;
+
+ return 0;
+}
+
+void
+ospf6_abr_router_lsa_add (struct ospf6_lsa *lsa)
+{
+ struct ospf6_route_req request;
+ int ret;
+
+ if (IS_OSPF6_DUMP_ABR)
+ zlog_info ("ABR: Calculate %s", lsa->str);
+
+ ret = ospf6_abr_router_lsa_to_route (lsa, &request);
+ if (ret < 0)
+ return;
+
+ if (IS_OSPF6_DUMP_ABR)
+ zlog_info ("ABR: Inter Area Router add for %s", lsa->str);
+
+ ospf6_route_add (&request, ospf6->topology_table);
+}
+
+void
+ospf6_abr_router_lsa_remove (struct ospf6_lsa *lsa)
+{
+ struct ospf6_inter_area_router_lsa *ier;
+ struct prefix_ls prefix_ls;
+ struct ospf6_route_req request;
+
+ ier = OSPF6_LSA_HEADER_END (lsa->header);
+
+ memset (&prefix_ls, 0, sizeof (prefix_ls));
+ prefix_ls.family = AF_INET6;
+ prefix_ls.prefixlen = 64; /* XXX */
+ prefix_ls.adv_router.s_addr = ier->router_id;
+
+ if (IS_OSPF6_DUMP_ABR)
+ zlog_info ("ABR: Inter Area Route remove for %s", lsa->str);
+
+ for (ospf6_route_lookup (&request, (struct prefix *) &prefix_ls,
+ ospf6->route_table);
+ ! ospf6_route_end (&request);
+ ospf6_route_next (&request))
+ {
+ if (memcmp (&prefix_ls, &request.route.prefix, sizeof (prefix_ls)))
+ break;
+ if (request.path.origin.type != htons (OSPF6_LSA_TYPE_INTER_ROUTER) ||
+ request.path.origin.adv_router != lsa->header->adv_router ||
+ request.path.origin.id != lsa->header->id)
+ continue;
+
+ ospf6_route_remove (&request, ospf6->route_table);
+ }
+}
+
+
+void
+ospf6_abr_abr_entry_add (struct ospf6_route_req *abr_entry)
+{
+ struct ospf6_lsdb_node node;
+ struct prefix_ls *abr_id;
+ struct ospf6_route_req request;
+ struct ospf6_area *area;
+
+ if (IS_OSPF6_DUMP_ABR)
+ zlog_info ("ABR: New Area Border Router found");
+
+ area = ospf6_area_lookup (abr_entry->path.area_id, ospf6);
+ if (! area)
+ {
+ if (IS_OSPF6_DUMP_ABR)
+ zlog_info ("ABR: Can't find associated area");
+ return;
+ }
+
+ abr_id = (struct prefix_ls *) &abr_entry->route.prefix;
+ if (! ospf6_abr_entry_lookup (&request, abr_id->adv_router.s_addr, area))
+ {
+ if (IS_OSPF6_DUMP_ABR)
+ zlog_info ("ABR: back check failed");
+ return;
+ }
+
+ /* for each inter-prefix LSA this ABR originated */
+ for (ospf6_lsdb_type_router (&node, htons (OSPF6_LSA_TYPE_INTER_PREFIX),
+ abr_id->adv_router.s_addr, area->lsdb);
+ ! ospf6_lsdb_is_end (&node);
+ ospf6_lsdb_next (&node))
+ ospf6_abr_prefix_lsa_add (node.lsa);
+
+ /* for each inter-router LSA this ABR originated */
+ for (ospf6_lsdb_type_router (&node, htons (OSPF6_LSA_TYPE_INTER_ROUTER),
+ abr_id->adv_router.s_addr, area->lsdb);
+ ! ospf6_lsdb_is_end (&node);
+ ospf6_lsdb_next (&node))
+ ospf6_abr_router_lsa_add (node.lsa);
+}
+
+void
+ospf6_abr_abr_entry_remove (struct ospf6_route_req *abr_entry)
+{
+ struct ospf6_lsdb_node node;
+ struct prefix_ls *abr_id;
+ struct ospf6_area *area;
+
+ if (IS_OSPF6_DUMP_ABR)
+ zlog_info ("ABR: Area Border Router removed");
+
+ abr_id = (struct prefix_ls *) &abr_entry->route.prefix;
+
+ area = ospf6_area_lookup (abr_entry->path.area_id, ospf6);
+ if (! area)
+ {
+ if (IS_OSPF6_DUMP_ABR)
+ zlog_info ("ABR: Can't find associated area");
+ return;
+ }
+
+ /* for each inter-prefix LSA this ABR originated */
+ for (ospf6_lsdb_type_router (&node, htons (OSPF6_LSA_TYPE_INTER_PREFIX),
+ abr_id->adv_router.s_addr, area->lsdb);
+ ! ospf6_lsdb_is_end (&node);
+ ospf6_lsdb_next (&node))
+ ospf6_abr_prefix_lsa_remove (node.lsa);
+
+ /* for each inter-router LSA this ABR originated */
+ for (ospf6_lsdb_type_router (&node, htons (OSPF6_LSA_TYPE_INTER_ROUTER),
+ abr_id->adv_router.s_addr, area->lsdb);
+ ! ospf6_lsdb_is_end (&node);
+ ospf6_lsdb_next (&node))
+ ospf6_abr_router_lsa_remove (node.lsa);
+}
+
+/* Inter-Area-Prefix-LSA Origination */
+
+static void
+ospf6_abr_prefix_lsa_update_add (struct ospf6_route_req *request,
+ struct ospf6_area *area)
+{
+ char buffer [MAXLSASIZE];
+ u_int16_t size;
+ struct ospf6_inter_area_prefix_lsa *iep;
+ char *p;
+
+ if (IS_OSPF6_DUMP_ABR)
+ zlog_info ("Update Inter-Prefix for %s: ID: %lu",
+ area->str, (u_long) ntohl (request->route_id));
+
+ /* prepare buffer */
+ memset (buffer, 0, sizeof (buffer));
+ size = sizeof (struct ospf6_inter_area_prefix_lsa);
+ iep = (struct ospf6_inter_area_prefix_lsa *) buffer;
+ p = (char *) (iep + 1);
+
+ /* prefixlen */
+ iep->prefix.prefix_length = request->route.prefix.prefixlen;
+
+ /* PrefixOptions */
+ iep->prefix.prefix_options = request->path.prefix_options;
+
+ /* set Prefix */
+ memcpy (p, &request->route.prefix.u.prefix6,
+ OSPF6_PREFIX_SPACE (request->route.prefix.prefixlen));
+ ospf6_prefix_apply_mask (&iep->prefix);
+ size += OSPF6_PREFIX_SPACE (request->route.prefix.prefixlen);
+
+ ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_INTER_PREFIX),
+ htonl (request->route_id), ospf6->router_id,
+ (char *) iep, size, area);
+}
+
+static void
+ospf6_abr_prefix_lsa_update_remove (struct ospf6_route_req *request,
+ struct ospf6_area *area)
+{
+ struct ospf6_lsa *lsa;
+ lsa = ospf6_lsdb_lookup_lsdb (htons (OSPF6_LSA_TYPE_INTER_PREFIX),
+ htonl (request->route_id),
+ ospf6->router_id, area->lsdb);
+ if (lsa)
+ ospf6_lsa_premature_aging (lsa);
+}
+
+static void
+ospf6_abr_prefix_lsa_update (int type, struct ospf6_route_req *request)
+{
+ struct ospf6_route_req route, target;
+ listnode node;
+ struct ospf6_area *area;
+ struct ospf6_interface *o6i;
+
+ if (request->route.type != OSPF6_DEST_TYPE_NETWORK)
+ return;
+
+ /* assert this is best path; if not, return */
+ ospf6_route_lookup (&route, &request->route.prefix, request->table);
+ if (memcmp (&route.path, &request->path, sizeof (route.path)))
+ return;
+
+ if (target.path.cost >= LS_INFINITY ||
+ target.path.cost_e2 >= LS_INFINITY)
+ {
+ if (IS_OSPF6_DUMP_ABR)
+ zlog_info ("ABR: Exceeds LS Infinity, ignore");
+ return;
+ }
+
+ ospf6_route_lookup (&target, &request->route.prefix, request->table);
+ if (type == REMOVE)
+ {
+ ospf6_route_next (&route);
+ if (! memcmp (&route.route, &request->route, sizeof (route.route)))
+ {
+ type = ADD;
+ ospf6_route_next (&target);
+ }
+ }
+
+ for (node = listhead (ospf6->area_list); node; nextnode (node))
+ {
+ area = getdata (node);
+
+ if (target.path.area_id == area->area_id)
+ continue;
+
+ o6i = ospf6_interface_lookup_by_index (target.nexthop.ifindex);
+ if (o6i && o6i->area && o6i->area->area_id == area->area_id)
+ {
+ zlog_info ("ABR: Logical equivalent of split horizon, skip for %s",
+ area->str);
+ continue;
+ }
+
+ if (area->area_id == ntohs (0) && /* Backbone */
+ target.path.type != OSPF6_PATH_TYPE_INTRA)
+ continue;
+
+ /* XXX, stub area check */
+
+ /* XXX, aggregate */
+ /* if either the area of the route or the area trying to
+ advertise is backbone, do not aggregate */
+
+ if (type == ADD)
+ ospf6_abr_prefix_lsa_update_add (&target, area);
+ else
+ ospf6_abr_prefix_lsa_update_remove (&target, area);
+ }
+}
+
+void
+ospf6_abr_route_add (struct ospf6_route_req *request)
+{
+ ospf6_abr_prefix_lsa_update (ADD, request);
+}
+
+void
+ospf6_abr_route_remove (struct ospf6_route_req *request)
+{
+ ospf6_abr_prefix_lsa_update (REMOVE, request);
+}
+
+int
+ospf6_abr_prefix_lsa_refresh (void *data)
+{
+ struct ospf6_lsa *lsa = data;
+ struct ospf6_inter_area_prefix_lsa *ier;
+ struct prefix_ipv6 prefix6;
+ struct ospf6_route_req route;
+
+ ier = OSPF6_LSA_HEADER_END (lsa->header);
+ memset (&prefix6, 0, sizeof (prefix6));
+ prefix6.family = AF_INET6;
+ prefix6.prefixlen = ier->prefix.prefix_length;
+ ospf6_prefix_in6_addr (&ier->prefix, &prefix6.prefix);
+
+ ospf6_route_lookup (&route, (struct prefix *) &prefix6,
+ ospf6->route_table);
+ assert (! ospf6_route_end (&route));
+
+ ospf6_abr_prefix_lsa_update (ADD, &route);
+ return 0;
+}
+
+int
+ospf6_abr_prefix_lsa_show (struct vty *vty, struct ospf6_lsa *lsa)
+{
+ struct ospf6_inter_area_prefix_lsa *ier;
+ char prefix[128];
+
+ assert (lsa->header);
+ ier = OSPF6_LSA_HEADER_END (lsa->header);
+
+ ospf6_prefix_string (&ier->prefix, prefix, sizeof (prefix));
+
+ vty_out (vty, " Metric: %d%s",
+ ntohl (ier->metric & htonl (0x000fffff)), VTY_NEWLINE);
+ vty_out (vty, " Prefix: %s%s", prefix, VTY_NEWLINE);
+
+ return 0;
+}
+
+int
+ospf6_abr_prefix_lsa_hook_add (void *data)
+{
+ struct ospf6_lsa *lsa = data;
+ ospf6_abr_prefix_lsa_add (lsa);
+ return 0;
+}
+
+int
+ospf6_abr_prefix_lsa_hook_remove (void *data)
+{
+ struct ospf6_lsa *lsa = data;
+ ospf6_abr_prefix_lsa_remove (lsa);
+ return 0;
+}
+
+void
+ospf6_abr_database_hook_inter_prefix (struct ospf6_lsa *old,
+ struct ospf6_lsa *new)
+{
+ if (old)
+ ospf6_abr_prefix_lsa_hook_remove (old);
+ if (new && ! IS_LSA_MAXAGE (new))
+ ospf6_abr_prefix_lsa_hook_add (new);
+}
+
+void
+ospf6_abr_register_inter_prefix ()
+{
+ struct ospf6_lsa_slot slot;
+
+ memset (&slot, 0, sizeof (slot));
+ slot.type = htons (OSPF6_LSA_TYPE_INTER_PREFIX);
+ slot.name = "Inter-Prefix";
+ slot.func_show = ospf6_abr_prefix_lsa_show;
+ slot.func_refresh = ospf6_abr_prefix_lsa_refresh;
+ ospf6_lsa_slot_register (&slot);
+
+ ospf6_lsdb_hook[OSPF6_LSA_TYPE_INTER_PREFIX & OSPF6_LSTYPE_CODE_MASK].hook =
+ ospf6_abr_database_hook_inter_prefix;
+}
+
+int
+ospf6_abr_router_lsa_hook_add (void *data)
+{
+ struct ospf6_lsa *lsa = data;
+ ospf6_abr_router_lsa_add (lsa);
+ return 0;
+}
+
+int
+ospf6_abr_router_lsa_hook_remove (void *data)
+{
+ struct ospf6_lsa *lsa = data;
+ ospf6_abr_router_lsa_remove (lsa);
+ return 0;
+}
+
+int
+ospf6_abr_router_lsa_show (struct vty *vty, struct ospf6_lsa *lsa)
+{
+ return 0;
+}
+
+int
+ospf6_abr_router_lsa_refresh (void *data)
+{
+ return 0;
+}
+
+void
+ospf6_abr_database_hook_inter_router (struct ospf6_lsa *old,
+ struct ospf6_lsa *new)
+{
+ if (old)
+ ospf6_abr_router_lsa_hook_remove (old);
+ if (new && ! IS_LSA_MAXAGE (new))
+ ospf6_abr_router_lsa_hook_add (new);
+}
+
+void
+ospf6_abr_register_inter_router ()
+{
+ struct ospf6_lsa_slot slot;
+
+ memset (&slot, 0, sizeof (slot));
+ slot.type = htons (OSPF6_LSA_TYPE_INTER_ROUTER);
+ slot.name = "Inter-Router";
+ slot.func_show = ospf6_abr_router_lsa_show;
+ slot.func_refresh = ospf6_abr_router_lsa_refresh;
+ ospf6_lsa_slot_register (&slot);
+
+ ospf6_lsdb_hook[OSPF6_LSA_TYPE_INTER_ROUTER & OSPF6_LSTYPE_CODE_MASK].hook =
+ ospf6_abr_database_hook_inter_router;
+}
+
+void
+ospf6_abr_inter_route_calculation (struct ospf6_area *area)
+{
+ struct ospf6_lsdb_node node;
+
+ /* for each inter-prefix LSA */
+ for (ospf6_lsdb_type (&node, htons (OSPF6_LSA_TYPE_INTER_PREFIX),
+ area->lsdb);
+ ! ospf6_lsdb_is_end (&node);
+ ospf6_lsdb_next (&node))
+ ospf6_abr_prefix_lsa_add (node.lsa);
+}
+
+void
+ospf6_abr_init ()
+{
+ abr_index = ospf6_dump_install ("abr", "Area Border Router Function\n");
+
+ ospf6_abr_register_inter_prefix ();
+ ospf6_abr_register_inter_router ();
+}
+
+
diff --git a/ospf6d/ospf6_abr.h b/ospf6d/ospf6_abr.h
new file mode 100644
index 00000000..510532e8
--- /dev/null
+++ b/ospf6d/ospf6_abr.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2001 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef OSPF6_ABR_H
+#define OSPF6_ABR_H
+
+/* Inter-Area-Prefix-LSA */
+struct ospf6_inter_area_prefix_lsa
+{
+ u_int32_t metric; /* 12bits reserved, 20bits metric */
+ struct ospf6_prefix prefix; /* followed by one address prefix */
+};
+
+/* Inter-Area-Router-LSA */
+struct ospf6_inter_area_router_lsa
+{
+ u_char reserved;
+ u_char options[3]; /* Optional Capability */
+ u_int32_t metric; /* 12bits reserved, 20bits metric */
+ u_int32_t router_id; /* Destination Router ID */
+};
+
+void ospf6_abr_prefix_lsa_add (struct ospf6_lsa *);
+void ospf6_abr_prefix_lsa_remove (struct ospf6_lsa *);
+void ospf6_abr_prefix_lsa_change (struct ospf6_lsa *, struct ospf6_lsa *);
+
+void ospf6_abr_abr_entry_add (struct ospf6_route_req *);
+void ospf6_abr_abr_entry_remove (struct ospf6_route_req *);
+
+void ospf6_abr_route_add (struct ospf6_route_req *);
+void ospf6_abr_route_remove (struct ospf6_route_req *);
+
+void ospf6_abr_inter_route_calculation (struct ospf6_area *);
+
+void ospf6_abr_init ();
+
+#endif /* OSPF6_ABR_H */
+
diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c
new file mode 100644
index 00000000..51af5080
--- /dev/null
+++ b/ospf6d/ospf6_area.c
@@ -0,0 +1,332 @@
+/*
+ * OSPF6 Area Data Structure
+ * Copyright (C) 1999-2002 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "ospf6d.h"
+
+static int area_index;
+#define IS_OSPF6_DUMP_AREA (ospf6_dump_is_on (area_index))
+
+static void
+ospf6_area_foreach_interface (struct ospf6_area *o6a, void *arg, int val,
+ void (*func) (void *, int, void *))
+{
+ listnode node;
+ struct ospf6_interface *o6i;
+
+ for (node = listhead (o6a->if_list); node; nextnode (node))
+ {
+ o6i = (struct ospf6_interface *) getdata (node);
+ (*func) (arg, val, o6i);
+ }
+}
+
+static void
+ospf6_area_foreach_neighbor (struct ospf6_area *o6a, void *arg, int val,
+ void (*func) (void *, int, void *))
+{
+ listnode node;
+ struct ospf6_interface *o6i;
+
+ for (node = listhead (o6a->if_list); node; nextnode (node))
+ {
+ o6i = (struct ospf6_interface *) getdata (node);
+ (*o6i->foreach_nei) (o6i, arg, val, func);
+ }
+}
+
+static int
+ospf6_area_maxage_remover (struct thread *t)
+{
+ int count;
+ struct ospf6_area *o6a = (struct ospf6_area *) THREAD_ARG (t);
+
+ o6a->maxage_remover = (struct thread *) NULL;
+
+ count = 0;
+ o6a->foreach_nei (o6a, &count, NBS_EXCHANGE, ospf6_count_state);
+ o6a->foreach_nei (o6a, &count, NBS_LOADING, ospf6_count_state);
+ if (count != 0)
+ return 0;
+
+ ospf6_lsdb_remove_maxage (o6a->lsdb);
+ return 0;
+}
+
+void
+ospf6_area_schedule_maxage_remover (void *arg, int val, void *obj)
+{
+ struct ospf6_area *o6a = (struct ospf6_area *) obj;
+
+ if (o6a->maxage_remover != NULL)
+ return;
+
+ o6a->maxage_remover =
+ thread_add_event (master, ospf6_area_maxage_remover, o6a, 0);
+}
+
+int
+ospf6_area_is_stub (struct ospf6_area *o6a)
+{
+ if (OSPF6_OPT_ISSET (o6a->options, OSPF6_OPT_E))
+ return 0;
+ return 1;
+}
+
+int
+ospf6_area_is_transit (struct ospf6_area *o6a)
+{
+ return 0;
+}
+
+
+
+void
+ospf6_area_route_add (void *data)
+{
+ struct ospf6_route_req *route = data;
+ struct in6_addr local;
+
+ inet_pton (AF_INET6, "::1", &local);
+ if (! memcmp (&route->nexthop.address, &local, sizeof (struct in6_addr)))
+ {
+ if (IS_OSPF6_DUMP_AREA)
+ zlog_info ("AREA: Self-originated route add, ignore");
+ return;
+ }
+
+ ospf6_route_add (route, ospf6->route_table);
+}
+
+void
+ospf6_area_route_remove (void *data)
+{
+ struct ospf6_route_req *route = data;
+ struct in6_addr local;
+
+ inet_pton (AF_INET6, "::1", &local);
+ if (! memcmp (&route->nexthop.address, &local, sizeof (struct in6_addr)))
+ {
+ if (IS_OSPF6_DUMP_AREA)
+ zlog_info ("AREA: Self-originated route remove, ignore");
+ return;
+ }
+
+ ospf6_route_remove (route, ospf6->route_table);
+}
+
+/* Make new area structure */
+struct ospf6_area *
+ospf6_area_create (u_int32_t area_id)
+{
+ struct ospf6_area *o6a;
+ char namebuf[64];
+
+ /* allocate memory */
+ o6a = XCALLOC (MTYPE_OSPF6_AREA, sizeof (struct ospf6_area));
+
+ /* initialize */
+ inet_ntop (AF_INET, &area_id, o6a->str, sizeof (o6a->str));
+ o6a->area_id = area_id;
+ o6a->if_list = list_new ();
+
+ o6a->lsdb = ospf6_lsdb_create ();
+ o6a->spf_tree = ospf6_spftree_create ();
+
+ snprintf (namebuf, sizeof (namebuf), "Area %s's route table", o6a->str);
+ o6a->route_table = ospf6_route_table_create (namebuf);
+ o6a->route_table->hook_add = ospf6_area_route_add;
+ o6a->route_table->hook_change = ospf6_area_route_add;
+ o6a->route_table->hook_remove = ospf6_area_route_remove;
+
+ snprintf (namebuf, sizeof (namebuf), "Area %s's topology table", o6a->str);
+ o6a->table_topology = ospf6_route_table_create (namebuf);
+ o6a->table_topology->hook_add = ospf6_intra_topology_add;
+ o6a->table_topology->hook_change = ospf6_intra_topology_add;
+ o6a->table_topology->hook_remove = ospf6_intra_topology_remove;
+
+ /* xxx, set options */
+ OSPF6_OPT_SET (o6a->options, OSPF6_OPT_V6);
+ OSPF6_OPT_SET (o6a->options, OSPF6_OPT_E);
+ OSPF6_OPT_SET (o6a->options, OSPF6_OPT_R);
+
+ o6a->foreach_if = ospf6_area_foreach_interface;
+ o6a->foreach_nei = ospf6_area_foreach_neighbor;
+
+ return o6a;
+}
+
+void
+ospf6_area_bind_top (struct ospf6_area *o6a, struct ospf6 *o6)
+{
+ o6a->ospf6 = o6;
+ CALL_CHANGE_HOOK (&area_hook, o6a);
+ return;
+}
+
+void
+ospf6_area_delete (struct ospf6_area *o6a)
+{
+ listnode n;
+ struct ospf6_interface *o6i;
+
+ CALL_REMOVE_HOOK (&area_hook, o6a);
+
+ /* ospf6 interface list */
+ for (n = listhead (o6a->if_list); n; nextnode (n))
+ {
+ o6i = (struct ospf6_interface *) getdata (n);
+ /* ospf6_interface_delete (o6i); */
+ }
+ list_delete (o6a->if_list);
+
+ /* terminate LSDB */
+ ospf6_lsdb_remove_all (o6a->lsdb);
+
+ /* spf tree terminate */
+ /* xxx */
+
+ /* threads */
+ if (o6a->spf_calc)
+ thread_cancel (o6a->spf_calc);
+ o6a->spf_calc = (struct thread *) NULL;
+ if (o6a->route_calc)
+ thread_cancel (o6a->route_calc);
+ o6a->route_calc = (struct thread *) NULL;
+
+ /* new */
+ ospf6_route_table_delete (o6a->route_table);
+
+ ospf6_spftree_delete (o6a->spf_tree);
+ ospf6_route_table_delete (o6a->table_topology);
+
+ /* free area */
+ XFREE (MTYPE_OSPF6_AREA, o6a);
+}
+
+struct ospf6_area *
+ospf6_area_lookup (u_int32_t area_id, struct ospf6 *o6)
+{
+ struct ospf6_area *o6a;
+ listnode n;
+
+ for (n = listhead (o6->area_list); n; nextnode (n))
+ {
+ o6a = (struct ospf6_area *) getdata (n);
+ if (o6a->area_id == area_id)
+ return o6a;
+ }
+
+ return (struct ospf6_area *) NULL;
+}
+
+void
+ospf6_area_show (struct vty *vty, struct ospf6_area *o6a)
+{
+ listnode i;
+ struct ospf6_interface *o6i;
+
+ vty_out (vty, " Area %s%s", o6a->str, VTY_NEWLINE);
+ vty_out (vty, " Number of Area scoped LSAs is %u%s",
+ o6a->lsdb->count, VTY_NEWLINE);
+
+ ospf6_spf_statistics_show (vty, o6a->spf_tree);
+
+ vty_out (vty, " Interface attached to this area:");
+ for (i = listhead (o6a->if_list); i; nextnode (i))
+ {
+ o6i = (struct ospf6_interface *) getdata (i);
+ vty_out (vty, " %s", o6i->interface->name);
+ }
+ vty_out (vty, "%s", VTY_NEWLINE);
+
+ for (i = listhead (o6a->if_list); i; nextnode (i))
+ {
+ o6i = (struct ospf6_interface *) getdata (i);
+ if (listcount (o6i->neighbor_list) != 0)
+ ospf6_interface_statistics_show (vty, o6i);
+ }
+}
+
+void
+ospf6_area_statistics_show (struct vty *vty, struct ospf6_area *o6a)
+{
+#if 0
+ listnode node;
+ struct ospf6_interface *o6i;
+
+ vty_out (vty, " Statistics of Area %s%s", o6a->str, VTY_NEWLINE);
+#endif
+}
+
+DEFUN (show_ipv6_ospf6_area_route,
+ show_ipv6_ospf6_area_route_cmd,
+ "show ipv6 ospf6 area A.B.C.D route",
+ SHOW_STR
+ IP6_STR
+ OSPF6_STR
+ OSPF6_AREA_STR
+ OSPF6_AREA_ID_STR
+ ROUTE_STR
+ )
+{
+ struct ospf6_area *o6a;
+ u_int32_t area_id;
+
+ OSPF6_CMD_CHECK_RUNNING ();
+
+ inet_pton (AF_INET, argv[0], &area_id);
+ o6a = ospf6_area_lookup (area_id, ospf6);
+
+ if (! o6a)
+ return CMD_SUCCESS;
+
+ argc -= 1;
+ argv += 1;
+
+ return ospf6_route_table_show (vty, argc, argv, o6a->route_table);
+}
+
+ALIAS (show_ipv6_ospf6_area_route,
+ show_ipv6_ospf6_area_route_prefix_cmd,
+ "show ipv6 ospf6 area A.B.C.D route (X::X|detail)",
+ SHOW_STR
+ IP6_STR
+ OSPF6_STR
+ OSPF6_AREA_STR
+ OSPF6_AREA_ID_STR
+ ROUTE_STR
+ "Specify IPv6 address\n"
+ "Detailed information\n"
+ )
+
+void
+ospf6_area_init ()
+{
+ area_index = ospf6_dump_install ("area", "Area information\n");
+
+ install_element (VIEW_NODE, &show_ipv6_ospf6_area_route_cmd);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_area_route_prefix_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_area_route_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_area_route_prefix_cmd);
+}
+
+
diff --git a/ospf6d/ospf6_area.h b/ospf6d/ospf6_area.h
new file mode 100644
index 00000000..06844646
--- /dev/null
+++ b/ospf6d/ospf6_area.h
@@ -0,0 +1,90 @@
+/*
+ * OSPF6 Area Data Structure
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef OSPF_AREA_H
+#define OSPF_AREA_H
+
+/* This file defines area parameters and data structures. */
+
+#define OSPF6_AREA_RANGE_ADVERTISE 0
+#define OSPF6_AREA_RANGE_NOT_ADVERTISE 1
+
+#include "ospf6_spf.h"
+#include "ospf6_top.h"
+
+struct ospf6_area
+{
+ char str[16];
+
+ struct ospf6 *ospf6; /* back pointer */
+ u_int32_t area_id;
+ u_char options[3]; /* OSPF Option including ExternalCapability */
+
+ list if_list; /* OSPF interface to this area */
+
+ struct ospf6_lsdb *lsdb;
+
+ struct thread *spf_calc;
+ struct thread *route_calc;
+ int stat_spf_execed;
+ int stat_route_execed;
+
+ struct route_table *table; /* new route table */
+
+ struct prefix_ipv6 area_range;
+ struct ospf6_spftree *spf_tree;
+
+ struct ospf6_route_table *route_table;
+ struct ospf6_route_table *table_topology;
+
+ void (*foreach_if) (struct ospf6_area *, void *, int,
+ void (*func) (void *, int, void *));
+ void (*foreach_nei) (struct ospf6_area *, void *, int,
+ void (*func) (void *, int, void *));
+
+ struct thread *maxage_remover;
+
+ struct thread *thread_router_lsa;
+};
+
+
+/* prototypes */
+
+int
+ospf6_area_count_neighbor_in_state (u_char state, struct ospf6_area *o6a);
+
+void
+ospf6_area_schedule_maxage_remover (void *arg, int val, void *obj);
+
+int ospf6_area_is_stub (struct ospf6_area *o6a);
+int ospf6_area_is_transit (struct ospf6_area *o6a);
+struct ospf6_area *ospf6_area_lookup (u_int32_t, struct ospf6 *);
+struct ospf6_area *ospf6_area_create (u_int32_t);
+void ospf6_area_delete (struct ospf6_area *);
+void ospf6_area_show (struct vty *, struct ospf6_area *);
+void
+ospf6_area_statistics_show (struct vty *vty, struct ospf6_area *o6a);
+
+void ospf6_area_init ();
+
+#endif /* OSPF_AREA_H */
+
diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c
new file mode 100644
index 00000000..00a2b66c
--- /dev/null
+++ b/ospf6d/ospf6_asbr.c
@@ -0,0 +1,1040 @@
+/*
+ * Copyright (C) 2001-2002 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "log.h"
+#include "memory.h"
+#include "prefix.h"
+#include "command.h"
+#include "vty.h"
+#include "routemap.h"
+#include "table.h"
+#include "plist.h"
+#include "thread.h"
+
+#include "ospf6_prefix.h" /* xxx for ospf6_asbr.h */
+#include "ospf6_lsa.h" /* xxx for ospf6_asbr.h */
+#include "ospf6_route.h" /* xxx for ospf6_asbr.h, ospf6_zebra.h */
+#include "ospf6_zebra.h"
+#include "ospf6_asbr.h"
+#include "ospf6_damp.h"
+#include "ospf6_top.h"
+#include "ospf6_lsdb.h"
+#include "ospf6_proto.h"
+
+extern struct thread_master *master;
+
+struct route_table *external_table;
+struct
+{
+ char *name;
+ struct route_map *map;
+} rmap [ZEBRA_ROUTE_MAX];
+
+static u_int32_t link_state_id = 0;
+
+char *
+zroute_name[] =
+{
+ "system", "kernel", "connected", "static",
+ "rip", "ripng", "ospf", "ospf6", "bgp", "unknown"
+};
+char *
+zroute_abname[] =
+{
+ "X", "K", "C", "S", "R", "R", "O", "O", "B", "?"
+};
+
+#define ZROUTE_NAME(x) \
+ (0 < (x) && (x) < ZEBRA_ROUTE_MAX ? \
+ zroute_name[(x)] : zroute_name[ZEBRA_ROUTE_MAX])
+
+#define ZROUTE_ABNAME(x) \
+ (0 < (x) && (x) < ZEBRA_ROUTE_MAX ? \
+ zroute_abname[(x)] : zroute_abname[ZEBRA_ROUTE_MAX])
+
+/* redistribute function */
+void
+ospf6_asbr_routemap_set (int type, char *mapname)
+{
+ if (rmap[type].name)
+ free (rmap[type].name);
+
+ rmap[type].name = strdup (mapname);
+ rmap[type].map = route_map_lookup_by_name (mapname);
+}
+
+void
+ospf6_asbr_routemap_unset (int type)
+{
+ if (rmap[type].name)
+ free (rmap[type].name);
+ rmap[type].name = NULL;
+ rmap[type].map = NULL;
+}
+
+void
+ospf6_asbr_routemap_update ()
+{
+ int i;
+ for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+ {
+ if (rmap[i].name)
+ rmap[i].map = route_map_lookup_by_name (rmap[i].name);
+ else
+ rmap[i].map = NULL;
+ }
+}
+
+DEFUN (ospf6_redistribute,
+ ospf6_redistribute_cmd,
+ "redistribute (static|kernel|connected|ripng|bgp)",
+ "Redistribute\n"
+ "Static route\n"
+ "Kernel route\n"
+ "Connected route\n"
+ "RIPng route\n"
+ "BGP route\n"
+ )
+{
+ int type = 0;
+
+ if (strncmp (argv[0], "sta", 3) == 0)
+ type = ZEBRA_ROUTE_STATIC;
+ else if (strncmp (argv[0], "ker", 3) == 0)
+ type = ZEBRA_ROUTE_KERNEL;
+ else if (strncmp (argv[0], "con", 3) == 0)
+ type = ZEBRA_ROUTE_CONNECT;
+ else if (strncmp (argv[0], "rip", 3) == 0)
+ type = ZEBRA_ROUTE_RIPNG;
+ else if (strncmp (argv[0], "bgp", 3) == 0)
+ type = ZEBRA_ROUTE_BGP;
+
+ ospf6_zebra_no_redistribute (type);
+ ospf6_asbr_routemap_unset (type);
+ ospf6_zebra_redistribute (type);
+ return CMD_SUCCESS;
+}
+
+DEFUN (ospf6_redistribute_routemap,
+ ospf6_redistribute_routemap_cmd,
+ "redistribute (static|kernel|connected|ripng|bgp) route-map WORD",
+ "Redistribute\n"
+ "Static routes\n"
+ "Kernel route\n"
+ "Connected route\n"
+ "RIPng route\n"
+ "BGP route\n"
+ "Route map reference\n"
+ "Route map name\n"
+ )
+{
+ int type = 0;
+
+ if (strncmp (argv[0], "sta", 3) == 0)
+ type = ZEBRA_ROUTE_STATIC;
+ else if (strncmp (argv[0], "ker", 3) == 0)
+ type = ZEBRA_ROUTE_KERNEL;
+ else if (strncmp (argv[0], "con", 3) == 0)
+ type = ZEBRA_ROUTE_CONNECT;
+ else if (strncmp (argv[0], "rip", 3) == 0)
+ type = ZEBRA_ROUTE_RIPNG;
+ else if (strncmp (argv[0], "bgp", 3) == 0)
+ type = ZEBRA_ROUTE_BGP;
+
+ ospf6_zebra_no_redistribute (type);
+ ospf6_asbr_routemap_set (type, argv[1]);
+ ospf6_zebra_redistribute (type);
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ospf6_redistribute,
+ no_ospf6_redistribute_cmd,
+ "no redistribute (static|kernel|connected|ripng|bgp)",
+ NO_STR
+ "Redistribute\n"
+ "Static route\n"
+ "Kernel route\n"
+ "Connected route\n"
+ "RIPng route\n"
+ "BGP route\n"
+ )
+{
+ int type = 0;
+ struct route_node *node;
+ struct ospf6_external_route *route;
+ struct ospf6_external_info *info, *info_next = NULL;
+
+ if (strncmp (argv[0], "sta", 3) == 0)
+ type = ZEBRA_ROUTE_STATIC;
+ else if (strncmp (argv[0], "ker", 3) == 0)
+ type = ZEBRA_ROUTE_KERNEL;
+ else if (strncmp (argv[0], "con", 3) == 0)
+ type = ZEBRA_ROUTE_CONNECT;
+ else if (strncmp (argv[0], "rip", 3) == 0)
+ type = ZEBRA_ROUTE_RIPNG;
+ else if (strncmp (argv[0], "bgp", 3) == 0)
+ type = ZEBRA_ROUTE_BGP;
+
+ ospf6_zebra_no_redistribute (type);
+ ospf6_asbr_routemap_unset (type);
+
+ /* remove redistributed route */
+ for (node = route_top (external_table); node; node = route_next (node))
+ {
+ route = node->info;
+ if (! route)
+ continue;
+ for (info = route->info_head; info; info = info_next)
+ {
+ info_next = info->next;
+ if (info->type != type)
+ continue;
+ ospf6_asbr_route_remove (info->type, info->ifindex,
+ &route->prefix);
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+
+int
+ospf6_redistribute_config_write (struct vty *vty)
+{
+ int i;
+
+ for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+ {
+ if (i == ZEBRA_ROUTE_OSPF6)
+ continue;
+
+ if (! ospf6_zebra_is_redistribute (i))
+ continue;
+
+ if (rmap[i].map)
+ vty_out (vty, " redistribute %s route-map %s%s",
+ ZROUTE_NAME(i), rmap[i].name, VTY_NEWLINE);
+ else
+ vty_out (vty, " redistribute %s%s",
+ ZROUTE_NAME(i), VTY_NEWLINE);
+ }
+
+ return 0;
+}
+
+void
+ospf6_redistribute_show_config (struct vty *vty)
+{
+ int i;
+
+ if (! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_SYSTEM) &&
+ ! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_KERNEL) &&
+ ! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_STATIC) &&
+ ! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_RIPNG) &&
+ ! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_BGP))
+ return;
+
+ vty_out (vty, " Redistributing External Routes from,%s", VTY_NEWLINE);
+ for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+ {
+ if (i == ZEBRA_ROUTE_OSPF6)
+ continue;
+ if (! ospf6_zebra_is_redistribute (i))
+ continue;
+
+ if (rmap[i].map)
+ vty_out (vty, " %s with route-map %s%s",
+ ZROUTE_NAME(i), rmap[i].name, VTY_NEWLINE);
+ else
+ vty_out (vty, " %s%s", ZROUTE_NAME(i), VTY_NEWLINE);
+ }
+}
+
+/* AS External LSA origination */
+int
+ospf6_asbr_external_lsa_originate (struct thread *thread)
+{
+ struct ospf6_external_info *info;
+ char buffer [MAXLSASIZE];
+ struct ospf6_lsa_as_external *e;
+ char *p;
+
+ info = THREAD_ARG (thread);
+
+ /* clear thread */
+ info->thread_originate = NULL;
+
+ if (info->is_removed)
+ {
+ if (IS_OSPF6_DUMP_ASBR)
+ {
+ char pbuf[64];
+ prefix2str (&info->route->prefix, pbuf, sizeof (pbuf));
+ zlog_info ("ASBR: quit redistribution %s: state is down",
+ pbuf);
+ }
+ return 0;
+ }
+
+ /* prepare buffer */
+ memset (buffer, 0, sizeof (buffer));
+ e = (struct ospf6_lsa_as_external *) buffer;
+ p = (char *) (e + 1);
+
+ if (info->metric_type == 2)
+ SET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_E); /* type2 */
+ else
+ UNSET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_E); /* type1, default */
+
+ /* forwarding address */
+ if (! IN6_IS_ADDR_UNSPECIFIED (&info->forwarding))
+ SET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_F);
+ else
+ UNSET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_F);
+
+ /* external route tag */
+ UNSET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_T);
+
+ /* set metric. note: related to E bit */
+ OSPF6_ASBR_METRIC_SET (e, info->metric);
+
+ /* prefixlen */
+ e->prefix.prefix_length = info->route->prefix.prefixlen;
+
+ /* PrefixOptions */
+ e->prefix.prefix_options = info->prefix_options;
+
+ /* don't use refer LS-type */
+ e->prefix.prefix_refer_lstype = htons (0);
+
+ /* set Prefix */
+ memcpy (p, &info->route->prefix.u.prefix6,
+ OSPF6_PREFIX_SPACE (info->route->prefix.prefixlen));
+ ospf6_prefix_apply_mask (&e->prefix);
+ p += OSPF6_PREFIX_SPACE (info->route->prefix.prefixlen);
+
+ /* Forwarding address */
+ if (CHECK_FLAG (e->bits_metric, OSPF6_ASBR_BIT_F))
+ {
+ memcpy (p, &info->forwarding, sizeof (struct in6_addr));
+ p += sizeof (struct in6_addr);
+ }
+
+ /* External Route Tag */
+ if (CHECK_FLAG (e->bits_metric, OSPF6_ASBR_BIT_T))
+ {
+ /* xxx */
+ }
+
+ ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_AS_EXTERNAL),
+ htonl (info->id), ospf6->router_id,
+ (char *) buffer, p - buffer, ospf6);
+ return 0;
+}
+
+int
+ospf6_asbr_schedule_external (void *data)
+{
+ struct ospf6_external_info *info = data;
+ u_long elasped_time, time = 0;
+
+ if (info->thread_originate)
+ {
+ if (IS_OSPF6_DUMP_ASBR)
+ {
+ char pbuf[64];
+ prefix2str (&info->route->prefix, pbuf, sizeof (pbuf));
+ zlog_info ("ASBR: schedule redistribution %s: another thread",
+ pbuf);
+ }
+ return 0;
+ }
+
+ elasped_time =
+ ospf6_lsa_has_elasped (htons (OSPF6_LSA_TYPE_AS_EXTERNAL),
+ htonl (info->id), ospf6->router_id, ospf6);
+ if (elasped_time < OSPF6_MIN_LS_INTERVAL)
+ time = OSPF6_MIN_LS_INTERVAL - elasped_time;
+ else
+ time = 0;
+
+ //if (IS_OSPF6_DUMP_ASBR)
+ {
+ char pbuf[64];
+ prefix2str (&info->route->prefix, pbuf, sizeof (pbuf));
+ zlog_info ("ASBR: schedule redistribution %s as LS-ID %ld after %lu sec",
+ pbuf, (u_long) info->id, time);
+ }
+
+ if (time)
+ info->thread_originate =
+ thread_add_timer (master, ospf6_asbr_external_lsa_originate, info, time);
+ else
+ info->thread_originate =
+ thread_add_timer (master, ospf6_asbr_external_lsa_originate, info, 0);
+
+ return 0;
+}
+
+int
+ospf6_asbr_external_lsa_flush (void *data)
+{
+ struct ospf6_lsa *lsa = data;
+ if (lsa)
+ ospf6_lsa_premature_aging (lsa);
+ return 0;
+}
+
+int
+ospf6_asbr_external_lsa_refresh (void *data)
+{
+ struct ospf6_lsa *lsa = data;
+ struct ospf6_lsa_as_external *e;
+ struct prefix prefix;
+ struct route_node *node;
+ struct ospf6_external_route *route;
+ struct ospf6_external_info *info;
+
+ if (IS_OSPF6_DUMP_ASBR)
+ zlog_info ("ASBR: refresh %s", lsa->str);
+
+ e = (struct ospf6_lsa_as_external *) (lsa->header + 1);
+ ospf6_prefix_in6_addr (&e->prefix, &prefix.u.prefix6);
+ prefix.prefixlen = e->prefix.prefix_length;
+ prefix.family = AF_INET6;
+ apply_mask_ipv6 ((struct prefix_ipv6 *) &prefix);
+
+ node = route_node_lookup (external_table, &prefix);
+ if (! node || ! node->info)
+ {
+ char pname[64];
+
+ prefix2str (&prefix, pname, sizeof (pname));
+ if (IS_OSPF6_DUMP_ASBR)
+ zlog_info ("ASBR: could not find %s: premature age", pname);
+ ospf6_lsa_premature_aging (lsa);
+ return 0;
+ }
+
+ /* find external_info */
+ route = node->info;
+ for (info = route->info_head; info; info = info->next)
+ {
+ if (lsa->header->id == htonl (info->id))
+ break;
+ }
+
+ if (info)
+ ospf6_asbr_schedule_external (info);
+ else
+ ospf6_lsa_premature_aging (lsa);
+
+ return 0;
+}
+
+void
+ospf6_asbr_route_add (int type, int ifindex, struct prefix *prefix,
+ u_int nexthop_num, struct in6_addr *nexthop)
+{
+ int ret;
+ struct route_node *node;
+ struct ospf6_external_route *route;
+ struct ospf6_external_info *info, tinfo;
+
+ if (! ospf6_zebra_is_redistribute (type))
+ return;
+
+ /* apply route-map */
+ memset (&tinfo, 0, sizeof (struct ospf6_external_info));
+ if (rmap[type].map)
+ {
+ ret = route_map_apply (rmap[type].map, prefix, RMAP_OSPF6, &tinfo);
+ if (ret == RMAP_DENYMATCH)
+ {
+ if (IS_OSPF6_DUMP_ASBR)
+ zlog_info ("ASBR: denied by route-map %s", rmap[type].name);
+ return;
+ }
+ }
+
+ node = route_node_get (external_table, prefix);
+ route = node->info;
+
+ if (! route)
+ {
+ route = XMALLOC (MTYPE_OSPF6_EXTERNAL_INFO,
+ sizeof (struct ospf6_external_route));
+ memset (route, 0, sizeof (struct ospf6_external_route));
+
+ memcpy (&route->prefix, prefix, sizeof (struct prefix));
+
+ node->info = route;
+ route->node = node;
+ }
+
+ for (info = route->info_head; info; info = info->next)
+ {
+ if (info->type == type && info->ifindex == ifindex)
+ break;
+ }
+
+ if (! info)
+ {
+ info = XMALLOC (MTYPE_OSPF6_EXTERNAL_INFO,
+ sizeof (struct ospf6_external_info));
+ memset (info, 0, sizeof (struct ospf6_external_info));
+
+ info->route = route;
+ /* add tail */
+ info->prev = route->info_tail;
+ if (route->info_tail)
+ route->info_tail->next = info;
+ else
+ route->info_head = info;
+ route->info_tail = info;
+
+ info->id = link_state_id++;
+ }
+
+ /* copy result of route-map */
+ info->metric_type = tinfo.metric_type;
+ info->metric = tinfo.metric;
+ memcpy (&info->forwarding, &tinfo.forwarding,
+ sizeof (struct in6_addr));
+
+ info->type = type;
+ info->ifindex = ifindex;
+
+ if (nexthop_num && nexthop)
+ {
+ info->nexthop_num = nexthop_num;
+
+ if (info->nexthop)
+ XFREE (MTYPE_OSPF6_EXTERNAL_INFO, info->nexthop);
+
+ info->nexthop = (struct in6_addr *)
+ XMALLOC (MTYPE_OSPF6_EXTERNAL_INFO,
+ nexthop_num * sizeof (struct in6_addr));
+ memcpy (info->nexthop, nexthop,
+ nexthop_num * sizeof (struct in6_addr));
+ }
+
+ info->is_removed = 0;
+
+ //if (IS_OSPF6_DUMP_ASBR)
+ {
+ char pbuf[64];
+ struct timeval now;
+ prefix2str (&info->route->prefix, pbuf, sizeof (pbuf));
+ gettimeofday (&now, NULL);
+ zlog_info ("ASBR: start redistributing %s as LS-ID %ld: %ld.%06ld",
+ pbuf, (u_long) info->id, now.tv_sec, now.tv_usec);
+ }
+
+#ifdef HAVE_OSPF6_DAMP
+ ospf6_damp_event_up (OSPF6_DAMP_TYPE_ROUTE, prefix,
+ ospf6_asbr_schedule_external, info);
+#else /*HAVE_OSPF6_DAMP*/
+ ospf6_asbr_schedule_external (info);
+#endif /*HAVE_OSPF6_DAMP*/
+}
+
+void
+ospf6_asbr_route_remove (int type, int ifindex, struct prefix *prefix)
+{
+ struct route_node *node;
+ struct ospf6_external_route *route;
+ struct ospf6_external_info *info;
+ struct ospf6_lsa *lsa;
+
+ node = route_node_get (external_table, prefix);
+ route = node->info;
+
+ if (! route)
+ return;
+
+ for (info = route->info_head; info; info = info->next)
+ {
+ if (info->type == type && info->ifindex == ifindex)
+ break;
+ }
+
+ if (! info)
+ return;
+
+ //if (IS_OSPF6_DUMP_ASBR)
+ {
+ char pbuf[64];
+ struct timeval now;
+ prefix2str (&info->route->prefix, pbuf, sizeof (pbuf));
+ gettimeofday (&now, NULL);
+ zlog_info ("ASBR: quit redistributing %s as LS-ID %ld: %ld.%06ld",
+ pbuf, (u_long) info->id, now.tv_sec, now.tv_usec);
+ }
+
+ if (info->thread_originate)
+ thread_cancel (info->thread_originate);
+ info->thread_originate = NULL;
+
+ lsa = ospf6_lsdb_lookup (htons (OSPF6_LSA_TYPE_AS_EXTERNAL),
+ htonl (info->id), ospf6->router_id, ospf6);
+#ifdef HAVE_OSPF6_DAMP
+ ospf6_damp_event_down (OSPF6_DAMP_TYPE_ROUTE, &info->route->prefix,
+ ospf6_asbr_external_lsa_flush, lsa);
+#else /*HAVE_OSPF6_DAMP*/
+ ospf6_asbr_external_lsa_flush (lsa);
+#endif /*HAVE_OSPF6_DAMP*/
+
+#if 1
+ info->is_removed = 1;
+#else
+ /* remove from route */
+ if (info->prev)
+ info->prev->next = info->next;
+ else
+ info->route->info_head = info->next;
+ if (info->next)
+ info->next->prev = info->prev;
+ else
+ info->route->info_tail = info->prev;
+
+ /* if no info, free route */
+ if (! info->route->info_head && ! info->route->info_tail)
+ {
+ info->route->node->info = NULL;
+ free (info->route);
+ }
+
+ if (info->nexthop)
+ free (info->nexthop);
+ free (info);
+#endif /*0*/
+}
+
+void
+ospf6_asbr_external_lsa_add (struct ospf6_lsa *lsa)
+{
+ struct ospf6_lsa_as_external *external;
+ struct prefix_ls asbr_id;
+ struct ospf6_route_req asbr_entry;
+ struct ospf6_route_req request;
+
+ external = OSPF6_LSA_HEADER_END (lsa->header);
+
+ if (IS_LSA_MAXAGE (lsa))
+ {
+ if (IS_OSPF6_DUMP_ASBR)
+ zlog_info ("ASBR: maxage external lsa: %s seq: %lx",
+ lsa->str, (u_long)ntohl (lsa->header->seqnum));
+ ospf6_asbr_external_lsa_remove (lsa);
+ return;
+ }
+
+ if (IS_OSPF6_DUMP_ASBR)
+ zlog_info ("ASBR: new external lsa: %s seq: %lx",
+ lsa->str, (u_long)ntohl (lsa->header->seqnum));
+
+ if (lsa->header->adv_router == ospf6->router_id)
+ {
+ if (IS_OSPF6_DUMP_ASBR)
+ zlog_info ("ASBR: my external LSA, ignore");
+ return;
+ }
+
+ if (OSPF6_ASBR_METRIC (external) == LS_INFINITY)
+ {
+ if (IS_OSPF6_DUMP_ASBR)
+ zlog_info ("ASBR: metric is infinity, ignore");
+ return;
+ }
+
+ memset (&asbr_id, 0, sizeof (asbr_id));
+ asbr_id.family = AF_UNSPEC;
+ asbr_id.prefixlen = 64; /* xxx */
+ asbr_id.adv_router.s_addr = lsa->header->adv_router;
+
+ ospf6_route_lookup (&asbr_entry, (struct prefix *) &asbr_id,
+ ospf6->topology_table);
+
+ if (ospf6_route_end (&asbr_entry))
+ {
+ if (IS_OSPF6_DUMP_ASBR)
+ {
+ char buf[64];
+ inet_ntop (AF_INET, &asbr_id.adv_router, buf, sizeof (buf));
+ zlog_info ("ASBR: router %s not found, ignore", buf);
+ }
+ return;
+ }
+
+ memset (&request, 0, sizeof (request));
+ request.route.type = OSPF6_DEST_TYPE_NETWORK;
+ request.route.prefix.family = AF_INET6;
+ request.route.prefix.prefixlen = external->prefix.prefix_length;
+ memcpy (&request.route.prefix.u.prefix6, (char *)(external + 1),
+ OSPF6_PREFIX_SPACE (request.route.prefix.prefixlen));
+
+ request.path.area_id = asbr_entry.path.area_id;
+ request.path.origin.type = htons (OSPF6_LSA_TYPE_AS_EXTERNAL);
+ request.path.origin.id = lsa->header->id;
+ request.path.origin.adv_router = lsa->header->adv_router;
+ if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_E))
+ {
+ request.path.type = OSPF6_PATH_TYPE_EXTERNAL2;
+ request.path.metric_type = 2;
+ request.path.cost = asbr_entry.path.cost;
+ request.path.cost_e2 = OSPF6_ASBR_METRIC (external);
+ }
+ else
+ {
+ request.path.type = OSPF6_PATH_TYPE_EXTERNAL1;
+ request.path.metric_type = 1;
+ request.path.cost = asbr_entry.path.cost
+ + OSPF6_ASBR_METRIC (external);
+ request.path.cost_e2 = 0;
+ }
+ request.path.prefix_options = external->prefix.prefix_options;
+
+ while (((struct prefix_ls *)&asbr_entry.route.prefix)->adv_router.s_addr ==
+ asbr_id.adv_router.s_addr &&
+ asbr_entry.route.type == OSPF6_DEST_TYPE_ROUTER)
+ {
+ memcpy (&request.nexthop, &asbr_entry.nexthop,
+ sizeof (struct ospf6_nexthop));
+ if (IS_OSPF6_DUMP_ASBR)
+ {
+ char buf[64], nhop[64], ifname[IFNAMSIZ];
+ prefix2str (&request.route.prefix, buf, sizeof (buf));
+ inet_ntop (AF_INET6, &request.nexthop.address, nhop, sizeof (nhop));
+ if_indextoname (request.nexthop.ifindex, ifname);
+ zlog_info ("ASBR: add route: %s %s%%%s", buf, nhop, ifname);
+ }
+ ospf6_route_add (&request, ospf6->route_table);
+ ospf6_route_next (&asbr_entry);
+ }
+}
+
+void
+ospf6_asbr_external_lsa_remove (struct ospf6_lsa *lsa)
+{
+ struct ospf6_lsa_as_external *external;
+ struct prefix dest;
+ char buf[64];
+ struct ospf6_route_req request;
+
+ if (IS_OSPF6_DUMP_ASBR)
+ zlog_info ("ASBR: withdraw external lsa: %s seq: %lx",
+ lsa->str, (u_long)ntohl (lsa->header->seqnum));
+
+ if (lsa->header->adv_router == ospf6->router_id)
+ {
+ if (IS_OSPF6_DUMP_ASBR)
+ zlog_info ("ASBR: my external LSA, ignore");
+ return;
+ }
+
+ external = OSPF6_LSA_HEADER_END (lsa->header);
+ memset (&dest, 0, sizeof (dest));
+ dest.family = AF_INET6;
+ dest.prefixlen = external->prefix.prefix_length;
+ memcpy (&dest.u.prefix6, (char *)(external + 1),
+ OSPF6_PREFIX_SPACE (dest.prefixlen));
+
+ ospf6_route_lookup (&request, &dest, ospf6->route_table);
+ if (ospf6_route_end (&request))
+ {
+ if (IS_OSPF6_DUMP_ASBR)
+ {
+ prefix2str (&dest, buf, sizeof (buf));
+ zlog_info ("ASBR: %s not found", buf);
+ }
+ return;
+ }
+
+ while (request.path.origin.id != lsa->header->id ||
+ request.path.origin.adv_router != lsa->header->adv_router)
+ {
+ if (prefix_same (&request.route.prefix, &dest) != 1)
+ {
+ if (IS_OSPF6_DUMP_ASBR)
+ zlog_info ("ASBR: Can't find the entry matches the origin");
+ return;
+ }
+ ospf6_route_next (&request);
+ }
+ assert (request.path.origin.id == lsa->header->id);
+ assert (request.path.origin.adv_router == request.path.origin.adv_router);
+
+ while (request.path.origin.id == lsa->header->id &&
+ request.path.origin.adv_router == lsa->header->adv_router &&
+ prefix_same (&request.route.prefix, &dest) == 1)
+ {
+ if (IS_OSPF6_DUMP_ASBR)
+ {
+ char nhop[64], ifname[IFNAMSIZ];
+ prefix2str (&dest, buf, sizeof (buf));
+ inet_ntop (AF_INET6, &request.nexthop.address, nhop, sizeof (nhop));
+ if_indextoname (request.nexthop.ifindex, ifname);
+ zlog_info ("ASBR: remove route: %s %s%%%s", buf, nhop, ifname);
+ }
+
+ ospf6_route_remove (&request, ospf6->route_table);
+ ospf6_route_next (&request);
+ }
+}
+
+void
+ospf6_asbr_external_lsa_change (struct ospf6_lsa *old, struct ospf6_lsa *new)
+{
+ assert (old || new);
+
+ if (old == NULL)
+ ospf6_asbr_external_lsa_add (new);
+ else if (new == NULL)
+ ospf6_asbr_external_lsa_remove (old);
+ else
+ {
+ ospf6_route_table_freeze (ospf6->route_table);
+ ospf6_asbr_external_lsa_remove (old);
+ ospf6_asbr_external_lsa_add (new);
+ ospf6_route_table_thaw (ospf6->route_table);
+ }
+}
+
+void
+ospf6_asbr_asbr_entry_add (struct ospf6_route_req *topo_entry)
+{
+ struct ospf6_lsdb_node node;
+
+ struct prefix_ls *inter_router;
+ u_int32_t id, adv_router;
+
+ inter_router = (struct prefix_ls *) &topo_entry->route.prefix;
+ id = inter_router->id.s_addr;
+ adv_router = inter_router->adv_router.s_addr;
+
+ if (IS_OSPF6_DUMP_ASBR)
+ {
+ char buf[64];
+ inet_ntop (AF_INET, &inter_router->adv_router, buf, sizeof (buf));
+ zlog_info ("ASBR: new router found: %s", buf);
+ }
+
+ if (ntohl (id) != 0 ||
+ ! OSPF6_OPT_ISSET (topo_entry->path.capability, OSPF6_OPT_E))
+ {
+ zlog_warn ("ASBR: Inter topology table malformed");
+ return;
+ }
+
+ for (ospf6_lsdb_type_router (&node, htons (OSPF6_LSA_TYPE_AS_EXTERNAL),
+ adv_router, ospf6->lsdb);
+ ! ospf6_lsdb_is_end (&node);
+ ospf6_lsdb_next (&node))
+ ospf6_asbr_external_lsa_add (node.lsa);
+}
+
+void
+ospf6_asbr_asbr_entry_remove (struct ospf6_route_req *topo_entry)
+{
+ struct prefix_ls *inter_router;
+ u_int32_t id, adv_router;
+ struct ospf6_route_req request;
+
+ inter_router = (struct prefix_ls *) &topo_entry->route.prefix;
+ id = inter_router->id.s_addr;
+ adv_router = inter_router->adv_router.s_addr;
+
+ if (IS_OSPF6_DUMP_ASBR)
+ {
+ char buf[64];
+ inet_ntop (AF_INET, &inter_router->adv_router, buf, sizeof (buf));
+ zlog_info ("ASBR: router disappearing: %s", buf);
+ }
+
+ if (ntohl (id) != 0 ||
+ ! OSPF6_OPT_ISSET (topo_entry->path.capability, OSPF6_OPT_E))
+ {
+ zlog_warn ("ASBR: Inter topology table malformed");
+ }
+
+ for (ospf6_route_head (&request, ospf6->route_table);
+ ! ospf6_route_end (&request);
+ ospf6_route_next (&request))
+ {
+ if (request.path.type != OSPF6_PATH_TYPE_EXTERNAL1 &&
+ request.path.type != OSPF6_PATH_TYPE_EXTERNAL2)
+ continue;
+ if (request.path.area_id != topo_entry->path.area_id)
+ continue;
+ if (request.path.origin.adv_router != topo_entry->path.origin.adv_router)
+ continue;
+ if (memcmp (&topo_entry->nexthop, &request.nexthop,
+ sizeof (struct ospf6_nexthop)))
+ continue;
+
+ ospf6_route_remove (&request, ospf6->route_table);
+ }
+}
+
+int
+ospf6_asbr_external_show (struct vty *vty, struct ospf6_lsa *lsa)
+{
+ struct ospf6_lsa_as_external *external;
+ char buf[128], *ptr;
+ struct in6_addr in6;
+
+ assert (lsa->header);
+ external = (struct ospf6_lsa_as_external *)(lsa->header + 1);
+
+ /* bits */
+ snprintf (buf, sizeof (buf), "%s%s%s",
+ (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_E) ?
+ "E" : "-"),
+ (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F) ?
+ "F" : "-"),
+ (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_T) ?
+ "T" : "-"));
+
+ vty_out (vty, " Bits: %s%s", buf, VTY_NEWLINE);
+ vty_out (vty, " Metric: %5lu%s", (u_long)OSPF6_ASBR_METRIC (external),
+ VTY_NEWLINE);
+
+ ospf6_prefix_options_str (external->prefix.prefix_options,
+ buf, sizeof (buf));
+ vty_out (vty, " Prefix Options: %s%s", buf, VTY_NEWLINE);
+
+ vty_out (vty, " Referenced LSType: %d%s",
+ ntohs (external->prefix.prefix_refer_lstype), VTY_NEWLINE);
+
+ ospf6_prefix_in6_addr (&external->prefix, &in6);
+ inet_ntop (AF_INET6, &in6, buf, sizeof (buf));
+ vty_out (vty, " Prefix: %s/%d%s",
+ buf, external->prefix.prefix_length, VTY_NEWLINE);
+
+ /* Forwarding-Address */
+ if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F))
+ {
+ ptr = ((char *)(external + 1))
+ + OSPF6_PREFIX_SPACE (external->prefix.prefix_length);
+ inet_ntop (AF_INET6, (struct in6_addr *) ptr, buf, sizeof (buf));
+ vty_out (vty, " Forwarding-Address: %s%s", buf, VTY_NEWLINE);
+ }
+
+ return 0;
+}
+
+void
+ospf6_asbr_database_hook (struct ospf6_lsa *old, struct ospf6_lsa *new)
+{
+ if (old)
+ ospf6_asbr_external_lsa_remove (old);
+ if (new && ! IS_LSA_MAXAGE (new))
+ ospf6_asbr_external_lsa_add (new);
+}
+
+void
+ospf6_asbr_register_as_external ()
+{
+ struct ospf6_lsa_slot slot;
+
+ memset (&slot, 0, sizeof (slot));
+ slot.type = htons (OSPF6_LSA_TYPE_AS_EXTERNAL);
+ slot.name = "AS-External";
+ slot.func_show = ospf6_asbr_external_show;
+ slot.func_refresh = ospf6_asbr_external_lsa_refresh;
+ ospf6_lsa_slot_register (&slot);
+
+ ospf6_lsdb_hook[OSPF6_LSA_TYPE_AS_EXTERNAL & OSPF6_LSTYPE_CODE_MASK].hook =
+ ospf6_asbr_database_hook;
+}
+
+void
+ospf6_asbr_external_info_show (struct vty *vty,
+ struct ospf6_external_info *info)
+{
+ char prefix_buf[64], id_buf[16];
+ struct in_addr id;
+
+ if (info->is_removed)
+ return;
+
+ id.s_addr = ntohl (info->id);
+ inet_ntop (AF_INET, &id, id_buf, sizeof (id_buf));
+ prefix2str (&info->route->prefix, prefix_buf, sizeof (prefix_buf));
+ vty_out (vty, "%s %-32s %3d %-15s %3d %lu(type-%d)%s",
+ ZROUTE_ABNAME(info->type), prefix_buf, info->ifindex, id_buf,
+ info->nexthop_num, (u_long) info->metric, info->metric_type,
+ VTY_NEWLINE);
+}
+
+void
+ospf6_asbr_external_route_show (struct vty *vty,
+ struct ospf6_external_route *route)
+{
+ struct ospf6_external_info *info;
+ for (info = route->info_head; info; info = info->next)
+ ospf6_asbr_external_info_show (vty, info);
+}
+
+DEFUN (show_ipv6_route_ospf6_external,
+ show_ipv6_route_ospf6_external_cmd,
+ "show ipv6 ospf6 route redistribute",
+ SHOW_STR
+ IP6_STR
+ ROUTE_STR
+ OSPF6_STR
+ "redistributing External information\n"
+ )
+{
+ struct route_node *node;
+ struct ospf6_external_route *route;
+
+ vty_out (vty, "%s %-32s %3s %-15s %3s %s%s",
+ " ", "Prefix", "I/F", "LS-Id", "#NH", "Metric",
+ VTY_NEWLINE);
+ for (node = route_top (external_table); node; node = route_next (node))
+ {
+ route = node->info;
+ if (route)
+ ospf6_asbr_external_route_show (vty, route);
+ }
+ return CMD_SUCCESS;
+}
+
+void
+ospf6_asbr_init ()
+{
+ external_table = route_table_init ();
+ link_state_id = 0;
+
+ ospf6_asbr_register_as_external ();
+
+ install_element (VIEW_NODE, &show_ipv6_route_ospf6_external_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_route_ospf6_external_cmd);
+ install_element (OSPF6_NODE, &ospf6_redistribute_cmd);
+ install_element (OSPF6_NODE, &ospf6_redistribute_routemap_cmd);
+ install_element (OSPF6_NODE, &no_ospf6_redistribute_cmd);
+}
+
+
diff --git a/ospf6d/ospf6_asbr.h b/ospf6d/ospf6_asbr.h
new file mode 100644
index 00000000..153ed21e
--- /dev/null
+++ b/ospf6d/ospf6_asbr.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2001 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef OSPF6_ASBR_H
+#define OSPF6_ASBR_H
+
+#include "thread.h"
+
+struct ospf6_external_info
+{
+ int is_removed;
+ struct thread *thread_originate;
+
+ struct ospf6_external_route *route;
+
+ struct ospf6_external_info *prev;
+ struct ospf6_external_info *next;
+
+ /* external route type */
+ int type;
+
+ /* external route ifindex */
+ int ifindex;
+
+ /* LS-ID */
+ u_int32_t id;
+
+ /* nexthops */
+ u_int nexthop_num;
+ struct in6_addr *nexthop;
+
+ u_int8_t prefix_options;
+
+ u_int8_t metric_type;
+ u_int32_t metric;
+ struct in6_addr forwarding;
+ /* u_int32_t tag; */
+};
+
+struct ospf6_external_route
+{
+ struct route_node *node;
+
+ /* prefix */
+ struct prefix prefix;
+
+ /* external information */
+ struct ospf6_external_info *info_head;
+ struct ospf6_external_info *info_tail;
+};
+
+/* AS-External-LSA */
+struct ospf6_lsa_as_external
+{
+ u_int32_t bits_metric;
+
+ struct ospf6_prefix prefix;
+ /* followed by none or one forwarding address */
+ /* followed by none or one external route tag */
+ /* followed by none or one referenced LS-ID */
+};
+
+#define OSPF6_ASBR_BIT_T ntohl (0x01000000)
+#define OSPF6_ASBR_BIT_F ntohl (0x02000000)
+#define OSPF6_ASBR_BIT_E ntohl (0x04000000)
+
+#define OSPF6_ASBR_METRIC(E) (ntohl ((E)->bits_metric & htonl (0x00ffffff)))
+#define OSPF6_ASBR_METRIC_SET(E,C) \
+ { (E)->bits_metric &= htonl (0xff000000); \
+ (E)->bits_metric |= htonl (0x00ffffff) & htonl (C); }
+
+void ospf6_asbr_routemap_update ();
+
+int ospf6_redistribute_config_write (struct vty *vty);
+void ospf6_redistribute_show_config (struct vty *vty);
+
+void
+ospf6_asbr_route_add (int type, int ifindex, struct prefix *prefix,
+ u_int nexthop_num, struct in6_addr *nexthop);
+void
+ospf6_asbr_route_remove (int type, int ifindex, struct prefix *prefix);
+
+void ospf6_asbr_external_lsa_add (struct ospf6_lsa *lsa);
+void ospf6_asbr_external_lsa_remove (struct ospf6_lsa *lsa);
+void ospf6_asbr_external_lsa_change (struct ospf6_lsa *old,
+ struct ospf6_lsa *new);
+
+void ospf6_asbr_asbr_entry_add (struct ospf6_route_req *topo_entry);
+void ospf6_asbr_asbr_entry_remove (struct ospf6_route_req *topo_entry);
+
+void ospf6_asbr_init ();
+
+#endif /* OSPF6_ASBR_H */
+
diff --git a/ospf6d/ospf6_bintree.c b/ospf6d/ospf6_bintree.c
new file mode 100644
index 00000000..c1e9e558
--- /dev/null
+++ b/ospf6d/ospf6_bintree.c
@@ -0,0 +1,436 @@
+
+#include <zebra.h>
+#include "ospf6_bintree.h"
+
+static struct bintree_node *
+bintree_lookup_node_min (struct bintree_node *subroot)
+{
+ struct bintree_node *node;
+
+ if (subroot == NULL)
+ return NULL;
+
+ node = subroot;
+ while (node->bl_left)
+ node = node->bl_left;
+ return node;
+}
+
+static struct bintree_node *
+bintree_lookup_node_max (struct bintree_node *subroot)
+{
+ struct bintree_node *node;
+
+ assert (subroot != NULL);
+ node = subroot;
+ while (node->bl_right)
+ node = node->bl_right;
+ return node;
+}
+
+void *
+bintree_lookup (void *data, struct bintree *tree)
+{
+ int cmp;
+ struct bintree_node *node;
+
+ node = tree->root;
+
+ while (node)
+ {
+ if (tree->cmp)
+ cmp = (*tree->cmp) (node->data, data);
+ else
+ cmp = (node->data - data);
+
+ if (cmp == 0)
+ break;
+
+ if (cmp > 0)
+ node = node->bl_left;
+ else /* if (cmp < 0) */
+ node = node->bl_right;
+ }
+
+ if (node)
+ return node->data;
+
+ return NULL;
+}
+
+void *
+bintree_lookup_min (struct bintree *tree)
+{
+ struct bintree_node *node;
+ node = bintree_lookup_node_min (tree->root);
+ if (node == NULL)
+ return NULL;
+ return node->data;
+}
+
+void *
+bintree_lookup_max (struct bintree *tree)
+{
+ struct bintree_node *node;
+ node = bintree_lookup_node_max (tree->root);
+ if (node == NULL)
+ return NULL;
+ return node->data;
+}
+
+int
+bintree_add (void *data, struct bintree *tree)
+{
+ int cmp = 0;
+ struct bintree_node *node, *parent;
+
+ node = tree->root;
+ parent = NULL;
+
+ while (node)
+ {
+ if (tree->cmp)
+ cmp = (*tree->cmp) (node->data, data);
+ else
+ cmp = (node->data - data);
+
+ if (cmp == 0)
+ break;
+
+ parent = node;
+ if (cmp > 0)
+ node = node->bl_left;
+ else /* if (cmp < 0) */
+ node = node->bl_right;
+ }
+
+ if (node)
+ return -1;
+
+ node = malloc (sizeof (struct bintree_node));
+ memset (node, 0, sizeof (struct bintree_node));
+ node->tree = tree;
+ node->data = data;
+
+ if (parent)
+ {
+ node->parent = parent;
+
+ assert (cmp != 0);
+ if (cmp > 0)
+ {
+ node->parent_link = BL_LEFT;
+ parent->bl_left = node;
+ }
+ else /* if (cmp < 0) */
+ {
+ node->parent_link = BL_RIGHT;
+ parent->bl_right = node;
+ }
+ }
+ else
+ tree->root = node;
+
+ tree->count++;
+ return 0;
+}
+
+static void
+bintree_remove_nochild (struct bintree_node *node)
+{
+ assert (node->bl_left == NULL && node->bl_right == NULL);
+
+ if (node->parent == NULL)
+ node->tree->root = NULL;
+ else
+ node->parent->link[node->parent_link] = NULL;
+}
+
+static void
+bintree_remove_onechild (struct bintree_node *node)
+{
+ assert ((node->bl_left == NULL && node->bl_right != NULL) ||
+ (node->bl_left != NULL && node->bl_right == NULL));
+
+ if (node->bl_left)
+ {
+ if (node->parent == NULL)
+ {
+ node->tree->root = node->bl_left;
+ node->bl_left->parent = NULL;
+ }
+ else
+ {
+ node->parent->link[node->parent_link] = node->bl_left;
+ node->bl_left->parent = node->parent;
+ node->bl_left->parent_link = node->parent_link;
+ }
+ }
+ else if (node->bl_right)
+ {
+ if (node->parent == NULL)
+ {
+ node->tree->root = node->bl_right;
+ node->bl_right->parent = NULL;
+ }
+ else
+ {
+ node->parent->link[node->parent_link] = node->bl_right;
+ node->bl_right->parent = node->parent;
+ node->bl_right->parent_link = node->parent_link;
+ }
+ }
+ else
+ assert (0);
+}
+
+int
+bintree_remove (void *data, struct bintree *tree)
+{
+ int cmp;
+ struct bintree_node *node;
+
+ node = tree->root;
+
+ while (node)
+ {
+ if (tree->cmp)
+ cmp = (*tree->cmp) (node->data, data);
+ else
+ cmp = (node->data - data);
+
+ if (cmp == 0)
+ break;
+
+ if (cmp > 0)
+ node = node->bl_left;
+ else /* if (cmp < 0) */
+ node = node->bl_right;
+ }
+
+ if (node == NULL)
+ return -1;
+
+ if (node->bl_left == NULL && node->bl_right == NULL)
+ {
+ bintree_remove_nochild (node);
+ free (node);
+ tree->count--;
+ return 0;
+ }
+
+ if ((node->bl_left == NULL && node->bl_right != NULL) ||
+ (node->bl_left != NULL && node->bl_right == NULL))
+ {
+ bintree_remove_onechild (node);
+ free (node);
+ tree->count--;
+ return 0;
+ }
+
+ if (node->bl_left != NULL && node->bl_right != NULL)
+ {
+ struct bintree_node *successor;
+
+ /* find successor of the removing node */
+ successor = bintree_lookup_node_min (node->bl_right);
+
+ /* remove successor from tree */
+ if (successor->bl_right)
+ bintree_remove_onechild (successor);
+ else
+ bintree_remove_nochild (successor);
+
+ /* swap removing node with successor */
+ successor->parent = node->parent;
+ successor->parent_link = node->parent_link;
+ successor->bl_left = node->bl_left;
+ successor->bl_right = node->bl_right;
+
+ /* if the successor was the node->bl_right itself,
+ bintree_remove_**child may touch node->bl_right,
+ so only the successor->bl_right may be NULL
+ by above assignment */
+ successor->bl_left->parent = successor;
+ if (successor->bl_right)
+ successor->bl_right->parent = successor;
+
+ if (successor->parent == NULL)
+ tree->root = successor;
+ else
+ successor->parent->link[successor->parent_link] = successor;
+
+ free (node);
+ tree->count--;
+ return 0;
+ }
+
+ /* not reached */
+ return -1;
+}
+
+/* in-order traversal */
+
+void
+bintree_head (struct bintree *tree, struct bintree_node *node)
+{
+ struct bintree_node *head;
+
+ head = bintree_lookup_node_min (tree->root);
+ if (head == NULL)
+ {
+ node->parent = NULL;
+ node->bl_left = NULL;
+ node->bl_right = NULL;
+ node->data = NULL;
+ return;
+ }
+
+ node->tree = head->tree;
+ node->parent = head->parent;
+ node->parent_link = head->parent_link;
+ node->bl_left = head->bl_left;
+ node->bl_right = head->bl_right;
+ node->data = head->data;
+}
+
+int
+bintree_end (struct bintree_node *node)
+{
+ if (node->parent || node->bl_left || node->bl_right || node->data)
+ return 0;
+ return 1;
+}
+
+#define GOTO_PROCED_SUBTREE_TOP(node) \
+ while (node->parent && node->parent->bl_right && \
+ node->parent->bl_right->data == node->data) \
+ { \
+ node->data = node->parent->data; \
+ node->bl_left = node->parent->bl_left; \
+ node->bl_right = node->parent->bl_right; \
+ node->parent_link = node->parent->parent_link; \
+ node->parent = node->parent->parent; \
+ }
+
+void
+bintree_next (struct bintree_node *node)
+{
+ struct bintree_node *next = NULL;
+
+ /* if node have just been removed, current point should have just been
+ replaced with its successor. that certainly will not be processed
+ yet, so process it */
+ if (node->parent == NULL)
+ {
+ if (node->tree->root == NULL)
+ {
+ assert (node->tree->count == 0);
+ node->parent = NULL;
+ node->bl_left = NULL;
+ node->bl_right = NULL;
+ node->data = NULL;
+ return;
+ }
+ else if (node->tree->root->data != node->data)
+ next = node->tree->root;
+ }
+ else if (node->parent->link[node->parent_link] == NULL)
+ {
+ if (node->parent_link == BL_LEFT)
+ next = node->parent;
+ else
+ {
+ GOTO_PROCED_SUBTREE_TOP (node);
+ next = node->parent;
+ }
+ }
+ else if (node->parent->link[node->parent_link]->data != node->data)
+ next = node->parent->link[node->parent_link];
+
+ if (next == NULL)
+ {
+ if (node->bl_right)
+ next = bintree_lookup_node_min (node->bl_right);
+ else
+ {
+ GOTO_PROCED_SUBTREE_TOP (node);
+ next = node->parent;
+ }
+ }
+
+ if (next)
+ {
+ node->tree = next->tree;
+ node->parent = next->parent;
+ node->parent_link = next->parent_link;
+ node->bl_left = next->bl_left;
+ node->bl_right = next->bl_right;
+ node->data = next->data;
+ }
+ else
+ {
+ node->parent = NULL;
+ node->bl_left = NULL;
+ node->bl_right = NULL;
+ node->data = NULL;
+ }
+}
+
+struct bintree *
+bintree_create ()
+{
+ struct bintree *tree;
+
+ tree = malloc (sizeof (struct bintree));
+ memset (tree, 0, sizeof (struct bintree));
+
+ return tree;
+}
+
+void
+bintree_delete (struct bintree *tree)
+{
+ struct bintree_node node;
+
+ for (bintree_head (tree, &node); ! bintree_end (&node);
+ bintree_next (&node))
+ bintree_remove (node.data, tree);
+
+ assert (tree->count == 0);
+ free (tree);
+}
+
+int indent_num = 0;
+
+void
+bintree_print_sub (void (*print) (int, void *), struct bintree_node *subroot)
+{
+ if (subroot == NULL)
+ return;
+
+ if (subroot->bl_right)
+ {
+ indent_num++;
+ bintree_print_sub (print, subroot->bl_right);
+ indent_num--;
+ }
+
+ (*print) (indent_num, subroot->data);
+
+ if (subroot->bl_left)
+ {
+ indent_num++;
+ bintree_print_sub (print, subroot->bl_left);
+ indent_num--;
+ }
+}
+
+void
+bintree_print (void (*print) (int, void *), struct bintree *tree)
+{
+ indent_num = 0;
+ bintree_print_sub (print, tree->root);
+}
+
+
diff --git a/ospf6d/ospf6_bintree.h b/ospf6d/ospf6_bintree.h
new file mode 100644
index 00000000..fad8bbdd
--- /dev/null
+++ b/ospf6d/ospf6_bintree.h
@@ -0,0 +1,47 @@
+
+#ifndef _BINTREE_H_
+#define _BINTREE_H_
+
+struct bintree_node
+{
+ struct bintree *tree;
+
+ struct bintree_node *parent;
+ int parent_link;
+
+#define BL_LEFT 0
+#define BL_RIGHT 1
+#define BL_MAX 2
+ struct bintree_node *link[BL_MAX];
+#define bl_left link[BL_LEFT]
+#define bl_right link[BL_RIGHT]
+
+ void *data;
+};
+
+struct bintree
+{
+ int count;
+ struct bintree_node *root;
+
+ int (*cmp) (void *, void *);
+};
+
+void *bintree_lookup (void *data, struct bintree *tree);
+void *bintree_lookup_min (struct bintree *tree);
+void *bintree_lookup_max (struct bintree *tree);
+
+int bintree_add (void *data, struct bintree *tree);
+int bintree_remove (void *data, struct bintree *tree);
+
+void bintree_head (struct bintree *tree, struct bintree_node *node);
+int bintree_end (struct bintree_node *node);
+void bintree_next (struct bintree_node *node);
+
+struct bintree *bintree_create ();
+void bintree_delete (struct bintree *);
+
+void bintree_print (void (*print) (int, void *), struct bintree *);
+
+#endif /*_BINTREE_H_*/
+
diff --git a/ospf6d/ospf6_damp.c b/ospf6d/ospf6_damp.c
new file mode 100644
index 00000000..4e807a70
--- /dev/null
+++ b/ospf6d/ospf6_damp.c
@@ -0,0 +1,748 @@
+/*
+ * OSPF flap dampening by Manav Bhatia
+ * Copyright (C) 2002
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+#include <math.h>
+
+#include "log.h"
+#include "prefix.h"
+#include "thread.h"
+#include "table.h"
+#include "command.h"
+#include "vty.h"
+
+extern struct thread_master *master;
+
+#include "ospf6_damp.h"
+
+#ifdef HAVE_OSPF6_DAMP
+
+#define DELTA_REUSE 10 /* Time granularity for reuse lists */
+#define DELTA_T 5 /* Time granularity for decay arrays */
+#define DEFAULT_HALF_LIFE 60 /* (sec) 1 min */
+
+#define DEFAULT_PENALTY 1000
+#define DEFAULT_REUSE 750
+#define DEFAULT_SUPPRESS 2000
+
+#define REUSE_LIST_SIZE 256
+#define REUSE_ARRAY_SIZE 1024
+
+/* Global variable to access damping configuration */
+struct ospf6_damp_config damp_config;
+struct ospf6_damp_config *dc = &damp_config;
+u_int reuse_array_offset = 0;
+struct route_table *damp_info_table[OSPF6_DAMP_TYPE_MAX];
+struct thread *ospf6_reuse_thread = NULL;
+
+int ospf6_damp_debug = 0;
+#define IS_OSPF6_DEBUG_DAMP (ospf6_damp_debug)
+
+static struct ospf6_damp_info *
+ospf6_damp_lookup (u_short type, struct prefix *name)
+{
+ struct route_node *node;
+
+ node = route_node_lookup (damp_info_table[type], name);
+ if (node && node->info)
+ return (struct ospf6_damp_info *) node->info;
+ return NULL;
+}
+
+static struct ospf6_damp_info *
+ospf6_damp_create (u_short type, struct prefix *name)
+{
+ struct route_node *node;
+ struct ospf6_damp_info *di;
+ char namebuf[64];
+
+ di = ospf6_damp_lookup (type, name);
+ if (di)
+ return di;
+
+ if (IS_OSPF6_DEBUG_DAMP)
+ {
+ prefix2str (name, namebuf, sizeof (namebuf));
+ zlog_info ("DAMP: create: type: %d, name: %s", type, namebuf);
+ }
+
+ di = (struct ospf6_damp_info *)
+ malloc (sizeof (struct ospf6_damp_info));
+ memset (di, 0, sizeof (struct ospf6_damp_info));
+ di->type = type;
+ prefix_copy (&di->name, name);
+
+ node = route_node_get (damp_info_table[type], name);
+ node->info = di;
+
+ return di;
+}
+
+static void
+ospf6_damp_delete (u_short type, struct prefix *name)
+{
+ struct route_node *node;
+ struct ospf6_damp_info *di;
+ char namebuf[64];
+
+ node = route_node_lookup (damp_info_table[type], name);
+ if (! node || ! node->info)
+ return;
+
+ di = node->info;
+
+ if (IS_OSPF6_DEBUG_DAMP)
+ {
+ prefix2str (&di->name, namebuf, sizeof (namebuf));
+ zlog_info ("DAMP: delete: type: %d, name: %s",
+ di->type, namebuf);
+ }
+
+ node->info = NULL;
+ free (di);
+}
+
+/* compute and fill the configuration parameter */
+void
+ospf6_damp_init_config (u_int half_life, u_int reuse,
+ u_int suppress, u_int t_hold)
+{
+ int i;
+ double max_ratio, max_ratio1, max_ratio2;
+
+ dc->half_life = half_life ? half_life : DEFAULT_HALF_LIFE;
+ dc->reuse = reuse ? reuse : DEFAULT_REUSE;
+ dc->suppress = suppress ? suppress : DEFAULT_SUPPRESS;
+ dc->t_hold = t_hold ? t_hold : 4 * dc->half_life;
+
+ /* Initialize system-wide params */
+ dc->delta_t = DELTA_T;
+ dc->delta_reuse = DELTA_REUSE;
+ dc->default_penalty = DEFAULT_PENALTY;
+ dc->reuse_index_array_size = REUSE_ARRAY_SIZE;
+
+ /* ceiling is the maximum penalty a route may attain */
+ /* ceiling = reuse * 2^(T-hold/half-life) */
+ dc->ceiling = (int)
+ (dc->reuse * (pow (2, (double) dc->t_hold / dc->half_life)));
+
+ /* Decay-array computations */
+ /* decay_array_size = decay memory/time granularity */
+ dc->decay_array_size = ceil ((double) dc->t_hold / dc->delta_t);
+ dc->decay_array = malloc (sizeof (double) * (dc->decay_array_size));
+
+ /* Each i-th element is per tick delay raised to the i-th power */
+ dc->decay_array[0] = 1.0;
+ dc->decay_array[1] = exp ((1.0 / (dc->half_life / dc->delta_t)) * log (0.5));
+ for (i = 2; i < dc->decay_array_size; i++)
+ dc->decay_array[i] = dc->decay_array[i - 1] * dc->decay_array[1];
+
+ /* Reuse-list computations (reuse queue head array ?) */
+ dc->reuse_list_size = ceil ((double) dc->t_hold / dc->delta_reuse) + 1;
+ if (dc->reuse_list_size == 0 || dc->reuse_list_size > REUSE_LIST_SIZE)
+ dc->reuse_list_size = REUSE_LIST_SIZE;
+ dc->reuse_list_array = (struct ospf6_damp_info **)
+ malloc (dc->reuse_list_size * sizeof (struct ospf6_reuse_list *));
+ memset (dc->reuse_list_array, 0x00,
+ dc->reuse_list_size * sizeof (struct ospf6_reuse_list *));
+
+ /* Reuse-array computations */
+ dc->reuse_index_array = malloc (sizeof (int) * dc->reuse_index_array_size);
+
+ /*
+ * This is the maximum ratio between the current value of the penalty and
+ * the reuse value which can be indexed by the reuse array. It will be
+ * limited by the ceiling or by the amount of time that the reuse list
+ * covers
+ */
+ max_ratio1 = (double) dc->ceiling / dc->reuse;
+ max_ratio2 = exp ((double) dc->t_hold / dc->half_life) * log10 (2.0);
+ max_ratio = (max_ratio2 != 0 && max_ratio2 < max_ratio1 ?
+ max_ratio2 : max_ratio1);
+
+ /*
+ * reuse array is just an estimator and we need something
+ * to use the full array
+ */
+ dc->scale_factor = (double) dc->reuse_index_array_size / (max_ratio - 1);
+
+ for (i = 0; i < dc->reuse_index_array_size; i++)
+ {
+ dc->reuse_index_array[i] = (int)
+ (((double) dc->half_life / dc->delta_reuse) *
+ log10 (1.0 / (dc->reuse * (1.0 + ((double) i / dc->scale_factor))))
+ / log10 (0.5));
+ }
+
+ dc->enabled = ON;
+}
+
+static double
+ospf6_damp_decay (time_t tdiff)
+{
+ int index = tdiff / dc->delta_t;
+
+ if (index >= dc->decay_array_size)
+ return 0;
+
+ return dc->decay_array[index];
+}
+
+static int
+ospf6_damp_reuse_index (int penalty)
+{
+ int index;
+
+ index = (int) (((double) penalty / dc->reuse - 1.0) * dc->scale_factor);
+
+ if (index >= dc->reuse_index_array_size)
+ index = dc->reuse_index_array_size - 1;
+
+ return (dc->reuse_index_array[index] - dc->reuse_index_array[0]);
+}
+
+static int
+ospf6_reuse_list_lookup (struct ospf6_damp_info *di)
+{
+ struct ospf6_damp_info *info;
+
+ for (info = dc->reuse_list_array[di->index]; info; info = info->next)
+ {
+ if (info == di)
+ return 1;
+ }
+ return 0;
+}
+
+static void
+ospf6_reuse_list_remove (struct ospf6_damp_info *di)
+{
+ if (di->prev)
+ di->prev->next = di->next;
+ else
+ dc->reuse_list_array[di->index] = di->next;
+ if (di->next)
+ di->next->prev = di->prev;
+
+ di->index = -1;
+ di->prev = NULL;
+ di->next = NULL;
+}
+
+static void
+ospf6_reuse_list_add (struct ospf6_damp_info *di)
+{
+ /* set the index of reuse-array */
+ di->index = (reuse_array_offset + (ospf6_damp_reuse_index (di->penalty)))
+ % dc->reuse_list_size;
+
+ /* insert to the head of the reuse list */
+ di->next = dc->reuse_list_array[di->index];
+ if (di->next)
+ di->next->prev = di;
+ di->prev = NULL;
+ dc->reuse_list_array[di->index] = di;
+}
+
+/* When we quit damping for a target, we should execute proper event
+ which have been postponed during damping */
+static void
+ospf6_damp_stop (struct ospf6_damp_info *di)
+{
+ time_t t_now;
+ char namebuf[64];
+ struct timeval now;
+
+ if (IS_OSPF6_DEBUG_DAMP)
+ {
+ t_now = time (NULL);
+ prefix2str (&di->name, namebuf, sizeof (namebuf));
+ gettimeofday (&now, NULL);
+ zlog_info ("DAMP: %lu.%06lu stop damping: %ld: type: %d, name: %s",
+ now.tv_sec, now.tv_usec,
+ t_now, di->type, namebuf);
+ }
+
+ /* set flag indicates that we're damping this target */
+ di->damping = OFF;
+
+ /* if the target's current status differ from that it should be,
+ execute the proper event to repair his status */
+ if (di->target_status != di->event_type)
+ {
+ (*(di->event)) (di->target);
+ di->target_status = di->event_type;
+
+ di->event = NULL;
+ di->event_type = event_none;
+ }
+}
+
+/* ospf6_reuse_timer is called every DELTA_REUSE seconds.
+ Each route in the current reuse-list is evaluated
+ and is used or requeued */
+int
+ospf6_damp_reuse_timer (struct thread *t)
+{
+ struct ospf6_damp_info *di, *next;
+ time_t t_now, t_diff;
+ char namebuf[64];
+ struct timeval now;
+
+ /* Restart the reuse timer */
+ ospf6_reuse_thread =
+ thread_add_timer (master, ospf6_damp_reuse_timer, NULL, dc->delta_reuse);
+
+ t_now = time (NULL);
+
+ /* get the damp info list head */
+ di = dc->reuse_list_array[reuse_array_offset];
+ dc->reuse_list_array[reuse_array_offset] = NULL;
+
+ /* rotate the circular reuse list head array */
+ reuse_array_offset = (reuse_array_offset + 1) % dc->reuse_list_size;
+
+ /* for each damp info */
+ while (di)
+ {
+ next = di->next;
+ di->next = NULL;
+
+ /* Update penalty */
+ t_diff = t_now - di->t_updated;
+ di->t_updated = t_now;
+ di->penalty = (int)
+ ((double) di->penalty * ospf6_damp_decay (t_diff));
+ /* configration of ceiling may be just changed */
+ if (di->penalty > dc->ceiling)
+ di->penalty = dc->ceiling;
+
+ if (IS_OSPF6_DEBUG_DAMP)
+ {
+ prefix2str (&di->name, namebuf, sizeof (namebuf));
+ gettimeofday (&now, NULL);
+ zlog_info ("DAMP: %lu.%06lu update penalty: type: %d, name: %s, penalty: %d",
+ now.tv_sec, now.tv_usec,
+ di->type, namebuf, di->penalty);
+ }
+
+ /* If the penalty becomes under reuse,
+ call real event that we have been postponed. */
+ if (di->penalty < dc->reuse && di->damping == ON)
+ ospf6_damp_stop (di);
+
+ /* If the penalty becomes less than the half of the
+ reuse value, this damp info will be freed from reuse-list,
+ by assuming that it is considered to be stable enough already,
+ and there's no need to maintain flapping history for this. */
+ if (di->penalty <= dc->reuse / 2)
+ {
+ ospf6_damp_delete (di->type, &di->name);
+ di = next;
+ continue;
+ }
+
+ /* re-insert to the reuse-list */
+ ospf6_reuse_list_add (di);
+
+ di = next;
+ }
+
+ return 0;
+}
+
+static void
+ospf6_damp_event (damp_event_t event_type,
+ u_short type, struct prefix *name,
+ int (*event) (void *), void *target)
+{
+ time_t t_now, t_diff;
+ struct ospf6_damp_info *di;
+ char namebuf[64];
+ struct timeval now;
+
+ if (dc->enabled == OFF)
+ {
+ (*event) (target);
+ return;
+ }
+
+ di = ospf6_damp_lookup (type, name);
+ if (! di)
+ di = ospf6_damp_create (type, name);
+
+ t_now = time (NULL);
+
+ di->event = event;
+ di->target = target;
+ di->event_type = event_type;
+
+ if (! ospf6_reuse_list_lookup (di))
+ di->t_start = t_now;
+ else
+ {
+ ospf6_reuse_list_remove (di);
+
+ t_diff = t_now - di->t_updated;
+ di->penalty = (int) (di->penalty * ospf6_damp_decay (t_diff));
+ }
+
+ /* penalty only on down event */
+ if (event_type == event_down)
+ {
+ di->flap++;
+ di->penalty += dc->default_penalty;
+ }
+
+ /* limit penalty up to ceiling */
+ if (di->penalty > dc->ceiling)
+ di->penalty = dc->ceiling;
+
+ if (IS_OSPF6_DEBUG_DAMP)
+ {
+ prefix2str (&di->name, namebuf, sizeof (namebuf));
+ gettimeofday (&now, NULL);
+ zlog_info ("DAMP: %lu.%06lu update penalty: type: %d, name: %s, penalty: %d",
+ now.tv_sec, now.tv_usec,
+ di->type, namebuf, di->penalty);
+ }
+
+ /* if penalty < reuse, stop damping here */
+ if (di->penalty < dc->reuse && di->damping == ON)
+ {
+ if (IS_OSPF6_DEBUG_DAMP)
+ {
+ prefix2str (&di->name, namebuf, sizeof (namebuf));
+ gettimeofday (&now, NULL);
+ zlog_info ("DAMP: %lu.%06lu stop damping: %ld: type: %d, name: %s",
+ now.tv_sec, now.tv_usec,
+ t_now, di->type, namebuf);
+ }
+ di->damping = OFF;
+ }
+
+ /* if event == up and if penalty >= suppress , start damping here */
+ if (di->event_type == event_up && di->penalty >= dc->suppress &&
+ di->damping == OFF)
+ {
+ if (IS_OSPF6_DEBUG_DAMP)
+ {
+ prefix2str (&di->name, namebuf, sizeof (namebuf));
+ gettimeofday (&now, NULL);
+ zlog_info ("DAMP: %lu.%06lu start damping: %ld: type: %d, name: %s",
+ now.tv_sec, now.tv_usec,
+ t_now, type, namebuf);
+ }
+ di->damping = ON;
+ }
+
+ /* execute event if we're not damping */
+ if (di->damping == OFF)
+ {
+ (*(di->event)) (di->target);
+ di->target_status = di->event_type;
+ }
+
+ /* if the penalty goes beyond suppress value, start damping */
+ if (di->penalty >= dc->suppress && di->damping == OFF)
+ {
+ if (IS_OSPF6_DEBUG_DAMP)
+ {
+ prefix2str (name, namebuf, sizeof (namebuf));
+ gettimeofday (&now, NULL);
+ zlog_info ("DAMP: %lu.%06lu start damping: %ld: type: %d, name: %s",
+ now.tv_sec, now.tv_usec,
+ t_now, type, namebuf);
+ }
+ di->damping = ON;
+ }
+
+ /* update last-updated-time field */
+ di->t_updated = t_now;
+
+ /* Insert it into the reuse list */
+ ospf6_reuse_list_add (di);
+}
+
+void
+ospf6_damp_event_up (u_short type, struct prefix *name,
+ int (*event) (void *), void *target)
+{
+ struct timeval now;
+
+ gettimeofday (&now, NULL);
+ if (IS_OSPF6_DEBUG_DAMP)
+ zlog_info ("DAMP: Up Event at %lu.%06lu", now.tv_sec, now.tv_usec);
+
+ ospf6_damp_event (event_up, type, name, event, target);
+}
+
+void
+ospf6_damp_event_down (u_short type, struct prefix *name,
+ int (*event) (void *), void *target)
+{
+ struct timeval now;
+
+ gettimeofday (&now, NULL);
+ if (IS_OSPF6_DEBUG_DAMP)
+ zlog_info ("DAMP: Down Event at %lu.%06lu", now.tv_sec, now.tv_usec);
+
+ ospf6_damp_event (event_down, type, name, event, target);
+}
+
+int
+ospf6_damp_debug_thread (struct thread *thread)
+{
+ int i;
+ struct ospf6_damp_info *di;
+ char buf[256];
+ time_t t_now;
+ struct timeval now;
+
+ for (i = 0; i < dc->reuse_list_size; i++)
+ {
+ for (di = dc->reuse_list_array[i]; di; di = di->next)
+ {
+ t_now = time (NULL);
+ gettimeofday (&now, NULL);
+ prefix2str (&di->name, buf, sizeof (buf));
+ zlog_info ("DAMP: %lu.%06lu %c %-32s penalty %7u",
+ now.tv_sec, now.tv_usec,
+ (di->damping == ON ? 'D' : 'A'), buf,
+ (u_int) (di->penalty *
+ ospf6_damp_decay (t_now - di->t_updated)));
+ }
+ }
+ thread_add_timer (master, ospf6_damp_debug_thread, NULL, 1);
+ return 0;
+}
+
+DEFUN (show_ipv6_ospf6_route_flapping,
+ show_ipv6_ospf6_route_flapping_cmd,
+ "show ipv6 ospf6 route flapping",
+ SHOW_STR
+ IP6_STR
+ OSPF6_STR)
+{
+ int i;
+ struct ospf6_damp_info *di;
+ char buf[256];
+ time_t t_now;
+
+ t_now = time (NULL);
+ vty_out (vty, "%c %-32s %7s%s", ' ', "Prefix", "penalty", VTY_NEWLINE);
+
+ for (i = 0; i < dc->reuse_list_size; i++)
+ {
+ for (di = dc->reuse_list_array[i]; di; di = di->next)
+ {
+ prefix2str (&di->name, buf, sizeof (buf));
+ vty_out (vty, "%c %-32s %7u%s",
+ (di->damping == ON ? 'D' : ' '), buf,
+ (u_int) (di->penalty *
+ ospf6_damp_decay (t_now - di->t_updated)),
+ VTY_NEWLINE);
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (flap_damping_route,
+ flap_damping_route_cmd,
+ "flap-damping route <0-4294967295> <0-4294967295> "
+ "<0-4294967295> <0-4294967295>",
+ "enable flap dampening\n"
+ "enable route flap dampening\n"
+ "half-life in second\n"
+ "reuse value\n"
+ "suppress value\n"
+ "t-hold in second (maximum time that the target can be damped)\n"
+ )
+{
+ u_int half_life, reuse, suppress, t_hold;
+
+ if (argc)
+ {
+ half_life = (u_int) strtoul (argv[0], NULL, 10);
+ reuse = (u_int) strtoul (argv[1], NULL, 10);
+ suppress = (u_int) strtoul (argv[2], NULL, 10);
+ t_hold = (u_int) strtoul (argv[3], NULL, 10);
+ }
+ else
+ {
+ half_life = (u_int) DEFAULT_HALF_LIFE;
+ reuse = (u_int) DEFAULT_REUSE;
+ suppress = (u_int) DEFAULT_SUPPRESS;
+ t_hold = (u_int) DEFAULT_HALF_LIFE * 4;
+ }
+
+ if (reuse && suppress && reuse >= suppress)
+ {
+ vty_out (vty, "reuse value exceeded suppress value, failed%s\n",
+ VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ if (half_life && t_hold && half_life >= t_hold)
+ {
+ vty_out (vty, "half-life exceeded t-hold, failed%s\n", VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ ospf6_damp_init_config (half_life, reuse, suppress, t_hold);
+
+ if (ospf6_reuse_thread == NULL)
+ ospf6_reuse_thread =
+ thread_add_timer (master, ospf6_damp_reuse_timer, NULL, dc->delta_reuse);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ipv6_ospf6_damp_config,
+ show_ipv6_ospf6_camp_config_cmd,
+ "show ipv6 ospf6 damp config",
+ SHOW_STR
+ IP6_STR
+ OSPF6_STR
+ "Flap-dampening information\n"
+ "shows dampening configuration\n"
+ )
+{
+ int i;
+
+ vty_out (vty, "%10s %10s %10s %10s%s",
+ "Half life", "Suppress", "Reuse", "T-hold",
+ VTY_NEWLINE);
+ vty_out (vty, "%10u %10u %10u %10u%s",
+ dc->half_life, dc->suppress, dc->reuse, dc->t_hold,
+ VTY_NEWLINE);
+ vty_out (vty, "%s", VTY_NEWLINE);
+
+ vty_out (vty, "Delta-t = %u%s", dc->delta_t, VTY_NEWLINE);
+ vty_out (vty, "Delta-Reuse = %u%s", dc->delta_reuse, VTY_NEWLINE);
+ vty_out (vty, "Default-Penalty = %u%s", dc->default_penalty, VTY_NEWLINE);
+ vty_out (vty, "Ceiling = %u%s", dc->ceiling, VTY_NEWLINE);
+ vty_out (vty, "ScaleFactor = %f%s", dc->scale_factor, VTY_NEWLINE);
+
+ vty_out (vty, "DecayArray(%d) =%s", dc->decay_array_size, VTY_NEWLINE);
+ for (i = 0; i < dc->decay_array_size; i++)
+ {
+ if (i % 10 == 0)
+ vty_out (vty, " ");
+ vty_out (vty, " %f", dc->decay_array[i]);
+ if (i % 10 == 0)
+ vty_out (vty, "%s", VTY_NEWLINE);
+ }
+ vty_out (vty, "%s", VTY_NEWLINE);
+
+ vty_out (vty, "ReuseIndexArray(%d) =%s",
+ dc->reuse_index_array_size, VTY_NEWLINE);
+ for (i = 0; i < dc->reuse_index_array_size; i++)
+ {
+ if (i % 10 == 0)
+ vty_out (vty, " ");
+ vty_out (vty, " %d", dc->reuse_index_array[i]);
+ if (i % 10 == 0)
+ vty_out (vty, "%s", VTY_NEWLINE);
+ }
+ vty_out (vty, "%s", VTY_NEWLINE);
+
+ return CMD_SUCCESS;
+}
+
+void
+ospf6_damp_config_write (struct vty *vty)
+{
+ if (dc->enabled == ON)
+ {
+ vty_out (vty, " flap-damping route %u %u %u %u%s",
+ dc->half_life, dc->reuse, dc->suppress, dc->t_hold,
+ VTY_NEWLINE);
+ }
+}
+
+DEFUN (debug_ospf6_damp,
+ debug_ospf6_damp_cmd,
+ "debug ospf6 damp",
+ DEBUG_STR
+ OSPF6_STR
+ "Flap-dampening information\n"
+ )
+{
+ ospf6_damp_debug = 1;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_ospf6_damp,
+ no_debug_ospf6_damp_cmd,
+ "no debug ospf6 damp",
+ NO_STR
+ DEBUG_STR
+ OSPF6_STR
+ "Flap-dampening information\n"
+ )
+{
+ ospf6_damp_debug = 0;
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_debug_ospf6_damp,
+ show_debug_ospf6_damp_cmd,
+ "show debugging ospf6 damp",
+ SHOW_STR
+ DEBUG_STR
+ OSPF6_STR
+ "Flap-dampening information\n"
+ )
+{
+ vty_out (vty, "debugging ospf6 damp is ");
+ if (IS_OSPF6_DEBUG_DAMP)
+ vty_out (vty, "enabled.");
+ else
+ vty_out (vty, "disabled.");
+ vty_out (vty, "%s", VTY_NEWLINE);
+ return CMD_SUCCESS;
+}
+
+void
+ospf6_damp_init ()
+{
+ int i;
+ for (i = 0; i < OSPF6_DAMP_TYPE_MAX; i++)
+ damp_info_table[i] = route_table_init ();
+
+ install_element (VIEW_NODE, &show_ipv6_ospf6_route_flapping_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_route_flapping_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_camp_config_cmd);
+ install_element (OSPF6_NODE, &flap_damping_route_cmd);
+
+ install_element (ENABLE_NODE, &show_debug_ospf6_damp_cmd);
+ install_element (CONFIG_NODE, &debug_ospf6_damp_cmd);
+ install_element (CONFIG_NODE, &no_debug_ospf6_damp_cmd);
+
+ thread_add_event (master, ospf6_damp_debug_thread, NULL, 0);
+}
+
+#endif /* HAVE_OSPF6_DAMP */
+
+
diff --git a/ospf6d/ospf6_damp.h b/ospf6d/ospf6_damp.h
new file mode 100644
index 00000000..19bdbc7a
--- /dev/null
+++ b/ospf6d/ospf6_damp.h
@@ -0,0 +1,109 @@
+/*
+ * OSPF flap dampening by Manav Bhatia
+ * Copyright (C) 2002
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+/*
+ * Flap Damping (target e.g. link/route)
+ */
+
+#define HAVE_OSPF6_DAMP
+
+typedef enum
+{
+ OFF,
+ ON,
+} onoff_t;
+
+typedef enum
+{
+ event_none,
+ event_up,
+ event_down,
+} damp_event_t;
+
+/* Structure maintained per target basis */
+struct ospf6_damp_info
+{
+ /* identifier to decide which target */
+ u_short type;
+ struct prefix name;
+
+ /* do we damping this info */
+ onoff_t damping;
+
+ u_int penalty;
+ u_int flap;
+ time_t t_start; /* First flap (down event) time */
+ time_t t_updated; /* Last time the penalty was updated */
+
+ /* index and double-link for reuse list */
+ int index;
+ struct ospf6_damp_info *next;
+ struct ospf6_damp_info *prev;
+
+ /* the last event that we are avoiding */
+ int (*event) (void *target);
+ void *target;
+ damp_event_t event_type;
+ damp_event_t target_status;
+};
+
+#define OSPF6_DAMP_TYPE_ROUTE 0
+#define OSPF6_DAMP_TYPE_MAX 1
+
+/* Global Configuration Parameters */
+struct ospf6_damp_config
+{
+ /* is damping enabled ? */
+ onoff_t enabled;
+
+ /* configurable parameters */
+ u_int half_life;
+ u_int suppress;
+ u_int reuse;
+ u_int t_hold; /* Maximum hold down time */
+
+ /* Non configurable parameters */
+ u_int delta_t;
+ u_int delta_reuse;
+ u_int default_penalty;
+ u_int ceiling; /* Max value a penalty can attain */
+ double scale_factor;
+
+ int decay_array_size; /* Calculated using config parameters */
+ double *decay_array; /* Storage for decay values */
+
+ int reuse_index_array_size; /* Size of reuse index array */
+ int *reuse_index_array;
+
+ int reuse_list_size; /* Number of reuse lists */
+ struct ospf6_damp_info **reuse_list_array;
+};
+
+int ospf6_damp_reuse_timer (struct thread *);
+void ospf6_damp_event_up (u_short type, struct prefix *name,
+ int (*exec_up) (void *), void *target);
+void ospf6_damp_event_down (u_short type, struct prefix *name,
+ int (*exec_down) (void *), void *target);
+
+void ospf6_damp_config_write (struct vty *);
+void ospf6_damp_init ();
+
diff --git a/ospf6d/ospf6_dbex.c b/ospf6d/ospf6_dbex.c
new file mode 100644
index 00000000..b10d9aeb
--- /dev/null
+++ b/ospf6d/ospf6_dbex.c
@@ -0,0 +1,704 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "ospf6d.h"
+
+/* check validity and put lsa in reqestlist if needed. */
+/* returns -1 if SeqNumMismatch required. */
+int
+ospf6_dbex_check_dbdesc_lsa_header (struct ospf6_lsa_header *lsa_header,
+ struct ospf6_neighbor *from)
+{
+ struct ospf6_lsa *received = NULL;
+ struct ospf6_lsa *have = NULL;
+
+ received = ospf6_lsa_summary_create
+ ((struct ospf6_lsa_header__ *) lsa_header);
+
+ /* case when received is AS-External though neighbor belongs stub area */
+ if (lsa_header->type == htons (OSPF6_LSA_TYPE_AS_EXTERNAL) &&
+ ospf6_area_is_stub (from->ospf6_interface->area))
+ {
+ zlog_err ("DbDesc %s receive from %s", from->str, received->str);
+ zlog_err (" E-bit mismatch: %s", received->str);
+ ospf6_lsa_delete (received);
+ return -1;
+ }
+
+ /* if already have newer database copy, check next LSA */
+ have = ospf6_lsdb_lookup (lsa_header->type, lsa_header->ls_id,
+ lsa_header->advrtr,
+ ospf6_lsa_get_scope (lsa_header->type,
+ from->ospf6_interface));
+ if (! have)
+ {
+ /* if we don't have database copy, add request */
+ if (IS_OSPF6_DUMP_DBEX)
+ zlog_info ("Have no database copy, Request");
+ ospf6_neighbor_request_add (received, from);
+ }
+ else if (have)
+ {
+ /* if database copy is less recent, add request */
+ if (ospf6_lsa_check_recent (received, have) < 0)
+ {
+ if (IS_OSPF6_DUMP_DBEX)
+ zlog_info ("Database copy less recent, Request");
+ ospf6_neighbor_request_add (received, from);
+ }
+ }
+
+ return 0;
+}
+
+/* Direct acknowledgement */
+static void
+ospf6_dbex_acknowledge_direct (struct ospf6_lsa *lsa,
+ struct ospf6_neighbor *o6n)
+{
+ struct iovec directack[MAXIOVLIST];
+ assert (lsa);
+
+ if (IS_OSPF6_DUMP_DBEX)
+ zlog_info ("DBEX: [%s:%s] direct ack %s ",
+ o6n->str, o6n->ospf6_interface->interface->name,
+ lsa->str);
+
+ /* clear pointers to fragments of packet for direct acknowledgement */
+ iov_clear (directack, MAXIOVLIST);
+
+ /* set pointer of LSA to send */
+ OSPF6_MESSAGE_ATTACH (directack, lsa->header,
+ sizeof (struct ospf6_lsa_header));
+
+ /* age update and add InfTransDelay */
+ ospf6_lsa_age_update_to_send (lsa, o6n->ospf6_interface->transdelay);
+
+ /* send unicast packet to neighbor's ipaddress */
+ ospf6_message_send (OSPF6_MESSAGE_TYPE_LSACK, directack, &o6n->hisaddr,
+ o6n->ospf6_interface->if_id);
+}
+
+/* Delayed acknowledgement */
+void
+ospf6_dbex_acknowledge_delayed (struct ospf6_lsa *lsa,
+ struct ospf6_interface *o6i)
+{
+ assert (o6i);
+
+ if (IS_OSPF6_DUMP_DBEX)
+ zlog_info ("DBEX: [%s] delayed ack %s", o6i->interface->name, lsa->str);
+
+ /* attach delayed acknowledge list */
+ ospf6_lsa_age_current (lsa);
+ ospf6_interface_delayed_ack_add (lsa, o6i);
+
+ /* if not yet, schedule delayed acknowledge RxmtInterval later.
+ timers should be *less than* RxmtInterval
+ or needless retrans will ensue */
+ if (o6i->thread_send_lsack_delayed == NULL)
+ o6i->thread_send_lsack_delayed
+ = thread_add_timer (master, ospf6_send_lsack_delayed,
+ o6i, o6i->rxmt_interval - 1);
+
+ return;
+}
+
+/* RFC2328 section 13 (4):
+ if MaxAge LSA and if we have no instance, and no neighbor
+ is in states Exchange or Loading */
+/* returns 1 if match this case, else returns 0 */
+static int
+ospf6_dbex_is_maxage_to_be_dropped (struct ospf6_lsa *received,
+ struct ospf6_neighbor *from)
+{
+ int count;
+
+ if (! IS_LSA_MAXAGE (received))
+ return 0;
+
+ if (ospf6_lsdb_lookup (received->header->type, received->header->id,
+ received->header->adv_router,
+ ospf6_lsa_get_scope (received->header->type,
+ from->ospf6_interface)))
+ return 0;
+
+ if (OSPF6_LSA_IS_SCOPE_LINKLOCAL (ntohs (received->header->type)))
+ {
+ count = 0;
+ (*from->ospf6_interface->foreach_nei)
+ (from->ospf6_interface, &count, NBS_EXCHANGE, ospf6_count_state);
+ (*from->ospf6_interface->foreach_nei)
+ (from->ospf6_interface, &count, NBS_LOADING, ospf6_count_state);
+ if (count)
+ return 0;
+ }
+ else if (OSPF6_LSA_IS_SCOPE_AREA (ntohs (received->header->type)))
+ {
+ count = 0;
+ (*from->ospf6_interface->area->foreach_nei)
+ (from->ospf6_interface->area, &count, NBS_EXCHANGE, ospf6_count_state);
+ (*from->ospf6_interface->area->foreach_nei)
+ (from->ospf6_interface->area, &count, NBS_LOADING, ospf6_count_state);
+ if (count)
+ return 0;
+ }
+ else if (OSPF6_LSA_IS_SCOPE_AS (ntohs (received->header->type)))
+ {
+ count = 0;
+ (*from->ospf6_interface->area->ospf6->foreach_nei)
+ (from->ospf6_interface->area->ospf6, &count, NBS_EXCHANGE,
+ ospf6_count_state);
+ (*from->ospf6_interface->area->ospf6->foreach_nei)
+ (from->ospf6_interface->area->ospf6, &count, NBS_LOADING,
+ ospf6_count_state);
+ if (count)
+ return 0;
+ }
+
+ return 1;
+}
+
+static void
+ospf6_dbex_remove_retrans (void *arg, int val, void *obj)
+{
+ struct ospf6_lsa *rem;
+ struct ospf6_neighbor *nei = (struct ospf6_neighbor *) obj;
+ struct ospf6_lsa *lsa = (struct ospf6_lsa *) arg;
+
+ rem = ospf6_lsdb_lookup_lsdb (lsa->header->type, lsa->header->id,
+ lsa->header->adv_router, nei->retrans_list);
+ if (rem)
+ {
+ ospf6_neighbor_retrans_remove (rem, nei);
+ ospf6_maxage_remover ();
+ }
+}
+
+void
+ospf6_dbex_remove_from_all_retrans_list (struct ospf6_lsa *lsa)
+{
+ struct ospf6_interface *o6i;
+ struct ospf6_area *o6a;
+
+ if (OSPF6_LSA_IS_SCOPE_LINKLOCAL (htons (lsa->header->type)))
+ {
+ o6i = lsa->scope;
+ (*o6i->foreach_nei) (o6i, lsa, 0, ospf6_dbex_remove_retrans);
+ }
+ else if (OSPF6_LSA_IS_SCOPE_AREA (htons (lsa->header->type)))
+ {
+ o6a = lsa->scope;
+ (*o6a->foreach_nei) (o6a, lsa, 0, ospf6_dbex_remove_retrans);
+ }
+ else if (OSPF6_LSA_IS_SCOPE_AS (htons (lsa->header->type)))
+ {
+ (*ospf6->foreach_nei) (ospf6, lsa, 0, ospf6_dbex_remove_retrans);
+ }
+}
+
+/* RFC2328 section 13 */
+void
+ospf6_dbex_receive_lsa (struct ospf6_lsa_header *lsa_header,
+ struct ospf6_neighbor *from)
+{
+ struct ospf6_lsa *received, *have, *rem;
+ struct timeval now;
+ int ismore_recent, acktype;
+ unsigned short cksum;
+ struct ospf6_lsa_slot *slot;
+
+ received = have = (struct ospf6_lsa *)NULL;
+ ismore_recent = -1;
+ recent_reason = "no instance";
+
+ zlog_info ("Receive LSA (header -> %p)", lsa_header);
+
+ /* make lsa structure for received lsa */
+ received = ospf6_lsa_create (lsa_header);
+
+ /* set LSA scope */
+ if (OSPF6_LSA_IS_SCOPE_LINKLOCAL (htons (lsa_header->type)))
+ received->scope = from->ospf6_interface;
+ else if (OSPF6_LSA_IS_SCOPE_AREA (htons (lsa_header->type)))
+ received->scope = from->ospf6_interface->area;
+ else if (OSPF6_LSA_IS_SCOPE_AS (htons (lsa_header->type)))
+ received->scope = from->ospf6_interface->area->ospf6;
+
+ /* (1) LSA Checksum */
+ cksum = ntohs (lsa_header->checksum);
+ if (ntohs (ospf6_lsa_checksum (lsa_header)) != cksum)
+ {
+ if (IS_OSPF6_DUMP_DBEX)
+ zlog_info ("DBEX: received %s from %s%%%s"
+ ": wrong checksum, drop",
+ received->str, from->str,
+ from->ospf6_interface->interface->name);
+ ospf6_lsa_delete (received);
+ return;
+ }
+
+ /* (3) Ebit Missmatch: AS-External-LSA */
+ if (lsa_header->type == htons (OSPF6_LSA_TYPE_AS_EXTERNAL) &&
+ ospf6_area_is_stub (from->ospf6_interface->area))
+ {
+ if (IS_OSPF6_DUMP_DBEX)
+ zlog_info ("DBEX: received %s from %s%%%s"
+ ": E-bit mismatch, drop",
+ received->str, from->str,
+ from->ospf6_interface->interface->name);
+ ospf6_lsa_delete (received);
+ return;
+ }
+
+ /* (4) if MaxAge LSA and if we have no instance, and no neighbor
+ is in states Exchange or Loading */
+ if (ospf6_dbex_is_maxage_to_be_dropped (received, from))
+ {
+ /* log */
+ if (IS_OSPF6_DUMP_DBEX)
+ zlog_info ("DBEX: received %s from %s%%%s"
+ ": MaxAge, no instance, no neighbor exchange, drop",
+ received->str, from->str,
+ from->ospf6_interface->interface->name);
+
+ /* a) Acknowledge back to neighbor (13.5) */
+ /* Direct Acknowledgement */
+ ospf6_dbex_acknowledge_direct (received, from);
+
+ /* b) Discard */
+ ospf6_lsa_delete (received);
+ return;
+ }
+
+ /* (5) */
+ /* lookup the same database copy in lsdb */
+ have = ospf6_lsdb_lookup (lsa_header->type, lsa_header->ls_id,
+ lsa_header->advrtr,
+ ospf6_lsa_get_scope (lsa_header->type,
+ from->ospf6_interface));
+ if (have)
+ {
+ ismore_recent = ospf6_lsa_check_recent (received, have);
+ if (ntohl (received->header->seqnum) == ntohl (have->header->seqnum))
+ SET_FLAG (received->flag, OSPF6_LSA_FLAG_DUPLICATE);
+ }
+
+ /* if no database copy or received is more recent */
+ if (!have || ismore_recent < 0)
+ {
+ /* in case we have no database copy */
+ ismore_recent = -1;
+
+ /* (a) MinLSArrival check */
+ gettimeofday (&now, (struct timezone *)NULL);
+ if (have && SEC_TVDIFF (&now, &have->installed) < OSPF6_MIN_LS_ARRIVAL)
+ {
+ //if (IS_OSPF6_DUMP_DBEX)
+ zlog_info ("DBEX: Receive new LSA from %s: %s seq: %#x age: %d "
+ "within MinLSArrival, drop: %ld.%06ld",
+ from->str, received->str,
+ ntohl (received->header->seqnum),
+ ntohs (received->header->age),
+ now.tv_sec, now.tv_usec);
+
+ /* this will do free this lsa */
+ ospf6_lsa_delete (received);
+ return; /* examin next lsa */
+ }
+
+ //if (IS_OSPF6_DUMP_DBEX)
+ zlog_info ("DBEX: Receive new LSA from %s: %s seq: %#x age: %d: "
+ "%ld.%06ld",
+ from->str, received->str,
+ ntohl (received->header->seqnum),
+ ntohs (received->header->age),
+ now.tv_sec, now.tv_usec);
+
+ /* (b) immediately flood */
+ ospf6_dbex_flood (received, from);
+
+#if 0
+ /* Because New LSDB do not permit two LSA having the same identifier
+ exist in a LSDB list, above ospf6_dbex_flood() will remove
+ the old instance automatically. thus bellow is not needed. */
+ /* (c) remove database copy from all neighbor's retranslist */
+ if (have)
+ ospf6_dbex_remove_from_all_retrans_list (have);
+#endif
+
+ /* (d), installing lsdb, which may cause routing
+ table calculation (replacing database copy) */
+ ospf6_lsdb_install (received);
+
+ /* (e) possibly acknowledge */
+ acktype = ack_type (received, ismore_recent, from);
+ if (acktype == DIRECT_ACK)
+ {
+ if (IS_OSPF6_DUMP_DBEX)
+ zlog_info ("DBEX: Direct Ack to %s", from->str);
+ ospf6_dbex_acknowledge_direct (received, from);
+ }
+ else if (acktype == DELAYED_ACK)
+ {
+ if (IS_OSPF6_DUMP_DBEX)
+ zlog_info ("DBEX: Delayed Ack to %s", from->str);
+ ospf6_dbex_acknowledge_delayed (received, from->ospf6_interface);
+ }
+ else
+ {
+ if (IS_OSPF6_DUMP_DBEX)
+ zlog_info ("DBEX: No Ack to %s", from->str);
+ }
+
+ /* (f) */
+ /* Self Originated LSA, section 13.4 */
+ if (received->lsa_hdr->lsh_advrtr == ospf6->router_id
+ && (! have || ismore_recent < 0))
+ {
+ /* we're going to make new lsa or to flush this LSA. */
+ if (IS_OSPF6_DUMP_DBEX)
+ zlog_info ("DBEX: Self-originated LSA %s from %s:%s",
+ received->str, from->str,
+ from->ospf6_interface->interface->name);
+ if (IS_OSPF6_DUMP_DBEX)
+ zlog_info ("DBEX: %s: Make new one/Flush", received->str);
+
+ SET_FLAG (received->flag, OSPF6_LSA_FLAG_REFRESH);
+ slot = ospf6_lsa_slot_get (received->header->type);
+ if (slot && slot->func_refresh)
+ {
+ (*slot->func_refresh) (received);
+ return;
+ }
+
+ zlog_warn ("Can't Refresh LSA: Unknown type: %#x, Flush",
+ ntohs (received->header->type));
+ ospf6_lsa_premature_aging (received);
+ return;
+ }
+ }
+ else if (ospf6_lsdb_lookup_lsdb (received->header->type,
+ received->header->id,
+ received->header->adv_router,
+ from->request_list))
+ /* (6) if there is instance on sending neighbor's request list */
+ {
+ /* if no database copy, should go above state (5) */
+ assert (have);
+
+ zlog_warn ("DBEX: [%s:%s] received LSA %s is not newer,"
+ " and is on his requestlist: Generate BadLSReq",
+ from->str, from->ospf6_interface->interface->name,
+ received->str);
+
+ /* BadLSReq */
+ thread_add_event (master, bad_lsreq, from, 0);
+
+ ospf6_lsa_delete (received);
+ }
+ else if (ismore_recent == 0) /* (7) if neither is more recent */
+ {
+ /* (a) if on retranslist, Treat this LSA as an Ack: Implied Ack */
+ rem = ospf6_lsdb_lookup_lsdb (received->header->type,
+ received->header->id,
+ received->header->adv_router,
+ from->retrans_list);
+ if (rem)
+ {
+ if (IS_OSPF6_DUMP_DBEX)
+ zlog_info ("DBEX: Implied Ack from %s, (remove retrans)",
+ from->str);
+ SET_FLAG (received->flag, OSPF6_LSA_FLAG_IMPLIEDACK);
+ ospf6_neighbor_retrans_remove (rem, from);
+ }
+
+ /* (b) possibly acknowledge */
+ acktype = ack_type (received, ismore_recent, from);
+ if (acktype == DIRECT_ACK)
+ {
+ if (IS_OSPF6_DUMP_DBEX)
+ zlog_info ("DBEX: Direct Ack to %s", from->str);
+ ospf6_dbex_acknowledge_direct (received, from);
+ }
+ else if (acktype == DELAYED_ACK)
+ {
+ if (IS_OSPF6_DUMP_DBEX)
+ zlog_info ("DBEX: Delayed Ack to %s", from->str);
+ ospf6_dbex_acknowledge_delayed (received, from->ospf6_interface);
+ }
+ else
+ {
+ if (IS_OSPF6_DUMP_DBEX)
+ zlog_info ("DBEX: No Ack to %s", from->str);
+ }
+ ospf6_lsa_delete (received);
+ }
+ else /* (8) previous database copy is more recent */
+ {
+ /* If Seqnumber Wrapping, simply discard
+ Otherwise, Send database copy of this LSA to this neighbor */
+ if (! IS_LSA_MAXAGE (received) ||
+ received->lsa_hdr->lsh_seqnum != MAX_SEQUENCE_NUMBER)
+ {
+ if (IS_OSPF6_DUMP_DBEX)
+ zlog_info ("DBEX: database is more recent: send back to %s",
+ from->str);
+ ospf6_send_lsupdate_direct (have, from);
+ }
+ ospf6_lsa_delete (received);
+ }
+}
+
+/* RFC2328: Table 19: Sending link state acknowledgements. */
+int
+ack_type (struct ospf6_lsa *newp, int ismore_recent,
+ struct ospf6_neighbor *from)
+{
+ struct ospf6_interface *ospf6_interface;
+ struct ospf6_lsa *have;
+ int count;
+
+ assert (from && from->ospf6_interface);
+ ospf6_interface = from->ospf6_interface;
+
+ if (CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_FLOODBACK))
+ return NO_ACK;
+
+ if (ismore_recent < 0)
+ {
+ if (ospf6_interface->state != IFS_BDR)
+ return DELAYED_ACK;
+
+ if (ospf6_interface->dr == from->router_id)
+ return DELAYED_ACK;
+ return NO_ACK;
+ }
+
+ if (CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_DUPLICATE) &&
+ CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_IMPLIEDACK))
+ {
+ if (ospf6_interface->state != IFS_BDR)
+ return NO_ACK;
+
+ if (ospf6_interface->dr == from->router_id)
+ return DELAYED_ACK;
+
+ return NO_ACK;
+ }
+
+ if (CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_DUPLICATE) &&
+ ! CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_IMPLIEDACK))
+ return DIRECT_ACK;
+
+ have = ospf6_lsdb_lookup (newp->header->type, newp->header->id,
+ newp->header->adv_router,
+ ospf6_lsa_get_scope (newp->header->type,
+ from->ospf6_interface));
+
+ count = 0;
+ ospf6->foreach_nei (ospf6, &count, NBS_EXCHANGE, ospf6_count_state);
+ ospf6->foreach_nei (ospf6, &count, NBS_LOADING, ospf6_count_state);
+
+ if (IS_LSA_MAXAGE (newp) && have == NULL && count == 0)
+ return DIRECT_ACK;
+
+ return NO_ACK;
+}
+
+static void
+ospf6_dbex_flood_linklocal (struct ospf6_lsa *lsa, struct ospf6_interface *o6i,
+ struct ospf6_neighbor *from)
+{
+ struct ospf6_neighbor *o6n = (struct ospf6_neighbor *) NULL;
+ int ismore_recent, addretrans = 0;
+ listnode n;
+ struct ospf6_lsa *req;
+
+ /* (1) for each neighbor */
+ for (n = listhead (o6i->neighbor_list); n; nextnode (n))
+ {
+ o6n = (struct ospf6_neighbor *) getdata (n);
+
+ /* (a) */
+ if (o6n->state < NBS_EXCHANGE)
+ continue; /* examin next neighbor */
+
+ /* (b) */
+ if (o6n->state == NBS_EXCHANGE
+ || o6n->state == NBS_LOADING)
+ {
+ req = ospf6_lsdb_lookup_lsdb (lsa->header->type,
+ lsa->header->id,
+ lsa->header->adv_router,
+ o6n->request_list);
+ if (req)
+ {
+ ismore_recent = ospf6_lsa_check_recent (lsa, req);
+ if (ismore_recent > 0)
+ {
+ continue; /* examin next neighbor */
+ }
+ else if (ismore_recent == 0)
+ {
+ ospf6_neighbor_request_remove (req, o6n);
+ continue; /* examin next neighbor */
+ }
+ else /* ismore_recent < 0 (the new LSA is more recent) */
+ {
+ ospf6_neighbor_request_remove (req, o6n);
+ }
+ }
+ }
+
+ /* (c) */
+ if (from && from->router_id == o6n->router_id)
+ continue; /* examin next neighbor */
+
+ /* (d) add retranslist */
+ if (IS_OSPF6_DUMP_DBEX)
+ zlog_info ("DBEX: schedule flooding [%s:%s]: %s",
+ o6n->str, o6n->ospf6_interface->interface->name,
+ lsa->str);
+ ospf6_neighbor_retrans_add (lsa, o6n);
+ addretrans++;
+ if (o6n->send_update == (struct thread *) NULL)
+ o6n->send_update =
+ thread_add_timer (master, ospf6_send_lsupdate_rxmt, o6n,
+ o6n->ospf6_interface->rxmt_interval);
+ }
+
+ /* (2) */
+ if (addretrans == 0)
+ return; /* examin next interface */
+
+ if (from && from->ospf6_interface == o6i)
+ {
+ if (IS_OSPF6_DUMP_DBEX)
+ zlog_info ("DBEX: flood back %s to %s",
+ lsa->str, o6i->interface->name);
+ /* note occurence of floodback */
+ SET_FLAG (lsa->flag, OSPF6_LSA_FLAG_FLOODBACK);
+ }
+
+ /* (3) */
+ if (from && from->ospf6_interface == o6i)
+ {
+ /* if from DR or BDR, don't need to flood this interface */
+ if (from->router_id == from->ospf6_interface->dr ||
+ from->router_id == from->ospf6_interface->bdr)
+ return; /* examin next interface */
+ }
+
+ /* (4) if I'm BDR, DR will flood this interface */
+ if (from && from->ospf6_interface == o6i
+ && o6i->state == IFS_BDR)
+ return; /* examin next interface */
+
+ if (IS_OSPF6_DUMP_DBEX)
+ zlog_info ("Flood to interface %s", o6i->interface->name);
+
+ /* (5) send LinkState Update */
+ ospf6_send_lsupdate_flood (lsa, o6i);
+
+ return;
+}
+
+/* RFC2328 section 13.3 */
+static void
+ospf6_dbex_flood_area (struct ospf6_lsa *lsa, struct ospf6_area *area,
+ struct ospf6_neighbor *from)
+{
+ listnode n;
+ struct ospf6_interface *ospf6_interface;
+
+ assert (lsa && lsa->lsa_hdr && area);
+
+ /* for each eligible ospf_ifs */
+ for (n = listhead (area->if_list); n; nextnode (n))
+ {
+ ospf6_interface = (struct ospf6_interface *) getdata (n);
+ ospf6_dbex_flood_linklocal (lsa, ospf6_interface, from);
+ }
+}
+
+static void
+ospf6_dbex_flood_as (struct ospf6_lsa *lsa, struct ospf6 *ospf6,
+ struct ospf6_neighbor *from)
+{
+ listnode n;
+ struct ospf6_area *o6a;
+
+ assert (lsa && lsa->lsa_hdr && ospf6);
+
+ /* for each attached area */
+ for (n = listhead (ospf6->area_list); n; nextnode (n))
+ {
+ o6a = (struct ospf6_area *) getdata (n);
+ ospf6_dbex_flood_area (lsa, o6a, from);
+ }
+}
+
+/* flood ospf6_lsa within appropriate scope */
+void
+ospf6_dbex_flood (struct ospf6_lsa *lsa, struct ospf6_neighbor *from)
+{
+ struct ospf6_area *o6a;
+ struct ospf6_interface *o6i;
+ struct ospf6 *o6;
+ struct ospf6_lsa_header *lsa_header;
+
+ lsa_header = (struct ospf6_lsa_header *) lsa->lsa_hdr;
+
+ if (OSPF6_LSA_IS_SCOPE_LINKLOCAL (ntohs (lsa_header->type)))
+ {
+ o6i = (struct ospf6_interface *) lsa->scope;
+ assert (o6i);
+
+ if (IS_OSPF6_DUMP_DBEX)
+ zlog_info ("Flood Linklocal: %s", o6i->interface->name);
+ ospf6_dbex_flood_linklocal (lsa, o6i, from);
+ }
+ else if (OSPF6_LSA_IS_SCOPE_AREA (ntohs (lsa_header->type)))
+ {
+ o6a = (struct ospf6_area *) lsa->scope;
+ assert (o6a);
+
+ if (IS_OSPF6_DUMP_DBEX)
+ zlog_info ("Flood Area: %s", o6a->str);
+ ospf6_dbex_flood_area (lsa, o6a, from);
+ }
+ else if (OSPF6_LSA_IS_SCOPE_AS (ntohs (lsa_header->type)))
+ {
+ o6 = (struct ospf6 *) lsa->scope;
+ assert (o6);
+
+ if (IS_OSPF6_DUMP_DBEX)
+ zlog_info ("Flood AS");
+ ospf6_dbex_flood_as (lsa, o6, from);
+ }
+ else
+ {
+ zlog_warn ("Can't Flood %s: scope unknown", lsa->str);
+ }
+}
+
+
diff --git a/ospf6d/ospf6_dbex.h b/ospf6d/ospf6_dbex.h
new file mode 100644
index 00000000..fbb7dc5e
--- /dev/null
+++ b/ospf6d/ospf6_dbex.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef OSPF6_DBEX_H
+#define OSPF6_DBEX_H
+
+/* for ack_type() */
+#define NO_ACK 0
+#define DELAYED_ACK 1
+#define DIRECT_ACK 2
+
+/* Function Prototypes */
+void
+ospf6_add_delayed_ack (struct ospf6_lsa *, struct ospf6_interface *);
+void
+ospf6_remove_delayed_ack (struct ospf6_lsa *, struct ospf6_interface *);
+void ospf6_lsa_delayed_ack_remove_all (struct ospf6_lsa *lsa);
+
+void ospf6_dbex_prepare_summary (struct ospf6_neighbor *);
+
+int
+ospf6_dbex_check_dbdesc_lsa_header (struct ospf6_lsa_header *lsa_header,
+ struct ospf6_neighbor *from);
+
+void
+ospf6_dbex_acknowledge_delayed (struct ospf6_lsa *lsa,
+ struct ospf6_interface *o6i);
+
+void
+ospf6_dbex_receive_lsa (struct ospf6_lsa_header *,
+ struct ospf6_neighbor *);
+
+int ack_type (struct ospf6_lsa *, int, struct ospf6_neighbor *);
+
+void ospf6_dbex_flood (struct ospf6_lsa *, struct ospf6_neighbor *);
+
+void
+ospf6_dbex_remove_from_all_retrans_list (struct ospf6_lsa *lsa);
+
+#endif /* OSPF6_DBEX_H */
+
diff --git a/ospf6d/ospf6_dump.c b/ospf6d/ospf6_dump.c
new file mode 100644
index 00000000..e950ec8c
--- /dev/null
+++ b/ospf6d/ospf6_dump.c
@@ -0,0 +1,314 @@
+/*
+ * Logging function
+ * Copyright (C) 1999-2002 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+/* Include other stuffs */
+#include "log.h"
+#include "command.h"
+#include "ospf6_dump.h"
+
+#define CMD_SHOW 0
+#define CMD_ENABLE 1
+#define CMD_DISABLE 2
+#define CMD_MAX 3
+
+struct ospf6_dump
+{
+ struct cmd_element cmd[CMD_MAX];
+ char *name;
+ int config;
+};
+
+#define DUMP_MAX 512
+struct ospf6_dump *ospf6_dump[DUMP_MAX];
+unsigned int dump_size = 0;
+
+static int
+ospf6_dump_index (struct cmd_element *cmd, int command)
+{
+ int i;
+
+ for (i = 0; i < DUMP_MAX; i++)
+ {
+ if (cmd != &ospf6_dump[i]->cmd[command])
+ continue;
+ break;
+ }
+
+ if (i == DUMP_MAX)
+ return -1;
+ return i;
+}
+
+int
+ospf6_dump_is_on (int index)
+{
+ if (ospf6_dump[index] == NULL)
+ return 0;
+
+ return ospf6_dump[index]->config;
+}
+
+int
+ospf6_dump_show (struct cmd_element *cmd,
+ struct vty *vty, int argc, char **argv)
+{
+ int index;
+
+ index = ospf6_dump_index (cmd, CMD_SHOW);
+ assert (index != -1);
+
+ vty_out (vty, " %-16s: %s%s", ospf6_dump[index]->name,
+ (ospf6_dump[index]->config ? "on" : "off"),
+ VTY_NEWLINE);
+ return CMD_SUCCESS;
+}
+
+int
+ospf6_dump_enable (struct cmd_element *cmd,
+ struct vty *vty, int argc, char **argv)
+{
+ int index;
+
+ index = ospf6_dump_index (cmd, CMD_ENABLE);
+ assert (index != -1);
+
+ ospf6_dump[index]->config = 1;
+ return CMD_SUCCESS;
+}
+
+int
+ospf6_dump_disable (struct cmd_element *cmd,
+ struct vty *vty, int argc, char **argv)
+{
+ int index;
+
+ index = ospf6_dump_index (cmd, CMD_DISABLE);
+ assert (index != -1);
+
+ ospf6_dump[index]->config = 0;
+ return CMD_SUCCESS;
+}
+
+int
+ospf6_dump_install (char *name, char *help)
+{
+ struct cmd_element *cmd;
+ char string[256];
+ char helpstring[256];
+
+ if (dump_size + 1 >= DUMP_MAX)
+ return -1;
+
+ ospf6_dump[dump_size] = malloc (sizeof (struct ospf6_dump));
+ if (ospf6_dump[dump_size] == NULL)
+ return -1;
+ memset (ospf6_dump[dump_size], 0, sizeof (struct ospf6_dump));
+
+ ospf6_dump[dump_size]->name = strdup (name);
+
+ cmd = &ospf6_dump[dump_size]->cmd[CMD_SHOW];
+ snprintf (string, sizeof (string), "show debugging ospf6 %s", name);
+ snprintf (helpstring, sizeof (helpstring), "%s%s%s%s",
+ SHOW_STR, DEBUG_STR, OSPF6_STR, help);
+ memset (cmd, 0, sizeof (struct cmd_element));
+ cmd->string = strdup (string);
+ cmd->func = ospf6_dump_show;
+ cmd->doc = strdup (helpstring);
+ install_element (VIEW_NODE, cmd);
+ install_element (ENABLE_NODE, cmd);
+
+ cmd = &ospf6_dump[dump_size]->cmd[CMD_ENABLE];
+ snprintf (string, sizeof (string), "debug ospf6 %s", name);
+ snprintf (helpstring, sizeof (helpstring), "%s%s%s",
+ DEBUG_STR, OSPF6_STR, help);
+ memset (cmd, 0, sizeof (struct cmd_element));
+ cmd->string = strdup (string);
+ cmd->func = ospf6_dump_enable;
+ cmd->doc = strdup (helpstring);
+ install_element (CONFIG_NODE, cmd);
+
+ cmd = &ospf6_dump[dump_size]->cmd[CMD_DISABLE];
+ snprintf (string, sizeof (string), "no debug ospf6 %s", name);
+ snprintf (helpstring, sizeof (helpstring), "%s%s%s%s",
+ NO_STR, DEBUG_STR, OSPF6_STR, help);
+ memset (cmd, 0, sizeof (struct cmd_element));
+ cmd->string = strdup (string);
+ cmd->func = ospf6_dump_disable;
+ cmd->doc = strdup (helpstring);
+ install_element (CONFIG_NODE, cmd);
+
+ return dump_size++;
+}
+
+DEFUN(show_debug_ospf6,
+ show_debug_ospf6_cmd,
+ "show debugging ospf6",
+ SHOW_STR
+ DEBUG_STR
+ OSPF6_STR)
+{
+ int i;
+
+ vty_out (vty, "OSPF6 debugging status:%s", VTY_NEWLINE);
+
+ for (i = 0; i < DUMP_MAX; i++)
+ {
+ if (ospf6_dump[i] == NULL)
+ continue;
+ ospf6_dump_show (&ospf6_dump[i]->cmd[CMD_SHOW], vty, 0, NULL);
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (debug_ospf6_all,
+ debug_ospf6_all_cmd,
+ "debug ospf6 all",
+ DEBUG_STR
+ OSPF6_STR
+ "Turn on ALL OSPFv3 debugging\n")
+{
+ int i;
+
+ for (i = 0; i < DUMP_MAX; i++)
+ {
+ if (ospf6_dump[i] == NULL)
+ continue;
+ ospf6_dump_enable (&ospf6_dump[i]->cmd[CMD_ENABLE], vty, 0, NULL);
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_ospf6_all,
+ no_debug_ospf6_all_cmd,
+ "no debug ospf6 all",
+ NO_STR
+ DEBUG_STR
+ OSPF6_STR
+ "Turn off ALL OSPFv3 debugging\n")
+{
+ int i;
+
+ for (i = 0; i < DUMP_MAX; i++)
+ {
+ if (ospf6_dump[i] == NULL)
+ continue;
+ ospf6_dump_disable (&ospf6_dump[i]->cmd[CMD_DISABLE], vty, 0, NULL);
+ }
+
+ return CMD_SUCCESS;
+}
+
+struct cmd_node debug_node =
+{
+ DEBUG_NODE,
+ ""
+};
+
+int
+ospf6_dump_config_write (struct vty *vty)
+{
+ int i;
+
+ for (i = 0; i < dump_size; i++)
+ {
+ if (ospf6_dump[i] == NULL)
+ continue;
+
+ if (ospf6_dump[i]->config == 0)
+ continue;
+
+ vty_out (vty, "debug ospf6 %s%s", ospf6_dump[i]->name, VTY_NEWLINE);
+ }
+
+ vty_out (vty, "!%s", VTY_NEWLINE);
+ return 0;
+}
+
+char dump_index[OSPF6_DUMP_MAX];
+
+void
+ospf6_dump_init ()
+{
+ memset (ospf6_dump, 0, sizeof (ospf6_dump));
+
+ install_node (&debug_node, ospf6_dump_config_write);
+
+ install_element (VIEW_NODE, &show_debug_ospf6_cmd);
+ install_element (ENABLE_NODE, &show_debug_ospf6_cmd);
+
+ install_element (CONFIG_NODE, &debug_ospf6_all_cmd);
+ install_element (CONFIG_NODE, &no_debug_ospf6_all_cmd);
+
+ /* bellow is for backward compatibility
+ should be moved to each modules */
+
+#define MESSAGE_STR "OSPFv3 Messages\n"
+
+ dump_index[OSPF6_DUMP_HELLO] =
+ ospf6_dump_install ("message hello",
+ MESSAGE_STR "Hello\n");
+ dump_index[OSPF6_DUMP_DBDESC] =
+ ospf6_dump_install ("message dbdesc",
+ MESSAGE_STR "Database Description\n");
+ dump_index[OSPF6_DUMP_LSREQ] =
+ ospf6_dump_install ("message lsreq",
+ MESSAGE_STR "Link State Request\n");
+ dump_index[OSPF6_DUMP_LSUPDATE] =
+ ospf6_dump_install ("message lsupdate",
+ MESSAGE_STR "Link State Update\n");
+ dump_index[OSPF6_DUMP_LSACK] =
+ ospf6_dump_install ("message lsack",
+ MESSAGE_STR "Link State Acknowledge\n");
+ dump_index[OSPF6_DUMP_NEIGHBOR] =
+ ospf6_dump_install ("neighbor", "Neighbors\n");
+ dump_index[OSPF6_DUMP_INTERFACE] =
+ ospf6_dump_install ("interface", "Interfaces\n");
+ dump_index[OSPF6_DUMP_LSA] =
+ ospf6_dump_install ("lsa", "Link State Advertisement\n");
+ dump_index[OSPF6_DUMP_ZEBRA] =
+ ospf6_dump_install ("zebra", "Communication with zebra\n");
+ dump_index[OSPF6_DUMP_CONFIG] =
+ ospf6_dump_install ("config", "Configuration Changes\n");
+ dump_index[OSPF6_DUMP_DBEX] =
+ ospf6_dump_install ("dbex", "Database Exchange/Flooding\n");
+ dump_index[OSPF6_DUMP_SPF] =
+ ospf6_dump_install ("spf", "SPF Calculation\n");
+ dump_index[OSPF6_DUMP_ROUTE] =
+ ospf6_dump_install ("route", "Route Calculation\n");
+ dump_index[OSPF6_DUMP_LSDB] =
+ ospf6_dump_install ("lsdb", "Link State Database\n");
+ dump_index[OSPF6_DUMP_REDISTRIBUTE] =
+ ospf6_dump_install ("redistribute",
+ "Route Exchange with other protocols\n");
+ dump_index[OSPF6_DUMP_HOOK] =
+ ospf6_dump_install ("hook", "Hooks\n");
+ dump_index[OSPF6_DUMP_ASBR] =
+ ospf6_dump_install ("asbr", "AS Boundary Router function\n");
+ dump_index[OSPF6_DUMP_PREFIX] =
+ ospf6_dump_install ("prefix", "Prefix\n");
+}
+
+
diff --git a/ospf6d/ospf6_dump.h b/ospf6d/ospf6_dump.h
new file mode 100644
index 00000000..18a6e466
--- /dev/null
+++ b/ospf6d/ospf6_dump.h
@@ -0,0 +1,95 @@
+/*
+ * Logging function
+ * Copyright (C) 1999-2002 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef OSPF6_DUMP_H
+#define OSPF6_DUMP_H
+
+enum ospf6_dump_type
+{
+ OSPF6_DUMP_HELLO,
+ OSPF6_DUMP_DBDESC,
+ OSPF6_DUMP_LSREQ,
+ OSPF6_DUMP_LSUPDATE,
+ OSPF6_DUMP_LSACK,
+ OSPF6_DUMP_NEIGHBOR,
+ OSPF6_DUMP_INTERFACE,
+ OSPF6_DUMP_AREA,
+ OSPF6_DUMP_LSA,
+ OSPF6_DUMP_ZEBRA,
+ OSPF6_DUMP_CONFIG,
+ OSPF6_DUMP_DBEX,
+ OSPF6_DUMP_SPF,
+ OSPF6_DUMP_ROUTE,
+ OSPF6_DUMP_LSDB,
+ OSPF6_DUMP_REDISTRIBUTE,
+ OSPF6_DUMP_HOOK,
+ OSPF6_DUMP_ASBR,
+ OSPF6_DUMP_PREFIX,
+ OSPF6_DUMP_ABR,
+ OSPF6_DUMP_MAX
+};
+
+#define IS_OSPF6_DUMP_HELLO \
+ (ospf6_dump_is_on (dump_index[OSPF6_DUMP_HELLO]))
+#define IS_OSPF6_DUMP_DBDESC \
+ (ospf6_dump_is_on (dump_index[OSPF6_DUMP_DBDESC]))
+#define IS_OSPF6_DUMP_LSREQ \
+ (ospf6_dump_is_on (dump_index[OSPF6_DUMP_LSREQ]))
+#define IS_OSPF6_DUMP_LSUPDATE \
+ (ospf6_dump_is_on (dump_index[OSPF6_DUMP_LSUPDATE]))
+#define IS_OSPF6_DUMP_LSACK \
+ (ospf6_dump_is_on (dump_index[OSPF6_DUMP_LSACK]))
+#define IS_OSPF6_DUMP_NEIGHBOR \
+ (ospf6_dump_is_on (dump_index[OSPF6_DUMP_NEIGHBOR]))
+#define IS_OSPF6_DUMP_INTERFACE \
+ (ospf6_dump_is_on (dump_index[OSPF6_DUMP_INTERFACE]))
+#define IS_OSPF6_DUMP_LSA \
+ (ospf6_dump_is_on (dump_index[OSPF6_DUMP_LSA]))
+#define IS_OSPF6_DUMP_ZEBRA \
+ (ospf6_dump_is_on (dump_index[OSPF6_DUMP_ZEBRA]))
+#define IS_OSPF6_DUMP_CONFIG \
+ (ospf6_dump_is_on (dump_index[OSPF6_DUMP_CONFIG]))
+#define IS_OSPF6_DUMP_DBEX \
+ (ospf6_dump_is_on (dump_index[OSPF6_DUMP_DBEX]))
+#define IS_OSPF6_DUMP_SPF \
+ (ospf6_dump_is_on (dump_index[OSPF6_DUMP_SPF]))
+#define IS_OSPF6_DUMP_ROUTE \
+ (ospf6_dump_is_on (dump_index[OSPF6_DUMP_ROUTE]))
+#define IS_OSPF6_DUMP_LSDB \
+ (ospf6_dump_is_on (dump_index[OSPF6_DUMP_LSDB]))
+#define IS_OSPF6_DUMP_REDISTRIBUTE \
+ (ospf6_dump_is_on (dump_index[OSPF6_DUMP_REDISTRIBUTE]))
+#define IS_OSPF6_DUMP_HOOK \
+ (ospf6_dump_is_on (dump_index[OSPF6_DUMP_HOOK]))
+#define IS_OSPF6_DUMP_ASBR \
+ (ospf6_dump_is_on (dump_index[OSPF6_DUMP_ASBR]))
+#define IS_OSPF6_DUMP_PREFIX \
+ (ospf6_dump_is_on (dump_index[OSPF6_DUMP_PREFIX]))
+
+extern char dump_index[OSPF6_DUMP_MAX];
+
+void ospf6_dump_init ();
+int ospf6_dump_is_on (int index);
+int ospf6_dump_install (char *name, char *help);
+
+#endif /* OSPF6_DUMP_H */
+
diff --git a/ospf6d/ospf6_hook.c b/ospf6d/ospf6_hook.c
new file mode 100644
index 00000000..fc9e185d
--- /dev/null
+++ b/ospf6d/ospf6_hook.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2001 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "log.h"
+#include "memory.h"
+
+#include "ospf6_hook.h"
+
+struct ospf6_hook_master neighbor_hook;
+struct ospf6_hook_master interface_hook;
+struct ospf6_hook_master area_hook;
+struct ospf6_hook_master top_hook;
+struct ospf6_hook_master database_hook;
+struct ospf6_hook_master intra_topology_hook;
+struct ospf6_hook_master inter_topology_hook;
+struct ospf6_hook_master route_hook;
+struct ospf6_hook_master redistribute_hook;
+
+static struct ospf6_hook *
+ospf6_hook_create ()
+{
+ struct ospf6_hook *new;
+ new = XMALLOC (MTYPE_OSPF6_OTHER, sizeof (struct ospf6_hook));
+ if (new == NULL)
+ return NULL;
+ memset (new, 0, sizeof (struct ospf6_hook));
+ return new;
+}
+
+static void
+ospf6_hook_delete (struct ospf6_hook *hook)
+{
+ XFREE (MTYPE_OSPF6_OTHER, hook);
+}
+
+static int
+ospf6_hook_issame (struct ospf6_hook *hook1, struct ospf6_hook *hook2)
+{
+ if (hook1->name && hook2->name &&
+ strcmp (hook1->name, hook2->name) != 0)
+ return 0;
+ if (hook1->hook_add != hook2->hook_add)
+ return 0;
+ if (hook1->hook_change != hook2->hook_change)
+ return 0;
+ if (hook1->hook_remove != hook2->hook_remove)
+ return 0;
+ return 1;
+}
+
+void
+ospf6_hook_register (struct ospf6_hook *hook,
+ struct ospf6_hook_master *master)
+{
+ struct ospf6_hook *new;
+
+ new = ospf6_hook_create ();
+
+ if (hook->name)
+ new->name = strdup (hook->name);
+ new->hook_add = hook->hook_add;
+ new->hook_change = hook->hook_change;
+ new->hook_remove = hook->hook_remove;
+
+ new->prev = master->tail;
+ if (master->tail)
+ master->tail->next = new;
+
+ master->tail = new;
+ if (! master->head)
+ master->head = new;
+
+ master->count++;
+
+ if (IS_OSPF6_DUMP_HOOK)
+ {
+ zlog_info ("HOOK: Register hook%s%s%s%s",
+ (hook->name ? " " : ""),
+ (hook->name ? hook->name : ""),
+ (master->name ? " to " : ""),
+ (master->name ? master->name : ""));
+ }
+}
+
+void
+ospf6_hook_unregister (struct ospf6_hook *req,
+ struct ospf6_hook_master *master)
+{
+ struct ospf6_hook *hook;
+
+ for (hook = master->head; hook; hook = hook->next)
+ {
+ if (ospf6_hook_issame (hook, req))
+ break;
+ }
+ if (! hook)
+ return;
+
+ if (hook->prev)
+ hook->prev->next = hook->next;
+ if (hook->next)
+ hook->next->prev = hook->prev;
+ if (master->head == hook)
+ master->head = hook->next;
+ if (master->tail == hook)
+ master->tail = hook->prev;
+
+ master->count--;
+
+ if (IS_OSPF6_DUMP_HOOK)
+ {
+ zlog_info ("HOOK: Unregister hook%s%s%s%s",
+ (hook->name ? " " : ""),
+ (hook->name ? hook->name : ""),
+ (master->name ? " to " : ""),
+ (master->name ? master->name : ""));
+ }
+
+ if (hook->name)
+ free (hook->name);
+ ospf6_hook_delete (hook);
+}
+
+void
+ospf6_hook_unregister_all (struct ospf6_hook_master *master)
+{
+ struct ospf6_hook *hook, *next;
+
+ for (hook = master->head; hook; hook = next)
+ {
+ next = hook->next;
+ ospf6_hook_delete (hook);
+ }
+
+ master->head = NULL;
+ master->tail = NULL;
+ master->count = 0;
+}
+
+
+void
+ospf6_hook_init ()
+{
+ neighbor_hook.name = "Neighbor Hooklist";
+ interface_hook.name = "Interface Hooklist";
+ area_hook.name = "Area Hooklist";
+ top_hook.name = "Top Hooklist";
+ database_hook.name = "Database Hooklist";
+ intra_topology_hook.name = "IntraTopology Hooklist";
+ inter_topology_hook.name = "InterTopology Hooklist";
+ route_hook.name = "Route Hooklist";
+}
+
+
diff --git a/ospf6d/ospf6_hook.h b/ospf6d/ospf6_hook.h
new file mode 100644
index 00000000..fa882a53
--- /dev/null
+++ b/ospf6d/ospf6_hook.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2001 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef OSPF6_HOOK_H
+#define OSPF6_HOOK_H
+
+#include "ospf6_dump.h"
+
+struct ospf6_hook
+{
+ struct ospf6_hook *prev;
+ struct ospf6_hook *next;
+
+ char *name;
+ int (*hook_add) (void *);
+ int (*hook_change) (void *);
+ int (*hook_remove) (void *);
+};
+
+struct ospf6_hook_master
+{
+ char *name;
+ struct ospf6_hook *head;
+ struct ospf6_hook *tail;
+ int count;
+};
+
+#define CALL_HOOKS(master,hookname,hookstr,data) \
+ {\
+ struct ospf6_hook *hook;\
+ for (hook = (master)->head; hook; hook = hook->next)\
+ {\
+ if (hook->hookname)\
+ {\
+ if (IS_OSPF6_DUMP_HOOK)\
+ zlog_info ("HOOK: Call %s hook: %s", (hookstr), hook->name);\
+ (*(hook->hookname)) (data);\
+ }\
+ }\
+ }
+#define CALL_ADD_HOOK(master,data) \
+ { CALL_HOOKS ((master), hook_add, "ADD", (data)) }
+#define CALL_CHANGE_HOOK(master,data) \
+ { CALL_HOOKS ((master), hook_change, "CHANGE", (data)) }
+#define CALL_REMOVE_HOOK(master,data) \
+ { CALL_HOOKS ((master), hook_remove, "REMOVE", (data)) }
+
+#define IS_HOOK_SET(hook) \
+ ((hook)->hook_add || (hook)->hook_change || (hook)->hook_remove)
+
+extern struct ospf6_hook_master neighbor_hook;
+extern struct ospf6_hook_master interface_hook;
+extern struct ospf6_hook_master area_hook;
+extern struct ospf6_hook_master top_hook;
+extern struct ospf6_hook_master database_hook;
+extern struct ospf6_hook_master intra_topology_hook;
+extern struct ospf6_hook_master inter_topology_hook;
+extern struct ospf6_hook_master route_hook;
+extern struct ospf6_hook_master redistribute_hook;
+
+void ospf6_hook_register (struct ospf6_hook *,
+ struct ospf6_hook_master *);
+void ospf6_hook_unregister (struct ospf6_hook *,
+ struct ospf6_hook_master *);
+void ospf6_hook_unregister_all (struct ospf6_hook_master *);
+void ospf6_hook_init ();
+
+#endif /*OSPF6_HOOK_H*/
+
diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c
new file mode 100644
index 00000000..d394f21b
--- /dev/null
+++ b/ospf6d/ospf6_interface.c
@@ -0,0 +1,1028 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "ospf6d.h"
+
+#include "if.h"
+#include "log.h"
+#include "command.h"
+
+#include "ospf6_lsdb.h"
+
+#include "ospf6_top.h"
+#include "ospf6_area.h"
+#include "ospf6_interface.h"
+
+char *ospf6_interface_state_string[] =
+{
+ "None", "Down", "Loopback", "Waiting", "PointToPoint",
+ "DROther", "BDR", "DR", NULL
+};
+
+static void
+ospf6_interface_foreach_neighbor (struct ospf6_interface *o6i,
+ void *arg, int val,
+ void (*func) (void *, int, void *))
+{
+ listnode node;
+ struct ospf6_neighbor *nei;
+
+ for (node = listhead (o6i->neighbor_list); node; nextnode (node))
+ {
+ nei = (struct ospf6_neighbor *) getdata (node);
+ (*func) (arg, val, nei);
+ }
+}
+
+static int
+ospf6_interface_maxage_remover (struct thread *t)
+{
+ int count;
+ struct ospf6_interface *o6i = (struct ospf6_interface *) THREAD_ARG (t);
+
+ o6i->maxage_remover = (struct thread *) NULL;
+
+ count = 0;
+ o6i->foreach_nei (o6i, &count, NBS_EXCHANGE, ospf6_count_state);
+ o6i->foreach_nei (o6i, &count, NBS_LOADING, ospf6_count_state);
+ if (count != 0)
+ return 0;
+
+ ospf6_lsdb_remove_maxage (o6i->lsdb);
+ return 0;
+}
+
+void
+ospf6_interface_schedule_maxage_remover (void *arg, int val, void *obj)
+{
+ struct ospf6_interface *o6i = (struct ospf6_interface *) obj;
+
+ if (o6i->maxage_remover != NULL)
+ return;
+
+ o6i->maxage_remover =
+ thread_add_event (master, ospf6_interface_maxage_remover, o6i, 0);
+}
+
+/* Create new ospf6 interface structure */
+struct ospf6_interface *
+ospf6_interface_create (struct interface *ifp)
+{
+ struct ospf6_interface *o6i;
+
+ o6i = (struct ospf6_interface *)
+ XMALLOC (MTYPE_OSPF6_IF, sizeof (struct ospf6_interface));
+
+ if (o6i)
+ memset (o6i, 0, sizeof (struct ospf6_interface));
+ else
+ {
+ zlog_err ("Can't malloc ospf6_interface for ifindex %d", ifp->ifindex);
+ return (struct ospf6_interface *) NULL;
+ }
+
+ o6i->instance_id = 0;
+ o6i->if_id = ifp->ifindex;
+ o6i->lladdr = (struct in6_addr *) NULL;
+ o6i->area = (struct ospf6_area *) NULL;
+ o6i->state = IFS_DOWN;
+ o6i->flag = 0;
+ o6i->neighbor_list = list_new ();
+
+ o6i->ack_list = ospf6_lsdb_create ();
+ o6i->lsdb = ospf6_lsdb_create ();
+
+ o6i->transdelay = 1;
+ o6i->priority = 1;
+ o6i->hello_interval = 10;
+ o6i->dead_interval = 40;
+ o6i->rxmt_interval = 5;
+ o6i->cost = 1;
+ o6i->ifmtu = 1280;
+
+ o6i->foreach_nei = ospf6_interface_foreach_neighbor;
+
+ /* link both */
+ o6i->interface = ifp;
+ ifp->info = o6i;
+
+ CALL_ADD_HOOK (&interface_hook, o6i);
+
+ /* Get the interface's link-local if any */
+ ospf6_interface_address_update(ifp);
+
+ return o6i;
+}
+
+void
+ospf6_interface_delete (struct ospf6_interface *o6i)
+{
+ listnode n;
+ struct ospf6_neighbor *o6n;
+
+ CALL_REMOVE_HOOK (&interface_hook, o6i);
+
+ for (n = listhead (o6i->neighbor_list); n; nextnode (n))
+ {
+ o6n = (struct ospf6_neighbor *) getdata (n);
+ ospf6_neighbor_delete (o6n);
+ }
+ list_delete (o6i->neighbor_list);
+
+ if (o6i->thread_send_hello)
+ {
+ thread_cancel (o6i->thread_send_hello);
+ o6i->thread_send_hello = NULL;
+ }
+ if (o6i->thread_send_lsack_delayed)
+ {
+ thread_cancel (o6i->thread_send_lsack_delayed);
+ o6i->thread_send_lsack_delayed = NULL;
+ }
+
+ ospf6_lsdb_delete (o6i->ack_list);
+ ospf6_lsdb_remove_all (o6i->lsdb);
+ ospf6_lsdb_delete (o6i->lsdb);
+
+ /* cut link */
+ o6i->interface->info = NULL;
+
+ /* plist_name */
+ if (o6i->plist_name)
+ XFREE (MTYPE_PREFIX_LIST_STR, o6i->plist_name);
+
+ XFREE (MTYPE_OSPF6_IF, o6i);
+}
+
+static struct in6_addr *
+ospf6_interface_update_linklocal_address (struct interface *ifp)
+{
+ listnode n;
+ struct connected *c;
+ struct in6_addr *l = (struct in6_addr *) NULL;
+
+ /* for each connected address */
+ for (n = listhead (ifp->connected); n; nextnode (n))
+ {
+ c = (struct connected *) getdata (n);
+
+ /* if family not AF_INET6, ignore */
+ if (c->address->family != AF_INET6)
+ continue;
+
+ /* linklocal scope check */
+ if (IN6_IS_ADDR_LINKLOCAL (&c->address->u.prefix6))
+ l = &c->address->u.prefix6;
+ }
+ return l;
+}
+
+void
+ospf6_interface_if_add (struct interface *ifp)
+{
+ struct ospf6_interface *o6i;
+
+ o6i = (struct ospf6_interface *) ifp->info;
+ if (!o6i)
+ return;
+
+ o6i->if_id = ifp->ifindex;
+
+ ospf6_interface_address_update (ifp);
+
+ /* interface start */
+ if (o6i->area)
+ thread_add_event (master, interface_up, o6i, 0);
+}
+
+void
+ospf6_interface_if_del (struct interface *ifp)
+{
+ struct ospf6_interface *o6i;
+
+ o6i = (struct ospf6_interface *) ifp->info;
+ if (!o6i)
+ return;
+
+ /* interface stop */
+ if (o6i->area)
+ thread_execute (master, interface_down, o6i, 0);
+
+ listnode_delete (o6i->area->if_list, o6i);
+ o6i->area = (struct ospf6_area *) NULL;
+
+ /* cut link */
+ o6i->interface = NULL;
+ ifp->info = NULL;
+
+ ospf6_interface_delete (o6i);
+}
+
+void
+ospf6_interface_state_update (struct interface *ifp)
+{
+ struct ospf6_interface *o6i;
+
+ o6i = (struct ospf6_interface *) ifp->info;
+ if (! o6i)
+ return;
+ if (! o6i->area)
+ return;
+
+ if (if_is_up (ifp))
+ thread_add_event (master, interface_up, o6i, 0);
+ else
+ thread_add_event (master, interface_down, o6i, 0);
+
+ return;
+}
+
+void
+ospf6_interface_address_update (struct interface *ifp)
+{
+ struct ospf6_interface *o6i;
+
+ o6i = (struct ospf6_interface *) ifp->info;
+ if (! o6i)
+ return;
+
+ /* reset linklocal pointer */
+ o6i->lladdr = ospf6_interface_update_linklocal_address (ifp);
+
+ /* if area is null, can't make link-lsa */
+ if (! o6i->area)
+ return;
+
+ /* create new Link-LSA */
+ CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, o6i);
+
+ CALL_CHANGE_HOOK (&interface_hook, o6i);
+}
+
+struct ospf6_interface *
+ospf6_interface_lookup_by_index (int ifindex)
+{
+ struct ospf6_interface *o6i;
+ struct interface *ifp;
+
+ ifp = if_lookup_by_index (ifindex);
+
+ if (! ifp)
+ return (struct ospf6_interface *) NULL;
+
+ o6i = (struct ospf6_interface *) ifp->info;
+ return o6i;
+}
+
+struct ospf6_interface *
+ospf6_interface_lookup_by_name (char *ifname)
+{
+ struct ospf6_interface *o6i;
+ struct interface *ifp;
+
+ ifp = if_lookup_by_name (ifname);
+
+ if (! ifp)
+ return (struct ospf6_interface *) NULL;
+
+ o6i = (struct ospf6_interface *) ifp->info;
+ return o6i;
+}
+
+int
+ospf6_interface_count_neighbor_in_state (u_char state,
+ struct ospf6_interface *o6i)
+{
+ listnode n;
+ struct ospf6_neighbor *o6n;
+ int count = 0;
+
+ for (n = listhead (o6i->neighbor_list); n; nextnode (n))
+ {
+ o6n = (struct ospf6_neighbor *) getdata (n);
+ if (o6n->state == state)
+ count++;
+ }
+ return count;
+}
+
+int
+ospf6_interface_count_full_neighbor (struct ospf6_interface *o6i)
+{
+ listnode n;
+ struct ospf6_neighbor *o6n;
+ int count = 0;
+
+ for (n = listhead (o6i->neighbor_list); n; nextnode (n))
+ {
+ o6n = (struct ospf6_neighbor *) getdata (n);
+ if (o6n->state == NBS_FULL)
+ count++;
+ }
+ return count;
+}
+
+int
+ospf6_interface_is_enabled (unsigned int ifindex)
+{
+ struct ospf6_interface *o6i;
+
+ o6i = ospf6_interface_lookup_by_index (ifindex);
+ if (! o6i)
+ return 0;
+
+ if (! o6i->area)
+ return 0;
+
+ if (o6i->state <= IFS_DOWN)
+ return 0;
+
+ return 1;
+}
+
+void
+ospf6_interface_delayed_ack_add (struct ospf6_lsa *lsa,
+ struct ospf6_interface *o6i)
+{
+ struct ospf6_lsa *summary;
+ summary = ospf6_lsa_summary_create (lsa->header);
+ ospf6_lsdb_add (summary, o6i->ack_list);
+}
+
+void
+ospf6_interface_delayed_ack_remove (struct ospf6_lsa *lsa,
+ struct ospf6_interface *o6i)
+{
+ struct ospf6_lsa *summary;
+ summary = ospf6_lsdb_lookup_lsdb (lsa->header->type, lsa->header->id,
+ lsa->header->adv_router, o6i->ack_list);
+ ospf6_lsdb_remove (summary, o6i->ack_list);
+}
+
+/* show specified interface structure */
+int
+ospf6_interface_show (struct vty *vty, struct interface *iface)
+{
+ struct ospf6_interface *ospf6_interface;
+ struct connected *c;
+ struct prefix *p;
+ listnode i;
+ char strbuf[64], dr[32], bdr[32];
+ char *updown[3] = {"down", "up", NULL};
+ char *type;
+
+ /* check physical interface type */
+ if (if_is_loopback (iface))
+ type = "LOOPBACK";
+ else if (if_is_broadcast (iface))
+ type = "BROADCAST";
+ else if (if_is_pointopoint (iface))
+ type = "POINTOPOINT";
+ else
+ type = "UNKNOWN";
+
+ vty_out (vty, "%s is %s, type %s%s",
+ iface->name, updown[if_is_up (iface)], type,
+ VTY_NEWLINE);
+ vty_out (vty, " Interface ID: %d%s", iface->ifindex, VTY_NEWLINE);
+
+ if (iface->info == NULL)
+ {
+ vty_out (vty, " OSPF not enabled on this interface%s", VTY_NEWLINE);
+ return 0;
+ }
+ else
+ ospf6_interface = (struct ospf6_interface *) iface->info;
+
+ vty_out (vty, " Internet Address:%s", VTY_NEWLINE);
+ for (i = listhead (iface->connected); i; nextnode (i))
+ {
+ c = (struct connected *)getdata (i);
+ p = c->address;
+ prefix2str (p, strbuf, sizeof (strbuf));
+ switch (p->family)
+ {
+ case AF_INET:
+ vty_out (vty, " inet : %s%s", strbuf,
+ VTY_NEWLINE);
+ break;
+ case AF_INET6:
+ vty_out (vty, " inet6: %s%s", strbuf,
+ VTY_NEWLINE);
+ break;
+ default:
+ vty_out (vty, " ??? : %s%s", strbuf,
+ VTY_NEWLINE);
+ break;
+ }
+ }
+
+ if (ospf6_interface->area)
+ {
+ inet_ntop (AF_INET, &ospf6_interface->area->ospf6->router_id,
+ strbuf, sizeof (strbuf));
+ vty_out (vty, " Instance ID %d, Router ID %s%s",
+ ospf6_interface->instance_id, strbuf,
+ VTY_NEWLINE);
+ inet_ntop (AF_INET, &ospf6_interface->area->area_id,
+ strbuf, sizeof (strbuf));
+ vty_out (vty, " Area ID %s, Cost %hu%s", strbuf,
+ ospf6_interface->cost, VTY_NEWLINE);
+ }
+ else
+ vty_out (vty, " Not Attached to Area%s", VTY_NEWLINE);
+
+ vty_out (vty, " State %s, Transmit Delay %d sec, Priority %d%s",
+ ospf6_interface_state_string[ospf6_interface->state],
+ ospf6_interface->transdelay,
+ ospf6_interface->priority,
+ VTY_NEWLINE);
+ vty_out (vty, " Timer intervals configured:%s", VTY_NEWLINE);
+ vty_out (vty, " Hello %d, Dead %d, Retransmit %d%s",
+ ospf6_interface->hello_interval,
+ ospf6_interface->dead_interval,
+ ospf6_interface->rxmt_interval,
+ VTY_NEWLINE);
+
+ inet_ntop (AF_INET, &ospf6_interface->dr, dr, sizeof (dr));
+ inet_ntop (AF_INET, &ospf6_interface->bdr, bdr, sizeof (bdr));
+ vty_out (vty, " DR:%s BDR:%s%s", dr, bdr, VTY_NEWLINE);
+
+ vty_out (vty, " Number of I/F scoped LSAs is %u%s",
+ ospf6_interface->lsdb->count, VTY_NEWLINE);
+ vty_out (vty, " %-16s %5d times, %-16s %5d times%s",
+ "DRElection", ospf6_interface->ospf6_stat_dr_election,
+ "DelayedLSAck", ospf6_interface->ospf6_stat_delayed_lsack,
+ VTY_NEWLINE);
+
+ return 0;
+}
+
+void
+ospf6_interface_statistics_show (struct vty *vty, struct ospf6_interface *o6i)
+{
+ struct timeval now, uptime;
+ u_long recv_total, send_total;
+ u_long bps_total_avg, bps_tx_avg, bps_rx_avg;
+ int i;
+
+ gettimeofday (&now, (struct timezone *) NULL);
+ ospf6_timeval_sub (&now, &ospf6->starttime, &uptime);
+
+ recv_total = send_total = 0;
+ for (i = 0; i < OSPF6_MESSAGE_TYPE_MAX; i++)
+ {
+ recv_total += o6i->message_stat[i].recv_octet;
+ send_total += o6i->message_stat[i].send_octet;
+ }
+ bps_total_avg = (recv_total + send_total) * 8 / uptime.tv_sec;
+ bps_tx_avg = send_total * 8 / uptime.tv_sec;
+ bps_rx_avg = recv_total * 8 / uptime.tv_sec;
+
+ vty_out (vty, " Statistics of interface %s%s",
+ o6i->interface->name, VTY_NEWLINE);
+ vty_out (vty, " Number of Neighbor: %d%s",
+ listcount (o6i->neighbor_list), VTY_NEWLINE);
+
+ vty_out (vty, " %-8s %6s %6s %8s %8s%s",
+ "Type", "tx", "rx", "tx-byte", "rx-byte", VTY_NEWLINE);
+ for (i = 0; i < OSPF6_MESSAGE_TYPE_MAX; i++)
+ {
+ vty_out (vty, " %-8s %6d %6d %8d %8d%s",
+ ospf6_message_type_string[i],
+ o6i->message_stat[i].send,
+ o6i->message_stat[i].recv,
+ o6i->message_stat[i].send_octet,
+ o6i->message_stat[i].recv_octet,
+ VTY_NEWLINE);
+ }
+
+ vty_out (vty, " Average Link bandwidth: %ldbps"
+ " (Tx: %ldbps Rx: %ldbps)%s",
+ bps_total_avg, bps_tx_avg, bps_rx_avg, VTY_NEWLINE);
+}
+
+/* show interface */
+DEFUN (show_ipv6_ospf6_interface,
+ show_ipv6_ospf6_interface_ifname_cmd,
+ "show ipv6 ospf6 interface IFNAME",
+ SHOW_STR
+ IP6_STR
+ OSPF6_STR
+ INTERFACE_STR
+ IFNAME_STR
+ )
+{
+ struct interface *ifp;
+ listnode i;
+
+ if (argc)
+ {
+ ifp = if_lookup_by_name (argv[0]);
+ if (!ifp)
+ {
+ vty_out (vty, "No such Interface: %s%s", argv[0],
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ ospf6_interface_show (vty, ifp);
+ }
+ else
+ {
+ for (i = listhead (iflist); i; nextnode (i))
+ {
+ ifp = (struct interface *)getdata (i);
+ ospf6_interface_show (vty, ifp);
+ }
+ }
+ return CMD_SUCCESS;
+}
+
+ALIAS (show_ipv6_ospf6_interface,
+ show_ipv6_ospf6_interface_cmd,
+ "show ipv6 ospf6 interface",
+ SHOW_STR
+ IP6_STR
+ OSPF6_STR
+ INTERFACE_STR
+ )
+
+/* interface variable set command */
+DEFUN (ipv6_ospf6_cost,
+ ipv6_ospf6_cost_cmd,
+ "ipv6 ospf6 cost COST",
+ IP6_STR
+ OSPF6_STR
+ "Interface cost\n"
+ "<1-65535> Cost\n"
+ )
+{
+ struct ospf6_interface *o6i;
+ struct interface *ifp;
+
+ ifp = (struct interface *)vty->index;
+ assert (ifp);
+
+ o6i = (struct ospf6_interface *)ifp->info;
+ if (!o6i)
+ o6i = ospf6_interface_create (ifp);
+ assert (o6i);
+
+ if (o6i->cost == strtol (argv[0], NULL, 10))
+ return CMD_SUCCESS;
+
+ o6i->cost = strtol (argv[0], NULL, 10);
+
+ /* execute LSA hooks */
+ CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, o6i);
+
+ CALL_CHANGE_HOOK (&interface_hook, o6i);
+
+ return CMD_SUCCESS;
+}
+
+/* interface variable set command */
+DEFUN (ipv6_ospf6_hellointerval,
+ ipv6_ospf6_hellointerval_cmd,
+ "ipv6 ospf6 hello-interval HELLO_INTERVAL",
+ IP6_STR
+ OSPF6_STR
+ "Time between HELLO packets\n"
+ SECONDS_STR
+ )
+{
+ struct ospf6_interface *ospf6_interface;
+ struct interface *ifp;
+
+ ifp = (struct interface *) vty->index;
+ assert (ifp);
+ ospf6_interface = (struct ospf6_interface *) ifp->info;
+ if (!ospf6_interface)
+ ospf6_interface = ospf6_interface_create (ifp);
+ assert (ospf6_interface);
+
+ ospf6_interface->hello_interval = strtol (argv[0], NULL, 10);
+ return CMD_SUCCESS;
+}
+
+/* interface variable set command */
+DEFUN (ipv6_ospf6_deadinterval,
+ ipv6_ospf6_deadinterval_cmd,
+ "ipv6 ospf6 dead-interval ROUTER_DEAD_INTERVAL",
+ IP6_STR
+ OSPF6_STR
+ "Interval after which a neighbor is declared dead\n"
+ SECONDS_STR
+ )
+{
+ struct ospf6_interface *ospf6_interface;
+ struct interface *ifp;
+
+ ifp = (struct interface *) vty->index;
+ assert (ifp);
+ ospf6_interface = (struct ospf6_interface *) ifp->info;
+ if (!ospf6_interface)
+ ospf6_interface = ospf6_interface_create (ifp);
+ assert (ospf6_interface);
+
+ ospf6_interface->dead_interval = strtol (argv[0], NULL, 10);
+ return CMD_SUCCESS;
+}
+
+/* interface variable set command */
+DEFUN (ipv6_ospf6_transmitdelay,
+ ipv6_ospf6_transmitdelay_cmd,
+ "ipv6 ospf6 transmit-delay TRANSMITDELAY",
+ IP6_STR
+ OSPF6_STR
+ "Link state transmit delay\n"
+ SECONDS_STR
+ )
+{
+ struct ospf6_interface *ospf6_interface;
+ struct interface *ifp;
+
+ ifp = (struct interface *) vty->index;
+ assert (ifp);
+ ospf6_interface = (struct ospf6_interface *) ifp->info;
+ if (!ospf6_interface)
+ ospf6_interface = ospf6_interface_create (ifp);
+ assert (ospf6_interface);
+
+ ospf6_interface->transdelay = strtol (argv[0], NULL, 10);
+ return CMD_SUCCESS;
+}
+
+/* interface variable set command */
+DEFUN (ipv6_ospf6_retransmitinterval,
+ ipv6_ospf6_retransmitinterval_cmd,
+ "ipv6 ospf6 retransmit-interval RXMTINTERVAL",
+ IP6_STR
+ OSPF6_STR
+ "Time between retransmitting lost link state advertisements\n"
+ SECONDS_STR
+ )
+{
+ struct ospf6_interface *ospf6_interface;
+ struct interface *ifp;
+
+ ifp = (struct interface *) vty->index;
+ assert (ifp);
+ ospf6_interface = (struct ospf6_interface *) ifp->info;
+ if (!ospf6_interface)
+ ospf6_interface = ospf6_interface_create (ifp);
+ assert (ospf6_interface);
+
+ ospf6_interface->rxmt_interval = strtol (argv[0], NULL, 10);
+ return CMD_SUCCESS;
+}
+
+/* interface variable set command */
+DEFUN (ipv6_ospf6_priority,
+ ipv6_ospf6_priority_cmd,
+ "ipv6 ospf6 priority PRIORITY",
+ IP6_STR
+ OSPF6_STR
+ "Router priority\n"
+ "<0-255> Priority\n"
+ )
+{
+ struct ospf6_interface *ospf6_interface;
+ struct interface *ifp;
+
+ ifp = (struct interface *) vty->index;
+ assert (ifp);
+ ospf6_interface = (struct ospf6_interface *) ifp->info;
+ if (!ospf6_interface)
+ ospf6_interface = ospf6_interface_create (ifp);
+ assert (ospf6_interface);
+
+ ospf6_interface->priority = strtol (argv[0], NULL, 10);
+
+ if (ospf6_interface->area)
+ ifs_change (dr_election (ospf6_interface), "Priority reconfigured",
+ ospf6_interface);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (ipv6_ospf6_instance,
+ ipv6_ospf6_instance_cmd,
+ "ipv6 ospf6 instance-id INSTANCE",
+ IP6_STR
+ OSPF6_STR
+ "Instance ID\n"
+ "<0-255> Instance ID\n"
+ )
+{
+ struct ospf6_interface *ospf6_interface;
+ struct interface *ifp;
+
+ ifp = (struct interface *)vty->index;
+ assert (ifp);
+
+ ospf6_interface = (struct ospf6_interface *)ifp->info;
+ if (!ospf6_interface)
+ ospf6_interface = ospf6_interface_create (ifp);
+ assert (ospf6_interface);
+
+ ospf6_interface->instance_id = strtol (argv[0], NULL, 10);
+ return CMD_SUCCESS;
+}
+
+DEFUN (ipv6_ospf6_passive,
+ ipv6_ospf6_passive_cmd,
+ "ipv6 ospf6 passive",
+ IP6_STR
+ OSPF6_STR
+ "passive interface: No Adjacency will be formed on this I/F\n"
+ )
+{
+ struct ospf6_interface *o6i;
+ struct interface *ifp;
+ listnode node;
+ struct ospf6_neighbor *o6n;
+
+ ifp = (struct interface *) vty->index;
+ assert (ifp);
+ o6i = (struct ospf6_interface *) ifp->info;
+ if (! o6i)
+ o6i = ospf6_interface_create (ifp);
+ assert (o6i);
+
+ SET_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_PASSIVE);
+ if (o6i->thread_send_hello)
+ {
+ thread_cancel (o6i->thread_send_hello);
+ o6i->thread_send_hello = (struct thread *) NULL;
+ }
+
+ for (node = listhead (o6i->neighbor_list); node; nextnode (node))
+ {
+ o6n = getdata (node);
+ if (o6n->inactivity_timer)
+ thread_cancel (o6n->inactivity_timer);
+ thread_execute (master, inactivity_timer, o6n, 0);
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_ospf6_passive,
+ no_ipv6_ospf6_passive_cmd,
+ "no ipv6 ospf6 passive",
+ NO_STR
+ IP6_STR
+ OSPF6_STR
+ "passive interface: No Adjacency will be formed on this I/F\n"
+ )
+{
+ struct ospf6_interface *o6i;
+ struct interface *ifp;
+
+ ifp = (struct interface *) vty->index;
+ assert (ifp);
+ o6i = (struct ospf6_interface *) ifp->info;
+ if (! o6i)
+ o6i = ospf6_interface_create (ifp);
+ assert (o6i);
+
+ UNSET_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_PASSIVE);
+ if (o6i->thread_send_hello == NULL)
+ thread_add_event (master, ospf6_send_hello, o6i, 0);
+
+ return CMD_SUCCESS;
+}
+
+
+DEFUN (ipv6_ospf6_advertise_force_prefix,
+ ipv6_ospf6_advertise_force_prefix_cmd,
+ "ipv6 ospf6 advertise force-prefix",
+ IP6_STR
+ OSPF6_STR
+ "Advertising options\n"
+ "Force advertising prefix, applicable if Loopback or P-to-P\n"
+ )
+{
+ struct ospf6_interface *o6i;
+ struct interface *ifp;
+
+ ifp = (struct interface *) vty->index;
+ assert (ifp);
+ o6i = (struct ospf6_interface *) ifp->info;
+ if (! o6i)
+ o6i = ospf6_interface_create (ifp);
+ assert (o6i);
+
+ if (! if_is_loopback (ifp) && ! if_is_pointopoint (ifp))
+ {
+ vty_out (vty, "Interface not Loopback nor PointToPoint%s",
+ VTY_NEWLINE);
+ return CMD_ERR_NOTHING_TODO;
+ }
+
+ SET_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_FORCE_PREFIX);
+
+ /* execute LSA hooks */
+ CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, o6i);
+
+ CALL_CHANGE_HOOK (&interface_hook, o6i);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_ospf6_advertise_force_prefix,
+ no_ipv6_ospf6_advertise_force_prefix_cmd,
+ "no ipv6 ospf6 advertise force-prefix",
+ NO_STR
+ IP6_STR
+ OSPF6_STR
+ "Advertising options\n"
+ "Force to advertise prefix, applicable if Loopback or P-to-P\n"
+ )
+{
+ struct ospf6_interface *o6i;
+ struct interface *ifp;
+
+ ifp = (struct interface *) vty->index;
+ assert (ifp);
+ o6i = (struct ospf6_interface *) ifp->info;
+ if (! o6i)
+ o6i = ospf6_interface_create (ifp);
+ assert (o6i);
+
+ UNSET_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_FORCE_PREFIX);
+
+ /* execute LSA hooks */
+ CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, o6i);
+
+ CALL_CHANGE_HOOK (&interface_hook, o6i);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (ipv6_ospf6_advertise_prefix_list,
+ ipv6_ospf6_advertise_prefix_list_cmd,
+ "ipv6 ospf6 advertise prefix-list WORD",
+ IP6_STR
+ OSPF6_STR
+ "Advertising options\n"
+ "Filter prefix using prefix-list\n"
+ "Prefix list name\n"
+ )
+{
+ struct ospf6_interface *o6i;
+ struct interface *ifp;
+
+ ifp = (struct interface *) vty->index;
+ assert (ifp);
+ o6i = (struct ospf6_interface *) ifp->info;
+ if (! o6i)
+ o6i = ospf6_interface_create (ifp);
+ assert (o6i);
+
+ if (o6i->plist_name)
+ XFREE (MTYPE_PREFIX_LIST_STR, o6i->plist_name);
+ o6i->plist_name = XSTRDUP (MTYPE_PREFIX_LIST_STR, argv[0]);
+
+ /* execute LSA hooks */
+ CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, o6i);
+
+ CALL_CHANGE_HOOK (&interface_hook, o6i);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_ospf6_advertise_prefix_list,
+ no_ipv6_ospf6_advertise_prefix_list_cmd,
+ "no ipv6 ospf6 advertise prefix-list",
+ NO_STR
+ IP6_STR
+ OSPF6_STR
+ "Advertising options\n"
+ "Filter prefix using prefix-list\n"
+ )
+{
+ struct ospf6_interface *o6i;
+ struct interface *ifp;
+
+ ifp = (struct interface *) vty->index;
+ assert (ifp);
+ o6i = (struct ospf6_interface *) ifp->info;
+ if (! o6i)
+ o6i = ospf6_interface_create (ifp);
+ assert (o6i);
+
+ if (o6i->plist_name)
+ {
+ XFREE (MTYPE_PREFIX_LIST_STR, o6i->plist_name);
+ o6i->plist_name = NULL;
+ }
+
+ /* execute LSA hooks */
+ CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, o6i);
+
+ CALL_CHANGE_HOOK (&interface_hook, o6i);
+
+ return CMD_SUCCESS;
+}
+
+int
+ospf6_interface_config_write (struct vty *vty)
+{
+ listnode i;
+ struct ospf6_interface *o6i;
+ struct interface *ifp;
+
+ for (i = listhead (iflist); i; nextnode (i))
+ {
+ ifp = (struct interface *) getdata (i);
+ o6i = (struct ospf6_interface *) ifp->info;
+ if (! o6i)
+ continue;
+
+ vty_out (vty, "interface %s%s",
+ o6i->interface->name, VTY_NEWLINE);
+ vty_out (vty, " ipv6 ospf6 cost %d%s",
+ o6i->cost, VTY_NEWLINE);
+ vty_out (vty, " ipv6 ospf6 hello-interval %d%s",
+ o6i->hello_interval, VTY_NEWLINE);
+ vty_out (vty, " ipv6 ospf6 dead-interval %d%s",
+ o6i->dead_interval, VTY_NEWLINE);
+ vty_out (vty, " ipv6 ospf6 retransmit-interval %d%s",
+ o6i->rxmt_interval, VTY_NEWLINE);
+ vty_out (vty, " ipv6 ospf6 priority %d%s",
+ o6i->priority, VTY_NEWLINE);
+ vty_out (vty, " ipv6 ospf6 transmit-delay %d%s",
+ o6i->transdelay, VTY_NEWLINE);
+ vty_out (vty, " ipv6 ospf6 instance-id %d%s",
+ o6i->instance_id, VTY_NEWLINE);
+
+ if (CHECK_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_FORCE_PREFIX))
+ vty_out (vty, " ipv6 ospf6 advertise force-prefix%s", VTY_NEWLINE);
+ if (o6i->plist_name)
+ vty_out (vty, " ipv6 ospf6 advertise prefix-list %s%s",
+ o6i->plist_name, VTY_NEWLINE);
+
+ if (CHECK_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_PASSIVE))
+ vty_out (vty, " ipv6 ospf6 passive%s", VTY_NEWLINE);
+
+ vty_out (vty, "!%s", VTY_NEWLINE);
+ }
+ return 0;
+}
+
+struct cmd_node interface_node =
+{
+ INTERFACE_NODE,
+ "%s(config-if)# ",
+};
+
+void
+ospf6_interface_init ()
+{
+ /* Install interface node. */
+ install_node (&interface_node, ospf6_interface_config_write);
+
+ install_element (VIEW_NODE, &show_ipv6_ospf6_interface_cmd);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_interface_ifname_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_ifname_cmd);
+
+ install_default (INTERFACE_NODE);
+ install_element (INTERFACE_NODE, &interface_desc_cmd);
+ install_element (INTERFACE_NODE, &no_interface_desc_cmd);
+ install_element (INTERFACE_NODE, &ipv6_ospf6_cost_cmd);
+ install_element (INTERFACE_NODE, &ipv6_ospf6_deadinterval_cmd);
+ install_element (INTERFACE_NODE, &ipv6_ospf6_hellointerval_cmd);
+ install_element (INTERFACE_NODE, &ipv6_ospf6_priority_cmd);
+ install_element (INTERFACE_NODE, &ipv6_ospf6_retransmitinterval_cmd);
+ install_element (INTERFACE_NODE, &ipv6_ospf6_transmitdelay_cmd);
+ install_element (INTERFACE_NODE, &ipv6_ospf6_instance_cmd);
+ install_element (INTERFACE_NODE, &ipv6_ospf6_advertise_force_prefix_cmd);
+ install_element (INTERFACE_NODE, &no_ipv6_ospf6_advertise_force_prefix_cmd);
+ install_element (INTERFACE_NODE, &ipv6_ospf6_advertise_prefix_list_cmd);
+ install_element (INTERFACE_NODE, &no_ipv6_ospf6_advertise_prefix_list_cmd);
+ install_element (INTERFACE_NODE, &ipv6_ospf6_passive_cmd);
+ install_element (INTERFACE_NODE, &no_ipv6_ospf6_passive_cmd);
+}
+
+
diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h
new file mode 100644
index 00000000..a96ef25a
--- /dev/null
+++ b/ospf6d/ospf6_interface.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef OSPF6_INTERFACE_H
+#define OSPF6_INTERFACE_H
+
+#include "ospf6_message.h"
+
+/* This file defines interface data structure. */
+
+struct ospf6_interface
+{
+ /* IF info from zebra */
+ struct interface *interface;
+
+ /* back pointer */
+ struct ospf6_area *area;
+
+ /* list of ospf6 neighbor */
+ list neighbor_list;
+
+ /* linklocal address of this I/F */
+ struct in6_addr *lladdr;
+
+ /* Interface ID; same as ifindex */
+ u_int32_t if_id;
+
+ /* ospf6 instance id */
+ u_char instance_id;
+
+ /* I/F transmission delay */
+ u_int32_t transdelay;
+
+ /* Router Priority */
+ u_char priority;
+
+ /* Timers */
+ u_int16_t hello_interval;
+ u_int16_t dead_interval;
+ u_int32_t rxmt_interval;
+
+ /* Cost */
+ u_int32_t cost;
+
+ /* I/F MTU */
+ u_int32_t ifmtu;
+
+ /* Interface State */
+ u_char state;
+
+ /* OSPF6 Interface flag */
+ char flag;
+
+ /* Decision of DR Election */
+ u_int32_t dr;
+ u_int32_t bdr;
+ u_int32_t prevdr;
+ u_int32_t prevbdr;
+
+ /* Ongoing Tasks */
+ struct thread *thread_send_hello;
+ struct thread *thread_send_lsack_delayed;
+
+ /* LSAs to Delayed Acknowledge */
+ struct ospf6_lsdb *ack_list;
+
+ /* Linklocal LSA Database: includes Link-LSA */
+ struct ospf6_lsdb *lsdb;
+
+ /* statistics */
+ u_int ospf6_stat_dr_election;
+ u_int ospf6_stat_delayed_lsack;
+
+ struct ospf6_message_stat message_stat[OSPF6_MESSAGE_TYPE_MAX];
+
+ void (*foreach_nei) (struct ospf6_interface *, void *, int,
+ void (*func) (void *, int, void *));
+
+ struct thread *maxage_remover;
+
+ /* route-map to filter connected prefix */
+ char *plist_name;
+};
+
+extern char *ospf6_interface_state_string[];
+
+#define OSPF6_INTERFACE_FLAG_PASSIVE 0x01
+#define OSPF6_INTERFACE_FLAG_FORCE_PREFIX 0x02
+
+
+/* Function Prototypes */
+
+void
+ospf6_interface_schedule_maxage_remover (void *arg, int val, void *obj);
+
+struct ospf6_interface *
+ospf6_interface_create (struct interface *);
+void
+ospf6_interface_delete (struct ospf6_interface *);
+
+struct ospf6_interface *
+ospf6_interface_lookup_by_index (int);
+struct ospf6_interface *
+ospf6_interface_lookup_by_name (char *);
+
+void ospf6_interface_if_add (struct interface *);
+void ospf6_interface_if_del (struct interface *);
+void ospf6_interface_state_update (struct interface *);
+void ospf6_interface_address_update (struct interface *);
+
+void ospf6_interface_init ();
+
+#if 0
+int
+ospf6_interface_count_neighbor_in_state (u_char state,
+ struct ospf6_interface *o6i);
+int
+ospf6_interface_count_full_neighbor (struct ospf6_interface *);
+#endif
+
+int ospf6_interface_is_enabled (u_int32_t ifindex);
+
+void
+ospf6_interface_delayed_ack_add (struct ospf6_lsa *lsa,
+ struct ospf6_interface *o6i);
+void
+ospf6_interface_delayed_ack_remove (struct ospf6_lsa *lsa,
+ struct ospf6_interface *o6i);
+
+void
+ospf6_interface_statistics_show (struct vty *vty,
+ struct ospf6_interface *o6i);
+
+#endif /* OSPF6_INTERFACE_H */
+
diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c
new file mode 100644
index 00000000..b9c9ebd0
--- /dev/null
+++ b/ospf6d/ospf6_intra.c
@@ -0,0 +1,896 @@
+/*
+ * Copyright (C) 2002 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "ospf6d.h"
+
+static int intra_index;
+#define IS_OSPF6_DUMP_INTRA (ospf6_dump_is_on (intra_index))
+
+#define ADD 0
+#define REMOVE 1
+
+static void
+ospf6_intra_route_calculate (int type, struct ospf6_lsa *lsa,
+ struct ospf6_route_req *topo_entry)
+{
+ struct ospf6_intra_area_prefix_lsa *intra_prefix;
+ char *start, *end;
+ struct ospf6_prefix *ospf6_prefix;
+ struct ospf6_route_req request;
+ struct ospf6_area *area;
+
+ if (IS_OSPF6_DUMP_INTRA)
+ {
+ char buf[64];
+ struct prefix_ls *p_ls;
+ p_ls = (struct prefix_ls *) &topo_entry->route.prefix;
+ inet_ntop (AF_INET, &p_ls->adv_router, buf, sizeof (buf));
+ zlog_info ("INTRA: Calculate [%s] %s and %s",
+ (type == ADD ? "add" : "remove"), lsa->str, buf);
+ }
+
+ intra_prefix = OSPF6_LSA_HEADER_END (lsa->header);
+
+ area = lsa->scope;
+ assert (area);
+
+ start = (char *) (intra_prefix + 1);
+ end = (char *) lsa->header + ntohs (lsa->header->length);
+ for (ospf6_prefix = (struct ospf6_prefix *) start;
+ (char *) ospf6_prefix < end;
+ ospf6_prefix = OSPF6_NEXT_PREFIX (ospf6_prefix))
+ {
+ memset (&request, 0, sizeof (request));
+
+ request.route.type = OSPF6_DEST_TYPE_NETWORK;
+ request.route.prefix.family = AF_INET6;
+ request.route.prefix.prefixlen = ospf6_prefix->prefix_length;
+ ospf6_prefix_in6_addr (ospf6_prefix, &request.route.prefix.u.prefix6);
+
+ request.path.type = OSPF6_PATH_TYPE_INTRA;
+ request.path.area_id = area->area_id;
+ request.path.origin.type = lsa->header->type;
+ request.path.origin.id = lsa->header->id;
+ request.path.origin.adv_router = lsa->header->adv_router;
+ request.path.cost = topo_entry->path.cost +
+ ntohs (ospf6_prefix->prefix_metric);
+ request.path.capability[0] = topo_entry->path.capability[0];
+ request.path.capability[1] = topo_entry->path.capability[1];
+ request.path.capability[2] = topo_entry->path.capability[2];
+
+ memcpy (&request.nexthop.address, &topo_entry->nexthop.address,
+ sizeof (request.nexthop.address));
+ request.nexthop.ifindex = topo_entry->nexthop.ifindex;
+
+ if (type == ADD)
+ ospf6_route_add (&request, area->route_table);
+ else if (type == REMOVE)
+ ospf6_route_remove (&request, area->route_table);
+ else
+ assert (0);
+ }
+}
+
+int
+ospf6_intra_prefix_database_hook_remove (void *data)
+{
+ struct ospf6_lsa *lsa = data;
+ struct ospf6_area *area;
+ struct ospf6_intra_area_prefix_lsa *iap;
+ struct prefix_ls prefix_ls;
+ struct ospf6_route_req topo_entry;
+
+ if (lsa->header->type != htons (OSPF6_LSA_TYPE_INTRA_PREFIX))
+ return 0;
+
+ area = (struct ospf6_area *) lsa->scope;
+ assert (area);
+
+ if (IS_OSPF6_DUMP_INTRA)
+ zlog_info ("INTRA: area %s remove: %s", area->str, lsa->str);
+
+ iap = OSPF6_LSA_HEADER_END (lsa->header);
+ memset (&prefix_ls, 0, sizeof (prefix_ls));
+ prefix_ls.prefixlen = 64;
+ prefix_ls.adv_router.s_addr = iap->refer_advrtr;
+ prefix_ls.id.s_addr = iap->refer_lsid;
+
+ if (iap->refer_lstype == htons (OSPF6_LSA_TYPE_ROUTER) &&
+ iap->refer_lsid != htonl (0))
+ {
+ zlog_warn ("SPF: Malformed ID %lu of Router reference in %s",
+ (u_long) ntohl (iap->refer_lsid), lsa->str);
+ prefix_ls.id.s_addr = htonl (0);
+ }
+
+ ospf6_route_lookup (&topo_entry, (struct prefix *) &prefix_ls,
+ area->table_topology);
+
+ while (iap->refer_lstype == topo_entry.path.origin.type &&
+ iap->refer_lsid == topo_entry.path.origin.id &&
+ iap->refer_advrtr == topo_entry.path.origin.adv_router)
+ {
+ ospf6_intra_route_calculate (REMOVE, lsa, &topo_entry);
+ ospf6_route_next (&topo_entry);
+ }
+ return 0;
+}
+
+int
+ospf6_intra_prefix_database_hook_add (void *data)
+{
+ struct ospf6_lsa *lsa = data;
+ struct ospf6_area *area;
+ struct ospf6_intra_area_prefix_lsa *iap;
+ struct prefix_ls prefix_ls;
+ struct ospf6_route_req topo_entry;
+
+ if (lsa->header->type != htons (OSPF6_LSA_TYPE_INTRA_PREFIX))
+ return 0;
+
+ area = (struct ospf6_area *) lsa->scope;
+ assert (area);
+
+ if (IS_LSA_MAXAGE (lsa))
+ {
+ ospf6_intra_prefix_database_hook_remove (lsa);
+ return 0;
+ }
+
+ if (IS_OSPF6_DUMP_INTRA)
+ zlog_info ("INTRA: area %s add: %s", area->str, lsa->str);
+
+ iap = OSPF6_LSA_HEADER_END (lsa->header);
+
+ memset (&prefix_ls, 0, sizeof (struct prefix_ls));
+ prefix_ls.prefixlen = 64;
+ prefix_ls.adv_router.s_addr = iap->refer_advrtr;
+ prefix_ls.id.s_addr = iap->refer_lsid;
+
+ if (iap->refer_lstype == htons (OSPF6_LSA_TYPE_ROUTER) &&
+ iap->refer_lsid != htonl (0))
+ {
+ zlog_warn ("INTRA: Malformed ID %lu of Router reference in %s",
+ (u_long) ntohl (iap->refer_lsid), lsa->str);
+ prefix_ls.id.s_addr = htonl (0);
+ }
+
+ ospf6_route_lookup (&topo_entry, (struct prefix *) &prefix_ls,
+ area->table_topology);
+
+ while (iap->refer_lstype == topo_entry.path.origin.type &&
+ iap->refer_lsid == topo_entry.path.origin.id &&
+ iap->refer_advrtr == topo_entry.path.origin.adv_router)
+ {
+ ospf6_intra_route_calculate (ADD, lsa, &topo_entry);
+ ospf6_route_next (&topo_entry);
+ }
+ return 0;
+}
+
+void
+ospf6_intra_topology_add (void *data)
+{
+ struct ospf6_route_req *topo_entry = data;
+ struct ospf6_area *area;
+ struct ospf6_intra_area_prefix_lsa *iap;
+ struct ospf6_lsdb_node node;
+
+ area = ospf6_area_lookup (topo_entry->path.area_id, ospf6);
+ if (! area)
+ return;
+
+ if (topo_entry->route.type == OSPF6_DEST_TYPE_ROUTER &&
+ (CHECK_FLAG (topo_entry->path.router_bits, OSPF6_ROUTER_LSA_BIT_B) ||
+ CHECK_FLAG (topo_entry->path.router_bits, OSPF6_ROUTER_LSA_BIT_E)))
+ ospf6_route_add (topo_entry, ospf6->topology_table);
+
+ for (ospf6_lsdb_type (&node, htons (OSPF6_LSA_TYPE_INTRA_PREFIX),
+ area->lsdb);
+ ! ospf6_lsdb_is_end (&node);
+ ospf6_lsdb_next (&node))
+ {
+ if (IS_LSA_MAXAGE (node.lsa))
+ continue;
+
+ iap = OSPF6_LSA_HEADER_END (node.lsa->header);
+
+ if (iap->refer_lstype == htons (OSPF6_LSA_TYPE_ROUTER) &&
+ iap->refer_lsid != htonl (0))
+ {
+ zlog_warn ("INTRA: Malformed ID %lu of Router reference in %s",
+ (u_long) ntohl (iap->refer_lsid), node.lsa->str);
+ }
+
+ if (iap->refer_lstype != topo_entry->path.origin.type ||
+ iap->refer_lsid != topo_entry->path.origin.id ||
+ iap->refer_advrtr != topo_entry->path.origin.adv_router)
+ continue;
+
+ ospf6_intra_route_calculate (ADD, node.lsa, topo_entry);
+ }
+}
+
+void
+ospf6_intra_topology_remove (void *data)
+{
+ struct ospf6_route_req *topo_entry = data;
+ struct ospf6_area *area;
+ struct ospf6_intra_area_prefix_lsa *iap;
+ struct ospf6_lsdb_node node;
+
+ area = ospf6_area_lookup (topo_entry->path.area_id, ospf6);
+ if (! area)
+ return;
+
+ if (topo_entry->route.type == OSPF6_DEST_TYPE_ROUTER &&
+ (CHECK_FLAG (topo_entry->path.router_bits, OSPF6_ROUTER_LSA_BIT_B) ||
+ CHECK_FLAG (topo_entry->path.router_bits, OSPF6_ROUTER_LSA_BIT_E)))
+ ospf6_route_remove (topo_entry, ospf6->topology_table);
+
+ for (ospf6_lsdb_type (&node, htons (OSPF6_LSA_TYPE_INTRA_PREFIX),
+ area->lsdb);
+ ! ospf6_lsdb_is_end (&node);
+ ospf6_lsdb_next (&node))
+ {
+ if (IS_LSA_MAXAGE (node.lsa))
+ continue;
+
+ iap = OSPF6_LSA_HEADER_END (node.lsa->header);
+
+ if (iap->refer_lstype == htons (OSPF6_LSA_TYPE_ROUTER) &&
+ iap->refer_lsid != htonl (0))
+ zlog_warn ("SPF: Malformed ID %lu of Router reference in %s",
+ (u_long) ntohl (iap->refer_lsid), node.lsa->str);
+
+ if (iap->refer_lstype != topo_entry->path.origin.type ||
+ iap->refer_lsid != topo_entry->path.origin.id ||
+ iap->refer_advrtr != topo_entry->path.origin.adv_router)
+ continue;
+
+ ospf6_intra_route_calculate (REMOVE, node.lsa, topo_entry);
+ }
+}
+
+
+/*****************************************/
+/* RFC2740 3.4.3.7 Intra-Area-Prefix-LSA */
+/*****************************************/
+
+#define CONTINUE_IF_ADDRESS_LINKLOCAL(addr)\
+ if (IN6_IS_ADDR_LINKLOCAL (&(addr)->u.prefix6))\
+ {\
+ char buf[64];\
+ prefix2str (addr, buf, sizeof (buf));\
+ if (IS_OSPF6_DUMP_PREFIX)\
+ zlog_info (" Filter out Linklocal: %s", buf);\
+ continue;\
+ }
+
+#define CONTINUE_IF_ADDRESS_UNSPECIFIED(addr)\
+ if (IN6_IS_ADDR_UNSPECIFIED (&(addr)->u.prefix6))\
+ {\
+ char buf[64];\
+ prefix2str (addr, buf, sizeof (buf));\
+ if (IS_OSPF6_DUMP_PREFIX)\
+ zlog_info (" Filter out Unspecified: %s", buf);\
+ continue;\
+ }
+
+#define CONTINUE_IF_ADDRESS_LOOPBACK(addr)\
+ if (IN6_IS_ADDR_LOOPBACK (&(addr)->u.prefix6))\
+ {\
+ char buf[64];\
+ prefix2str (addr, buf, sizeof (buf));\
+ if (IS_OSPF6_DUMP_PREFIX)\
+ zlog_info (" Filter out Loopback: %s", buf);\
+ continue;\
+ }
+
+#define CONTINUE_IF_ADDRESS_V4COMPAT(addr)\
+ if (IN6_IS_ADDR_V4COMPAT (&(addr)->u.prefix6))\
+ {\
+ char buf[64];\
+ prefix2str (addr, buf, sizeof (buf));\
+ if (IS_OSPF6_DUMP_PREFIX)\
+ zlog_info (" Filter out V4Compat: %s", buf);\
+ continue;\
+ }
+
+#define CONTINUE_IF_ADDRESS_V4MAPPED(addr)\
+ if (IN6_IS_ADDR_V4MAPPED (&(addr)->u.prefix6))\
+ {\
+ char buf[64];\
+ prefix2str (addr, buf, sizeof (buf));\
+ if (IS_OSPF6_DUMP_PREFIX)\
+ zlog_info (" Filter out V4Mapped: %s", buf);\
+ continue;\
+ }
+
+
+int
+ospf6_lsa_intra_prefix_show (struct vty *vty, struct ospf6_lsa *lsa)
+{
+ struct ospf6_intra_area_prefix_lsa *iap_lsa;
+ struct ospf6_prefix *prefix;
+ unsigned short prefixnum;
+ char buf[128], type[32], id[32], adv_router[32];
+ struct in6_addr in6;
+ char *start, *end, *current;
+
+ assert (lsa->header);
+ iap_lsa = (struct ospf6_intra_area_prefix_lsa *) (lsa->header + 1);
+
+ prefixnum = ntohs (iap_lsa->prefix_number);
+ ospf6_lsa_type_string (iap_lsa->refer_lstype, type, sizeof (type));
+ inet_ntop (AF_INET, &iap_lsa->refer_lsid, id, sizeof (id));
+ inet_ntop (AF_INET, &iap_lsa->refer_advrtr, adv_router,
+ sizeof (adv_router));
+
+ vty_out (vty, " Number of Prefix: %d%s", prefixnum, VTY_NEWLINE);
+ vty_out (vty, " Referenced LS Type: %s%s", type, VTY_NEWLINE);
+ vty_out (vty, " Referenced LS ID: %s%s", id, VTY_NEWLINE);
+ vty_out (vty, " Referenced Advertising Router: %s%s", adv_router,
+ VTY_NEWLINE);
+
+ start = (char *) lsa->header + sizeof (struct ospf6_lsa_header)
+ + sizeof (struct ospf6_intra_area_prefix_lsa);
+ end = (char *) lsa->header + ntohs (lsa->header->length);
+
+ for (current = start; current < end; current += OSPF6_PREFIX_SIZE (prefix))
+ {
+ prefix = (struct ospf6_prefix *) current;
+ if (current + OSPF6_PREFIX_SIZE (prefix) > end)
+ {
+ vty_out (vty, " Trailing %d byte garbage ... Malformed%s",
+ end - current, VTY_NEWLINE);
+ return -1;
+ }
+
+ ospf6_prefix_options_str (prefix->prefix_options, buf, sizeof (buf));
+ vty_out (vty, " Prefix Options: %s%s", buf, VTY_NEWLINE);
+
+ ospf6_prefix_in6_addr (prefix, &in6);
+ inet_ntop (AF_INET6, &in6, buf, sizeof (buf));
+ vty_out (vty, " Prefix: %s/%d%s",
+ buf, prefix->prefix_length, VTY_NEWLINE);
+ }
+
+ return 0;
+}
+
+void
+ospf6_lsa_intra_prefix_update_transit (char *ifname)
+{
+ char buffer [MAXLSASIZE];
+ u_int16_t size;
+ struct ospf6_lsa *old;
+ struct interface *ifp;
+ struct ospf6_interface *o6i;
+ struct ospf6_neighbor *o6n;
+
+ struct ospf6_intra_area_prefix_lsa *iap;
+ struct ospf6_lsdb_node n;
+ listnode node;
+ char *start, *end, *current;
+ struct ospf6_prefix *prefix, *dup, *src, *dst;
+ struct ospf6_link_lsa *link;
+ char buf[128];
+ int count, prefix_num;
+
+ list adv_list;
+
+ ifp = if_lookup_by_name (ifname);
+ if (! ifp)
+ {
+ zlog_warn ("Update Intra-Prefix (Transit): No such Interface: %s",
+ ifname);
+ return;
+ }
+
+ o6i = (struct ospf6_interface *) ifp->info;
+ if (! o6i || ! o6i->area)
+ {
+ zlog_warn ("Update Intra-Prefix (Transit): Interface not enabled: %s",
+ ifname);
+ return;
+ }
+
+ /* find previous LSA */
+ old = ospf6_lsdb_lookup (htons (OSPF6_LSA_TYPE_INTRA_PREFIX),
+ htonl (o6i->if_id), ospf6->router_id,
+ o6i->area);
+
+ /* Don't originate Network-LSA if not DR */
+ if (o6i->state != IFS_DR)
+ {
+ if (old)
+ {
+ if (IS_OSPF6_DUMP_PREFIX)
+ zlog_info ("Update Intra-Prefix (Transit): %s not DR",
+ o6i->interface->name);
+ ospf6_lsa_premature_aging (old);
+ }
+ return;
+ }
+
+ /* If none of neighbor is adjacent to us */
+ count = 0;
+ o6i->foreach_nei (o6i, &count, NBS_FULL, ospf6_count_state);
+ if (count == 0)
+ {
+ if (IS_OSPF6_DUMP_PREFIX)
+ zlog_info ("Update Intra-Prefix (Transit): %s is Stub",
+ o6i->interface->name);
+ if (old)
+ ospf6_lsa_premature_aging (old);
+ return;
+ }
+
+ if (IS_OSPF6_DUMP_PREFIX)
+ zlog_info ("Update Intra-Prefix (Transit): Interface %s",
+ o6i->interface->name);
+
+ adv_list = list_new ();
+
+ /* foreach Link-LSA associated with this Link */
+ for (ospf6_lsdb_type (&n, htons (OSPF6_LSA_TYPE_LINK), o6i->lsdb);
+ ! ospf6_lsdb_is_end (&n); ospf6_lsdb_next (&n))
+ {
+ if (IS_LSA_MAXAGE (n.lsa))
+ continue;
+
+ if (IS_OSPF6_DUMP_PREFIX)
+ zlog_info ("Update Intra-Prefix (Transit): Checking %s",
+ n.lsa->str);
+
+ /* Check status of the advertising router */
+ if (n.lsa->header->adv_router != o6i->area->ospf6->router_id)
+ {
+ o6n = ospf6_neighbor_lookup (n.lsa->header->adv_router, o6i);
+ if (! o6n)
+ {
+ if (IS_OSPF6_DUMP_PREFIX)
+ zlog_info ("Update Intra-Prefix (Transit): neighbor not found");
+ continue;
+ }
+
+ if (o6n->state != NBS_FULL)
+ {
+ if (IS_OSPF6_DUMP_PREFIX)
+ zlog_info ("Update Intra-Prefix (Transit): %s not FULL",
+ o6n->str);
+ continue;
+ }
+ }
+
+ /* For each Prefix in this Link-LSA */
+ link = (struct ospf6_link_lsa *) (n.lsa->header + 1);
+ prefix_num = ntohl (link->llsa_prefix_num);
+
+ if (IS_OSPF6_DUMP_PREFIX)
+ zlog_info (" Prefix #%d", prefix_num);
+
+ start = (char *) (link + 1);
+ end = (char *) (n.lsa->header) + ntohs (n.lsa->header->length);
+ prefix = (struct ospf6_prefix *) start;
+ for (current = start; current < end;
+ current += OSPF6_PREFIX_SIZE (prefix))
+ {
+ prefix = (struct ospf6_prefix *) current;
+ ospf6_prefix_string (prefix, buf, sizeof (buf));
+
+ /* Check duplicate prefix */
+ dup = ospf6_prefix_lookup (adv_list, prefix);
+ if (dup)
+ {
+ if (IS_OSPF6_DUMP_PREFIX)
+ zlog_info (" Duplicate %s", buf);
+ dup->prefix_options |= prefix->prefix_options;
+ continue;
+ }
+
+ if (prefix_num <= 0)
+ {
+ zlog_warn (" Wong prefix number ...");
+ break;
+ }
+
+ if (IS_OSPF6_DUMP_PREFIX)
+ zlog_info (" Prefix %s", buf);
+
+ /* copy prefix to advertise list */
+ ospf6_prefix_add (adv_list, prefix);
+
+ prefix_num --;
+ }
+ }
+
+ /* if no prefix to advertise, return */
+ if (listcount (adv_list) == 0)
+ {
+ if (IS_OSPF6_DUMP_PREFIX)
+ zlog_info (" No Prefix to advertise");
+ if (old)
+ ospf6_lsa_premature_aging (old);
+ return;
+ }
+
+ /* prepare buffer */
+ memset (buffer, 0, sizeof (buffer));
+ size = sizeof (struct ospf6_intra_area_prefix_lsa);
+ iap = (struct ospf6_intra_area_prefix_lsa *) buffer;
+
+ /* Set Referenced LSA field */
+ iap->refer_lstype = htons (OSPF6_LSA_TYPE_NETWORK);
+ iap->refer_lsid = htonl (o6i->if_id);
+ iap->refer_advrtr = o6i->area->ospf6->router_id;
+
+ dst = (struct ospf6_prefix *) (iap + 1);
+ for (node = listhead (adv_list); node; nextnode (node))
+ {
+ src = (struct ospf6_prefix *) getdata (node);
+
+ memcpy (dst, src, OSPF6_PREFIX_SIZE (src));
+
+ size += OSPF6_PREFIX_SIZE (dst);
+ dst = OSPF6_NEXT_PREFIX (dst);
+ }
+ iap->prefix_number = htons (listcount (adv_list));
+
+ while ((node = listhead (adv_list)) != NULL)
+ {
+ prefix = getdata (node);
+ ospf6_prefix_delete (prefix);
+ listnode_delete (adv_list, prefix);
+ }
+ list_delete (adv_list);
+
+ ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_INTRA_PREFIX),
+ htonl (o6i->if_id), ospf6->router_id,
+ buffer, size, o6i->area);
+}
+
+void
+ospf6_lsa_intra_prefix_update_stub (u_int32_t area_id)
+{
+ char buffer [MAXLSASIZE];
+ u_int16_t size;
+ struct ospf6_lsa *old;
+ struct ospf6_area *o6a;
+ int count;
+
+ struct ospf6_intra_area_prefix_lsa *iap;
+ listnode i,j;
+ struct ospf6_interface *o6i = NULL;
+ struct ospf6_prefix *prefix, *dst, *src;
+ struct connected *c;
+ char buf[128];
+
+ list adv_list;
+ listnode node;
+ char prefix_buf[sizeof (struct ospf6_prefix) + sizeof (struct in6_addr)];
+
+ o6a = ospf6_area_lookup (area_id, ospf6);
+ if (! o6a)
+ {
+ char tmp[16];
+ inet_ntop (AF_INET, &area_id, tmp, sizeof (tmp));
+ zlog_warn ("Update Intra-Prefix (Stub): No such area: %s", tmp);
+ return;
+ }
+ else if (IS_OSPF6_DUMP_PREFIX)
+ {
+ zlog_info ("Update Intra-Prefix (Stub): area: %s", o6a->str);
+ }
+
+ /* find previous LSA */
+ old = ospf6_lsdb_lookup (htons (OSPF6_LSA_TYPE_INTRA_PREFIX),
+ htonl (0), ospf6->router_id,
+ o6a); /* xxx, ls-id */
+
+ adv_list = list_new ();
+
+ /* Examin for each interface */
+ for (i = listhead (o6a->if_list); i; nextnode (i))
+ {
+ o6i = (struct ospf6_interface *) getdata (i);
+
+ if (o6i->state == IFS_DOWN)
+ {
+ if (IS_OSPF6_DUMP_PREFIX)
+ zlog_info (" Interface %s: down", o6i->interface->name);
+ continue;
+ }
+
+ count = 0;
+ o6i->foreach_nei (o6i, &count, NBS_FULL, ospf6_count_state);
+ if (o6i->state != IFS_LOOPBACK && o6i->state != IFS_PTOP &&
+ count != 0)
+ {
+ /* This interface's prefix will be included in DR's */
+ if (IS_OSPF6_DUMP_PREFIX)
+ zlog_info (" Interface %s: not stub", o6i->interface->name);
+ continue;
+ }
+
+ if (IS_OSPF6_DUMP_PREFIX)
+ zlog_info (" Interface %s:", o6i->interface->name);
+
+ /* copy foreach address prefix */
+ for (j = listhead (o6i->interface->connected); j; nextnode (j))
+ {
+ c = (struct connected *) getdata (j);
+
+ /* filter prefix not IPv6 */
+ if (c->address->family != AF_INET6)
+ continue;
+
+ /* for log */
+ prefix2str (c->address, buf, sizeof (buf));
+
+ CONTINUE_IF_ADDRESS_LINKLOCAL (c->address);
+ CONTINUE_IF_ADDRESS_UNSPECIFIED (c->address);
+ CONTINUE_IF_ADDRESS_LOOPBACK (c->address);
+ CONTINUE_IF_ADDRESS_V4COMPAT (c->address);
+ CONTINUE_IF_ADDRESS_V4MAPPED (c->address);
+
+ /* filter prefix specified by configuration */
+ if (o6i->plist_name)
+ {
+ struct prefix_list *plist;
+ enum prefix_list_type result = PREFIX_PERMIT;
+
+ plist = prefix_list_lookup (AFI_IP6, o6i->plist_name);
+ if (plist)
+ result = prefix_list_apply (plist, c->address);
+ else
+ zlog_warn ("Update Intra-Prefix (Stub): "
+ "Prefix list \"%s\" not found",
+ o6i->plist_name);
+
+ if (result == PREFIX_DENY)
+ {
+ if (IS_OSPF6_DUMP_PREFIX)
+ zlog_info (" %s: Filtered by %s",
+ buf, o6i->plist_name);
+ continue;
+ }
+ }
+
+ /* initialize buffer for ospf6 prefix */
+ memset (prefix_buf, 0, sizeof (prefix_buf));
+ prefix = (struct ospf6_prefix *) prefix_buf;
+
+ /* set ospf6 prefix according to its state */
+ /* xxx, virtual links */
+ if (! CHECK_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_FORCE_PREFIX) &&
+ (o6i->state == IFS_LOOPBACK || o6i->state == IFS_PTOP
+ /* xxx, PoinToMultiPoint I/F type */ ))
+ {
+ prefix->prefix_length = 128;
+ prefix->prefix_options = OSPF6_PREFIX_OPTION_LA;
+ prefix->prefix_metric = htons (0);
+ memcpy (prefix + 1, &c->address->u.prefix6,
+ OSPF6_PREFIX_SPACE (prefix->prefix_length));
+ }
+ else
+ {
+ struct prefix_ipv6 prefix_ipv6;
+ /* apply mask */
+ prefix_copy ((struct prefix *) &prefix_ipv6, c->address);
+ apply_mask_ipv6 (&prefix_ipv6);
+
+ prefix->prefix_length = prefix_ipv6.prefixlen;
+ prefix->prefix_options = 0; /* xxx, no options yet */
+ prefix->prefix_metric = htons (o6i->cost);
+ memcpy (prefix + 1, &prefix_ipv6.prefix,
+ OSPF6_PREFIX_SPACE (prefix->prefix_length));
+ }
+
+ ospf6_prefix_string (prefix, buf, sizeof (buf));
+ if (IS_OSPF6_DUMP_PREFIX)
+ zlog_info (" Advertise %s", buf);
+
+ /* check in the prefix to advertising prefix list */
+ ospf6_prefix_add (adv_list, prefix);
+ }
+ }
+
+ /* If no prefix to advertise */
+ if (listcount (adv_list) == 0)
+ {
+ if (IS_OSPF6_DUMP_PREFIX)
+ zlog_info (" No prefix to advertise");
+ if (old)
+ ospf6_lsa_premature_aging (old);
+ return;
+ }
+
+ /* prepare buffer */
+ memset (buffer, 0, sizeof (buffer));
+ size = sizeof (struct ospf6_intra_area_prefix_lsa);
+ iap = (struct ospf6_intra_area_prefix_lsa *) buffer;
+
+ /* Set Referenced LSA field */
+ iap->refer_lstype = htons (OSPF6_LSA_TYPE_ROUTER);
+ iap->refer_lsid = htonl (0);
+ iap->refer_advrtr = o6a->ospf6->router_id;
+
+ dst = (struct ospf6_prefix *) (iap + 1);
+ for (node = listhead (adv_list); node; nextnode (node))
+ {
+ src = (struct ospf6_prefix *) getdata (node);
+
+ memcpy (dst, src, OSPF6_PREFIX_SIZE (src));
+
+ size += OSPF6_PREFIX_SIZE (dst);
+ dst = OSPF6_NEXT_PREFIX (dst);
+ }
+ iap->prefix_number = htons (listcount (adv_list));
+
+ while ((node = listhead (adv_list)) != NULL)
+ {
+ prefix = getdata (node);
+ ospf6_prefix_delete (prefix);
+ listnode_delete (adv_list, prefix);
+ }
+ list_delete (adv_list);
+
+ ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_INTRA_PREFIX),
+ htonl (0) /* xxx */, ospf6->router_id,
+ buffer, size, o6a);
+}
+
+int
+ospf6_lsa_intra_prefix_hook_interface (void *interface)
+{
+ struct ospf6_interface *o6i = interface;
+ if (o6i->area)
+ {
+ ospf6_lsa_intra_prefix_update_transit (o6i->interface->name);
+ ospf6_lsa_intra_prefix_update_stub (o6i->area->area_id);
+ }
+ return 0;
+}
+
+int
+ospf6_lsa_intra_prefix_hook_neighbor (void *neighbor)
+{
+ struct ospf6_neighbor *o6n = neighbor;
+ if (o6n->ospf6_interface->area)
+ {
+ ospf6_lsa_intra_prefix_update_transit (o6n->ospf6_interface->interface->name);
+ ospf6_lsa_intra_prefix_update_stub (o6n->ospf6_interface->area->area_id);
+ }
+ return 0;
+}
+
+int
+ospf6_intra_prefix_link_database_hook (void *new)
+{
+ struct ospf6_lsa *lsa = new;
+ struct ospf6_interface *o6i;
+
+ if (lsa->header->type != htons (OSPF6_LSA_TYPE_LINK))
+ return 0;
+
+ o6i = lsa->scope;
+ if (o6i->state != IFS_DR)
+ return 0;
+
+ ospf6_lsa_intra_prefix_update_transit (o6i->interface->name);
+ ospf6_lsa_intra_prefix_update_stub (o6i->area->area_id);
+ return 0;
+}
+
+int
+ospf6_lsa_intra_prefix_refresh (void *old)
+{
+ struct ospf6_lsa *lsa = old;
+ struct ospf6_interface *o6i;
+ struct ospf6_area *o6a;
+ u_int32_t id;
+
+ id = ntohl (lsa->header->id);
+ if (id)
+ {
+ o6i = ospf6_interface_lookup_by_index (id);
+ if (o6i)
+ ospf6_lsa_intra_prefix_update_transit (o6i->interface->name);
+ else
+ ospf6_lsa_premature_aging (lsa);
+ }
+ else
+ {
+ o6a = lsa->scope;
+ ospf6_lsa_intra_prefix_update_stub (o6a->area_id);
+ }
+
+ return 0;
+}
+
+void
+ospf6_intra_prefix_register ()
+{
+ struct ospf6_lsa_slot slot, *sp;
+ struct ospf6_hook hook;
+
+ memset (&slot, 0, sizeof (struct ospf6_lsa_slot));
+ slot.type = htons (OSPF6_LSA_TYPE_INTRA_PREFIX);
+ slot.name = "Intra-Prefix";
+ slot.func_show = ospf6_lsa_intra_prefix_show;
+ slot.func_refresh = ospf6_lsa_intra_prefix_refresh;
+ ospf6_lsa_slot_register (&slot);
+
+ memset (&hook, 0, sizeof (hook));
+ hook.name = "OriginateIntraPrefix";
+ hook.hook_add = ospf6_lsa_intra_prefix_hook_interface;
+ hook.hook_change = ospf6_lsa_intra_prefix_hook_interface;
+ hook.hook_remove = NULL; /* XXX */
+ ospf6_hook_register (&hook, &interface_hook);
+
+ memset (&hook, 0, sizeof (hook));
+ hook.name = "OriginateIntraPrefix";
+ hook.hook_add = ospf6_lsa_intra_prefix_hook_neighbor;
+ hook.hook_change = ospf6_lsa_intra_prefix_hook_neighbor;
+ hook.hook_remove = ospf6_lsa_intra_prefix_hook_neighbor;
+ ospf6_hook_register (&hook, &neighbor_hook);
+
+ sp = ospf6_lsa_slot_get (htons (OSPF6_LSA_TYPE_INTRA_PREFIX));
+ hook.name = "CalculateIntraPrefix";
+ hook.hook_add = ospf6_intra_prefix_database_hook_add;
+ hook.hook_change = ospf6_intra_prefix_database_hook_add;
+ hook.hook_remove = ospf6_intra_prefix_database_hook_remove;
+ ospf6_hook_register (&hook, &sp->database_hook);
+}
+
+void
+ospf6_intra_database_hook_intra_prefix (struct ospf6_lsa *old,
+ struct ospf6_lsa *new)
+{
+ if (old)
+ ospf6_intra_prefix_database_hook_remove (old);
+ if (new && ! IS_LSA_MAXAGE (new))
+ ospf6_intra_prefix_database_hook_add (new);
+}
+
+void
+ospf6_intra_database_hook_link (struct ospf6_lsa *old,
+ struct ospf6_lsa *new)
+{
+ ospf6_intra_prefix_link_database_hook (new);
+ ospf6_spf_database_hook (old, new);
+}
+
+void
+ospf6_intra_init ()
+{
+ ospf6_lsdb_hook[OSPF6_LSA_TYPE_INTRA_PREFIX & OSPF6_LSTYPE_CODE_MASK].hook =
+ ospf6_intra_database_hook_intra_prefix;
+ ospf6_lsdb_hook[OSPF6_LSA_TYPE_LINK & OSPF6_LSTYPE_CODE_MASK].hook =
+ ospf6_intra_database_hook_link;
+
+ intra_index = ospf6_dump_install ("intra-area", "Intra-area calculation\n");
+ ospf6_intra_prefix_register ();
+}
+
+
diff --git a/ospf6d/ospf6_intra.h b/ospf6d/ospf6_intra.h
new file mode 100644
index 00000000..4fb68e95
--- /dev/null
+++ b/ospf6d/ospf6_intra.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2001 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef OSPF6_INTRA_H
+#define OSPF6_INTRA_H
+
+void ospf6_intra_topology_add (void *);
+void ospf6_intra_topology_remove (void *);
+
+void ospf6_intra_init ();
+
+#endif /* OSPF6_INTRA_H */
+
diff --git a/ospf6d/ospf6_ism.c b/ospf6d/ospf6_ism.c
new file mode 100644
index 00000000..d13be127
--- /dev/null
+++ b/ospf6d/ospf6_ism.c
@@ -0,0 +1,519 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* Interface State Machine */
+
+#include "ospf6d.h"
+
+int
+ifs_change (state_t ifs_next, char *reason, struct ospf6_interface *o6i)
+{
+ state_t ifs_prev;
+
+ ifs_prev = o6i->state;
+
+ if (ifs_prev == ifs_next)
+ return 0;
+
+ if (IS_OSPF6_DUMP_INTERFACE)
+ zlog_info ("I/F: %s: %s -> %s (%s)",
+ o6i->interface->name,
+ ospf6_interface_state_string[ifs_prev],
+ ospf6_interface_state_string[ifs_next], reason);
+
+ if ((ifs_prev == IFS_DR || ifs_prev == IFS_BDR) &&
+ (ifs_next != IFS_DR && ifs_next != IFS_BDR))
+ ospf6_leave_alldrouters (o6i->interface->ifindex);
+ else if ((ifs_prev != IFS_DR && ifs_prev != IFS_BDR) &&
+ (ifs_next == IFS_DR || ifs_next == IFS_BDR))
+ ospf6_join_alldrouters (o6i->interface->ifindex);
+
+ o6i->state = ifs_next;
+
+ if (o6i->prevdr != o6i->dr || o6i->prevbdr != o6i->bdr)
+ {
+ if (IS_OSPF6_DUMP_INTERFACE)
+ {
+ char dr[16], bdr[16], prevdr[16], prevbdr[16];
+ inet_ntop (AF_INET, &o6i->prevdr, prevdr, sizeof (prevdr));
+ inet_ntop (AF_INET, &o6i->prevbdr, prevbdr, sizeof (prevbdr));
+ inet_ntop (AF_INET, &o6i->dr, dr, sizeof (dr));
+ inet_ntop (AF_INET, &o6i->bdr, bdr, sizeof (bdr));
+ zlog_info ("I/F: %s: DR: %s -> %s", o6i->interface->name,
+ prevdr, dr);
+ zlog_info ("I/F: %s: BDR: %s -> %s", o6i->interface->name,
+ prevbdr, bdr);
+ }
+ }
+
+ CALL_CHANGE_HOOK (&interface_hook, o6i);
+ return 0;
+}
+
+
+/* Interface State Machine */
+int
+interface_up (struct thread *thread)
+{
+ struct ospf6_interface *ospf6_interface;
+
+ ospf6_interface = (struct ospf6_interface *)THREAD_ARG (thread);
+
+ assert (ospf6_interface);
+ assert (ospf6_interface->interface);
+
+ if (IS_OSPF6_DUMP_INTERFACE)
+ zlog_info ("I/F: %s: InterfaceUp",
+ ospf6_interface->interface->name);
+
+ /* check physical interface is up */
+ if (!if_is_up (ospf6_interface->interface))
+ {
+ if (IS_OSPF6_DUMP_INTERFACE)
+ zlog_warn (" interface %s down, can't execute InterfaceUp",
+ ospf6_interface->interface->name);
+ return -1;
+ }
+
+ /* if already enabled, do nothing */
+ if (ospf6_interface->state > IFS_DOWN)
+ {
+ zlog_warn ("Interface %s already up",
+ ospf6_interface->interface->name);
+ return 0;
+ }
+
+ /* ifid of this interface */
+ ospf6_interface->if_id = ospf6_interface->interface->ifindex;
+
+ /* Join AllSPFRouters */
+ ospf6_join_allspfrouters (ospf6_interface->interface->ifindex);
+
+ /* set socket options */
+ ospf6_set_reuseaddr ();
+ ospf6_reset_mcastloop ();
+ ospf6_set_pktinfo ();
+ ospf6_set_checksum ();
+
+ /* Schedule Hello */
+ if (! CHECK_FLAG (ospf6_interface->flag, OSPF6_INTERFACE_FLAG_PASSIVE))
+ thread_add_event (master, ospf6_send_hello, ospf6_interface, 0);
+
+ /* decide next interface state */
+ if (if_is_pointopoint (ospf6_interface->interface))
+ ifs_change (IFS_PTOP, "IF Type PointToPoint", ospf6_interface);
+ else if (ospf6_interface->priority == 0)
+ ifs_change (IFS_DROTHER, "Router Priority = 0", ospf6_interface);
+ else
+ {
+ ifs_change (IFS_WAITING, "Priority > 0", ospf6_interface);
+ thread_add_timer (master, wait_timer, ospf6_interface,
+ ospf6_interface->dead_interval);
+ }
+
+ CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, ospf6_interface);
+
+ return 0;
+}
+
+int
+wait_timer (struct thread *thread)
+{
+ struct ospf6_interface *ospf6_interface;
+
+ ospf6_interface = (struct ospf6_interface *)THREAD_ARG (thread);
+ assert (ospf6_interface);
+
+ if (ospf6_interface->state != IFS_WAITING)
+ return 0;
+
+ if (IS_OSPF6_DUMP_INTERFACE)
+ zlog_info ("I/F: %s: WaitTimer", ospf6_interface->interface->name);
+
+ ifs_change (dr_election (ospf6_interface),
+ "WaitTimer:DR Election", ospf6_interface);
+ return 0;
+}
+
+int backup_seen (struct thread *thread)
+{
+ struct ospf6_interface *ospf6_interface;
+
+ ospf6_interface = (struct ospf6_interface *)THREAD_ARG (thread);
+ assert (ospf6_interface);
+
+ if (IS_OSPF6_DUMP_INTERFACE)
+ zlog_info ("I/F: %s: BackupSeen", ospf6_interface->interface->name);
+
+ if (ospf6_interface->state == IFS_WAITING)
+ ifs_change (dr_election (ospf6_interface),
+ "BackupSeen:DR Election", ospf6_interface);
+
+ return 0;
+}
+
+int neighbor_change (struct thread *thread)
+{
+ struct ospf6_interface *ospf6_interface;
+
+ ospf6_interface = (struct ospf6_interface *)THREAD_ARG (thread);
+ assert (ospf6_interface);
+
+ if (ospf6_interface->state != IFS_DROTHER &&
+ ospf6_interface->state != IFS_BDR &&
+ ospf6_interface->state != IFS_DR)
+ return 0;
+
+ if (IS_OSPF6_DUMP_INTERFACE)
+ zlog_info ("I/F: %s: NeighborChange", ospf6_interface->interface->name);
+
+ ifs_change (dr_election (ospf6_interface),
+ "NeighborChange:DR Election", ospf6_interface);
+
+ return 0;
+}
+
+int
+loopind (struct thread *thread)
+{
+ struct ospf6_interface *ospf6_interface;
+
+ ospf6_interface = (struct ospf6_interface *)THREAD_ARG (thread);
+ assert (ospf6_interface);
+
+ if (IS_OSPF6_DUMP_INTERFACE)
+ zlog_info ("I/F: %s: LoopInd", ospf6_interface->interface->name);
+
+ /* XXX not yet */
+
+ return 0;
+}
+
+int
+interface_down (struct thread *thread)
+{
+ struct ospf6_interface *ospf6_interface;
+
+ ospf6_interface = (struct ospf6_interface *) THREAD_ARG (thread);
+ assert (ospf6_interface);
+
+ if (IS_OSPF6_DUMP_INTERFACE)
+ zlog_info ("I/F: %s: InterfaceDown", ospf6_interface->interface->name);
+
+ if (ospf6_interface->state == IFS_NONE)
+ return 1;
+
+ /* Leave AllSPFRouters */
+ if (ospf6_interface_is_enabled (ospf6_interface->interface->ifindex))
+ ospf6_leave_allspfrouters (ospf6_interface->interface->ifindex);
+
+ ifs_change (IFS_DOWN, "Configured", ospf6_interface);
+
+ return 0;
+}
+
+
+/* 9.4 of RFC2328 */
+int
+dr_election (struct ospf6_interface *ospf6_interface)
+{
+ list candidate_list = list_new ();
+ listnode i, j, n;
+ ifid_t prevdr, prevbdr, dr = 0, bdr;
+ struct ospf6_neighbor *nbpi, *nbpj, myself, *nbr;
+ int declare = 0;
+ int gofive = 0;
+
+ /* statistics */
+ ospf6_interface->ospf6_stat_dr_election++;
+
+ /* pseudo neighbor "myself" */
+ memset (&myself, 0, sizeof (myself));
+ myself.state = NBS_TWOWAY;
+ myself.dr = ospf6_interface->dr;
+ myself.bdr = ospf6_interface->bdr;
+ myself.priority = ospf6_interface->priority;
+ myself.ifid = ospf6_interface->if_id;
+ myself.router_id = ospf6_interface->area->ospf6->router_id;
+
+/* step_one: */
+
+ ospf6_interface->prevdr = prevdr = ospf6_interface->dr;
+ ospf6_interface->prevbdr = prevbdr = ospf6_interface->bdr;
+
+step_two:
+
+ /* Calculate Backup Designated Router. */
+ /* Make Candidate list */
+ if (!list_isempty (candidate_list))
+ list_delete_all_node (candidate_list);
+ declare = 0;
+ for (i = listhead (ospf6_interface->neighbor_list); i; nextnode (i))
+ {
+ nbpi = (struct ospf6_neighbor *)getdata (i);
+ if (nbpi->priority == 0)
+ continue;
+ if (nbpi->state < NBS_TWOWAY)
+ continue;
+ if (nbpi->dr == nbpi->router_id)
+ continue;
+ if (nbpi->bdr == nbpi->router_id)
+ declare++;
+ listnode_add (candidate_list, nbpi);
+ }
+
+ if (myself.priority)
+ {
+ if (myself.dr != myself.router_id)
+ {
+ if (myself.bdr == myself.router_id)
+ declare++;
+ listnode_add (candidate_list, &myself);
+ }
+ }
+
+ /* Elect BDR */
+ for (i = listhead (candidate_list);
+ candidate_list->count > 1;
+ i = listhead (candidate_list))
+ {
+ j = i;
+ nextnode(j);
+ assert (j);
+ nbpi = (struct ospf6_neighbor *)getdata (i);
+ nbpj = (struct ospf6_neighbor *)getdata (j);
+ if (declare)
+ {
+ int deleted = 0;
+ if (nbpi->bdr != nbpi->router_id)
+ {
+ listnode_delete (candidate_list, nbpi);
+ deleted++;
+ }
+ if (nbpj->bdr != nbpj->router_id)
+ {
+ listnode_delete (candidate_list, nbpj);
+ deleted++;
+ }
+ if (deleted)
+ continue;
+ }
+ if (nbpi->priority > nbpj->priority)
+ {
+ listnode_delete (candidate_list, nbpj);
+ continue;
+ }
+ else if (nbpi->priority < nbpj->priority)
+ {
+ listnode_delete (candidate_list, nbpi);
+ continue;
+ }
+ else /* equal, case of tie */
+ {
+ if (ntohl (nbpi->router_id) > ntohl (nbpj->router_id))
+ {
+ listnode_delete (candidate_list, nbpj);
+ continue;
+ }
+ else if (ntohl (nbpi->router_id) < ntohl (nbpj->router_id))
+ {
+ listnode_delete (candidate_list, nbpi);
+ continue;
+ }
+ else
+ assert (0);
+ }
+ }
+
+ if (!list_isempty (candidate_list))
+ {
+ assert (candidate_list->count == 1);
+ n = listhead (candidate_list);
+ nbr = (struct ospf6_neighbor *)getdata (n);
+ bdr = nbr->router_id;
+ }
+ else
+ bdr = 0;
+
+/* step_three: */
+
+ /* Calculate Designated Router. */
+ /* Make Candidate list */
+ if (!list_isempty (candidate_list))
+ list_delete_all_node (candidate_list);
+ declare = 0;
+ for (i = listhead (ospf6_interface->neighbor_list); i; nextnode (i))
+ {
+ nbpi = (struct ospf6_neighbor *)getdata (i);
+ if (nbpi->priority == 0)
+ continue;
+ if (nbpi->state < NBS_TWOWAY)
+ continue;
+ if (nbpi->dr == nbpi->router_id)
+ {
+ declare++;
+ listnode_add (candidate_list, nbpi);
+ }
+ }
+ if (myself.priority)
+ {
+ if (myself.dr == myself.router_id)
+ {
+ declare++;
+ listnode_add (candidate_list, &myself);
+ }
+ }
+
+ /* Elect DR */
+ if (declare == 0)
+ {
+ assert (list_isempty (candidate_list));
+ /* No one declare but candidate_list not empty */
+ dr = bdr;
+ }
+ else
+ {
+ assert (!list_isempty (candidate_list));
+ for (i = listhead (candidate_list);
+ candidate_list->count > 1;
+ i = listhead (candidate_list))
+ {
+ j = i;
+ nextnode (j);
+ assert (j);
+ nbpi = (struct ospf6_neighbor *)getdata (i);
+ nbpj = (struct ospf6_neighbor *)getdata (j);
+
+ if (nbpi->dr != nbpi->router_id)
+ {
+ list_delete_node (candidate_list, i);
+ continue;
+ }
+ if (nbpj->dr != nbpj->router_id)
+ {
+ list_delete_node (candidate_list, j);
+ continue;
+ }
+
+ if (nbpi->priority > nbpj->priority)
+ {
+ list_delete_node (candidate_list, j);
+ continue;
+ }
+ else if (nbpi->priority < nbpj->priority)
+ {
+ list_delete_node (candidate_list, i);
+ continue;
+ }
+ else /* equal, case of tie */
+ {
+ if (nbpi->router_id > nbpj->router_id)
+ {
+ list_delete_node (candidate_list, j);
+ continue;
+ }
+ else if (nbpi->router_id < nbpj->router_id)
+ {
+ list_delete_node (candidate_list, i);
+ continue;
+ }
+ else
+ {
+ zlog_warn ("!!!THE SAME ROUTER ID FOR DIFFERENT NEIGHBOR");
+ zlog_warn ("!!!MISCONFIGURATION?");
+ list_delete_node (candidate_list, i);
+ continue;
+ }
+ }
+ }
+ if (!list_isempty (candidate_list))
+ {
+ assert (candidate_list->count == 1);
+ n = listhead (candidate_list);
+ nbr = (struct ospf6_neighbor *)getdata (n);
+ dr = nbr->router_id;
+ }
+ else
+ assert (0);
+ }
+
+/* step_four: */
+
+ if (gofive)
+ goto step_five;
+
+ if (dr != prevdr)
+ {
+ if ((dr == myself.router_id || prevdr == myself.router_id)
+ && !(dr == myself.router_id && prevdr == myself.router_id))
+ {
+ myself.dr = dr;
+ myself.bdr = bdr;
+ gofive++;
+ goto step_two;
+ }
+ }
+ if (bdr != prevbdr)
+ {
+ if ((bdr == myself.router_id || prevbdr == myself.router_id)
+ && !(bdr == myself.router_id && prevbdr == myself.router_id))
+ {
+ myself.dr = dr;
+ myself.bdr = bdr;
+ gofive++;
+ goto step_two;
+ }
+ }
+
+step_five:
+
+ ospf6_interface->dr = dr;
+ ospf6_interface->bdr = bdr;
+
+ if (prevdr != dr || prevbdr != bdr)
+ {
+ for (i = listhead (ospf6_interface->neighbor_list); i; nextnode (i))
+ {
+ nbpi = getdata (i);
+ if (nbpi->state < NBS_TWOWAY)
+ continue;
+ /* Schedule or Execute AdjOK. which does "invoke" mean? */
+ thread_add_event (master, adj_ok, nbpi, 0);
+ }
+ }
+
+ list_delete (candidate_list);
+
+ if (dr == myself.router_id)
+ {
+ assert (bdr != myself.router_id);
+ return IFS_DR;
+ }
+ else if (bdr == myself.router_id)
+ {
+ assert (dr != myself.router_id);
+ return IFS_BDR;
+ }
+ else
+ return IFS_DROTHER;
+}
+
+
diff --git a/ospf6d/ospf6_ism.h b/ospf6d/ospf6_ism.h
new file mode 100644
index 00000000..12470d98
--- /dev/null
+++ b/ospf6d/ospf6_ism.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef OSPF6_ISM_H
+#define OSPF6_ISM_H
+
+/* interface state */
+#define IFS_NONE 0
+#define IFS_DOWN 1
+#define IFS_LOOPBACK 2
+#define IFS_WAITING 3
+#define IFS_PTOP 4
+#define IFS_DROTHER 5
+#define IFS_BDR 6
+#define IFS_DR 7
+#define IFS_MAX 8
+
+
+
+/* Function Prototypes */
+/* interface event */
+int interface_up (struct thread *);
+int interface_down (struct thread *);
+int wait_timer (struct thread *);
+int backup_seen (struct thread *);
+int neighbor_change (struct thread *);
+
+
+#include "ospf6_types.h"
+
+int dr_change (struct ospf6_interface *);
+int ifs_change (state_t, char *, struct ospf6_interface *);
+
+#endif /* OSPF6_ISM_H */
+
diff --git a/ospf6d/ospf6_linklist.c b/ospf6d/ospf6_linklist.c
new file mode 100644
index 00000000..8c179359
--- /dev/null
+++ b/ospf6d/ospf6_linklist.c
@@ -0,0 +1,193 @@
+
+#include <zebra.h>
+
+#include "ospf6_linklist.h"
+
+static struct linklist_node *
+linklist_lookup_node (void *data, struct linklist *linklist)
+{
+ struct linklist_node *node;
+
+ for (node = linklist->head; node; node = node->next)
+ {
+ if (linklist->cmp && (*linklist->cmp) (node->data, data) == 0)
+ return node;
+ if (node->data == data)
+ return node;
+ }
+
+ return NULL;
+}
+
+void *
+linklist_lookup (void *data, struct linklist *linklist)
+{
+ struct linklist_node *node;
+
+ node = linklist_lookup_node (data, linklist);
+ if (node)
+ return node->data;
+ return NULL;
+}
+
+int
+linklist_add (void *data, struct linklist *linklist)
+{
+ struct linklist_node *node = NULL, *add;
+
+ if (linklist_lookup_node (data, linklist))
+ return -1;
+
+ add = malloc (sizeof (struct linklist_node));
+ if (add == NULL)
+ return -1;
+ memset (add, 0, sizeof (struct linklist_node));
+ add->data = data;
+
+ if (linklist->cmp)
+ {
+ for (node = linklist->head; node; node = node->next)
+ {
+ if ((*linklist->cmp) (node->data, add->data) > 0)
+ break;
+ }
+ }
+
+ if (! node)
+ {
+ /* add to tail */
+ if (linklist->tail)
+ {
+ linklist->tail->next = add;
+ add->prev = linklist->tail;
+ }
+ else
+ {
+ linklist->head = add;
+ add->prev = NULL;
+ }
+
+ linklist->tail = add;
+ add->next = NULL;
+ }
+ else
+ {
+ /* insert just before 'node' */
+ if (node->prev)
+ {
+ node->prev->next = add;
+ add->prev = node->prev;
+ }
+ else
+ {
+ linklist->head = add;
+ add->prev = NULL;
+ }
+
+ add->next = node;
+ node->prev = add;
+ }
+
+ linklist->count++;
+ return 0;
+}
+
+int
+linklist_remove (void *data, struct linklist *linklist)
+{
+ struct linklist_node *rem;
+
+ rem = linklist_lookup_node (data, linklist);
+ if (rem == NULL)
+ return -1;
+
+ if (rem->prev)
+ rem->prev->next = rem->next;
+ else
+ linklist->head = rem->next;
+
+ if (rem->next)
+ rem->next->prev = rem->prev;
+ else
+ linklist->tail = rem->prev;
+
+ free (rem);
+ linklist->count--;
+ return 0;
+}
+
+void
+linklist_head (struct linklist *linklist, struct linklist_node *node)
+{
+ if (linklist->head == NULL)
+ {
+ node->prev = NULL;
+ node->next = NULL;
+ node->data = NULL;
+ return;
+ }
+
+ node->prev = linklist->head->prev;
+ node->next = linklist->head->next;
+ node->data = linklist->head->data;
+}
+
+int
+linklist_end (struct linklist_node *node)
+{
+ if (node->data == NULL && node->next == NULL)
+ return 1;
+ return 0;
+}
+
+void
+linklist_next (struct linklist_node *node)
+{
+ if (node->next == NULL)
+ {
+ node->prev = NULL;
+ node->next = NULL;
+ node->data = NULL;
+ return;
+ }
+
+ node->data = node->next->data;
+ node->prev = node->next->prev;
+ node->next = node->next->next;
+}
+
+struct linklist *
+linklist_create ()
+{
+ struct linklist *linklist;
+
+ linklist = malloc (sizeof (struct linklist));
+ if (linklist == NULL)
+ return NULL;
+ memset (linklist, 0, sizeof (struct linklist));
+
+ return linklist;
+}
+
+void
+linklist_remove_all (struct linklist *linklist)
+{
+ struct linklist_node node;
+
+ for (linklist_head (linklist, &node); ! linklist_end (&node);
+ linklist_next (&node))
+ linklist_remove (node.data, linklist);
+}
+
+void
+linklist_delete (struct linklist *linklist)
+{
+ linklist_remove_all (linklist);
+ assert (linklist->count == 0);
+ assert (linklist->head == NULL);
+ assert (linklist->tail == NULL);
+
+ free (linklist);
+}
+
+
diff --git a/ospf6d/ospf6_linklist.h b/ospf6d/ospf6_linklist.h
new file mode 100644
index 00000000..6d978999
--- /dev/null
+++ b/ospf6d/ospf6_linklist.h
@@ -0,0 +1,35 @@
+
+#ifndef _LINKLIST_H_
+#define _LINKLIST_H_
+
+struct linklist_node
+{
+ struct linklist_node *prev;
+ struct linklist_node *next;
+
+ void *data;
+};
+
+struct linklist
+{
+ int count;
+ struct linklist_node *head;
+ struct linklist_node *tail;
+
+ int (*cmp) (void *, void *);
+};
+
+void *linklist_lookup (void *data, struct linklist *linklist);
+int linklist_add (void *data, struct linklist *linklist);
+int linklist_remove (void *data, struct linklist *linklist);
+void linklist_remove_all (struct linklist *linklist);
+
+void linklist_head (struct linklist *linklist, struct linklist_node *node);
+int linklist_end (struct linklist_node *node);
+void linklist_next (struct linklist_node *node);
+
+struct linklist *linklist_create ();
+void linklist_delete (struct linklist *);
+
+#endif /*_LINKLIST_H_*/
+
diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c
new file mode 100644
index 00000000..b14979ff
--- /dev/null
+++ b/ospf6d/ospf6_lsa.c
@@ -0,0 +1,1926 @@
+/*
+ * LSA function
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+/* Include other stuffs */
+#include "version.h"
+#include "log.h"
+#include "getopt.h"
+#include "linklist.h"
+#include "thread.h"
+#include "command.h"
+#include "memory.h"
+#include "sockunion.h"
+#include "if.h"
+#include "prefix.h"
+#include "stream.h"
+#include "thread.h"
+#include "filter.h"
+#include "zclient.h"
+#include "table.h"
+#include "plist.h"
+
+#include "ospf6_proto.h"
+#include "ospf6_prefix.h"
+#include "ospf6_lsa.h"
+#include "ospf6_lsdb.h"
+#include "ospf6_message.h"
+#include "ospf6_dump.h"
+
+#include "ospf6_top.h"
+#include "ospf6_area.h"
+#include "ospf6_interface.h"
+#include "ospf6_neighbor.h"
+#include "ospf6_ism.h"
+#include "ospf6_nsm.h"
+#include "ospf6_dbex.h"
+
+#define HEADER_DEPENDENCY
+#include "ospf6d.h"
+#undef HEADER_DEPENDENCY
+
+/* test LSAs identity */
+static int
+ospf6_lsa_issame (struct ospf6_lsa_header__ *lsh1,
+ struct ospf6_lsa_header__ *lsh2)
+{
+ assert (lsh1 && lsh2);
+
+ if (lsh1->adv_router != lsh2->adv_router)
+ return 0;
+
+ if (lsh1->id != lsh2->id)
+ return 0;
+
+ if (lsh1->type != lsh2->type)
+ return 0;
+
+ return 1;
+}
+
+/* RFC2328: Section 13.2 */
+int
+ospf6_lsa_differ (struct ospf6_lsa *lsa1,
+ struct ospf6_lsa *lsa2)
+{
+ int diff, cmplen;
+
+ if (! ospf6_lsa_issame (lsa1->header, lsa2->header))
+ return 1;
+
+ /* check Options field */
+ /* xxx */
+
+ ospf6_lsa_age_current (lsa1);
+ ospf6_lsa_age_current (lsa2);
+ if (ntohs (lsa1->header->age) == MAXAGE &&
+ ntohs (lsa2->header->age) != MAXAGE)
+ return 1;
+ if (ntohs (lsa1->header->age) != MAXAGE &&
+ ntohs (lsa2->header->age) == MAXAGE)
+ return 1;
+
+ /* compare body */
+ if (ntohs (lsa1->header->length) != ntohs (lsa2->header->length))
+ return 1;
+
+ cmplen = ntohs (lsa1->header->length) - sizeof (struct ospf6_lsa_header);
+ diff = memcmp (lsa1->header + 1, lsa2->header + 1, cmplen);
+
+ return diff;
+}
+
+int
+ospf6_lsa_match (u_int16_t type, u_int32_t id, u_int32_t adv_router,
+ struct ospf6_lsa_header *lsh)
+{
+ if (lsh->advrtr != adv_router)
+ return 0;
+
+ if (lsh->ls_id != id)
+ return 0;
+
+ if (lsh->type != type)
+ return 0;
+
+ return 1;
+}
+
+/* ospf6 age functions */
+/* calculate birth and set expire timer */
+static void
+ospf6_lsa_age_set (struct ospf6_lsa *lsa)
+{
+ struct timeval now;
+
+ assert (lsa && lsa->header);
+
+ if (gettimeofday (&now, (struct timezone *)NULL) < 0)
+ zlog_warn ("LSA: gettimeofday failed, may fail LSA AGEs: %s",
+ strerror (errno));
+
+ lsa->birth.tv_sec = now.tv_sec - ntohs (lsa->header->age);
+ lsa->birth.tv_usec = now.tv_usec;
+ if (ntohs (lsa->header->age) != MAXAGE)
+ lsa->expire = thread_add_timer (master, ospf6_lsa_expire, lsa,
+ lsa->birth.tv_sec + MAXAGE - now.tv_sec);
+ else
+ lsa->expire = NULL;
+ return;
+}
+
+/* this function calculates current age from its birth,
+ then update age field of LSA header. return value is current age */
+u_int16_t
+ospf6_lsa_age_current (struct ospf6_lsa *lsa)
+{
+ struct timeval now;
+ u_int32_t ulage;
+ u_int16_t age;
+
+ assert (lsa);
+ assert (lsa->header);
+
+ /* current time */
+ if (gettimeofday (&now, (struct timezone *)NULL) < 0)
+ zlog_warn ("LSA: gettimeofday failed, may fail ages: %s",
+ strerror (errno));
+
+ /* calculate age */
+ ulage = now.tv_sec - lsa->birth.tv_sec;
+
+ /* if over MAXAGE, set to it */
+ if (ulage > MAXAGE)
+ age = MAXAGE;
+ else
+ age = ulage;
+
+ lsa->header->age = htons (age);
+ return age;
+}
+
+/* update age field of LSA header with adding InfTransDelay */
+void
+ospf6_lsa_age_update_to_send (struct ospf6_lsa *lsa, u_int32_t transdelay)
+{
+ unsigned short age;
+
+ age = ospf6_lsa_age_current (lsa) + transdelay;
+ if (age > MAXAGE)
+ age = MAXAGE;
+ lsa->header->age = htons (age);
+ return;
+}
+
+void
+ospf6_lsa_premature_aging (struct ospf6_lsa *lsa)
+{
+ /* log */
+ if (IS_OSPF6_DUMP_LSA)
+ zlog_info ("LSA: Premature aging: %s", lsa->str);
+
+ if (lsa->expire)
+ thread_cancel (lsa->expire);
+ lsa->expire = (struct thread *) NULL;
+ if (lsa->refresh)
+ thread_cancel (lsa->refresh);
+ lsa->refresh = (struct thread *) NULL;
+
+ memset (&lsa->birth, 0, sizeof (struct timeval));
+ thread_execute (master, ospf6_lsa_expire, lsa, 0);
+}
+
+/* check which is more recent. if a is more recent, return -1;
+ if the same, return 0; otherwise(b is more recent), return 1 */
+int
+ospf6_lsa_check_recent (struct ospf6_lsa *a, struct ospf6_lsa *b)
+{
+ signed long seqnuma, seqnumb;
+ u_int16_t cksuma, cksumb;
+ u_int16_t agea, ageb;
+
+ assert (a && a->header);
+ assert (b && b->header);
+ assert (ospf6_lsa_issame (a->header, b->header));
+
+ seqnuma = ((signed long) ntohl (a->header->seqnum))
+ - (signed long) INITIAL_SEQUENCE_NUMBER;
+ seqnumb = ((signed long) ntohl (b->header->seqnum))
+ - (signed long) INITIAL_SEQUENCE_NUMBER;
+
+ /* compare by sequence number */
+ /* xxx, care about LS sequence number wrapping */
+ recent_reason = "seqnum";
+ if (seqnuma > seqnumb)
+ return -1;
+ else if (seqnuma < seqnumb)
+ return 1;
+
+ /* Checksum */
+ cksuma = ntohs (a->header->checksum);
+ cksumb = ntohs (b->header->checksum);
+ if (cksuma > cksumb)
+ return -1;
+ if (cksuma < cksumb)
+ return 0;
+
+ /* Age check */
+ agea = ospf6_lsa_age_current (a);
+ ageb = ospf6_lsa_age_current (b);
+
+ /* MaxAge check */
+ recent_reason = "max age";
+ if (agea == OSPF6_LSA_MAXAGE && ageb != OSPF6_LSA_MAXAGE)
+ return -1;
+ else if (agea != OSPF6_LSA_MAXAGE && ageb == OSPF6_LSA_MAXAGE)
+ return 1;
+
+ recent_reason = "age differ";
+ if (agea > ageb && agea - ageb >= OSPF6_LSA_MAXAGEDIFF)
+ return 1;
+ else if (agea < ageb && ageb - agea >= OSPF6_LSA_MAXAGEDIFF)
+ return -1;
+
+ /* neither recent */
+ recent_reason = "the same instance";
+ return 0;
+}
+
+int
+ospf6_lsa_lsd_num (struct ospf6_lsa_header *lsa_header)
+{
+ int ldnum = 0;
+ u_int16_t len;
+
+ len = ntohs (lsa_header->length);
+ len -= sizeof (struct ospf6_lsa_header);
+ if (lsa_header->type == htons (OSPF6_LSA_TYPE_ROUTER))
+ {
+ len -= sizeof (struct ospf6_router_lsa);
+ ldnum = len / sizeof (struct ospf6_router_lsd);
+ }
+ else /* (lsa_header->type == htons (OSPF6_LSA_TYPE_NETWORK)) */
+ {
+ len -= sizeof (struct ospf6_network_lsa);
+ ldnum = len / sizeof (u_int32_t);
+ }
+
+ return ldnum;
+}
+
+void *
+ospf6_lsa_lsd_get (int index, struct ospf6_lsa_header *lsa_header)
+{
+ void *p;
+ struct ospf6_router_lsa *router_lsa;
+ struct ospf6_router_lsd *router_lsd;
+ struct ospf6_network_lsa *network_lsa;
+ struct ospf6_network_lsd *network_lsd;
+
+ if (lsa_header->type == htons (OSPF6_LSA_TYPE_ROUTER))
+ {
+ router_lsa = (struct ospf6_router_lsa *) (lsa_header + 1);
+ router_lsd = (struct ospf6_router_lsd *) (router_lsa + 1);
+ router_lsd += index;
+ p = (void *) router_lsd;
+ }
+ else if (lsa_header->type == htons (OSPF6_LSA_TYPE_NETWORK))
+ {
+ network_lsa = (struct ospf6_network_lsa *) (lsa_header + 1);
+ network_lsd = (struct ospf6_network_lsd *) (network_lsa + 1);
+ network_lsd += index;
+ p = (void *) network_lsd;
+ }
+ else
+ {
+ p = (void *) NULL;
+ }
+
+ return p;
+}
+
+/* network_lsd <-> router_lsd */
+static int
+ospf6_lsa_lsd_network_reference_match (struct ospf6_network_lsd *network_lsd1,
+ struct ospf6_lsa_header *lsa_header1,
+ struct ospf6_router_lsd *router_lsd2,
+ struct ospf6_lsa_header *lsa_header2)
+{
+ if (network_lsd1->adv_router != lsa_header2->advrtr)
+ return 0;
+ if (router_lsd2->type != OSPF6_ROUTER_LSD_TYPE_TRANSIT_NETWORK)
+ return 0;
+ if (router_lsd2->neighbor_router_id != lsa_header1->advrtr)
+ return 0;
+ if (router_lsd2->neighbor_interface_id != lsa_header1->ls_id)
+ return 0;
+ return 1;
+}
+
+/* router_lsd <-> router_lsd */
+static int
+ospf6_lsa_lsd_router_reference_match (struct ospf6_router_lsd *router_lsd1,
+ struct ospf6_lsa_header *lsa_header1,
+ struct ospf6_router_lsd *router_lsd2,
+ struct ospf6_lsa_header *lsa_header2)
+{
+ if (router_lsd1->type != OSPF6_ROUTER_LSD_TYPE_POINTTOPOINT)
+ return 0;
+ if (router_lsd2->type != OSPF6_ROUTER_LSD_TYPE_POINTTOPOINT)
+ return 0;
+ if (router_lsd1->neighbor_router_id != lsa_header2->advrtr)
+ return 0;
+ if (router_lsd2->neighbor_router_id != lsa_header1->advrtr)
+ return 0;
+ if (router_lsd1->neighbor_interface_id != router_lsd2->interface_id)
+ return 0;
+ if (router_lsd2->neighbor_interface_id != router_lsd1->interface_id)
+ return 0;
+ return 1;
+}
+
+int
+ospf6_lsa_lsd_is_refer_ok (int index1, struct ospf6_lsa_header *lsa_header1,
+ int index2, struct ospf6_lsa_header *lsa_header2)
+{
+ struct ospf6_router_lsd *r1, *r2;
+ struct ospf6_network_lsd *n;
+
+ r1 = (struct ospf6_router_lsd *) NULL;
+ r2 = (struct ospf6_router_lsd *) NULL;
+ n = (struct ospf6_network_lsd *) NULL;
+ if (lsa_header1->type == htons (OSPF6_LSA_TYPE_ROUTER))
+ r1 = (struct ospf6_router_lsd *) ospf6_lsa_lsd_get (index1, lsa_header1);
+ else
+ n = (struct ospf6_network_lsd *) ospf6_lsa_lsd_get (index1, lsa_header1);
+
+ if (lsa_header2->type == htons (OSPF6_LSA_TYPE_ROUTER))
+ r2 = (struct ospf6_router_lsd *) ospf6_lsa_lsd_get (index2, lsa_header2);
+ else
+ n = (struct ospf6_network_lsd *) ospf6_lsa_lsd_get (index2, lsa_header2);
+
+ if (r1 && r2)
+ return ospf6_lsa_lsd_router_reference_match (r1, lsa_header1,
+ r2, lsa_header2);
+ else if (r1 && n)
+ return ospf6_lsa_lsd_network_reference_match (n, lsa_header2,
+ r1, lsa_header1);
+ else if (n && r2)
+ return ospf6_lsa_lsd_network_reference_match (n, lsa_header1,
+ r2, lsa_header2);
+ return 0;
+}
+
+void
+ospf6_lsa_show (struct vty *vty, struct ospf6_lsa *lsa)
+{
+ char adv_router[64], id[64], type[32];
+
+ assert (lsa);
+ assert (lsa->header);
+
+ ospf6_lsa_type_string (lsa->header->type, type, sizeof (type));
+ inet_ntop (AF_INET, &lsa->header->id, id, sizeof (id));
+ inet_ntop (AF_INET, &lsa->header->adv_router,
+ adv_router, sizeof (adv_router));
+
+ vty_out (vty, "%s", VTY_NEWLINE);
+ vty_out (vty, "Age: %4hu Type: %s%s", ospf6_lsa_age_current (lsa),
+ type, VTY_NEWLINE);
+ vty_out (vty, "Link State ID: %s%s", id, VTY_NEWLINE);
+ vty_out (vty, "Advertising Router: %s%s", adv_router, VTY_NEWLINE);
+ vty_out (vty, "LS Sequence Number: %#lx%s", (u_long)ntohl (lsa->header->seqnum),
+ VTY_NEWLINE);
+ vty_out (vty, "CheckSum: %#hx Length: %hu%s", ntohs (lsa->header->checksum),
+ ntohs (lsa->header->length), VTY_NEWLINE);
+
+ {
+ struct ospf6_lsa_slot *slot;
+ slot = ospf6_lsa_slot_get (lsa->header->type);
+ if (slot)
+ {
+ (*slot->func_show) (vty, lsa);
+ vty_out (vty, "%s", VTY_NEWLINE);
+ return;
+ }
+ }
+
+ vty_out (vty, "%sUnknown LSA type ...%s", VTY_NEWLINE, VTY_NEWLINE);
+}
+
+void
+ospf6_lsa_show_summary_header (struct vty *vty)
+{
+ vty_out (vty, "%-12s %-15s %-15s %4s %8s %4s %4s %-8s%s",
+ "Type", "LSId", "AdvRouter", "Age", "SeqNum",
+ "Cksm", "Len", "Duration", VTY_NEWLINE);
+}
+
+void
+ospf6_lsa_show_summary (struct vty *vty, struct ospf6_lsa *lsa)
+{
+ char adv_router[16], id[16], type[16];
+ struct timeval now, res;
+ char duration[16];
+
+ assert (lsa);
+ assert (lsa->header);
+
+ memset (type, 0, sizeof (type));
+ ospf6_lsa_type_string (lsa->header->type, type, 13);
+ inet_ntop (AF_INET, &lsa->header->id, id, sizeof (id));
+ inet_ntop (AF_INET, &lsa->header->adv_router, adv_router,
+ sizeof (adv_router));
+
+ gettimeofday (&now, NULL);
+ ospf6_timeval_sub (&now, &lsa->installed, &res);
+ ospf6_timeval_string_summary (&res, duration, sizeof (duration));
+
+ vty_out (vty, "%-12s %-15s %-15s %4hu %8lx %04hx %4hu %8s%s",
+ type, id, adv_router, ospf6_lsa_age_current (lsa),
+ (u_long) ntohl (lsa->header->seqnum),
+ ntohs (lsa->header->checksum), ntohs (lsa->header->length),
+ duration, VTY_NEWLINE);
+}
+
+void
+ospf6_lsa_show_dump (struct vty *vty, struct ospf6_lsa *lsa)
+{
+ u_char *start, *end, *current;
+ char byte[4];
+
+ start = (char *) lsa->header;
+ end = (char *) lsa->header + ntohs (lsa->header->length);
+
+ vty_out (vty, "%s", VTY_NEWLINE);
+ vty_out (vty, "%s:%s", lsa->str, VTY_NEWLINE);
+
+ for (current = start; current < end; current ++)
+ {
+ if ((current - start) % 16 == 0)
+ vty_out (vty, "%s ", VTY_NEWLINE);
+ else if ((current - start) % 4 == 0)
+ vty_out (vty, " ");
+
+ snprintf (byte, sizeof (byte), "%02x", *current);
+ vty_out (vty, "%s", byte);
+ }
+
+ vty_out (vty, "%s%s", VTY_NEWLINE, VTY_NEWLINE);
+}
+
+/* OSPFv3 LSA creation/deletion function */
+
+/* calculate LS sequence number for my new LSA.
+ return value is network byte order */
+static signed long
+ospf6_lsa_seqnum_new (u_int16_t type, u_int32_t id, u_int32_t adv_router,
+ void *scope)
+{
+ struct ospf6_lsa *lsa;
+ signed long seqnum;
+
+ /* get current database copy */
+ lsa = ospf6_lsdb_lookup (type, id, adv_router, scope);
+
+ /* if current database copy not found, return InitialSequenceNumber */
+ if (!lsa)
+ seqnum = INITIAL_SEQUENCE_NUMBER;
+ else
+ seqnum = (signed long) ntohl (lsa->header->seqnum) + 1;
+
+ return (htonl (seqnum));
+}
+
+#if 0
+static void
+ospf6_lsa_header_set (u_int16_t type, u_int32_t ls_id, u_int32_t advrtr,
+ struct ospf6_lsa_header *lsa_header, int bodysize)
+{
+ /* fill LSA header */
+ lsa_header->age = 0;
+ lsa_header->type = type;
+ lsa_header->ls_id = ls_id;
+ lsa_header->advrtr = advrtr;
+ lsa_header->seqnum =
+ ospf6_lsa_seqnum_new (lsa_header->type, lsa_header->ls_id,
+ lsa_header->advrtr);
+ lsa_header->length = htons (sizeof (struct ospf6_lsa_header) + bodysize);
+
+ /* LSA checksum */
+ ospf6_lsa_checksum (lsa_header);
+}
+#endif /*0*/
+
+struct ospf6_lsa *
+ospf6_lsa_create (struct ospf6_lsa_header *source)
+{
+ struct ospf6_lsa *lsa = NULL;
+ struct ospf6_lsa_header *lsa_header = NULL;
+ u_int16_t lsa_size = 0;
+ char buf_router[16], buf_id[16], typebuf[32];
+
+ /* whole length of this LSA */
+ lsa_size = ntohs (source->length);
+
+ /* allocate memory for this LSA */
+ lsa_header = (struct ospf6_lsa_header *)
+ XMALLOC (MTYPE_OSPF6_LSA, lsa_size);
+ if (! lsa_header)
+ {
+ zlog_err ("Can't allocate memory for LSA Header");
+ return (struct ospf6_lsa *) NULL;
+ }
+ memset (lsa_header, 0, lsa_size);
+
+ /* copy LSA from source */
+ memcpy (lsa_header, source, lsa_size);
+
+ /* LSA information structure */
+ /* allocate memory */
+ lsa = (struct ospf6_lsa *)
+ XMALLOC (MTYPE_OSPF6_LSA, sizeof (struct ospf6_lsa));
+ memset (lsa, 0, sizeof (struct ospf6_lsa));
+
+ lsa->lsa_hdr = (struct ospf6_lsa_hdr *) lsa_header;
+ lsa->header = (struct ospf6_lsa_header__ *) lsa_header;
+
+ lsa->summary = 0; /* this is not LSA summary */
+
+ /* dump string */
+ inet_ntop (AF_INET, &lsa->header->id, buf_id, sizeof (buf_id));
+ inet_ntop (AF_INET, &lsa->header->adv_router, buf_router,
+ sizeof (buf_router));
+ snprintf (lsa->str, sizeof (lsa->str), "[%s ID=%s Adv=%s]",
+ ospf6_lsa_type_string (lsa_header->type, typebuf,
+ sizeof (typebuf)),
+ buf_id, buf_router);
+
+ /* calculate birth, expire and refresh of this lsa */
+ ospf6_lsa_age_set (lsa);
+
+#ifdef DEBUG
+ if (IS_OSPF6_DUMP_LSA)
+ zlog_info ("Create: %s (%p/%p)", lsa->str, lsa, lsa->header);
+#endif /*DEBUG*/
+
+ return lsa;
+}
+
+struct ospf6_lsa *
+ospf6_lsa_summary_create (struct ospf6_lsa_header__ *source)
+{
+ struct ospf6_lsa *lsa = NULL;
+ struct ospf6_lsa_header *lsa_header = NULL;
+ u_int16_t lsa_size = 0;
+ char buf_router[16], buf_id[16], typebuf[16];
+
+ /* LSA summary contains LSA Header only */
+ lsa_size = sizeof (struct ospf6_lsa_header);
+
+ /* allocate memory for this LSA */
+ lsa_header = (struct ospf6_lsa_header *)
+ XMALLOC (MTYPE_OSPF6_LSA_SUMMARY, lsa_size);
+ memset (lsa_header, 0, lsa_size);
+
+ /* copy LSA from source */
+ memcpy (lsa_header, source, lsa_size);
+
+ /* LSA information structure */
+ /* allocate memory */
+ lsa = (struct ospf6_lsa *)
+ XMALLOC (MTYPE_OSPF6_LSA_SUMMARY, sizeof (struct ospf6_lsa));
+ memset (lsa, 0, sizeof (struct ospf6_lsa));
+
+ lsa->lsa_hdr = (struct ospf6_lsa_hdr *) lsa_header;
+ lsa->header = (struct ospf6_lsa_header__ *) lsa_header;
+ lsa->summary = 1; /* this is LSA summary */
+
+ /* dump string */
+ inet_ntop (AF_INET, &lsa->header->id, buf_id, sizeof (buf_id));
+ inet_ntop (AF_INET, &lsa->header->adv_router, buf_router,
+ sizeof (buf_router));
+ snprintf (lsa->str, sizeof (lsa->str), "[%s Summary ID=%s Adv=%s]",
+ ospf6_lsa_type_string (lsa->header->type, typebuf,
+ sizeof (typebuf)),
+ buf_id, buf_router);
+
+ /* calculate birth, expire and refresh of this lsa */
+ ospf6_lsa_age_set (lsa);
+
+#ifdef DEBUG
+ if (IS_OSPF6_DUMP_LSA)
+ zlog_info ("Create: %s (%p/%p)", lsa->str, lsa, lsa->header);
+#endif /*DEBUG*/
+
+ return lsa;
+}
+
+void
+ospf6_lsa_delete (struct ospf6_lsa *lsa)
+{
+ /* just to make sure */
+ if (lsa->lock != 0)
+ {
+ zlog_err ("Can't delete %s: lock: %ld", lsa->str, lsa->lock);
+ return;
+ }
+
+ /* cancel threads */
+ if (lsa->expire)
+ thread_cancel (lsa->expire);
+ lsa->expire = (struct thread *) NULL;
+ if (lsa->refresh)
+ thread_cancel (lsa->refresh);
+ lsa->refresh = (struct thread *) NULL;
+
+#ifdef DEBUG
+ if (IS_OSPF6_DUMP_LSA)
+ zlog_info ("Delete %s (%p/%p)", lsa->str, lsa, lsa->header);
+#endif /*DEBUG*/
+
+ /* do free */
+ if (lsa->summary)
+ XFREE (MTYPE_OSPF6_LSA_SUMMARY, lsa->header);
+ else
+ XFREE (MTYPE_OSPF6_LSA, lsa->header);
+ lsa->header = NULL;
+
+ if (lsa->summary)
+ XFREE (MTYPE_OSPF6_LSA_SUMMARY, lsa);
+ else
+ XFREE (MTYPE_OSPF6_LSA, lsa);
+}
+
+/* increment reference counter of struct ospf6_lsa */
+void
+ospf6_lsa_lock (struct ospf6_lsa *lsa)
+{
+ lsa->lock++;
+ return;
+}
+
+/* decrement reference counter of struct ospf6_lsa */
+void
+ospf6_lsa_unlock (struct ospf6_lsa *lsa)
+{
+ /* decrement reference counter */
+ if (lsa->lock > 0)
+ lsa->lock--;
+ else
+ zlog_warn ("Can't unlock %s: already no lock", lsa->str);
+
+ if (lsa->lock == 0)
+ ospf6_lsa_delete (lsa);
+}
+
+void
+ospf6_lsa_originate (u_int16_t type, u_int32_t id, u_int32_t adv_router,
+ char *data, int data_len, void *scope)
+{
+ char buffer[MAXLSASIZE];
+ struct ospf6_lsa_header *lsa_header;
+ struct ospf6_lsa *lsa;
+ struct ospf6_lsa *old;
+
+ assert (data_len <= sizeof (buffer) - sizeof (struct ospf6_lsa_header));
+
+ lsa_header = (struct ospf6_lsa_header *) buffer;
+
+ /* Copy LSA Body */
+ memcpy (buffer + sizeof (struct ospf6_lsa_header), data, data_len);
+
+ /* Fill LSA Header */
+ lsa_header->age = 0;
+ lsa_header->type = type;
+ lsa_header->ls_id = id;
+ lsa_header->advrtr = adv_router;
+ lsa_header->seqnum =
+ ospf6_lsa_seqnum_new (lsa_header->type, lsa_header->ls_id,
+ lsa_header->advrtr, scope);
+ lsa_header->length = htons (sizeof (struct ospf6_lsa_header) + data_len);
+
+ /* LSA checksum */
+ ospf6_lsa_checksum (lsa_header);
+
+ /* create LSA */
+ lsa = ospf6_lsa_create ((struct ospf6_lsa_header *) buffer);
+ lsa->scope = scope;
+
+ /* find previous LSA */
+ old = ospf6_lsdb_lookup (lsa->header->type, lsa->header->id,
+ lsa->header->adv_router, lsa->scope);
+ if (old)
+ {
+ /* Check if this is neither different instance nor refresh, return */
+ if (! CHECK_FLAG (old->flag, OSPF6_LSA_FLAG_REFRESH) &&
+ ! ospf6_lsa_differ (lsa, old))
+ {
+ if (IS_OSPF6_DUMP_LSA)
+ zlog_info ("LSA: Suppress updating %s", lsa->str);
+ ospf6_lsa_delete (lsa);
+ return;
+ }
+ }
+
+ lsa->refresh = thread_add_timer (master, ospf6_lsa_refresh, lsa,
+ OSPF6_LS_REFRESH_TIME);
+ gettimeofday (&lsa->originated, NULL);
+
+ //if (IS_OSPF6_DUMP_LSA)
+ zlog_info ("LSA: originate %s seq: %#x age: %hu %ld.%06ld",
+ lsa->str, ntohl (lsa->header->seqnum),
+ ospf6_lsa_age_current (lsa),
+ lsa->originated.tv_sec, lsa->originated.tv_usec);
+
+ ospf6_dbex_remove_from_all_retrans_list (lsa);
+ ospf6_dbex_flood (lsa, NULL);
+ ospf6_lsdb_install (lsa);
+}
+
+
+/* ospf6_lsa expired */
+int
+ospf6_lsa_expire (struct thread *thread)
+{
+ struct ospf6_lsa *lsa;
+ struct ospf6_lsdb *lsdb = NULL;
+ void (*hook) (struct ospf6_lsa *, struct ospf6_lsa *);
+
+ lsa = (struct ospf6_lsa *) THREAD_ARG (thread);
+ assert (lsa && lsa->lsa_hdr);
+
+ /* assertion */
+ assert (IS_LSA_MAXAGE (lsa));
+ assert (!lsa->refresh);
+
+ lsa->expire = (struct thread *) NULL;
+
+ /* log */
+ if (IS_OSPF6_DUMP_LSA)
+ zlog_info ("LSA: Expire: %s", lsa->str);
+
+ if (!lsa->summary)
+ {
+ /* reflood lsa */
+ ospf6_dbex_flood (lsa, NULL);
+
+ /* get scoped lsdb, call remove hook */
+ if (OSPF6_LSA_IS_SCOPE_LINKLOCAL (ntohs (lsa->header->type)))
+ lsdb = ((struct ospf6_interface *) lsa->scope)->lsdb;
+ else if (OSPF6_LSA_IS_SCOPE_AREA (ntohs (lsa->header->type)))
+ lsdb = ((struct ospf6_area *) lsa->scope)->lsdb;
+ else if (OSPF6_LSA_IS_SCOPE_AS (ntohs (lsa->header->type)))
+ lsdb = ((struct ospf6 *) lsa->scope)->lsdb;
+ else
+ assert (0);
+
+ /* call LSDB hook to re-process LSA */
+ hook = ospf6_lsdb_hook[ntohs (lsa->header->type) &
+ OSPF6_LSTYPE_CODE_MASK].hook;
+ if (hook)
+ (*hook) (NULL, lsa);
+
+ /* do not free LSA, and do nothing about lslists.
+ wait event (ospf6_lsdb_check_maxage) */
+ }
+
+ return 0;
+}
+
+int
+ospf6_lsa_refresh (struct thread *thread)
+{
+ struct ospf6_lsa *lsa;
+ struct ospf6_lsa_slot *slot;
+
+ assert (thread);
+ lsa = (struct ospf6_lsa *) THREAD_ARG (thread);
+ assert (lsa && lsa->lsa_hdr);
+
+ /* this will be used later as flag to decide really originate */
+ lsa->refresh = (struct thread *) NULL;
+ SET_FLAG (lsa->flag, OSPF6_LSA_FLAG_REFRESH);
+
+ /* log */
+ if (IS_OSPF6_DUMP_LSA)
+ zlog_info ("LSA Refresh: %s", lsa->str);
+
+ slot = ospf6_lsa_slot_get (lsa->header->type);
+ if (slot)
+ {
+ zlog_info ("LSA Refresh: %s", slot->name);
+ (*slot->func_refresh) (lsa);
+ return 0;
+ }
+
+ zlog_warn ("Can't Refresh LSA: Unknown type: %#x",
+ ntohs (lsa->header->type));
+ return 1;
+}
+
+
+
+/* enhanced Fletcher checksum algorithm, RFC1008 7.2 */
+#define MODX 4102
+#define LSA_CHECKSUM_OFFSET 15
+
+unsigned short
+ospf6_lsa_checksum (struct ospf6_lsa_header *lsa_header)
+{
+ u_char *sp, *ep, *p, *q;
+ int c0 = 0, c1 = 0;
+ int x, y;
+ u_int16_t length;
+
+ lsa_header->checksum = 0;
+ length = ntohs (lsa_header->length) - 2;
+ sp = (char *) &lsa_header->type;
+
+ for (ep = sp + length; sp < ep; sp = q)
+ {
+ q = sp + MODX;
+ if (q > ep)
+ q = ep;
+ for (p = sp; p < q; p++)
+ {
+ c0 += *p;
+ c1 += c0;
+ }
+ c0 %= 255;
+ c1 %= 255;
+ }
+
+ /* r = (c1 << 8) + c0; */
+ x = ((length - LSA_CHECKSUM_OFFSET) * c0 - c1) % 255;
+ if (x <= 0)
+ x += 255;
+ y = 510 - c0 - x;
+ if (y > 255)
+ y -= 255;
+
+ lsa_header->checksum = htons ((x << 8) + y);
+
+ return (lsa_header->checksum);
+}
+
+int
+ospf6_lsa_is_known_type (struct ospf6_lsa_header *lsa_header)
+{
+ struct ospf6_lsa_slot *slot;
+
+ slot = ospf6_lsa_slot_get (lsa_header->type);
+ if (slot)
+ return 1;
+ return 0;
+}
+
+struct ospf6_lsa_slot *slot_head = NULL;
+
+struct ospf6_lsa_slot *
+ospf6_lsa_slot_get (u_int16_t type)
+{
+ struct ospf6_lsa_slot *slot;
+
+ for (slot = slot_head; slot; slot = slot->next)
+ {
+ if (slot->type == type)
+ return slot;
+ }
+
+ return NULL;
+}
+
+int
+ospf6_lsa_slot_register (struct ospf6_lsa_slot *src)
+{
+ struct ospf6_lsa_slot *new, *slot;
+
+ slot = ospf6_lsa_slot_get (src->type);
+ if (slot)
+ {
+ if (IS_OSPF6_DUMP_LSA)
+ zlog_info ("LSA: Slot register: already exists: %#x %s",
+ slot->type, slot->name);
+ return -1;
+ }
+
+ new = (struct ospf6_lsa_slot *)
+ XMALLOC (MTYPE_OSPF6_LSA, sizeof (struct ospf6_lsa_slot));
+ if (! new)
+ {
+ zlog_err ("Can't allocate memory for LSA slot: %s", strerror (errno));
+ return -1;
+ }
+ memset (new, 0, sizeof (struct ospf6_lsa_slot));
+ memcpy (new, src, sizeof (struct ospf6_lsa_slot));
+
+ if (IS_OSPF6_DUMP_LSA)
+ zlog_info ("LSA: Slot register: %#x %s", slot->type, slot->name);
+
+ if (slot_head == NULL)
+ {
+ new->prev = NULL;
+ new->next = NULL;
+ slot_head = new;
+ return 0;
+ }
+
+ slot = slot_head;
+ while (slot->next)
+ slot = slot->next;
+
+ slot->next = new;
+ new->prev = slot;
+
+ return 0;
+}
+
+int
+ospf6_lsa_slot_unregister (u_int16_t type)
+{
+ struct ospf6_lsa_slot *slot;
+
+ slot = ospf6_lsa_slot_get (type);
+ if (slot == NULL)
+ {
+ if (IS_OSPF6_DUMP_LSA)
+ zlog_info ("Registering LSA slot: no such slot: %#x", type);
+ return -1;
+ }
+
+ if (IS_OSPF6_DUMP_LSA)
+ zlog_info ("Unregistering LSA Slot: %#x %s", slot->type, slot->name);
+
+ if (slot->prev)
+ slot->prev->next = slot->next;
+ if (slot->next)
+ slot->next->prev = slot->prev;
+
+ if (slot_head == slot)
+ slot_head = slot->next;
+
+ XFREE (MTYPE_OSPF6_LSA, slot);
+ return 0;
+}
+
+char *
+ospf6_lsa_type_string (u_int16_t type, char *buf, int bufsize)
+{
+ struct ospf6_lsa_slot *slot;
+
+ slot = ospf6_lsa_slot_get (type);
+ if (slot)
+ snprintf (buf, bufsize, "%s", slot->name);
+ else
+ snprintf (buf, bufsize, "Type=0x%04x", ntohs (type));
+
+ return buf;
+}
+
+
+/*******************/
+/* LSA Origination */
+/*******************/
+
+#define CONTINUE_IF_ADDRESS_LINKLOCAL(addr)\
+ if (IN6_IS_ADDR_LINKLOCAL (&(addr)->u.prefix6))\
+ {\
+ char buf[64];\
+ prefix2str (addr, buf, sizeof (buf));\
+ if (IS_OSPF6_DUMP_LSA)\
+ zlog_info (" Filter out Linklocal: %s", buf);\
+ continue;\
+ }
+
+#define CONTINUE_IF_ADDRESS_UNSPECIFIED(addr)\
+ if (IN6_IS_ADDR_UNSPECIFIED (&(addr)->u.prefix6))\
+ {\
+ char buf[64];\
+ prefix2str (addr, buf, sizeof (buf));\
+ if (IS_OSPF6_DUMP_LSA)\
+ zlog_info (" Filter out Unspecified: %s", buf);\
+ continue;\
+ }
+
+#define CONTINUE_IF_ADDRESS_LOOPBACK(addr)\
+ if (IN6_IS_ADDR_LOOPBACK (&(addr)->u.prefix6))\
+ {\
+ char buf[64];\
+ prefix2str (addr, buf, sizeof (buf));\
+ if (IS_OSPF6_DUMP_LSA)\
+ zlog_info (" Filter out Loopback: %s", buf);\
+ continue;\
+ }
+
+#define CONTINUE_IF_ADDRESS_V4COMPAT(addr)\
+ if (IN6_IS_ADDR_V4COMPAT (&(addr)->u.prefix6))\
+ {\
+ char buf[64];\
+ prefix2str (addr, buf, sizeof (buf));\
+ if (IS_OSPF6_DUMP_LSA)\
+ zlog_info (" Filter out V4Compat: %s", buf);\
+ continue;\
+ }
+
+#define CONTINUE_IF_ADDRESS_V4MAPPED(addr)\
+ if (IN6_IS_ADDR_V4MAPPED (&(addr)->u.prefix6))\
+ {\
+ char buf[64];\
+ prefix2str (addr, buf, sizeof (buf));\
+ if (IS_OSPF6_DUMP_LSA)\
+ zlog_info (" Filter out V4Mapped: %s", buf);\
+ continue;\
+ }
+
+/******************************/
+/* RFC2740 3.4.3.1 Router-LSA */
+/******************************/
+
+char *
+ospf6_lsa_router_bits_string (u_char router_bits, char *buf, int size)
+{
+ char w, v, e, b;
+
+ w = (router_bits & OSPF6_ROUTER_LSA_BIT_W ? 'W' : '-');
+ v = (router_bits & OSPF6_ROUTER_LSA_BIT_V ? 'V' : '-');
+ e = (router_bits & OSPF6_ROUTER_LSA_BIT_E ? 'E' : '-');
+ b = (router_bits & OSPF6_ROUTER_LSA_BIT_B ? 'B' : '-');
+ snprintf (buf, size, "----%c%c%c%c", w, v, e, b);
+ return buf;
+}
+
+int
+ospf6_lsa_router_show (struct vty *vty, struct ospf6_lsa *lsa)
+{
+ char *start, *end, *current;
+ char buf[32], name[32], bits[32], options[32];
+ struct ospf6_router_lsa *router_lsa;
+ struct ospf6_router_lsd *lsdesc;
+
+ assert (lsa->header);
+
+ router_lsa = (struct ospf6_router_lsa *)
+ ((char *) lsa->header + sizeof (struct ospf6_lsa_header));
+
+ ospf6_lsa_router_bits_string (router_lsa->bits, bits, sizeof (bits));
+ ospf6_options_string (router_lsa->options, options, sizeof (options));
+ vty_out (vty, " Bits: %s Options: %s%s", bits, options, VTY_NEWLINE);
+
+ start = (char *) router_lsa + sizeof (struct ospf6_router_lsa);
+ end = (char *) lsa->header + ntohs (lsa->header->length);
+ for (current = start; current + sizeof (struct ospf6_router_lsd) <= end;
+ current += sizeof (struct ospf6_router_lsd))
+ {
+ lsdesc = (struct ospf6_router_lsd *) current;
+
+ if (lsdesc->type == OSPF6_ROUTER_LSD_TYPE_POINTTOPOINT)
+ snprintf (name, sizeof (name), "Point-To-Point");
+ else if (lsdesc->type == OSPF6_ROUTER_LSD_TYPE_TRANSIT_NETWORK)
+ snprintf (name, sizeof (name), "Transit-Network");
+ else if (lsdesc->type == OSPF6_ROUTER_LSD_TYPE_STUB_NETWORK)
+ snprintf (name, sizeof (name), "Stub-Network");
+ else if (lsdesc->type == OSPF6_ROUTER_LSD_TYPE_VIRTUAL_LINK)
+ snprintf (name, sizeof (name), "Virtual-Link");
+ else
+ snprintf (name, sizeof (name), "Unknown (%#x)", lsdesc->type);
+
+ vty_out (vty, " Type: %s Metric: %d%s",
+ name, ntohs (lsdesc->metric), VTY_NEWLINE);
+ vty_out (vty, " Interface ID: %s%s",
+ inet_ntop (AF_INET, &lsdesc->interface_id,
+ buf, sizeof (buf)), VTY_NEWLINE);
+ vty_out (vty, " Neighbor Interface ID: %s%s",
+ inet_ntop (AF_INET, &lsdesc->neighbor_interface_id,
+ buf, sizeof (buf)), VTY_NEWLINE);
+ vty_out (vty, " Neighbor Router ID: %s%s",
+ inet_ntop (AF_INET, &lsdesc->neighbor_router_id,
+ buf, sizeof (buf)), VTY_NEWLINE);
+ }
+ return 0;
+}
+
+u_long
+ospf6_lsa_has_elasped (u_int16_t type, u_int32_t id,
+ u_int32_t adv_router, void *scope)
+{
+ struct ospf6_lsa *old;
+ struct timeval now;
+
+ if (adv_router != ospf6->router_id)
+ zlog_info ("LSA: Router-ID changed ?");
+
+ old = ospf6_lsdb_lookup (type, id, adv_router, scope);
+ if (! old)
+ return OSPF6_LSA_MAXAGE;
+
+ gettimeofday (&now, NULL);
+ return ((u_long) SEC_TVDIFF (&now, &old->originated));
+}
+
+int
+ospf6_lsa_originate_router (struct thread *thread)
+{
+ char buffer [MAXLSASIZE];
+ u_int16_t size;
+ struct ospf6_area *o6a;
+ int count;
+ u_int32_t area_id;
+
+ struct ospf6_router_lsa *router_lsa;
+ struct ospf6_router_lsd *router_lsd;
+ listnode i;
+ struct ospf6_interface *o6i;
+ struct ospf6_neighbor *o6n = NULL;
+
+ area_id = (u_int32_t) THREAD_ARG (thread);
+
+ o6a = ospf6_area_lookup (area_id, ospf6);
+ if (! o6a)
+ {
+ inet_ntop (AF_INET, &area_id, buffer, sizeof (buffer));
+ if (IS_OSPF6_DUMP_LSA)
+ zlog_info ("LSA: Update Router-LSA: No such area: %s", buffer);
+ return 0;
+ }
+
+ /* clear thread */
+ o6a->thread_router_lsa = NULL;
+
+ if (IS_OSPF6_DUMP_LSA)
+ zlog_info ("LSA: originate Router-LSA for Area %s", o6a->str);
+
+ size = sizeof (struct ospf6_router_lsa);
+ memset (buffer, 0, sizeof (buffer));
+ router_lsa = (struct ospf6_router_lsa *) buffer;
+
+ OSPF6_OPT_CLEAR_ALL (router_lsa->options);
+ OSPF6_OPT_SET (router_lsa->options, OSPF6_OPT_V6);
+ OSPF6_OPT_SET (router_lsa->options, OSPF6_OPT_E);
+ OSPF6_OPT_CLEAR (router_lsa->options, OSPF6_OPT_MC);
+ OSPF6_OPT_CLEAR (router_lsa->options, OSPF6_OPT_N);
+ OSPF6_OPT_SET (router_lsa->options, OSPF6_OPT_R);
+ OSPF6_OPT_CLEAR (router_lsa->options, OSPF6_OPT_DC);
+
+ OSPF6_ROUTER_LSA_CLEAR_ALL_BITS (router_lsa);
+ OSPF6_ROUTER_LSA_CLEAR (router_lsa, OSPF6_ROUTER_LSA_BIT_B);
+
+ if (ospf6_is_asbr (o6a->ospf6))
+ OSPF6_ROUTER_LSA_SET (router_lsa, OSPF6_ROUTER_LSA_BIT_E);
+ else
+ OSPF6_ROUTER_LSA_CLEAR (router_lsa, OSPF6_ROUTER_LSA_BIT_E);
+
+ OSPF6_ROUTER_LSA_CLEAR (router_lsa, OSPF6_ROUTER_LSA_BIT_V);
+ OSPF6_ROUTER_LSA_CLEAR (router_lsa, OSPF6_ROUTER_LSA_BIT_W);
+
+ /* describe links for each interfaces */
+ router_lsd = (struct ospf6_router_lsd *) (router_lsa + 1);
+ for (i = listhead (o6a->if_list); i; nextnode (i))
+ {
+ o6i = (struct ospf6_interface *) getdata (i);
+ assert (o6i);
+
+ /* Interfaces in state Down or Loopback are not described */
+ if (o6i->state == IFS_DOWN || o6i->state == IFS_LOOPBACK)
+ continue;
+
+ /* Nor are interfaces without any full adjacencies described */
+ count = 0;
+ o6i->foreach_nei (o6i, &count, NBS_FULL, ospf6_count_state);
+ if (count == 0)
+ continue;
+
+ /* Point-to-Point interfaces */
+ if (if_is_pointopoint (o6i->interface))
+ {
+ if (listcount (o6i->neighbor_list) == 0)
+ continue;
+
+ if (listcount (o6i->neighbor_list) != 1)
+ zlog_warn ("LSA: Multiple neighbors on PoinToPoint: %s",
+ o6i->interface->name);
+
+ o6n = (struct ospf6_neighbor *)
+ getdata (listhead (o6i->neighbor_list));
+ assert (o6n);
+
+ router_lsd->type = OSPF6_ROUTER_LSD_TYPE_POINTTOPOINT;
+ router_lsd->metric = htons (o6i->cost);
+ router_lsd->interface_id = htonl (o6i->if_id);
+ router_lsd->neighbor_interface_id = htonl (o6n->ifid);
+ router_lsd->neighbor_router_id = o6n->router_id;
+
+ size += sizeof (struct ospf6_router_lsd);
+ router_lsd ++;
+
+ continue;
+ }
+
+ /* Broadcast and NBMA interfaces */
+ if (if_is_broadcast (o6i->interface))
+ {
+ /* If this router is not DR,
+ and If this router not fully adjacent with DR,
+ this interface is not transit yet: ignore. */
+ if (o6i->state != IFS_DR)
+ {
+ o6n = ospf6_neighbor_lookup (o6i->dr, o6i); /* find DR */
+ if (o6n == NULL || o6n->state != NBS_FULL)
+ continue;
+ }
+ else
+ {
+ count = 0;
+ o6i->foreach_nei (o6i, &count, NBS_FULL, ospf6_count_state);
+ if (count == 0)
+ continue;
+ }
+
+ router_lsd->type = OSPF6_ROUTER_LSD_TYPE_TRANSIT_NETWORK;
+ router_lsd->metric = htons (o6i->cost);
+ router_lsd->interface_id = htonl (o6i->if_id);
+ if (o6i->state != IFS_DR)
+ {
+ router_lsd->neighbor_interface_id = htonl (o6n->ifid);
+ router_lsd->neighbor_router_id = o6n->router_id;
+ }
+ else
+ {
+ router_lsd->neighbor_interface_id = htonl (o6i->if_id);
+ router_lsd->neighbor_router_id = o6i->area->ospf6->router_id;
+ }
+
+ size += sizeof (struct ospf6_router_lsd);
+ router_lsd ++;
+
+ continue;
+ }
+
+ /* Virtual links */
+ /* xxx */
+ /* Point-to-Multipoint interfaces */
+ /* xxx */
+ }
+
+ ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_ROUTER),
+ htonl (0), o6a->ospf6->router_id,
+ (char *) router_lsa, size, o6a);
+ return 0;
+}
+
+void
+ospf6_lsa_schedule_router (struct ospf6_area *area)
+{
+ u_long elasped_time, time = 0;
+
+ if (area->thread_router_lsa)
+ {
+ if (IS_OSPF6_DUMP_LSA)
+ zlog_info ("LSA: schedule: Router-LSA for Area %s: another thread",
+ area->str);
+ return;
+ }
+
+ elasped_time =
+ ospf6_lsa_has_elasped (htons (OSPF6_LSA_TYPE_ROUTER), htonl (0),
+ area->ospf6->router_id, area);
+ if (elasped_time < OSPF6_MIN_LS_INTERVAL)
+ time = (u_long) (OSPF6_MIN_LS_INTERVAL - elasped_time);
+ else
+ time = 0;
+
+ if (IS_OSPF6_DUMP_LSA)
+ zlog_info ("LSA: schedule: Router-LSA for Area %s after %lu sec",
+ area->str, time);
+
+ if (time)
+ area->thread_router_lsa =
+ thread_add_timer (master, ospf6_lsa_originate_router,
+ (void *) area->area_id, time);
+ else
+ area->thread_router_lsa =
+ thread_add_event (master, ospf6_lsa_originate_router,
+ (void *) area->area_id, 0);
+}
+
+int
+ospf6_lsa_router_hook_neighbor (void *neighbor)
+{
+ struct ospf6_neighbor *o6n = neighbor;
+ if (o6n->ospf6_interface->area)
+ ospf6_lsa_schedule_router (o6n->ospf6_interface->area);
+ return 0;
+}
+
+int
+ospf6_lsa_router_hook_interface (void *interface)
+{
+ struct ospf6_interface *o6i = interface;
+ if (o6i->area)
+ ospf6_lsa_schedule_router (o6i->area);
+ return 0;
+}
+
+int
+ospf6_lsa_router_hook_area (void *area)
+{
+ struct ospf6_area *o6a = area;
+ ospf6_lsa_schedule_router (o6a);
+ return 0;
+}
+
+int
+ospf6_lsa_router_hook_top (void *ospf6)
+{
+ struct ospf6 *o6 = ospf6;
+ struct ospf6_area *o6a;
+ listnode node;
+
+ for (node = listhead (o6->area_list); node; nextnode (node))
+ {
+ o6a = getdata (node);
+ ospf6_lsa_schedule_router (o6a);
+ }
+ return 0;
+}
+
+int
+ospf6_lsa_router_refresh (void *old)
+{
+ struct ospf6_lsa *lsa = old;
+ struct ospf6_area *o6a;
+
+ o6a = lsa->scope;
+ ospf6_lsa_schedule_router (o6a);
+ return 0;
+}
+
+void
+ospf6_lsa_slot_register_router ()
+{
+ struct ospf6_lsa_slot slot;
+ struct ospf6_hook hook;
+
+ memset (&slot, 0, sizeof (struct ospf6_lsa_slot));
+ slot.type = htons (OSPF6_LSA_TYPE_ROUTER);
+ slot.name = "Router";
+ slot.func_show = ospf6_lsa_router_show;
+ slot.func_refresh = ospf6_lsa_router_refresh;
+ ospf6_lsa_slot_register (&slot);
+
+ ospf6_lsdb_hook[OSPF6_LSA_TYPE_ROUTER & OSPF6_LSTYPE_CODE_MASK].hook =
+ ospf6_spf_database_hook;
+
+ memset (&hook, 0, sizeof (hook));
+ hook.name = "OriginateRouter";
+ hook.hook_change = ospf6_lsa_router_hook_neighbor;
+ ospf6_hook_register (&hook, &neighbor_hook);
+
+ memset (&hook, 0, sizeof (hook));
+ hook.name = "OriginateRouter";
+ hook.hook_change = ospf6_lsa_router_hook_interface;
+ ospf6_hook_register (&hook, &interface_hook);
+
+ memset (&hook, 0, sizeof (hook));
+ hook.name = "OriginateRouter";
+ hook.hook_change = ospf6_lsa_router_hook_area;
+ ospf6_hook_register (&hook, &area_hook);
+
+ memset (&hook, 0, sizeof (hook));
+ hook.name = "OriginateRouter";
+ hook.hook_change = ospf6_lsa_router_hook_top;
+ ospf6_hook_register (&hook, &top_hook);
+}
+
+/*******************************/
+/* RFC2740 3.4.3.2 Network-LSA */
+/*******************************/
+
+int
+ospf6_lsa_network_show (struct vty *vty, struct ospf6_lsa *lsa)
+{
+ char *start, *end, *current;
+ struct ospf6_network_lsa *network_lsa;
+ u_int32_t *router_id;
+ char buf[128], options[32];
+
+ assert (lsa->header);
+ network_lsa = (struct ospf6_network_lsa *) (lsa->header + 1);
+ router_id = (u_int32_t *)(network_lsa + 1);
+
+ ospf6_options_string (network_lsa->options, options, sizeof (options));
+ vty_out (vty, " Options: %s%s", options, VTY_NEWLINE);
+
+ start = (char *) network_lsa + sizeof (struct ospf6_network_lsa);
+ end = (char *) lsa->header + ntohs (lsa->header->length);
+ for (current = start; current + sizeof (u_int32_t) <= end;
+ current += sizeof (u_int32_t))
+ {
+ router_id = (u_int32_t *) current;
+ inet_ntop (AF_INET, router_id, buf, sizeof (buf));
+ vty_out (vty, " Attached Router: %s%s", buf, VTY_NEWLINE);
+ }
+ return 0;
+}
+
+void
+ospf6_lsa_network_update (char *ifname)
+{
+ char buffer [MAXLSASIZE];
+ u_int16_t size;
+ struct ospf6_lsa *old;
+ struct interface *ifp;
+ struct ospf6_interface *o6i;
+ int count;
+
+ struct ospf6_network_lsa *network_lsa;
+ struct ospf6_neighbor *o6n;
+ u_int32_t *router_id;
+ listnode node;
+
+ ifp = if_lookup_by_name (ifname);
+ if (! ifp)
+ {
+ if (IS_OSPF6_DUMP_LSA)
+ zlog_warn ("Update Network: No such Interface: %s", ifname);
+ return;
+ }
+
+ o6i = (struct ospf6_interface *) ifp->info;
+ if (! o6i || ! o6i->area)
+ {
+ if (IS_OSPF6_DUMP_LSA)
+ zlog_warn ("Update Network: Interface not enabled: %s", ifname);
+ return;
+ }
+
+ /* find previous LSA */
+ old = ospf6_lsdb_lookup (htons (OSPF6_LSA_TYPE_NETWORK),
+ htonl (o6i->if_id),
+ o6i->area->ospf6->router_id, o6i->area);
+
+ /* Don't originate Network-LSA if not DR */
+ if (o6i->state != IFS_DR)
+ {
+ if (IS_OSPF6_DUMP_LSA)
+ zlog_info ("Update Network: Interface %s is not DR",
+ o6i->interface->name);
+ if (old)
+ ospf6_lsa_premature_aging (old);
+ return;
+ }
+
+ /* If none of neighbor is adjacent to us */
+ count = 0;
+ o6i->foreach_nei (o6i, &count, NBS_FULL, ospf6_count_state);
+ if (count == 0)
+ {
+ if (IS_OSPF6_DUMP_LSA)
+ zlog_info ("Update Network: Interface %s is Stub",
+ o6i->interface->name);
+ if (old)
+ ospf6_lsa_premature_aging (old);
+ return;
+ }
+
+ if (IS_OSPF6_DUMP_LSA)
+ zlog_info ("Update Network: Interface %s", o6i->interface->name);
+
+ /* prepare buffer */
+ memset (buffer, 0, sizeof (buffer));
+ size = sizeof (struct ospf6_network_lsa);
+ network_lsa = (struct ospf6_network_lsa *) buffer;
+ router_id = (u_int32_t *)(network_lsa + 1);
+
+ /* set fields of myself */
+ *router_id++ = o6i->area->ospf6->router_id;
+ size += sizeof (u_int32_t);
+ network_lsa->options[0] |= o6i->area->options[0];
+ network_lsa->options[1] |= o6i->area->options[1];
+ network_lsa->options[2] |= o6i->area->options[2];
+
+ /* Walk through neighbors */
+ for (node = listhead (o6i->neighbor_list); node; nextnode (node))
+ {
+ o6n = (struct ospf6_neighbor *) getdata (node);
+
+ if (o6n->state != NBS_FULL)
+ continue;
+
+ /* set this neighbor's Router-ID to LSA */
+ *router_id++ = o6n->router_id;
+ size += sizeof (u_int32_t);
+
+ /* options field is logical OR */
+ network_lsa->options[0] |= o6n->options[0];
+ network_lsa->options[1] |= o6n->options[1];
+ network_lsa->options[2] |= o6n->options[2];
+ }
+
+ ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_NETWORK),
+ htonl (o6i->if_id), o6i->area->ospf6->router_id,
+ (char *) network_lsa, size, o6i->area);
+}
+
+int
+ospf6_lsa_network_hook_neighbor (void *neighbor)
+{
+ struct ospf6_neighbor *o6n = neighbor;
+ ospf6_lsa_network_update (o6n->ospf6_interface->interface->name);
+ return 0;
+}
+
+int
+ospf6_lsa_network_hook_interface (void *interface)
+{
+ struct ospf6_interface *o6i = interface;
+ if (o6i->area)
+ ospf6_lsa_network_update (o6i->interface->name);
+ return 0;
+}
+
+int
+ospf6_lsa_network_refresh (void *old)
+{
+ struct ospf6_lsa *lsa = old;
+ struct interface *ifp;
+
+ ifp = if_lookup_by_index (ntohl (lsa->header->id));
+ if (! ifp)
+ ospf6_lsa_premature_aging (old);
+ else
+ ospf6_lsa_network_update (ifp->name);
+
+ return 0;
+}
+
+void
+ospf6_lsa_slot_register_network ()
+{
+ struct ospf6_lsa_slot slot;
+ struct ospf6_hook hook;
+
+ memset (&slot, 0, sizeof (struct ospf6_lsa_slot));
+ slot.type = htons (OSPF6_LSA_TYPE_NETWORK);
+ slot.name = "Network";
+ slot.func_show = ospf6_lsa_network_show;
+ slot.func_refresh = ospf6_lsa_network_refresh;
+ ospf6_lsa_slot_register (&slot);
+
+ ospf6_lsdb_hook[OSPF6_LSA_TYPE_NETWORK & OSPF6_LSTYPE_CODE_MASK].hook =
+ ospf6_spf_database_hook;
+
+ memset (&hook, 0, sizeof (hook));
+ hook.name = "OriginateNetwork";
+ hook.hook_change = ospf6_lsa_network_hook_neighbor;
+ ospf6_hook_register (&hook, &neighbor_hook);
+
+ memset (&hook, 0, sizeof (hook));
+ hook.name = "OriginateNetwork";
+ hook.hook_change = ospf6_lsa_network_hook_interface;
+ ospf6_hook_register (&hook, &interface_hook);
+}
+
+/****************************/
+/* RFC2740 3.4.3.6 Link-LSA */
+/****************************/
+
+int
+ospf6_lsa_link_show (struct vty *vty, struct ospf6_lsa *lsa)
+{
+ char *start, *end, *current;
+ struct ospf6_link_lsa *link_lsa;
+ int prefixnum;
+ struct ospf6_prefix *prefix;
+ char buf[128];
+ struct in6_addr in6;
+
+ assert (lsa->header);
+
+ link_lsa = (struct ospf6_link_lsa *) (lsa->header + 1);
+ prefixnum = ntohl (link_lsa->llsa_prefix_num);
+
+ inet_ntop (AF_INET6, (void *)&link_lsa->llsa_linklocal, buf, sizeof (buf));
+ vty_out (vty, " LinkLocal Address: %s%s", buf, VTY_NEWLINE);
+ vty_out (vty, " Number of Prefix: %d%s", prefixnum, VTY_NEWLINE);
+
+ start = (char *) link_lsa + sizeof (struct ospf6_link_lsa);
+ end = (char *) lsa->header + ntohs (lsa->header->length);
+ for (current = start; current < end; current += OSPF6_PREFIX_SIZE (prefix))
+ {
+ prefix = (struct ospf6_prefix *) current;
+ if (current + OSPF6_PREFIX_SIZE (prefix) > end)
+ {
+ vty_out (vty, " Trailing %d byte garbage ... Malformed%s",
+ end - current, VTY_NEWLINE);
+ return -1;
+ }
+
+ ospf6_prefix_options_str (prefix->prefix_options, buf, sizeof (buf));
+ vty_out (vty, " Prefix Options: %s%s", buf, VTY_NEWLINE);
+ ospf6_prefix_in6_addr (prefix, &in6);
+ inet_ntop (AF_INET6, &in6, buf, sizeof (buf));
+ vty_out (vty, " Prefix: %s/%d%s",
+ buf, prefix->prefix_length, VTY_NEWLINE);
+ }
+
+ return 0;
+}
+
+
+void
+ospf6_lsa_link_update (char *ifname)
+{
+ char *cp, buffer [MAXLSASIZE], buf[32];
+ u_int16_t size;
+ struct ospf6_lsa *old;
+ struct interface *ifp;
+ struct ospf6_interface *o6i;
+
+ struct ospf6_link_lsa *link_lsa;
+ struct ospf6_prefix *p;
+ list prefix_connected;
+ listnode node;
+ struct connected *c;
+
+ ifp = if_lookup_by_name (ifname);
+ if (! ifp)
+ {
+ if (IS_OSPF6_DUMP_LSA)
+ zlog_info ("Update Link: No such Interface: %s", ifname);
+ return;
+ }
+
+ o6i = (struct ospf6_interface *) ifp->info;
+ if (! o6i || ! o6i->area)
+ {
+ if (IS_OSPF6_DUMP_LSA)
+ zlog_info ("Update Link: Interface not enabled: %s", ifname);
+ return;
+ }
+
+#if 0
+ /* Link-LSA is on Broadcast or NBMA */
+ if (! if_is_broadcast (o6i->interface) /* && ! NBMA xxx */)
+ {
+ return;
+ }
+#endif /*0*/
+
+ /* find previous LSA */
+ old = ospf6_lsdb_lookup (htons (OSPF6_LSA_TYPE_LINK), htonl (o6i->if_id),
+ ospf6->router_id, o6i->area);
+
+ /* can't make Link-LSA if linklocal address not set */
+ if (! o6i->lladdr)
+ {
+ if (IS_OSPF6_DUMP_LSA)
+ zlog_warn ("Update Link: No Linklocal Address: %s",
+ o6i->interface->name);
+ if (old)
+ ospf6_lsa_premature_aging (old);
+ return;
+ }
+
+ if (IS_OSPF6_DUMP_LSA)
+ zlog_info ("Update Link: Interface %s", o6i->interface->name);
+
+ if (! ospf6_interface_is_enabled (o6i->interface->ifindex))
+ {
+ if (IS_OSPF6_DUMP_LSA)
+ zlog_info (" Interface %s not enabled", o6i->interface->name);
+ if (old)
+ ospf6_lsa_premature_aging (old);
+ return;
+ }
+
+ /* check connected prefix */
+ prefix_connected = list_new ();
+ for (node = listhead (o6i->interface->connected); node; nextnode (node))
+ {
+ c = (struct connected *) getdata (node);
+
+ /* filter prefix not IPv6 */
+ if (c->address->family != AF_INET6)
+ continue;
+
+ /* for log */
+ prefix2str (c->address, buf, sizeof (buf));
+
+ CONTINUE_IF_ADDRESS_LINKLOCAL (c->address);
+ CONTINUE_IF_ADDRESS_UNSPECIFIED (c->address);
+ CONTINUE_IF_ADDRESS_LOOPBACK (c->address);
+ CONTINUE_IF_ADDRESS_V4COMPAT (c->address);
+ CONTINUE_IF_ADDRESS_V4MAPPED (c->address);
+
+ /* filter prefix specified by configuration */
+ if (o6i->plist_name)
+ {
+ struct prefix_list *plist;
+ enum prefix_list_type result = PREFIX_PERMIT;
+
+ plist = prefix_list_lookup (AFI_IP6, o6i->plist_name);
+ if (plist)
+ result = prefix_list_apply (plist, c->address);
+ else if (IS_OSPF6_DUMP_LSA)
+ zlog_warn ("Update Intra-Prefix (Stub): "
+ "Prefix list \"%s\" not found", o6i->plist_name);
+
+ if (result == PREFIX_DENY)
+ {
+ if (IS_OSPF6_DUMP_LSA)
+ zlog_info (" Filter out Prefix-list %s: %s",
+ o6i->plist_name, buf);
+ continue;
+ }
+ }
+
+ if (IS_OSPF6_DUMP_LSA)
+ zlog_info (" Advertise %s", buf);
+
+ /* hold prefix in list. duplicate is filtered in ospf6_prefix_add() */
+ p = ospf6_prefix_create (0, 0, (struct prefix_ipv6 *) c->address);
+ ospf6_prefix_add (prefix_connected, p);
+ }
+
+ /* Note: even if no prefix configured, still we have to create Link-LSA
+ for next-hop resolution */
+
+ memset (buffer, 0, sizeof (buffer));
+ size = sizeof (struct ospf6_link_lsa);
+ link_lsa = (struct ospf6_link_lsa *) buffer;
+
+ /* fill Link LSA and calculate size */
+ link_lsa->llsa_rtr_pri = o6i->priority;
+ link_lsa->llsa_options[0] = o6i->area->options[0];
+ link_lsa->llsa_options[1] = o6i->area->options[1];
+ link_lsa->llsa_options[2] = o6i->area->options[2];
+
+ /* linklocal address */
+ memcpy (&link_lsa->llsa_linklocal, o6i->lladdr, sizeof (struct in6_addr));
+
+#ifdef KAME /* clear ifindex */
+ if (link_lsa->llsa_linklocal.s6_addr[3] & 0x0f)
+ link_lsa->llsa_linklocal.s6_addr[3] &= ~((char)0x0f);
+#endif /* KAME */
+
+ link_lsa->llsa_prefix_num = htonl (listcount (prefix_connected));
+ cp = (char *)(link_lsa + 1);
+ for (node = listhead (prefix_connected); node; nextnode (node))
+ {
+ p = (struct ospf6_prefix *) getdata (node);
+ size += OSPF6_PREFIX_SIZE (p);
+ memcpy (cp, p, OSPF6_PREFIX_SIZE (p));
+ cp += OSPF6_PREFIX_SIZE (p);
+ }
+
+ for (node = listhead (prefix_connected); node; nextnode (node))
+ {
+ p = (struct ospf6_prefix *) getdata (node);
+ ospf6_prefix_delete (p);
+ }
+ list_delete (prefix_connected);
+
+ ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_LINK),
+ htonl (o6i->if_id), o6i->area->ospf6->router_id,
+ (char *) link_lsa, size, o6i);
+}
+
+int
+ospf6_lsa_link_hook_interface (void *interface)
+{
+ struct ospf6_interface *o6i = interface;
+ if (o6i->area)
+ ospf6_lsa_link_update (o6i->interface->name);
+ return 0;
+}
+
+int
+ospf6_lsa_link_refresh (void *old)
+{
+ struct ospf6_lsa *lsa = old;
+ struct interface *ifp;
+
+ ifp = if_lookup_by_index (ntohl (lsa->header->id));
+ if (! ifp)
+ ospf6_lsa_premature_aging (old);
+ else
+ ospf6_lsa_link_update (ifp->name);
+
+ return 0;
+}
+
+void
+ospf6_lsa_slot_register_link ()
+{
+ struct ospf6_lsa_slot slot;
+
+ memset (&slot, 0, sizeof (struct ospf6_lsa_slot));
+ slot.type = htons (OSPF6_LSA_TYPE_LINK);
+ slot.name = "Link";
+ slot.func_show = ospf6_lsa_link_show;
+ slot.func_refresh = ospf6_lsa_link_refresh;
+ slot.hook_interface.name = "OriginateLink";
+ slot.hook_interface.hook_change = ospf6_lsa_link_hook_interface;
+ ospf6_lsa_slot_register (&slot);
+
+ /*
+ * Link LSA handling will be shift in ospf6_intra.c
+ * Currently, only database hook only moved to ospf6_intra.c
+ */
+#if 0
+ ospf6_lsdb_hook[OSPF6_LSA_TYPE_LINK & OSPF6_LSTYPE_CODE_MASK].hook =
+ ospf6_spf_database_hook;
+#endif /*0*/
+}
+
+int
+ospf6_lsa_add_hook (void *data)
+{
+ struct ospf6_lsa *lsa = data;
+ struct ospf6_lsa_slot *sp;
+
+ sp = ospf6_lsa_slot_get (lsa->header->type);
+ if (sp)
+ {
+ CALL_CHANGE_HOOK (&sp->database_hook, lsa);
+ }
+ else
+ zlog_warn ("Unknown LSA added to database: %s", lsa->str);
+ return 0;
+}
+
+int
+ospf6_lsa_change_hook (void *data)
+{
+ struct ospf6_lsa *lsa = data;
+ struct ospf6_lsa_slot *sp;
+
+ sp = ospf6_lsa_slot_get (lsa->header->type);
+ if (sp)
+ {
+ CALL_CHANGE_HOOK (&sp->database_hook, lsa);
+ }
+ else
+ zlog_warn ("Unknown LSA changed in database: %s", lsa->str);
+ return 0;
+}
+
+int
+ospf6_lsa_remove_hook (void *data)
+{
+ struct ospf6_lsa *lsa = data;
+ struct ospf6_lsa_slot *sp;
+
+ sp = ospf6_lsa_slot_get (lsa->header->type);
+ if (sp)
+ {
+ CALL_REMOVE_HOOK (&sp->database_hook, lsa);
+ }
+ else
+ zlog_warn ("Unknown LSA removed from database: %s", lsa->str);
+ return 0;
+}
+
+/* Initialize LSA slots */
+void
+ospf6_lsa_init ()
+{
+ struct ospf6_hook hook;
+
+ slot_head = NULL;
+ ospf6_lsa_slot_register_router ();
+ ospf6_lsa_slot_register_network ();
+ ospf6_lsa_slot_register_link ();
+#if 0
+ ospf6_lsa_slot_register_intra_prefix ();
+ ospf6_lsa_slot_register_as_external ();
+#endif /*0*/
+
+ hook.name = "LSADatabaseHook";
+ hook.hook_add = ospf6_lsa_add_hook;
+ hook.hook_change = ospf6_lsa_change_hook;
+ hook.hook_remove = ospf6_lsa_remove_hook;
+ ospf6_hook_register (&hook, &database_hook);
+}
+
diff --git a/ospf6d/ospf6_lsa.h b/ospf6d/ospf6_lsa.h
new file mode 100644
index 00000000..02ad7c6f
--- /dev/null
+++ b/ospf6d/ospf6_lsa.h
@@ -0,0 +1,426 @@
+/*
+ * LSA function
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef OSPF6_LSA_H
+#define OSPF6_LSA_H
+
+#include "ospf6_hook.h"
+
+#define ONESECOND_USEC 1000000
+#define USEC_TVDIFF(tv2,tv1) \
+ (((tv2)->tv_sec - (tv1)->tv_sec) * ONESECOND_USEC \
+ + ((tv2)->tv_usec - (tv1)->tv_usec))
+#define SEC_TVDIFF(tv2,tv1) \
+ (USEC_TVDIFF((tv2),(tv1)) / ONESECOND_USEC)
+
+/* LSA definition */
+
+#define MAXLSASIZE 1024
+
+#define OSPF6_LSA_MAXAGE 3600 /* 1 hour */
+#define OSPF6_LSA_CHECKAGE 300 /* 5 min */
+#define OSPF6_LSA_MAXAGEDIFF 900 /* 15 min */
+
+/* Type */
+#define OSPF6_LSA_TYPE_NONE 0x0000
+#define OSPF6_LSA_TYPE_ROUTER 0x2001
+#define OSPF6_LSA_TYPE_NETWORK 0x2002
+#define OSPF6_LSA_TYPE_INTER_PREFIX 0x2003
+#define OSPF6_LSA_TYPE_INTER_ROUTER 0x2004
+#define OSPF6_LSA_TYPE_AS_EXTERNAL 0x4005
+#define OSPF6_LSA_TYPE_GROUP_MEMBERSHIP 0x2006
+#define OSPF6_LSA_TYPE_TYPE_7 0x2007
+#define OSPF6_LSA_TYPE_LINK 0x0008
+#define OSPF6_LSA_TYPE_INTRA_PREFIX 0x2009
+#define OSPF6_LSA_TYPE_MAX 0x000a
+#define OSPF6_LSA_TYPE_SIZE 0x000b
+
+/* Masks for LS Type : RFC 2740 A.4.2.1 "LS type" */
+#define OSPF6_LSTYPE_UBIT_MASK 0x8000
+#define OSPF6_LSTYPE_SCOPE_MASK 0x6000
+#define OSPF6_LSTYPE_CODE_MASK 0x1fff
+
+#define OSPF6_LSA_TYPESW_MASK OSPF6_LSTYPE_CODE_MASK
+#define OSPF6_LSA_TYPESW(x) (ntohs((x)) & OSPF6_LSA_TYPESW_MASK)
+#define OSPF6_LSA_TYPESW_ISKNOWN(x) (OSPF6_LSA_TYPESW(x) < OSPF6_LSA_TYPE_MAX)
+
+/* lsa scope */
+#define OSPF6_LSA_SCOPE_LINKLOCAL 0x0000
+#define OSPF6_LSA_SCOPE_AREA 0x2000
+#define OSPF6_LSA_SCOPE_AS 0x4000
+#define OSPF6_LSA_SCOPE_RESERVED 0x6000
+#define OSPF6_LSA_IS_SCOPE_LINKLOCAL(x) \
+ (((x) & OSPF6_LSTYPE_SCOPE_MASK) == OSPF6_LSA_SCOPE_LINKLOCAL)
+#define OSPF6_LSA_IS_SCOPE_AREA(x) \
+ (((x) & OSPF6_LSTYPE_SCOPE_MASK) == OSPF6_LSA_SCOPE_AREA)
+#define OSPF6_LSA_IS_SCOPE_AS(x) \
+ (((x) & OSPF6_LSTYPE_SCOPE_MASK) == OSPF6_LSA_SCOPE_AS)
+
+/* NOTE that all LSAs are kept NETWORK BYTE ORDER */
+
+/* Router-LSA */
+struct ospf6_router_lsa
+{
+ u_char bits;
+ u_char options[3];
+ /* followed by ospf6_router_lsd(s) */
+};
+
+#define OSPF6_ROUTER_LSA_BIT_B (1 << 0)
+#define OSPF6_ROUTER_LSA_BIT_E (1 << 1)
+#define OSPF6_ROUTER_LSA_BIT_V (1 << 2)
+#define OSPF6_ROUTER_LSA_BIT_W (1 << 3)
+
+#define OSPF6_ROUTER_LSA_SET(x,y) ((x)->bits |= (y))
+#define OSPF6_ROUTER_LSA_ISSET(x,y) ((x)->bits & (y))
+#define OSPF6_ROUTER_LSA_CLEAR(x,y) ((x)->bits &= ~(y))
+#define OSPF6_ROUTER_LSA_CLEAR_ALL_BITS(x) ((x)->bits = 0)
+
+/* Link State Description in Router-LSA */
+struct ospf6_router_lsd
+{
+ u_char type;
+ u_char reserved;
+ u_int16_t metric; /* output cost */
+ u_int32_t interface_id;
+ u_int32_t neighbor_interface_id;
+ u_int32_t neighbor_router_id;
+};
+
+#define OSPF6_ROUTER_LSD_TYPE_POINTTOPOINT 1
+#define OSPF6_ROUTER_LSD_TYPE_TRANSIT_NETWORK 2
+#define OSPF6_ROUTER_LSD_TYPE_STUB_NETWORK 3
+#define OSPF6_ROUTER_LSD_TYPE_VIRTUAL_LINK 4
+
+/* Network-LSA */
+struct ospf6_network_lsa
+{
+ u_char reserved;
+ u_char options[3];
+ /* followed by ospf6_netowrk_lsd(s) */
+};
+
+/* Link State Description in Router-LSA */
+struct ospf6_network_lsd
+{
+ u_int32_t adv_router;
+};
+
+/* Link-LSA */
+struct ospf6_link_lsa
+{
+ u_char llsa_rtr_pri;
+ u_char llsa_options[3];
+ struct in6_addr llsa_linklocal;
+ u_int32_t llsa_prefix_num;
+ /* followed by prefix(es) */
+};
+
+/* Intra-Area-Prefix-LSA */
+struct ospf6_intra_area_prefix_lsa
+{
+ u_int16_t prefix_number;
+ u_int16_t refer_lstype;
+ u_int32_t refer_lsid;
+ u_int32_t refer_advrtr;
+};
+
+/* AS-External-LSA */
+struct ospf6_as_external_lsa
+{
+ u_char ase_bits;
+ u_char ase_pre_metric; /* 1st byte of metric */
+ u_int16_t ase_metric; /* 2nd, 3rd byte of metric */
+#if 1
+ struct ospf6_prefix ospf6_prefix;
+#else
+ u_char ase_prefix_len;
+ u_char ase_prefix_opt;
+ u_int16_t ase_refer_lstype;
+ /* followed by one address prefix */
+#endif
+ /* followed by none or one forwarding address */
+ /* followed by none or one external route tag */
+ /* followed by none or one referenced LS-ID */
+};
+#define ASE_LSA_BIT_T (1 << 0)
+#define ASE_LSA_BIT_F (1 << 1)
+#define ASE_LSA_BIT_E (1 << 2)
+
+#define ASE_LSA_SET(x,y) ((x)->ase_bits |= (y))
+#define ASE_LSA_ISSET(x,y) ((x)->ase_bits & (y))
+#define ASE_LSA_CLEAR(x,y) ((x)->ase_bits &= ~(y))
+
+/* LSA Header */
+struct ospf6_lsa_hdr
+{
+ u_int16_t lsh_age; /* LS age */
+ u_int16_t lsh_type; /* LS type */
+ u_int32_t lsh_id; /* Link State ID */
+ u_int32_t lsh_advrtr; /* Advertising Router */
+ u_int32_t lsh_seqnum; /* LS sequence number */
+ u_int16_t lsh_cksum; /* LS checksum */
+ u_int16_t lsh_len; /* length */
+};
+struct ospf6_lsa_header
+{
+ u_int16_t age; /* LS age */
+ u_int16_t type; /* LS type */
+ u_int32_t ls_id; /* Link State ID */
+ u_int32_t advrtr; /* Advertising Router */
+ u_int32_t seqnum; /* LS sequence number */
+ u_int16_t checksum; /* LS checksum */
+ u_int16_t length; /* LSA length */
+};
+struct ospf6_lsa_header__
+{
+ u_int16_t age; /* LS age */
+ u_int16_t type; /* LS type */
+ u_int32_t id; /* Link State ID */
+ u_int32_t adv_router; /* Advertising Router */
+ u_int32_t seqnum; /* LS sequence number */
+ u_int16_t checksum; /* LS checksum */
+ u_int16_t length; /* LSA length */
+};
+
+#define OSPF6_LSA_NEXT(x) ((struct ospf6_lsa_header *) \
+ ((char *)(x) + ntohs ((x)->length)))
+
+#define OSPF6_LSA_HEADER_END(header) \
+ ((void *)((char *)(header) + sizeof (struct ospf6_lsa_header)))
+
+struct ospf6_lsa
+{
+ char str[256]; /* dump string */
+
+ u_long lock; /* reference counter */
+ int summary; /* indicate this is LS header only */
+ void *scope; /* pointer of scoped data structure */
+ unsigned char flag; /* to decide ack type and refresh */
+ struct timeval birth; /* tv_sec when LS age 0 */
+ struct timeval installed; /* installed time */
+ struct timeval originated; /* installed time */
+ struct thread *expire;
+ struct thread *refresh; /* For self-originated LSA */
+ u_int32_t from; /* from which neighbor */
+
+ /* lsa instance */
+ struct ospf6_lsa_hdr *lsa_hdr;
+ struct ospf6_lsa_header__ *header;
+
+ /* statistics */
+ u_long turnover_num;
+ u_long turnover_total;
+ u_long turnover_min;
+ u_long turnover_max;
+};
+
+struct ospf6_lsa_slot
+{
+ struct ospf6_lsa_slot *prev;
+ struct ospf6_lsa_slot *next;
+
+ u_int16_t type;
+ char *name;
+
+ int (*func_print) (struct ospf6_lsa *lsa);
+ int (*func_show) (struct vty *vty, struct ospf6_lsa *lsa);
+ int (*func_refresh) (void *lsa);
+
+ int (*database_add) (void *lsa);
+ int (*database_remove) (void *lsa);
+
+ struct ospf6_hook_master database_hook;
+
+ struct ospf6_hook hook_neighbor;
+ struct ospf6_hook hook_interface;
+ struct ospf6_hook hook_area;
+ struct ospf6_hook hook_top;
+ struct ospf6_hook hook_database;
+ struct ospf6_hook hook_route;
+};
+
+#define OSPF6_LSA_FLAG_FLOODBACK 0x01
+#define OSPF6_LSA_FLAG_DUPLICATE 0x02
+#define OSPF6_LSA_FLAG_IMPLIEDACK 0x04
+#define OSPF6_LSA_FLAG_REFRESH 0x08
+
+/* Back pointer check, Is X's reference field bound to Y ? */
+#define x_ipl(x) ((struct intra_area_prefix_lsa *)LSH_NEXT((x)->lsa_hdr))
+#define is_reference_network_ok(x,y) \
+ ((x_ipl(x))->intra_prefix_refer_lstype == (y)->lsa_hdr->lsh_type &&\
+ (x_ipl(x))->intra_prefix_refer_lsid == (y)->lsa_hdr->lsh_id &&\
+ (x_ipl(x))->intra_prefix_refer_advrtr == (y)->lsa_hdr->lsh_advrtr)
+ /* referencing router's ifid must be 0,
+ see draft-ietf-ospf-ospfv6-06.txt */
+#define is_reference_router_ok(x,y) \
+ ((x_ipl(x))->intra_prefix_refer_lstype == (y)->lsa_hdr->lsh_type &&\
+ (x_ipl(x))->intra_prefix_refer_lsid == htonl (0) &&\
+ (x_ipl(x))->intra_prefix_refer_advrtr == (y)->lsa_hdr->lsh_advrtr)
+
+/* MaxAge check. */
+/* ospf6_lsa_is_maxage (struct ospf6_lsa *lsa) */
+#define IS_LSA_MAXAGE(L) (ospf6_lsa_age_current (L) == OSPF6_LSA_MAXAGE)
+
+struct ospf6_lsa_slot *ospf6_lsa_slot_get (u_int16_t type);
+int ospf6_lsa_slot_register (struct ospf6_lsa_slot *src);
+int ospf6_lsa_slot_unregister (u_int16_t type);
+
+extern struct ospf6_lsa_slot *slot_head;
+#define CALL_FOREACH_LSA_HOOK(hook,func,data) \
+ if (ospf6)\
+ {\
+ struct ospf6_lsa_slot *slot;\
+ for (slot = slot_head; slot; slot = slot->next)\
+ {\
+ if (slot->hook.func)\
+ (*slot->hook.func) (data);\
+ }\
+ }
+#define CALL_LSA_FUNC(type,func,data) \
+ if (ospf6)\
+ {\
+ struct ospf6_lsa_slot *slot;\
+ slot = ospf6_lsa_slot_get (type);\
+ if (slot && slot->func)\
+ {\
+ (*slot->func) (data);\
+ }\
+ else\
+ {\
+ zlog_warn ("LSA: No slot for type %#x: %s line:%d",\
+ ntohs (type), __FILE__, __LINE__);\
+ }\
+ }
+
+#define CALL_LSA_DATABASE_ADD(type,data) \
+ if (ospf6)\
+ {\
+ struct ospf6_lsa_slot *slot;\
+ slot = ospf6_lsa_slot_get (type);\
+ if (slot)\
+ {\
+ CALL_ADD_HOOK (&slot->database_hook, data);\
+ }\
+ else\
+ {\
+ zlog_warn ("LSA: No slot for type %#x: %s line:%d",\
+ ntohs (type), __FILE__, __LINE__);\
+ }\
+ }
+#define CALL_LSA_DATABASE_CHANGE(type,data) \
+ if (ospf6)\
+ {\
+ struct ospf6_lsa_slot *slot;\
+ slot = ospf6_lsa_slot_get (type);\
+ if (slot)\
+ {\
+ CALL_CHANGE_HOOK (&slot->database_hook, data);\
+ }\
+ else\
+ {\
+ zlog_warn ("LSA: No slot for type %#x: %s line:%d",\
+ ntohs (type), __FILE__, __LINE__);\
+ }\
+ }
+#define CALL_LSA_DATABASE_REMOVE(type,data) \
+ if (ospf6)\
+ {\
+ struct ospf6_lsa_slot *slot;\
+ slot = ospf6_lsa_slot_get (type);\
+ if (slot)\
+ {\
+ CALL_REMOVE_HOOK (&slot->database_hook, data);\
+ }\
+ else\
+ {\
+ zlog_warn ("LSA: No slot for type %#x: %s line:%d",\
+ ntohs (type), __FILE__, __LINE__);\
+ }\
+ }
+
+void ospf6_lsa_init ();
+
+/* Function Prototypes */
+
+struct router_lsd *
+get_router_lsd (u_int32_t, struct ospf6_lsa *);
+unsigned long get_ifindex_to_router (u_int32_t, struct ospf6_lsa *);
+
+int ospf6_lsa_differ (struct ospf6_lsa *lsa1, struct ospf6_lsa *lsa2);
+int ospf6_lsa_match (u_int16_t, u_int32_t, u_int32_t,
+ struct ospf6_lsa_header *);
+
+void ospf6_lsa_show (struct vty *, struct ospf6_lsa *);
+void ospf6_lsa_show_dump (struct vty *, struct ospf6_lsa *);
+void ospf6_lsa_show_summary (struct vty *, struct ospf6_lsa *);
+void ospf6_lsa_show_summary_header (struct vty *);
+
+struct ospf6_lsa *
+ospf6_lsa_create (struct ospf6_lsa_header *);
+struct ospf6_lsa *
+ospf6_lsa_summary_create (struct ospf6_lsa_header__ *);
+void
+ospf6_lsa_delete (struct ospf6_lsa *);
+
+void ospf6_lsa_lock (struct ospf6_lsa *);
+void ospf6_lsa_unlock (struct ospf6_lsa *);
+
+unsigned short ospf6_lsa_age_current (struct ospf6_lsa *);
+int ospf6_lsa_is_maxage (struct ospf6_lsa *);
+void ospf6_lsa_age_update_to_send (struct ospf6_lsa *, u_int32_t);
+void ospf6_lsa_premature_aging (struct ospf6_lsa *);
+
+int ospf6_lsa_check_recent (struct ospf6_lsa *, struct ospf6_lsa *);
+
+int
+ospf6_lsa_lsd_num (struct ospf6_lsa_header *lsa_header);
+void *
+ospf6_lsa_lsd_get (int index, struct ospf6_lsa_header *lsa_header);
+int
+ospf6_lsa_lsd_is_refer_ok (int index1, struct ospf6_lsa_header *lsa_header1,
+ int index2, struct ospf6_lsa_header *lsa_header2);
+
+int ospf6_lsa_expire (struct thread *);
+int ospf6_lsa_refresh (struct thread *);
+
+u_short ospf6_lsa_checksum (struct ospf6_lsa_header *);
+
+void ospf6_lsa_update_network (char *ifname);
+void ospf6_lsa_update_link (char *ifname);
+void ospf6_lsa_update_as_external (u_int32_t ls_id);
+void ospf6_lsa_update_intra_prefix_transit (char *ifname);
+void ospf6_lsa_update_intra_prefix_stub (u_int32_t area_id);
+
+u_int16_t ospf6_lsa_get_scope_type (u_int16_t);
+int ospf6_lsa_is_known_type (struct ospf6_lsa_header *lsa_header);
+
+char *ospf6_lsa_type_string (u_int16_t type, char *buf, int bufsize);
+char *ospf6_lsa_router_bits_string (u_char router_bits, char *buf, int size);
+
+u_long
+ospf6_lsa_has_elasped (u_int16_t, u_int32_t, u_int32_t, void *);
+void
+ospf6_lsa_originate (u_int16_t, u_int32_t, u_int32_t, char *, int, void *);
+
+#endif /* OSPF6_LSA_H */
+
diff --git a/ospf6d/ospf6_lsdb.c b/ospf6d/ospf6_lsdb.c
new file mode 100644
index 00000000..ad53eb4f
--- /dev/null
+++ b/ospf6d/ospf6_lsdb.c
@@ -0,0 +1,723 @@
+/*
+ * Copyright (C) 2002 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "memory.h"
+#include "log.h"
+#include "command.h"
+#include "if.h"
+
+#include "ospf6_dump.h"
+#include "ospf6_lsdb.h"
+
+#include "ospf6_interface.h"
+#include "ospf6_area.h"
+#include "ospf6_top.h"
+
+#define OSPF6_LSDB_MATCH_TYPE 0x01
+#define OSPF6_LSDB_MATCH_ID 0x02
+#define OSPF6_LSDB_MATCH_ADV_ROUTER 0x04
+#define OSPF6_LSDB_SHOW_DUMP 0x08
+#define OSPF6_LSDB_SHOW_DETAIL 0x10
+
+struct ospf6_lsdb_hook_t hooks[0x2000];
+struct ospf6_lsdb_hook_t *ospf6_lsdb_hook = hooks;
+
+struct ospf6_lsdb *
+ospf6_lsdb_create ()
+{
+ struct ospf6_lsdb *lsdb;
+
+ lsdb = XCALLOC (MTYPE_OSPF6_LSDB, sizeof (struct ospf6_lsdb));
+ if (lsdb == NULL)
+ {
+ zlog_warn ("Can't malloc lsdb");
+ return NULL;
+ }
+ memset (lsdb, 0, sizeof (struct ospf6_lsdb));
+
+ lsdb->table = route_table_init ();
+ return lsdb;
+}
+
+void
+ospf6_lsdb_delete (struct ospf6_lsdb *lsdb)
+{
+ ospf6_lsdb_remove_all (lsdb);
+ route_table_finish (lsdb->table);
+ XFREE (MTYPE_OSPF6_LSDB, lsdb);
+}
+
+static void
+ospf6_lsdb_set_key (struct prefix_ipv6 *key, int flag,
+ u_int16_t type, u_int32_t id, u_int32_t adv_router)
+{
+ int len = 0;
+ memset (key, 0, sizeof (struct prefix_ipv6));
+
+ if (CHECK_FLAG (flag, OSPF6_LSDB_MATCH_TYPE))
+ {
+ len += 2;
+ if (CHECK_FLAG (flag, OSPF6_LSDB_MATCH_ADV_ROUTER))
+ {
+ len += 4;
+ if (CHECK_FLAG (flag, OSPF6_LSDB_MATCH_ID))
+ len += 4;
+ }
+ }
+
+ if (len > 0)
+ memcpy ((char *)&key->prefix, &type, 2);
+ if (len > 2)
+ memcpy ((char *)&key->prefix + 2, &adv_router, 4);
+ if (len > 6)
+ memcpy ((char *)&key->prefix + 6, &id, 4);
+
+ key->family = AF_INET6;
+ key->prefixlen = len * 8;
+}
+
+void
+ospf6_lsdb_add (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb)
+{
+ int flag;
+ struct prefix_ipv6 key;
+ struct route_node *rn;
+ struct ospf6_lsa *old = NULL;
+
+ flag = OSPF6_LSDB_MATCH_TYPE | OSPF6_LSDB_MATCH_ID |
+ OSPF6_LSDB_MATCH_ADV_ROUTER;
+ ospf6_lsdb_set_key (&key, flag, lsa->header->type, lsa->header->id,
+ lsa->header->adv_router);
+
+ rn = route_node_get (lsdb->table, (struct prefix *) &key);
+ if (rn->info)
+ old = rn->info;
+ rn->info = lsa;
+ ospf6_lsa_lock (lsa);
+
+ if (old)
+ ospf6_lsa_unlock (old);
+ else
+ lsdb->count++;
+}
+
+void
+ospf6_lsdb_remove (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb)
+{
+ int flag;
+ struct prefix_ipv6 key;
+ struct route_node *rn;
+ struct ospf6_lsa *old;
+
+ flag = OSPF6_LSDB_MATCH_TYPE | OSPF6_LSDB_MATCH_ID |
+ OSPF6_LSDB_MATCH_ADV_ROUTER;
+ ospf6_lsdb_set_key (&key, flag, lsa->header->type, lsa->header->id,
+ lsa->header->adv_router);
+
+ rn = route_node_lookup (lsdb->table, (struct prefix *) &key);
+ if (! rn || ! rn->info)
+ {
+ zlog_warn ("LSDB: Can't remove: no such LSA: %s", lsa->str);
+ return;
+ }
+
+ old = rn->info;
+ if (old != lsa)
+ {
+ zlog_warn ("LSDB: Can't remove: different instance: %s (%p <-> %p) %s",
+ lsa->str, lsa, old, old->str);
+ return;
+ }
+
+ rn->info = NULL;
+ ospf6_lsa_unlock (old);
+ lsdb->count--;
+}
+
+static void
+ospf6_lsdb_lookup_node (struct ospf6_lsdb_node *node,
+ u_int16_t type, u_int32_t id, u_int32_t adv_router,
+ struct ospf6_lsdb *lsdb)
+{
+ int flag;
+ struct route_node *rn;
+
+ memset (node, 0, sizeof (struct ospf6_lsdb_node));
+
+ flag = OSPF6_LSDB_MATCH_TYPE | OSPF6_LSDB_MATCH_ID |
+ OSPF6_LSDB_MATCH_ADV_ROUTER;
+ ospf6_lsdb_set_key (&node->key, flag, type, id, adv_router);
+
+ rn = route_node_lookup (lsdb->table, (struct prefix *) &node->key);
+ if (! rn || ! rn->info)
+ return;
+
+ node->node = rn;
+ node->next = route_next (rn);
+ node->lsa = rn->info;
+ if (node->next != NULL)
+ route_unlock_node (node->next);
+}
+
+struct ospf6_lsa *
+ospf6_lsdb_lookup_lsdb (u_int16_t type, u_int32_t id, u_int32_t adv_router,
+ struct ospf6_lsdb *lsdb)
+{
+ struct ospf6_lsdb_node node;
+ ospf6_lsdb_lookup_node (&node, type, id, adv_router, lsdb);
+ return node.lsa;
+}
+
+/* Iteration function */
+void
+ospf6_lsdb_head (struct ospf6_lsdb_node *node, struct ospf6_lsdb *lsdb)
+{
+ struct route_node *rn;
+
+ memset (node, 0, sizeof (struct ospf6_lsdb_node));
+
+ rn = route_top (lsdb->table);
+ if (rn == NULL)
+ return;
+
+ while (rn && rn->info == NULL)
+ rn = route_next (rn);
+
+ if (rn && rn->info)
+ {
+ node->node = rn;
+ node->next = route_next (rn);
+ node->lsa = rn->info;
+ if (node->next != NULL)
+ route_unlock_node (node->next);
+ }
+}
+
+void
+ospf6_lsdb_type (struct ospf6_lsdb_node *node, u_int16_t type,
+ struct ospf6_lsdb *lsdb)
+{
+ int flag;
+ struct route_node *rn;
+
+ memset (node, 0, sizeof (struct ospf6_lsdb_node));
+
+ flag = OSPF6_LSDB_MATCH_TYPE;
+ ospf6_lsdb_set_key (&node->key, flag, type, 0, 0);
+
+ /* get the closest radix node */
+ rn = route_node_get (lsdb->table, (struct prefix *) &node->key);
+
+ /* skip to the real existing lsdb entry */
+ while (rn && rn->info == NULL && rn->p.prefixlen >= node->key.prefixlen &&
+ prefix_match ((struct prefix *) &node->key, &rn->p))
+ rn = route_next (rn);
+
+ if (rn && rn->info)
+ {
+ node->node = rn;
+ node->next = route_next (rn);
+ node->lsa = rn->info;
+ if (node->next != NULL)
+ route_unlock_node (node->next);
+ }
+}
+
+void
+ospf6_lsdb_type_router (struct ospf6_lsdb_node *node,
+ u_int16_t type, u_int32_t adv_router,
+ struct ospf6_lsdb *lsdb)
+{
+ int flag;
+ struct route_node *rn;
+
+ memset (node, 0, sizeof (struct ospf6_lsdb_node));
+
+ flag = OSPF6_LSDB_MATCH_TYPE | OSPF6_LSDB_MATCH_ADV_ROUTER;
+ ospf6_lsdb_set_key (&node->key, flag, type, 0, adv_router);
+
+ /* get the closest radix node */
+ rn = route_node_get (lsdb->table, (struct prefix *) &node->key);
+
+ /* skip to the real existing lsdb entry */
+ while (rn && rn->info == NULL && rn->p.prefixlen >= node->key.prefixlen &&
+ prefix_match ((struct prefix *) &node->key, &rn->p))
+ rn = route_next (rn);
+
+ if (rn && rn->info)
+ {
+ node->node = rn;
+ node->next = route_next (rn);
+ node->lsa = rn->info;
+ if (node->next != NULL)
+ route_unlock_node (node->next);
+ }
+}
+
+void
+ospf6_lsdb_next (struct ospf6_lsdb_node *node)
+{
+ struct route_node *rn;
+
+ route_lock_node (node->node);
+ rn = route_next (node->node);
+
+ /* skip to the real existing lsdb entry */
+ while (rn && rn->info == NULL && rn->p.prefixlen >= node->key.prefixlen &&
+ prefix_match ((struct prefix *) &node->key, &rn->p))
+ rn = route_next (rn);
+
+ if (rn && rn->info && rn->p.prefixlen >= node->key.prefixlen &&
+ prefix_match ((struct prefix *) &node->key, &rn->p))
+ {
+ node->node = rn;
+ node->next = route_next (rn);
+ node->lsa = rn->info;
+ if (node->next != NULL)
+ route_unlock_node (node->next);
+ }
+ else
+ {
+ node->node = NULL;
+ node->next = NULL;
+ node->lsa = NULL;
+ }
+}
+
+struct ospf6_lsa *
+ospf6_lsdb_lookup (u_int16_t type, u_int32_t id, u_int32_t adv_router,
+ void *scope)
+{
+ struct ospf6_interface *o6i;
+ struct ospf6_area *o6a;
+ listnode i, j;
+
+ if (scope == (void *) ospf6)
+ return ospf6_lsdb_lookup_lsdb (type, id, adv_router, ospf6->lsdb);
+
+ for (i = listhead (ospf6->area_list); i; nextnode (i))
+ {
+ o6a = getdata (i);
+
+ if (scope == (void *) o6a)
+ return ospf6_lsdb_lookup_lsdb (type, id, adv_router, o6a->lsdb);
+
+ for (j = listhead (o6a->if_list); j; nextnode (j))
+ {
+ o6i = getdata (j);
+
+ if (scope == (void *) o6i)
+ return ospf6_lsdb_lookup_lsdb (type, id, adv_router, o6i->lsdb);
+ }
+ }
+
+ zlog_warn ("LSDB: Can't lookup: unknown scope, type %#hx", ntohs (type));
+ return NULL;
+}
+
+void
+ospf6_lsdb_install (struct ospf6_lsa *new)
+{
+ struct ospf6_lsdb *lsdb;
+ struct ospf6_lsa *old;
+ int need_hook = 0;
+ void (*hook) (struct ospf6_lsa *, struct ospf6_lsa *);
+
+ struct ospf6 *as = NULL;
+ struct ospf6_area *area = NULL;
+ struct ospf6_interface *linklocal = NULL;
+ hook = NULL;
+
+ switch (ntohs (new->header->type) & OSPF6_LSTYPE_SCOPE_MASK)
+ {
+ case OSPF6_LSA_SCOPE_LINKLOCAL:
+ linklocal = (struct ospf6_interface *) new->scope;
+ lsdb = linklocal->lsdb;
+ break;
+ case OSPF6_LSA_SCOPE_AREA:
+ area = (struct ospf6_area *) new->scope;
+ lsdb = area->lsdb;
+ break;
+ case OSPF6_LSA_SCOPE_AS:
+ as = (struct ospf6 *) new->scope;
+ lsdb = as->lsdb;
+ break;
+ default:
+ zlog_warn ("LSDB: Can't install: scope unknown: %s", new->str);
+ return;
+ }
+
+ /* whether schedule calculation or not */
+ old = ospf6_lsdb_lookup_lsdb (new->header->type, new->header->id,
+ new->header->adv_router, lsdb);
+
+ if (! old || ospf6_lsa_differ (old, new))
+ need_hook++;
+
+ /* log */
+ if (IS_OSPF6_DUMP_LSDB)
+ zlog_info ("LSDB: Install: %s %s", new->str,
+ ((IS_LSA_MAXAGE (new)) ? "(MaxAge)" : ""));
+
+ if (old)
+ ospf6_lsa_lock (old);
+
+ ospf6_lsdb_add (new, lsdb);
+ gettimeofday (&new->installed, NULL);
+
+ hook = ospf6_lsdb_hook[ntohs (new->header->type) &
+ OSPF6_LSTYPE_CODE_MASK].hook;
+ if (need_hook && hook)
+ (*hook) (old, new);
+
+ /* old LSA should be freed here */
+ if (old)
+ ospf6_lsa_unlock (old);
+}
+
+void
+ospf6_lsdb_remove_all (struct ospf6_lsdb *lsdb)
+{
+ struct ospf6_lsdb_node node;
+ for (ospf6_lsdb_head (&node, lsdb); ! ospf6_lsdb_is_end (&node);
+ ospf6_lsdb_next (&node))
+ ospf6_lsdb_remove (node.lsa, lsdb);
+}
+
+void
+ospf6_lsdb_remove_maxage (struct ospf6_lsdb *lsdb)
+{
+ struct ospf6_lsdb_node node;
+ struct ospf6_lsa *lsa;
+
+ for (ospf6_lsdb_head (&node, lsdb); ! ospf6_lsdb_is_end (&node);
+ ospf6_lsdb_next (&node))
+ {
+ lsa = node.lsa;
+
+ /* contiue if it's not MaxAge */
+ if (! IS_LSA_MAXAGE (lsa))
+ continue;
+
+ /* continue if it's referenced by some retrans-lists */
+ if (lsa->lock != 1)
+ continue;
+
+ if (IS_OSPF6_DUMP_LSDB)
+ zlog_info ("Remove MaxAge LSA: %s", lsa->str);
+
+ ospf6_lsdb_remove (lsa, lsdb);
+ }
+}
+
+
+
+/* vty functions */
+
+static int
+ospf6_lsdb_match (int flag, u_int16_t type, u_int32_t id,
+ u_int32_t adv_router, struct ospf6_lsa *lsa)
+{
+ if (CHECK_FLAG (flag, OSPF6_LSDB_MATCH_TYPE) &&
+ lsa->header->type != type)
+ return 0;
+
+ if (CHECK_FLAG (flag, OSPF6_LSDB_MATCH_ID) &&
+ lsa->header->id != id)
+ return 0;
+
+ if (CHECK_FLAG (flag, OSPF6_LSDB_MATCH_ADV_ROUTER) &&
+ lsa->header->adv_router != adv_router)
+ return 0;
+
+ return 1;
+}
+
+int
+show_ipv6_ospf6_lsdb (struct vty *vty, int argc, char **argv,
+ struct ospf6_lsdb *lsdb)
+{
+ u_int flag;
+ u_int16_t type = 0;
+ u_int32_t id, adv_router;
+ int ret;
+ struct ospf6_lsdb_node node;
+ char invalid[32], *invalidp;
+ int l_argc = argc;
+ char **l_argv = argv;
+
+ flag = 0;
+ memset (invalid, 0, sizeof (invalid));
+ invalidp = invalid;
+
+ /* chop tail if the words is 'dump' or 'summary' */
+ if (l_argc > 0 && ! strcmp (l_argv[l_argc - 1], "dump"))
+ {
+ SET_FLAG (flag, OSPF6_LSDB_SHOW_DUMP);
+ l_argc --;
+ }
+ else if (l_argc > 0 && ! strcmp (l_argv[l_argc - 1], "detail"))
+ {
+ SET_FLAG (flag, OSPF6_LSDB_SHOW_DETAIL);
+ l_argc --;
+ }
+
+ if (l_argc > 0)
+ {
+ SET_FLAG (flag, OSPF6_LSDB_MATCH_TYPE);
+ if (! strncmp (l_argv[0], "r", 1))
+ type = htons (OSPF6_LSA_TYPE_ROUTER);
+ if (! strncmp (l_argv[0], "n", 1))
+ type = htons (OSPF6_LSA_TYPE_NETWORK);
+ if (! strncmp (l_argv[0], "a", 1))
+ type = htons (OSPF6_LSA_TYPE_AS_EXTERNAL);
+ if (! strcmp (l_argv[0], "intra-prefix"))
+ type = htons (OSPF6_LSA_TYPE_INTRA_PREFIX);
+ if (! strcmp (l_argv[0], "inter-router"))
+ type = htons (OSPF6_LSA_TYPE_INTER_ROUTER);
+ if (! strcmp (l_argv[0], "inter-prefix"))
+ type = htons (OSPF6_LSA_TYPE_INTER_PREFIX);
+ if (! strncmp (l_argv[0], "l", 1))
+ type = htons (OSPF6_LSA_TYPE_LINK);
+ if (! strncmp (l_argv[0], "0x", 2) && strlen (l_argv[0]) == 6)
+ type = htons ((short) strtol (l_argv[0], (char **)NULL, 16));
+ if (! strncmp (l_argv[0], "*", 1))
+ UNSET_FLAG (flag, OSPF6_LSDB_MATCH_TYPE);
+ }
+
+ if (l_argc > 1)
+ {
+ SET_FLAG (flag, OSPF6_LSDB_MATCH_ID);
+ if (! strncmp (l_argv[1], "*", 1))
+ UNSET_FLAG (flag, OSPF6_LSDB_MATCH_ID);
+ else
+ {
+ ret = inet_pton (AF_INET, l_argv[1], &id);
+ if (ret != 1)
+ {
+ id = htonl (strtoul (l_argv[1], &invalidp, 10));
+ if (invalid[0] != '\0')
+ {
+ vty_out (vty, "Link State ID is not parsable: %s%s",
+ l_argv[1], VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+ }
+ }
+ }
+
+ if (l_argc > 2)
+ {
+ SET_FLAG (flag, OSPF6_LSDB_MATCH_ADV_ROUTER);
+ if (! strncmp (l_argv[2], "*", 1))
+ UNSET_FLAG (flag, OSPF6_LSDB_MATCH_ADV_ROUTER);
+ else
+ {
+ ret = inet_pton (AF_INET, l_argv[2], &adv_router);
+ if (ret != 1)
+ {
+ adv_router = htonl (strtoul (l_argv[2], &invalidp, 10));
+ if (invalid[0] != '\0')
+ {
+ vty_out (vty, "Advertising Router is not parsable: %s%s",
+ l_argv[2], VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+ }
+ }
+ }
+
+ if (! CHECK_FLAG (flag, OSPF6_LSDB_SHOW_DETAIL))
+ ospf6_lsa_show_summary_header (vty);
+
+ for (ospf6_lsdb_head (&node, lsdb); ! ospf6_lsdb_is_end (&node);
+ ospf6_lsdb_next (&node))
+ {
+ if (! ospf6_lsdb_match (flag, type, id, adv_router, node.lsa))
+ continue;
+
+ if (CHECK_FLAG (flag, OSPF6_LSDB_SHOW_DUMP))
+ ospf6_lsa_show_dump (vty, node.lsa);
+ else if (CHECK_FLAG (flag, OSPF6_LSDB_SHOW_DETAIL))
+ ospf6_lsa_show (vty, node.lsa);
+ else
+ ospf6_lsa_show_summary (vty, node.lsa);
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ipv6_ospf6_database,
+ show_ipv6_ospf6_database_cmd,
+ "show ipv6 ospf6 database",
+ SHOW_STR
+ IP6_STR
+ OSPF6_STR
+ "LSA Database\n"
+ )
+{
+ struct ospf6_area *o6a;
+ struct ospf6_interface *o6i;
+ listnode i, j;
+
+ /* call show function for each of LSAs in the LSDBs */
+
+ for (i = listhead (ospf6->area_list); i; nextnode (i))
+ {
+ o6a = (struct ospf6_area *) getdata (i);
+
+ /* LinkLocal LSDBs */
+ for (j = listhead (o6a->if_list); j; nextnode (j))
+ {
+ o6i = (struct ospf6_interface *) getdata (j);
+
+ vty_out (vty, "%s", VTY_NEWLINE);
+ vty_out (vty, " Interface %s (Area: %s):%s",
+ o6i->interface->name, o6a->str, VTY_NEWLINE);
+ vty_out (vty, "%s", VTY_NEWLINE);
+ show_ipv6_ospf6_lsdb (vty, argc, argv, o6i->lsdb);
+ }
+
+ /* Area LSDBs */
+ vty_out (vty, "%s", VTY_NEWLINE);
+ vty_out (vty, " Area %s:%s", o6a->str, VTY_NEWLINE);
+ vty_out (vty, "%s", VTY_NEWLINE);
+ show_ipv6_ospf6_lsdb (vty, argc, argv, o6a->lsdb);
+ }
+
+ /* AS LSDBs */
+ vty_out (vty, "%s", VTY_NEWLINE);
+ vty_out (vty, " AS:%s", VTY_NEWLINE);
+ vty_out (vty, "%s", VTY_NEWLINE);
+ show_ipv6_ospf6_lsdb (vty, argc, argv, ospf6->lsdb);
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (show_ipv6_ospf6_database,
+ show_ipv6_ospf6_database_type_cmd,
+ "show ipv6 ospf6 database (router|network|as-external|intra-prefix|inter-prefix|inter-router|link|*|HEX|dump|detail)",
+ SHOW_STR
+ IP6_STR
+ OSPF6_STR
+ "LSA Database\n"
+ "Router-LSA\n"
+ "Network-LSA\n"
+ "AS-External-LSA\n"
+ "Intra-Area-Prefix-LSA\n"
+ "Inter-Area-Router-LSA\n"
+ "Inter-Area-Prefix-LSA\n"
+ "Link-LSA\n"
+ "All LS Type\n"
+ "Specify LS Type by Hex\n"
+ "Dump raw LSA data in Hex\n"
+ "show detail of LSAs\n"
+ )
+
+ALIAS (show_ipv6_ospf6_database,
+ show_ipv6_ospf6_database_type_id_cmd,
+ "show ipv6 ospf6 database (router|network|as-external|intra-prefix|inter-prefix|inter-router|link|*|HEX) (A.B.C.D|*|dump|detail)",
+ SHOW_STR
+ IP6_STR
+ OSPF6_STR
+ "LSA Database\n"
+ "Router-LSA\n"
+ "Network-LSA\n"
+ "AS-External-LSA\n"
+ "Intra-Area-Prefix-LSA\n"
+ "Inter-Area-Router-LSA\n"
+ "Inter-Area-Prefix-LSA\n"
+ "Link-LSA\n"
+ "All LS Type\n"
+ "Specify LS Type by Hex\n"
+ "Link State ID\n"
+ "All Link State ID\n"
+ "Dump raw LSA data in Hex\n"
+ "show detail of LSAs\n"
+ )
+
+ALIAS (show_ipv6_ospf6_database,
+ show_ipv6_ospf6_database_type_id_adv_router_cmd,
+ "show ipv6 ospf6 database (router|network|as-external|intra-prefix|inter-prefix|inter-router|link|*|HEX) (A.B.C.D|*) (A.B.C.D|*|dump|detail)",
+ SHOW_STR
+ IP6_STR
+ OSPF6_STR
+ "LSA Database\n"
+ "Router-LSA\n"
+ "Network-LSA\n"
+ "AS-External-LSA\n"
+ "Intra-Area-Prefix-LSA\n"
+ "Inter-Area-Router-LSA\n"
+ "Inter-Area-Prefix-LSA\n"
+ "Link-LSA\n"
+ "All LS Type\n"
+ "Specify LS Type by Hex\n"
+ "Link State ID\n"
+ "All Link State ID\n"
+ "Advertising Router\n"
+ "All Advertising Router\n"
+ "Dump raw LSA data in Hex\n"
+ "show detail of LSAs\n"
+ )
+
+ALIAS (show_ipv6_ospf6_database,
+ show_ipv6_ospf6_database_type_id_adv_router_dump_cmd,
+ "show ipv6 ospf6 database (router|network|as-external|intra-prefix|inter-prefix|inter-router|link|*|HEX) (A.B.C.D|*) (A.B.C.D|*) (dump|detail|)",
+ SHOW_STR
+ IP6_STR
+ OSPF6_STR
+ "LSA Database\n"
+ "Router-LSA\n"
+ "Network-LSA\n"
+ "AS-External-LSA\n"
+ "Intra-Area-Prefix-LSA\n"
+ "Inter-Area-Router-LSA\n"
+ "Inter-Area-Prefix-LSA\n"
+ "Link-LSA\n"
+ "All LS Type\n"
+ "Specify LS Type by Hex\n"
+ "Link State ID\n"
+ "All Link State ID\n"
+ "Advertising Router\n"
+ "All Advertising Router\n"
+ "Dump raw LSA data in Hex\n"
+ "show detail of LSAs\n"
+ )
+
+void
+ospf6_lsdb_init ()
+{
+ install_element (VIEW_NODE, &show_ipv6_ospf6_database_cmd);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_cmd);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_id_cmd);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_id_adv_router_cmd);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_id_adv_router_dump_cmd);
+
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_database_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_id_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_id_adv_router_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_id_adv_router_dump_cmd);
+}
+
+
diff --git a/ospf6d/ospf6_lsdb.h b/ospf6d/ospf6_lsdb.h
new file mode 100644
index 00000000..50eedc85
--- /dev/null
+++ b/ospf6d/ospf6_lsdb.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2002 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef OSPF6_LSDB_H
+#define OSPF6_LSDB_H
+
+#include "prefix.h"
+#include "table.h"
+
+#include "ospf6_prefix.h"
+#include "ospf6_lsa.h"
+
+struct ospf6_lsdb_node
+{
+ struct prefix_ipv6 key;
+
+ struct route_node *node;
+ struct route_node *next;
+
+ struct ospf6_lsa *lsa;
+};
+
+struct ospf6_lsdb
+{
+ struct route_table *table;
+ u_int32_t count;
+ void (*hook) (struct ospf6_lsa *);
+};
+
+/* int ospf6_lsdb_is_end (struct ospf6_lsdb_node *lsdb_node); */
+#define ospf6_lsdb_is_end(lsdb_node) ((lsdb_node)->node == NULL ? 1 : 0)
+
+/* global holding hooks for each LS type */
+struct ospf6_lsdb_hook_t
+{
+ void (*hook) (struct ospf6_lsa *old, struct ospf6_lsa *new);
+};
+extern struct ospf6_lsdb_hook_t *ospf6_lsdb_hook;
+
+/* Function Prototypes */
+struct ospf6_lsdb * ospf6_lsdb_create ();
+void ospf6_lsdb_delete (struct ospf6_lsdb *lsdb);
+
+void ospf6_lsdb_remove_maxage (struct ospf6_lsdb *lsdb);
+
+struct ospf6_lsa *
+ospf6_lsdb_lookup (u_int16_t type, u_int32_t id, u_int32_t adv_router,
+ void *scope);
+
+void ospf6_lsdb_install (struct ospf6_lsa *new);
+
+void ospf6_lsdb_head (struct ospf6_lsdb_node *node, struct ospf6_lsdb *lsdb);
+void ospf6_lsdb_type (struct ospf6_lsdb_node *node, u_int16_t type,
+ struct ospf6_lsdb *lsdb);
+void ospf6_lsdb_type_router (struct ospf6_lsdb_node *node, u_int16_t type,
+ u_int32_t adv_router, struct ospf6_lsdb *lsdb);
+void ospf6_lsdb_next (struct ospf6_lsdb_node *node);
+
+void ospf6_lsdb_add (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb);
+void ospf6_lsdb_remove (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb);
+void ospf6_lsdb_remove_all (struct ospf6_lsdb *lsdb);
+
+struct ospf6_lsa *
+ospf6_lsdb_lookup_lsdb (u_int16_t type, u_int32_t id, u_int32_t adv_router,
+ struct ospf6_lsdb *lsdb);
+
+void ospf6_lsdb_init ();
+
+#endif /* OSPF6_LSDB_H */
+
diff --git a/ospf6d/ospf6_main.c b/ospf6d/ospf6_main.c
new file mode 100644
index 00000000..5ab517f3
--- /dev/null
+++ b/ospf6d/ospf6_main.c
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <zebra.h>
+#include "getopt.h"
+#include "thread.h"
+#include "log.h"
+#include "version.h"
+#include "command.h"
+#include "vty.h"
+#include "memory.h"
+
+#include "ospf6d.h"
+#include "ospf6_network.h"
+
+void ospf6_init ();
+void ospf6_terminate ();
+void nexthop_init ();
+int ospf6_receive (struct thread *);
+
+extern int ospf6_sock;
+
+/* Default configuration file name for ospf6d. */
+#define OSPF6_DEFAULT_CONFIG "ospf6d.conf"
+/* Default port values. */
+#define OSPF6_VTY_PORT 2606
+
+/* ospf6d options, we use GNU getopt library. */
+struct option longopts[] =
+{
+ { "daemon", no_argument, NULL, 'd'},
+ { "config_file", required_argument, NULL, 'f'},
+ { "pid_file", required_argument, NULL, 'i'},
+ { "vty_addr", required_argument, NULL, 'A'},
+ { "vty_port", required_argument, NULL, 'P'},
+ { "version", no_argument, NULL, 'v'},
+ { "help", no_argument, NULL, 'h'},
+ { 0 }
+};
+
+/* Configuration file and directory. */
+char config_current[] = OSPF6_DEFAULT_CONFIG;
+char config_default[] = SYSCONFDIR OSPF6_DEFAULT_CONFIG;
+
+/* ospf6d program name. */
+
+/* is daemon? */
+int daemon_mode = 0;
+
+/* Master of threads. */
+struct thread_master *master;
+
+/* Process ID saved for use by init system */
+char *pid_file = PATH_OSPF6D_PID;
+
+/* for reload */
+char _cwd[64];
+char _progpath[64];
+int _argc;
+char **_argv;
+char **_envp;
+
+/* Help information display. */
+static void
+usage (char *progname, int status)
+{
+ if (status != 0)
+ fprintf (stderr, "Try `%s --help' for more information.\n", progname);
+ else
+ {
+ printf ("Usage : %s [OPTION...]\n\n\
+Daemon which manages OSPF version 3.\n\n\
+-d, --daemon Runs in daemon mode\n\
+-f, --config_file Set configuration file name\n\
+-i, --pid_file Set process identifier file name\n\
+-A, --vty_addr Set vty's bind address\n\
+-P, --vty_port Set vty's port number\n\
+-v, --version Print program version\n\
+-h, --help Display this help and exit\n\
+\n\
+Report bugs to yasu@sfc.wide.ad.jp\n", progname);
+ }
+
+ exit (status);
+}
+
+
+void
+_reload ()
+{
+ zlog_notice ("OSPF6d (Zebra-%s ospf6d-%s) reloaded",
+ ZEBRA_VERSION, OSPF6_DAEMON_VERSION);
+ ospf6_zebra_finish ();
+ vty_finish ();
+ execve (_progpath, _argv, _envp);
+}
+
+void
+terminate (int i)
+{
+ ospf6_delete (ospf6);
+ unlink (PATH_OSPF6D_PID);
+ zlog_notice ("OSPF6d (Zebra-%s ospf6d-%s) terminated",
+ ZEBRA_VERSION, OSPF6_DAEMON_VERSION);
+ exit (i);
+}
+
+/* SIGHUP handler. */
+void
+sighup (int sig)
+{
+ zlog_info ("SIGHUP received");
+ _reload ();
+}
+
+/* SIGINT handler. */
+void
+sigint (int sig)
+{
+ zlog_info ("SIGINT received");
+ terminate (0);
+}
+
+/* SIGTERM handler. */
+void
+sigterm (int sig)
+{
+ zlog_info ("SIGTERM received");
+ terminate (0);
+}
+
+/* SIGUSR1 handler. */
+void
+sigusr1 (int sig)
+{
+ zlog_info ("SIGUSR1 received");
+ zlog_rotate (NULL);
+}
+
+/* Signale wrapper. */
+RETSIGTYPE *
+signal_set (int signo, void (*func)(int))
+{
+ int ret;
+ struct sigaction sig;
+ struct sigaction osig;
+
+ sig.sa_handler = func;
+ sigemptyset (&sig.sa_mask);
+ sig.sa_flags = 0;
+#ifdef SA_RESTART
+ sig.sa_flags |= SA_RESTART;
+#endif /* SA_RESTART */
+
+ ret = sigaction (signo, &sig, &osig);
+
+ if (ret < 0)
+ return (SIG_ERR);
+ else
+ return (osig.sa_handler);
+}
+
+/* Initialization of signal handles. */
+void
+signal_init ()
+{
+ signal_set (SIGHUP, sighup);
+ signal_set (SIGINT, sigint);
+ signal_set (SIGTERM, sigterm);
+ signal_set (SIGPIPE, SIG_IGN);
+#ifdef SIGTSTP
+ signal_set (SIGTSTP, SIG_IGN);
+#endif
+#ifdef SIGTTIN
+ signal_set (SIGTTIN, SIG_IGN);
+#endif
+#ifdef SIGTTOU
+ signal_set (SIGTTOU, SIG_IGN);
+#endif
+ signal_set (SIGUSR1, sigusr1);
+}
+
+/* Main routine of ospf6d. Treatment of argument and start ospf finite
+ state machine is handled here. */
+int
+main (int argc, char *argv[], char *envp[])
+{
+ char *p;
+ int opt;
+ char *vty_addr = NULL;
+ int vty_port = 0;
+ char *config_file = NULL;
+ char *progname;
+ struct thread thread;
+ int flag;
+
+ /* Set umask before anything for security */
+ umask (0027);
+
+ /* Preserve name of myself. */
+ progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]);
+
+ /* for reload */
+ _argc = argc;
+ _argv = argv;
+ _envp = envp;
+ getcwd (_cwd, sizeof (_cwd));
+ if (*argv[0] == '.')
+ snprintf (_progpath, sizeof (_progpath), "%s/%s", _cwd, _argv[0]);
+ else
+ snprintf (_progpath, sizeof (_progpath), "%s", argv[0]);
+
+ /* Command line argument treatment. */
+ while (1)
+ {
+ opt = getopt_long (argc, argv, "df:hp:A:P:v", longopts, 0);
+
+ if (opt == EOF)
+ break;
+
+ switch (opt)
+ {
+ case 0:
+ break;
+ case 'd':
+ daemon_mode = 1;
+ break;
+ case 'f':
+ config_file = optarg;
+ break;
+ case 'A':
+ vty_addr = optarg;
+ break;
+ case 'i':
+ pid_file = optarg;
+ break;
+ case 'P':
+ vty_port = atoi (optarg);
+ break;
+ case 'v':
+ print_version (progname);
+ exit (0);
+ break;
+ case 'h':
+ usage (progname, 0);
+ break;
+ default:
+ usage (progname, 1);
+ break;
+ }
+ }
+
+ /* thread master */
+ master = thread_master_create ();
+
+ /* Initializations. */
+ if (! daemon_mode)
+ flag = ZLOG_STDOUT;
+ else
+ flag = 0;
+
+ zlog_default = openzlog (progname, flag, ZLOG_OSPF6,
+ LOG_CONS|LOG_NDELAY|LOG_PERROR|LOG_PID,
+ LOG_DAEMON);
+ signal_init ();
+ cmd_init (1);
+ vty_init ();
+ ospf6_init ();
+ memory_init ();
+ sort_node ();
+
+ /* parse config file */
+ vty_read_config (config_file, config_current, config_default);
+
+ if (daemon_mode)
+ daemon (0, 0);
+
+ /* pid file create */
+#if 0
+ pid_output_lock (pid_file);
+#else
+ pid_output (pid_file);
+#endif
+
+ /* Make ospf protocol socket. */
+ ospf6_serv_sock ();
+ thread_add_read (master, ospf6_receive, NULL, ospf6_sock);
+
+ /* Make ospf vty socket. */
+ vty_serv_sock (vty_addr,
+ vty_port ? vty_port : OSPF6_VTY_PORT, OSPF6_VTYSH_PATH);
+
+ /* Print start message */
+ zlog_notice ("OSPF6d (Zebra-%s ospf6d-%s) starts",
+ ZEBRA_VERSION, OSPF6_DAEMON_VERSION);
+
+ /* Start finite state machine, here we go! */
+ while (thread_fetch (master, &thread))
+ thread_call (&thread);
+
+ /* Log in case thread failed */
+ zlog_warn ("Thread failed");
+ terminate (0);
+
+ /* Not reached. */
+ exit (0);
+}
+
diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c
new file mode 100644
index 00000000..f6577a99
--- /dev/null
+++ b/ospf6d/ospf6_message.c
@@ -0,0 +1,1972 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "ospf6d.h"
+
+int
+is_ospf6_message_dump (u_char type)
+{
+ if (type > OSPF6_MESSAGE_TYPE_LSACK)
+ type = OSPF6_MESSAGE_TYPE_UNKNOWN;
+
+ switch (type)
+ {
+ case OSPF6_MESSAGE_TYPE_UNKNOWN:
+ return 1;
+ break;
+ case OSPF6_MESSAGE_TYPE_HELLO:
+ if (IS_OSPF6_DUMP_HELLO)
+ return 1;
+ break;
+ case OSPF6_MESSAGE_TYPE_DBDESC:
+ if (IS_OSPF6_DUMP_DBDESC)
+ return 1;
+ break;
+ case OSPF6_MESSAGE_TYPE_LSREQ:
+ if (IS_OSPF6_DUMP_LSREQ)
+ return 1;
+ break;
+ case OSPF6_MESSAGE_TYPE_LSUPDATE:
+ if (IS_OSPF6_DUMP_LSUPDATE)
+ return 1;
+ break;
+ case OSPF6_MESSAGE_TYPE_LSACK:
+ if (IS_OSPF6_DUMP_LSACK)
+ return 1;
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+#define IS_OSPF6_DUMP_MESSAGE(x) (is_ospf6_message_dump(x))
+
+char *ospf6_message_type_string[] =
+{
+ "Unknown", "Hello", "DbDesc", "LSReq", "LSUpdate", "LSAck", NULL
+};
+
+void
+ospf6_message_log_lsa_header (struct ospf6_lsa_header *lsa_header)
+{
+ char buf_id[16], buf_router[16], typebuf[32];
+
+ inet_ntop (AF_INET, &lsa_header->advrtr, buf_router, sizeof (buf_router));
+ inet_ntop (AF_INET, &lsa_header->ls_id, buf_id, sizeof (buf_id));
+ zlog_info (" [%s ID=%s Adv=%s]",
+ ospf6_lsa_type_string (lsa_header->type, typebuf,
+ sizeof (typebuf)),
+ buf_id, buf_router);
+ zlog_info (" Age=%hu SeqNum=%#lx Cksum=%#hx Len=%hu",
+ ntohs (lsa_header->age), (u_long)ntohl (lsa_header->seqnum),
+ ntohs (lsa_header->checksum), ntohs (lsa_header->length));
+}
+
+static void
+ospf6_message_log_unknown (struct iovec *message)
+{
+ zlog_info ("Message: Unknown");
+}
+
+static void
+ospf6_message_log_hello (struct iovec *message)
+{
+ struct ospf6_header *ospf6_header;
+ u_int16_t length_left;
+ struct ospf6_hello *hello;
+ char dr_str[16], bdr_str[16];
+ char *start, *end, *current;
+
+ /* calculate length */
+ ospf6_header = (struct ospf6_header *) message[0].iov_base;
+ length_left = ntohs (ospf6_header->len) - sizeof (struct ospf6_header);
+ length_left = (length_left < iov_totallen (message) - sizeof (struct ospf6_header) ?
+ length_left : iov_totallen (message) - sizeof (struct ospf6_header));
+
+ hello = (struct ospf6_hello *) message[1].iov_base;
+
+ inet_ntop (AF_INET, &hello->dr, dr_str, sizeof (dr_str));
+ inet_ntop (AF_INET, &hello->bdr, bdr_str, sizeof (bdr_str));
+
+ zlog_info (" IFID:%ld Priority:%d Option:%s",
+ (u_long)ntohl (hello->interface_id), hello->rtr_pri, "xxx");
+ zlog_info (" HelloInterval:%hu Deadinterval:%hu",
+ ntohs (hello->hello_interval),
+ ntohs (hello->router_dead_interval));
+ zlog_info (" DR:%s BDR:%s", dr_str, bdr_str);
+
+ start = (char *) (hello + 1);
+ if (start >= (char *) message[1].iov_base + message[1].iov_len)
+ start = message[2].iov_base;
+ end = (char *) start + (length_left - sizeof (struct ospf6_hello));
+
+ for (current = start; current < end; current += sizeof (u_int32_t))
+ {
+ char neighbor[16];
+ inet_ntop (AF_INET, current, neighbor, sizeof (neighbor));
+ zlog_info (" Neighbor: %s", neighbor);
+ }
+}
+
+static void
+ospf6_message_log_dbdesc (struct iovec *message)
+{
+ struct ospf6_header *ospf6_header;
+ u_int16_t length_left;
+ struct ospf6_dbdesc *dbdesc;
+ int i;
+ char buffer[16];
+ struct ospf6_lsa_header *lsa_header;
+
+ /* calculate length */
+ ospf6_header = (struct ospf6_header *) message[0].iov_base;
+ length_left = ntohs (ospf6_header->len) - sizeof (struct ospf6_header);
+ length_left = (length_left < iov_totallen (message) - sizeof (struct ospf6_header) ?
+ length_left : iov_totallen (message) - sizeof (struct ospf6_header));
+
+ dbdesc = (struct ospf6_dbdesc *) message[1].iov_base;
+ ospf6_options_string (dbdesc->options, buffer, sizeof (buffer));
+
+ zlog_info (" Option:%s IFMTU:%hu", buffer, ntohs (dbdesc->ifmtu));
+ zlog_info (" Bits:%s%s%s SeqNum:%#lx",
+ (DD_IS_IBIT_SET (dbdesc->bits) ? "I" : "-"),
+ (DD_IS_MBIT_SET (dbdesc->bits) ? "M" : "-"),
+ (DD_IS_MSBIT_SET (dbdesc->bits) ? "m" : "s"),
+ (u_long)ntohl (dbdesc->seqnum));
+
+ for (lsa_header = (struct ospf6_lsa_header *) (dbdesc + 1);
+ (char *)(lsa_header + 1) <= (char *)(message[1].iov_base + message[1].iov_len) &&
+ (char *)(lsa_header + 1) <= (char *)dbdesc + length_left;
+ lsa_header++)
+ ospf6_message_log_lsa_header (lsa_header);
+
+ length_left -= message[1].iov_len;
+ for (i = 2; message[i].iov_base; i++)
+ {
+ for (lsa_header = (struct ospf6_lsa_header *) message[i].iov_base;
+ (char *)(lsa_header + 1) <= (char *) (message[i].iov_base +
+ message[i].iov_len) &&
+ (char *)(lsa_header + 1) <= (char *) (message[i].iov_base + length_left);
+ lsa_header++)
+ ospf6_message_log_lsa_header (lsa_header);
+ length_left -= message[i].iov_len;
+ }
+}
+
+static void
+ospf6_message_log_lsreq (struct iovec *message)
+{
+ struct ospf6_header *ospf6_header;
+ u_int16_t length_left;
+ int i;
+ struct ospf6_lsreq *lsreq;
+ char buf_router[16], buf_id[16], buf_type[16];
+
+ /* calculate length */
+ ospf6_header = (struct ospf6_header *) message[0].iov_base;
+ length_left = ntohs (ospf6_header->len) - sizeof (struct ospf6_header);
+ length_left = (length_left < iov_totallen (message) - sizeof (struct ospf6_header) ?
+ length_left : iov_totallen (message) - sizeof (struct ospf6_header));
+
+ for (i = 1; message[i].iov_base; i++)
+ {
+ for (lsreq = (struct ospf6_lsreq *) message[i].iov_base;
+ (char *)(lsreq + 1) <= (char *) (message[i].iov_base + message[i].iov_len) &&
+ (char *)(lsreq + 1) <= (char *) (message[i].iov_base + length_left);
+ lsreq++)
+ {
+ inet_ntop (AF_INET, &lsreq->adv_router, buf_router, sizeof (buf_router));
+ inet_ntop (AF_INET, &lsreq->id, buf_id, sizeof (buf_id));
+ zlog_info (" [%s ID=%s Adv=%s]",
+ ospf6_lsa_type_string (lsreq->type, buf_type,
+ sizeof (buf_type)),
+ buf_id, buf_router);
+ }
+ length_left -= message[i].iov_len;
+ }
+}
+
+static void
+ospf6_message_log_lsupdate (struct iovec *message)
+{
+ struct ospf6_header *ospf6_header;
+ u_int16_t length_left;
+ int i, lsanum;
+ struct ospf6_lsupdate *lsupdate;
+ struct ospf6_lsa_header *lsa_header;
+
+ /* calculate length */
+ ospf6_header = (struct ospf6_header *) message[0].iov_base;
+ length_left = ntohs (ospf6_header->len) - sizeof (struct ospf6_header);
+ length_left = (length_left < iov_totallen (message) - sizeof (struct ospf6_header) ?
+ length_left : iov_totallen (message) - sizeof (struct ospf6_header));
+
+ lsupdate = (struct ospf6_lsupdate *) message[1].iov_base;
+ lsanum = ntohl (lsupdate->lsupdate_num);
+
+ zlog_info (" Number of LSA: #%d", lsanum);
+
+ for (lsa_header = (struct ospf6_lsa_header *) (lsupdate + 1);
+ (char *)lsa_header < (char *)(message[1].iov_base + message[1].iov_len) &&
+ (char *)lsa_header < (char *)(message[1].iov_base + length_left);
+ lsa_header = OSPF6_LSA_NEXT (lsa_header))
+ ospf6_message_log_lsa_header (lsa_header);
+ length_left -= message[1].iov_len;
+
+ for (i = 2; message[i].iov_base; i++)
+ {
+
+ for (lsa_header = (struct ospf6_lsa_header *) message[i].iov_base;
+ (char *)lsa_header < (char *) (message[i].iov_base + message[i].iov_len) &&
+ (char *)lsa_header < (char *) (message[i].iov_base + length_left);
+ lsa_header = OSPF6_LSA_NEXT (lsa_header))
+ ospf6_message_log_lsa_header (lsa_header);
+ length_left -= message[i].iov_len;
+ }
+}
+
+static void
+ospf6_message_log_lsack (struct iovec *message)
+{
+ struct ospf6_header *ospf6_header;
+ u_int16_t length_left;
+ struct ospf6_lsa_header *lsa_header;
+ int i;
+
+ /* calculate length */
+ ospf6_header = (struct ospf6_header *) message[0].iov_base;
+ length_left = ntohs (ospf6_header->len) - sizeof (struct ospf6_header);
+ length_left = (length_left < iov_totallen (message) - sizeof (struct ospf6_header) ?
+ length_left : iov_totallen (message) - sizeof (struct ospf6_header));
+
+ for (i = 1; message[i].iov_base; i++)
+ {
+ for (lsa_header = (struct ospf6_lsa_header *) message[i].iov_base;
+ (char *)(lsa_header + 1) <= (char *) (message[i].iov_base +
+ message[i].iov_len) &&
+ (char *)(lsa_header + 1) <= (char *) (message[i].iov_base + length_left);
+ lsa_header++)
+ ospf6_message_log_lsa_header (lsa_header);
+ length_left -= message[i].iov_len;
+ }
+}
+
+struct {
+ void (*message_log) (struct iovec *);
+} ospf6_message_log_body [] =
+{
+ {ospf6_message_log_unknown},
+ {ospf6_message_log_hello},
+ {ospf6_message_log_dbdesc},
+ {ospf6_message_log_lsreq},
+ {ospf6_message_log_lsupdate},
+ {ospf6_message_log_lsack},
+};
+
+static void
+ospf6_message_log (struct iovec *message)
+{
+ struct ospf6_header *o6h;
+ char router_id[16], area_id[16];
+ u_char type;
+
+ assert (message[0].iov_len == sizeof (struct ospf6_header));
+ o6h = (struct ospf6_header *) message[0].iov_base;
+
+ inet_ntop (AF_INET, &o6h->router_id, router_id, sizeof (router_id));
+ inet_ntop (AF_INET, &o6h->area_id, area_id, sizeof (area_id));
+
+ zlog_info (" OSPFv%d Type:%d Len:%hu RouterID:%s",
+ o6h->version, o6h->type, ntohs (o6h->len), router_id);
+ zlog_info (" AreaID:%s Cksum:%hx InstanceID:%d",
+ area_id, ntohs (o6h->cksum), o6h->instance_id);
+
+ type = (OSPF6_MESSAGE_TYPE_UNKNOWN < o6h->type &&
+ o6h->type <= OSPF6_MESSAGE_TYPE_LSACK ?
+ o6h->type : OSPF6_MESSAGE_TYPE_UNKNOWN);
+ (* ospf6_message_log_body[type].message_log) (&message[0]);
+}
+
+int
+ospf6_opt_is_mismatch (unsigned char opt, char *options1, char *options2)
+{
+ return (OSPF6_OPT_ISSET (options1, opt) ^ OSPF6_OPT_ISSET (options2, opt));
+}
+
+
+void
+ospf6_process_unknown (struct iovec *message,
+ struct in6_addr *src,
+ struct in6_addr *dst,
+ struct ospf6_interface *o6i,
+ u_int32_t router_id)
+{
+ zlog_warn ("unknown message type, drop");
+}
+
+void
+ospf6_process_hello (struct iovec *message,
+ struct in6_addr *src,
+ struct in6_addr *dst,
+ struct ospf6_interface *o6i,
+ u_int32_t router_id)
+{
+ struct ospf6_header *ospf6_header;
+ u_int16_t length;
+ struct ospf6_hello *hello;
+ char changes = 0;
+#define CHANGE_RTRPRI (1 << 0)
+#define CHANGE_DR (1 << 1)
+#define CHANGE_BDR (1 << 2)
+ int twoway = 0, backupseen = 0, nbchange = 0;
+ u_int32_t *router_id_ptr;
+ int i, seenrtrnum = 0, router_id_space = 0;
+ char strbuf[64];
+ struct ospf6_neighbor *o6n = NULL;
+
+ /* assert interface */
+ assert (o6i);
+
+ /* caluculate length */
+ ospf6_header = (struct ospf6_header *) message[0].iov_base;
+ length = ntohs (ospf6_header->len) - sizeof (struct ospf6_header);
+ length = (length < message[1].iov_len ? length : message[1].iov_len);
+
+ /* set hello pointer */
+ hello = (struct ospf6_hello *) message[1].iov_base;
+
+ /* find neighbor. if cannot be found, create */
+ o6n = ospf6_neighbor_lookup (router_id, o6i);
+ if (!o6n)
+ {
+ o6n = ospf6_neighbor_create (router_id, o6i);
+ o6n->ifid = ntohl (hello->interface_id);
+ o6n->prevdr = o6n->dr = hello->dr;
+ o6n->prevbdr = o6n->bdr = hello->bdr;
+ o6n->priority = hello->rtr_pri;
+ memcpy (&o6n->hisaddr, src, sizeof (struct in6_addr));
+ }
+
+ /* HelloInterval check */
+ if (ntohs (hello->hello_interval) != o6i->hello_interval)
+ {
+ zlog_warn ("HelloInterval mismatch with %s", o6n->str);
+ return;
+ }
+
+ /* RouterDeadInterval check */
+ if (ntohs (hello->router_dead_interval)
+ != o6i->dead_interval)
+ {
+ zlog_warn ("RouterDeadInterval mismatch with %s", o6n->str);
+ return;
+ }
+
+ /* check options */
+ /* Ebit */
+ if (ospf6_opt_is_mismatch (OSPF6_OPT_E, hello->options, o6i->area->options))
+ {
+ zlog_warn ("Ebit mismatch with %s", o6n->str);
+ return;
+ }
+
+ /* RouterPriority set */
+ if (o6n->priority != hello->rtr_pri)
+ {
+ o6n->priority = hello->rtr_pri;
+ if (IS_OSPF6_DUMP_HELLO)
+ zlog_info ("%s: RouterPriority changed", o6n->str);
+ changes |= CHANGE_RTRPRI;
+ }
+
+ /* DR set */
+ if (o6n->dr != hello->dr)
+ {
+ /* save previous dr, set current */
+ o6n->prevdr = o6n->dr;
+ o6n->dr = hello->dr;
+ inet_ntop (AF_INET, &o6n->dr, strbuf, sizeof (strbuf));
+ if (IS_OSPF6_DUMP_HELLO)
+ zlog_info ("%s declare %s as DR", o6n->str, strbuf);
+ changes |= CHANGE_DR;
+ }
+
+ /* BDR set */
+ if (o6n->bdr != hello->bdr)
+ {
+ /* save previous bdr, set current */
+ o6n->prevbdr = o6n->bdr;
+ o6n->bdr = hello->bdr;
+ inet_ntop (AF_INET, &o6n->bdr, strbuf, sizeof (strbuf));
+ if (IS_OSPF6_DUMP_HELLO)
+ zlog_info ("%s declare %s as BDR", o6n->str, strbuf);
+ changes |= CHANGE_BDR;
+ }
+
+ /* TwoWay check */
+ router_id_space = length - sizeof (struct ospf6_hello);
+ seenrtrnum = router_id_space / sizeof (u_int32_t);
+ router_id_ptr = (u_int32_t *) (hello + 1);
+ for (i = 0; i < seenrtrnum; i++)
+ {
+ if (*router_id_ptr == o6i->area->ospf6->router_id)
+ twoway++;
+ router_id_ptr++;
+ }
+
+ /* execute neighbor events */
+ thread_execute (master, hello_received, o6n, 0);
+ if (twoway)
+ thread_execute (master, twoway_received, o6n, 0);
+ else
+ thread_execute (master, oneway_received, o6n, 0);
+
+ /* BackupSeen check */
+ if (o6i->state == IFS_WAITING)
+ {
+ if (hello->dr == hello->bdr &&
+ hello->dr == o6n->router_id)
+ zlog_warn ("*** DR Election of %s is illegal", o6n->str);
+
+ if (hello->bdr == o6n->router_id)
+ backupseen++;
+ else if (hello->dr == o6n->router_id && hello->bdr == 0)
+ backupseen++;
+ }
+
+ /* NeighborChange check */
+ if (changes & CHANGE_RTRPRI)
+ nbchange++;
+ if (changes & CHANGE_DR)
+ if (o6n->prevdr == o6n->router_id || o6n->dr == o6n->router_id)
+ nbchange++;
+ if (changes & CHANGE_BDR)
+ if (o6n->prevbdr == o6n->router_id || o6n->bdr == o6n->router_id)
+ nbchange++;
+
+ /* schedule interface events */
+ if (backupseen)
+ thread_add_event (master, backup_seen, o6i, 0);
+ if (nbchange)
+ thread_add_event (master, neighbor_change, o6i, 0);
+
+ return;
+}
+
+int
+ospf6_dbdesc_is_master (struct ospf6_neighbor *o6n)
+{
+ char buf[128];
+
+ if (o6n->router_id == ospf6->router_id)
+ {
+ inet_ntop (AF_INET6, &o6n->hisaddr, buf, sizeof (buf));
+ zlog_warn ("Message: Neighbor router-id conflicts: %s: %s",
+ o6n->str, buf);
+ return -1;
+ }
+ else if (ntohl (o6n->router_id) > ntohl (ospf6->router_id))
+ return 0;
+ return 1;
+}
+
+int
+ospf6_dbdesc_is_duplicate (struct ospf6_dbdesc *received,
+ struct ospf6_dbdesc *last_received)
+{
+ if (memcmp (received->options, last_received->options, 3) != 0)
+ return 0;
+ if (received->ifmtu != last_received->ifmtu)
+ return 0;
+ if (received->bits != last_received->bits)
+ return 0;
+ if (received->seqnum != last_received->seqnum)
+ return 0;
+ return 1;
+}
+
+void
+ospf6_process_dbdesc_master (struct iovec *message, struct ospf6_neighbor *o6n)
+{
+ struct ospf6_header *ospf6_header;
+ u_int16_t length, lsa_count;
+ struct ospf6_dbdesc *dbdesc;
+ struct ospf6_lsa_header *lsa_header;
+
+ /* caluculate length */
+ ospf6_header = (struct ospf6_header *) message[0].iov_base;
+ length = ntohs (ospf6_header->len) - sizeof (struct ospf6_header);
+ length = (length < message[1].iov_len ? length : message[1].iov_len);
+
+ /* set database description pointer */
+ dbdesc = (struct ospf6_dbdesc *) message[1].iov_base;
+
+ switch (o6n->state)
+ {
+ case NBS_DOWN:
+ case NBS_ATTEMPT:
+ case NBS_TWOWAY:
+ if (IS_OSPF6_DUMP_DBDESC)
+ zlog_info ("DbDesc from %s Ignored: state less than Init",
+ o6n->str);
+ return;
+
+ case NBS_INIT:
+ thread_execute (master, twoway_received, o6n, 0);
+ if (o6n->state != NBS_EXSTART)
+ {
+ if (IS_OSPF6_DUMP_DBDESC)
+ zlog_info ("DbDesc from %s Ignored: state less than ExStart",
+ o6n->str);
+ return;
+ }
+ /* else fall through to ExStart */
+ case NBS_EXSTART:
+ if (DDBIT_IS_SLAVE (dbdesc->bits) &&
+ !DDBIT_IS_INITIAL (dbdesc->bits) &&
+ ntohl (dbdesc->seqnum) == o6n->dbdesc_seqnum)
+ {
+ ospf6_neighbor_dbex_init (o6n);
+
+ if (o6n->thread_rxmt_dbdesc)
+ thread_cancel (o6n->thread_rxmt_dbdesc);
+ o6n->thread_rxmt_dbdesc = (struct thread *) NULL;
+
+ thread_add_event (master, negotiation_done, o6n, 0);
+ }
+ else
+ {
+ if (IS_OSPF6_DUMP_DBDESC)
+ zlog_info (" negotiation failed with %s", o6n->str);
+ return;
+ }
+ break;
+
+ case NBS_EXCHANGE:
+ /* duplicate dbdesc dropped by master */
+ if (!memcmp (dbdesc, &o6n->last_dd,
+ sizeof (struct ospf6_dbdesc)))
+ {
+ if (IS_OSPF6_DUMP_DBDESC)
+ zlog_info (" duplicate dbdesc, drop");
+ return;
+ }
+
+ /* check Initialize bit and Master/Slave bit */
+ if (DDBIT_IS_INITIAL (dbdesc->bits))
+ {
+ if (IS_OSPF6_DUMP_DBDESC)
+ zlog_info ("Initialize bit mismatch");
+ thread_add_event (master, seqnumber_mismatch, o6n, 0);
+ return;
+ }
+ if (DDBIT_IS_MASTER (dbdesc->bits))
+ {
+ if (IS_OSPF6_DUMP_DBDESC)
+ zlog_info ("Master/Slave bit mismatch");
+ thread_add_event (master, seqnumber_mismatch, o6n, 0);
+ return;
+ }
+
+ /* dbdesc option check */
+ if (memcmp (dbdesc->options, o6n->last_dd.options,
+ sizeof (dbdesc->options)))
+ {
+ if (IS_OSPF6_DUMP_DBDESC)
+ zlog_info ("dbdesc option field changed");
+ thread_add_event (master, seqnumber_mismatch, o6n, 0);
+ return;
+ }
+
+ /* dbdesc sequence number check */
+ if (ntohl (dbdesc->seqnum) != o6n->dbdesc_seqnum)
+ {
+ if (IS_OSPF6_DUMP_DBDESC)
+ zlog_warn ("*** dbdesc seqnumber mismatch: %d expected",
+ o6n->dbdesc_seqnum);
+ thread_add_event (master, seqnumber_mismatch, o6n, 0);
+ return;
+ }
+ break;
+
+ case NBS_LOADING:
+ case NBS_FULL:
+ /* duplicate dbdesc dropped by master */
+ if (ospf6_dbdesc_is_duplicate (dbdesc, &o6n->last_dd))
+ {
+ if (IS_OSPF6_DUMP_DBDESC)
+ zlog_info (" duplicate dbdesc, drop");
+ return;
+ }
+ else
+ {
+ if (IS_OSPF6_DUMP_DBDESC)
+ zlog_info (" not duplicate dbdesc in state %s",
+ ospf6_neighbor_state_string[o6n->state]);
+ thread_add_event (master, seqnumber_mismatch, o6n, 0);
+ return;
+ }
+ break; /* not reached */
+
+ default:
+ assert (0);
+ break; /* not reached */
+ }
+
+ /* process LSA headers */
+ lsa_count = 0;
+ for (lsa_header = (struct ospf6_lsa_header *) (dbdesc + 1);
+ (char *)(lsa_header + 1) <= (char *)dbdesc + length;
+ lsa_header++)
+ {
+ if (ospf6_dbex_check_dbdesc_lsa_header (lsa_header, o6n) < 0)
+ {
+ thread_add_event (master, seqnumber_mismatch, o6n, 0);
+ return;
+ }
+ lsa_count ++;
+ }
+
+ /* increment dbdesc seqnum */
+ o6n->dbdesc_seqnum++;
+
+ /* cancel transmission/retransmission thread */
+ if (o6n->thread_send_dbdesc)
+ thread_cancel (o6n->thread_send_dbdesc);
+ o6n->thread_send_dbdesc = (struct thread *) NULL;
+ if (o6n->thread_rxmt_dbdesc)
+ thread_cancel (o6n->thread_rxmt_dbdesc);
+ o6n->thread_rxmt_dbdesc = (struct thread *) NULL;
+
+ /* more bit check */
+ if (!DD_IS_MBIT_SET (dbdesc->bits) && !DD_IS_MBIT_SET (o6n->dbdesc_bits))
+ thread_add_event (master, exchange_done, o6n, 0);
+ else
+ o6n->thread_send_dbdesc =
+ thread_add_event (master, ospf6_send_dbdesc, o6n, 0);
+
+ /* save last received dbdesc */
+ memcpy (&o6n->last_dd, dbdesc, sizeof (struct ospf6_dbdesc));
+
+ /* statistics */
+ o6n->lsa_receive[OSPF6_MESSAGE_TYPE_DBDESC] += lsa_count;
+
+ return;
+}
+
+void
+ospf6_process_dbdesc_slave (struct iovec *message, struct ospf6_neighbor *o6n)
+{
+ struct ospf6_header *ospf6_header;
+ u_int16_t length, lsa_count;
+ struct ospf6_dbdesc *dbdesc;
+ struct ospf6_lsa_header *lsa_header;
+
+ /* caluculate length */
+ ospf6_header = (struct ospf6_header *) message[0].iov_base;
+ length = ntohs (ospf6_header->len) - sizeof (struct ospf6_header);
+ length = (length < message[1].iov_len ? length : message[1].iov_len);
+
+ /* set database description pointer */
+ dbdesc = (struct ospf6_dbdesc *) message[1].iov_base;
+
+ switch (o6n->state)
+ {
+ case NBS_DOWN:
+ case NBS_ATTEMPT:
+ case NBS_TWOWAY:
+ return;
+ case NBS_INIT:
+ thread_execute (master, twoway_received, o6n, 0);
+ if (o6n->state != NBS_EXSTART)
+ {
+ return;
+ }
+ /* else fall through to ExStart */
+ case NBS_EXSTART:
+ if (DD_IS_IBIT_SET (dbdesc->bits) &&
+ DD_IS_MBIT_SET (dbdesc->bits) &&
+ DD_IS_MSBIT_SET (dbdesc->bits))
+ {
+ /* Master/Slave bit set to slave */
+ DD_MSBIT_CLEAR (o6n->dbdesc_bits);
+ /* Initialize bit clear */
+ DD_IBIT_CLEAR (o6n->dbdesc_bits);
+ /* sequence number set to master's */
+ o6n->dbdesc_seqnum = ntohl (dbdesc->seqnum);
+ ospf6_neighbor_dbex_init (o6n);
+
+ if (o6n->thread_rxmt_dbdesc)
+ thread_cancel (o6n->thread_rxmt_dbdesc);
+ o6n->thread_rxmt_dbdesc = (struct thread *) NULL;
+
+ thread_add_event (master, negotiation_done, o6n, 0);
+ }
+ else
+ {
+ if (IS_OSPF6_DUMP_DBDESC)
+ zlog_info ("negotiation failed");
+ return;
+ }
+ break;
+
+ case NBS_EXCHANGE:
+ /* duplicate dbdesc dropped by master */
+ if (!memcmp (dbdesc, &o6n->last_dd,
+ sizeof (struct ospf6_dbdesc)))
+ {
+ if (IS_OSPF6_DUMP_DBDESC)
+ zlog_info (" duplicate dbdesc, retransmit dbdesc");
+
+ if (o6n->thread_rxmt_dbdesc)
+ thread_cancel (o6n->thread_rxmt_dbdesc);
+ o6n->thread_rxmt_dbdesc =
+ thread_add_event (master, ospf6_send_dbdesc_rxmt, o6n, 0);
+
+ return;
+ }
+
+ /* check Initialize bit and Master/Slave bit */
+ if (DDBIT_IS_INITIAL (dbdesc->bits))
+ {
+ if (IS_OSPF6_DUMP_DBDESC)
+ zlog_info ("Initialize bit mismatch");
+ thread_add_event (master, seqnumber_mismatch, o6n, 0);
+ return;
+ }
+ if (DDBIT_IS_SLAVE (dbdesc->bits))
+ {
+ if (IS_OSPF6_DUMP_DBDESC)
+ zlog_info ("Master/Slave bit mismatch");
+ thread_add_event (master, seqnumber_mismatch, o6n, 0);
+ return;
+ }
+
+ /* dbdesc option check */
+ if (memcmp (dbdesc->options, o6n->last_dd.options,
+ sizeof (dbdesc->options)))
+ {
+ if (IS_OSPF6_DUMP_DBDESC)
+ zlog_info ("dbdesc option field changed");
+ thread_add_event (master, seqnumber_mismatch, o6n, 0);
+ return;
+ }
+
+ /* dbdesc sequence number check */
+ if (ntohl (dbdesc->seqnum) != o6n->dbdesc_seqnum + 1)
+ {
+ if (IS_OSPF6_DUMP_DBDESC)
+ zlog_warn ("*** dbdesc seqnumber mismatch: %d expected",
+ o6n->dbdesc_seqnum + 1);
+ thread_add_event (master, seqnumber_mismatch, o6n, 0);
+ return;
+ }
+ break;
+
+ case NBS_LOADING:
+ case NBS_FULL:
+ /* duplicate dbdesc cause slave to retransmit */
+ if (ospf6_dbdesc_is_duplicate (dbdesc, &o6n->last_dd))
+ {
+ if (IS_OSPF6_DUMP_DBDESC)
+ zlog_info (" duplicate dbdesc, retransmit");
+
+ if (o6n->thread_rxmt_dbdesc)
+ thread_cancel (o6n->thread_rxmt_dbdesc);
+ o6n->thread_rxmt_dbdesc =
+ thread_add_event (master, ospf6_send_dbdesc_rxmt, o6n, 0);
+
+ return;
+ }
+ else
+ {
+ if (IS_OSPF6_DUMP_DBDESC)
+ zlog_info (" not duplicate dbdesc in state %s",
+ ospf6_neighbor_state_string[o6n->state]);
+ thread_add_event (master, seqnumber_mismatch, o6n, 0);
+ return;
+ }
+ break; /* not reached */
+
+ default:
+ assert (0);
+ break; /* not reached */
+ }
+
+ /* process LSA headers */
+ lsa_count = 0;
+ for (lsa_header = (struct ospf6_lsa_header *) (dbdesc + 1);
+ (char *)(lsa_header + 1) <= (char *)dbdesc + length;
+ lsa_header++)
+ {
+ if (ospf6_dbex_check_dbdesc_lsa_header (lsa_header, o6n) < 0)
+ {
+ thread_add_event (master, seqnumber_mismatch, o6n, 0);
+ return;
+ }
+ lsa_count ++;
+ }
+
+ /* set dbdesc seqnum to master's */
+ o6n->dbdesc_seqnum = ntohl (dbdesc->seqnum);
+
+ if (o6n->thread_send_dbdesc)
+ thread_cancel (o6n->thread_send_dbdesc);
+ o6n->thread_send_dbdesc =
+ thread_add_event (master, ospf6_send_dbdesc, o6n, 0);
+
+ /* save last received dbdesc */
+ memcpy (&o6n->last_dd, dbdesc, sizeof (struct ospf6_dbdesc));
+
+ /* statistics */
+ o6n->lsa_receive[OSPF6_MESSAGE_TYPE_DBDESC] += lsa_count;
+
+ return;
+}
+
+void
+ospf6_process_dbdesc (struct iovec *message,
+ struct in6_addr *src,
+ struct in6_addr *dst,
+ struct ospf6_interface *o6i,
+ u_int32_t router_id)
+{
+ struct ospf6_header *ospf6_header;
+ u_int16_t length;
+ struct ospf6_neighbor *o6n;
+ struct ospf6_dbdesc *dbdesc;
+ int Im_master = 0;
+
+ /* assert interface */
+ assert (o6i);
+
+ /* caluculate length */
+ ospf6_header = (struct ospf6_header *) message[0].iov_base;
+ length = ntohs (ospf6_header->len) - sizeof (struct ospf6_header);
+ length = (length < message[1].iov_len ? length : message[1].iov_len);
+
+ /* set database description pointer */
+ dbdesc = (struct ospf6_dbdesc *) message[1].iov_base;
+
+ /* find neighbor. if cannot be found, reject this message */
+ o6n = ospf6_neighbor_lookup (router_id, o6i);
+ if (!o6n)
+ {
+ if (IS_OSPF6_DUMP_DBDESC)
+ zlog_info ("neighbor not found, reject");
+ return;
+ }
+
+ if (memcmp (src, &o6n->hisaddr, sizeof (struct in6_addr)))
+ {
+ if (IS_OSPF6_DUMP_MESSAGE (ospf6_header->type))
+ zlog_info ("From Secondary I/F of the neighbor: ignore");
+ return;
+ }
+
+ /* interface mtu check */
+ /* xxx */
+
+ /* check am I master */
+ Im_master = ospf6_dbdesc_is_master (o6n);
+ if (Im_master < 0)
+ {
+ return; /* can't decide which is master, return */
+ }
+
+ if (Im_master)
+ ospf6_process_dbdesc_master (message, o6n);
+ else
+ ospf6_process_dbdesc_slave (message, o6n);
+
+ return;
+}
+
+void
+ospf6_process_lsreq (struct iovec *message,
+ struct in6_addr *src,
+ struct in6_addr *dst,
+ struct ospf6_interface *o6i,
+ u_int32_t router_id)
+{
+ struct ospf6_header *ospf6_header;
+ u_int16_t length;
+ struct ospf6_neighbor *o6n;
+ struct ospf6_lsreq *lsreq;
+ struct iovec response[OSPF6_MESSAGE_IOVEC_SIZE];
+ struct ospf6_lsa *lsa;
+ unsigned long lsanum = 0;
+ struct ospf6_lsupdate lsupdate;
+ char buf_id[16], buf_router[16], buf_type[16];
+
+ /* assert interface */
+ assert (o6i);
+
+ /* caluculate length */
+ ospf6_header = (struct ospf6_header *) message[0].iov_base;
+ length = ntohs (ospf6_header->len) - sizeof (struct ospf6_header);
+ length = (length < message[1].iov_len ? length : message[1].iov_len);
+
+ /* find neighbor. if cannot be found, reject this message */
+ o6n = ospf6_neighbor_lookup (router_id, o6i);
+ if (!o6n)
+ {
+ if (IS_OSPF6_DUMP_LSREQ)
+ zlog_info (" neighbor not found, reject");
+ return;
+ }
+
+ if (memcmp (src, &o6n->hisaddr, sizeof (struct in6_addr)))
+ {
+ if (IS_OSPF6_DUMP_MESSAGE (ospf6_header->type))
+ zlog_info ("From Secondary I/F of the neighbor: ignore");
+ return;
+ }
+
+ /* In states other than ExChange, Loading, or Full, the packet
+ should be ignored. */
+ if (o6n->state != NBS_EXCHANGE && o6n->state != NBS_LOADING
+ && o6n->state != NBS_FULL)
+ {
+ if (IS_OSPF6_DUMP_LSREQ)
+ zlog_info (" neighbor state less than Exchange, reject");
+ return;
+ }
+
+ /* Initialize response LSUpdate packet */
+ OSPF6_MESSAGE_CLEAR (response);
+ memset (&lsupdate, 0, sizeof (struct ospf6_lsupdate));
+ OSPF6_MESSAGE_ATTACH (response, &lsupdate, sizeof (struct ospf6_lsupdate));
+
+ /* process each request */
+ lsanum = 0;
+ for (lsreq = (struct ospf6_lsreq *) message[1].iov_base;
+ (char *)(lsreq + 1) <= (char *)(message[1].iov_base + length);
+ lsreq++)
+ {
+ inet_ntop (AF_INET, &lsreq->adv_router, buf_router, sizeof (buf_router));
+ inet_ntop (AF_INET, &lsreq->id, buf_id, sizeof (buf_id));
+
+ /* find instance of database copy */
+ lsa = ospf6_lsdb_lookup (lsreq->type, lsreq->id, lsreq->adv_router,
+ ospf6_lsa_get_scope (lsreq->type, o6i));
+
+ if (!lsa)
+ {
+ if (IS_OSPF6_DUMP_LSREQ)
+ zlog_info ("BadLSReq: %s requests [%s ID=%s Adv=%s] not found",
+ o6n->str, ospf6_lsa_type_string (lsreq->type, buf_type,
+ sizeof (buf_type)),
+ buf_id, buf_router);
+ thread_add_event (master, bad_lsreq, o6n, 0);
+ return;
+ }
+
+ /* I/F MTU check */
+ if (sizeof (struct ospf6_header) + sizeof (struct ospf6_lsupdate)
+ + iov_totallen (response) + ntohs (lsa->header->length)
+ > o6i->ifmtu)
+ break;
+
+ OSPF6_MESSAGE_ATTACH (response, lsa->header, ntohs (lsa->header->length));
+ lsanum++;
+ }
+
+ /* send response LSUpdate to this request */
+ if (lsanum)
+ {
+ lsupdate.lsupdate_num = htonl (lsanum);
+
+ ospf6_message_send (OSPF6_MESSAGE_TYPE_LSUPDATE, response,
+ &o6n->hisaddr, o6i->if_id);
+ }
+
+ /* statistics */
+ o6n->lsa_receive[OSPF6_MESSAGE_TYPE_LSREQ]
+ += length / sizeof (struct ospf6_lsreq);
+}
+
+void
+ospf6_process_lsupdate (struct iovec *message,
+ struct in6_addr *src,
+ struct in6_addr *dst,
+ struct ospf6_interface *o6i,
+ u_int32_t router_id)
+{
+ struct ospf6_header *ospf6_header;
+ u_int16_t length;
+ struct ospf6_lsupdate *lsupdate;
+ struct ospf6_neighbor *o6n;
+ unsigned long lsanum;
+ struct ospf6_lsa_header *lsa_header;
+
+ /* assert interface */
+ assert (o6i);
+
+ /* caluculate length */
+ ospf6_header = (struct ospf6_header *) message[0].iov_base;
+ length = ntohs (ospf6_header->len) - sizeof (struct ospf6_header);
+ length = (length < message[1].iov_len ? length : message[1].iov_len);
+
+ /* find neighbor. if cannot be found, reject this message */
+ o6n = ospf6_neighbor_lookup (router_id, o6i);
+ if (! o6n)
+ {
+ if (IS_OSPF6_DUMP_LSUPDATE)
+ zlog_info (" neighbor not found, reject");
+ return;
+ }
+
+ if (memcmp (src, &o6n->hisaddr, sizeof (struct in6_addr)))
+ {
+ if (IS_OSPF6_DUMP_MESSAGE (ospf6_header->type))
+ zlog_info ("From Secondary I/F of the neighbor: ignore");
+ return;
+ }
+
+ /* if neighbor state less than ExChange, reject this message */
+ if (o6n->state < NBS_EXCHANGE)
+ {
+ if (IS_OSPF6_DUMP_LSUPDATE)
+ zlog_info (" neighbor state less than Exchange, reject");
+ return;
+ }
+
+ /* set linkstate update pointer */
+ lsupdate = (struct ospf6_lsupdate *) message[1].iov_base;
+
+ /* save linkstate update info */
+ lsanum = ntohl (lsupdate->lsupdate_num);
+
+ /* statistics */
+ o6n->ospf6_stat_received_lsa += lsanum;
+ o6n->ospf6_stat_received_lsupdate++;
+
+ /* RFC2328 Section 10.9: When the neighbor responds to these requests
+ with the proper Link State Update packet(s), the Link state request
+ list is truncated and a new Link State Request packet is sent. */
+
+ /* process LSAs */
+ for (lsa_header = (struct ospf6_lsa_header *) (lsupdate + 1);
+ lsanum && (char *)lsa_header < (char *)lsupdate + length;
+ lsanum--)
+ {
+ ospf6_dbex_receive_lsa (lsa_header, o6n);
+ lsa_header = OSPF6_LSA_NEXT (lsa_header);
+ }
+
+ /* send new Link State Request packet if this LS Update packet
+ can be recognized as a response to our previous LS request */
+ if (! IN6_IS_ADDR_MULTICAST(dst) &&
+ (o6n->state == NBS_EXCHANGE || o6n->state == NBS_LOADING))
+ thread_add_event (master, ospf6_send_lsreq, o6n, 0);
+
+ return;
+}
+
+void
+ospf6_process_lsack (struct iovec *message,
+ struct in6_addr *src,
+ struct in6_addr *dst,
+ struct ospf6_interface *o6i,
+ u_int32_t router_id)
+{
+ struct ospf6_header *ospf6_header;
+ u_int16_t length;
+ struct ospf6_neighbor *o6n;
+ struct ospf6_lsa_header *lsa_header;
+ struct ospf6_lsa *lsa, *copy, *rem;
+
+ /* assert interface */
+ assert (o6i);
+
+ /* caluculate length */
+ ospf6_header = (struct ospf6_header *) message[0].iov_base;
+ length = ntohs (ospf6_header->len) - sizeof (struct ospf6_header);
+ length = (length < message[1].iov_len ? length : message[1].iov_len);
+
+ /* find neighbor. if cannot be found, reject this message */
+ o6n = ospf6_neighbor_lookup (router_id, o6i);
+ if (!o6n)
+ {
+ if (IS_OSPF6_DUMP_LSACK)
+ zlog_info ("LSACK: neighbor not found, reject");
+ return;
+ }
+
+ if (memcmp (src, &o6n->hisaddr, sizeof (struct in6_addr)))
+ {
+ if (IS_OSPF6_DUMP_LSACK)
+ zlog_info ("LSACK: From Secondary I/F of the neighbor: ignore");
+ return;
+ }
+
+ /* if neighbor state less than ExChange, reject this message */
+ if (o6n->state < NBS_EXCHANGE)
+ {
+ if (IS_OSPF6_DUMP_LSACK)
+ zlog_info ("LSACK: neighbor state less than Exchange, reject");
+ return;
+ }
+
+ /* process each LSA header */
+ for (lsa_header = (struct ospf6_lsa_header *) message[1].iov_base;
+ (char *)(lsa_header + 1) <= (char *)(message[1].iov_base + length);
+ lsa_header++)
+ {
+ /* find database copy */
+ copy = ospf6_lsdb_lookup (lsa_header->type, lsa_header->ls_id,
+ lsa_header->advrtr,
+ ospf6_lsa_get_scope (lsa_header->type, o6i));
+
+ /* if no database copy */
+ if (!copy)
+ {
+ if (IS_OSPF6_DUMP_LSACK)
+ zlog_info ("LSACK: no database copy, ignore");
+ continue;
+ }
+
+ /* if not on his retrans list */
+ rem = ospf6_lsdb_lookup_lsdb (copy->header->type, copy->header->id,
+ copy->header->adv_router,
+ o6n->retrans_list);
+ if (rem == NULL)
+ {
+ if (IS_OSPF6_DUMP_LSACK)
+ zlog_info ("LSACK: not on %s's retranslist, ignore", o6n->str);
+ continue;
+ }
+
+ /* create temporary LSA from Ack message */
+ lsa = ospf6_lsa_summary_create ((struct ospf6_lsa_header__ *) lsa_header);
+
+ /* if the same instance, remove from retrans list.
+ else, log and ignore */
+ if (ospf6_lsa_check_recent (lsa, copy) == 0)
+ ospf6_neighbor_retrans_remove (rem, o6n);
+ else
+ {
+ /* Log the questionable acknowledgement,
+ and examine the next one. */
+ zlog_info ("LSACK: questionable acknowledge: %s", copy->str);
+ zlog_info ("LSACK: received: seq: %#x age: %hu",
+ ntohl (lsa->header->seqnum),
+ ntohs (lsa->header->age));
+ zlog_info ("LSACK: instance: seq: %#x age: %hu",
+ ntohl (copy->header->seqnum),
+ ospf6_lsa_age_current (copy));
+ }
+
+ /* release temporary LSA from Ack message */
+ ospf6_lsa_delete (lsa);
+ }
+
+ ospf6_maxage_remover ();
+ return;
+}
+
+struct {
+ void (*process) (struct iovec *, struct in6_addr *, struct in6_addr *,
+ struct ospf6_interface *, u_int32_t);
+} ospf6_message_process_type [] =
+{
+ {ospf6_process_unknown},
+ {ospf6_process_hello},
+ {ospf6_process_dbdesc},
+ {ospf6_process_lsreq},
+ {ospf6_process_lsupdate},
+ {ospf6_process_lsack}
+};
+
+/* process ospf6 protocol header. then, call next process function
+ for each message type */
+static void
+ospf6_message_process (struct iovec *message,
+ struct in6_addr *src,
+ struct in6_addr *dst,
+ struct ospf6_interface *o6i)
+{
+ struct ospf6_header *ospf6_header = NULL;
+ u_char type;
+ u_int32_t router_id;
+ char srcname[64];
+
+ assert (o6i);
+ assert (src);
+ assert (dst);
+
+ /* set ospf6_hdr pointer to head of buffer */
+ ospf6_header = (struct ospf6_header *) message[0].iov_base;
+
+ /* version check */
+ if (ospf6_header->version != OSPF6_VERSION)
+ {
+ if (IS_OSPF6_DUMP_MESSAGE (ospf6_header->type))
+ zlog_info ("version mismatch, drop");
+ return;
+ }
+
+ /* area id check */
+ if (ospf6_header->area_id != o6i->area->area_id)
+ {
+ if (ospf6_header->area_id == 0)
+ {
+ if (IS_OSPF6_DUMP_MESSAGE (ospf6_header->type))
+ zlog_info ("virtual link not yet, drop");
+ return;
+ }
+
+ if (IS_OSPF6_DUMP_MESSAGE (ospf6_header->type))
+ zlog_info ("area id mismatch, drop");
+ return;
+ }
+
+ /* instance id check */
+ if (ospf6_header->instance_id != o6i->instance_id)
+ {
+ if (IS_OSPF6_DUMP_MESSAGE (ospf6_header->type))
+ zlog_info ("instance id mismatch, drop");
+ return;
+ }
+
+ /* message type check */
+ type = (ospf6_header->type >= OSPF6_MESSAGE_TYPE_MAX ?
+ OSPF6_MESSAGE_TYPE_UNKNOWN : ospf6_header->type);
+
+ /* log */
+ if (IS_OSPF6_DUMP_MESSAGE (type))
+ {
+ char srcname[64], dstname[64];
+ inet_ntop (AF_INET6, dst, dstname, sizeof (dstname));
+ inet_ntop (AF_INET6, src, srcname, sizeof (srcname));
+ zlog_info ("Receive %s on %s",
+ ospf6_message_type_string[type], o6i->interface->name);
+ zlog_info (" %s -> %s", srcname, dstname);
+ ospf6_message_log (message);
+ }
+
+ /* router id check */
+ router_id = ospf6_header->router_id;
+ if (ospf6_header->router_id == o6i->area->ospf6->router_id)
+ {
+ inet_ntop (AF_INET6, src, srcname, sizeof (srcname));
+ zlog_warn ("*** Router-ID mismatch: from %s on %s",
+ srcname, o6i->interface->name);
+ return;
+ }
+
+ /* octet statistics relies on some asumption:
+ on ethernet, no IPv6 Extention header, etc */
+#define OSPF6_IP6_HEADER_SIZE 40
+#define OSPF6_ETHER_HEADER_SIZE 14
+ o6i->message_stat[type].recv++;
+ o6i->message_stat[type].recv_octet += ntohs (ospf6_header->len)
+ + OSPF6_IP6_HEADER_SIZE + OSPF6_ETHER_HEADER_SIZE;
+
+ /* futher process */
+ (*ospf6_message_process_type[type].process) (&message[0], src, dst, o6i, router_id);
+
+ return;
+}
+
+int
+ospf6_receive (struct thread *thread)
+{
+ int sockfd;
+ struct in6_addr src, dst;
+ unsigned int ifindex;
+ struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE];
+ struct ospf6_header ospf6_header;
+ char buffer[OSPF6_MESSAGE_RECEIVE_BUFSIZE];
+ struct ospf6_interface *o6i;
+ unsigned char type;
+
+ /* get socket */
+ sockfd = THREAD_FD (thread);
+
+ /* add next read thread */
+ thread_add_read (master, ospf6_receive, NULL, sockfd);
+
+ /* initialize */
+ OSPF6_MESSAGE_CLEAR (message);
+ memset (&ospf6_header, 0, sizeof (struct ospf6_header));
+
+ OSPF6_MESSAGE_ATTACH (message, &ospf6_header, sizeof (struct ospf6_header));
+ OSPF6_MESSAGE_ATTACH (message, buffer, OSPF6_MESSAGE_RECEIVE_BUFSIZE);
+
+ /* receive message */
+ ospf6_recvmsg (&src, &dst, &ifindex, message);
+
+ type = (OSPF6_MESSAGE_TYPE_UNKNOWN < ospf6_header.type &&
+ ospf6_header.type <= OSPF6_MESSAGE_TYPE_LSACK ?
+ ospf6_header.type : OSPF6_MESSAGE_TYPE_UNKNOWN);
+ o6i = ospf6_interface_lookup_by_index (ifindex);
+ if (!o6i || !o6i->area)
+ {
+ //zlog_warn ("*** received interface ospf6 disabled");
+ return 0;
+ }
+
+ /* if not passive, process message */
+ if (! CHECK_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_PASSIVE))
+ ospf6_message_process (message, &src, &dst, o6i);
+ else if (IS_OSPF6_DUMP_MESSAGE (type))
+ zlog_info ("Ignore message on passive interface %s",
+ o6i->interface->name);
+
+ return 0;
+}
+
+
+/* send section */
+int
+ospf6_message_length (struct iovec *message)
+{
+ int i, length = 0;
+ for (i = 0; i < OSPF6_MESSAGE_IOVEC_SIZE; i++)
+ {
+ if (message[i].iov_base == NULL && message[i].iov_len == 0)
+ break;
+ length += message[i].iov_len;
+ }
+ return length;
+}
+#define OSPF6_MESSAGE_LENGTH(msg) \
+(ospf6_message_length (msg))
+
+void
+ospf6_message_send (unsigned char type, struct iovec *msg,
+ struct in6_addr *dst, u_int ifindex)
+{
+ struct ospf6_interface *o6i;
+ struct ospf6_header ospf6_header;
+ char dst_name[64], src_name[64];
+ struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE];
+ int msg_len;
+
+ /* ospf6 interface lookup */
+ o6i = ospf6_interface_lookup_by_index (ifindex);
+ assert (o6i);
+
+ msg_len = OSPF6_MESSAGE_LENGTH (msg);
+
+ /* I/F MTU check */
+#if 0
+ if (msg_len + sizeof (struct ospf6_header) >= o6i->interface->mtu)
+#else
+ if (msg_len + sizeof (struct ospf6_header) >= o6i->ifmtu)
+#endif
+ {
+ /* If Interface MTU is 0, save the case
+ since zebra had been failed to get MTU from Kernel */
+ if (o6i->interface->mtu != 0)
+ {
+ zlog_warn ("Message: Send failed on %s: exceeds I/F MTU",
+ o6i->interface->name);
+ zlog_warn ("Message: while sending %s: Len:%d MTU:%d",
+ ospf6_message_type_string[type],
+ msg_len + sizeof (struct ospf6_header),
+ o6i->ifmtu);
+ return;
+ }
+ else
+ {
+ zlog_warn ("Message: I/F MTU check ignored on %s",
+ o6i->interface->name);
+ }
+ }
+
+ /* Initialize */
+ OSPF6_MESSAGE_CLEAR (message);
+
+ /* set OSPF header */
+ memset (&ospf6_header, 0, sizeof (ospf6_header));
+ ospf6_header.version = OSPF6_VERSION;
+ ospf6_header.type = type;
+ ospf6_header.len = htons (msg_len + sizeof (struct ospf6_header));
+ ospf6_header.router_id = ospf6->router_id;
+ ospf6_header.area_id = o6i->area->area_id;
+ /* checksum is calculated by kernel */
+ ospf6_header.instance_id = o6i->instance_id;
+ ospf6_header.reserved = 0;
+ OSPF6_MESSAGE_ATTACH (message, &ospf6_header, sizeof (struct ospf6_header));
+
+ /* Attach rest to message */
+ OSPF6_MESSAGE_JOIN (message, msg);
+
+ /* statistics */
+ if (type >= OSPF6_MESSAGE_TYPE_MAX)
+ type = OSPF6_MESSAGE_TYPE_UNKNOWN;
+ o6i->message_stat[type].send++;
+ o6i->message_stat[type].send_octet += ntohs (ospf6_header.len);
+
+ /* log */
+ if (IS_OSPF6_DUMP_MESSAGE (type))
+ {
+ inet_ntop (AF_INET6, dst, dst_name, sizeof (dst_name));
+ if (o6i->lladdr)
+ inet_ntop (AF_INET6, o6i->lladdr, src_name, sizeof (src_name));
+ else
+ memcpy (src_name, "Unknown", sizeof (src_name));
+ zlog_info ("Send %s on %s",
+ ospf6_message_type_string[type], o6i->interface->name);
+ zlog_info (" %s -> %s", src_name, dst_name);
+ ospf6_message_log (message);
+ }
+
+ /* send message */
+ ospf6_sendmsg (o6i->lladdr, dst, &ifindex, message);
+}
+
+
+int
+ospf6_send_hello (struct thread *thread)
+{
+ listnode n;
+ struct ospf6_interface *o6i;
+ struct ospf6_neighbor *o6n;
+ struct in6_addr dst;
+ struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE];
+ struct ospf6_hello hello;
+ char router_buffer[1024]; /* xxx */
+ u_int router_size;
+
+ /* which ospf6 interface to send */
+ o6i = (struct ospf6_interface *) THREAD_ARG (thread);
+ o6i->thread_send_hello = (struct thread *) NULL;
+
+ /* assure interface is up */
+ if (o6i->state <= IFS_DOWN)
+ {
+ if (IS_OSPF6_DUMP_HELLO)
+ zlog_warn ("Send HELLO Failed: Interface not enabled: %s",
+ o6i->interface->name);
+ return 0;
+ }
+
+ /* clear message buffer */
+ OSPF6_MESSAGE_CLEAR (message);
+
+ /* set Hello fields */
+ hello.interface_id = htonl (o6i->if_id);
+ hello.rtr_pri = o6i->priority;
+ memcpy (hello.options, o6i->area->options, sizeof (hello.options));
+ hello.hello_interval = htons (o6i->hello_interval);
+ hello.router_dead_interval = htons (o6i->dead_interval);
+ hello.dr = o6i->dr;
+ hello.bdr = o6i->bdr;
+ OSPF6_MESSAGE_ATTACH (message, &hello, sizeof (struct ospf6_hello));
+
+ /* set neighbor router id */
+ router_size = 0;
+ for (n = listhead (o6i->neighbor_list); n; nextnode (n))
+ {
+ o6n = (struct ospf6_neighbor *) getdata (n);
+
+ if (o6n->state < NBS_INIT)
+ continue;
+
+ if (router_size + sizeof (o6n->router_id) > sizeof (router_buffer))
+ {
+ zlog_warn ("Send HELLO: Buffer shortage on %s",
+ o6i->interface->name);
+ break;
+ }
+
+ /* Copy Router-ID to Buffer */
+ memcpy (router_buffer + router_size, &o6n->router_id,
+ sizeof (o6n->router_id));
+ router_size += sizeof (o6n->router_id);
+ }
+ OSPF6_MESSAGE_ATTACH (message, router_buffer, router_size);
+
+ /* set destionation */
+ inet_pton (AF_INET6, ALLSPFROUTERS6, &dst);
+
+ /* send hello */
+ ospf6_message_send (OSPF6_MESSAGE_TYPE_HELLO, message, &dst,
+ o6i->interface->ifindex);
+
+ /* set next timer thread */
+ o6i->thread_send_hello = thread_add_timer (master, ospf6_send_hello,
+ o6i, o6i->hello_interval);
+
+ return 0;
+}
+
+void
+ospf6_dbdesc_seqnum_init (struct ospf6_neighbor *o6n)
+{
+ struct timeval tv;
+
+ if (gettimeofday (&tv, (struct timezone *) NULL) < 0)
+ tv.tv_sec = 1;
+
+ o6n->dbdesc_seqnum = tv.tv_sec;
+
+ if (IS_OSPF6_DUMP_DBDESC)
+ zlog_info ("set dbdesc seqnum %d for %s", o6n->dbdesc_seqnum, o6n->str);
+}
+
+int
+ospf6_send_dbdesc_rxmt (struct thread *thread)
+{
+ struct ospf6_lsdb_node node;
+ struct ospf6_neighbor *o6n;
+ struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE];
+ struct ospf6_lsa *lsa;
+ struct ospf6_lsa_header *lsa_header;
+ struct ospf6_dbdesc dbdesc;
+
+ o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+ assert (o6n);
+
+ /* clear thread */
+ o6n->thread_rxmt_dbdesc = (struct thread *) NULL;
+
+ /* if state less than ExStart, do nothing */
+ if (o6n->state < NBS_EXSTART)
+ return 0;
+
+ OSPF6_MESSAGE_CLEAR (message);
+
+ /* set dbdesc */
+ memcpy (dbdesc.options, o6n->ospf6_interface->area->options,
+ sizeof (dbdesc.options));
+ dbdesc.ifmtu = htons (o6n->ospf6_interface->interface->mtu);
+ dbdesc.bits = o6n->dbdesc_bits;
+ dbdesc.seqnum = htonl (o6n->dbdesc_seqnum);
+ OSPF6_MESSAGE_ATTACH (message, &dbdesc, sizeof (struct ospf6_dbdesc));
+
+ /* if this is not initial, set LSA summary to dbdesc */
+ if (! DD_IS_IBIT_SET (o6n->dbdesc_bits))
+ {
+ for (ospf6_lsdb_head (&node, o6n->dbdesc_list);
+ ! ospf6_lsdb_is_end (&node); ospf6_lsdb_next (&node))
+ {
+ lsa = node.lsa;
+
+ /* xxx, no MTU check: no support for Dynamic MTU change */
+
+ /* set age and add InfTransDelay */
+ ospf6_lsa_age_update_to_send (lsa, o6n->ospf6_interface->transdelay);
+
+ /* set LSA summary to send buffer */
+ lsa_header = (struct ospf6_lsa_header *) lsa->lsa_hdr;
+ OSPF6_MESSAGE_ATTACH (message, lsa_header,
+ sizeof (struct ospf6_lsa_header));
+ }
+ }
+
+ /* send dbdesc */
+ ospf6_message_send (OSPF6_MESSAGE_TYPE_DBDESC, message, &o6n->hisaddr,
+ o6n->ospf6_interface->interface->ifindex);
+
+ /* if master, set futher retransmission */
+ if (DD_IS_MSBIT_SET (o6n->dbdesc_bits))
+ o6n->thread_rxmt_dbdesc =
+ thread_add_timer (master, ospf6_send_dbdesc_rxmt,
+ o6n, o6n->ospf6_interface->rxmt_interval);
+
+ /* statistics */
+ o6n->ospf6_stat_retrans_dbdesc++;
+
+ return 0;
+}
+
+int
+ospf6_send_dbdesc (struct thread *thread)
+{
+ struct ospf6_neighbor *o6n;
+ struct ospf6_lsa *lsa;
+ struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE];
+ struct ospf6_dbdesc dbdesc;
+ struct ospf6_lsdb_node node;
+
+ o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+ assert (o6n);
+
+ /* clear thread */
+ o6n->thread_send_dbdesc = (struct thread *) NULL;
+ if (o6n->thread_rxmt_dbdesc)
+ thread_cancel (o6n->thread_rxmt_dbdesc);
+ o6n->thread_rxmt_dbdesc = (struct thread *) NULL;
+
+ /* if state less than ExStart, do nothing */
+ if (o6n->state < NBS_EXSTART)
+ return 0;
+
+ OSPF6_MESSAGE_CLEAR (message);
+ OSPF6_MESSAGE_ATTACH (message, &dbdesc, sizeof (struct ospf6_dbdesc));
+
+ /* clear previous LSA summary sent */
+ ospf6_lsdb_remove_all (o6n->dbdesc_list);
+ assert (o6n->dbdesc_list->count == 0);
+
+ /* if this is not initial, set LSA summary to dbdesc */
+ if (! DD_IS_IBIT_SET (o6n->dbdesc_bits))
+ {
+ for (ospf6_lsdb_head (&node, o6n->summary_list);
+ ! ospf6_lsdb_is_end (&node);
+ ospf6_lsdb_next (&node))
+ {
+ lsa = node.lsa;
+
+ /* MTU check */
+ if (OSPF6_MESSAGE_LENGTH (message)
+ + sizeof (struct ospf6_lsa_header)
+ + sizeof (struct ospf6_header)
+ > o6n->ospf6_interface->ifmtu)
+ break;
+
+ /* debug */
+ if (IS_OSPF6_DUMP_DBDESC)
+ zlog_info ("Include DbDesc: %s", lsa->str);
+
+ /* attach to dbdesclist */
+ ospf6_neighbor_dbdesc_add (lsa, o6n);
+ /* detach from summarylist */
+ ospf6_neighbor_summary_remove (lsa, o6n);
+
+ /* set age and add InfTransDelay */
+ ospf6_lsa_age_update_to_send (lsa, o6n->ospf6_interface->transdelay);
+
+ /* set LSA summary to send buffer */
+ OSPF6_MESSAGE_ATTACH (message, lsa->header,
+ sizeof (struct ospf6_lsa_header));
+ }
+
+ if (o6n->summary_list->count == 0)
+ {
+ /* Clear more bit */
+ DD_MBIT_CLEAR (o6n->dbdesc_bits);
+
+ /* slave must schedule ExchangeDone on sending, here */
+ if (! DD_IS_MSBIT_SET (o6n->dbdesc_bits))
+ {
+ if (! DD_IS_MBIT_SET (o6n->dbdesc_bits) &&
+ ! DD_IS_MBIT_SET (o6n->last_dd.bits))
+ thread_add_event (master, exchange_done, o6n, 0);
+ }
+ }
+ }
+
+ /* if this is initial, set seqnum */
+ if (DDBIT_IS_INITIAL (o6n->dbdesc_bits))
+ ospf6_dbdesc_seqnum_init (o6n);
+
+ /* set dbdesc */
+ memcpy (dbdesc.options, o6n->ospf6_interface->area->options,
+ sizeof (dbdesc.options));
+ dbdesc.ifmtu = htons (o6n->ospf6_interface->interface->mtu);
+ dbdesc.bits = o6n->dbdesc_bits;
+ dbdesc.seqnum = htonl (o6n->dbdesc_seqnum);
+
+ /* send dbdesc */
+ ospf6_message_send (OSPF6_MESSAGE_TYPE_DBDESC, message, &o6n->hisaddr,
+ o6n->ospf6_interface->interface->ifindex);
+
+ /* if master, set retransmission */
+ if (DD_IS_MSBIT_SET (o6n->dbdesc_bits))
+ o6n->thread_rxmt_dbdesc =
+ thread_add_timer (master, ospf6_send_dbdesc_rxmt,
+ o6n, o6n->ospf6_interface->rxmt_interval);
+
+ /* statistics */
+ o6n->lsa_send[OSPF6_MESSAGE_TYPE_DBDESC] += o6n->dbdesc_list->count;
+
+ return 0;
+}
+
+int
+ospf6_send_lsreq_rxmt (struct thread *thread)
+{
+ struct ospf6_neighbor *o6n;
+
+ o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+ assert (o6n);
+
+ o6n->thread_rxmt_lsreq = (struct thread *) NULL;
+ o6n->thread_send_lsreq = thread_add_event (master, ospf6_send_lsreq, o6n, 0);
+ return 0;
+}
+
+int
+ospf6_send_lsreq (struct thread *thread)
+{
+ struct ospf6_neighbor *o6n;
+ struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE];
+ struct ospf6_lsreq lsreq[OSPF6_MESSAGE_IOVEC_SIZE];
+ struct ospf6_lsa *lsa;
+ struct ospf6_lsdb_node node;
+ int i;
+
+ o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+ assert (o6n);
+
+ /* LSReq will be send only in ExStart or Loading */
+ if (o6n->state != NBS_EXCHANGE && o6n->state != NBS_LOADING)
+ return 0;
+
+ /* clear thread */
+ o6n->thread_send_lsreq = (struct thread *) NULL;
+ if (o6n->thread_rxmt_lsreq)
+ thread_cancel (o6n->thread_rxmt_lsreq);
+ o6n->thread_rxmt_lsreq = (struct thread *) NULL;
+
+ /* schedule loading_done if request list is empty */
+ if (o6n->request_list->count == 0)
+ {
+ thread_add_event (master, loading_done, o6n, 0);
+ return 0;
+ }
+
+ /* clear message buffer */
+ OSPF6_MESSAGE_CLEAR (message);
+
+ i = 0;
+ for (ospf6_lsdb_head (&node, o6n->request_list);
+ ! ospf6_lsdb_is_end (&node); ospf6_lsdb_next (&node))
+ {
+ lsa = node.lsa;
+
+ /* Buffer Overflow */
+ if (i >= OSPF6_MESSAGE_IOVEC_SIZE)
+ break;
+
+ /* I/F MTU check */
+ if (OSPF6_MESSAGE_LENGTH (message)
+ + sizeof (struct ospf6_lsreq)
+ + sizeof (struct ospf6_header)
+ > o6n->ospf6_interface->ifmtu)
+ break;
+
+ lsreq[i].mbz = 0;
+ lsreq[i].type = lsa->header->type;
+ lsreq[i].id = lsa->header->id;
+ lsreq[i].adv_router = lsa->header->adv_router;
+
+ OSPF6_MESSAGE_ATTACH (message, &lsreq[i], sizeof (struct ospf6_lsreq));
+ i++;
+ }
+
+ ospf6_message_send (OSPF6_MESSAGE_TYPE_LSREQ, message, &o6n->hisaddr,
+ o6n->ospf6_interface->interface->ifindex);
+
+ /* set retransmit thread */
+ o6n->thread_rxmt_lsreq =
+ thread_add_timer (master, ospf6_send_lsreq_rxmt,
+ o6n, o6n->ospf6_interface->rxmt_interval);
+
+ /* statistics */
+ o6n->lsa_send[OSPF6_MESSAGE_TYPE_LSREQ] += i;
+
+ return 0;
+}
+
+/* Send LSUpdate directly to the neighbor, from his retransmission list */
+int
+ospf6_send_lsupdate_rxmt (struct thread *thread)
+{
+ struct ospf6_neighbor *o6n;
+ struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE];
+ struct ospf6_lsupdate lsupdate;
+ struct ospf6_lsa *lsa;
+ struct ospf6_lsdb_node node;
+
+ o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+ assert (o6n);
+
+ o6n->send_update = (struct thread *) NULL;
+
+ if (o6n->ospf6_interface->state <= IFS_WAITING)
+ return -1;
+
+ /* clear message buffer */
+ OSPF6_MESSAGE_CLEAR (message);
+
+ /* set lsupdate header */
+ lsupdate.lsupdate_num = 0; /* set gradually */
+ OSPF6_MESSAGE_ATTACH (message, &lsupdate, sizeof (struct ospf6_lsupdate));
+
+ /* for each LSA listed on retransmission-list */
+ for (ospf6_lsdb_head (&node, o6n->retrans_list);
+ ! ospf6_lsdb_is_end (&node);
+ ospf6_lsdb_next (&node))
+ {
+ lsa = node.lsa;
+
+ /* I/F MTU check */
+ if (OSPF6_MESSAGE_LENGTH (message)
+ + sizeof (struct ospf6_lsupdate)
+ + sizeof (struct ospf6_header)
+ + ntohs (lsa->header->length)
+ > o6n->ospf6_interface->ifmtu)
+ break;
+
+ ospf6_lsa_age_update_to_send (lsa, o6n->ospf6_interface->transdelay);
+ OSPF6_MESSAGE_ATTACH (message, lsa->header, ntohs (lsa->header->length));
+ lsupdate.lsupdate_num++;
+ }
+
+ /* check and correct lsupdate */
+ if (lsupdate.lsupdate_num == 0)
+ return 0;
+ lsupdate.lsupdate_num = htonl (lsupdate.lsupdate_num);
+
+ if (IS_OSPF6_DUMP_LSUPDATE)
+ zlog_info ("MESSAGE: retrsnsmit LSUpdate to %s", o6n->str);
+
+ /* statistics */
+ o6n->ospf6_stat_retrans_lsupdate++;
+
+ ospf6_message_send (OSPF6_MESSAGE_TYPE_LSUPDATE, message,
+ &o6n->hisaddr, o6n->ospf6_interface->if_id);
+
+ o6n->send_update = thread_add_timer (master, ospf6_send_lsupdate_rxmt, o6n,
+ o6n->ospf6_interface->rxmt_interval);
+ return 0;
+}
+
+/* Send LSUpdate containing one LSA directly to the neighbor.
+ This is "implied acknowledgement" */
+void
+ospf6_send_lsupdate_direct (struct ospf6_lsa *lsa, struct ospf6_neighbor *o6n)
+{
+ struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE];
+ struct ospf6_lsupdate lsupdate;
+ int lsa_len;
+
+ /* clear message buffer */
+ OSPF6_MESSAGE_CLEAR (message);
+
+ /* set lsupdate header */
+ lsupdate.lsupdate_num = ntohl (1);
+ OSPF6_MESSAGE_ATTACH (message, &lsupdate, sizeof (struct ospf6_lsupdate));
+
+ /* set one LSA */
+ lsa_len = ntohs (lsa->lsa_hdr->lsh_len);
+ ospf6_lsa_age_update_to_send (lsa, o6n->ospf6_interface->transdelay);
+ OSPF6_MESSAGE_ATTACH (message, lsa->lsa_hdr, lsa_len);
+
+ ospf6_message_send (OSPF6_MESSAGE_TYPE_LSUPDATE, message, &o6n->hisaddr,
+ o6n->ospf6_interface->if_id);
+}
+
+/* Send LSUpdate containing one LSA by multicast.
+ On non-broadcast link, send it to each neighbor by unicast.
+ This is ordinary flooding */
+void
+ospf6_send_lsupdate_flood (struct ospf6_lsa *lsa, struct ospf6_interface *o6i)
+{
+ struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE];
+ struct ospf6_lsupdate lsupdate;
+ struct in6_addr dst;
+ int lsa_len;
+
+ /* clear message buffer */
+ OSPF6_MESSAGE_CLEAR (message);
+
+ /* set lsupdate header */
+ lsupdate.lsupdate_num = ntohl (1);
+ OSPF6_MESSAGE_ATTACH (message, &lsupdate, sizeof (struct ospf6_lsupdate));
+
+ /* set one LSA */
+ lsa_len = ntohs (lsa->lsa_hdr->lsh_len);
+ ospf6_lsa_age_update_to_send (lsa, o6i->transdelay);
+ OSPF6_MESSAGE_ATTACH (message, lsa->lsa_hdr, lsa_len);
+
+ if (if_is_broadcast (o6i->interface))
+ {
+ /* set destination */
+ if (o6i->state == IFS_DR || o6i->state == IFS_BDR)
+ inet_pton (AF_INET6, ALLSPFROUTERS6, &dst);
+ else
+ inet_pton (AF_INET6, ALLDROUTERS6, &dst);
+ }
+ else
+ {
+ /* IPv6 relies on link local multicast */
+ inet_pton (AF_INET6, ALLSPFROUTERS6, &dst);
+ }
+
+ ospf6_message_send (OSPF6_MESSAGE_TYPE_LSUPDATE, message, &dst,
+ o6i->if_id);
+}
+
+int
+ospf6_send_lsack_delayed (struct thread *thread)
+{
+ struct ospf6_interface *o6i;
+ struct iovec message[MAXIOVLIST];
+ struct ospf6_lsa *lsa;
+ struct ospf6_lsdb_node node;
+
+ o6i = THREAD_ARG (thread);
+ assert (o6i);
+
+ if (IS_OSPF6_DUMP_LSACK)
+ zlog_info ("LSACK: Delayed LSAck for %s\n", o6i->interface->name);
+
+ o6i->thread_send_lsack_delayed = (struct thread *) NULL;
+
+ if (o6i->state <= IFS_WAITING)
+ return 0;
+
+ if (o6i->ack_list->count == 0)
+ return 0;
+
+ iov_clear (message, MAXIOVLIST);
+
+ for (ospf6_lsdb_head (&node, o6i->ack_list);
+ ! ospf6_lsdb_is_end (&node);
+ ospf6_lsdb_next (&node))
+ {
+ lsa = node.lsa;
+ if (IS_OVER_MTU (message, o6i->ifmtu, sizeof (struct ospf6_lsa_hdr)))
+ break;
+
+ OSPF6_MESSAGE_ATTACH (message, lsa->header,
+ sizeof (struct ospf6_lsa_header));
+ ospf6_interface_delayed_ack_remove (lsa, o6i);
+ }
+
+ /* statistics */
+ o6i->ospf6_stat_delayed_lsack++;
+
+ switch (o6i->state)
+ {
+ case IFS_DR:
+ case IFS_BDR:
+ ospf6_message_send (OSPF6_MESSAGE_TYPE_LSACK, message,
+ &allspfrouters6.sin6_addr, o6i->if_id);
+ break;
+ default:
+ ospf6_message_send (OSPF6_MESSAGE_TYPE_LSACK, message,
+ &alldrouters6.sin6_addr, o6i->if_id);
+ break;
+ }
+
+ iov_clear (message, MAXIOVLIST);
+ return 0;
+}
+
diff --git a/ospf6d/ospf6_message.h b/ospf6d/ospf6_message.h
new file mode 100644
index 00000000..105cb4f0
--- /dev/null
+++ b/ospf6d/ospf6_message.h
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef OSPF6_MESSAGE_H
+#define OSPF6_MESSAGE_H
+
+#include "ospf6_prefix.h"
+#include "ospf6_lsa.h"
+
+/* Type */
+#define OSPF6_MESSAGE_TYPE_NONE 0x0
+#define OSPF6_MESSAGE_TYPE_UNKNOWN 0x0
+#define OSPF6_MESSAGE_TYPE_HELLO 0x1 /* Discover/maintain neighbors */
+#define OSPF6_MESSAGE_TYPE_DBDESC 0x2 /* Summarize database contents */
+#define OSPF6_MESSAGE_TYPE_LSREQ 0x3 /* Database download */
+#define OSPF6_MESSAGE_TYPE_LSUPDATE 0x4 /* Database update */
+#define OSPF6_MESSAGE_TYPE_LSACK 0x5 /* Flooding acknowledgment */
+#define OSPF6_MESSAGE_TYPE_MAX 0x6
+
+/* OSPFv3 packet header */
+struct ospf6_header
+{
+ u_char version;
+ u_char type;
+ u_int16_t len;
+ u_int32_t router_id;
+ u_int32_t area_id;
+ u_int16_t cksum;
+ u_char instance_id;
+ u_char reserved;
+};
+
+/* Hello */
+#define MAXLISTEDNBR 64
+struct ospf6_hello
+{
+ u_int32_t interface_id;
+ u_char rtr_pri;
+ u_char options[3];
+ u_int16_t hello_interval;
+ u_int16_t router_dead_interval;
+ u_int32_t dr;
+ u_int32_t bdr;
+};
+
+/* Database Description */
+struct ospf6_dbdesc
+{
+ u_char mbz1;
+ u_char options[3];
+ u_int16_t ifmtu;
+ u_char mbz2;
+ u_char bits;
+ u_int32_t seqnum;
+ /* Followed by LSAs */
+};
+#define DEFAULT_INTERFACE_MTU 1500
+
+#define DD_IS_MSBIT_SET(x) ((x) & (1 << 0))
+#define DD_MSBIT_SET(x) ((x) |= (1 << 0))
+#define DD_MSBIT_CLEAR(x) ((x) &= ~(1 << 0))
+#define DD_IS_MBIT_SET(x) ((x) & (1 << 1))
+#define DD_MBIT_SET(x) ((x) |= (1 << 1))
+#define DD_MBIT_CLEAR(x) ((x) &= ~(1 << 1))
+#define DD_IS_IBIT_SET(x) ((x) & (1 << 2))
+#define DD_IBIT_SET(x) ((x) |= (1 << 2))
+#define DD_IBIT_CLEAR(x) ((x) &= ~(1 << 2))
+
+#define DDBIT_IS_MASTER(x) ((x) & (1 << 0))
+#define DDBIT_IS_SLAVE(x) (!((x) & (1 << 0)))
+#define DDBIT_SET_MASTER(x) ((x) |= (1 << 0))
+#define DDBIT_SET_SLAVE(x) ((x) |= ~(1 << 0))
+#define DDBIT_IS_MORE(x) ((x) & (1 << 1))
+#define DDBIT_SET_MORE(x) ((x) |= (1 << 1))
+#define DDBIT_CLR_MORE(x) ((x) |= ~(1 << 1))
+#define DDBIT_IS_INITIAL(x) ((x) & (1 << 2))
+#define DDBIT_SET_INITIAL(x) ((x) |= (1 << 2))
+#define DDBIT_CLR_INITIAL(x) ((x) |= ~(1 << 2))
+
+#define OSPF6_DBDESC_BIT_MASTER 0x01
+#define OSPF6_DBDESC_BIT_MORE 0x02
+#define OSPF6_DBDESC_BIT_INITIAL 0x04
+
+/* Link State Request */
+struct ospf6_lsreq
+{
+ u_int16_t mbz; /* Must Be Zero */
+ u_int16_t type; /* LS type */
+ u_int32_t id; /* Link State ID */
+ u_int32_t adv_router; /* Advertising Router */
+};
+
+/* Link State Update */
+struct ospf6_lsupdate
+{
+ u_int32_t lsupdate_num;
+};
+
+/* Link State Acknowledgement */
+ /* no need for structure,
+ it will include only LSA header in the packet body.*/
+
+/* definition for ospf6_message.c */
+#define OSPF6_MESSAGE_RECEIVE_BUFSIZE 5120
+#define OSPF6_MESSAGE_IOVEC_END 1024
+
+#define IS_OVER_MTU(message,mtu,addsize) \
+ (iov_totallen(message)+(addsize) >= \
+ (mtu)-sizeof(struct ospf6_header))
+
+#define OSPF6_MESSAGE_IOVEC_SIZE 1024
+#define OSPF6_MESSAGE_CLEAR(msg) \
+do { \
+ int x; \
+ for (x = 0; x < OSPF6_MESSAGE_IOVEC_SIZE; x++) \
+ { \
+ (msg)[x].iov_base = NULL; \
+ (msg)[x].iov_len = 0; \
+ } \
+} while (0)
+
+#define OSPF6_MESSAGE_ATTACH(msg,buf,bufsize) \
+do { \
+ int x; \
+ for (x = 0; x < OSPF6_MESSAGE_IOVEC_SIZE; x++) \
+ if ((msg)[x].iov_base == (void *)NULL && (msg)[x].iov_len == 0) \
+ break; \
+ if (x < OSPF6_MESSAGE_IOVEC_SIZE - 1) \
+ { \
+ (msg)[x].iov_base = (void *)(buf); \
+ (msg)[x].iov_len = (bufsize); \
+ } \
+} while (0)
+
+#define OSPF6_MESSAGE_JOIN(msg,join) \
+do { \
+ int x,y; \
+ for (x = 0; x < OSPF6_MESSAGE_IOVEC_SIZE; x++) \
+ if ((msg)[x].iov_base == NULL && (msg)[x].iov_len == 0) \
+ break; \
+ for (y = x; y < OSPF6_MESSAGE_IOVEC_SIZE; y++) \
+ { \
+ (msg)[y].iov_base = (join)[y - x].iov_base; \
+ (msg)[y].iov_len = (join)[y - x].iov_len; \
+ } \
+} while (0)
+
+
+/* Statistics */
+struct ospf6_message_stat
+{
+ u_int32_t send;
+ u_int32_t send_octet;
+ u_int32_t recv;
+ u_int32_t recv_octet;
+};
+
+/* Type string */
+extern char *ospf6_message_type_string[];
+
+/* Function Prototypes */
+int ospf6_receive (struct thread *);
+
+int ospf6_send_hello (struct thread *);
+int ospf6_send_dbdesc_rxmt (struct thread *);
+int ospf6_send_dbdesc (struct thread *);
+int ospf6_send_lsreq (struct thread *);
+
+struct ospf6_neighbor;
+struct ospf6_interface;
+int
+ospf6_send_lsupdate_rxmt (struct thread *);
+void
+ospf6_send_lsupdate_direct (struct ospf6_lsa *, struct ospf6_neighbor *);
+void
+ospf6_send_lsupdate_flood (struct ospf6_lsa *, struct ospf6_interface *);
+
+int ospf6_send_lsack_delayed (struct thread *);
+int ospf6_send_lsack_direct (struct thread *);
+
+void ospf6_message_send (u_char, struct iovec *, struct in6_addr *, u_int);
+
+#endif /* OSPF6_MESSAGE_H */
+
diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c
new file mode 100644
index 00000000..72735d5d
--- /dev/null
+++ b/ospf6d/ospf6_neighbor.c
@@ -0,0 +1,602 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "ospf6d.h"
+
+#include <zebra.h>
+
+#include "log.h"
+#include "thread.h"
+#include "linklist.h"
+#include "vty.h"
+#include "command.h"
+
+#include "ospf6_lsa.h"
+#include "ospf6_message.h"
+#include "ospf6_neighbor.h"
+#include "ospf6_nsm.h"
+#include "ospf6_lsa.h"
+#include "ospf6_lsdb.h"
+
+char *ospf6_neighbor_state_string[] =
+{
+ "None", "Down", "Attempt", "Init", "Twoway",
+ "ExStart", "ExChange", "Loading", "Full", NULL
+};
+
+int
+ospf6_neighbor_last_dbdesc_release (struct thread *thread)
+{
+ struct ospf6_neighbor *o6n;
+
+ o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+ assert (o6n);
+ memset (&o6n->last_dd, 0, sizeof (struct ospf6_dbdesc));
+ return 0;
+}
+
+
+
+void
+ospf6_neighbor_thread_cancel_all (struct ospf6_neighbor *o6n)
+{
+ if (o6n->inactivity_timer)
+ thread_cancel (o6n->inactivity_timer);
+ o6n->inactivity_timer = (struct thread *) NULL;
+
+ if (o6n->send_update)
+ thread_cancel (o6n->send_update);
+ o6n->send_update = (struct thread *) NULL;
+
+ if (o6n->thread_send_dbdesc)
+ thread_cancel (o6n->thread_send_dbdesc);
+ o6n->thread_send_dbdesc = (struct thread *) NULL;
+ if (o6n->thread_rxmt_dbdesc)
+ thread_cancel (o6n->thread_rxmt_dbdesc);
+ o6n->thread_rxmt_dbdesc = (struct thread *) NULL;
+
+ if (o6n->thread_rxmt_lsreq)
+ thread_cancel (o6n->thread_rxmt_lsreq);
+ o6n->thread_rxmt_lsreq = (struct thread *) NULL;
+}
+
+void
+ospf6_neighbor_lslist_clear (struct ospf6_neighbor *nei)
+{
+ ospf6_lsdb_remove_all (nei->summary_list);
+ ospf6_lsdb_remove_all (nei->request_list);
+ ospf6_lsdb_remove_all (nei->retrans_list);
+ ospf6_lsdb_remove_all (nei->dbdesc_list);
+}
+
+void
+ospf6_neighbor_summary_add (struct ospf6_lsa *lsa,
+ struct ospf6_neighbor *nei)
+{
+ struct ospf6_lsa *summary;
+
+ if (IS_OSPF6_DUMP_NEIGHBOR)
+ {
+ zlog_info ("Neighbor %s summary-list:", nei->str);
+ zlog_info (" Add %s", lsa->str);
+ }
+
+ ospf6_lsa_age_current (lsa);
+ summary = ospf6_lsa_summary_create (lsa->header);
+ ospf6_lsdb_add (summary, nei->summary_list);
+}
+
+void
+ospf6_neighbor_summary_remove (struct ospf6_lsa *lsa,
+ struct ospf6_neighbor *nei)
+{
+ struct ospf6_lsa *summary;
+
+ if (IS_OSPF6_DUMP_NEIGHBOR)
+ {
+ zlog_info ("Neighbor %s summary-list:", nei->str);
+ zlog_info (" Remove %s", lsa->str);
+ }
+
+ summary = ospf6_lsdb_lookup_lsdb (lsa->header->type, lsa->header->id,
+ lsa->header->adv_router, nei->summary_list);
+ ospf6_lsdb_remove (summary, nei->summary_list);
+}
+
+void
+ospf6_neighbor_request_add (struct ospf6_lsa *lsa,
+ struct ospf6_neighbor *nei)
+{
+ struct ospf6_lsa *summary;
+
+ if (IS_OSPF6_DUMP_NEIGHBOR)
+ {
+ zlog_info ("Neighbor %s request-list:", nei->str);
+ zlog_info (" Add %s", lsa->str);
+ }
+
+ ospf6_lsa_age_current (lsa);
+ summary = ospf6_lsa_summary_create (lsa->header);
+ ospf6_lsdb_add (summary, nei->request_list);
+}
+
+void
+ospf6_neighbor_request_remove (struct ospf6_lsa *lsa,
+ struct ospf6_neighbor *nei)
+{
+ struct ospf6_lsa *summary;
+
+ if (IS_OSPF6_DUMP_NEIGHBOR)
+ {
+ zlog_info ("Neighbor %s request-list:", nei->str);
+ zlog_info (" Remove %s", lsa->str);
+ }
+
+ summary = ospf6_lsdb_lookup_lsdb (lsa->header->type, lsa->header->id,
+ lsa->header->adv_router, nei->request_list);
+ ospf6_lsdb_remove (summary, nei->request_list);
+}
+
+void
+ospf6_neighbor_retrans_add (struct ospf6_lsa *lsa,
+ struct ospf6_neighbor *nei)
+{
+ if (IS_OSPF6_DUMP_NEIGHBOR)
+ {
+ zlog_info ("Neighbor %s retrans-list:", nei->str);
+ zlog_info (" Add %s", lsa->str);
+ }
+
+ ospf6_lsdb_add (lsa, nei->retrans_list);
+}
+
+void
+ospf6_neighbor_retrans_remove (struct ospf6_lsa *lsa,
+ struct ospf6_neighbor *nei)
+{
+ if (IS_OSPF6_DUMP_NEIGHBOR)
+ {
+ zlog_info ("Neighbor %s retrans-list:", nei->str);
+ zlog_info (" Remove %s", lsa->str);
+ }
+
+ ospf6_lsdb_remove (lsa, nei->retrans_list);
+
+ if (nei->retrans_list->count == 0)
+ {
+ if (nei->send_update)
+ thread_cancel (nei->send_update);
+ nei->send_update = NULL;
+ }
+}
+
+void
+ospf6_neighbor_dbdesc_add (struct ospf6_lsa *lsa,
+ struct ospf6_neighbor *nei)
+{
+ if (IS_OSPF6_DUMP_NEIGHBOR)
+ {
+ zlog_info ("Neighbor %s dbdesc-list:", nei->str);
+ zlog_info (" Add %s", lsa->str);
+ }
+
+ ospf6_lsdb_add (lsa, nei->dbdesc_list);
+}
+
+void
+ospf6_neighbor_dbdesc_remove (struct ospf6_lsa *lsa,
+ struct ospf6_neighbor *nei)
+{
+ if (IS_OSPF6_DUMP_NEIGHBOR)
+ {
+ zlog_info ("Neighbor %s dbdesc-list:", nei->str);
+ zlog_info (" Remove %s", lsa->str);
+ }
+
+ ospf6_lsdb_remove (lsa, nei->dbdesc_list);
+}
+
+
+/* prepare summary-list of his neighbor structure */
+void
+ospf6_neighbor_dbex_init (struct ospf6_neighbor *nei)
+{
+ struct ospf6_lsdb_node node;
+
+ /* clear ls-list */
+ ospf6_neighbor_lslist_clear (nei);
+
+ /* AS scope LSAs */
+ for (ospf6_lsdb_head (&node, nei->ospf6_interface->area->ospf6->lsdb);
+ ! ospf6_lsdb_is_end (&node); ospf6_lsdb_next (&node))
+ {
+ if (IS_LSA_MAXAGE (node.lsa))
+ ospf6_neighbor_retrans_add (node.lsa, nei);
+ else
+ ospf6_neighbor_summary_add (node.lsa, nei);
+ }
+
+ /* AREA scope LSAs */
+ for (ospf6_lsdb_head (&node, nei->ospf6_interface->area->lsdb);
+ ! ospf6_lsdb_is_end (&node); ospf6_lsdb_next (&node))
+ {
+ if (IS_LSA_MAXAGE (node.lsa))
+ ospf6_neighbor_retrans_add (node.lsa, nei);
+ else
+ ospf6_neighbor_summary_add (node.lsa, nei);
+ }
+
+ /* INTERFACE scope LSAs */
+ for (ospf6_lsdb_head (&node, nei->ospf6_interface->lsdb);
+ ! ospf6_lsdb_is_end (&node); ospf6_lsdb_next (&node))
+ {
+ if (IS_LSA_MAXAGE (node.lsa))
+ ospf6_neighbor_retrans_add (node.lsa, nei);
+ else
+ ospf6_neighbor_summary_add (node.lsa, nei);
+ }
+}
+
+/* create ospf6_neighbor */
+struct ospf6_neighbor *
+ospf6_neighbor_create (u_int32_t router_id, struct ospf6_interface *o6i)
+{
+ struct ospf6_neighbor *new;
+ char buf[32];
+
+ new = (struct ospf6_neighbor *)
+ XMALLOC (MTYPE_OSPF6_NEIGHBOR, sizeof (struct ospf6_neighbor));
+ if (new == NULL)
+ {
+ zlog_warn ("neighbor: malloc failed");
+ return NULL;
+ }
+
+ memset (new, 0, sizeof (struct ospf6_neighbor));
+
+ new->state = OSPF6_NEIGHBOR_STATE_DOWN;
+
+ new->router_id = router_id;
+ inet_ntop (AF_INET, &router_id, buf, sizeof (buf));
+ snprintf (new->str, sizeof (new->str), "%s%%%s", buf, o6i->interface->name);
+ new->inactivity_timer = (struct thread *) NULL;
+
+ new->summary_list = ospf6_lsdb_create ();
+ new->request_list = ospf6_lsdb_create ();
+ new->retrans_list = ospf6_lsdb_create ();
+ new->dbdesc_list = ospf6_lsdb_create ();
+
+ listnode_add (o6i->neighbor_list, new);
+ new->ospf6_interface = o6i;
+
+ CALL_ADD_HOOK (&neighbor_hook, new);
+
+ return new;
+}
+
+void
+ospf6_neighbor_delete (struct ospf6_neighbor *o6n)
+{
+ CALL_REMOVE_HOOK (&neighbor_hook, o6n);
+
+ ospf6_neighbor_thread_cancel_all (o6n);
+ ospf6_neighbor_lslist_clear (o6n);
+
+ list_free (o6n->dbdesc_lsa);
+
+ ospf6_lsdb_delete (o6n->summary_list);
+ ospf6_lsdb_delete (o6n->request_list);
+ ospf6_lsdb_delete (o6n->retrans_list);
+ ospf6_lsdb_delete (o6n->dbdesc_list);
+
+ XFREE (MTYPE_OSPF6_NEIGHBOR, o6n);
+}
+
+struct ospf6_neighbor *
+ospf6_neighbor_lookup (u_int32_t router_id,
+ struct ospf6_interface *o6i)
+{
+ listnode n;
+ struct ospf6_neighbor *o6n;
+
+ for (n = listhead (o6i->neighbor_list); n; nextnode (n))
+ {
+ o6n = (struct ospf6_neighbor *) getdata (n);
+ if (o6n->router_id == router_id)
+ return o6n;
+ }
+ return (struct ospf6_neighbor *) NULL;
+}
+
+
+/* vty functions */
+/* show neighbor structure */
+void
+ospf6_neighbor_show_summary (struct vty *vty, struct ospf6_neighbor *o6n)
+{
+ char router_id[16];
+ char dr[16], bdr[16];
+ char duration[16];
+ struct timeval now, res;
+
+/*
+ vty_out (vty, "%-15s %6s/%-11s %-15s %-15s %s[%s]%s",
+ "RouterID", "State", "Duration", "DR", "BDR", "I/F",
+ "State", VTY_NEWLINE);
+*/
+
+ inet_ntop (AF_INET, &o6n->router_id, router_id, sizeof (router_id));
+ inet_ntop (AF_INET, &o6n->dr, dr, sizeof (dr));
+ inet_ntop (AF_INET, &o6n->bdr, bdr, sizeof (bdr));
+
+ gettimeofday (&now, NULL);
+ ospf6_timeval_sub (&now, &o6n->last_changed, &res);
+ ospf6_timeval_string_summary (&res, duration, sizeof (duration));
+
+ vty_out (vty, "%-15s %6s/%-11s %-15s %-15s %s[%s]%s",
+ router_id, ospf6_neighbor_state_string[o6n->state],
+ duration, dr, bdr, o6n->ospf6_interface->interface->name,
+ ospf6_interface_state_string[o6n->ospf6_interface->state],
+ VTY_NEWLINE);
+}
+
+void
+ospf6_neighbor_show (struct vty *vty, struct ospf6_neighbor *o6n)
+{
+ char hisaddr[64], timestring[32];
+ struct timeval now, res;
+
+ inet_ntop (AF_INET6, &o6n->hisaddr, hisaddr, sizeof (hisaddr));
+ vty_out (vty, " Neighbor %s, interface address %s%s",
+ o6n->str, hisaddr, VTY_NEWLINE);
+ vty_out (vty, " Area %s via interface %s (ifindex %d)%s",
+ o6n->ospf6_interface->area->str,
+ o6n->ospf6_interface->interface->name,
+ o6n->ospf6_interface->interface->ifindex,
+ VTY_NEWLINE);
+ vty_out (vty, " Priority: %d, State: %s, %d state changes%s",
+ o6n->priority, ospf6_neighbor_state_string[o6n->state],
+ o6n->ospf6_stat_state_changed, VTY_NEWLINE);
+
+ gettimeofday (&now, NULL);
+ ospf6_timeval_sub (&now, &o6n->last_changed, &res);
+ ospf6_timeval_string_summary (&res, timestring, sizeof (timestring));
+ vty_out (vty, " Last state changed: %s ago%s", timestring, VTY_NEWLINE);
+}
+
+void
+ospf6_neighbor_show_detail (struct vty *vty, struct ospf6_neighbor *o6n)
+{
+ char hisdr[16], hisbdr[16];
+
+ ospf6_neighbor_show (vty, o6n);
+
+ inet_ntop (AF_INET, &o6n->dr, hisdr, sizeof (hisdr));
+ inet_ntop (AF_INET, &o6n->bdr, hisbdr, sizeof (hisbdr));
+
+ vty_out (vty, " His Ifindex of myside: %d%s",
+ o6n->ifid, VTY_NEWLINE);
+ vty_out (vty, " His DR Election: DR %s, BDR %s%s",
+ hisdr, hisbdr, VTY_NEWLINE);
+
+ vty_out (vty, " Last received DbDesc: opt:%s"
+ " ifmtu:%hu bit:%s%s%s seqnum:%ld%s",
+ "xxx", ntohs (o6n->last_dd.ifmtu),
+ (DD_IS_IBIT_SET (o6n->last_dd.bits) ? "I" : "-"),
+ (DD_IS_MBIT_SET (o6n->last_dd.bits) ? "M" : "-"),
+ (DD_IS_MSBIT_SET (o6n->last_dd.bits) ? "m" : "s"),
+ (u_long)ntohl (o6n->last_dd.seqnum), VTY_NEWLINE);
+ vty_out (vty, " My DbDesc bit for this neighbor: %s%s%s%s",
+ (DD_IS_IBIT_SET (o6n->dbdesc_bits) ? "I" : "-"),
+ (DD_IS_MBIT_SET (o6n->dbdesc_bits) ? "M" : "-"),
+ (DD_IS_MSBIT_SET (o6n->dbdesc_bits) ? "m" : "s"),
+ VTY_NEWLINE);
+
+ vty_out (vty, " %-16s %5d times, %-16s %5d times%s",
+ "SeqnumMismatch", o6n->ospf6_stat_seqnum_mismatch,
+ "BadLSReq", o6n->ospf6_stat_bad_lsreq, VTY_NEWLINE);
+ vty_out (vty, " %-16s %5d times, %-16s %5d times%s",
+ "OnewayReceived", o6n->ospf6_stat_oneway_received,
+ "InactivityTimer", o6n->ospf6_stat_inactivity_timer,
+ VTY_NEWLINE);
+ vty_out (vty, " %-16s %5d times, %-16s %5d times%s",
+ "DbDescRetrans", o6n->ospf6_stat_retrans_dbdesc,
+ "LSReqRetrans", o6n->ospf6_stat_retrans_lsreq,
+ VTY_NEWLINE);
+ vty_out (vty, " %-16s %5d times%s",
+ "LSUpdateRetrans", o6n->ospf6_stat_retrans_lsupdate,
+ VTY_NEWLINE);
+ vty_out (vty, " %-16s %5d times, %-16s %5d times%s",
+ "LSAReceived", o6n->ospf6_stat_received_lsa,
+ "LSUpdateReceived", o6n->ospf6_stat_received_lsupdate,
+ VTY_NEWLINE);
+
+ vty_out (vty, " %-12s %-12s %-12s%s",
+ "Message", "DbDesc", "LSReq", VTY_NEWLINE);
+ vty_out (vty, " %-12s %12d %12d%s", "LSA Send",
+ o6n->lsa_send[OSPF6_MESSAGE_TYPE_DBDESC],
+ o6n->lsa_send[OSPF6_MESSAGE_TYPE_LSREQ], VTY_NEWLINE);
+ vty_out (vty, " %-12s %12d %12d%s", "LSA Receive",
+ o6n->lsa_receive[OSPF6_MESSAGE_TYPE_DBDESC],
+ o6n->lsa_receive[OSPF6_MESSAGE_TYPE_LSREQ], VTY_NEWLINE);
+ vty_out (vty, "%s", VTY_NEWLINE);
+}
+
+void
+ospf6_neighbor_timestamp_hello (struct ospf6_neighbor *o6n)
+{
+ struct timeval now, interval;
+ gettimeofday (&now, (struct timezone *) NULL);
+ if (o6n->tv_last_hello_received.tv_sec)
+ {
+ ospf6_timeval_sub (&now, &o6n->tv_last_hello_received, &interval);
+ zlog_info ("Hello Interval %s : %ld msec",
+ o6n->str, interval.tv_sec * 1000 + interval.tv_usec % 1000);
+ }
+ o6n->tv_last_hello_received.tv_sec = now.tv_sec;
+ o6n->tv_last_hello_received.tv_usec = now.tv_usec;
+}
+
+DEFUN (show_ipv6_ospf6_neighbor_routerid,
+ show_ipv6_ospf6_neighbor_routerid_cmd,
+ "show ipv6 ospf6 neighbor A.B.C.D",
+ SHOW_STR
+ IP6_STR
+ OSPF6_STR
+ "Neighbor list\n"
+ "OSPF6 neighbor Router ID in IP address format\n"
+ )
+{
+ u_int32_t router_id;
+ struct ospf6_neighbor *o6n;
+ struct ospf6_interface *o6i;
+ struct ospf6_area *o6a;
+ listnode nodei, nodej, nodek;
+
+ OSPF6_CMD_CHECK_RUNNING ();
+
+ if (argc == 0)
+ vty_out (vty, "%-15s %6s/%-11s %-15s %-15s %s[%s]%s",
+ "RouterID", "State", "Duration", "DR", "BDR", "I/F",
+ "State", VTY_NEWLINE);
+ else if (inet_pton (AF_INET, argv[0], &router_id) != 1)
+ {
+ vty_out (vty, "Malformed Router-ID: %s%s", argv[0], VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ for (nodei = listhead (ospf6->area_list); nodei; nextnode (nodei))
+ {
+ o6a = getdata (nodei);
+ for (nodej = listhead (o6a->if_list); nodej; nextnode (nodej))
+ {
+ o6i = getdata (nodej);
+ for (nodek = listhead (o6i->neighbor_list); nodek; nextnode (nodek))
+ {
+ o6n = getdata (nodek);
+ if (argc == 0)
+ ospf6_neighbor_show_summary (vty, o6n);
+ else if (o6n->router_id == router_id)
+ ospf6_neighbor_show_detail (vty, o6n);
+ }
+ }
+ }
+ return CMD_SUCCESS;
+}
+
+ALIAS (show_ipv6_ospf6_neighbor_routerid,
+ show_ipv6_ospf6_neighbor_cmd,
+ "show ipv6 ospf6 neighbor",
+ SHOW_STR
+ IP6_STR
+ OSPF6_STR
+ "Neighbor list\n"
+ )
+
+DEFUN (show_ipv6_ospf6_neighborlist,
+ show_ipv6_ospf6_neighborlist_cmd,
+ "show ipv6 ospf6 (summary-list|request-list|retrans-list|dbdesc-list)",
+ SHOW_STR
+ IP6_STR
+ OSPF6_STR
+ "Link State summary list\n"
+ "Link State request list\n"
+ "Link State retransmission list\n"
+ "Link State Description list (Used to retrans DbDesc)\n"
+ )
+{
+ struct ospf6_area *o6a;
+ struct ospf6_interface *o6i;
+ struct ospf6_neighbor *o6n;
+ listnode i, j, k, l;
+ struct ospf6_lsa *lsa;
+ struct ospf6_lsdb *lsdb = NULL;
+ char type[16], id[16], adv_router[16];
+ struct ospf6_lsdb_node node;
+ u_int16_t age, cksum, len;
+ u_int32_t seqnum;
+
+ OSPF6_CMD_CHECK_RUNNING ();
+ i = j = k = l = NULL;
+
+ for (i = listhead (ospf6->area_list); i; nextnode (i))
+ {
+ o6a = (struct ospf6_area *) getdata (i);
+ for (j = listhead (o6a->if_list); j; nextnode (j))
+ {
+ o6i = (struct ospf6_interface *) getdata (j);
+ for (k = listhead (o6i->neighbor_list); k; nextnode (k))
+ {
+ o6n = (struct ospf6_neighbor *) getdata (k);
+
+ if (strncmp (argv[0], "sum", 3) == 0)
+ lsdb = o6n->summary_list;
+ else if (strncmp (argv[0], "req", 3) == 0)
+ lsdb = o6n->request_list;
+ else if (strncmp (argv[0], "ret", 3) == 0)
+ lsdb = o6n->retrans_list;
+ else if (strncmp (argv[0], "dbd", 3) == 0)
+ lsdb = o6n->dbdesc_list;
+
+ vty_out (vty, "neighbor %s on interface %s: %d%s", o6n->str,
+ o6i->interface->name, lsdb->count,
+ VTY_NEWLINE);
+ for (ospf6_lsdb_head (&node, lsdb); ! ospf6_lsdb_is_end (&node);
+ ospf6_lsdb_next (&node))
+ {
+ lsa = node.lsa;
+ ospf6_lsa_age_current (lsa);
+
+ ospf6_lsa_type_string (lsa->header->type, type,
+ sizeof (type));
+ inet_ntop (AF_INET, &lsa->header->id, id, sizeof (id));
+ inet_ntop (AF_INET, &lsa->header->adv_router, adv_router,
+ sizeof (adv_router));
+ age = ntohs (lsa->header->age);
+ seqnum = ntohl (lsa->header->seqnum);
+ cksum = ntohs (lsa->header->checksum);
+ len = ntohs (lsa->header->length);
+
+ vty_out (vty, " %s-LSA ID=%s Adv=%s%s",
+ type, id, adv_router, VTY_NEWLINE);
+ vty_out (vty, " Age: %hu SeqNum: %#x Cksum: %hx Len: %hu%s",
+ age, seqnum, cksum, len, VTY_NEWLINE);
+ }
+ }
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+void
+ospf6_neighbor_init ()
+{
+ install_element (VIEW_NODE, &show_ipv6_ospf6_neighbor_cmd);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_neighbor_routerid_cmd);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_neighborlist_cmd);
+
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_neighbor_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_neighbor_routerid_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_neighborlist_cmd);
+}
+
+
diff --git a/ospf6d/ospf6_neighbor.h b/ospf6d/ospf6_neighbor.h
new file mode 100644
index 00000000..c3821c67
--- /dev/null
+++ b/ospf6d/ospf6_neighbor.h
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef OSPF6_NEIGHBOR_H
+#define OSPF6_NEIGHBOR_H
+
+/* Neighbor structure */
+struct ospf6_neighbor
+{
+ /* Neighbor Router ID String */
+ char str[32];
+
+ /* OSPFv3 Interface this neighbor belongs to */
+ struct ospf6_interface *ospf6_interface;
+
+ /* Neighbor state */
+ u_char state;
+ struct timeval last_changed;
+
+ /* Neighbor Router ID */
+ u_int32_t router_id;
+
+ /* Router Priority of this neighbor */
+ u_char priority;
+
+ u_int32_t ifid;
+ u_int32_t dr;
+ u_int32_t bdr;
+ u_int32_t prevdr;
+ u_int32_t prevbdr;
+
+ /* Link-LSA's options field */
+ char options[3];
+
+ /* IPaddr of I/F on our side link */
+ struct in6_addr hisaddr;
+
+ /* new */
+ struct ospf6_lsdb *summary_list;
+ struct ospf6_lsdb *request_list;
+ struct ospf6_lsdb *retrans_list;
+
+ /* For Database Exchange */
+ u_char dbdesc_bits;
+ u_int32_t dbdesc_seqnum;
+ struct ospf6_dbdesc *dbdesc_previous;
+
+ /* last received DD , including OSPF capability of this neighbor */
+ struct ospf6_dbdesc last_dd;
+
+ /* LSAs to retransmit to this neighbor */
+ list dbdesc_lsa;
+
+ /* placeholder for DbDesc */
+ struct iovec dbdesc_last_send[1024];
+
+ struct thread *inactivity_timer;
+
+ /* DbDesc */
+ struct thread *thread_send_dbdesc;
+ struct thread *thread_rxmt_dbdesc;
+ list dbdesclist;
+ struct ospf6_lsdb *dbdesc_list;
+
+ /* LSReq */
+ struct thread *thread_send_lsreq;
+ struct thread *thread_rxmt_lsreq;
+
+ /* LSUpdate */
+ struct thread *send_update;
+ struct thread *thread_send_update;
+ struct thread *thread_rxmt_update;
+
+ /* statistics */
+ u_int message_send[OSPF6_MESSAGE_TYPE_MAX];
+ u_int message_receive[OSPF6_MESSAGE_TYPE_MAX];
+ u_int lsa_send[OSPF6_MESSAGE_TYPE_MAX];
+ u_int lsa_receive[OSPF6_MESSAGE_TYPE_MAX];
+
+ u_int ospf6_stat_state_changed;
+ u_int ospf6_stat_seqnum_mismatch;
+ u_int ospf6_stat_bad_lsreq;
+ u_int ospf6_stat_oneway_received;
+ u_int ospf6_stat_inactivity_timer;
+ u_int ospf6_stat_dr_election;
+ u_int ospf6_stat_retrans_dbdesc;
+ u_int ospf6_stat_retrans_lsreq;
+ u_int ospf6_stat_retrans_lsupdate;
+ u_int ospf6_stat_received_lsa;
+ u_int ospf6_stat_received_lsupdate;
+
+ struct timeval tv_last_hello_received;
+};
+
+extern char *ospf6_neighbor_state_string[];
+
+
+/* Function Prototypes */
+int
+ospf6_neighbor_last_dbdesc_release (struct thread *);
+
+void
+ospf6_neighbor_lslist_clear (struct ospf6_neighbor *);
+
+void
+ospf6_neighbor_summary_add (struct ospf6_lsa *, struct ospf6_neighbor *);
+void
+ospf6_neighbor_summary_remove (struct ospf6_lsa *, struct ospf6_neighbor *);
+
+void
+ospf6_neighbor_request_add (struct ospf6_lsa *, struct ospf6_neighbor *);
+void
+ospf6_neighbor_request_remove (struct ospf6_lsa *, struct ospf6_neighbor *);
+
+void
+ospf6_neighbor_retrans_add (struct ospf6_lsa *, struct ospf6_neighbor *);
+void
+ospf6_neighbor_retrans_remove (struct ospf6_lsa *, struct ospf6_neighbor *);
+
+void
+ospf6_neighbor_dbdesc_add (struct ospf6_lsa *lsa,
+ struct ospf6_neighbor *nei);
+void
+ospf6_neighbor_dbdesc_remove (struct ospf6_lsa *lsa,
+ struct ospf6_neighbor *nei);
+
+void
+ospf6_neighbor_dbex_init (struct ospf6_neighbor *nei);
+
+void
+ospf6_neighbor_thread_cancel_all (struct ospf6_neighbor *);
+
+struct ospf6_neighbor *
+ospf6_neighbor_create (u_int32_t, struct ospf6_interface *);
+void
+ospf6_neighbor_delete (struct ospf6_neighbor *);
+struct ospf6_neighbor *
+ospf6_neighbor_lookup (u_int32_t, struct ospf6_interface *);
+
+void ospf6_neighbor_init ();
+
+#endif /* OSPF6_NEIGHBOR_H */
+
diff --git a/ospf6d/ospf6_network.c b/ospf6d/ospf6_network.c
new file mode 100644
index 00000000..041d829b
--- /dev/null
+++ b/ospf6d/ospf6_network.c
@@ -0,0 +1,501 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <zebra.h>
+#include "memory.h"
+#include "log.h"
+#include "sockunion.h"
+
+#include "ospf6d.h"
+#include "ospf6_proto.h"
+
+extern int errno;
+extern struct sockaddr_in6 allspfrouters6;
+extern struct sockaddr_in6 alldrouters6;
+extern int ospf6_sock;
+extern struct thread_master *master;
+
+/* iovec functions */
+void
+iov_clear (struct iovec *iov, size_t iovlen)
+{
+ int i;
+ for (i = 0; i < iovlen; i++)
+ {
+ iov[i].iov_base = NULL;
+ iov[i].iov_len = 0;
+ }
+}
+
+int
+iov_count (struct iovec *iov)
+{
+ int i;
+ for (i = 0; iov[i].iov_base; i++)
+ ;
+ return i;
+}
+
+int
+iov_totallen (struct iovec *iov)
+{
+ int i;
+ int totallen = 0;
+ for (i = 0; iov[i].iov_base; i++)
+ totallen += iov[i].iov_len;
+ return totallen;
+}
+
+void *
+iov_prepend (int mtype, struct iovec *iov, size_t len)
+{
+ int i, iovlen;
+ void *base;
+
+ base = (void *) XMALLOC (mtype, len);
+ if (!base)
+ {
+ zlog_warn ("Network: iov_prepend failed");
+ return NULL;
+ }
+ memset (base, 0, len);
+
+ iovlen = iov_count (iov);
+ for (i = iovlen; i; i--)
+ {
+ iov[i].iov_base = iov[i - 1].iov_base;
+ iov[i].iov_len = iov[i - 1].iov_len;
+ }
+ iov[0].iov_base = (char *)base;
+ iov[0].iov_len = len;
+
+ return base;
+}
+
+void *
+iov_append (int mtype, struct iovec *iov, size_t len)
+{
+ int i;
+ void *base;
+
+ base = (void *)XMALLOC (mtype, len);
+ if (!base)
+ {
+ zlog_warn ("Network: iov_append failed");
+ return NULL;
+ }
+ memset (base, 0, len);
+
+ /* proceed to the end */
+ i = iov_count (iov);
+
+ iov[i].iov_base = (char *)base;
+ iov[i].iov_len = len;
+
+ return base;
+}
+
+void *
+iov_attach_last (struct iovec *iov, void *base, size_t len)
+{
+ int i;
+ i = iov_count (iov);
+ iov[i].iov_base = (char *)base;
+ iov[i].iov_len = len;
+ return base;
+}
+
+void *
+iov_detach_first (struct iovec *iov)
+{
+ int i, iovlen;
+ void *base;
+ size_t len;
+
+ base = iov[0].iov_base;
+ len = iov[0].iov_len;
+ iovlen = iov_count (iov);
+ for (i = 0; i < iovlen; i++)
+ {
+ iov[i].iov_base = iov[i + 1].iov_base;
+ iov[i].iov_len = iov[i + 1].iov_len;
+ }
+ return base;
+}
+
+int
+iov_free (int mtype, struct iovec *iov, u_int begin, u_int end)
+{
+ int i;
+
+ for (i = begin; i < end; i++)
+ {
+ XFREE (mtype, iov[i].iov_base);
+ iov[i].iov_base = NULL;
+ iov[i].iov_len = 0;
+ }
+
+ return 0;
+}
+
+void
+iov_trim_head (int mtype, struct iovec *iov)
+{
+ void *base;
+
+ base = iov_detach_first (iov);
+ XFREE (mtype, base);
+ return;
+}
+
+void
+iov_free_all (int mtype, struct iovec *iov)
+{
+ int i, end = iov_count (iov);
+ for (i = 0; i < end; i++)
+ {
+ XFREE (mtype, iov[i].iov_base);
+ iov[i].iov_base = NULL;
+ iov[i].iov_len = 0;
+ }
+}
+
+void
+iov_copy_all (struct iovec *dst, struct iovec *src, size_t size)
+{
+ int i;
+ for (i = 0; i < size; i++)
+ {
+ dst[i].iov_base = src[i].iov_base;
+ dst[i].iov_len = src[i].iov_len;
+ }
+}
+
+
+/* Make ospf6d's server socket. */
+int
+ospf6_serv_sock ()
+{
+ ospf6_sock = socket (AF_INET6, SOCK_RAW, IPPROTO_OSPFIGP);
+ if (ospf6_sock < 0)
+ {
+ zlog_warn ("Network: can't create OSPF6 socket.");
+ return -1;
+ }
+ sockopt_reuseaddr (ospf6_sock);
+
+ /* setup global sockaddr_in6, allspf6 & alldr6 for later use */
+ allspfrouters6.sin6_family = AF_INET6;
+ alldrouters6.sin6_family = AF_INET6;
+#ifdef SIN6_LEN
+ allspfrouters6.sin6_len = sizeof (struct sockaddr_in6);
+ alldrouters6.sin6_len = sizeof (struct sockaddr_in6);
+#endif /* SIN6_LEN */
+ inet_pton (AF_INET6, ALLSPFROUTERS6, &allspfrouters6.sin6_addr);
+ inet_pton (AF_INET6, ALLDROUTERS6, &alldrouters6.sin6_addr);
+
+ return 0;
+}
+
+/* returns 0 if succeed, else returns -1 */
+int
+ospf6_join_allspfrouters (u_int ifindex)
+{
+ struct ipv6_mreq mreq6;
+ int retval;
+
+ assert (ifindex);
+ mreq6.ipv6mr_interface = ifindex;
+ memcpy (&mreq6.ipv6mr_multiaddr, &allspfrouters6.sin6_addr,
+ sizeof (struct in6_addr));
+
+ retval = setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
+ &mreq6, sizeof (mreq6));
+
+ if (retval < 0)
+ zlog_err ("Network: Join AllSPFRouters on ifindex %d failed: %s",
+ ifindex, strerror (errno));
+#if 0
+ else
+ zlog_info ("Network: Join AllSPFRouters on ifindex %d", ifindex);
+#endif
+
+ return retval;
+}
+
+void
+ospf6_leave_allspfrouters (u_int ifindex)
+{
+ struct ipv6_mreq mreq6;
+
+ assert (ifindex);
+ mreq6.ipv6mr_interface = ifindex;
+ memcpy (&mreq6.ipv6mr_multiaddr, &allspfrouters6.sin6_addr,
+ sizeof (struct in6_addr));
+
+ if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
+ &mreq6, sizeof (mreq6)) < 0)
+ zlog_warn ("Network: Leave AllSPFRouters on ifindex %d Failed: %s",
+ ifindex, strerror (errno));
+#if 0
+ else
+ zlog_info ("Network: Leave AllSPFRouters on ifindex %d", ifindex);
+#endif
+}
+
+void
+ospf6_join_alldrouters (u_int ifindex)
+{
+ struct ipv6_mreq mreq6;
+
+ assert (ifindex);
+ mreq6.ipv6mr_interface = ifindex;
+ memcpy (&mreq6.ipv6mr_multiaddr, &alldrouters6.sin6_addr,
+ sizeof (struct in6_addr));
+
+ if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
+ &mreq6, sizeof (mreq6)) < 0)
+ zlog_warn ("Network: Join AllDRouters on ifindex %d Failed: %s",
+ ifindex, strerror (errno));
+#if 0
+ else
+ zlog_info ("Network: Join AllDRouters on ifindex %d", ifindex);
+#endif
+}
+
+void
+ospf6_leave_alldrouters (u_int ifindex)
+{
+ struct ipv6_mreq mreq6;
+
+ assert (ifindex);
+ mreq6.ipv6mr_interface = ifindex;
+ memcpy (&mreq6.ipv6mr_multiaddr, &alldrouters6.sin6_addr,
+ sizeof (struct in6_addr));
+
+ if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
+ &mreq6, sizeof (mreq6)) < 0)
+ zlog_warn ("Network: Leave AllDRouters on ifindex %d Failed", ifindex);
+#if 0
+ else
+ zlog_info ("Network: Leave AllDRouters on ifindex %d", ifindex);
+#endif
+}
+
+/* setsockopt ReUseAddr to on */
+void
+ospf6_set_reuseaddr ()
+{
+ u_int on = 0;
+ if (setsockopt (ospf6_sock, SOL_SOCKET, SO_REUSEADDR, &on,
+ sizeof (u_int)) < 0)
+ zlog_warn ("Network: set SO_REUSEADDR failed: %s", strerror (errno));
+}
+
+/* setsockopt MulticastLoop to off */
+void
+ospf6_reset_mcastloop ()
+{
+ u_int off = 0;
+ if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
+ &off, sizeof (u_int)) < 0)
+ zlog_warn ("Network: reset IPV6_MULTICAST_LOOP failed: %s",
+ strerror (errno));
+}
+
+void
+ospf6_set_pktinfo ()
+{
+ u_int on = 1;
+#ifdef IPV6_RECVPKTINFO /*2292bis-01*/
+ if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
+ &on, sizeof (u_int)) < 0)
+ zlog_warn ("Network: set IPV6_RECVPKTINFO failed: %s", strerror (errno));
+#else /*RFC2292*/
+ if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_PKTINFO,
+ &on, sizeof (u_int)) < 0)
+ zlog_warn ("Network: set IPV6_PKTINFO failed: %s", strerror (errno));
+#endif
+}
+
+void
+ospf6_set_checksum ()
+{
+ int offset = 12;
+#ifndef DISABLE_IPV6_CHECKSUM
+ if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_CHECKSUM,
+ &offset, sizeof (offset)) < 0)
+ zlog_warn ("Network: set IPV6_CHECKSUM failed: %s", strerror (errno));
+#else
+ zlog_warn ("Network: Don't set IPV6_CHECKSUM");
+#endif /* DISABLE_IPV6_CHECKSUM */
+}
+
+void
+ospf6_sendmsg (struct in6_addr *src, struct in6_addr *dst,
+ unsigned int *ifindex, struct iovec *message)
+{
+ int retval;
+ struct msghdr smsghdr;
+ struct cmsghdr *scmsgp;
+ u_char cmsgbuf[CMSG_SPACE(sizeof (struct in6_pktinfo))];
+ struct in6_pktinfo *pktinfo;
+ struct sockaddr_in6 dst_sin6;
+
+ assert (dst);
+ assert (*ifindex);
+
+ scmsgp = (struct cmsghdr *)cmsgbuf;
+ pktinfo = (struct in6_pktinfo *)(CMSG_DATA(scmsgp));
+ memset (&dst_sin6, 0, sizeof (struct sockaddr_in6));
+
+ /* source address */
+ pktinfo->ipi6_ifindex = *ifindex;
+ if (src)
+ memcpy (&pktinfo->ipi6_addr, src, sizeof (struct in6_addr));
+ else
+ memset (&pktinfo->ipi6_addr, 0, sizeof (struct in6_addr));
+
+ /* destination address */
+ dst_sin6.sin6_family = AF_INET6;
+#ifdef SIN6_LEN
+ dst_sin6.sin6_len = sizeof (struct sockaddr_in6);
+#endif /*SIN6_LEN*/
+ memcpy (&dst_sin6.sin6_addr, dst, sizeof (struct in6_addr));
+#ifdef HAVE_SIN6_SCOPE_ID
+ dst_sin6.sin6_scope_id = *ifindex;
+#endif
+
+ /* send control msg */
+ scmsgp->cmsg_level = IPPROTO_IPV6;
+ scmsgp->cmsg_type = IPV6_PKTINFO;
+ scmsgp->cmsg_len = CMSG_LEN (sizeof (struct in6_pktinfo));
+ /* scmsgp = CMSG_NXTHDR (&smsghdr, scmsgp); */
+
+ /* send msg hdr */
+ smsghdr.msg_iov = message;
+ smsghdr.msg_iovlen = iov_count (message);
+ smsghdr.msg_name = (caddr_t) &dst_sin6;
+ smsghdr.msg_namelen = sizeof (struct sockaddr_in6);
+ smsghdr.msg_control = (caddr_t) cmsgbuf;
+ smsghdr.msg_controllen = sizeof (cmsgbuf);
+
+ retval = sendmsg (ospf6_sock, &smsghdr, 0);
+ if (retval != iov_totallen (message))
+ zlog_warn ("Network: sendmsg (ifindex: %d) failed: %s(%d)",
+ *ifindex, strerror (errno), errno);
+}
+
+void
+ospf6_recvmsg (struct in6_addr *src, struct in6_addr *dst,
+ unsigned int *ifindex, struct iovec *message)
+{
+ int retval;
+ struct msghdr rmsghdr;
+ struct cmsghdr *rcmsgp;
+ u_char cmsgbuf[CMSG_SPACE(sizeof (struct in6_pktinfo))];
+ struct in6_pktinfo *pktinfo;
+ struct sockaddr_in6 src_sin6;
+
+ rcmsgp = (struct cmsghdr *)cmsgbuf;
+ pktinfo = (struct in6_pktinfo *)(CMSG_DATA(rcmsgp));
+ memset (&src_sin6, 0, sizeof (struct sockaddr_in6));
+
+ /* receive control msg */
+ rcmsgp->cmsg_level = IPPROTO_IPV6;
+ rcmsgp->cmsg_type = IPV6_PKTINFO;
+ rcmsgp->cmsg_len = CMSG_LEN (sizeof (struct in6_pktinfo));
+ /* rcmsgp = CMSG_NXTHDR (&rmsghdr, rcmsgp); */
+
+ /* receive msg hdr */
+ rmsghdr.msg_iov = message;
+ rmsghdr.msg_iovlen = iov_count (message);
+ rmsghdr.msg_name = (caddr_t) &src_sin6;
+ rmsghdr.msg_namelen = sizeof (struct sockaddr_in6);
+ rmsghdr.msg_control = (caddr_t) cmsgbuf;
+ rmsghdr.msg_controllen = sizeof (cmsgbuf);
+
+ retval = recvmsg (ospf6_sock, &rmsghdr, 0);
+ if (retval < 0)
+ {
+ zlog_warn ("Network: recvmsg failed: %s", strerror (errno));
+ }
+ else if (retval == iov_totallen (message))
+ {
+ zlog_warn ("Network: possibly buffer shortage: %d received, buffer size: %d",
+ retval, iov_totallen (message));
+ }
+
+ /* source address */
+ assert (src);
+ memcpy (src, &src_sin6.sin6_addr, sizeof (struct in6_addr));
+
+ /* destination address */
+ if (ifindex)
+ *ifindex = pktinfo->ipi6_ifindex;
+ if (dst)
+ memcpy (dst, &pktinfo->ipi6_addr, sizeof (struct in6_addr));
+}
+
+void
+ospf6_recvmsg_peek (struct in6_addr *src, struct in6_addr *dst,
+ unsigned int *ifindex, struct iovec *message)
+{
+ int retval;
+ struct msghdr rmsghdr;
+ struct cmsghdr *rcmsgp;
+ u_char cmsgbuf[CMSG_SPACE(sizeof (struct in6_pktinfo))];
+ struct in6_pktinfo *pktinfo;
+ struct sockaddr_in6 src_sin6;
+
+ rcmsgp = (struct cmsghdr *)cmsgbuf;
+ pktinfo = (struct in6_pktinfo *)(CMSG_DATA(rcmsgp));
+ memset (&src_sin6, 0, sizeof (struct sockaddr_in6));
+
+ /* receive control msg */
+ rcmsgp->cmsg_level = IPPROTO_IPV6;
+ rcmsgp->cmsg_type = IPV6_PKTINFO;
+ rcmsgp->cmsg_len = CMSG_LEN (sizeof (struct in6_pktinfo));
+ /* rcmsgp = CMSG_NXTHDR (&rmsghdr, rcmsgp); */
+
+ /* receive msg hdr */
+ rmsghdr.msg_iov = message;
+ rmsghdr.msg_iovlen = iov_count (message);
+ rmsghdr.msg_name = (caddr_t) &src_sin6;
+ rmsghdr.msg_namelen = sizeof (struct sockaddr_in6);
+ rmsghdr.msg_control = (caddr_t) cmsgbuf;
+ rmsghdr.msg_controllen = sizeof (cmsgbuf);
+
+ retval = recvmsg (ospf6_sock, &rmsghdr, MSG_PEEK);
+ if (retval != iov_totallen (message))
+ zlog_warn ("Network: recvmsg failed: %s", strerror (errno));
+
+ /* source address */
+ assert (src);
+ memcpy (src, &src_sin6.sin6_addr, sizeof (struct in6_addr));
+
+ /* destination address */
+ if (ifindex)
+ *ifindex = pktinfo->ipi6_ifindex;
+ if (dst)
+ memcpy (dst, &pktinfo->ipi6_addr, sizeof (struct in6_addr));
+}
+
diff --git a/ospf6d/ospf6_network.h b/ospf6d/ospf6_network.h
new file mode 100644
index 00000000..934cce59
--- /dev/null
+++ b/ospf6d/ospf6_network.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef OSPF6_NETWORK_H
+#define OSPF6_NETWORK_H
+
+
+
+/* Function Prototypes */
+void iov_clear (struct iovec *, size_t);
+int iov_count (struct iovec *);
+int iov_totallen (struct iovec *);
+void *iov_prepend (int, struct iovec *, size_t);
+void *iov_append (int, struct iovec *, size_t);
+void *iov_attach_last (struct iovec *, void *, size_t);
+void *iov_detach_first (struct iovec *);
+int iov_free (int, struct iovec *, u_int, u_int);
+void iov_trim_head (int, struct iovec *);
+void iov_free_all (int, struct iovec *);
+void iov_copy_all (struct iovec *, struct iovec *, size_t);
+
+int ospf6_serv_sock ();
+int ospf6_join_allspfrouters (u_int);
+void ospf6_leave_allspfrouters (u_int);
+void ospf6_join_alldrouters (u_int);
+void ospf6_leave_alldrouters (u_int);
+void ospf6_set_reuseaddr ();
+void ospf6_reset_mcastloop ();
+void ospf6_set_pktinfo ();
+void ospf6_set_checksum ();
+
+void ospf6_sendmsg (struct in6_addr *, struct in6_addr *,
+ unsigned int *, struct iovec *);
+void ospf6_recvmsg (struct in6_addr *, struct in6_addr *,
+ unsigned int *, struct iovec *);
+void ospf6_recvmsg_peek (struct in6_addr *, struct in6_addr *,
+ unsigned int *, struct iovec *);
+
+#endif /* OSPF6_NETWORK_H */
+
diff --git a/ospf6d/ospf6_nsm.c b/ospf6d/ospf6_nsm.c
new file mode 100644
index 00000000..aa08d40b
--- /dev/null
+++ b/ospf6d/ospf6_nsm.c
@@ -0,0 +1,391 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "ospf6d.h"
+
+static int
+nbs_full_change (struct ospf6_interface *ospf6_interface)
+{
+ CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, ospf6_interface);
+ return 0;
+}
+
+static int
+nbs_change (state_t nbs_next, char *reason, struct ospf6_neighbor *o6n)
+{
+ state_t nbs_previous;
+
+ nbs_previous = o6n->state;
+ o6n->state = nbs_next;
+
+ if (nbs_previous == nbs_next)
+ return 0;
+
+ /* statistics */
+ o6n->ospf6_stat_state_changed++;
+ gettimeofday (&o6n->last_changed, NULL);
+
+ /* log */
+ if (IS_OSPF6_DUMP_NEIGHBOR)
+ {
+ if (reason)
+ zlog_info ("Neighbor status change %s: [%s]->[%s](%s)",
+ o6n->str,
+ ospf6_neighbor_state_string[nbs_previous],
+ ospf6_neighbor_state_string[nbs_next],
+ reason);
+ else
+ zlog_info ("Neighbor status change %s: [%s]->[%s]",
+ o6n->str,
+ ospf6_neighbor_state_string[nbs_previous],
+ ospf6_neighbor_state_string[nbs_next]);
+ }
+
+ if (nbs_previous == NBS_FULL || nbs_next == NBS_FULL)
+ nbs_full_change (o6n->ospf6_interface);
+
+ /* check for LSAs that already reached MaxAge */
+ if ((nbs_previous == NBS_EXCHANGE || nbs_previous == NBS_LOADING) &&
+ (nbs_next != NBS_EXCHANGE && nbs_next != NBS_LOADING))
+ {
+ ospf6_maxage_remover ();
+ }
+
+ CALL_CHANGE_HOOK (&neighbor_hook, o6n);
+
+ return 0;
+}
+
+/* RFC2328 section 10.4 */
+int
+need_adjacency (struct ospf6_neighbor *o6n)
+{
+
+ if (o6n->ospf6_interface->state == IFS_PTOP)
+ return 1;
+ if (o6n->ospf6_interface->state == IFS_DR)
+ return 1;
+ if (o6n->ospf6_interface->state == IFS_BDR)
+ return 1;
+ if (o6n->router_id == o6n->ospf6_interface->dr)
+ return 1;
+ if (o6n->router_id == o6n->ospf6_interface->bdr)
+ return 1;
+
+ return 0;
+}
+
+int
+hello_received (struct thread *thread)
+{
+ struct ospf6_neighbor *o6n;
+
+ o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+ assert (o6n);
+
+ if (IS_OSPF6_DUMP_NEIGHBOR)
+ zlog_info ("Neighbor Event %s: *HelloReceived*", o6n->str);
+
+ if (o6n->inactivity_timer)
+ thread_cancel (o6n->inactivity_timer);
+
+ o6n->inactivity_timer = thread_add_timer (master, inactivity_timer, o6n,
+ o6n->ospf6_interface->dead_interval);
+ if (o6n->state <= NBS_DOWN)
+ nbs_change (NBS_INIT, "HelloReceived", o6n);
+ return 0;
+}
+
+int
+twoway_received (struct thread *thread)
+{
+ struct ospf6_neighbor *o6n;
+
+ o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+ assert (o6n);
+
+ if (o6n->state > NBS_INIT)
+ return 0;
+
+ if (IS_OSPF6_DUMP_NEIGHBOR)
+ zlog_info ("Neighbor Event %s: *2Way-Received*", o6n->str);
+
+ thread_add_event (master, neighbor_change, o6n->ospf6_interface, 0);
+
+ if (!need_adjacency (o6n))
+ {
+ nbs_change (NBS_TWOWAY, "No Need Adjacency", o6n);
+ return 0;
+ }
+ else
+ nbs_change (NBS_EXSTART, "Need Adjacency", o6n);
+
+ DD_MSBIT_SET (o6n->dbdesc_bits);
+ DD_MBIT_SET (o6n->dbdesc_bits);
+ DD_IBIT_SET (o6n->dbdesc_bits);
+
+ if (o6n->thread_send_dbdesc)
+ thread_cancel (o6n->thread_send_dbdesc);
+ o6n->thread_send_dbdesc =
+ thread_add_event (master, ospf6_send_dbdesc, o6n, 0);
+ if (o6n->thread_rxmt_dbdesc)
+ thread_cancel (o6n->thread_rxmt_dbdesc);
+ o6n->thread_rxmt_dbdesc = (struct thread *) NULL;
+
+ return 0;
+}
+
+int
+negotiation_done (struct thread *thread)
+{
+ struct ospf6_neighbor *o6n;
+
+ o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+ assert (o6n);
+
+ if (o6n->state != NBS_EXSTART)
+ return 0;
+
+ if (IS_OSPF6_DUMP_NEIGHBOR)
+ zlog_info ("Neighbor Event %s: *NegotiationDone*", o6n->str);
+
+ nbs_change (NBS_EXCHANGE, "NegotiationDone", o6n);
+ DD_IBIT_CLEAR (o6n->dbdesc_bits);
+
+ return 0;
+}
+
+int
+exchange_done (struct thread *thread)
+{
+ struct ospf6_neighbor *o6n;
+
+ o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+ assert (o6n);
+
+ if (o6n->state != NBS_EXCHANGE)
+ return 0;
+
+ if (o6n->thread_rxmt_dbdesc)
+ thread_cancel (o6n->thread_rxmt_dbdesc);
+ o6n->thread_rxmt_dbdesc = (struct thread *) NULL;
+
+ if (IS_OSPF6_DUMP_NEIGHBOR)
+ zlog_info ("Neighbor Event %s: *ExchangeDone*", o6n->str);
+
+ ospf6_lsdb_remove_all (o6n->dbdesc_list);
+
+ thread_add_timer (master, ospf6_neighbor_last_dbdesc_release, o6n,
+ o6n->ospf6_interface->dead_interval);
+
+ if (o6n->request_list->count == 0)
+ nbs_change (NBS_FULL, "Requestlist Empty", o6n);
+ else
+ {
+ thread_add_event (master, ospf6_send_lsreq, o6n, 0);
+ nbs_change (NBS_LOADING, "Requestlist Not Empty", o6n);
+ }
+ return 0;
+}
+
+int
+loading_done (struct thread *thread)
+{
+ struct ospf6_neighbor *o6n;
+
+ o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+ assert (o6n);
+
+ if (o6n->state != NBS_LOADING)
+ return 0;
+
+ if (IS_OSPF6_DUMP_NEIGHBOR)
+ zlog_info ("Neighbor Event %s: *LoadingDone*", o6n->str);
+
+ assert (o6n->request_list->count == 0);
+
+ nbs_change (NBS_FULL, "LoadingDone", o6n);
+
+ return 0;
+}
+
+int
+adj_ok (struct thread *thread)
+{
+ struct ospf6_neighbor *o6n;
+
+ o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+ assert (o6n);
+
+ if (IS_OSPF6_DUMP_NEIGHBOR)
+ zlog_info ("Neighbor Event %s: *AdjOK?*", o6n->str);
+
+ if (o6n->state == NBS_TWOWAY)
+ {
+ if (!need_adjacency (o6n))
+ {
+ nbs_change (NBS_TWOWAY, "No Need Adjacency", o6n);
+ return 0;
+ }
+ else
+ nbs_change (NBS_EXSTART, "Need Adjacency", o6n);
+
+ DD_MSBIT_SET (o6n->dbdesc_bits);
+ DD_MBIT_SET (o6n->dbdesc_bits);
+ DD_IBIT_SET (o6n->dbdesc_bits);
+
+ if (o6n->thread_send_dbdesc)
+ thread_cancel (o6n->thread_send_dbdesc);
+ o6n->thread_send_dbdesc =
+ thread_add_event (master, ospf6_send_dbdesc, o6n, 0);
+
+ return 0;
+ }
+
+ if (o6n->state >= NBS_EXSTART)
+ {
+ if (need_adjacency (o6n))
+ return 0;
+ else
+ {
+ nbs_change (NBS_TWOWAY, "No Need Adjacency", o6n);
+ ospf6_neighbor_lslist_clear (o6n);
+ }
+ }
+ return 0;
+}
+
+int
+seqnumber_mismatch (struct thread *thread)
+{
+ struct ospf6_neighbor *o6n;
+
+ o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+ assert (o6n);
+
+ if (o6n->state < NBS_EXCHANGE)
+ return 0;
+
+ /* statistics */
+ o6n->ospf6_stat_seqnum_mismatch++;
+
+ if (IS_OSPF6_DUMP_NEIGHBOR)
+ zlog_info ("Neighbor Event %s: *SeqNumberMismatch*", o6n->str);
+
+ nbs_change (NBS_EXSTART, "SeqNumberMismatch", o6n);
+
+ DD_MSBIT_SET (o6n->dbdesc_bits);
+ DD_MBIT_SET (o6n->dbdesc_bits);
+ DD_IBIT_SET (o6n->dbdesc_bits);
+ ospf6_neighbor_lslist_clear (o6n);
+
+ if (o6n->thread_send_dbdesc)
+ thread_cancel (o6n->thread_send_dbdesc);
+ o6n->thread_send_dbdesc =
+ thread_add_event (master, ospf6_send_dbdesc, o6n, 0);
+
+ return 0;
+}
+
+int
+bad_lsreq (struct thread *thread)
+{
+ struct ospf6_neighbor *o6n;
+
+ o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+ assert (o6n);
+
+ if (o6n->state < NBS_EXCHANGE)
+ return 0;
+
+ /* statistics */
+ o6n->ospf6_stat_bad_lsreq++;
+
+ if (IS_OSPF6_DUMP_NEIGHBOR)
+ zlog_info ("Neighbor Event %s: *BadLSReq*", o6n->str);
+
+ nbs_change (NBS_EXSTART, "BadLSReq", o6n);
+
+ DD_MSBIT_SET (o6n->dbdesc_bits);
+ DD_MBIT_SET (o6n->dbdesc_bits);
+ DD_IBIT_SET (o6n->dbdesc_bits);
+ ospf6_neighbor_lslist_clear (o6n);
+
+ if (o6n->thread_send_dbdesc)
+ thread_cancel (o6n->thread_send_dbdesc);
+ o6n->thread_send_dbdesc =
+ thread_add_event (master, ospf6_send_dbdesc, o6n, 0);
+
+ return 0;
+}
+
+int
+oneway_received (struct thread *thread)
+{
+ struct ospf6_neighbor *o6n;
+
+ o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+ assert (o6n);
+
+ if (o6n->state < NBS_TWOWAY)
+ return 0;
+
+ /* statistics */
+ o6n->ospf6_stat_oneway_received++;
+
+ if (IS_OSPF6_DUMP_NEIGHBOR)
+ zlog_info ("Neighbor Event %s: *1Way-Received*", o6n->str);
+
+ nbs_change (NBS_INIT, "1Way-Received", o6n);
+
+ thread_add_event (master, neighbor_change, o6n->ospf6_interface, 0);
+
+ ospf6_neighbor_thread_cancel_all (o6n);
+ ospf6_neighbor_lslist_clear (o6n);
+ return 0;
+}
+
+int
+inactivity_timer (struct thread *thread)
+{
+ struct ospf6_neighbor *o6n;
+
+ o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+ assert (o6n);
+
+ /* statistics */
+ o6n->ospf6_stat_inactivity_timer++;
+
+ if (IS_OSPF6_DUMP_NEIGHBOR)
+ zlog_info ("Neighbor Event %s: *InactivityTimer*", o6n->str);
+
+ o6n->inactivity_timer = NULL;
+ o6n->dr = o6n->bdr = o6n->prevdr = o6n->prevbdr = 0;
+ nbs_change (NBS_DOWN, "InactivityTimer", o6n);
+
+ thread_add_event (master, neighbor_change, o6n->ospf6_interface, 0);
+
+ listnode_delete (o6n->ospf6_interface->neighbor_list, o6n);
+ ospf6_neighbor_delete (o6n);
+
+ return 0;
+}
+
diff --git a/ospf6d/ospf6_nsm.h b/ospf6d/ospf6_nsm.h
new file mode 100644
index 00000000..d70f1e88
--- /dev/null
+++ b/ospf6d/ospf6_nsm.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef OSPF6_NSM_H
+#define OSPF6_NSM_H
+
+/* Neighbor state */
+#define NBS_DOWN 1
+#define OSPF6_NEIGHBOR_STATE_DOWN 1
+#define NBS_ATTEMPT 2
+#define OSPF6_NEIGHBOR_STATE_ATTEMPT 2
+#define NBS_INIT 3
+#define OSPF6_NEIGHBOR_STATE_INIT 3
+#define NBS_TWOWAY 4
+#define OSPF6_NEIGHBOR_STATE_TWOWAY 4
+#define NBS_EXSTART 5
+#define OSPF6_NEIGHBOR_STATE_EXSTART 5
+#define NBS_EXCHANGE 6
+#define OSPF6_NEIGHBOR_STATE_EXCHANGE 6
+#define NBS_LOADING 7
+#define OSPF6_NEIGHBOR_STATE_LOADING 7
+#define NBS_FULL 8
+#define OSPF6_NEIGHBOR_STATE_FULL 8
+
+
+
+/* Function Prototypes */
+
+#include "ospf6_types.h"
+
+int need_adjacency (struct ospf6_neighbor *);
+
+
+/* Neighbor event */
+int hello_received (struct thread *);
+int twoway_received (struct thread *);
+int negotiation_done (struct thread *);
+int exchange_done (struct thread *);
+int loading_done (struct thread *);
+int adj_ok (struct thread *);
+int seqnumber_mismatch (struct thread *);
+int bad_lsreq (struct thread *);
+int oneway_received (struct thread *);
+int inactivity_timer (struct thread *);
+
+int dr_election (struct ospf6_interface *);
+
+#endif /* OSPF6_NSM_H */
+
diff --git a/ospf6d/ospf6_prefix.c b/ospf6d/ospf6_prefix.c
new file mode 100644
index 00000000..1542200c
--- /dev/null
+++ b/ospf6d/ospf6_prefix.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if 0
+
+#include <zebra.h>
+
+#include "log.h"
+#include "prefix.h"
+#include "memory.h"
+#include "linklist.h"
+
+#include "ospf6_prefix.h"
+
+#else /*0*/
+
+#include "ospf6d.h"
+
+#endif /*0*/
+
+struct ospf6_prefix *
+ospf6_prefix_create (u_int8_t options, u_int16_t metric, struct prefix_ipv6 *p)
+{
+ struct prefix_ipv6 prefix;
+ struct ospf6_prefix *o6p;
+ size_t size;
+
+ /* copy prefix and apply mask */
+ prefix_copy ((struct prefix *) &prefix, (struct prefix *) p);
+ apply_mask_ipv6 (&prefix);
+
+ size = OSPF6_PREFIX_SPACE (prefix.prefixlen) + sizeof (struct ospf6_prefix);
+ o6p = (struct ospf6_prefix *) XMALLOC (MTYPE_OSPF6_PREFIX, size);
+ if (! o6p)
+ zlog_warn ("Can't allocate memory for ospf6 prefix: size: %d", size);
+ else
+ memset (o6p, 0, size);
+
+ o6p->prefix_length = prefix.prefixlen;
+ o6p->prefix_options = options;
+ o6p->prefix_metric = htons (metric);
+ memcpy (o6p + 1, &prefix.prefix, OSPF6_PREFIX_SPACE (prefix.prefixlen));
+
+ return o6p;
+}
+
+void
+ospf6_prefix_delete (struct ospf6_prefix *p)
+{
+ XFREE (MTYPE_OSPF6_PREFIX, p);
+}
+
+int
+ospf6_prefix_issame (struct ospf6_prefix *p1, struct ospf6_prefix *p2)
+{
+ if (p1->prefix_length != p2->prefix_length)
+ return 0;
+ if (memcmp (&p1->u, &p2->u, sizeof (p1->u)))
+ return 0;
+ if (memcmp (p1 + 1, p2 + 1, OSPF6_PREFIX_SPACE (p1->prefix_length)))
+ return 0;
+ return 1;
+}
+
+struct ospf6_prefix *
+ospf6_prefix_lookup (list l, struct ospf6_prefix *p1)
+{
+ listnode node;
+ struct ospf6_prefix *p2;
+ for (node = listhead (l); node; nextnode (node))
+ {
+ p2 = (struct ospf6_prefix *) getdata (node);
+ if (ospf6_prefix_issame (p1, p2))
+ return p2;
+ }
+ return NULL;
+}
+
+/* add a copy of given prefix to the list */
+void
+ospf6_prefix_add (list l, struct ospf6_prefix *p)
+{
+ struct ospf6_prefix *add;
+ add = (struct ospf6_prefix *) XMALLOC (MTYPE_OSPF6_PREFIX,
+ OSPF6_PREFIX_SIZE (p));
+ if (add == NULL)
+ {
+ zlog_warn ("Can't allocate memory for ospf6 prefix");
+ return;
+ }
+ else
+ memcpy (add, p, OSPF6_PREFIX_SIZE (p));
+
+ if (ospf6_prefix_lookup (l, add))
+ {
+ ospf6_prefix_delete (add);
+ return;
+ }
+ listnode_add (l, add);
+}
+
+void
+ospf6_prefix_remove (list l, struct ospf6_prefix *p)
+{
+ struct ospf6_prefix *rem;
+ rem = ospf6_prefix_lookup (l, p);
+ if (rem)
+ {
+ listnode_delete (l, rem);
+ ospf6_prefix_delete (rem);
+ }
+}
+
+void
+ospf6_prefix_in6_addr (struct ospf6_prefix *o6p, struct in6_addr *in6)
+{
+ memset (in6, 0, sizeof (struct in6_addr));
+ memcpy (in6, o6p + 1, OSPF6_PREFIX_SPACE (o6p->prefix_length));
+ return;
+}
+
+char *
+ospf6_prefix_options_str (u_int8_t opt, char *buf, size_t bufsize)
+{
+ char *p, *mc, *la, *nu;
+
+ p = (CHECK_FLAG (opt, OSPF6_PREFIX_OPTION_P) ? "P" : "-");
+ mc = (CHECK_FLAG (opt, OSPF6_PREFIX_OPTION_MC) ? "MC" : "--");
+ la = (CHECK_FLAG (opt, OSPF6_PREFIX_OPTION_LA) ? "LA" : "--");
+ nu = (CHECK_FLAG (opt, OSPF6_PREFIX_OPTION_NU) ? "NU" : "--");
+
+ snprintf (buf, bufsize, "%s|%s|%s|%s", p, mc, la, nu);
+ return buf;
+}
+
+char *
+ospf6_prefix_string (struct ospf6_prefix *prefix, char *buf, size_t size)
+{
+ struct in6_addr in6;
+ char s[64];
+
+ memset (&in6, 0, sizeof (in6));
+ memcpy (&in6, prefix + 1, OSPF6_PREFIX_SPACE (prefix->prefix_length));
+ inet_ntop (AF_INET6, &in6, s, sizeof (s));
+
+ snprintf (buf, size, "%s/%d", s, prefix->prefix_length);
+ return buf;
+}
+
+void
+ospf6_prefix_copy (struct ospf6_prefix *dst, struct ospf6_prefix *src,
+ size_t dstsize)
+{
+ size_t srcsize;
+
+ memset (dst, 0, dstsize);
+
+ srcsize = OSPF6_PREFIX_SIZE (src);
+ if (dstsize < srcsize)
+ memcpy (dst, src, dstsize);
+ else
+ memcpy (dst, src, srcsize);
+
+ return;
+}
+
+void
+ospf6_prefix_apply_mask (struct ospf6_prefix *o6p)
+{
+ u_char *pnt, mask;
+ int index, offset;
+
+ char buf[128];
+ struct in6_addr in6;
+ ospf6_prefix_in6_addr (o6p, &in6);
+ inet_ntop (AF_INET6, &in6, buf, sizeof (buf));
+
+ pnt = (u_char *)(o6p + 1);
+ index = o6p->prefix_length / 8;
+ offset = o6p->prefix_length % 8;
+ mask = 0xff << (8 - offset);
+
+ if (index >= 16)
+ return;
+
+ pnt[index] &= mask;
+ index ++;
+
+ while (index < OSPF6_PREFIX_SPACE (o6p->prefix_length))
+ pnt[index++] = 0;
+
+ ospf6_prefix_in6_addr (o6p, &in6);
+ inet_ntop (AF_INET6, &in6, buf, sizeof (buf));
+}
+
diff --git a/ospf6d/ospf6_prefix.h b/ospf6d/ospf6_prefix.h
new file mode 100644
index 00000000..65a8cbc8
--- /dev/null
+++ b/ospf6d/ospf6_prefix.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef OSPF6_PREFIX_H
+#define OSPF6_PREFIX_H
+
+#include "linklist.h"
+
+#define OSPF6_PREFIX_OPTION_NU (1 << 0) /* No Unicast */
+#define OSPF6_PREFIX_OPTION_LA (1 << 1) /* Local Address */
+#define OSPF6_PREFIX_OPTION_MC (1 << 2) /* MultiCast */
+#define OSPF6_PREFIX_OPTION_P (1 << 3) /* Propagate (NSSA) */
+
+struct ospf6_prefix
+{
+ u_int8_t prefix_length;
+ u_int8_t prefix_options;
+ union {
+ u_int16_t _prefix_metric;
+ u_int16_t _prefix_referenced_lstype;
+ } u;
+#define prefix_metric u._prefix_metric
+#define prefix_refer_lstype u._prefix_referenced_lstype
+ /* followed by one address_prefix */
+};
+
+/* size_t OSPF6_PREFIX_SPACE (int prefixlength); */
+#define OSPF6_PREFIX_SPACE(x) ((((x) + 31) / 32) * 4)
+
+/* size_t OSPF6_PREFIX_SIZE (struct ospf6_prefix *); */
+#define OSPF6_PREFIX_SIZE(x) \
+ (OSPF6_PREFIX_SPACE ((x)->prefix_length) + sizeof (struct ospf6_prefix))
+
+/* struct ospf6_prefix *OSPF6_NEXT_PREFIX (struct ospf6_prefix *); */
+#define OSPF6_NEXT_PREFIX(x) \
+ ((struct ospf6_prefix *)((char *)(x) + OSPF6_PREFIX_SIZE (x)))
+
+
+
+/* Function Prototypes */
+struct ospf6_prefix *
+ ospf6_prefix_make (u_int8_t, u_int16_t, struct prefix_ipv6 *);
+void ospf6_prefix_free (struct ospf6_prefix *);
+void ospf6_prefix_in6_addr (struct ospf6_prefix *, struct in6_addr *);
+void ospf6_prefix_copy (struct ospf6_prefix *, struct ospf6_prefix *,
+ size_t);
+
+void ospf6_prefix_apply_mask (struct ospf6_prefix *);
+int ospf6_prefix_issame (struct ospf6_prefix *, struct ospf6_prefix *);
+
+char *ospf6_prefix_options_str (u_int8_t, char *, size_t);
+char *ospf6_prefix_string (struct ospf6_prefix *, char *, size_t);
+
+struct ospf6_prefix *
+ospf6_prefix_lookup (list l, struct ospf6_prefix *prefix);
+void ospf6_prefix_add (list, struct ospf6_prefix *);
+
+struct ospf6_prefix *
+ospf6_prefix_create (u_int8_t, u_int16_t, struct prefix_ipv6 *);
+void ospf6_prefix_delete (struct ospf6_prefix *);
+
+void ospf6_prefix_init ();
+
+#endif /* OSPF6_PREFIX_H */
+
diff --git a/ospf6d/ospf6_proto.c b/ospf6d/ospf6_proto.c
new file mode 100644
index 00000000..71e575f1
--- /dev/null
+++ b/ospf6d/ospf6_proto.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "ospf6_proto.h"
+
+char *
+ospf6_options_string (u_char opt_capability[3], char *buffer, int size)
+{
+ char *dc, *r, *n, *mc, *e, *v6;
+
+ dc = (OSPF6_OPT_ISSET (opt_capability, OSPF6_OPT_DC) ? "DC" : "--");
+ r = (OSPF6_OPT_ISSET (opt_capability, OSPF6_OPT_R) ? "R" : "-");
+ n = (OSPF6_OPT_ISSET (opt_capability, OSPF6_OPT_N) ? "N" : "-");
+ mc = (OSPF6_OPT_ISSET (opt_capability, OSPF6_OPT_MC) ? "MC" : "--");
+ e = (OSPF6_OPT_ISSET (opt_capability, OSPF6_OPT_E) ? "E" : "-");
+ v6 = (OSPF6_OPT_ISSET (opt_capability, OSPF6_OPT_V6) ? "V6" : "--");
+ snprintf (buffer, size, "%s|%s|%s|%s|%s|%s", dc, r, n, mc, e, v6);
+ return buffer;
+}
+
diff --git a/ospf6d/ospf6_proto.h b/ospf6d/ospf6_proto.h
new file mode 100644
index 00000000..9a95444a
--- /dev/null
+++ b/ospf6d/ospf6_proto.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef OSPF6_PROTO_H
+#define OSPF6_PROTO_H
+
+/* OSPF protocol version */
+#define OSPF6_VERSION 3
+
+/* OSPF protocol number. */
+#ifndef IPPROTO_OSPFIGP
+#define IPPROTO_OSPFIGP 89
+#endif
+
+/* TOS field normaly null */
+#define OSPF6_TOS_VALUE 0x0
+
+/* Architectural Constants */
+#define OSPF6_LS_REFRESH_TIME 1800 /* 30 min */
+#define OSPF6_MIN_LS_INTERVAL 5
+#define OSPF6_MIN_LS_ARRIVAL 1
+#define MAXAGE 3600 /* 1 hour */
+#define CHECK_AGE 300 /* 5 min */
+#define MAX_AGE_DIFF 900 /* 15 min */
+#define LS_INFINITY 0xffffff /* 24-bit binary value */
+#define INITIAL_SEQUENCE_NUMBER 0x80000001 /* signed 32-bit integer */
+#define MAX_SEQUENCE_NUMBER 0x7fffffff /* signed 32-bit integer */
+
+#define MAXOSPFMESSAGELEN 4096
+
+#define ALLSPFROUTERS6 "ff02::5"
+#define ALLDROUTERS6 "ff02::6"
+
+/* Configurable Constants */
+
+#define DEFAULT_HELLO_INTERVAL 10
+#define DEFAULT_ROUTER_DEAD_TIMER 40
+
+/* OSPF options */
+/* present in HELLO, DD, LSA */
+#define OSPF6_OPT_SET(x,opt) ((x)[2] |= (opt))
+#define OSPF6_OPT_ISSET(x,opt) ((x)[2] & (opt))
+#define OSPF6_OPT_CLEAR(x,opt) ((x)[2] &= ~(opt))
+#define OSPF6_OPT_CLEAR_ALL(x) ((x)[0] = (x)[1] = (x)[2] = 0)
+
+#define OSPF6_OPT_V6 (1 << 0) /* IPv6 forwarding Capability */
+#define OSPF6_OPT_E (1 << 1) /* AS External Capability */
+#define OSPF6_OPT_MC (1 << 2) /* Multicasting Capability */
+#define OSPF6_OPT_N (1 << 3) /* Handling Type-7 LSA Capability */
+#define OSPF6_OPT_R (1 << 4) /* Forwarding Capability (Any Protocol) */
+#define OSPF6_OPT_DC (1 << 5) /* Demand Circuit handling Capability */
+
+char *
+ospf6_options_string (u_char opt_capability[3], char *buffer, int size);
+
+#endif /* OSPF6_PROTO_H */
+
diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c
new file mode 100644
index 00000000..c35efa6e
--- /dev/null
+++ b/ospf6d/ospf6_route.c
@@ -0,0 +1,1130 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "ospf6d.h"
+
+char *
+dtype_name[OSPF6_DEST_TYPE_MAX] =
+{
+ "Unknown", "Router", "Network", "Discard"
+};
+#define DTYPE_NAME(x) \
+ (0 < (x) && (x) < sizeof (dtype_name) ? \
+ dtype_name[(x)] : dtype_name[0])
+
+char *
+dtype_abname[OSPF6_DEST_TYPE_MAX] =
+{
+ "?", "R", "N", "D"
+};
+#define DTYPE_ABNAME(x) \
+ (0 < (x) && (x) < sizeof (dtype_abname) ? \
+ dtype_abname[(x)] : dtype_abname[0])
+
+char *
+ptype_name[OSPF6_PATH_TYPE_MAX] =
+{
+ "Unknown", "Intra", "Inter", "External-1", "External-2",
+ "System", "Kernel", "Connect", "Static", "RIP", "RIPng",
+ "OSPF", "OSPF6", "BGP"
+};
+#define PTYPE_NAME(x) \
+ (0 < (x) && (x) < sizeof (ptype_name) ? \
+ ptype_name[(x)] : ptype_name[0])
+
+char *
+ptype_abname[OSPF6_PATH_TYPE_MAX] =
+{
+ "??", "Ia", "Ie", "E1", "E2",
+ "-X", "-K", "-C", "-S", "-R", "-R",
+ "-O", "-O", "-B"
+};
+#define PTYPE_ABNAME(x) \
+ (0 < (x) && (x) < sizeof (ptype_abname) ? \
+ ptype_abname[(x)] : ptype_abname[0])
+
+
+
+int
+ospf6_path_cmp (void *arg1, void *arg2)
+{
+ struct ospf6_path_node *pn1 = arg1;
+ struct ospf6_path_node *pn2 = arg2;
+ struct ospf6_path *p1 = &pn1->path;
+ struct ospf6_path *p2 = &pn2->path;
+
+ if (p1->type < p2->type)
+ return -1;
+ else if (p1->type > p2->type)
+ return 1;
+
+ if (p1->type == OSPF6_PATH_TYPE_EXTERNAL2)
+ {
+ if (p1->cost_e2 < p2->cost_e2)
+ return -1;
+ else if (p1->cost_e2 > p2->cost_e2)
+ return 1;
+ }
+
+ if (p1->cost < p2->cost)
+ return -1;
+ else if (p1->cost > p2->cost)
+ return 1;
+
+ /* if from the same source, recognize as identical
+ (and treat this as update) */
+ if (! memcmp (&p1->origin, &p2->origin, sizeof (struct ls_origin)) &&
+ p1->area_id == p2->area_id)
+ return 0;
+
+ /* else, always prefer left */
+ return -1;
+}
+
+int
+ospf6_nexthop_cmp (void *arg1, void *arg2)
+{
+ int i, ret = 0;
+ struct ospf6_nexthop_node *nn1 = arg1;
+ struct ospf6_nexthop_node *nn2 = arg2;
+ struct ospf6_nexthop *n1 = &nn1->nexthop;
+ struct ospf6_nexthop *n2 = &nn2->nexthop;
+
+ if (memcmp (n1, n2, sizeof (struct ospf6_nexthop)) == 0)
+ return 0;
+
+ for (i = 0; i < sizeof (struct in6_addr); i++)
+ {
+ if (nn1->nexthop.address.s6_addr[i] != nn2->nexthop.address.s6_addr[i])
+ {
+ ret = nn1->nexthop.address.s6_addr[i] -
+ nn2->nexthop.address.s6_addr[i];
+ break;
+ }
+ }
+
+ if (ret == 0)
+ ret = -1;
+
+ return ret;
+}
+
+static void
+ospf6_route_request (struct ospf6_route_req *request,
+ struct ospf6_route_node *rn,
+ struct ospf6_path_node *pn,
+ struct ospf6_nexthop_node *nn)
+{
+ assert (request);
+ assert (rn && pn && nn);
+
+ request->route_node = rn->route_node;
+
+ linklist_head (rn->path_list, &request->path_lnode);
+ while (request->path_lnode.data != pn)
+ {
+ //assert (! linklist_end (&request->path_lnode));
+ if (linklist_end (&request->path_lnode))
+ {
+ struct linklist_node node;
+
+ zlog_info ("rn: %p, pn: %p", rn, pn);
+ zlog_info ("origin: %hx %x %x bits: %x opt: %x%x%x popt: %x area: %x type: %d cost %d %d %d",
+ pn->path.origin.type, pn->path.origin.id, pn->path.origin.adv_router, (int)pn->path.router_bits, (int)pn->path.capability[0],
+ (int)pn->path.capability[1], (int)pn->path.capability[2],
+ (int)pn->path.prefix_options, pn->path.area_id,
+ pn->path.type, pn->path.metric_type, pn->path.cost, pn->path.cost_e2);
+
+ for (linklist_head (rn->path_list, &node); ! linklist_end (&node);
+ linklist_next (&node))
+ {
+ struct ospf6_path_node *pn2 = node.data;
+
+ zlog_info (" %p: path data with pn(%p): %s", pn2, pn,
+ (memcmp (&pn->path, &pn2->path,
+ sizeof (struct ospf6_path)) ?
+ "different" : "same"));
+
+ zlog_info (" origin: %hx %x %x bits: %x opt: %x%x%x popt: %x area: %x type: %d cost %d %d %d",
+ pn2->path.origin.type, pn2->path.origin.id, pn2->path.origin.adv_router, (int)pn2->path.router_bits, (int)pn2->path.capability[0],
+ (int)pn2->path.capability[1], (int)pn2->path.capability[2],
+ (int)pn2->path.prefix_options, pn2->path.area_id,
+ pn2->path.type, pn2->path.metric_type, pn2->path.cost, pn2->path.cost_e2);
+
+ if (! memcmp (&pn->path, &pn2->path, sizeof (struct ospf6_path)))
+ {
+ pn = pn2;
+ request->nexthop_lnode.data = pn2;
+ }
+ }
+ break;
+ }
+ linklist_next (&request->path_lnode);
+ }
+ assert (request->path_lnode.data == pn);
+
+ linklist_head (pn->nexthop_list, &request->nexthop_lnode);
+ while (request->nexthop_lnode.data != nn)
+ {
+ assert (! linklist_end (&request->nexthop_lnode));
+ linklist_next (&request->nexthop_lnode);
+ }
+ assert (request->nexthop_lnode.data == nn);
+
+ request->table = rn->table;
+ request->count = rn->count;
+ request->route_id = rn->route_id;
+ memcpy (&request->route, &rn->route, sizeof (struct ospf6_route));
+ memcpy (&request->path, &pn->path, sizeof (struct ospf6_path));
+ memcpy (&request->nexthop, &nn->nexthop, sizeof (struct ospf6_nexthop));
+}
+
+int
+ospf6_route_count (struct ospf6_route_req *request)
+{
+ return request->count;
+}
+
+int
+ospf6_route_lookup (struct ospf6_route_req *request,
+ struct prefix *prefix,
+ struct ospf6_route_table *table)
+{
+ struct route_node *node;
+ struct ospf6_route_node *rn = NULL;
+ struct ospf6_path_node *pn = NULL;
+ struct ospf6_nexthop_node *nn = NULL;
+ struct linklist_node lnode;
+
+ if (request)
+ memset ((void *) request, 0, sizeof (struct ospf6_route_req));
+
+ node = route_node_lookup (table->table, prefix);
+ if (! node)
+ return 0;
+
+ rn = (struct ospf6_route_node *) node->info;
+ if (! rn)
+ return 0;
+
+ if (request)
+ {
+ linklist_head (rn->path_list, &lnode);
+ pn = lnode.data;
+ linklist_head (pn->nexthop_list, &lnode);
+ nn = lnode.data;
+
+ ospf6_route_request (request, rn, pn, nn);
+ }
+
+ return 1;
+}
+
+void
+ospf6_route_head (struct ospf6_route_req *request,
+ struct ospf6_route_table *table)
+{
+ struct route_node *node;
+ struct ospf6_route_node *rn = NULL;
+ struct ospf6_path_node *pn = NULL;
+ struct ospf6_nexthop_node *nn = NULL;
+ struct linklist_node lnode;
+
+ if (request)
+ memset (request, 0, sizeof (struct ospf6_route_req));
+
+ node = route_top (table->table);
+ if (! node)
+ return;
+
+ while (node && node->info == NULL)
+ node = route_next (node);
+ if (! node)
+ return;
+
+ rn = (struct ospf6_route_node *) node->info;
+ linklist_head (rn->path_list, &lnode);
+ pn = lnode.data;
+ linklist_head (pn->nexthop_list, &lnode);
+ nn = lnode.data;
+
+ ospf6_route_request (request, rn, pn, nn);
+}
+
+int
+ospf6_route_end (struct ospf6_route_req *request)
+{
+ if (request->route_node == NULL &&
+ linklist_end (&request->path_lnode) &&
+ linklist_end (&request->nexthop_lnode) &&
+ request->nexthop.ifindex == 0 &&
+ IN6_IS_ADDR_UNSPECIFIED (&request->nexthop.address))
+ return 1;
+ return 0;
+}
+
+void
+ospf6_route_next (struct ospf6_route_req *request)
+{
+ struct ospf6_route_node *route_node = NULL;
+ struct ospf6_path_node *path_node = NULL;
+ struct ospf6_nexthop_node *nexthop_node = NULL;
+
+ linklist_next (&request->nexthop_lnode);
+ if (linklist_end (&request->nexthop_lnode))
+ {
+ linklist_next (&request->path_lnode);
+ if (linklist_end (&request->path_lnode))
+ {
+ request->route_node = route_next (request->route_node);
+ while (request->route_node && request->route_node->info == NULL)
+ request->route_node = route_next (request->route_node);
+ if (request->route_node)
+ {
+ route_node = request->route_node->info;
+ if (route_node)
+ linklist_head (route_node->path_list, &request->path_lnode);
+ }
+ }
+
+ path_node = request->path_lnode.data;
+ if (path_node)
+ linklist_head (path_node->nexthop_list, &request->nexthop_lnode);
+ }
+
+ nexthop_node = request->nexthop_lnode.data;
+
+ if (nexthop_node == NULL)
+ {
+ assert (path_node == NULL);
+ assert (route_node == NULL);
+
+ memset (&request->route, 0, sizeof (struct ospf6_route));
+ memset (&request->path, 0, sizeof (struct ospf6_path));
+ memset (&request->nexthop, 0, sizeof (struct ospf6_nexthop));
+ }
+ else
+ {
+ path_node = request->path_lnode.data;
+ route_node = request->route_node->info;
+
+ assert (path_node != NULL);
+ assert (route_node != NULL);
+
+ memcpy (&request->route, &route_node->route,
+ sizeof (struct ospf6_route));
+ memcpy (&request->path, &path_node->path,
+ sizeof (struct ospf6_path));
+ memcpy (&request->nexthop, &nexthop_node->nexthop,
+ sizeof (struct ospf6_nexthop));
+ }
+}
+
+#define ADD 0
+#define CHANGE 1
+#define REMOVE 2
+
+void
+ospf6_route_hook_call (int type,
+ struct ospf6_route_req *request,
+ struct ospf6_route_table *table)
+{
+ struct linklist_node node;
+ void (*func) (struct ospf6_route_req *);
+
+ for (linklist_head (table->hook_list[type], &node);
+ ! linklist_end (&node);
+ linklist_next (&node))
+ {
+ func = node.data;
+ (*func) (request);
+ }
+}
+
+void
+ospf6_route_hook_register (void (*add) (struct ospf6_route_req *),
+ void (*change) (struct ospf6_route_req *),
+ void (*remove) (struct ospf6_route_req *),
+ struct ospf6_route_table *table)
+{
+ linklist_add (add, table->hook_list[ADD]);
+ linklist_add (change, table->hook_list[CHANGE]);
+ linklist_add (remove, table->hook_list[REMOVE]);
+}
+
+void
+ospf6_route_hook_unregister (void (*add) (struct ospf6_route_req *),
+ void (*change) (struct ospf6_route_req *),
+ void (*remove) (struct ospf6_route_req *),
+ struct ospf6_route_table *table)
+{
+ linklist_remove (add, table->hook_list[ADD]);
+ linklist_remove (change, table->hook_list[CHANGE]);
+ linklist_remove (remove, table->hook_list[REMOVE]);
+}
+
+
+int
+prefix_ls2str (struct prefix *p, char *str, int size)
+{
+ char id[BUFSIZ], adv_router[BUFSIZ];
+ struct prefix_ls *pl = (struct prefix_ls *) p;
+
+ inet_ntop (AF_INET, &pl->id, id, BUFSIZ);
+ inet_ntop (AF_INET, &pl->adv_router, adv_router, BUFSIZ);
+ snprintf (str, size, "%s-%s", adv_router, id);
+ return 0;
+}
+
+void
+ospf6_route_log_request (char *what, char *where,
+ struct ospf6_route_req *request)
+{
+ char prefix[64];
+ char area_id[16];
+ char type[16], id[16], adv[16];
+ char address[64], ifname[IFNAMSIZ];
+
+ if (request->route.prefix.family != AF_INET &&
+ request->route.prefix.family != AF_INET6)
+ prefix_ls2str (&request->route.prefix, prefix, sizeof (prefix));
+ else
+ prefix2str (&request->route.prefix, prefix, sizeof (prefix));
+
+ inet_ntop (AF_INET, &request->path.area_id, area_id, sizeof (area_id));
+
+ ospf6_lsa_type_string (request->path.origin.type, type, sizeof (type));
+ inet_ntop (AF_INET, &request->path.origin.id, id, sizeof (id));
+ inet_ntop (AF_INET, &request->path.origin.adv_router, adv, sizeof (adv));
+
+ inet_ntop (AF_INET6, &request->nexthop.address, address, sizeof (address));
+
+ zlog_info ("ROUTE: %s %s %s %s %s",
+ what, DTYPE_ABNAME (request->route.type), prefix,
+ ((strcmp ("Add", what) == 0) ? "to" : "from"), where);
+ zlog_info ("ROUTE: Area: %s type: %s cost: %lu (E2: %lu)",
+ area_id, PTYPE_NAME (request->path.type),
+ (u_long) request->path.cost, (u_long) request->path.cost_e2);
+ zlog_info ("ROUTE: Origin: Type: %s", type);
+ zlog_info ("ROUTE: Origin: Id: %s Adv: %s", id, adv);
+ zlog_info ("ROUTE: Nexthop: %s", address);
+ zlog_info ("ROUTE: Nexthop: Ifindex: %u (%s)",
+ request->nexthop.ifindex,
+ if_indextoname (request->nexthop.ifindex, ifname));
+}
+
+struct ospf6_path_node *
+ospf6_route_find_path_node (struct ospf6_route_req *request,
+ struct ospf6_route_node *rn)
+{
+ struct linklist_node node;
+
+ for (linklist_head (rn->path_list, &node); ! linklist_end (&node);
+ linklist_next (&node))
+ {
+ struct ospf6_path_node *path_node = node.data;
+
+ if (path_node->path.area_id == request->path.area_id &&
+ path_node->path.origin.type == request->path.origin.type &&
+ path_node->path.origin.id == request->path.origin.id &&
+ path_node->path.origin.adv_router == request->path.origin.adv_router)
+ return path_node;
+ }
+
+#if 0
+ zlog_info ("req path : area: %#x origin: type: %d, id: %d, adv_router: %#x",
+ request->path.area_id, request->path.origin.type,
+ request->path.origin.id, request->path.origin.adv_router);
+ for (linklist_head (rn->path_list, &node); ! linklist_end (&node);
+ linklist_next (&node))
+ {
+ struct ospf6_path_node *path_node = node.data;
+ zlog_info (" path : area: %#x origin: type: %d, id: %d, adv_router: %#x",
+ path_node->path.area_id, path_node->path.origin.type,
+ path_node->path.origin.id, path_node->path.origin.adv_router);
+ }
+#endif
+
+ return NULL;
+}
+
+struct ospf6_nexthop_node *
+ospf6_route_find_nexthop_node (struct ospf6_route_req *request,
+ struct ospf6_path_node *pn)
+{
+ struct linklist_node node;
+ for (linklist_head (pn->nexthop_list, &node); ! linklist_end (&node);
+ linklist_next (&node))
+ {
+ struct ospf6_nexthop_node *nexthop_node = node.data;
+
+ if (! memcmp (&nexthop_node->nexthop, &request->nexthop,
+ sizeof (struct ospf6_nexthop)))
+ return nexthop_node;
+ }
+ return NULL;
+}
+
+void
+ospf6_route_add (struct ospf6_route_req *request,
+ struct ospf6_route_table *table)
+{
+ struct ospf6_route_node *rn;
+ struct ospf6_path_node *pn;
+ struct ospf6_nexthop_node *nn;
+ struct route_node *route_node;
+
+ struct ospf6_route_req route;
+
+ int route_change = 0;
+ int path_change = 0;
+ int nexthop_change = 0;
+
+ /* find the requested route */
+ route_node = route_node_get (table->table, &request->route.prefix);
+ rn = (struct ospf6_route_node *) route_node->info;
+
+ if (rn)
+ {
+ if (memcmp (&rn->route, &request->route, sizeof (struct ospf6_route)))
+ {
+ memcpy (&rn->route, &request->route, sizeof (struct ospf6_route));
+ route_change++;
+ }
+ }
+ else
+ {
+ rn = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_route_node));
+ rn->table = table;
+ rn->route_node = route_node;
+ rn->route_id = table->route_id++;
+ rn->path_list = linklist_create ();
+ rn->path_list->cmp = ospf6_path_cmp;
+ memcpy (&rn->route, &request->route, sizeof (struct ospf6_route));
+ route_node->info = rn;
+ }
+
+ /* find the same path */
+ pn = ospf6_route_find_path_node (request, rn);
+
+ if (pn)
+ {
+ if (memcmp (&pn->path, &request->path, sizeof (struct ospf6_path)))
+ {
+ memcpy (&pn->path, &request->path, sizeof (struct ospf6_path));
+ path_change++;
+ }
+ }
+ else
+ {
+ pn = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_path_node));
+ pn->route_node = rn;
+ pn->nexthop_list = linklist_create ();
+ pn->nexthop_list->cmp = ospf6_nexthop_cmp;
+ memcpy (&pn->path, &request->path, sizeof (struct ospf6_path));
+ linklist_add (pn, rn->path_list);
+ }
+
+ /* find the same nexthop */
+ nn = ospf6_route_find_nexthop_node (request, pn);
+
+ if (nn)
+ {
+ if (memcmp (&nn->nexthop, &request->nexthop,
+ sizeof (struct ospf6_nexthop)))
+ {
+ memcpy (&nn->nexthop, &request->nexthop,
+ sizeof (struct ospf6_nexthop));
+ nexthop_change++;
+ gettimeofday (&nn->installed, (struct timezone *) NULL);
+ }
+ }
+ else
+ {
+ nn = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_nexthop_node));
+ nn->path_node = pn;
+ memcpy (&nn->nexthop, &request->nexthop, sizeof (struct ospf6_nexthop));
+ linklist_add (nn, pn->nexthop_list);
+ rn->count++;
+ gettimeofday (&nn->installed, (struct timezone *) NULL);
+ }
+
+ SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ADD);
+ if (route_change)
+ SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ROUTE_CHANGE);
+ if (path_change)
+ SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_PATH_CHANGE);
+ if (nexthop_change)
+ SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE);
+
+ if (table->freeze)
+ return;
+
+ if (IS_OSPF6_DUMP_ROUTE)
+ {
+ ospf6_route_log_request ("Add", table->name, request);
+
+ if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ROUTE_CHANGE))
+ zlog_info ("ROUTE: route attribute change");
+ if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_PATH_CHANGE))
+ zlog_info ("ROUTE: path attribute change");
+ if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE))
+ zlog_info ("ROUTE: nexthop attribute change");
+ }
+
+ if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ROUTE_CHANGE) ||
+ CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_PATH_CHANGE))
+ SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE);
+
+ /* Call hooks */
+ ospf6_route_request (&route, rn, pn, nn);
+ if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ADD))
+ ospf6_route_hook_call (ADD, &route, table);
+ else if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE))
+ ospf6_route_hook_call (CHANGE, &route, table);
+
+ if (table->hook_add &&
+ CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ADD))
+ (*table->hook_add) (&route);
+ else if (table->hook_change &&
+ CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE))
+ (*table->hook_change) (&route);
+
+ /* clear flag */
+ nn->flag = 0;
+}
+
+void
+ospf6_route_remove (struct ospf6_route_req *request,
+ struct ospf6_route_table *table)
+{
+ struct ospf6_route_node *rn;
+ struct ospf6_path_node *pn;
+ struct ospf6_nexthop_node *nn;
+ struct route_node *route_node;
+ struct ospf6_route_req route;
+
+ /* find the requested route */
+ route_node = route_node_get (table->table, &request->route.prefix);
+ rn = (struct ospf6_route_node *) route_node->info;
+
+ if (! rn)
+ {
+ if (IS_OSPF6_DUMP_ROUTE)
+ {
+ ospf6_route_log_request ("Remove", table->name, request);
+ zlog_info ("ROUTE: Can't remove: No such route");
+ }
+ return;
+ }
+
+ pn = ospf6_route_find_path_node (request, rn);
+ if (! pn)
+ {
+ if (IS_OSPF6_DUMP_ROUTE)
+ {
+ ospf6_route_log_request ("Remove", table->name, request);
+ zlog_info ("ROUTE: Can't remove: No such path");
+ }
+ return;
+ }
+
+ if (pn->path.area_id != request->path.area_id ||
+ pn->path.origin.type != request->path.origin.type ||
+ pn->path.origin.id != request->path.origin.id ||
+ pn->path.origin.adv_router != request->path.origin.adv_router)
+ {
+ if (IS_OSPF6_DUMP_ROUTE)
+ {
+ ospf6_route_log_request ("Remove", table->name, request);
+ zlog_info ("ROUTE: Can't remove: Path differ");
+ {
+ char *s, *e, *c;
+ char line[512], *p;
+
+ p = line;
+ s = (char *) &pn->path;
+ e = s + sizeof (struct ospf6_path);
+ for (c = s; c < e; c++)
+ {
+ if ((c - s) % 4 == 0)
+ snprintf (p++, line + sizeof (line) - p, " ");
+ snprintf (p, line + sizeof (line) - p, "%02x", *c);
+ p += 2;
+ }
+ zlog_info ("ROUTE: path: %s", line);
+
+ p = line;
+ s = (char *) &request->path;
+ e = s + sizeof (struct ospf6_path);
+ for (c = s; c < e; c++)
+ {
+ if ((c - s) % 4 == 0)
+ snprintf (p++, line + sizeof (line) - p, " ");
+ snprintf (p, line + sizeof (line) - p, "%02x", *c);
+ p += 2;
+ }
+ zlog_info ("ROUTE: req : %s", line);
+
+ }
+ }
+ return;
+ }
+
+ nn = ospf6_route_find_nexthop_node (request, pn);
+ if (! nn)
+ {
+ if (IS_OSPF6_DUMP_ROUTE)
+ {
+ ospf6_route_log_request ("Remove", table->name, request);
+ zlog_info ("ROUTE: Can't remove: No such nexthop");
+ }
+ return;
+ }
+
+ if (memcmp (&nn->nexthop, &request->nexthop, sizeof (struct ospf6_nexthop)))
+ {
+ if (IS_OSPF6_DUMP_ROUTE)
+ {
+ ospf6_route_log_request ("Remove", table->name, request);
+ zlog_info ("ROUTE: Can't remove: Nexthop differ");
+ }
+ return;
+ }
+
+ SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_REMOVE);
+
+ if (table->freeze)
+ return;
+
+ if (IS_OSPF6_DUMP_ROUTE)
+ ospf6_route_log_request ("Remove", table->name, request);
+
+ ospf6_route_request (&route, rn, pn, nn);
+ ospf6_route_hook_call (REMOVE, &route, table);
+ if (table->hook_remove)
+ (*table->hook_remove) (&route);
+
+ /* clear flag */
+ nn->flag = 0;
+
+ /* remove nexthop */
+ linklist_remove (nn, pn->nexthop_list);
+ rn->count--;
+ XFREE (MTYPE_OSPF6_ROUTE, nn);
+
+ /* remove path if there's no nexthop for the path */
+ if (pn->nexthop_list->count != 0)
+ return;
+ linklist_remove (pn, rn->path_list);
+ linklist_delete (pn->nexthop_list);
+ XFREE (MTYPE_OSPF6_ROUTE, pn);
+
+ /* remove route if there's no path for the route */
+ if (rn->path_list->count != 0)
+ return;
+ route_node->info = NULL;
+ linklist_delete (rn->path_list);
+ XFREE (MTYPE_OSPF6_ROUTE, rn);
+}
+
+void
+ospf6_route_remove_all (struct ospf6_route_table *table)
+{
+ struct ospf6_route_req request;
+
+ for (ospf6_route_head (&request, table); ! ospf6_route_end (&request);
+ ospf6_route_next (&request))
+ ospf6_route_remove (&request, table);
+}
+
+
+struct ospf6_route_table *
+ospf6_route_table_create (char *name)
+{
+ int i;
+ struct ospf6_route_table *new;
+
+ new = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_route_table));
+ snprintf (new->name, sizeof (new->name), "%s", name);
+
+ new->table = route_table_init ();
+ for (i = 0; i < 3; i++)
+ new->hook_list[i] = linklist_create ();
+
+ return new;
+}
+
+void
+ospf6_route_table_delete (struct ospf6_route_table *table)
+{
+ int i;
+
+ ospf6_route_remove_all (table);
+ route_table_finish (table->table);
+ for (i = 0; i < 3; i++)
+ linklist_delete (table->hook_list[i]);
+ XFREE (MTYPE_OSPF6_ROUTE, table);
+}
+
+void
+ospf6_route_table_freeze (struct ospf6_route_table *route_table)
+{
+ if (IS_OSPF6_DUMP_ROUTE)
+ zlog_info ("ROUTE: Table freeze: %s", route_table->name);
+ assert (route_table->freeze == 0);
+ route_table->freeze = 1;
+}
+
+void
+ospf6_route_table_thaw (struct ospf6_route_table *route_table)
+{
+ struct route_node *node;
+ struct linklist_node pnode;
+ struct linklist_node nnode;
+
+ struct ospf6_route_node *rn;
+ struct ospf6_path_node *pn;
+ struct ospf6_nexthop_node *nn;
+
+ struct ospf6_route_req request;
+
+ if (IS_OSPF6_DUMP_ROUTE)
+ zlog_info ("ROUTE: Table thaw: %s", route_table->name);
+
+ assert (route_table->freeze == 1);
+ route_table->freeze = 0;
+
+ for (node = route_top (route_table->table); node;
+ node = route_next (node))
+ {
+ rn = node->info;
+ if (! rn)
+ continue;
+
+ for (linklist_head (rn->path_list, &pnode);
+ ! linklist_end (&pnode);
+ linklist_next (&pnode))
+ {
+ pn = pnode.data;
+
+ for (linklist_head (pn->nexthop_list, &nnode);
+ ! linklist_end (&nnode);
+ linklist_next (&nnode))
+ {
+ nn = nnode.data;
+
+ /* if the add and remove flag set without change flag,
+ do nothing with this route */
+ if (! CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE) &&
+ CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ADD) &&
+ CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_REMOVE))
+ {
+ nn->flag = 0;
+ continue;
+ }
+
+ memset (&request, 0, sizeof (request));
+ memcpy (&request.route, &rn->route, sizeof (rn->route));
+ memcpy (&request.path, &pn->path, sizeof (pn->path));
+ memcpy (&request.nexthop, &nn->nexthop, sizeof (nn->nexthop));
+
+ if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ADD) ||
+ CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE))
+ ospf6_route_add (&request, route_table);
+ else if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_REMOVE))
+ ospf6_route_remove (&request, route_table);
+ }
+ }
+ }
+}
+
+
+/* VTY commands */
+
+void
+ospf6_route_show (struct vty *vty, struct ospf6_route_node *rn)
+{
+ struct linklist_node pnode;
+ struct linklist_node nnode;
+ struct ospf6_path_node *pn;
+ struct ospf6_nexthop_node *nn;
+
+ struct timeval now, res;
+ char duration[16];
+
+ u_int pc = 0;
+ u_int nc = 0;
+#define HEAD (pc == 0 && nc == 0)
+
+ char prefix[64], nexthop[64], ifname[IFNAMSIZ];
+
+ gettimeofday (&now, (struct timezone *) NULL);
+
+ /* destination */
+ if (rn->route.prefix.family == AF_INET ||
+ rn->route.prefix.family == AF_INET6)
+ prefix2str (&rn->route.prefix, prefix, sizeof (prefix));
+ else
+ prefix_ls2str (&rn->route.prefix, prefix, sizeof (prefix));
+
+ for (linklist_head (rn->path_list, &pnode); ! linklist_end (&pnode);
+ linklist_next (&pnode))
+ {
+ pn = pnode.data;
+
+ for (linklist_head (pn->nexthop_list, &nnode); ! linklist_end (&nnode);
+ linklist_next (&nnode))
+ {
+ nn = nnode.data;
+
+ inet_ntop (AF_INET6, &nn->nexthop.address, nexthop,
+ sizeof (nexthop));
+ if (! if_indextoname (nn->nexthop.ifindex, ifname))
+ snprintf (ifname, sizeof (ifname), "%d", nn->nexthop.ifindex);
+
+ ospf6_timeval_sub (&now, &nn->installed, &res);
+ ospf6_timeval_string_summary (&res, duration, sizeof (duration));
+
+ vty_out (vty, "%c%1s %2s %-30s %-25s %6s %s%s",
+ (HEAD ? '*' : ' '),
+ DTYPE_ABNAME (rn->route.type),
+ PTYPE_ABNAME (pn->path.type),
+ prefix, nexthop, ifname, duration, VTY_NEWLINE);
+
+ nc++;
+ }
+ pc++;
+ }
+}
+
+void
+ospf6_route_show_detail (struct vty *vty, struct ospf6_route_node *rn)
+{
+ struct linklist_node pnode;
+ struct linklist_node nnode;
+ struct ospf6_path_node *pn;
+ struct ospf6_nexthop_node *nn;
+
+ u_int pc = 0;
+ u_int nc = 0;
+
+ char prefix[64], nexthop[64], ifname[IFNAMSIZ];
+ char area_id[16], type[16], id[16], adv[16];
+ char capa[64];
+
+ /* destination */
+ if (rn->route.prefix.family == AF_INET ||
+ rn->route.prefix.family == AF_INET6)
+ prefix2str (&rn->route.prefix, prefix, sizeof (prefix));
+ else
+ prefix_ls2str (&rn->route.prefix, prefix, sizeof (prefix));
+
+ vty_out (vty, "%s%s%s", VTY_NEWLINE, prefix, VTY_NEWLINE);
+ vty_out (vty, " Destination Type: %s%s",
+ DTYPE_NAME (rn->route.type), VTY_NEWLINE);
+
+ for (linklist_head (rn->path_list, &pnode); ! linklist_end (&pnode);
+ linklist_next (&pnode))
+ {
+ pn = pnode.data;
+
+ inet_ntop (AF_INET, &pn->path.area_id, area_id, sizeof (area_id));
+ ospf6_lsa_type_string (pn->path.origin.type, type, sizeof (type));
+ inet_ntop (AF_INET, &pn->path.origin.id, id, sizeof (id));
+ inet_ntop (AF_INET, &pn->path.origin.adv_router, adv, sizeof (adv));
+ ospf6_options_string (pn->path.capability, capa, sizeof (capa));
+
+ vty_out (vty, " Path:%s", VTY_NEWLINE);
+ vty_out (vty, " Associated Area: %s%s", area_id, VTY_NEWLINE);
+ vty_out (vty, " LS Origin: %s ID: %s Adv: %s%s",
+ type, id, adv, VTY_NEWLINE);
+ vty_out (vty, " Path Type: %s%s",
+ PTYPE_NAME (pn->path.type), VTY_NEWLINE);
+ vty_out (vty, " Metric Type: %d%s",
+ pn->path.metric_type, VTY_NEWLINE);
+ vty_out (vty, " Cost: Type-1: %lu Type-2: %lu%s",
+ (u_long) pn->path.cost, (u_long) pn->path.cost_e2,
+ VTY_NEWLINE);
+ vty_out (vty, " Router Bits: %s|%s|%s|%s%s",
+ (CHECK_FLAG (pn->path.router_bits, OSPF6_ROUTER_LSA_BIT_W) ?
+ "W" : "-"),
+ (CHECK_FLAG (pn->path.router_bits, OSPF6_ROUTER_LSA_BIT_V) ?
+ "V" : "-"),
+ (CHECK_FLAG (pn->path.router_bits, OSPF6_ROUTER_LSA_BIT_E) ?
+ "E" : "-"),
+ (CHECK_FLAG (pn->path.router_bits, OSPF6_ROUTER_LSA_BIT_B) ?
+ "B" : "-"), VTY_NEWLINE);
+ vty_out (vty, " Optional Capabilities: %s%s", capa, VTY_NEWLINE);
+ vty_out (vty, " Prefix Options: %s%s", "xxx", VTY_NEWLINE);
+ vty_out (vty, " Next Hops:%s", VTY_NEWLINE);
+
+ for (linklist_head (pn->nexthop_list, &nnode); ! linklist_end (&nnode);
+ linklist_next (&nnode))
+ {
+ nn = nnode.data;
+
+ inet_ntop (AF_INET6, &nn->nexthop.address, nexthop,
+ sizeof (nexthop));
+ if (! if_indextoname (nn->nexthop.ifindex, ifname))
+ snprintf (ifname, sizeof (ifname), "%d", nn->nexthop.ifindex);
+
+ vty_out (vty, " %c%s%%%s%s",
+ (HEAD ? '*' : ' '), nexthop, ifname, VTY_NEWLINE);
+
+ nc++;
+ }
+ pc++;
+ }
+ vty_out (vty, "%s", VTY_NEWLINE);
+}
+
+int
+ospf6_route_table_show (struct vty *vty, int argc, char **argv,
+ struct ospf6_route_table *table)
+{
+ int i, ret;
+ unsigned long ret_ul;
+ char *endptr;
+ struct prefix prefix;
+ int detail = 0;
+ int arg_ipv6 = 0;
+ int arg_ipv4 = 0;
+ int arg_digit = 0;
+ struct prefix_ipv6 *p6 = (struct prefix_ipv6 *) &prefix;
+ struct prefix_ls *pl = (struct prefix_ls *) &prefix;
+ struct route_node *node;
+
+ u_int route_count = 0;
+ u_int path_count = 0;
+ u_int route_redundant = 0;
+
+ memset (&prefix, 0, sizeof (struct prefix));
+
+ for (i = 0; i < argc; i++)
+ {
+ if (! strcmp (argv[i], "detail"))
+ {
+ detail++;
+ break;
+ }
+
+ if (! arg_ipv6 && ! arg_ipv4 && ! arg_digit)
+ {
+
+ if ((ret = inet_pton (AF_INET6, argv[i], &p6->prefix)) == 1)
+ {
+ p6->family = AF_INET6;
+ p6->prefixlen = 128;
+ arg_ipv6++;
+ continue;
+ }
+ else if ((ret = inet_pton (AF_INET, argv[i], &pl->adv_router)) == 1)
+ {
+ pl->family = AF_UNSPEC;
+ pl->prefixlen = 64; /* xxx */
+ arg_ipv4++;
+ continue;
+ }
+ else
+ {
+ ret_ul = strtoul (argv[i], &endptr, 10);
+ if (*endptr == '\0')
+ {
+ pl->adv_router.s_addr = htonl (ret_ul);
+ pl->family = AF_UNSPEC;
+ pl->prefixlen = 64; /* xxx */
+ arg_digit++;
+ continue;
+ }
+ else
+ {
+ vty_out (vty, "Malformed argument: %s%s",
+ argv[i], VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+ }
+ }
+
+ if (arg_ipv4 || arg_digit)
+ {
+ if ((ret = inet_pton (AF_INET, argv[i], &pl->id)) == 1)
+ {
+ arg_ipv4++;
+ }
+ else
+ {
+ ret_ul = strtoul (argv[i], &endptr, 10);
+ if (*endptr == '\0')
+ {
+ pl->id.s_addr = htonl (ret_ul);
+ arg_digit++;
+ }
+ else
+ {
+ vty_out (vty, "Malformed argument: %s%s",
+ argv[i], VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+ }
+ }
+ }
+
+ if (arg_ipv4 || arg_ipv6 || arg_digit)
+ {
+ node = route_node_match (table->table, &prefix);
+ if (node && node->info)
+ ospf6_route_show_detail (vty, node->info);
+ return CMD_SUCCESS;
+ }
+
+ if (! detail)
+ {
+ vty_out (vty, "%s%c%1s %2s %-30s %-25s %6s%s", VTY_NEWLINE,
+ ' ', " ", " ", "Destination", "Gateway", "I/F", VTY_NEWLINE);
+ vty_out (vty, "---------------------------%s", VTY_NEWLINE);
+ }
+
+ for (node = route_top (table->table); node; node = route_next (node))
+ {
+ struct ospf6_route_node *route = node->info;
+
+ if (! route)
+ continue;
+
+ if (detail)
+ ospf6_route_show_detail (vty, route);
+ else
+ ospf6_route_show (vty, route);
+
+ route_count++;
+ path_count += route->path_list->count;
+ if (route->path_list->count > 1)
+ route_redundant++;
+ }
+
+ vty_out (vty, "===========%s", VTY_NEWLINE);
+ vty_out (vty, "Route: %d Path: %d Redundant: %d%s",
+ route_count, path_count, route_redundant, VTY_NEWLINE);
+
+ return CMD_SUCCESS;
+}
+
diff --git a/ospf6d/ospf6_route.h b/ospf6d/ospf6_route.h
new file mode 100644
index 00000000..71b2562b
--- /dev/null
+++ b/ospf6d/ospf6_route.h
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef OSPF6_ROUTE_H
+#define OSPF6_ROUTE_H
+
+#include "ospf6_hook.h"
+#include "ospf6_linklist.h"
+
+struct ospf6_route_table
+{
+ char name[128];
+
+ int freeze;
+
+ /* radix tree */
+ struct route_table *table;
+
+ /* list of hooks */
+ struct linklist *hook_list[3];
+ void (*hook_add) (void *);
+ void (*hook_change) (void *);
+ void (*hook_remove) (void *);
+
+ u_int32_t route_id;
+};
+
+
+
+struct ospf6_route
+{
+ /* Destination ID */
+ struct prefix prefix;
+
+ /* Destination Type */
+ u_char type;
+};
+
+/* Path */
+struct ls_origin
+{
+ u_int16_t type;
+ u_int32_t id;
+ u_int32_t adv_router;
+};
+
+struct ospf6_path
+{
+ /* Link State Origin */
+ struct ls_origin origin;
+
+ /* Router bits */
+ u_char router_bits;
+
+ /* Optional Capabilities */
+ u_char capability[3];
+
+ /* Prefix Options */
+ u_char prefix_options;
+
+ /* Associated Area */
+ u_int32_t area_id;
+
+ /* Path-type */
+ u_char type;
+
+ /* Cost */
+ u_int8_t metric_type;
+ u_int32_t cost;
+ u_int32_t cost_e2;
+};
+
+/* Nexthop */
+struct ospf6_nexthop
+{
+ /* Interface index */
+ unsigned int ifindex;
+
+ /* IP address, if any */
+ struct in6_addr address;
+};
+
+struct ospf6_route_node
+{
+ struct ospf6_route_table *table;
+ int count;
+ u_int32_t route_id;
+
+ struct route_node *route_node;
+ struct ospf6_route route;
+ struct linklist *path_list;
+};
+
+struct ospf6_path_node
+{
+ struct ospf6_route_node *route_node;
+ struct ospf6_path path;
+ struct linklist *nexthop_list;
+};
+
+struct ospf6_nexthop_node
+{
+ int flag;
+ struct timeval installed;
+
+ struct ospf6_path_node *path_node;
+ struct ospf6_nexthop nexthop;
+};
+
+struct ospf6_route_req
+{
+ struct ospf6_route_table *table;
+ struct route_node *route_node;
+ struct linklist_node path_lnode;
+ struct linklist_node nexthop_lnode;
+ u_int32_t route_id;
+
+ int count;
+ struct ospf6_route route;
+ struct ospf6_path path;
+ struct ospf6_nexthop nexthop;
+};
+
+#define OSPF6_DEST_TYPE_NONE 0
+#define OSPF6_DEST_TYPE_ROUTER 1
+#define OSPF6_DEST_TYPE_NETWORK 2
+#define OSPF6_DEST_TYPE_DISCARD 3
+#define OSPF6_DEST_TYPE_MAX 4
+
+#define OSPF6_PATH_TYPE_NONE 0
+#define OSPF6_PATH_TYPE_INTRA 1
+#define OSPF6_PATH_TYPE_INTER 2
+#define OSPF6_PATH_TYPE_EXTERNAL1 3
+#define OSPF6_PATH_TYPE_EXTERNAL2 4
+#define OSPF6_PATH_TYPE_ZOFFSET 5
+#define OSPF6_PATH_TYPE_ZSYSTEM (OSPF6_PATH_TYPE_ZOFFSET + ZEBRA_ROUTE_SYSTEM)
+#define OSPF6_PATH_TYPE_ZKERNEL (OSPF6_PATH_TYPE_ZOFFSET + ZEBRA_ROUTE_KERNEL)
+#define OSPF6_PATH_TYPE_ZCONNECT (OSPF6_PATH_TYPE_ZOFFSET + ZEBRA_ROUTE_CONNECT)
+#define OSPF6_PATH_TYPE_ZSTATIC (OSPF6_PATH_TYPE_ZOFFSET + ZEBRA_ROUTE_STATIC)
+#define OSPF6_PATH_TYPE_ZRIP (OSPF6_PATH_TYPE_ZOFFSET + ZEBRA_ROUTE_RIP)
+#define OSPF6_PATH_TYPE_ZRIPNG (OSPF6_PATH_TYPE_ZOFFSET + ZEBRA_ROUTE_RIPNG)
+#define OSPF6_PATH_TYPE_ZOSPF (OSPF6_PATH_TYPE_ZOFFSET + ZEBRA_ROUTE_OSPF)
+#define OSPF6_PATH_TYPE_ZOSPF6 (OSPF6_PATH_TYPE_ZOFFSET + ZEBRA_ROUTE_OSPF6)
+#define OSPF6_PATH_TYPE_ZBGP (OSPF6_PATH_TYPE_ZOFFSET + ZEBRA_ROUTE_BGP)
+#define OSPF6_PATH_TYPE_MAX (OSPF6_PATH_TYPE_ZOFFSET + ZEBRA_ROUTE_MAX)
+
+#define OSPF6_ROUTE_FLAG_ROUTE_CHANGE 0x01
+#define OSPF6_ROUTE_FLAG_PATH_CHANGE 0x02
+#define OSPF6_ROUTE_FLAG_ADD 0x04
+#define OSPF6_ROUTE_FLAG_REMOVE 0x08
+#define OSPF6_ROUTE_FLAG_CHANGE 0x10
+
+int ospf6_route_lookup (struct ospf6_route_req *request,
+ struct prefix *prefix,
+ struct ospf6_route_table *table);
+void ospf6_route_head (struct ospf6_route_req *request,
+ struct ospf6_route_table *table);
+int ospf6_route_end (struct ospf6_route_req *request);
+void ospf6_route_next (struct ospf6_route_req *request);
+
+void ospf6_route_add (struct ospf6_route_req *, struct ospf6_route_table *);
+void ospf6_route_remove (struct ospf6_route_req *, struct ospf6_route_table *);
+void ospf6_route_remove_all (struct ospf6_route_table *);
+
+struct ospf6_route_table *ospf6_route_table_create ();
+void ospf6_route_table_delete (struct ospf6_route_table *);
+
+void ospf6_route_table_freeze (struct ospf6_route_table *);
+void ospf6_route_table_thaw (struct ospf6_route_table *);
+
+void ospf6_route_log_request (char *what, char *where,
+ struct ospf6_route_req *request);
+
+void
+ospf6_route_hook_register (void (*add) (struct ospf6_route_req *),
+ void (*change) (struct ospf6_route_req *),
+ void (*remove) (struct ospf6_route_req *),
+ struct ospf6_route_table *table);
+void
+ospf6_route_hook_unregister (void (*add) (struct ospf6_route_req *),
+ void (*change) (struct ospf6_route_req *),
+ void (*remove) (struct ospf6_route_req *),
+ struct ospf6_route_table *table);
+
+void ospf6_route_init ();
+
+int ospf6_route_table_show (struct vty *, int, char **,
+ struct ospf6_route_table *);
+
+#endif /* OSPF6_ROUTE_H */
+
diff --git a/ospf6d/ospf6_routemap.c b/ospf6d/ospf6_routemap.c
new file mode 100644
index 00000000..14df7940
--- /dev/null
+++ b/ospf6d/ospf6_routemap.c
@@ -0,0 +1,359 @@
+/*
+ * OSPFv3 Route-Map
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "log.h"
+#include "memory.h"
+#include "linklist.h"
+#include "prefix.h"
+#include "command.h"
+#include "vty.h"
+#include "routemap.h"
+#include "table.h"
+#include "plist.h"
+
+#include "ospf6_route.h"
+#include "ospf6_prefix.h"
+#include "ospf6_lsa.h"
+#include "ospf6_asbr.h"
+
+route_map_result_t
+ospf6_routemap_rule_match_address_prefixlist (void *rule,
+ struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
+{
+ struct prefix_list *plist;
+
+ if (type != RMAP_OSPF6)
+ return RMAP_NOMATCH;
+
+ plist = prefix_list_lookup (AFI_IP6, (char *) rule);
+
+ if (plist == NULL)
+ return RMAP_NOMATCH;
+
+ return (prefix_list_apply (plist, prefix) == PREFIX_DENY ?
+ RMAP_NOMATCH : RMAP_MATCH);
+}
+
+void *
+ospf6_routemap_rule_match_address_prefixlist_compile (char *arg)
+{
+ return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+void
+ospf6_routemap_rule_match_address_prefixlist_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+struct route_map_rule_cmd
+ospf6_routemap_rule_match_address_prefixlist_cmd =
+{
+ "ipv6 address prefix-list",
+ ospf6_routemap_rule_match_address_prefixlist,
+ ospf6_routemap_rule_match_address_prefixlist_compile,
+ ospf6_routemap_rule_match_address_prefixlist_free,
+};
+
+route_map_result_t
+ospf6_routemap_rule_set_metric_type (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ char *metric_type = rule;
+ struct ospf6_external_info *info = object;
+
+ if (type != RMAP_OSPF6)
+ return RMAP_OKAY;
+
+ if (strcmp (metric_type, "type-2") == 0)
+ info->metric_type = 2;
+ else
+ info->metric_type = 1;
+
+ return RMAP_OKAY;
+}
+
+void *
+ospf6_routemap_rule_set_metric_type_compile (char *arg)
+{
+ return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+void
+ospf6_routemap_rule_set_metric_type_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+struct route_map_rule_cmd
+ospf6_routemap_rule_set_metric_type_cmd =
+{
+ "metric-type",
+ ospf6_routemap_rule_set_metric_type,
+ ospf6_routemap_rule_set_metric_type_compile,
+ ospf6_routemap_rule_set_metric_type_free,
+};
+
+route_map_result_t
+ospf6_routemap_rule_set_metric (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ char *metric = rule;
+ struct ospf6_external_info *info = object;
+
+ if (type != RMAP_OSPF6)
+ return RMAP_OKAY;
+
+ info->metric = atoi (metric);
+ return RMAP_OKAY;
+}
+
+void *
+ospf6_routemap_rule_set_metric_compile (char *arg)
+{
+ return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+void
+ospf6_routemap_rule_set_metric_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+struct route_map_rule_cmd
+ospf6_routemap_rule_set_metric_cmd =
+{
+ "metric",
+ ospf6_routemap_rule_set_metric,
+ ospf6_routemap_rule_set_metric_compile,
+ ospf6_routemap_rule_set_metric_free,
+};
+
+route_map_result_t
+ospf6_routemap_rule_set_forwarding (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ char *forwarding = rule;
+ struct ospf6_external_info *info = object;
+
+ if (type != RMAP_OSPF6)
+ return RMAP_OKAY;
+
+ if (inet_pton (AF_INET6, forwarding, &info->forwarding) != 1)
+ {
+ memset (&info->forwarding, 0, sizeof (struct in6_addr));
+ return RMAP_ERROR;
+ }
+
+ return RMAP_OKAY;
+}
+
+void *
+ospf6_routemap_rule_set_forwarding_compile (char *arg)
+{
+ return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+void
+ospf6_routemap_rule_set_forwarding_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+struct route_map_rule_cmd
+ospf6_routemap_rule_set_forwarding_cmd =
+{
+ "forwarding-address",
+ ospf6_routemap_rule_set_forwarding,
+ ospf6_routemap_rule_set_forwarding_compile,
+ ospf6_routemap_rule_set_forwarding_free,
+};
+
+int
+route_map_command_status (struct vty *vty, int ret)
+{
+ if (! ret)
+ return CMD_SUCCESS;
+
+ switch (ret)
+ {
+ case RMAP_RULE_MISSING:
+ vty_out (vty, "Can't find rule.%s", VTY_NEWLINE);
+ break;
+ case RMAP_COMPILE_ERROR:
+ vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE);
+ break;
+ default:
+ vty_out (vty, "route-map add set failed.%s", VTY_NEWLINE);
+ break;
+ }
+ return CMD_WARNING;
+}
+
+/* add "match address" */
+DEFUN (ospf6_routemap_match_address_prefixlist,
+ ospf6_routemap_match_address_prefixlist_cmd,
+ "match ipv6 address prefix-list WORD",
+ "Match values\n"
+ IPV6_STR
+ "Match address of route\n"
+ "Match entries of prefix-lists\n"
+ "IPv6 prefix-list name\n")
+{
+ int ret = route_map_add_match ((struct route_map_index *) vty->index,
+ "ipv6 address prefix-list", argv[0]);
+ return route_map_command_status (vty, ret);
+}
+
+/* delete "match address" */
+DEFUN (ospf6_routemap_no_match_address_prefixlist,
+ ospf6_routemap_no_match_address_prefixlist_cmd,
+ "no match ipv6 address prefix-list WORD",
+ NO_STR
+ "Match values\n"
+ IPV6_STR
+ "Match address of route\n"
+ "Match entries of prefix-lists\n"
+ "IPv6 prefix-list name\n")
+{
+ int ret = route_map_delete_match ((struct route_map_index *) vty->index,
+ "ipv6 address prefix-list", argv[0]);
+ return route_map_command_status (vty, ret);
+}
+
+/* add "set metric-type" */
+DEFUN (ospf6_routemap_set_metric_type,
+ ospf6_routemap_set_metric_type_cmd,
+ "set metric-type (type-1|type-2)",
+ "Set value\n"
+ "Type of metric\n"
+ "OSPF6 external type 1 metric\n"
+ "OSPF6 external type 2 metric\n")
+{
+ int ret = route_map_add_set ((struct route_map_index *) vty->index,
+ "metric-type", argv[0]);
+ return route_map_command_status (vty, ret);
+}
+
+/* delete "set metric-type" */
+DEFUN (ospf6_routemap_no_set_metric_type,
+ ospf6_routemap_no_set_metric_type_cmd,
+ "no set metric-type (type-1|type-2)",
+ NO_STR
+ "Set value\n"
+ "Type of metric\n"
+ "OSPF6 external type 1 metric\n"
+ "OSPF6 external type 2 metric\n")
+{
+ int ret = route_map_delete_set ((struct route_map_index *) vty->index,
+ "metric-type", argv[0]);
+ return route_map_command_status (vty, ret);
+}
+
+/* add "set metric" */
+DEFUN (set_metric,
+ set_metric_cmd,
+ "set metric <0-4294967295>",
+ "Set value\n"
+ "Metric value\n"
+ "Metric value\n")
+{
+ int ret = route_map_add_set ((struct route_map_index *) vty->index,
+ "metric", argv[0]);
+ return route_map_command_status (vty, ret);
+}
+
+/* delete "set metric" */
+DEFUN (no_set_metric,
+ no_set_metric_cmd,
+ "no set metric <0-4294967295>",
+ NO_STR
+ "Set value\n"
+ "Metric\n"
+ "METRIC value\n")
+{
+ int ret = route_map_delete_set ((struct route_map_index *) vty->index,
+ "metric", argv[0]);
+ return route_map_command_status (vty, ret);
+}
+
+/* add "set forwarding-address" */
+DEFUN (ospf6_routemap_set_forwarding,
+ ospf6_routemap_set_forwarding_cmd,
+ "set forwarding-address X:X::X:X",
+ "Set value\n"
+ "Forwarding Address\n"
+ "IPv6 Address\n")
+{
+ int ret = route_map_add_set ((struct route_map_index *) vty->index,
+ "forwarding-address", argv[0]);
+ return route_map_command_status (vty, ret);
+}
+
+/* delete "set forwarding-address" */
+DEFUN (ospf6_routemap_no_set_forwarding,
+ ospf6_routemap_no_set_forwarding_cmd,
+ "no set forwarding-address X:X::X:X",
+ NO_STR
+ "Set value\n"
+ "Forwarding Address\n"
+ "IPv6 Address\n")
+{
+ int ret = route_map_delete_set ((struct route_map_index *) vty->index,
+ "forwarding-address", argv[0]);
+ return route_map_command_status (vty, ret);
+}
+
+void
+ospf6_routemap_init ()
+{
+ route_map_init ();
+ route_map_init_vty ();
+ route_map_add_hook (ospf6_asbr_routemap_update);
+ route_map_delete_hook (ospf6_asbr_routemap_update);
+
+ route_map_install_match (&ospf6_routemap_rule_match_address_prefixlist_cmd);
+ route_map_install_set (&ospf6_routemap_rule_set_metric_type_cmd);
+ route_map_install_set (&ospf6_routemap_rule_set_metric_cmd);
+ route_map_install_set (&ospf6_routemap_rule_set_forwarding_cmd);
+
+ /* Match address prefix-list */
+ install_element (RMAP_NODE, &ospf6_routemap_match_address_prefixlist_cmd);
+ install_element (RMAP_NODE, &ospf6_routemap_no_match_address_prefixlist_cmd);
+
+ /* ASE Metric Type (e.g. Type-1/Type-2) */
+ install_element (RMAP_NODE, &ospf6_routemap_set_metric_type_cmd);
+ install_element (RMAP_NODE, &ospf6_routemap_no_set_metric_type_cmd);
+
+ /* ASE Metric */
+ install_element (RMAP_NODE, &set_metric_cmd);
+ install_element (RMAP_NODE, &no_set_metric_cmd);
+
+ /* ASE Metric */
+ install_element (RMAP_NODE, &ospf6_routemap_set_forwarding_cmd);
+ install_element (RMAP_NODE, &ospf6_routemap_no_set_forwarding_cmd);
+}
+
diff --git a/ospf6d/ospf6_routemap.h b/ospf6d/ospf6_routemap.h
new file mode 100644
index 00000000..c68e0ffc
--- /dev/null
+++ b/ospf6d/ospf6_routemap.h
@@ -0,0 +1,27 @@
+/*
+ * OSPFv3 Route-Map
+ * Copyright (C) 2000 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef OSPF6_ROUTEMAP_H
+
+void ospf6_routemap_init ();
+
+#endif /* OSPF6_ROUTEMAP_H */
diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c
new file mode 100644
index 00000000..fd7fc779
--- /dev/null
+++ b/ospf6d/ospf6_spf.c
@@ -0,0 +1,1454 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/* Shortest Path First calculation for OSPFv3 */
+
+#include "ospf6d.h"
+
+#include "linklist.h"
+#include "prefix.h"
+#include "table.h"
+
+#include "ospf6_proto.h"
+#include "ospf6_lsa.h"
+#include "ospf6_lsdb.h"
+#include "ospf6_route.h"
+#include "ospf6_spf.h"
+#include "ospf6_neighbor.h"
+#include "ospf6_interface.h"
+#include "ospf6_area.h"
+
+#include "ospf6_bintree.h"
+#include "ospf6_linklist.h"
+
+struct bintree *_candidate_list;
+struct linklist *nexthop_list;
+
+struct ospf6_spf_candidate_node
+{
+ u_int32_t cost;
+ struct linklist *list;
+};
+
+int
+ospf6_spf_candidate_node_cmp (void *a, void *b)
+{
+ struct ospf6_spf_candidate_node *ca = a;
+ struct ospf6_spf_candidate_node *cb = b;
+ return ca->cost - cb->cost;
+}
+
+int
+ospf6_spf_vertex_cmp (void *a, void *b)
+{
+ return 1;
+}
+
+void
+ospf6_spf_candidate_node_print (int indent_num, void *node)
+{
+ struct ospf6_spf_candidate_node *cn = node;
+ char format[256];
+
+ snprintf (format, sizeof (format), "%%%ds %%d (num: %%d)",
+ indent_num * 2 + 1);
+ zlog_info (format, " ", cn->cost, cn->list->count);
+}
+
+void
+ospf6_spf_candidate_init ()
+{
+ _candidate_list = bintree_create ();
+ _candidate_list->cmp = ospf6_spf_candidate_node_cmp;
+}
+
+u_int32_t
+ospf6_spf_candidate_count ()
+{
+ u_int32_t count = 0;
+ struct bintree_node node;
+ struct ospf6_spf_candidate_node *cnode;
+
+ for (bintree_head (_candidate_list, &node); ! bintree_end (&node);
+ bintree_next (&node))
+ {
+ cnode = node.data;
+ count += cnode->list->count;
+ }
+
+ return count;
+}
+
+void
+ospf6_spf_candidate_print ()
+{
+ zlog_info ("---------------------------");
+ bintree_print (ospf6_spf_candidate_node_print, _candidate_list);
+ zlog_info ("---------------------------");
+}
+
+void
+ospf6_spf_candidate_enqueue (struct ospf6_vertex *v)
+{
+ struct ospf6_spf_candidate_node req, *node;
+
+ memset (&req, 0, sizeof (req));
+ req.cost = v->distance;
+ node = bintree_lookup (&req, _candidate_list);
+
+ if (node == NULL)
+ {
+ node = malloc (sizeof (struct ospf6_spf_candidate_node));
+ node->cost = v->distance;
+ node->list = linklist_create ();
+ node->list->cmp = ospf6_spf_vertex_cmp;
+ bintree_add (node, _candidate_list);
+ }
+
+ linklist_add (v, node->list);
+
+#if 0
+ if (IS_OSPF6_DUMP_SPF)
+ ospf6_spf_candidate_print ();
+#endif
+}
+
+struct ospf6_vertex *
+ospf6_spf_candidate_dequeue ()
+{
+ struct ospf6_spf_candidate_node *node;
+ struct linklist_node lnode;
+ struct ospf6_vertex *ret;
+
+ node = bintree_lookup_min (_candidate_list);
+ if (node == NULL)
+ return NULL;
+
+ linklist_head (node->list, &lnode);
+ ret = lnode.data;
+
+ linklist_remove (ret, node->list);
+ if (node->list->count == 0)
+ {
+ linklist_delete (node->list);
+ bintree_remove (node, _candidate_list);
+ }
+
+#if 0
+ if (IS_OSPF6_DUMP_SPF)
+ ospf6_spf_candidate_print ();
+#endif
+
+ return ret;
+}
+
+void
+ospf6_spf_candidate_remove (struct ospf6_vertex *v)
+{
+ struct bintree_node node;
+ struct ospf6_spf_candidate_node *cnode = NULL;
+
+ for (bintree_head (_candidate_list, &node); ! bintree_end (&node);
+ bintree_next (&node))
+ {
+ cnode = node.data;
+ if (linklist_lookup (v, cnode->list))
+ {
+ linklist_remove (v, cnode->list);
+ break;
+ }
+ }
+
+ if (cnode->list->count == 0)
+ {
+ linklist_delete (cnode->list);
+ bintree_remove (cnode, _candidate_list);
+ }
+}
+
+
+#define TIMER_SEC_MICRO 1000000
+
+/* timeval calculation */
+static void
+ospf6_timeval_add (const struct timeval *t1, const struct timeval *t2,
+ struct timeval *result)
+{
+ long moveup = 0;
+
+ result->tv_usec = t1->tv_usec + t2->tv_usec;
+ while (result->tv_usec > TIMER_SEC_MICRO)
+ {
+ result->tv_usec -= TIMER_SEC_MICRO;
+ moveup ++;
+ }
+
+ result->tv_sec = t1->tv_sec + t2->tv_sec + moveup;
+}
+
+static void
+ospf6_timeval_add_equal (const struct timeval *t, struct timeval *result)
+{
+ struct timeval tmp;
+ ospf6_timeval_add (t, result, &tmp);
+ result->tv_sec = tmp.tv_sec;
+ result->tv_usec = tmp.tv_usec;
+}
+
+/* Compare timeval a and b. It returns an integer less than, equal
+ to, or great than zero if a is found, respectively, to be less
+ than, to match, or be greater than b. */
+static int
+ospf6_timeval_cmp (const struct timeval t1, const struct timeval t2)
+{
+ return (t1.tv_sec == t2.tv_sec
+ ? t1.tv_usec - t2.tv_usec : t1.tv_sec - t2.tv_sec);
+}
+
+
+static int
+ospf6_spf_lsd_num (struct ospf6_vertex *V, struct ospf6_area *o6a)
+{
+ u_int16_t type;
+ u_int32_t id, adv_router;
+ struct ospf6_lsa *lsa;
+
+ if (V->vertex_id.id.s_addr)
+ type = htons (OSPF6_LSA_TYPE_NETWORK);
+ else
+ type = htons (OSPF6_LSA_TYPE_ROUTER);
+ id = V->vertex_id.id.s_addr;
+ adv_router = V->vertex_id.adv_router.s_addr;
+
+ lsa = ospf6_lsdb_lookup_lsdb (type, id, adv_router, o6a->lsdb);
+ if (! lsa)
+ {
+ zlog_err ("SPF: Can't find associated LSA for %s", V->string);
+ return 0;
+ }
+
+ return ospf6_lsa_lsd_num ((struct ospf6_lsa_header *) lsa->header);
+}
+
+/* RFC2328 section 16.1.1:
+ Check if there is at least one router in the path
+ from the root to this vertex. */
+static int
+ospf6_spf_is_router_to_root (struct ospf6_vertex *c,
+ struct ospf6_spftree *spf_tree)
+{
+ listnode node;
+ struct ospf6_vertex *p;
+
+ if (spf_tree->root == c)
+ return 0;
+
+ for (node = listhead (c->parent_list); node; nextnode (node))
+ {
+ p = (struct ospf6_vertex *) getdata (node);
+
+ if (p == spf_tree->root)
+ return 0;
+
+ if (p->vertex_id.id.s_addr == 0) /* this is router */
+ continue;
+ else if (ospf6_spf_is_router_to_root (p, spf_tree))
+ continue;
+
+ return 0;
+ }
+
+ return 1;
+}
+
+static struct in6_addr *
+ospf6_spf_get_ipaddr (u_int32_t id, u_int32_t adv_router, u_int32_t ifindex)
+{
+ char buf[64], nhbuf[64];
+ struct ospf6_interface *o6i;
+ struct ospf6_neighbor *o6n;
+ struct ospf6_lsa *lsa;
+ struct ospf6_lsdb_node node;
+
+ o6i = ospf6_interface_lookup_by_index (ifindex);
+ if (! o6i)
+ {
+ zlog_err ("SPF: Can't find interface: index %d", ifindex);
+ return (struct in6_addr *) NULL;
+ }
+
+ /* Find Link-LSA of the vertex in question */
+ lsa = NULL;
+ for (ospf6_lsdb_type_router (&node, htons (OSPF6_LSA_TYPE_LINK),
+ adv_router, o6i->lsdb);
+ ! ospf6_lsdb_is_end (&node);
+ ospf6_lsdb_next (&node))
+ lsa = node.lsa;
+
+ /* return Linklocal Address field if the Link-LSA exists */
+ if (lsa && lsa->header->adv_router == adv_router)
+ {
+ struct ospf6_link_lsa *link_lsa;
+ link_lsa = (struct ospf6_link_lsa *) (lsa->header + 1);
+ return &link_lsa->llsa_linklocal;
+ }
+
+ zlog_warn ("SPF: Can't find Link-LSA for %s",
+ inet_ntop (AF_INET, &adv_router, buf, sizeof (buf)));
+
+ o6n = ospf6_neighbor_lookup (adv_router, o6i);
+ if (! o6n)
+ {
+ inet_ntop (AF_INET, &adv_router, buf, sizeof (buf));
+ zlog_err ("SPF: Can't find neighbor %s in %s, "
+ "unable to find his linklocal address",
+ buf, o6i->interface->name);
+ return (struct in6_addr *) NULL;
+ }
+
+ zlog_warn ("SPF: use packet's source address for %s's nexthop: %s",
+ inet_ntop (AF_INET, &adv_router, buf, sizeof (buf)),
+ inet_ntop (AF_INET6, &o6n->hisaddr, nhbuf, sizeof (nhbuf)));
+
+ return &o6n->hisaddr;
+}
+
+static int
+ospf6_spf_nexthop_calculation (struct ospf6_vertex *W,
+ u_int32_t ifindex,
+ struct ospf6_vertex *V,
+ struct ospf6_spftree *spf_tree)
+{
+ struct ospf6_nexthop *nexthop, *n;
+ u_int32_t adv_router, id;
+ struct in6_addr nexthop_ipaddr, *ipaddr;
+ unsigned int nexthop_ifindex;
+ struct linklist_node node;
+
+ /* until this, nexthop_list should be untouched */
+ assert (list_isempty (W->nexthop_list));
+
+ /* If ther is at least one intervening router from root to W */
+ if (ospf6_spf_is_router_to_root (W, spf_tree))
+ {
+ /* Create no new nexthop, Inherit from the intervening router */
+ for (linklist_head (V->nexthop_list, &node); ! linklist_end (&node);
+ linklist_next (&node))
+ linklist_add (node.data, W->nexthop_list);
+ return 0;
+ }
+
+ /* Create new nexthop */
+
+ adv_router = W->vertex_id.adv_router.s_addr;
+ id = W->vertex_id.id.s_addr;
+
+ nexthop_ifindex = 0;
+ memset (&nexthop_ipaddr, 0, sizeof (struct in6_addr));
+ if (spf_tree->root && V == spf_tree->root)
+ {
+ nexthop_ifindex = ifindex;
+ if (! id) /* xxx, if V is router */
+ {
+ ipaddr = ospf6_spf_get_ipaddr (id, adv_router, ifindex);
+ if (! ipaddr)
+ {
+ /* xxx, should trigger error and quit SPF calculation... */
+ memset (&nexthop_ipaddr, 0xff, sizeof (struct in6_addr));
+ return -1;
+ }
+ else
+ memcpy (&nexthop_ipaddr, ipaddr, sizeof (struct in6_addr));
+ }
+ }
+ else
+ {
+ /* V is broadcast network, W is router */
+ assert (V->vertex_id.id.s_addr != 0);
+ assert (W->vertex_id.id.s_addr == 0);
+
+ linklist_head (V->nexthop_list, &node);
+ n = (struct ospf6_nexthop *) node.data;
+ nexthop_ifindex = n->ifindex;
+ ipaddr = ospf6_spf_get_ipaddr (id, adv_router, n->ifindex);
+ if (! ipaddr)
+ {
+ /* xxx, should trigger error and quit SPF calculation... */
+ memset (&nexthop_ipaddr, 0xff, sizeof (struct in6_addr));
+ return -1;
+ }
+ else
+ memcpy (&nexthop_ipaddr, ipaddr, sizeof (struct in6_addr));
+ }
+
+ nexthop = XCALLOC (MTYPE_OSPF6_VERTEX, sizeof (struct ospf6_nexthop));
+ nexthop->ifindex = nexthop_ifindex;
+ memcpy (&nexthop->address, &nexthop_ipaddr, sizeof (nexthop->address));
+
+ linklist_add (nexthop, W->nexthop_list);
+
+ /* to hold malloced memory */
+ linklist_add (nexthop, nexthop_list);
+
+ return 0;
+}
+
+static struct ospf6_vertex *
+ospf6_spf_vertex_create (int index, struct ospf6_vertex *V,
+ struct ospf6_area *o6a)
+{
+ struct ospf6_lsa *lsa;
+ struct ospf6_router_lsa *router_lsa;
+ struct ospf6_router_lsd *router_lsd;
+ struct ospf6_network_lsa *network_lsa;
+ struct ospf6_network_lsd *network_lsd;
+ u_int32_t id, adv_router;
+ u_int16_t type;
+ void *lsd;
+ struct ospf6_vertex *W;
+ u_int16_t distance;
+ u_int32_t ifindex;
+ int backreference, lsdnum, i;
+ char buf_router[16], buf_id[16];
+
+ type = id = adv_router = 0;
+
+ /* Get Linkstate description */
+ lsd = ospf6_lsa_lsd_get (index, (struct ospf6_lsa_header *) V->lsa->header);
+ if (! lsd)
+ {
+ zlog_err ("SPF: Can't find %dth Link description from %s",
+ index, V->lsa->str);
+ return (struct ospf6_vertex *) NULL;
+ }
+
+ /* Check Link state description */
+ distance = 0;
+ ifindex = 0;
+ if (V->lsa->header->type == htons (OSPF6_LSA_TYPE_ROUTER))
+ {
+ router_lsd = lsd;
+ if (router_lsd->type == OSPF6_ROUTER_LSD_TYPE_POINTTOPOINT)
+ {
+ type = htons (OSPF6_LSA_TYPE_ROUTER);
+ id = htonl (0);
+ }
+ else if (router_lsd->type == OSPF6_ROUTER_LSD_TYPE_TRANSIT_NETWORK)
+ {
+ type = htons (OSPF6_LSA_TYPE_NETWORK);
+ id = router_lsd->neighbor_interface_id;
+ }
+ adv_router = router_lsd->neighbor_router_id;
+ distance = ntohs (router_lsd->metric);
+ ifindex = ntohl (router_lsd->interface_id);
+ }
+ else if (V->lsa->header->type == htons (OSPF6_LSA_TYPE_NETWORK))
+ {
+ network_lsd = lsd;
+ type = htons (OSPF6_LSA_TYPE_ROUTER);
+ id = htonl (0);
+ adv_router = network_lsd->adv_router;
+ }
+
+ /* Avoid creating candidate of myself */
+ if (adv_router == o6a->ospf6->router_id &&
+ type == htons (OSPF6_LSA_TYPE_ROUTER))
+ {
+ return (struct ospf6_vertex *) NULL;
+ }
+
+ /* Find Associated LSA for W */
+ lsa = ospf6_lsdb_lookup_lsdb (type, id, adv_router, o6a->lsdb);
+
+ if (! lsa)
+ {
+ inet_ntop (AF_INET, &adv_router, buf_router, sizeof (buf_router));
+ inet_ntop (AF_INET, &id, buf_id, sizeof (buf_id));
+
+ if (IS_OSPF6_DUMP_SPF)
+ {
+ if (type == htons (OSPF6_LSA_TYPE_ROUTER))
+ zlog_info ("SPF: Can't find LSA for W (%s *): not found",
+ buf_router);
+ else
+ zlog_info ("SPF: Can't find LSA for W (%s %s): not found",
+ buf_router, buf_id);
+ }
+ return (struct ospf6_vertex *) NULL;
+ }
+
+ if (IS_LSA_MAXAGE (lsa))
+ {
+ if (IS_OSPF6_DUMP_SPF)
+ zlog_info ("SPF: Associated LSA for W is MaxAge: %s", lsa->str);
+ return (struct ospf6_vertex *) NULL;
+ }
+
+ /* Check back reference from W's lsa to V's lsa */
+ backreference = 0;
+ lsdnum = ospf6_lsa_lsd_num ((struct ospf6_lsa_header *) lsa->header);
+ for (i = 0; i < lsdnum; i++)
+ {
+ if (ospf6_lsa_lsd_is_refer_ok (i, (struct ospf6_lsa_header *) lsa->header,
+ index, (struct ospf6_lsa_header *) V->lsa->header))
+ backreference++;
+ }
+ if (! backreference)
+ {
+ if (IS_OSPF6_DUMP_SPF)
+ zlog_info ("SPF: Back reference failed: V: %s, W: %s",
+ V->lsa->str, lsa->str);
+ return (struct ospf6_vertex *) NULL;
+ }
+
+ /* Allocate new ospf6_vertex for W */
+ W = (struct ospf6_vertex *) XMALLOC (MTYPE_OSPF6_VERTEX,
+ sizeof (struct ospf6_vertex));
+ if (! W)
+ {
+ zlog_err ("SPF: Can't allocate memory for Vertex");
+ return (struct ospf6_vertex *) NULL;
+ }
+ memset (W, 0, sizeof (struct ospf6_vertex));
+
+ /* Initialize */
+ W->vertex_id.family = AF_UNSPEC;
+ W->vertex_id.prefixlen = 64; /* xxx */
+ W->lsa = lsa;
+ if (type == htons (OSPF6_LSA_TYPE_ROUTER))
+ W->vertex_id.id.s_addr = htonl (0); /* XXX */
+ else
+ W->vertex_id.id.s_addr = W->lsa->header->id;
+ W->vertex_id.adv_router.s_addr = W->lsa->header->adv_router;
+ W->nexthop_list = linklist_create ();
+ W->path_list = list_new ();
+ W->parent_list = list_new ();
+ W->distance = V->distance + distance;
+ W->depth = V->depth + 1;
+
+ inet_ntop (AF_INET, &W->vertex_id.adv_router.s_addr,
+ buf_router, sizeof (buf_router));
+ inet_ntop (AF_INET, &W->vertex_id.id.s_addr, buf_id, sizeof (buf_id));
+ snprintf (W->string, sizeof (W->string), "[%s-%s (%d)]",
+ buf_router, buf_id, W->distance);
+
+ /* capability bits and optional capabilities */
+ if (W->vertex_id.id.s_addr == 0)
+ {
+ router_lsa = (struct ospf6_router_lsa *) (W->lsa->header + 1);
+ W->capability_bits = router_lsa->bits;
+ memcpy (W->opt_capability, router_lsa->options,
+ sizeof (W->opt_capability));
+ }
+ else
+ {
+ network_lsa = (struct ospf6_network_lsa *) (W->lsa->header + 1);
+ W->capability_bits = network_lsa->reserved;
+ memcpy (W->opt_capability, network_lsa->options,
+ sizeof (W->opt_capability));
+ }
+
+ /* Link to Parent node */
+ listnode_add (W->parent_list, V);
+
+ /* Nexthop Calculation */
+ if (ospf6_spf_nexthop_calculation (W, ifindex, V, o6a->spf_tree) < 0)
+ return NULL;
+
+ return W;
+}
+
+static void
+ospf6_spf_vertex_delete (struct ospf6_vertex *v)
+{
+ linklist_delete (v->nexthop_list);
+ list_delete (v->path_list);
+ list_delete (v->parent_list);
+ XFREE (MTYPE_OSPF6_VERTEX, v);
+}
+
+static void
+ospf6_spf_vertex_merge (struct ospf6_vertex *w, struct ospf6_vertex *x)
+{
+ listnode node;
+ struct linklist_node lnode;
+
+ /* merge should be done on two nodes which are
+ almost the same */
+
+ /* these w and x should be both candidate.
+ candidate should not have any children */
+ assert (list_isempty (w->path_list));
+ assert (list_isempty (x->path_list));
+
+ /* merge parent list */
+ for (node = listhead (w->parent_list); node; nextnode (node))
+ {
+ if (listnode_lookup (x->parent_list, getdata (node)))
+ continue;
+ listnode_add (x->parent_list, getdata (node));
+ }
+
+ /* merge nexthop list */
+ for (linklist_head (w->nexthop_list, &lnode); ! linklist_end (&lnode);
+ linklist_next (&lnode))
+ linklist_add (lnode.data, x->nexthop_list);
+}
+
+static void
+ospf6_spf_initialize (list candidate_list, struct ospf6_area *o6a)
+{
+ listnode node;
+ struct ospf6_vertex *v;
+ struct ospf6_lsa *lsa;
+ u_int16_t type;
+ u_int32_t id, adv_router;
+ struct linklist_node lnode;
+
+ struct ospf6_nexthop *nexthop;
+ struct interface *ifp;
+ char buf_router[64], buf_id[64];
+
+ /* delete topology routing table for this area */
+ ospf6_route_remove_all (o6a->table_topology);
+
+ /* Delete previous spf tree */
+ for (node = listhead (o6a->spf_tree->list); node; nextnode (node))
+ {
+ v = (struct ospf6_vertex *) getdata (node);
+ ospf6_spf_vertex_delete (v);
+ }
+ list_delete_all_node (o6a->spf_tree->list);
+
+ for (linklist_head (nexthop_list, &lnode); ! linklist_end (&lnode);
+ linklist_next (&lnode))
+ XFREE (MTYPE_OSPF6_VERTEX, lnode.data);
+ linklist_remove_all (nexthop_list);
+
+ /* Find self originated Router-LSA */
+ type = htons (OSPF6_LSA_TYPE_ROUTER);
+ id = htonl (0);
+ adv_router = ospf6->router_id;
+
+ lsa = ospf6_lsdb_lookup_lsdb (type, id, adv_router, o6a->lsdb);
+
+ if (! lsa)
+ {
+ if (IS_OSPF6_DUMP_SPF)
+ zlog_info ("SPF: Can't find self originated Router-LSA");
+ return;
+ }
+ if (IS_LSA_MAXAGE (lsa))
+ {
+ zlog_err ("SPF: MaxAge self originated Router-LSA");
+ return;
+ }
+
+ /* Create root vertex */
+ v = (struct ospf6_vertex *) XMALLOC (MTYPE_OSPF6_VERTEX,
+ sizeof (struct ospf6_vertex));
+ if (! v)
+ {
+ zlog_err ("SPF: Can't allocate memory for root vertex");
+ return;
+ }
+ memset (v, 0, sizeof (struct ospf6_vertex));
+
+ v->vertex_id.family = AF_UNSPEC; /* XXX */
+ v->vertex_id.prefixlen = 64; /* XXX */
+ v->vertex_id.id.s_addr = htonl (0);
+ v->vertex_id.adv_router.s_addr = ospf6->router_id;
+ if (ospf6_is_asbr (ospf6))
+ OSPF6_OPT_SET (v->opt_capability, OSPF6_OPT_E);
+ OSPF6_OPT_SET (v->opt_capability, OSPF6_OPT_V6);
+ OSPF6_OPT_SET (v->opt_capability, OSPF6_OPT_R);
+ v->nexthop_list = linklist_create ();
+ v->path_list = list_new ();
+ v->parent_list = list_new ();
+ v->distance = 0;
+ v->depth = 0;
+ v->lsa = lsa;
+
+ inet_ntop (AF_INET, &v->vertex_id.adv_router.s_addr,
+ buf_router, sizeof (buf_router));
+ inet_ntop (AF_INET, &v->vertex_id.id.s_addr, buf_id, sizeof (buf_id));
+ snprintf (v->string, sizeof (v->string), "[%s-%s (%d)]",
+ buf_router, buf_id, v->distance);
+
+ nexthop = XCALLOC (MTYPE_OSPF6_VERTEX, sizeof (struct ospf6_nexthop));
+ ifp = if_lookup_by_name ("lo0");
+ if (ifp)
+ nexthop->ifindex = ifp->ifindex;
+ inet_pton (AF_INET6, "::1", &nexthop->address);
+ linklist_add (nexthop, v->nexthop_list);
+ linklist_add (nexthop, nexthop_list);
+
+ o6a->spf_tree->root = v;
+ listnode_add (candidate_list, v);
+
+ ospf6_spf_candidate_enqueue (v);
+}
+
+static struct ospf6_vertex *
+ospf6_spf_get_closest_candidate (list candidate_list)
+{
+ listnode node;
+ struct ospf6_vertex *candidate, *closest;
+
+ closest = (struct ospf6_vertex *) NULL;
+ for (node = listhead (candidate_list); node; nextnode (node))
+ {
+ candidate = (struct ospf6_vertex *) getdata (node);
+
+ if (closest && candidate->distance > closest->distance)
+ continue;
+
+ /* always choose network vertices if those're the same cost */
+ if (closest && candidate->distance == closest->distance
+ && closest->vertex_id.id.s_addr != 0)
+ continue;
+
+ closest = candidate;
+ }
+
+ return closest;
+}
+
+static struct ospf6_vertex *
+ospf6_spf_get_same_candidate (struct ospf6_vertex *w, list candidate_list)
+{
+ listnode node;
+ struct ospf6_vertex *c, *same;
+
+ same = (struct ospf6_vertex *) NULL;
+ for (node = listhead (candidate_list); node; nextnode (node))
+ {
+ c = (struct ospf6_vertex *) getdata (node);
+ if (w->vertex_id.adv_router.s_addr != c->vertex_id.adv_router.s_addr)
+ continue;
+ if (w->vertex_id.id.s_addr != c->vertex_id.id.s_addr)
+ continue;
+
+ if (same)
+ zlog_warn ("SPF: duplicate candidates in candidate_list");
+
+ same = c;
+ }
+
+ return same;
+}
+
+static void
+ospf6_spf_install (struct ospf6_vertex *vertex, struct ospf6_area *o6a)
+{
+ listnode node;
+ struct ospf6_vertex *parent;
+ struct ospf6_nexthop *nexthop;
+ struct ospf6_route_req request;
+ struct linklist_node lnode;
+
+ struct ospf6_router_lsa *router_lsa;
+ struct ospf6_network_lsa *network_lsa;
+
+ router_lsa = OSPF6_LSA_HEADER_END (vertex->lsa->header);
+ network_lsa = OSPF6_LSA_HEADER_END (vertex->lsa->header);
+
+ if (IS_OSPF6_DUMP_SPF)
+ {
+ zlog_info ("SPF: Install: %s", vertex->string);
+ }
+
+ listnode_add (o6a->spf_tree->list, vertex);
+
+ for (node = listhead (vertex->parent_list); node; nextnode (node))
+ {
+ parent = (struct ospf6_vertex *) getdata (node);
+ listnode_add (parent->path_list, vertex);
+ vertex->depth = parent->depth + 1;
+ }
+
+#if 0
+ if (vertex == o6a->spf_tree->root)
+ return;
+#endif /*0*/
+
+ /* install route to topology table */
+ memset (&request, 0, sizeof (request));
+ if (vertex->vertex_id.id.s_addr) /* xxx */
+ request.route.type = OSPF6_DEST_TYPE_NETWORK;
+ else
+ request.route.type = OSPF6_DEST_TYPE_ROUTER;
+ memcpy (&request.route.prefix, &vertex->vertex_id,
+ sizeof (struct prefix));
+
+ request.path.area_id = o6a->area_id;
+ request.path.type = OSPF6_PATH_TYPE_INTRA;
+ request.path.cost = vertex->distance;
+ request.path.cost_e2 = 0;
+ request.path.origin.type = vertex->lsa->header->type;
+ request.path.origin.id = vertex->lsa->header->id;
+ request.path.origin.adv_router = vertex->lsa->header->adv_router;
+ if (vertex->lsa->header->type == htons (OSPF6_LSA_TYPE_ROUTER))
+ request.path.router_bits = router_lsa->bits;
+ memcpy (&request.path.capability, vertex->opt_capability,
+ sizeof (request.path.capability));
+
+#if 0
+ if (IS_OSPF6_DUMP_SPF)
+ zlog_info ("SPF: install %d nexthops for %s",
+ listcount (vertex->nexthop_list), vertex->string);
+#endif
+
+ for (linklist_head (vertex->nexthop_list, &lnode); ! linklist_end (&lnode);
+ linklist_next (&lnode))
+ {
+ nexthop = lnode.data;
+
+ request.nexthop.ifindex = nexthop->ifindex;
+ memcpy (&request.nexthop.address, &nexthop->address,
+ sizeof (request.nexthop.address));
+
+ ospf6_route_add (&request, o6a->table_topology);
+ }
+}
+
+struct ospf6_vertex *
+ospf6_spf_lookup (struct ospf6_vertex *w, struct ospf6_area *o6a)
+{
+ listnode node;
+ struct ospf6_vertex *v;
+
+ for (node = listhead (o6a->spf_tree->list); node; nextnode (node))
+ {
+ v = (struct ospf6_vertex *) getdata (node);
+
+ if (w->vertex_id.adv_router.s_addr != v->vertex_id.adv_router.s_addr)
+ continue;
+ if (w->vertex_id.id.s_addr != v->vertex_id.id.s_addr)
+ continue;
+
+ return v;
+ }
+
+ return (struct ospf6_vertex *) NULL;
+}
+
+u_int32_t stat_node = 0;
+u_int32_t stat_candidate = 0;
+u_int32_t stat_candidate_max = 0;
+u_int32_t stat_spf = 0;
+
+
+/* RFC2328 section 16.1 , RFC2740 section 3.8.1 */
+static int
+ospf6_spf_calculation (struct ospf6_area *o6a)
+{
+ list candidate_list;
+ struct ospf6_vertex *V, *W, *X;
+ int ldnum, i;
+
+ if (! o6a || ! o6a->spf_tree)
+ {
+ zlog_err ("SPF: Can't calculate SPF tree: malformed area");
+ return -1;
+ }
+
+ stat_spf ++;
+ stat_node = 0;
+ stat_candidate = 0;
+ stat_candidate_max = 0;
+
+ if (IS_OSPF6_DUMP_SPF)
+ zlog_info ("SPF: Calculation for area %s", o6a->str);
+
+ ospf6_route_table_freeze (o6a->table_topology);
+ ospf6_route_remove_all (o6a->table_topology);
+
+ /* (1): Initialize the algorithm's data structures */
+ candidate_list = list_new ();
+ ospf6_spf_initialize (candidate_list, o6a);
+ stat_candidate ++;
+
+ /* (3): Install closest from candidate list; if empty, break */
+ while (listcount (candidate_list))
+ {
+ V = ospf6_spf_get_closest_candidate (candidate_list);
+ listnode_delete (candidate_list, V);
+
+ {
+ struct ospf6_vertex *V_;
+
+ if (stat_candidate_max < ospf6_spf_candidate_count ())
+ stat_candidate_max = ospf6_spf_candidate_count ();
+
+ V_ = ospf6_spf_candidate_dequeue ();
+
+#if 0
+ if (IS_OSPF6_DUMP_SPF)
+ {
+ zlog_info ("Candidate list count: %lu",
+ (u_long)ospf6_spf_candidate_count ());
+ zlog_info ("*** Candidate %s: %p <-> %p",
+ (V == V_ ? "same" : "*** differ ***"), V, V_);
+ zlog_info (" %p: %s", V, V->string);
+ zlog_info (" %p: %s", V_, V_->string);
+ }
+#endif
+
+ }
+
+ stat_node++;
+ ospf6_spf_install (V, o6a);
+
+ /* (2): Examin LSA of just added vertex */
+ ldnum = ospf6_spf_lsd_num (V, o6a);
+ for (i = 0; i < ldnum; i++)
+ {
+ /* (b): If no LSA, or MaxAge, or LinkBack fail, examin next */
+ W = ospf6_spf_vertex_create (i, V, o6a);
+ if (! W)
+ continue;
+
+ stat_candidate ++;
+
+ /* (c) */
+ if (ospf6_spf_lookup (W, o6a))
+ {
+ if (IS_OSPF6_DUMP_SPF)
+ zlog_info ("SPF: %s: Already in SPF tree", W->string);
+ ospf6_spf_vertex_delete (W);
+ continue;
+ }
+
+ /* (d) */
+ X = ospf6_spf_get_same_candidate (W, candidate_list);
+ if (X && X->distance < W->distance)
+ {
+ if (IS_OSPF6_DUMP_SPF)
+ zlog_info ("SPF: %s: More closer found", W->string);
+ ospf6_spf_vertex_delete (W);
+ continue;
+ }
+ if (X && X->distance == W->distance)
+ {
+ if (IS_OSPF6_DUMP_SPF)
+ zlog_info ("SPF: %s: new ECMP candidate", W->string);
+ ospf6_spf_vertex_merge (W, X);
+ ospf6_spf_vertex_delete (W);
+ continue;
+ }
+
+ if (X)
+ {
+ if (IS_OSPF6_DUMP_SPF)
+ zlog_info ("SPF: %s: Swap with old candidate", W->string);
+ listnode_delete (candidate_list, X);
+ ospf6_spf_candidate_remove (X);
+ ospf6_spf_vertex_delete (X);
+ }
+ else
+ {
+ if (IS_OSPF6_DUMP_SPF)
+ zlog_info ("SPF: %s: New Candidate", W->string);
+ }
+
+ if (stat_candidate_max < ospf6_spf_candidate_count ())
+ stat_candidate_max = ospf6_spf_candidate_count ();
+
+ listnode_add (candidate_list, W);
+ ospf6_spf_candidate_enqueue (W);
+ }
+ }
+
+ assert (listcount (candidate_list) == 0);
+ list_free (candidate_list);
+ assert (ospf6_spf_candidate_count () == 0);
+
+ /* Clear thread timer */
+ o6a->spf_tree->t_spf_calculation = (struct thread *) NULL;
+
+ if (IS_OSPF6_DUMP_SPF)
+ {
+ zlog_info ("SPF: Calculation for area %s done", o6a->str);
+ zlog_info ("SPF: Statistics: %luth", (u_long)stat_spf);
+ zlog_info ("SPF: Node Number: %lu", (u_long)stat_node);
+ zlog_info ("SPF: Candidate Number: %lu Max: %lu",
+ (u_long) stat_candidate, (u_long) stat_candidate_max);
+ }
+
+ ospf6_route_table_thaw (o6a->table_topology);
+ return 0;
+}
+
+int
+ospf6_spf_calculation_thread (struct thread *t)
+{
+ struct ospf6_area *o6a;
+ struct timeval start, end, runtime, interval;
+
+ o6a = (struct ospf6_area *) THREAD_ARG (t);
+ if (! o6a)
+ {
+ zlog_err ("SPF: Thread error");
+ return -1;
+ }
+
+ if (! o6a->spf_tree)
+ {
+ zlog_err ("SPF: Can't find SPF Tree for area: %s", o6a->str);
+ return -1;
+ }
+
+ /* execute SPF calculation */
+ gettimeofday (&start, (struct timezone *) NULL);
+ ospf6_spf_calculation (o6a);
+ gettimeofday (&end, (struct timezone *) NULL);
+
+ /* update statistics */
+ o6a->spf_tree->timerun ++;
+ ospf6_timeval_sub (&end, &start, &runtime);
+ ospf6_timeval_add_equal (&runtime, &o6a->spf_tree->runtime_total);
+
+ if (o6a->spf_tree->timerun == 1)
+ {
+ o6a->spf_tree->runtime_min.tv_sec = runtime.tv_sec;
+ o6a->spf_tree->runtime_min.tv_usec = runtime.tv_usec;
+ o6a->spf_tree->runtime_max.tv_sec = runtime.tv_sec;
+ o6a->spf_tree->runtime_max.tv_usec = runtime.tv_usec;
+ }
+ if (ospf6_timeval_cmp (o6a->spf_tree->runtime_min, runtime) > 0)
+ {
+ o6a->spf_tree->runtime_min.tv_sec = runtime.tv_sec;
+ o6a->spf_tree->runtime_min.tv_usec = runtime.tv_usec;
+ }
+ if (ospf6_timeval_cmp (runtime, o6a->spf_tree->runtime_max) > 0)
+ {
+ o6a->spf_tree->runtime_max.tv_sec = runtime.tv_sec;
+ o6a->spf_tree->runtime_max.tv_usec = runtime.tv_usec;
+ }
+
+ if (o6a->spf_tree->timerun == 1)
+ {
+ ospf6_timeval_sub (&start, &ospf6->starttime, &interval);
+ ospf6_timeval_add_equal (&interval, &o6a->spf_tree->interval_total);
+ o6a->spf_tree->interval_min.tv_sec = interval.tv_sec;
+ o6a->spf_tree->interval_min.tv_usec = interval.tv_usec;
+ o6a->spf_tree->interval_max.tv_sec = interval.tv_sec;
+ o6a->spf_tree->interval_max.tv_usec = interval.tv_usec;
+ }
+ else
+ {
+ ospf6_timeval_sub (&start, &o6a->spf_tree->updated_time, &interval);
+ ospf6_timeval_add_equal (&interval, &o6a->spf_tree->interval_total);
+ if (ospf6_timeval_cmp (o6a->spf_tree->interval_min, interval) > 0)
+ {
+ o6a->spf_tree->interval_min.tv_sec = interval.tv_sec;
+ o6a->spf_tree->interval_min.tv_usec = interval.tv_usec;
+ }
+ if (ospf6_timeval_cmp (interval, o6a->spf_tree->interval_max) > 0)
+ {
+ o6a->spf_tree->interval_max.tv_sec = interval.tv_sec;
+ o6a->spf_tree->interval_max.tv_usec = interval.tv_usec;
+ }
+ }
+ o6a->spf_tree->updated_time.tv_sec = end.tv_sec;
+ o6a->spf_tree->updated_time.tv_usec = end.tv_usec;
+
+ /* clear thread */
+ o6a->spf_tree->t_spf_calculation = (struct thread *) NULL;
+
+ return 0;
+}
+
+void
+ospf6_spf_database_hook (struct ospf6_lsa *old, struct ospf6_lsa *new)
+{
+ struct ospf6_area *o6a = NULL;
+ struct ospf6_interface *o6i = NULL;
+
+ if (new->header->type == htons (OSPF6_LSA_TYPE_ROUTER) ||
+ new->header->type == htons (OSPF6_LSA_TYPE_NETWORK))
+ o6a = new->scope;
+ else if (new->header->type == htons (OSPF6_LSA_TYPE_LINK))
+ {
+ o6i = new->scope;
+ o6a = o6i->area;
+ }
+
+ if (o6a)
+ ospf6_spf_calculation_schedule (o6a->area_id);
+}
+
+void
+ospf6_spf_calculation_schedule (u_int32_t area_id)
+{
+ struct ospf6_area *o6a;
+ char buf[64];
+
+ o6a = ospf6_area_lookup (area_id, ospf6);
+ if (! o6a)
+ {
+ inet_ntop (AF_INET, &area_id, buf, sizeof (buf));
+ zlog_err ("SPF: Can't find area: %s", buf);
+ return;
+ }
+
+ if (! o6a->spf_tree)
+ {
+ zlog_err ("SPF: Can't find SPF Tree for area: %s", o6a->str);
+ return;
+ }
+
+ if (o6a->spf_tree->t_spf_calculation)
+ return;
+
+ o6a->spf_tree->t_spf_calculation =
+ thread_add_event (master, ospf6_spf_calculation_thread, o6a, 0);
+}
+
+struct ospf6_spftree *
+ospf6_spftree_create ()
+{
+ struct ospf6_spftree *spf_tree;
+ spf_tree = (struct ospf6_spftree *) XMALLOC (MTYPE_OSPF6_SPFTREE,
+ sizeof (struct ospf6_spftree));
+ if (! spf_tree)
+ {
+ zlog_err ("SPF: Can't allocate memory for SPF tree");
+ return (struct ospf6_spftree *) NULL;
+ }
+ memset (spf_tree, 0, sizeof (spf_tree));
+
+ spf_tree->list = list_new ();
+
+ return spf_tree;
+}
+
+void
+ospf6_spftree_delete (struct ospf6_spftree *spf_tree)
+{
+ listnode node;
+ struct ospf6_vertex *v;
+
+ /* Delete spf tree */
+ for (node = listhead (spf_tree->list); node; nextnode (node))
+ {
+ v = (struct ospf6_vertex *) getdata (node);
+ ospf6_spf_vertex_delete (v);
+ }
+ list_delete_all_node (spf_tree->list);
+
+ XFREE (MTYPE_OSPF6_SPFTREE, spf_tree);
+}
+
+void
+ospf6_nexthop_show (struct vty *vty, struct ospf6_nexthop *nexthop)
+{
+ char buf[128], *ifname;
+ struct ospf6_interface *o6i;
+
+ ifname = NULL;
+
+ o6i = ospf6_interface_lookup_by_index (nexthop->ifindex);
+ if (! o6i)
+ {
+ zlog_err ("Spf: invalid ifindex %d in nexthop", nexthop->ifindex);
+ }
+ else
+ ifname = o6i->interface->name;
+
+ inet_ntop (AF_INET6, &nexthop->address, buf, sizeof (buf));
+ vty_out (vty, " %s%%%s(%d)%s", buf, ifname,
+ nexthop->ifindex, VTY_NEWLINE);
+}
+
+void
+ospf6_vertex_show (struct vty *vty, struct ospf6_vertex *vertex)
+{
+ listnode node;
+ struct ospf6_vertex *v;
+ struct linklist_node lnode;
+
+ vty_out (vty, "SPF node %s%s", vertex->string, VTY_NEWLINE);
+ vty_out (vty, " cost to this node: %d%s", vertex->distance, VTY_NEWLINE);
+ vty_out (vty, " hops to this node: %d%s", vertex->depth, VTY_NEWLINE);
+
+ vty_out (vty, " nexthops reachable to this node:%s", VTY_NEWLINE);
+ for (linklist_head (vertex->nexthop_list, &lnode);
+ ! linklist_end (&lnode);
+ linklist_next (&lnode))
+ ospf6_nexthop_show (vty, (struct ospf6_nexthop *) lnode.data);
+
+ vty_out (vty, " parent nodes to this node:%s", VTY_NEWLINE);
+ if (! list_isempty (vertex->parent_list))
+ vty_out (vty, " ");
+ for (node = listhead (vertex->parent_list); node; nextnode (node))
+ {
+ v = (struct ospf6_vertex *) getdata (node);
+ vty_out (vty, "%s ", v->string);
+ }
+ if (! list_isempty (vertex->parent_list))
+ vty_out (vty, "%s", VTY_NEWLINE);
+
+ vty_out (vty, " child nodes to this node:%s", VTY_NEWLINE);
+ if (! list_isempty (vertex->path_list))
+ vty_out (vty, " ");
+ for (node = listhead (vertex->path_list); node; nextnode (node))
+ {
+ v = (struct ospf6_vertex *) getdata (node);
+ vty_out (vty, "%s ", v->string);
+ }
+ if (! list_isempty (vertex->path_list))
+ vty_out (vty, "%s", VTY_NEWLINE);
+
+ vty_out (vty, "%s", VTY_NEWLINE);
+}
+
+void
+ospf6_spf_statistics_show (struct vty *vty, struct ospf6_spftree *spf_tree)
+{
+ listnode node;
+ struct ospf6_vertex *vertex;
+ u_int router_count, network_count, maxdepth;
+ struct timeval runtime_avg, interval_avg, last_updated, now;
+ char rmin[64], rmax[64], ravg[64];
+ char imin[64], imax[64], iavg[64];
+ char last_updated_string[64];
+
+ maxdepth = router_count = network_count = 0;
+ for (node = listhead (spf_tree->list); node; nextnode (node))
+ {
+ vertex = (struct ospf6_vertex *) getdata (node);
+ if (vertex->vertex_id.id.s_addr)
+ network_count++;
+ else
+ router_count++;
+ if (maxdepth < vertex->depth)
+ maxdepth = vertex->depth;
+ }
+
+ ospf6_timeval_div (&spf_tree->runtime_total, spf_tree->timerun,
+ &runtime_avg);
+ ospf6_timeval_string (&spf_tree->runtime_min, rmin, sizeof (rmin));
+ ospf6_timeval_string (&spf_tree->runtime_max, rmax, sizeof (rmax));
+ ospf6_timeval_string (&runtime_avg, ravg, sizeof (ravg));
+
+ ospf6_timeval_div (&spf_tree->interval_total, spf_tree->timerun,
+ &interval_avg);
+ ospf6_timeval_string (&spf_tree->interval_min, imin, sizeof (imin));
+ ospf6_timeval_string (&spf_tree->interval_max, imax, sizeof (imax));
+ ospf6_timeval_string (&interval_avg, iavg, sizeof (iavg));
+
+ gettimeofday (&now, (struct timezone *) NULL);
+ ospf6_timeval_sub (&now, &spf_tree->updated_time, &last_updated);
+ ospf6_timeval_string (&last_updated, last_updated_string,
+ sizeof (last_updated_string));
+
+ vty_out (vty, " SPF algorithm executed %d times%s",
+ spf_tree->timerun, VTY_NEWLINE);
+ vty_out (vty, " Average time to run SPF: %s%s",
+ ravg, VTY_NEWLINE);
+ vty_out (vty, " Maximum time to run SPF: %s%s",
+ rmax, VTY_NEWLINE);
+ vty_out (vty, " Average interval of SPF: %s%s",
+ iavg, VTY_NEWLINE);
+ vty_out (vty, " SPF last updated: %s ago%s",
+ last_updated_string, VTY_NEWLINE);
+ vty_out (vty, " Current SPF node count: %d%s",
+ listcount (spf_tree->list), VTY_NEWLINE);
+ vty_out (vty, " Router: %d Network: %d%s",
+ router_count, network_count, VTY_NEWLINE);
+ vty_out (vty, " Maximum of Hop count to nodes: %d%s",
+ maxdepth, VTY_NEWLINE);
+}
+
+DEFUN (show_ipv6_ospf6_area_spf_node,
+ show_ipv6_ospf6_area_spf_node_cmd,
+ "show ipv6 ospf6 area A.B.C.D spf node",
+ SHOW_STR
+ IP6_STR
+ OSPF6_STR
+ OSPF6_AREA_STR
+ OSPF6_AREA_ID_STR
+ "Shortest Path First caculation\n"
+ "vertex infomation\n"
+ )
+{
+ listnode i;
+ u_int32_t area_id;
+ struct ospf6_area *o6a;
+ struct ospf6_vertex *vertex;
+
+ OSPF6_CMD_CHECK_RUNNING ();
+
+ inet_pton (AF_INET, argv[0], &area_id);
+ o6a = ospf6_area_lookup (area_id, ospf6);
+ if (! o6a)
+ return CMD_SUCCESS;
+
+ for (i = listhead (o6a->spf_tree->list); i; nextnode (i))
+ {
+ vertex = (struct ospf6_vertex *) getdata (i);
+ ospf6_vertex_show (vty, vertex);
+ }
+
+ return CMD_SUCCESS;
+}
+
+static void
+ospf6_spftree_show (struct vty *vty, char *prefix, int current_rest,
+ struct ospf6_vertex *v)
+{
+ char *p;
+ int psize;
+ int restnum;
+ listnode node;
+
+ vty_out (vty, "%s+-%s%s", prefix, v->string, VTY_NEWLINE);
+
+ if (listcount (v->path_list) == 0)
+ return;
+
+ psize = strlen (prefix) + 3;
+ p = malloc (psize);
+ if (!p)
+ {
+ vty_out (vty, "depth too long ...%s", VTY_NEWLINE);
+ return;
+ }
+
+ restnum = listcount (v->path_list);
+ for (node = listhead (v->path_list); node; nextnode (node))
+ {
+ --restnum;
+ snprintf (p, psize, "%s%s", prefix, (current_rest ? "| " : " "));
+ ospf6_spftree_show (vty, p, restnum,
+ (struct ospf6_vertex *) getdata (node));
+ }
+
+ free (p);
+}
+
+DEFUN (show_ipv6_ospf6_area_spf_tree,
+ show_ipv6_ospf6_area_spf_tree_cmd,
+ "show ipv6 ospf6 area A.B.C.D spf tree",
+ SHOW_STR
+ IP6_STR
+ OSPF6_STR
+ OSPF6_AREA_STR
+ OSPF6_AREA_ID_STR
+ "Shortest Path First caculation\n"
+ "Displays spf tree\n")
+{
+ u_int32_t area_id;
+ struct ospf6_area *o6a;
+
+ OSPF6_CMD_CHECK_RUNNING ();
+
+ inet_pton (AF_INET, argv[0], &area_id);
+ o6a = ospf6_area_lookup (area_id, ospf6);
+ if (! o6a)
+ return CMD_SUCCESS;
+
+ vty_out (vty, "%s SPF tree for Area %s%s%s",
+ VTY_NEWLINE, o6a->str, VTY_NEWLINE, VTY_NEWLINE);
+
+ if (! o6a->spf_tree->root)
+ return CMD_SUCCESS;
+
+ ospf6_spftree_show (vty, "", 0, o6a->spf_tree->root);
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ipv6_ospf6_area_topology,
+ show_ipv6_ospf6_area_topology_cmd,
+ "show ipv6 ospf6 area A.B.C.D topology",
+ SHOW_STR
+ IP6_STR
+ OSPF6_STR
+ OSPF6_AREA_STR
+ OSPF6_AREA_ID_STR
+ OSPF6_SPF_STR
+ "Displays SPF topology table\n")
+{
+ struct ospf6_area *o6a;
+ u_int32_t area_id;
+
+ OSPF6_CMD_CHECK_RUNNING ();
+
+ inet_pton (AF_INET, argv[0], &area_id);
+ o6a = ospf6_area_lookup (area_id, ospf6);
+
+ if (! o6a)
+ return CMD_SUCCESS;
+
+ argc -= 1;
+ argv += 1;
+
+ return ospf6_route_table_show (vty, argc, argv, o6a->table_topology);
+}
+
+ALIAS (show_ipv6_ospf6_area_topology,
+ show_ipv6_ospf6_area_topology_router_cmd,
+ "show ipv6 ospf6 area A.B.C.D topology (A.B.C.D|<0-4294967295>|detail)",
+ SHOW_STR
+ IP6_STR
+ OSPF6_STR
+ OSPF6_AREA_STR
+ OSPF6_AREA_ID_STR
+ OSPF6_SPF_STR
+ "Displays SPF topology table\n"
+ OSPF6_ROUTER_ID_STR
+ OSPF6_ROUTER_ID_STR
+ )
+
+ALIAS (show_ipv6_ospf6_area_topology,
+ show_ipv6_ospf6_area_topology_router_lsid_cmd,
+ "show ipv6 ospf6 area A.B.C.D topology (A.B.C.D|<0-4294967295>) (A.B.C.D|<0-4294967295>)",
+ SHOW_STR
+ IP6_STR
+ OSPF6_STR
+ OSPF6_AREA_STR
+ OSPF6_AREA_ID_STR
+ OSPF6_SPF_STR
+ "Displays SPF topology table\n"
+ OSPF6_ROUTER_ID_STR
+ OSPF6_ROUTER_ID_STR
+ OSPF6_LS_ID_STR
+ OSPF6_LS_ID_STR
+ )
+
+void
+ospf6_spf_init ()
+{
+ nexthop_list = linklist_create ();
+ ospf6_spf_candidate_init ();
+ install_element (VIEW_NODE, &show_ipv6_ospf6_area_spf_node_cmd);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_area_spf_tree_cmd);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_area_topology_cmd);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_area_topology_router_cmd);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_area_topology_router_lsid_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_area_spf_node_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_area_spf_tree_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_area_topology_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_area_topology_router_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_area_topology_router_lsid_cmd);
+}
+
diff --git a/ospf6d/ospf6_spf.h b/ospf6d/ospf6_spf.h
new file mode 100644
index 00000000..de50e94a
--- /dev/null
+++ b/ospf6d/ospf6_spf.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef OSPF6_SPF_H
+#define OSPF6_SPF_H
+
+#include "prefix.h"
+
+/* Transit Vertex */
+struct ospf6_vertex
+{
+ /* type of this vertex */
+ u_int8_t type;
+
+ /* Vertex Identifier */
+ struct prefix_ls vertex_id;
+
+ /* Identifier String */
+ char string[128];
+
+ /* Associated LSA */
+ struct ospf6_lsa *lsa;
+
+ /* Distance from Root (Cost) */
+ u_int16_t distance;
+
+ /* Depth of this node */
+ u_char depth;
+
+ /* nexthops to this node */
+ struct linklist *nexthop_list;
+
+ /* upper nodes in spf tree */
+ list parent_list;
+
+ /* lower nodes in spf tree */
+ list path_list;
+
+ /* capability bits */
+ u_char capability_bits;
+
+ /* Optional capabilities */
+ u_char opt_capability[3];
+};
+
+#define OSPF6_VERTEX_TYPE_ROUTER 0x01
+#define OSPF6_VERTEX_TYPE_NETWORK 0x02
+
+struct ospf6_spftree
+{
+ /* calculation thread */
+ struct thread *t_spf_calculation;
+
+ /* root of this tree */
+ struct ospf6_vertex *root;
+
+ /* list for search */
+ list list;
+
+ /* statistics */
+ u_int32_t timerun;
+
+ struct timeval runtime_total;
+ struct timeval runtime_min;
+ struct timeval runtime_max;
+
+ struct timeval updated_time;
+ struct timeval interval_total;
+ struct timeval interval_min;
+ struct timeval interval_max;
+};
+
+int ospf6_spf_calculate_route (void *);
+
+void
+ospf6_spf_calculation_schedule (u_int32_t area_id);
+struct ospf6_spftree *ospf6_spftree_create ();
+void
+ospf6_spf_statistics_show (struct vty *vty, struct ospf6_spftree *spf_tree);
+void ospf6_spftree_delete (struct ospf6_spftree *spf_tree);
+
+void ospf6_spf_database_hook (struct ospf6_lsa *old, struct ospf6_lsa *new);
+
+void ospf6_spf_init ();
+
+#endif /* OSPF6_SPF_H */
+
diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c
new file mode 100644
index 00000000..a8a058f2
--- /dev/null
+++ b/ospf6d/ospf6_top.c
@@ -0,0 +1,401 @@
+/*
+ * OSPFv3 Top Level Data Structure
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "log.h"
+#include "memory.h"
+#include "vty.h"
+#include "linklist.h"
+#include "prefix.h"
+#include "table.h"
+#include "thread.h"
+#include "command.h"
+
+#include "ospf6_hook.h"
+#include "ospf6_proto.h"
+#include "ospf6_prefix.h"
+#include "ospf6_lsa.h"
+#include "ospf6_lsdb.h"
+
+#include "ospf6_message.h"
+#include "ospf6_neighbor.h"
+#include "ospf6_interface.h"
+#include "ospf6_area.h"
+#include "ospf6_top.h"
+
+#include "ospf6_route.h"
+#include "ospf6_zebra.h"
+
+#include "ospf6_nsm.h"
+#include "ospf6_asbr.h"
+#include "ospf6_abr.h"
+
+#define HEADER_DEPENDENCY
+#include "ospf6d.h"
+#undef HEADER_DEPENDENCY
+
+/* global ospf6d variable */
+struct ospf6 *ospf6;
+
+static void
+ospf6_top_foreach_area (struct ospf6 *o6, void *arg, int val,
+ void (*func) (void *, int, void *))
+{
+ listnode node;
+ struct ospf6_area *o6a;
+
+ for (node = listhead (o6->area_list); node; nextnode (node))
+ {
+ o6a = (struct ospf6_area *) getdata (node);
+ (*func) (arg, val, o6a);
+ }
+}
+
+static void
+ospf6_top_foreach_interface (struct ospf6 *o6, void *arg, int val,
+ void (*func) (void *, int, void *))
+{
+ listnode node;
+ struct ospf6_area *o6a;
+
+ for (node = listhead (o6->area_list); node; nextnode (node))
+ {
+ o6a = (struct ospf6_area *) getdata (node);
+ (*o6a->foreach_if) (o6a, arg, val, func);
+ }
+}
+
+static void
+ospf6_top_foreach_neighbor (struct ospf6 *o6, void *arg, int val,
+ void (*func) (void *, int, void *))
+{
+ listnode node;
+ struct ospf6_area *o6a;
+
+ for (node = listhead (o6->area_list); node; nextnode (node))
+ {
+ o6a = (struct ospf6_area *) getdata (node);
+ (*o6a->foreach_nei) (o6a, arg, val, func);
+ }
+}
+
+static int
+ospf6_top_maxage_remover (struct thread *t)
+{
+ int count;
+ struct ospf6 *o6 = (struct ospf6 *) THREAD_ARG (t);
+
+ o6->maxage_remover = (struct thread *) NULL;
+
+ count = 0;
+ o6->foreach_nei (o6, &count, NBS_EXCHANGE, ospf6_count_state);
+ o6->foreach_nei (o6, &count, NBS_LOADING, ospf6_count_state);
+ if (count != 0)
+ return 0;
+
+ ospf6_lsdb_remove_maxage (o6->lsdb);
+ return 0;
+}
+
+void
+ospf6_top_schedule_maxage_remover (void *arg, int val, struct ospf6 *o6)
+{
+ if (o6->maxage_remover != NULL)
+ return;
+
+ o6->maxage_remover =
+ thread_add_event (master, ospf6_top_maxage_remover, o6, 0);
+}
+
+void
+ospf6_show (struct vty *vty)
+{
+ listnode n;
+ struct ospf6_area *area;
+ char id_string[32];
+ unsigned long day, hour, min, sec;
+ struct timeval now, running;
+
+ /* process id, router id */
+ inet_ntop (AF_INET, &ospf6->router_id, id_string, sizeof (id_string));
+ vty_out (vty, " Routing Process (%lu) with ID %s%s",
+ ospf6->process_id, id_string, VTY_NEWLINE);
+
+ /* running time */
+ gettimeofday (&now, (struct timezone *)NULL);
+ ospf6_timeval_sub (&now, &ospf6->starttime, &running);
+ ospf6_timeval_decode (&running, &day, &hour, &min, &sec, NULL, NULL);
+ vty_out (vty, " Running %ld days %ld hours %ld minutes %ld seconds%s",
+ day, hour, min, sec, VTY_NEWLINE);
+
+ vty_out (vty, " Supports only single TOS(TOS0) routes%s", VTY_NEWLINE);
+
+ /* Redistribute config */
+ ospf6_redistribute_show_config (vty);
+
+ /* LSAs */
+ vty_out (vty, " Number of AS scoped LSAs is %u%s",
+ ospf6->lsdb->count, VTY_NEWLINE);
+ vty_out (vty, " Route calculation executed %d times%s",
+ ospf6->stat_route_calculation_execed, VTY_NEWLINE);
+
+ /* Route Statistics */
+#if 0
+ ospf6_route_statistics_show (vty, ospf6->route_table);
+#endif
+
+ /* Areas */
+ vty_out (vty, " Number of areas in this router is %u%s",
+ listcount (ospf6->area_list), VTY_NEWLINE);
+ for (n = listhead (ospf6->area_list); n; nextnode (n))
+ {
+ area = (struct ospf6_area *) getdata (n);
+ ospf6_area_show (vty, area);
+ }
+}
+
+void
+ospf6_statistics_show (struct vty *vty, struct ospf6 *o6)
+{
+ listnode node;
+ struct ospf6_area *o6a;
+ char running_time[128];
+ struct timeval now, running;
+
+ gettimeofday (&now, (struct timezone *) NULL);
+ ospf6_timeval_sub (&now, &o6->starttime, &running);
+ ospf6_timeval_string (&running, running_time, sizeof (running_time));
+
+ vty_out (vty, "Statistics of OSPF process %ld%s",
+ o6->process_id, VTY_NEWLINE);
+ vty_out (vty, " Running: %s%s", running_time, VTY_NEWLINE);
+
+#if 0
+ ospf6_route_statistics_show (vty, o6->route_table);
+#endif
+
+ for (node = listhead (o6->area_list); node; nextnode (node))
+ {
+ o6a = (struct ospf6_area *) getdata (node);
+ ospf6_area_statistics_show (vty, o6a);
+ }
+}
+
+static struct ospf6 *
+ospf6_new ()
+{
+ struct ospf6 *new;
+ new = XMALLOC (MTYPE_OSPF6_TOP, sizeof (struct ospf6));
+ if (new)
+ memset (new, 0, sizeof (struct ospf6));
+ return new;
+}
+
+void
+ospf6_free (struct ospf6 *ospf6)
+{
+ XFREE (MTYPE_OSPF6_TOP, ospf6);
+}
+
+void
+ospf6_top_topology_add (struct ospf6_route_req *request)
+{
+ assert (request->route.type == OSPF6_DEST_TYPE_ROUTER);
+ if (CHECK_FLAG (request->path.router_bits, OSPF6_ROUTER_LSA_BIT_E))
+ ospf6_asbr_asbr_entry_add (request);
+}
+
+void
+ospf6_top_topology_remove (struct ospf6_route_req *request)
+{
+ assert (request->route.type == OSPF6_DEST_TYPE_ROUTER);
+ if (CHECK_FLAG (request->path.router_bits, OSPF6_ROUTER_LSA_BIT_E))
+ ospf6_asbr_asbr_entry_remove (request);
+}
+
+struct ospf6 *
+ospf6_create (unsigned long process_id)
+{
+ struct ospf6 *o6;
+ char namebuf[64];
+
+ o6 = ospf6_new ();
+
+ /* initialize */
+ gettimeofday (&o6->starttime, (struct timezone *)NULL);
+ o6->process_id = process_id;
+ o6->version = OSPF6_VERSION;
+ o6->area_list = list_new ();
+
+ o6->lsdb = ospf6_lsdb_create ();
+
+ o6->foreach_area = ospf6_top_foreach_area;
+ o6->foreach_if = ospf6_top_foreach_interface;
+ o6->foreach_nei = ospf6_top_foreach_neighbor;
+
+ snprintf (namebuf, sizeof (namebuf), "InterTopology table");
+ o6->topology_table = ospf6_route_table_create (namebuf);
+ ospf6_route_hook_register (ospf6_top_topology_add,
+ ospf6_top_topology_add,
+ ospf6_top_topology_remove,
+ o6->topology_table);
+
+#if 0
+ snprintf (namebuf, sizeof (namebuf), "External table");
+ o6->external_table = ospf6_route_table_create (namebuf);
+ ospf6_route_hook_register (ospf6_asbr_external_route_add,
+ ospf6_asbr_external_route_add,
+ ospf6_asbr_external_route_remove,
+ o6->external_table);
+#endif /*0*/
+
+ snprintf (namebuf, sizeof (namebuf), "Top route table");
+ o6->route_table = ospf6_route_table_create (namebuf);
+ ospf6_route_hook_register (ospf6_zebra_route_update_add,
+ ospf6_zebra_route_update_add,
+ ospf6_zebra_route_update_remove,
+ o6->route_table);
+ ospf6_route_hook_register (ospf6_abr_route_add,
+ ospf6_abr_route_add,
+ ospf6_abr_route_remove,
+ o6->route_table);
+
+ return o6;
+}
+
+void
+ospf6_delete (struct ospf6 *ospf6)
+{
+ ospf6_route_remove_all (ospf6->route_table);
+ ospf6_free (ospf6);
+}
+
+struct ospf6 *
+ospf6_start ()
+{
+ if (ospf6)
+ return ospf6;
+
+ ospf6 = ospf6_create (0);
+ return ospf6;
+}
+
+void
+ospf6_stop ()
+{
+ if (!ospf6)
+ return;
+
+ ospf6_delete (ospf6);
+ ospf6 = NULL;
+}
+
+int
+ospf6_is_asbr (struct ospf6 *o6)
+{
+ int i = 0;
+ i |= ospf6_zebra_is_redistribute (ZEBRA_ROUTE_SYSTEM);
+ i |= ospf6_zebra_is_redistribute (ZEBRA_ROUTE_CONNECT);
+ i |= ospf6_zebra_is_redistribute (ZEBRA_ROUTE_STATIC);
+ i |= ospf6_zebra_is_redistribute (ZEBRA_ROUTE_KERNEL);
+ i |= ospf6_zebra_is_redistribute (ZEBRA_ROUTE_RIPNG);
+ i |= ospf6_zebra_is_redistribute (ZEBRA_ROUTE_BGP);
+ return (i);
+}
+
+DEFUN (show_ipv6_ospf6_route,
+ show_ipv6_ospf6_route_cmd,
+ "show ipv6 ospf6 route",
+ SHOW_STR
+ IP6_STR
+ OSPF6_STR
+ "Routing table\n"
+ )
+{
+ OSPF6_CMD_CHECK_RUNNING ();
+ return ospf6_route_table_show (vty, argc, argv, ospf6->route_table);
+}
+
+ALIAS (show_ipv6_ospf6_route,
+ show_ipv6_ospf6_route_prefix_cmd,
+ "show ipv6 ospf6 route (X::X|detail)",
+ SHOW_STR
+ IP6_STR
+ OSPF6_STR
+ "Routing table\n"
+ "match IPv6 prefix\n"
+ )
+
+DEFUN (show_ipv6_ospf6_topology,
+ show_ipv6_ospf6_topology_cmd,
+ "show ipv6 ospf6 topology",
+ SHOW_STR
+ IP6_STR
+ OSPF6_STR
+ "Inter Area topology information\n"
+ )
+{
+ OSPF6_CMD_CHECK_RUNNING ();
+ return ospf6_route_table_show (vty, argc, argv, ospf6->topology_table);
+}
+
+ALIAS (show_ipv6_ospf6_topology,
+ show_ipv6_ospf6_topology_router_cmd,
+ "show ipv6 ospf6 topology (A.B.C.D|<0-4294967295>|detail)",
+ SHOW_STR
+ IP6_STR
+ OSPF6_STR
+ "Inter Area topology information\n"
+ OSPF6_ROUTER_ID_STR
+ OSPF6_ROUTER_ID_STR
+ "Detailed information\n"
+ )
+
+ALIAS (show_ipv6_ospf6_topology,
+ show_ipv6_ospf6_topology_router_lsid_cmd,
+ "show ipv6 ospf6 topology (A.B.C.D|<0-4294967295>) (A.B.C.D|<0-4294967295>)",
+ SHOW_STR
+ IP6_STR
+ OSPF6_STR
+ "Inter Area topology information\n"
+ OSPF6_ROUTER_ID_STR
+ OSPF6_ROUTER_ID_STR
+ OSPF6_LS_ID_STR
+ OSPF6_LS_ID_STR
+ )
+
+void
+ospf6_top_init ()
+{
+ install_element (VIEW_NODE, &show_ipv6_ospf6_route_cmd);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_route_prefix_cmd);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_topology_cmd);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_topology_router_cmd);
+ install_element (VIEW_NODE, &show_ipv6_ospf6_topology_router_lsid_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_route_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_route_prefix_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_topology_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_topology_router_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_topology_router_lsid_cmd);
+}
+
diff --git a/ospf6d/ospf6_top.h b/ospf6d/ospf6_top.h
new file mode 100644
index 00000000..4c687563
--- /dev/null
+++ b/ospf6d/ospf6_top.h
@@ -0,0 +1,96 @@
+/*
+ * OSPFv3 Top Level Data Structure
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef OSPF6_TOP_H
+#define OSPF6_TOP_H
+
+#include "routemap.h"
+
+/* ospfv3 top level data structure */
+struct ospf6
+{
+ /* process id */
+ u_long process_id;
+
+ /* start time */
+ struct timeval starttime;
+
+ /* ospf version must be 3 */
+ unsigned char version;
+
+ /* my router id */
+ u_int32_t router_id;
+
+ /* list of areas */
+ list area_list;
+
+ /* AS scope link state database */
+ struct ospf6_lsdb *lsdb;
+
+ /* redistribute route-map */
+ struct
+ {
+ char *name;
+ struct route_map *map;
+ } rmap[ZEBRA_ROUTE_MAX];
+
+ struct thread *t_route_calculation;
+ u_int stat_route_calculation_execed;
+
+ struct ospf6_route_table *route_table;
+ struct ospf6_route_table *topology_table;
+ struct ospf6_route_table *external_table;
+
+ void (*foreach_area) (struct ospf6 *, void *arg, int val,
+ void (*func) (void *, int, void *));
+ void (*foreach_if) (struct ospf6 *, void *arg, int val,
+ void (*func) (void *, int, void *));
+ void (*foreach_nei) (struct ospf6 *, void *arg, int val,
+ void (*func) (void *, int, void *));
+
+ struct thread *maxage_remover;
+
+ list nexthop_list;
+};
+
+extern struct ospf6 *ospf6;
+
+/* prototypes */
+int
+ospf6_top_count_neighbor_in_state (u_char state, struct ospf6 *o6);
+
+void
+ospf6_top_schedule_maxage_remover (void *arg, int val, struct ospf6 *o6);
+
+void ospf6_show (struct vty *);
+void ospf6_statistics_show (struct vty *vty, struct ospf6 *o6);
+
+struct ospf6 *ospf6_start ();
+void ospf6_stop ();
+
+void ospf6_delete (struct ospf6 *);
+int ospf6_is_asbr (struct ospf6 *);
+
+void ospf6_top_init ();
+
+#endif /* OSPF6_TOP_H */
+
diff --git a/ospf6d/ospf6_types.h b/ospf6d/ospf6_types.h
new file mode 100644
index 00000000..574e2f35
--- /dev/null
+++ b/ospf6d/ospf6_types.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef OSPF6_TYPES_H
+#define OSPF6_TYPES_H
+
+typedef unsigned char msgtype_t;
+typedef unsigned char instance_id_t;
+typedef unsigned char state_t;
+typedef unsigned char vers_t;
+typedef unsigned char opt_t;
+typedef unsigned char rtr_pri_t;
+typedef unsigned char prefixlen_t;
+typedef unsigned char ddbits_t;
+typedef unsigned long ddseqnum_t;
+typedef unsigned long rtr_id_t;
+typedef unsigned long ifid_t;
+typedef unsigned long cost_t;
+typedef unsigned long rxmt_int_t;
+typedef unsigned short hello_int_t;
+typedef unsigned short rtr_dead_int_t;
+typedef unsigned long area_id_t;
+
+#endif /* OSPF6_TYPES_H */
+
diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c
new file mode 100644
index 00000000..7b8a8dcf
--- /dev/null
+++ b/ospf6d/ospf6_zebra.c
@@ -0,0 +1,727 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "ospf6d.h"
+
+#include "ospf6_interface.h"
+#include "ospf6_asbr.h"
+
+#include "ospf6_linklist.h"
+
+/* information about zebra. */
+struct zclient *zclient = NULL;
+
+/* redistribute function */
+void
+ospf6_zebra_redistribute (int type)
+{
+ int top_change = 0;
+
+ if (zclient->redist[type])
+ return;
+
+ if (! ospf6_is_asbr (ospf6))
+ top_change = 1;
+
+ zclient->redist[type] = 1;
+
+ if (zclient->sock > 0)
+ zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient->sock, type);
+
+ if (top_change)
+ CALL_CHANGE_HOOK (&top_hook, ospf6);
+}
+
+void
+ospf6_zebra_no_redistribute (int type)
+{
+ int top_change = 0;
+
+ if (!zclient->redist[type])
+ return;
+
+ if (ospf6_is_asbr (ospf6))
+ top_change = 1;
+
+ zclient->redist[type] = 0;
+
+ if (zclient->sock > 0)
+ zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient->sock, type);
+
+ if (top_change)
+ CALL_CHANGE_HOOK (&top_hook, ospf6);
+}
+
+int
+ospf6_zebra_is_redistribute (int type)
+{
+ return zclient->redist[type];
+}
+
+
+/* Inteface addition message from zebra. */
+int
+ospf6_zebra_if_add (int command, struct zclient *zclient, zebra_size_t length)
+{
+ struct interface *ifp;
+
+ ifp = zebra_interface_add_read (zclient->ibuf);
+
+ /* log */
+ if (IS_OSPF6_DUMP_ZEBRA)
+ zlog_info ("ZEBRA: I/F add: %s index %d mtu %d",
+ ifp->name, ifp->ifindex, ifp->mtu);
+
+ ospf6_interface_if_add (ifp);
+
+ return 0;
+}
+
+int
+ospf6_zebra_if_del (int command, struct zclient *zclient, zebra_size_t length)
+{
+#if 0
+ struct interface *ifp = NULL;
+
+ ifp = zebra_interface_delete_read (zclient->ibuf);
+
+ /* log */
+ if (IS_OSPF6_DUMP_ZEBRA)
+ zlog_info ("ZEBRA: I/F delete: %s index %d mtu %d",
+ ifp->name, ifp->ifindex, ifp->mtu);
+
+ ospf6_interface_if_del (ifp);
+#endif
+
+ return 0;
+}
+
+int
+ospf6_zebra_if_state_update (int command, struct zclient *zclient,
+ zebra_size_t length)
+{
+ struct interface *ifp;
+
+ ifp = zebra_interface_state_read (zclient->ibuf);
+
+ /* log */
+ if (IS_OSPF6_DUMP_ZEBRA)
+ zlog_info ("ZEBRA: I/F %s state change: index %d flags %ld metric %d mtu %d",
+ ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu);
+
+ ospf6_interface_state_update (ifp);
+ return 0;
+}
+
+int
+ospf6_zebra_if_address_update_add (int command, struct zclient *zclient,
+ zebra_size_t length)
+{
+ struct connected *c;
+ char buf[128];
+
+ c = zebra_interface_address_add_read (zclient->ibuf);
+ if (c == NULL)
+ return 0;
+
+ if (IS_OSPF6_DUMP_ZEBRA)
+ zlog_info ("ZEBRA: I/F %s address add: %5s %s/%d",
+ c->ifp->name, prefix_family_str (c->address),
+ inet_ntop (c->address->family, &c->address->u.prefix,
+ buf, sizeof (buf)), c->address->prefixlen);
+
+ if (c->address->family == AF_INET6)
+ ospf6_interface_address_update (c->ifp);
+
+ return 0;
+}
+
+int
+ospf6_zebra_if_address_update_delete (int command, struct zclient *zclient,
+ zebra_size_t length)
+{
+ struct connected *c;
+ char buf[128];
+
+ c = zebra_interface_address_delete_read (zclient->ibuf);
+ if (c == NULL)
+ return 0;
+
+ if (IS_OSPF6_DUMP_ZEBRA)
+ zlog_info ("ZEBRA: I/F %s address del: %5s %s/%d",
+ c->ifp->name, prefix_family_str (c->address),
+ inet_ntop (c->address->family, &c->address->u.prefix,
+ buf, sizeof (buf)), c->address->prefixlen);
+
+ if (c->address->family == AF_INET6)
+ ospf6_interface_address_update (c->ifp);
+
+ return 0;
+}
+
+
+
+const char *zebra_route_name[ZEBRA_ROUTE_MAX] =
+{
+ "System",
+ "Kernel",
+ "Connect",
+ "Static",
+ "RIP",
+ "RIPng",
+ "OSPF",
+ "OSPF6",
+ "BGP",
+};
+
+const char *zebra_route_abname[ZEBRA_ROUTE_MAX] =
+ { "X", "K", "C", "S", "r", "R", "o", "O", "B" };
+
+int
+ospf6_zebra_read_ipv6 (int command, struct zclient *zclient,
+ zebra_size_t length)
+{
+ struct stream *s;
+ struct zapi_ipv6 api;
+ unsigned long ifindex;
+ struct prefix_ipv6 p;
+ struct in6_addr *nexthop;
+ char prefixstr[128], nexthopstr[128];
+
+ s = zclient->ibuf;
+ ifindex = 0;
+ nexthop = NULL;
+ memset (&api, 0, sizeof (api));
+
+ /* Type, flags, message. */
+ api.type = stream_getc (s);
+ api.flags = stream_getc (s);
+ api.message = stream_getc (s);
+
+ /* IPv6 prefix. */
+ memset (&p, 0, sizeof (struct prefix_ipv6));
+ p.family = AF_INET6;
+ p.prefixlen = stream_getc (s);
+ stream_get (&p.prefix, s, PSIZE (p.prefixlen));
+
+ /* Nexthop, ifindex, distance, metric. */
+ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP))
+ {
+ api.nexthop_num = stream_getc (s);
+ nexthop = (struct in6_addr *)
+ malloc (api.nexthop_num * sizeof (struct in6_addr));
+ stream_get (nexthop, s, api.nexthop_num * sizeof (struct in6_addr));
+ }
+ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX))
+ {
+ api.ifindex_num = stream_getc (s);
+ ifindex = stream_getl (s);
+ }
+ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
+ api.distance = stream_getc (s);
+ else
+ api.distance = 0;
+ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
+ api.metric = stream_getl (s);
+ else
+ api.metric = 0;
+
+ /* log */
+ if (IS_OSPF6_DUMP_ZEBRA)
+ {
+ prefix2str ((struct prefix *)&p, prefixstr, sizeof (prefixstr));
+ inet_ntop (AF_INET6, &nexthop, nexthopstr, sizeof (nexthopstr));
+
+ if (command == ZEBRA_IPV6_ROUTE_ADD)
+ zlog_info ("ZEBRA: Receive add %s route: %s nexthop:%s ifindex:%ld",
+ zebra_route_name [api.type], prefixstr,
+ nexthopstr, ifindex);
+ else
+ zlog_info ("ZEBRA: Receive remove %s route: %s nexthop:%s ifindex:%ld",
+ zebra_route_name [api.type], prefixstr,
+ nexthopstr, ifindex);
+ }
+
+ if (command == ZEBRA_IPV6_ROUTE_ADD)
+ ospf6_asbr_route_add (api.type, ifindex, (struct prefix *) &p,
+ api.nexthop_num, nexthop);
+ else
+ ospf6_asbr_route_remove (api.type, ifindex, (struct prefix *) &p);
+
+ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP))
+ free (nexthop);
+
+ return 0;
+}
+
+
+DEFUN (show_zebra,
+ show_zebra_cmd,
+ "show zebra",
+ SHOW_STR
+ "Zebra information\n")
+{
+ int i;
+ if (!zclient)
+ vty_out (vty, "Not connected to zebra%s", VTY_NEWLINE);
+
+ vty_out (vty, "Zebra Infomation%s", VTY_NEWLINE);
+ vty_out (vty, " enable: %d%s", zclient->enable, VTY_NEWLINE);
+ vty_out (vty, " fail: %d%s", zclient->fail, VTY_NEWLINE);
+ vty_out (vty, " redistribute default: %d%s", zclient->redist_default,
+ VTY_NEWLINE);
+ for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+ vty_out (vty, " RouteType: %s - %s%s", zebra_route_name[i],
+ zclient->redist[i] ? "redistributed" : "not redistributed",
+ VTY_NEWLINE);
+ return CMD_SUCCESS;
+}
+
+DEFUN (router_zebra,
+ router_zebra_cmd,
+ "router zebra",
+ "Enable a routing process\n"
+ "Make connection to zebra daemon\n")
+{
+ if (IS_OSPF6_DUMP_CONFIG)
+ zlog_info ("Config: router zebra");
+
+ vty->node = ZEBRA_NODE;
+ zclient->enable = 1;
+ zclient_start (zclient);
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_router_zebra,
+ no_router_zebra_cmd,
+ "no router zebra",
+ NO_STR
+ "Configure routing process\n"
+ "Disable connection to zebra daemon\n")
+{
+ if (IS_OSPF6_DUMP_CONFIG)
+ zlog_info ("no router zebra");
+
+ zclient->enable = 0;
+ zclient_stop (zclient);
+ return CMD_SUCCESS;
+}
+
+/* Zebra configuration write function. */
+int
+ospf6_zebra_config_write (struct vty *vty)
+{
+ if (! zclient->enable)
+ {
+ vty_out (vty, "no router zebra%s", VTY_NEWLINE);
+ return 1;
+ }
+ else if (! zclient->redist[ZEBRA_ROUTE_OSPF6])
+ {
+ vty_out (vty, "router zebra%s", VTY_NEWLINE);
+ vty_out (vty, " no redistribute ospf6%s", VTY_NEWLINE);
+ return 1;
+ }
+ return 0;
+}
+
+/* Zebra node structure. */
+struct cmd_node zebra_node =
+{
+ ZEBRA_NODE,
+ "%s(config-zebra)# ",
+};
+
+#define ADD 0
+#define CHANGE 1
+#define REMOVE 2
+
+static void
+ospf6_zebra_route_update (int type, struct ospf6_route_req *request)
+{
+ char buf[96], ifname[IFNAMSIZ];
+
+ struct zapi_ipv6 api;
+ struct ospf6_route_req route;
+ struct linklist *nexthop_list;
+ struct linklist_node node;
+ struct ospf6_nexthop *nexthop = NULL;
+ struct in6_addr **nexthops;
+ unsigned int *ifindexes;
+ struct prefix_ipv6 *p;
+ int i, ret = 0;
+
+ if (IS_OSPF6_DUMP_ZEBRA)
+ {
+ prefix2str (&request->route.prefix, buf, sizeof (buf));
+ if (type == REMOVE)
+ zlog_info ("ZEBRA: Send remove route: %s", buf);
+ else
+ zlog_info ("ZEBRA: Send add route: %s", buf);
+ }
+
+ if (zclient->sock < 0)
+ {
+ if (IS_OSPF6_DUMP_ZEBRA)
+ zlog_info ("ZEBRA: failed: not connected to zebra");
+ return;
+ }
+
+ if (request->path.origin.adv_router == ospf6->router_id &&
+ (request->path.type == OSPF6_PATH_TYPE_EXTERNAL1 ||
+ request->path.type == OSPF6_PATH_TYPE_EXTERNAL2))
+ {
+ if (IS_OSPF6_DUMP_ZEBRA)
+ zlog_info ("ZEBRA: self originated external route, ignore");
+ return;
+ }
+
+ /* Only the best path (i.e. the first path of the path-list
+ in 'struct ospf6_route') will be sent to zebra. */
+ ospf6_route_lookup (&route, &request->route.prefix, request->table);
+ if (memcmp (&route.path, &request->path, sizeof (route.path)))
+ {
+ /* this is not preferred best route, ignore */
+ if (IS_OSPF6_DUMP_ZEBRA)
+ zlog_info ("ZEBRA: not best path, ignore");
+ return;
+ }
+
+ nexthop_list = linklist_create ();
+
+ /* for each nexthop */
+ for (ospf6_route_lookup (&route, &request->route.prefix, request->table);
+ ! ospf6_route_end (&route); ospf6_route_next (&route))
+ {
+ if (memcmp (&route.path, &request->path, sizeof (route.path)))
+ break;
+
+ #define IN6_IS_ILLEGAL_NEXTHOP(a)\
+ ((*(u_int32_t *)(void *)(&(a)->s6_addr[0]) == 0xffffffff) &&\
+ (*(u_int32_t *)(void *)(&(a)->s6_addr[4]) == 0xffffffff) &&\
+ (*(u_int32_t *)(void *)(&(a)->s6_addr[8]) == 0xffffffff) &&\
+ (*(u_int32_t *)(void *)(&(a)->s6_addr[12]) == 0xffffffff))
+ if (IN6_IS_ILLEGAL_NEXTHOP (&route.nexthop.address))
+ {
+ zlog_warn ("ZEBRA: Illegal nexthop");
+ continue;
+ }
+
+ if (type == REMOVE && ! memcmp (&route.nexthop, &request->nexthop,
+ sizeof (struct ospf6_nexthop)))
+ continue;
+
+ nexthop = XCALLOC (MTYPE_OSPF6_OTHER, sizeof (struct ospf6_nexthop));
+ if (! nexthop)
+ {
+ zlog_warn ("ZEBRA: Can't update nexthop: malloc failed");
+ continue;
+ }
+
+ memcpy (nexthop, &route.nexthop, sizeof (struct ospf6_nexthop));
+ linklist_add (nexthop, nexthop_list);
+ }
+
+ if (type == REMOVE && nexthop_list->count != 0)
+ type = ADD;
+ else if (type == REMOVE && nexthop_list->count == 0)
+ {
+ if (IS_OSPF6_DUMP_ZEBRA)
+ zlog_info ("ZEBRA: all nexthop with the selected path has gone");
+
+ if (! memcmp (&request->route, &route.route,
+ sizeof (struct ospf6_route)))
+ {
+ /* send 'add' of alternative route */
+ struct ospf6_path seconde_path;
+
+ if (IS_OSPF6_DUMP_ZEBRA)
+ zlog_info ("ZEBRA: found alternative path to add");
+
+ memcpy (&seconde_path, &route.path, sizeof (struct ospf6_path));
+ type = ADD;
+
+ while (! memcmp (&seconde_path, &route.path,
+ sizeof (struct ospf6_path)))
+ {
+ nexthop = XCALLOC (MTYPE_OSPF6_OTHER,
+ sizeof (struct ospf6_nexthop));
+ if (! nexthop)
+ zlog_warn ("ZEBRA: Can't update nexthop: malloc failed");
+ else
+ {
+ memcpy (nexthop, &route.nexthop,
+ sizeof (struct ospf6_nexthop));
+ linklist_add (nexthop, nexthop_list);
+ }
+
+ ospf6_route_next (&route);
+ }
+ }
+ else
+ {
+ /* there is no alternative route. send 'remove' to zebra for
+ requested route */
+ if (IS_OSPF6_DUMP_ZEBRA)
+ zlog_info ("ZEBRA: can't find alternative path, remove");
+
+ if (IS_OSPF6_DUMP_ZEBRA)
+ {
+ zlog_info ("ZEBRA: Debug: walk over the route ?");
+ ospf6_route_log_request ("Debug route", "***", &route);
+ ospf6_route_log_request ("Debug request", "***", request);
+ }
+
+ nexthop = XCALLOC (MTYPE_OSPF6_OTHER,
+ sizeof (struct ospf6_nexthop));
+ if (! nexthop)
+ zlog_warn ("ZEBRA: Can't update nexthop: malloc failed");
+ else
+ {
+ memcpy (nexthop, &request->nexthop,
+ sizeof (struct ospf6_nexthop));
+ linklist_add (nexthop, nexthop_list);
+ }
+ }
+ }
+
+ if (nexthop_list->count == 0)
+ {
+ if (IS_OSPF6_DUMP_ZEBRA)
+ zlog_info ("ZEBRA: no nexthop, ignore");
+ linklist_delete (nexthop_list);
+ return;
+ }
+
+ /* allocate memory for nexthop_list */
+ nexthops = XCALLOC (MTYPE_OSPF6_OTHER,
+ nexthop_list->count * sizeof (struct in6_addr *));
+ if (! nexthops)
+ {
+ zlog_warn ("ZEBRA: Can't update zebra route: malloc failed");
+ for (linklist_head (nexthop_list, &node); !linklist_end (&node);
+ linklist_next (&node))
+ XFREE (MTYPE_OSPF6_OTHER, node.data);
+ linklist_delete (nexthop_list);
+ return;
+ }
+
+ /* allocate memory for ifindex_list */
+ ifindexes = XCALLOC (MTYPE_OSPF6_OTHER,
+ nexthop_list->count * sizeof (unsigned int));
+ if (! ifindexes)
+ {
+ zlog_warn ("ZEBRA: Can't update zebra route: malloc failed");
+ for (linklist_head (nexthop_list, &node); !linklist_end (&node);
+ linklist_next (&node))
+ XFREE (MTYPE_OSPF6_OTHER, node.data);
+ linklist_delete (nexthop_list);
+ XFREE (MTYPE_OSPF6_OTHER, nexthops);
+ return;
+ }
+
+ i = 0;
+ for (linklist_head (nexthop_list, &node); ! linklist_end (&node);
+ linklist_next (&node))
+ {
+ nexthop = node.data;
+ if (IS_OSPF6_DUMP_ZEBRA)
+ {
+ inet_ntop (AF_INET6, &nexthop->address, buf, sizeof (buf));
+ if_indextoname (nexthop->ifindex, ifname);
+ zlog_info ("ZEBRA: nexthop: %s%%%s(%d)",
+ buf, ifname, nexthop->ifindex);
+ }
+ nexthops[i] = &nexthop->address;
+ ifindexes[i] = nexthop->ifindex;
+ i++;
+ }
+
+ api.type = ZEBRA_ROUTE_OSPF6;
+ api.flags = 0;
+ api.message = 0;
+ SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
+ SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX);
+ api.nexthop_num = nexthop_list->count;
+ api.nexthop = nexthops;
+ api.ifindex_num = nexthop_list->count;
+ api.ifindex = ifindexes;
+
+ p = (struct prefix_ipv6 *) &request->route.prefix;
+ if (type == REMOVE && nexthop_list->count == 1)
+ ret = zapi_ipv6_delete (zclient, p, &api);
+ else
+ ret = zapi_ipv6_add (zclient, p, &api);
+
+ if (ret < 0)
+ zlog_err ("ZEBRA: zapi_ipv6_add () failed: %s", strerror (errno));
+
+ for (linklist_head (nexthop_list, &node); !linklist_end (&node);
+ linklist_next (&node))
+ XFREE (MTYPE_OSPF6_OTHER, node.data);
+ linklist_delete (nexthop_list);
+ XFREE (MTYPE_OSPF6_OTHER, nexthops);
+ XFREE (MTYPE_OSPF6_OTHER, ifindexes);
+
+ return;
+}
+
+void
+ospf6_zebra_route_update_add (struct ospf6_route_req *request)
+{
+ ospf6_zebra_route_update (ADD, request);
+}
+
+void
+ospf6_zebra_route_update_remove (struct ospf6_route_req *request)
+{
+ ospf6_zebra_route_update (REMOVE, request);
+}
+
+static void
+ospf6_zebra_redistribute_ospf6 ()
+{
+ struct route_node *node;
+
+ for (node = route_top (ospf6->route_table->table); node;
+ node = route_next (node))
+ {
+ if (! node || ! node->info)
+ continue;
+ ospf6_zebra_route_update_add (node->info);
+ }
+}
+
+static void
+ospf6_zebra_no_redistribute_ospf6 ()
+{
+ struct route_node *node;
+
+ if (! ospf6)
+ return;
+
+ for (node = route_top (ospf6->route_table->table); node;
+ node = route_next (node))
+ {
+ if (! node || ! node->info)
+ continue;
+
+ ospf6_zebra_route_update_remove (node->info);
+ }
+}
+
+
+DEFUN (redistribute_ospf6,
+ redistribute_ospf6_cmd,
+ "redistribute ospf6",
+ "Redistribute control\n"
+ "OSPF6 route\n")
+{
+ /* log */
+ if (IS_OSPF6_DUMP_CONFIG)
+ zlog_info ("Config: redistribute ospf6");
+
+ zclient->redist[ZEBRA_ROUTE_OSPF6] = 1;
+
+ /* set zebra route table */
+ ospf6_zebra_redistribute_ospf6 ();
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_redistribute_ospf6,
+ no_redistribute_ospf6_cmd,
+ "no redistribute ospf6",
+ NO_STR
+ "Redistribute control\n"
+ "OSPF6 route\n")
+{
+ /* log */
+ if (IS_OSPF6_DUMP_CONFIG)
+ zlog_info ("Config: no redistribute ospf6");
+
+ zclient->redist[ZEBRA_ROUTE_OSPF6] = 0;
+
+ if (! ospf6)
+ return CMD_SUCCESS;
+
+ /* clean up zebra route table */
+ ospf6_zebra_no_redistribute_ospf6 ();
+
+ ospf6_route_hook_unregister (ospf6_zebra_route_update_add,
+ ospf6_zebra_route_update_add,
+ ospf6_zebra_route_update_remove,
+ ospf6->route_table);
+
+ return CMD_SUCCESS;
+}
+
+void
+ospf6_zebra_init ()
+{
+ /* Allocate zebra structure. */
+ zclient = zclient_new ();
+ zclient_init (zclient, ZEBRA_ROUTE_OSPF6);
+ zclient->interface_add = ospf6_zebra_if_add;
+ zclient->interface_delete = ospf6_zebra_if_del;
+ zclient->interface_up = ospf6_zebra_if_state_update;
+ zclient->interface_down = ospf6_zebra_if_state_update;
+ zclient->interface_address_add = ospf6_zebra_if_address_update_add;
+ zclient->interface_address_delete = ospf6_zebra_if_address_update_delete;
+ zclient->ipv4_route_add = NULL;
+ zclient->ipv4_route_delete = NULL;
+ zclient->ipv6_route_add = ospf6_zebra_read_ipv6;
+ zclient->ipv6_route_delete = ospf6_zebra_read_ipv6;
+
+ /* redistribute connected route by default */
+ /* ospf6_zebra_redistribute (ZEBRA_ROUTE_CONNECT); */
+
+ /* Install zebra node. */
+ install_node (&zebra_node, ospf6_zebra_config_write);
+
+ /* Install command element for zebra node. */
+ install_element (VIEW_NODE, &show_zebra_cmd);
+ install_element (ENABLE_NODE, &show_zebra_cmd);
+ install_element (CONFIG_NODE, &router_zebra_cmd);
+ install_element (CONFIG_NODE, &no_router_zebra_cmd);
+ install_default (ZEBRA_NODE);
+ install_element (ZEBRA_NODE, &redistribute_ospf6_cmd);
+ install_element (ZEBRA_NODE, &no_redistribute_ospf6_cmd);
+
+#if 0
+ hook.name = "ZebraRouteUpdate";
+ hook.hook_add = ospf6_zebra_route_update_add;
+ hook.hook_change = ospf6_zebra_route_update_add;
+ hook.hook_remove = ospf6_zebra_route_update_remove;
+ ospf6_hook_register (&hook, &route_hook);
+#endif
+
+ return;
+}
+
+void
+ospf6_zebra_finish ()
+{
+ zclient_stop (zclient);
+ zclient_free (zclient);
+ zclient = (struct zclient *) NULL;
+}
+
diff --git a/ospf6d/ospf6_zebra.h b/ospf6d/ospf6_zebra.h
new file mode 100644
index 00000000..d86b2db7
--- /dev/null
+++ b/ospf6d/ospf6_zebra.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef OSPF6_ZEBRA_H
+#define OSPF6_ZEBRA_H
+
+extern struct zclient *zclient;
+
+void ospf6_zebra_redistribute (int);
+void ospf6_zebra_no_redistribute (int);
+int ospf6_zebra_is_redistribute (int);
+
+int ospf6_zebra_get_interface (int, struct zclient *, zebra_size_t);
+int ospf6_zebra_read (struct thread *);
+void ospf6_zebra_init ();
+void ospf6_zebra_finish ();
+void ospf6_zebra_start ();
+
+int ospf6_zebra_read_ipv6 (int, struct zclient *, zebra_size_t);
+
+extern const char *zebra_route_name[ZEBRA_ROUTE_MAX];
+extern const char *zebra_route_abname[ZEBRA_ROUTE_MAX];
+
+void ospf6_zebra_route_update_add (struct ospf6_route_req *request);
+void ospf6_zebra_route_update_remove (struct ospf6_route_req *request);
+
+#endif /*OSPF6_ZEBRA_H*/
+
diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c
new file mode 100644
index 00000000..dbe7a88f
--- /dev/null
+++ b/ospf6d/ospf6d.c
@@ -0,0 +1,826 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "ospf6d.h"
+
+#include "ospf6_damp.h"
+
+/* global ospf6d variable */
+int ospf6_sock;
+list iflist;
+list nexthoplist = NULL;
+struct sockaddr_in6 allspfrouters6;
+struct sockaddr_in6 alldrouters6;
+char *recent_reason; /* set by ospf6_lsa_check_recent () */
+int proctitle_mode = 0;
+
+char ospf6_daemon_version[] = OSPF6_DAEMON_VERSION;
+
+
+#define TIMER_SEC_MICRO 1000000
+
+void
+ospf6_timeval_sub (const struct timeval *t1, const struct timeval *t2,
+ struct timeval *result)
+{
+ long usec, movedown = 0;
+
+ if (t1->tv_sec < t2->tv_sec ||
+ (t1->tv_sec == t2->tv_sec && t1->tv_usec < t2->tv_usec))
+ {
+ result->tv_sec = 0;
+ result->tv_usec = 0;
+ return;
+ }
+
+ if (t1->tv_usec < t2->tv_usec)
+ {
+ usec = t1->tv_usec + TIMER_SEC_MICRO;
+ movedown++;
+ }
+ else
+ usec = t1->tv_usec;
+ result->tv_usec = usec - t2->tv_usec;
+
+ result->tv_sec = t1->tv_sec - t2->tv_sec - movedown;
+}
+
+void
+ospf6_timeval_div (const struct timeval *t1, u_int by,
+ struct timeval *result)
+{
+ long movedown;
+
+ if (by == 0)
+ {
+ result->tv_sec = 0;
+ result->tv_usec = 0;
+ return;
+ }
+
+ movedown = t1->tv_sec % by;
+ result->tv_sec = t1->tv_sec / by;
+ result->tv_usec = (t1->tv_usec + movedown * TIMER_SEC_MICRO) / by;
+}
+
+void
+ospf6_timeval_decode (const struct timeval *t, long *dayp, long *hourp,
+ long *minp, long *secp, long *msecp, long *usecp)
+{
+ long day, hour, min, sec, msec, usec, left;
+
+ left = t->tv_sec;
+ day = left / 86400; left -= day * 86400;
+ hour = left / 3600; left -= hour * 3600;
+ min = left / 60; left -= min * 60;
+ sec = left;
+ left = t->tv_usec;
+ msec = left / 1000; left -= msec * 1000;
+ usec = left;
+
+ if (dayp) *dayp = day;
+ if (hourp) *hourp = hour;
+ if (minp) *minp = min;
+ if (secp) *secp = sec;
+ if (msecp) *msecp = msec;
+ if (usecp) *usecp = usec;
+}
+
+void
+ospf6_timeval_string (struct timeval *tv, char *buf, int size)
+{
+ char days[16], hours[16], mins[16], secs[16], msecs[16], usecs[16];
+ long day, hour, min, sec, msec, usec;
+
+ ospf6_timeval_decode (tv, &day, &hour, &min, &sec, &msec, &usec);
+ snprintf (days, sizeof (days), "%ld days ", day);
+ snprintf (hours, sizeof (hours), "%ld hours ", hour);
+ snprintf (mins, sizeof (mins), "%ld mins ", min);
+ snprintf (secs, sizeof (secs), "%ld secs ", sec);
+ snprintf (msecs, sizeof (msecs), "%ld msecs ", msec);
+ snprintf (usecs, sizeof (usecs), "%ld usecs ", usec);
+
+ snprintf (buf, size, "%s%s%s%s%s%s",
+ (day ? days : ""), (hour ? hours : ""),
+ (min ? mins : ""), (sec ? secs : ""),
+ (msec ? msecs : ""), (usec ? usecs : ""));
+}
+
+void
+ospf6_timeval_string_summary (struct timeval *tv, char *buf, int size)
+{
+ char days[16], hours[16], mins[16], secs[16], msecs[16], usecs[16];
+ long day, hour, min, sec, msec, usec;
+
+ ospf6_timeval_decode (tv, &day, &hour, &min, &sec, &msec, &usec);
+ snprintf (days, sizeof (days), "%02ldd", day);
+ snprintf (hours, sizeof (hours), "%ldh", hour);
+ snprintf (mins, sizeof (mins), "%ldm", min);
+ snprintf (secs, sizeof (secs), "%lds", sec);
+ snprintf (msecs, sizeof (msecs), "%ldms", msec);
+ snprintf (usecs, sizeof (usecs), "%ldus", usec);
+
+ snprintf (buf, size, "%s%02ld:%02ld:%02ld",
+ (day ? days : ""), hour, min, sec);
+}
+
+/* foreach function */
+void
+ospf6_count_state (void *arg, int val, void *obj)
+{
+ int *count = (int *) arg;
+ u_char state = val;
+ struct ospf6_neighbor *nei = (struct ospf6_neighbor *) obj;
+
+ if (nei->state == state)
+ (*count)++;
+}
+
+/* VTY commands. */
+DEFUN (reload,
+ reload_cmd,
+ "reload",
+ "Reloads\n")
+{
+ extern void _reload ();
+ _reload ();
+ return CMD_SUCCESS;
+}
+
+DEFUN (garbage_collection,
+ garbage_collection_cmd,
+ "ipv6 ospf6 garbage collect",
+ IPV6_STR
+ OSPF6_STR
+ "garbage collection by hand\n"
+ "Remove Maxages if possible and recalculate routes\n")
+{
+ ospf6_maxage_remover ();
+#if 0
+ ospf6_route_calculation_schedule ();
+#endif
+ return CMD_SUCCESS;
+}
+
+/* Show version. */
+DEFUN (show_version_ospf6,
+ show_version_ospf6_cmd,
+ "show version ospf6",
+ SHOW_STR
+ "Displays ospf6d version\n")
+{
+ vty_out (vty, "Zebra OSPF6d Version: %s%s",
+ ospf6_daemon_version, VTY_NEWLINE);
+
+ return CMD_SUCCESS;
+}
+
+/* start ospf6 */
+DEFUN (router_ospf6,
+ router_ospf6_cmd,
+ "router ospf6",
+ OSPF6_ROUTER_STR
+ OSPF6_STR)
+{
+ if (ospf6 == NULL)
+ ospf6_start ();
+
+ /* set current ospf point. */
+ vty->node = OSPF6_NODE;
+ vty->index = ospf6;
+
+ return CMD_SUCCESS;
+}
+
+/* stop ospf6 */
+DEFUN (no_router_ospf6,
+ no_router_ospf6_cmd,
+ "no router ospf6",
+ NO_STR
+ OSPF6_ROUTER_STR)
+{
+ if (!ospf6)
+ vty_out (vty, "OSPFv3 is not running%s", VTY_NEWLINE);
+ else
+ ospf6_stop ();
+
+ /* return to config node . */
+ vty->node = CONFIG_NODE;
+ vty->index = NULL;
+
+ return CMD_SUCCESS;
+}
+
+/* show top level structures */
+DEFUN (show_ipv6_ospf6,
+ show_ipv6_ospf6_cmd,
+ "show ipv6 ospf6",
+ SHOW_STR
+ IP6_STR
+ OSPF6_STR)
+{
+ OSPF6_CMD_CHECK_RUNNING ();
+
+ ospf6_show (vty);
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ipv6_ospf6_nexthoplist,
+ show_ipv6_ospf6_nexthoplist_cmd,
+ "show ipv6 ospf6 nexthop-list",
+ SHOW_STR
+ IP6_STR
+ OSPF6_STR
+ "List of nexthop\n")
+{
+#if 0
+ listnode i;
+ struct ospf6_nexthop *nh;
+ char buf[128];
+ for (i = listhead (nexthoplist); i; nextnode (i))
+ {
+ nh = (struct ospf6_nexthop *) getdata (i);
+ nexthop_str (nh, buf, sizeof (buf));
+ vty_out (vty, "%s%s", buf,
+ VTY_NEWLINE);
+ }
+#endif
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ipv6_ospf6_statistics,
+ show_ipv6_ospf6_statistics_cmd,
+ "show ipv6 ospf6 statistics",
+ SHOW_STR
+ IP6_STR
+ OSPF6_STR
+ "Statistics\n")
+{
+ OSPF6_CMD_CHECK_RUNNING ();
+
+ ospf6_statistics_show (vty, ospf6);
+ return CMD_SUCCESS;
+}
+
+/* change Router_ID commands. */
+DEFUN (router_id,
+ router_id_cmd,
+ "router-id ROUTER_ID",
+ "Configure ospf Router-ID.\n"
+ V4NOTATION_STR)
+{
+ int ret;
+ u_int32_t router_id;
+
+ ret = inet_pton (AF_INET, argv[0], &router_id);
+ if (!ret)
+ {
+ vty_out (vty, "malformed ospf router identifier%s", VTY_NEWLINE);
+ vty_out (vty, "%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (IS_OSPF6_DUMP_CONFIG)
+ zlog_info ("CONFIG: router-id %s", argv[0]);
+ ospf6->router_id = router_id;
+
+ return CMD_SUCCESS;
+}
+
+int
+ospf6_interface_bind_area (struct vty *vty,
+ char *if_name, char *area_name,
+ char *plist_name, int passive)
+{
+ struct interface *ifp;
+ struct ospf6_interface *o6i;
+ struct ospf6_area *o6a;
+ u_int32_t area_id;
+
+ /* find/create ospf6 interface */
+ ifp = if_get_by_name (if_name);
+ o6i = (struct ospf6_interface *) ifp->info;
+ if (! o6i)
+ o6i = ospf6_interface_create (ifp);
+
+ /* parse Area-ID */
+ if (inet_pton (AF_INET, area_name, &area_id) != 1)
+ {
+ vty_out (vty, "Invalid Area-ID: %s%s", area_name, VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
+ }
+
+ /* find/create ospf6 area */
+ o6a = ospf6_area_lookup (area_id, ospf6);
+ if (!o6a)
+ {
+ o6a = ospf6_area_create (area_id);
+ o6a->ospf6 = ospf6;
+ listnode_add (ospf6->area_list, o6a);
+ }
+
+ if (o6i->area)
+ {
+ if (o6i->area != o6a)
+ {
+ vty_out (vty, "Aready attached to area %s%s",
+ o6i->area->str, VTY_NEWLINE);
+ return CMD_ERR_NOTHING_TODO;
+ }
+ }
+ else
+ {
+ listnode_add (o6a->if_list, o6i);
+ o6i->area = o6a;
+ }
+
+ /* prefix-list name */
+ if (plist_name)
+ {
+ if (o6i->plist_name)
+ XFREE (MTYPE_PREFIX_LIST_STR, o6i->plist_name);
+ o6i->plist_name = XSTRDUP (MTYPE_PREFIX_LIST_STR, plist_name);
+ }
+ else
+ {
+ if (o6i->plist_name)
+ XFREE (MTYPE_PREFIX_LIST_STR, o6i->plist_name);
+ o6i->plist_name = NULL;
+ }
+
+ if (passive)
+ {
+ listnode node;
+ struct ospf6_neighbor *o6n;
+
+ SET_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_PASSIVE);
+ if (o6i->thread_send_hello)
+ {
+ thread_cancel (o6i->thread_send_hello);
+ o6i->thread_send_hello = (struct thread *) NULL;
+ }
+
+ for (node = listhead (o6i->neighbor_list); node; nextnode (node))
+ {
+ o6n = getdata (node);
+ if (o6n->inactivity_timer)
+ thread_cancel (o6n->inactivity_timer);
+ thread_execute (master, inactivity_timer, o6n, 0);
+ }
+ }
+ else
+ {
+ UNSET_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_PASSIVE);
+ if (o6i->thread_send_hello == NULL)
+ thread_add_event (master, ospf6_send_hello, o6i, 0);
+ }
+
+ /* enable I/F if it's not enabled still */
+ if (! ospf6_interface_is_enabled (o6i->interface->ifindex))
+ thread_add_event (master, interface_up, o6i, 0);
+ else
+ CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, o6i);
+
+ CALL_CHANGE_HOOK (&interface_hook, o6i);
+ return CMD_SUCCESS;
+}
+
+DEFUN (interface_area_plist,
+ interface_area_plist_cmd,
+ "interface IFNAME area A.B.C.D prefix-list WORD",
+ "Enable routing on an IPv6 interface\n"
+ IFNAME_STR
+ "Set the OSPF6 area ID\n"
+ "OSPF6 area ID in IPv4 address notation\n"
+ OSPF6_PREFIX_LIST_STR
+ "IPv6 prefix-list name\n"
+ )
+{
+ if (IS_OSPF6_DUMP_CONFIG)
+ zlog_info ("CONFIG: interface %s area %s prefix-list %s",
+ argv[0], argv[1], argv[2]);
+
+ return ospf6_interface_bind_area (vty, argv[0], argv[1], argv[2], 0);
+}
+
+DEFUN (interface_area_plist_passive,
+ interface_area_plist_passive_cmd,
+ "interface IFNAME area A.B.C.D prefix-list WORD passive",
+ "Enable routing on an IPv6 interface\n"
+ IFNAME_STR
+ "Set the OSPF6 area ID\n"
+ "OSPF6 area ID in IPv4 address notation\n"
+ OSPF6_PREFIX_LIST_STR
+ "IPv6 prefix-list name\n"
+ "IPv6 prefix-list name\n"
+ OSPF6_PASSIVE_STR
+ )
+{
+ if (IS_OSPF6_DUMP_CONFIG)
+ zlog_info ("CONFIG: interface %s area %s prefix-list %s passive",
+ argv[0], argv[1], argv[2]);
+
+ return ospf6_interface_bind_area (vty, argv[0], argv[1], argv[2], 1);
+}
+
+DEFUN (interface_area,
+ interface_area_cmd,
+ "interface IFNAME area A.B.C.D",
+ "Enable routing on an IPv6 interface\n"
+ IFNAME_STR
+ "Set the OSPF6 area ID\n"
+ "OSPF6 area ID in IPv4 address notation\n"
+ )
+{
+ struct interface *ifp;
+ struct ospf6_interface *o6i;
+ int passive;
+ char *plist_name;
+
+ if (IS_OSPF6_DUMP_CONFIG)
+ zlog_info ("CONFIG: interface %s area %s",
+ argv[0], argv[1]);
+
+ ifp = if_get_by_name (argv[0]);
+ o6i = (struct ospf6_interface *) ifp->info;
+ if (o6i)
+ {
+ passive = CHECK_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_PASSIVE);
+ plist_name = o6i->plist_name;
+ }
+ else
+ {
+ passive = 0;
+ plist_name = NULL;
+ }
+
+ return ospf6_interface_bind_area (vty, argv[0], argv[1],
+ plist_name, passive);
+}
+
+DEFUN (interface_area_passive,
+ interface_area_passive_cmd,
+ "interface IFNAME area A.B.C.D passive",
+ "Enable routing on an IPv6 interface\n"
+ IFNAME_STR
+ "Set the OSPF6 area ID\n"
+ "OSPF6 area ID in IPv4 address notation\n"
+ OSPF6_PASSIVE_STR
+ )
+{
+ if (IS_OSPF6_DUMP_CONFIG)
+ zlog_info ("CONFIG: interface %s area %s passive",
+ argv[0], argv[1]);
+
+ return ospf6_interface_bind_area (vty, argv[0], argv[1], NULL, 1);
+}
+
+DEFUN (no_interface_area,
+ no_interface_area_cmd,
+ "no interface IFNAME area A.B.C.D",
+ NO_STR
+ "Disable routing on an IPv6 interface\n"
+ IFNAME_STR)
+{
+ struct interface *ifp;
+ struct ospf6_interface *o6i;
+ struct ospf6 *o6;
+ u_int32_t area_id;
+
+ o6 = (struct ospf6 *) vty->index;
+
+ ifp = if_lookup_by_name (argv[0]);
+ if (!ifp)
+ return CMD_ERR_NO_MATCH;
+
+ o6i = (struct ospf6_interface *) ifp->info;
+ if (!o6i)
+ return CMD_SUCCESS;
+
+ /* parse Area-ID */
+ if (inet_pton (AF_INET, argv[1], &area_id) != 1)
+ {
+ vty_out (vty, "Invalid Area-ID: %s%s", argv[1], VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
+ }
+
+ if (o6i->area->area_id != area_id)
+ {
+ vty_out (vty, "Wrong Area-ID: %s aready attached to area %s%s",
+ o6i->interface->name, o6i->area->str, VTY_NEWLINE);
+ return CMD_ERR_NOTHING_TODO;
+ }
+
+ if (o6i->area)
+ thread_execute (master, interface_down, o6i, 0);
+
+ listnode_delete (o6i->area->if_list, o6i);
+ o6i->area = (struct ospf6_area *) NULL;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (area_range,
+ area_range_cmd,
+ "area A.B.C.D range X:X::X:X/M",
+ "OSPFv3 area parameters\n"
+ "OSPFv3 area ID in IPv4 address format\n"
+ "Summarize routes matching address/mask (border routers only)\n"
+ "IPv6 address range\n")
+{
+ struct ospf6 *o6;
+ struct ospf6_area *o6a;
+ u_int32_t area_id;
+ int ret;
+
+ o6 = (struct ospf6 *) vty->index;
+ inet_pton (AF_INET, argv[0], &area_id);
+ o6a = ospf6_area_lookup (area_id, o6);
+ if (! o6a)
+ {
+ vty_out (vty, "No such area%s", VTY_NEWLINE);
+ return CMD_ERR_NO_MATCH;
+ }
+
+ ret = str2prefix_ipv6 (argv[1], &o6a->area_range);
+ if (ret <= 0)
+ {
+ vty_out (vty, "Malformed IPv6 address%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (passive_interface,
+ passive_interface_cmd,
+ "passive-interface IFNAME",
+ OSPF6_PASSIVE_STR
+ IFNAME_STR)
+{
+ struct interface *ifp;
+ struct ospf6_interface *o6i;
+
+ ifp = if_get_by_name (argv[0]);
+ if (ifp->info)
+ o6i = (struct ospf6_interface *) ifp->info;
+ else
+ o6i = ospf6_interface_create (ifp);
+
+ SET_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_PASSIVE);
+
+ if (o6i->thread_send_hello)
+ {
+ thread_cancel (o6i->thread_send_hello);
+ o6i->thread_send_hello = (struct thread *) NULL;
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_passive_interface,
+ no_passive_interface_cmd,
+ "no passive-interface IFNAME",
+ NO_STR
+ OSPF6_PASSIVE_STR
+ IFNAME_STR)
+{
+ struct interface *ifp;
+ struct ospf6_interface *o6i;
+
+ ifp = if_lookup_by_name (argv[0]);
+ if (! ifp)
+ return CMD_ERR_NO_MATCH;
+
+ o6i = (struct ospf6_interface *) ifp->info;
+ UNSET_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_PASSIVE);
+ if (o6i->thread_send_hello == NULL)
+ thread_add_event (master, ospf6_send_hello, o6i, 0);
+
+ return CMD_SUCCESS;
+}
+
+#ifdef HAVE_SETPROCTITLE
+extern int _argc;
+extern char **_argv;
+
+DEFUN (set_proctitle,
+ set_proctitle_cmd,
+ "set proctitle (version|normal|none)",
+ "Set command\n"
+ "Process title\n"
+ "Version information\n"
+ "Normal command-line options\n"
+ "Just program name\n")
+{
+ int i;
+ char buf[64], tmp[64];
+
+ if (strncmp (argv[0], "v", 1) == 0)
+ {
+ proctitle_mode = 1;
+ setproctitle ("%s Zebra: %s", OSPF6_DAEMON_VERSION, ZEBRA_VERSION);
+ }
+ else if (strncmp (argv[0], "nor", 3) == 0)
+ {
+ proctitle_mode = 0;
+ memset (tmp, 0, sizeof (tmp));
+ memset (buf, 0, sizeof (buf));
+ for (i = 0; i < _argc; i++)
+ {
+ snprintf (buf, sizeof (buf), "%s%s ", tmp, _argv[i]);
+ memcpy (&tmp, &buf, sizeof (tmp));
+ }
+ setproctitle (buf);
+ }
+ else if (strncmp (argv[0], "non", 3) == 0)
+ {
+ proctitle_mode = -1;
+ setproctitle (NULL);
+ }
+ else
+ return CMD_ERR_NO_MATCH;
+
+ return CMD_SUCCESS;
+}
+#endif /* HAVE_SETPROCTITLE */
+
+/* OSPF configuration write function. */
+int
+ospf6_config_write (struct vty *vty)
+{
+ listnode j, k;
+ char buf[64];
+ struct ospf6_area *area;
+ struct ospf6_interface *o6i;
+
+ if (proctitle_mode == 1)
+ vty_out (vty, "set proctitle version%s", VTY_NEWLINE);
+ else if (proctitle_mode == -1)
+ vty_out (vty, "set proctitle none%s", VTY_NEWLINE);
+
+ vty_out (vty, "!%s", VTY_NEWLINE);
+
+ if (! ospf6)
+ return 0;
+
+ /* OSPFv6 configuration. */
+ if (!ospf6)
+ return CMD_SUCCESS;
+
+ inet_ntop (AF_INET, &ospf6->router_id, buf, sizeof (buf));
+ vty_out (vty, "router ospf6%s", VTY_NEWLINE);
+ vty_out (vty, " router-id %s%s", buf, VTY_NEWLINE);
+
+ ospf6_redistribute_config_write (vty);
+ ospf6_damp_config_write (vty);
+
+ for (j = listhead (ospf6->area_list); j; nextnode (j))
+ {
+ area = (struct ospf6_area *)getdata (j);
+ for (k = listhead (area->if_list); k; nextnode (k))
+ {
+ o6i = (struct ospf6_interface *) getdata (k);
+ vty_out (vty, " interface %s area %s%s",
+ o6i->interface->name, area->str, VTY_NEWLINE);
+ }
+ }
+ vty_out (vty, "!%s", VTY_NEWLINE);
+ return 0;
+}
+
+/* OSPF6 node structure. */
+struct cmd_node ospf6_node =
+{
+ OSPF6_NODE,
+ "%s(config-ospf6)# ",
+};
+
+/* Install ospf related commands. */
+void
+ospf6_init ()
+{
+ /* Install ospf6 top node. */
+ install_node (&ospf6_node, ospf6_config_write);
+
+ install_element (VIEW_NODE, &show_ipv6_ospf6_cmd);
+ install_element (VIEW_NODE, &show_version_ospf6_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_cmd);
+ install_element (ENABLE_NODE, &show_version_ospf6_cmd);
+ install_element (ENABLE_NODE, &reload_cmd);
+ install_element (CONFIG_NODE, &router_ospf6_cmd);
+ install_element (CONFIG_NODE, &interface_cmd);
+#ifdef OSPF6_STATISTICS
+ install_element (VIEW_NODE, &show_ipv6_ospf6_statistics_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_ospf6_statistics_cmd);
+#endif /* OSPF6_STATISTICS */
+#ifdef OSPF6_GARBAGE_COLLECT
+ install_element (ENABLE_NODE, &garbage_collection_cmd);
+#endif /* OSPF6_GARBAGE_COLLECT */
+#ifdef HAVE_SETPROCTITLE
+ install_element (CONFIG_NODE, &set_proctitle_cmd);
+#endif /* HAVE_SETPROCTITLE */
+
+ install_default (OSPF6_NODE);
+ install_element (OSPF6_NODE, &router_id_cmd);
+ install_element (OSPF6_NODE, &interface_area_cmd);
+ install_element (OSPF6_NODE, &interface_area_passive_cmd);
+ install_element (OSPF6_NODE, &interface_area_plist_cmd);
+ install_element (OSPF6_NODE, &interface_area_plist_passive_cmd);
+ install_element (OSPF6_NODE, &no_interface_area_cmd);
+ install_element (OSPF6_NODE, &passive_interface_cmd);
+ install_element (OSPF6_NODE, &no_passive_interface_cmd);
+ install_element (OSPF6_NODE, &area_range_cmd);
+
+ /* Make empty list of top list. */
+ if_init ();
+
+ /* Install access list */
+ access_list_init ();
+
+ /* Install prefix list */
+ prefix_list_init ();
+
+ ospf6_dump_init ();
+
+#ifdef HAVE_OSPF6_DAMP
+ ospf6_damp_init ();
+#endif /*HAVE_OSPF6_DAMP*/
+
+ ospf6_hook_init ();
+ ospf6_lsa_init ();
+
+ ospf6_top_init ();
+ ospf6_area_init ();
+ ospf6_interface_init ();
+ ospf6_neighbor_init ();
+ ospf6_zebra_init ();
+
+ ospf6_routemap_init ();
+ ospf6_lsdb_init ();
+
+ ospf6_spf_init ();
+
+ ospf6_intra_init ();
+ ospf6_abr_init ();
+ ospf6_asbr_init ();
+}
+
+void
+ospf6_terminate ()
+{
+ /* stop ospf6 */
+ ospf6_stop ();
+
+ /* log */
+ zlog (NULL, LOG_INFO, "OSPF6d terminated");
+}
+
+void
+ospf6_maxage_remover ()
+{
+#if 0
+ if (IS_OSPF6_DUMP_LSDB)
+ zlog_info ("MaxAge Remover");
+#endif
+
+ ospf6_top_schedule_maxage_remover (NULL, 0, ospf6);
+ (*ospf6->foreach_area) (ospf6, NULL, 0,
+ ospf6_area_schedule_maxage_remover);
+ (*ospf6->foreach_if) (ospf6, NULL, 0,
+ ospf6_interface_schedule_maxage_remover);
+}
+
+
+
+void *
+ospf6_lsa_get_scope (u_int16_t type, struct ospf6_interface *o6i)
+{
+ if (OSPF6_LSA_IS_SCOPE_LINKLOCAL (ntohs (type)))
+ return o6i;
+ else if (OSPF6_LSA_IS_SCOPE_AREA (ntohs (type)))
+ return o6i->area;
+ else if (OSPF6_LSA_IS_SCOPE_AS (ntohs (type)))
+ return o6i->area->ospf6;
+ else
+ return NULL;
+}
+
diff --git a/ospf6d/ospf6d.conf.sample b/ospf6d/ospf6d.conf.sample
new file mode 100644
index 00000000..71972f59
--- /dev/null
+++ b/ospf6d/ospf6d.conf.sample
@@ -0,0 +1,54 @@
+!
+! Zebra configuration saved from vty
+! 2000/05/11 02:09:37
+!
+hostname ospf6d@yasu3380
+password zebra
+log file /var/log/zebra-ospf6d.log
+log stdout
+!
+debug ospf6 message dbdesc
+debug ospf6 message lsreq
+debug ospf6 message lsupdate
+debug ospf6 message lsack
+debug ospf6 neighbor
+debug ospf6 spf
+debug ospf6 interface
+debug ospf6 area
+debug ospf6 lsa
+debug ospf6 zebra
+debug ospf6 config
+debug ospf6 dbex
+debug ospf6 route
+!
+interface ed0
+ ipv6 ospf6 cost 1
+ ipv6 ospf6 hello-interval 10
+ ipv6 ospf6 dead-interval 40
+ ipv6 ospf6 retransmit-interval 5
+ ipv6 ospf6 priority 1
+ ipv6 ospf6 transmit-delay 1
+ ipv6 ospf6 instance-id 0
+!
+interface lo0
+ ipv6 ospf6 cost 1
+ ipv6 ospf6 hello-interval 10
+ ipv6 ospf6 dead-interval 40
+ ipv6 ospf6 retransmit-interval 5
+ ipv6 ospf6 priority 1
+ ipv6 ospf6 transmit-delay 1
+ ipv6 ospf6 instance-id 0
+!
+router ospf6
+ router-id 0.0.0.1
+ redistribute static route-map static-ospf6
+ interface ed0 area 0.0.0.0
+ interface lo0 area 0.0.0.0
+!
+ipv6 prefix-list hostroute seq 10 permit 3ffe:501:100c:4380::/60 le 128 ge 128
+!
+route-map static-ospf6 permit 50
+ match ipv6 address prefix-list hostroute
+ set metric-type type-2
+ set metric 30
+!
diff --git a/ospf6d/ospf6d.h b/ospf6d/ospf6d.h
new file mode 100644
index 00000000..e0d310a9
--- /dev/null
+++ b/ospf6d/ospf6d.h
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef OSPF6D_H
+#define OSPF6D_H
+
+#include <zebra.h>
+#include "linklist.h"
+
+#ifndef HEADER_DEPENDENCY
+/* Include other stuffs */
+#include "version.h"
+#include "log.h"
+#include "getopt.h"
+#include "thread.h"
+#include "command.h"
+#include "memory.h"
+#include "sockunion.h"
+#include "if.h"
+#include "prefix.h"
+#include "stream.h"
+#include "thread.h"
+#include "filter.h"
+#include "zclient.h"
+#include "table.h"
+#include "plist.h"
+
+/* OSPF stuffs */
+#include "ospf6_hook.h"
+#include "ospf6_types.h"
+#include "ospf6_prefix.h"
+#include "ospf6_lsa.h"
+#include "ospf6_lsdb.h"
+
+#include "ospf6_message.h"
+#include "ospf6_proto.h"
+#include "ospf6_spf.h"
+#include "ospf6_top.h"
+#include "ospf6_area.h"
+#include "ospf6_interface.h"
+#include "ospf6_neighbor.h"
+#include "ospf6_ism.h"
+#include "ospf6_nsm.h"
+#include "ospf6_route.h"
+#include "ospf6_dbex.h"
+#include "ospf6_network.h"
+#include "ospf6_zebra.h"
+#include "ospf6_dump.h"
+#include "ospf6_routemap.h"
+#include "ospf6_asbr.h"
+#include "ospf6_abr.h"
+#include "ospf6_intra.h"
+#endif /*HEADER_DEPENDENCY*/
+
+#define HASHVAL 64
+#define MAXIOVLIST 1024
+
+#define OSPF6_DAEMON_VERSION "0.9.6o"
+
+#define AF_LINKSTATE 0xff
+
+/* global variables */
+extern char *progname;
+extern int errno;
+extern int daemon_mode;
+extern struct thread_master *master;
+extern list iflist;
+extern list nexthoplist;
+extern struct sockaddr_in6 allspfrouters6;
+extern struct sockaddr_in6 alldrouters6;
+extern int ospf6_sock;
+extern char *recent_reason;
+
+/* Default configuration file name for ospfd. */
+#define OSPF6_DEFAULT_CONFIG "ospf6d.conf"
+
+/* Default port values. */
+#define OSPF6_VTY_PORT 2606
+#define OSPF6_VTYSH_PATH "/tmp/.ospf6d"
+
+#ifdef INRIA_IPV6
+#ifndef IPV6_PKTINFO
+#define IPV6_PKTINFO IPV6_RECVPKTINFO
+#endif /* IPV6_PKTINFO */
+#endif /* INRIA_IPV6 */
+
+/* Historycal for KAME. */
+#ifndef IPV6_JOIN_GROUP
+#ifdef IPV6_ADD_MEMBERSHIP
+#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
+#endif /* IPV6_ADD_MEMBERSHIP. */
+#ifdef IPV6_JOIN_MEMBERSHIP
+#define IPV6_JOIN_GROUP IPV6_JOIN_MEMBERSHIP
+#endif /* IPV6_JOIN_MEMBERSHIP. */
+#endif /* ! IPV6_JOIN_GROUP*/
+
+#ifndef IPV6_LEAVE_GROUP
+#ifdef IPV6_DROP_MEMBERSHIP
+#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
+#endif /* IPV6_DROP_MEMBERSHIP */
+#endif /* ! IPV6_LEAVE_GROUP */
+
+#define OSPF6_CMD_CHECK_RUNNING() \
+ if (ospf6 == NULL) \
+ { \
+ vty_out (vty, "OSPFv3 is not running%s", VTY_NEWLINE); \
+ return CMD_SUCCESS; \
+ }
+
+#define OSPF6_LEVEL_NONE 0
+#define OSPF6_LEVEL_NEIGHBOR 1
+#define OSPF6_LEVEL_INTERFACE 2
+#define OSPF6_LEVEL_AREA 3
+#define OSPF6_LEVEL_TOP 4
+#define OSPF6_LEVEL_MAX 5
+
+#define OSPF6_PASSIVE_STR \
+ "Suppress routing updates on an interface\n"
+#define OSPF6_PREFIX_LIST_STR \
+ "Advertise I/F Address only match entries of prefix-list\n"
+
+#define OSPF6_AREA_STR "Area information\n"
+#define OSPF6_AREA_ID_STR "Area ID (as an IPv4 notation)\n"
+#define OSPF6_SPF_STR "Shortest Path First tree information\n"
+#define OSPF6_ROUTER_ID_STR "Specify Router-ID\n"
+#define OSPF6_LS_ID_STR "Specify Link State ID\n"
+
+
+/* Function Prototypes */
+void
+ospf6_timeval_sub (const struct timeval *t1, const struct timeval *t2,
+ struct timeval *result);
+void
+ospf6_timeval_div (const struct timeval *t1, u_int by,
+ struct timeval *result);
+void
+ospf6_timeval_sub_equal (const struct timeval *t, struct timeval *result);
+void
+ospf6_timeval_decode (const struct timeval *t, long *dayp, long *hourp,
+ long *minp, long *secp, long *msecp, long *usecp);
+void
+ospf6_timeval_string (struct timeval *tv, char *buf, int size);
+void
+ospf6_timeval_string_summary (struct timeval *tv, char *buf, int size);
+
+void
+ospf6_count_state (void *arg, int val, void *obj);
+
+void ospf6_init ();
+void ospf6_terminate ();
+
+void ospf6_maxage_remover ();
+
+void *ospf6_lsa_get_scope (u_int16_t type, struct ospf6_interface *o6i);
+
+#endif /* OSPF6D_H */
+