aboutsummaryrefslogtreecommitdiff
path: root/net/zebra/files
diff options
context:
space:
mode:
authorMunechika SUMIKAWA <sumikawa@FreeBSD.org>2003-04-26 23:40:59 +0000
committerMunechika SUMIKAWA <sumikawa@FreeBSD.org>2003-04-26 23:40:59 +0000
commit57848a7fcc93d06fc872af2a7556d059dab10731 (patch)
tree08f4709ef55146515306500a1093f4121afe21f6 /net/zebra/files
parentab18ec5992898609fb85f3dbc9ca9f128969421f (diff)
downloadports-57848a7fcc93d06fc872af2a7556d059dab10731.tar.gz
ports-57848a7fcc93d06fc872af2a7556d059dab10731.zip
Upgrade to ospf6d to 0.9.6p to fix the critical bug on AS-External
LSA refreshing. Obtained from: zebra cvs
Notes
Notes: svn path=/head/; revision=79711
Diffstat (limited to 'net/zebra/files')
-rw-r--r--net/zebra/files/patch-ospf6d3427
1 files changed, 3427 insertions, 0 deletions
diff --git a/net/zebra/files/patch-ospf6d b/net/zebra/files/patch-ospf6d
new file mode 100644
index 000000000000..8dce08ba2c3e
--- /dev/null
+++ b/net/zebra/files/patch-ospf6d
@@ -0,0 +1,3427 @@
+diff -x CVS -urN ospf6d.old/ChangeLog ospf6d/ChangeLog
+--- ospf6d.old/ChangeLog Sat Apr 26 23:17:47 2003
++++ ospf6d/ChangeLog Fri Apr 25 11:40:31 2003
+@@ -1,3 +1,36 @@
++2003-04-25 Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
++
++ * ospf6_asbr.c: AS-External LSA refresh was based on the
++ prefix of the obsolete LSA. It was wrong so fixed.
++ * version: 0.9.6p
++
++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()
+diff -x CVS -urN ospf6d.old/Makefile.in ospf6d/Makefile.in
+--- ospf6d.old/Makefile.in Sat Apr 26 23:17:47 2003
++++ ospf6d/Makefile.in Thu Feb 20 01:31:12 2003
+@@ -1,4 +1,4 @@
+-# Makefile.in generated by automake 1.6.2 from Makefile.am.
++# Makefile.in generated by automake 1.6.3 from Makefile.am.
+ # @configure_input@
+
+ # Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
+@@ -111,9 +111,9 @@
+ 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_redistribute.c ospf6_routemap.c ospf6_proto.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_abr.c ospf6_intra.c ospf6_damp.c
+
+
+ noinst_HEADERS = \
+@@ -121,9 +121,9 @@
+ 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_redistribute.h ospf6_routemap.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_abr.h ospf6_intra.h ospf6_damp.h
+
+
+ ospf6d_SOURCES = \
+@@ -150,10 +150,10 @@
+ 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_redistribute.$(OBJEXT) ospf6_routemap.$(OBJEXT) \
+- ospf6_proto.$(OBJEXT) ospf6_hook.$(OBJEXT) ospf6_asbr.$(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_abr.$(OBJEXT) ospf6_intra.$(OBJEXT) ospf6_damp.$(OBJEXT)
+ libospf6_a_OBJECTS = $(am_libospf6_a_OBJECTS)
+ sbin_PROGRAMS = ospf6d$(EXEEXT)
+ PROGRAMS = $(sbin_PROGRAMS)
+@@ -165,10 +165,10 @@
+ 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_redistribute.$(OBJEXT) ospf6_routemap.$(OBJEXT) \
+- ospf6_proto.$(OBJEXT) ospf6_hook.$(OBJEXT) ospf6_asbr.$(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_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
+@@ -182,8 +182,8 @@
+ @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_dbex.Po ./$(DEPDIR)/ospf6_dump.Po \
+-@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_hook.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 \
+@@ -195,7 +195,6 @@
+ @AMDEP_TRUE@ ./$(DEPDIR)/ospf6_nsm.Po \
+ @AMDEP_TRUE@ ./$(DEPDIR)/ospf6_prefix.Po \
+ @AMDEP_TRUE@ ./$(DEPDIR)/ospf6_proto.Po \
+-@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_redistribute.Po \
+ @AMDEP_TRUE@ ./$(DEPDIR)/ospf6_route.Po \
+ @AMDEP_TRUE@ ./$(DEPDIR)/ospf6_routemap.Po \
+ @AMDEP_TRUE@ ./$(DEPDIR)/ospf6_spf.Po ./$(DEPDIR)/ospf6_top.Po \
+@@ -218,7 +217,7 @@
+
+ .SUFFIXES:
+ .SUFFIXES: .c .o .obj
+-$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
++$(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
+@@ -238,8 +237,7 @@
+ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ if test -f $$p \
+ ; then \
+- p1=`echo "$$p1" | sed -e 's,^.*/,,'`; \
+- f=`echo $$p1|sed '$(transform);s/$$/$(EXEEXT)/'`; \
++ 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; \
+ else :; fi; \
+@@ -248,8 +246,7 @@
+ uninstall-sbinPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(sbin_PROGRAMS)'; for p in $$list; do \
+- f=`echo $$p|sed 's/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+- f=`echo "$$f" | sed -e 's,^.*/,,'`; \
++ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " rm -f $(DESTDIR)$(sbindir)/$$f"; \
+ rm -f $(DESTDIR)$(sbindir)/$$f; \
+ done
+@@ -270,6 +267,7 @@
+ @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@
+@@ -286,7 +284,6 @@
+ @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_redistribute.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@
+diff -x CVS -urN ospf6d.old/ospf6_abr.c ospf6d/ospf6_abr.c
+--- ospf6d.old/ospf6_abr.c Sat Apr 26 23:17:47 2003
++++ ospf6d/ospf6_abr.c Tue Oct 1 10:28:07 2002
+@@ -42,7 +42,7 @@
+
+ inet_ntop (AF_INET, &router_id, router_string, sizeof (router_string));
+
+- zlog_info ("ABR: Finding router %s in area %s", router_string, area->str);
++ //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;
+diff -x CVS -urN ospf6d.old/ospf6_area.h ospf6d/ospf6_area.h
+--- ospf6d.old/ospf6_area.h Sat Apr 26 23:17:47 2003
++++ ospf6d/ospf6_area.h Sat Nov 9 11:25:30 2002
+@@ -62,6 +62,8 @@
+ void (*func) (void *, int, void *));
+
+ struct thread *maxage_remover;
++
++ struct thread *thread_router_lsa;
+ };
+
+
+diff -x CVS -urN ospf6d.old/ospf6_asbr.c ospf6d/ospf6_asbr.c
+--- ospf6d.old/ospf6_asbr.c Sat Apr 26 23:17:47 2003
++++ ospf6d/ospf6_asbr.c Fri Apr 25 11:40:31 2003
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (C) 2001 Yasuhiro Ohara
++ * Copyright (C) 2001-2002 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+@@ -19,108 +19,641 @@
+ * Boston, MA 02111-1307, USA.
+ */
+
+-#include "ospf6d.h"
++#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_asbr_external_lsa_update (struct ospf6_route_req *request)
++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];
+- u_int16_t size;
+- struct ospf6_lsa_as_external *external;
++ struct ospf6_lsa_as_external *e;
+ char *p;
+- struct ospf6_route_req route;
+- char pbuf[BUFSIZ];
+
+- /* 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;
++ info = THREAD_ARG (thread);
+
+- if (IS_OSPF6_DUMP_LSA)
+- zlog_info ("Update AS-External: ID: %lu",
+- (u_long) ntohl (request->path.origin.id));
++ /* 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));
+- size = sizeof (struct ospf6_lsa_as_external);
+- external = (struct ospf6_lsa_as_external *) buffer;
+- p = (char *) (external + 1);
++ e = (struct ospf6_lsa_as_external *) buffer;
++ p = (char *) (e + 1);
+
+- if (route.path.metric_type == 2)
+- SET_FLAG (external->bits_metric, OSPF6_ASBR_BIT_E); /* type2 */
++ if (info->metric_type == 2)
++ SET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_E); /* type2 */
+ else
+- UNSET_FLAG (external->bits_metric, OSPF6_ASBR_BIT_E); /* type1 */
++ UNSET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_E); /* type1, default */
+
+ /* forwarding address */
+- if (! IN6_IS_ADDR_UNSPECIFIED (&route.nexthop.address))
+- SET_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F);
++ if (! IN6_IS_ADDR_UNSPECIFIED (&info->forwarding))
++ SET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_F);
+ else
+- UNSET_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F);
++ UNSET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_F);
+
+ /* external route tag */
+- UNSET_FLAG (external->bits_metric, OSPF6_ASBR_BIT_T);
++ UNSET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_T);
+
+ /* set metric. note: related to E bit */
+- OSPF6_ASBR_METRIC_SET (external, route.path.cost);
++ OSPF6_ASBR_METRIC_SET (e, info->metric);
+
+ /* prefixlen */
+- external->prefix.prefix_length = route.route.prefix.prefixlen;
++ e->prefix.prefix_length = info->route->prefix.prefixlen;
+
+ /* PrefixOptions */
+- external->prefix.prefix_options = route.path.prefix_options;
++ e->prefix.prefix_options = info->prefix_options;
+
+ /* don't use refer LS-type */
+- external->prefix.prefix_refer_lstype = htons (0);
+-
+- if (IS_OSPF6_DUMP_LSA)
+- {
+- prefix2str (&route.route.prefix, pbuf, sizeof (pbuf));
+- zlog_info (" Prefix: %s", pbuf);
+- }
++ e->prefix.prefix_refer_lstype = htons (0);
+
+ /* set Prefix */
+- memcpy (p, &route.route.prefix.u.prefix6,
+- OSPF6_PREFIX_SPACE (route.route.prefix.prefixlen));
+- ospf6_prefix_apply_mask (&external->prefix);
+- size += OSPF6_PREFIX_SPACE (route.route.prefix.prefixlen);
+- p += OSPF6_PREFIX_SPACE (route.route.prefix.prefixlen);
++ 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 (external->bits_metric, OSPF6_ASBR_BIT_F))
++ if (CHECK_FLAG (e->bits_metric, OSPF6_ASBR_BIT_F))
+ {
+- memcpy (p, &route.nexthop.address, sizeof (struct in6_addr));
+- size += sizeof (struct in6_addr);
++ memcpy (p, &info->forwarding, sizeof (struct in6_addr));
+ p += sizeof (struct in6_addr);
+ }
+
+ /* External Route Tag */
+- if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_T))
++ if (CHECK_FLAG (e->bits_metric, OSPF6_ASBR_BIT_T))
+ {
+ /* xxx */
+ }
+
+ ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_AS_EXTERNAL),
+- route.path.origin.id, ospf6->router_id,
+- (char *) external, size, ospf6);
+- return;
++ 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 = NULL;
++ struct ospf6_external_info *info = NULL;
++ struct ospf6_external_info *match = NULL;
++
++ 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);
++
++ for (node = route_top (external_table); node; node = route_next (node))
++ {
++ route = node->info;
++ if (route == NULL)
++ continue;
++
++ for (info = route->info_head; info; info = info->next)
++ {
++ if (lsa->header->id == htonl (info->id))
++ match = info;
++ }
++ }
++
++ if (match == NULL)
++ {
++ ospf6_lsa_premature_aging (lsa);
++ return 0;
++ }
++
++ ospf6_asbr_schedule_external (match);
++ return 0;
++
++#if 0
++ 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;
++#endif
+ }
+
+ void
+-ospf6_asbr_external_route_add (struct ospf6_route_req *route)
++ospf6_asbr_route_add (int type, int ifindex, struct prefix *prefix,
++ u_int nexthop_num, struct in6_addr *nexthop)
+ {
+- ospf6_asbr_external_lsa_update (route);
++ 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_external_route_remove (struct ospf6_route_req *route)
++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;
+
+- lsa = ospf6_lsdb_lookup_lsdb (htons (OSPF6_LSA_TYPE_AS_EXTERNAL),
+- route->path.origin.id,
+- ospf6->router_id, ospf6->lsdb);
+- if (lsa)
+- ospf6_lsa_premature_aging (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
+@@ -134,22 +667,29 @@
+ external = OSPF6_LSA_HEADER_END (lsa->header);
+
+ if (IS_LSA_MAXAGE (lsa))
+- return;
++ {
++ 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: Calculate %s", lsa->str);
++ 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: Self-originated, ignore");
++ 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");
++ zlog_info ("ASBR: metric is infinity, ignore");
+ return;
+ }
+
+@@ -167,7 +707,7 @@
+ {
+ char buf[64];
+ inet_ntop (AF_INET, &asbr_id.adv_router, buf, sizeof (buf));
+- zlog_info ("ASBR: ASBR %s not found, ignore", buf);
++ zlog_info ("ASBR: router %s not found, ignore", buf);
+ }
+ return;
+ }
+@@ -206,6 +746,14 @@
+ {
+ 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);
+ }
+@@ -220,12 +768,13 @@
+ struct ospf6_route_req request;
+
+ if (IS_OSPF6_DUMP_ASBR)
+- zlog_info ("ASBR: Withdraw route of %s", lsa->str);
++ 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: Self-originated, ignore");
++ zlog_info ("ASBR: my external LSA, ignore");
+ return;
+ }
+
+@@ -236,14 +785,14 @@
+ memcpy (&dest.u.prefix6, (char *)(external + 1),
+ OSPF6_PREFIX_SPACE (dest.prefixlen));
+
+- prefix2str (&dest, buf, sizeof (buf));
+- if (IS_OSPF6_DUMP_ASBR)
+- zlog_info ("ASBR: route: %s", buf);
+-
+ ospf6_route_lookup (&request, &dest, ospf6->route_table);
+ if (ospf6_route_end (&request))
+ {
+- zlog_info ("ASBR: route not found");
++ if (IS_OSPF6_DUMP_ASBR)
++ {
++ prefix2str (&dest, buf, sizeof (buf));
++ zlog_info ("ASBR: %s not found", buf);
++ }
+ return;
+ }
+
+@@ -252,7 +801,8 @@
+ {
+ if (prefix_same (&request.route.prefix, &dest) != 1)
+ {
+- zlog_info ("ASBR: Can't find the entry matches the origin");
++ if (IS_OSPF6_DUMP_ASBR)
++ zlog_info ("ASBR: Can't find the entry matches the origin");
+ return;
+ }
+ ospf6_route_next (&request);
+@@ -264,6 +814,15 @@
+ 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);
+ }
+@@ -303,7 +862,7 @@
+ {
+ char buf[64];
+ inet_ntop (AF_INET, &inter_router->adv_router, buf, sizeof (buf));
+- zlog_info ("ASBR: New router found: %s", buf);
++ zlog_info ("ASBR: new router found: %s", buf);
+ }
+
+ if (ntohl (id) != 0 ||
+@@ -335,7 +894,7 @@
+ {
+ char buf[64];
+ inet_ntop (AF_INET, &inter_router->adv_router, buf, sizeof (buf));
+- zlog_info ("ASBR: Router disappearing: %s", buf);
++ zlog_info ("ASBR: router disappearing: %s", buf);
+ }
+
+ if (ntohl (id) != 0 ||
+@@ -410,37 +969,6 @@
+ return 0;
+ }
+
+-int
+-ospf6_asbr_external_refresh (void *old)
+-{
+- struct ospf6_lsa *lsa = old;
+- struct ospf6_route_req route, *target;
+-
+- assert (ospf6);
+-
+- if (IS_OSPF6_DUMP_ASBR)
+- zlog_info ("ASBR: refresh %s", lsa->str);
+-
+- target = NULL;
+- for (ospf6_route_head (&route, ospf6->external_table);
+- ! ospf6_route_end (&route);
+- ospf6_route_next (&route))
+- {
+- if (route.path.origin.id == lsa->header->id)
+- {
+- target = &route;
+- break;
+- }
+- }
+-
+- if (target)
+- ospf6_asbr_external_lsa_update (target);
+- else
+- ospf6_lsa_premature_aging (lsa);
+-
+- return 0;
+-}
+-
+ void
+ ospf6_asbr_database_hook (struct ospf6_lsa *old, struct ospf6_lsa *new)
+ {
+@@ -459,7 +987,7 @@
+ 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_refresh;
++ 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 =
+@@ -467,9 +995,71 @@
+ }
+
+ 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 -x CVS -urN ospf6d.old/ospf6_asbr.h ospf6d/ospf6_asbr.h
+--- ospf6d.old/ospf6_asbr.h Sat Apr 26 23:17:47 2003
++++ ospf6d/ospf6_asbr.h Sat Nov 9 11:25:30 2002
+@@ -22,6 +22,51 @@
+ #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
+ {
+@@ -42,8 +87,16 @@
+ { (E)->bits_metric &= htonl (0xff000000); \
+ (E)->bits_metric |= htonl (0x00ffffff) & htonl (C); }
+
+-void ospf6_asbr_external_route_add (struct ospf6_route_req *route);
+-void ospf6_asbr_external_route_remove (struct ospf6_route_req *route);
++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);
+diff -x CVS -urN ospf6d.old/ospf6_damp.c ospf6d/ospf6_damp.c
+--- ospf6d.old/ospf6_damp.c Thu Jan 1 01:00:00 1970
++++ ospf6d/ospf6_damp.c Sat Nov 9 11:25:30 2002
+@@ -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 -x CVS -urN ospf6d.old/ospf6_damp.h ospf6d/ospf6_damp.h
+--- ospf6d.old/ospf6_damp.h Thu Jan 1 01:00:00 1970
++++ ospf6d/ospf6_damp.h Tue Oct 1 00:41:10 2002
+@@ -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 -x CVS -urN ospf6d.old/ospf6_dbex.c ospf6d/ospf6_dbex.c
+--- ospf6d.old/ospf6_dbex.c Sat Apr 26 23:17:47 2003
++++ ospf6d/ospf6_dbex.c Sat Nov 9 11:25:30 2002
+@@ -230,12 +230,11 @@
+ 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);
+
+- if (IS_OSPF6_DUMP_DBEX)
+- zlog_info ("Receive %s from %s", received->str, from->str);
+-
+ /* set LSA scope */
+ if (OSPF6_LSA_IS_SCOPE_LINKLOCAL (htons (lsa_header->type)))
+ received->scope = from->ospf6_interface;
+@@ -248,27 +247,24 @@
+ cksum = ntohs (lsa_header->checksum);
+ if (ntohs (ospf6_lsa_checksum (lsa_header)) != cksum)
+ {
+- zlog_warn ("DBEX: LSA cksum wrong: %s checksum %#hx should be %#hx",
+- received->str, cksum, ntohs (ospf6_lsa_checksum (lsa_header)));
++ 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;
+ }
+
+-#if 0
+- /* (2) warn if unknown */
+- if (! ospf6_lsa_is_known_type (lsa_header))
+- zlog_warn ("[%s:%s] receive LSA unknown: %#x",
+- from->str, from->ospf6_interface->interface->name,
+- ntohs (lsa_header->type));
+-#endif /*0*/
+-
+ /* (3) Ebit Missmatch: AS-External-LSA */
+ if (lsa_header->type == htons (OSPF6_LSA_TYPE_AS_EXTERNAL) &&
+ ospf6_area_is_stub (from->ospf6_interface->area))
+ {
+- zlog_err ("DBEX: [%s:%s] receive LSA E-bit mismatch: %s",
+- from->str, from->ospf6_interface->interface->name,
+- received->str);
++ 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;
+ }
+@@ -279,8 +275,10 @@
+ {
+ /* log */
+ if (IS_OSPF6_DUMP_DBEX)
+- zlog_info ("Drop MaxAge LSA: no instance, no neighbor "
+- "exchanging DB: %s", received->str);
++ 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 */
+@@ -312,18 +310,29 @@
+
+ /* (a) MinLSArrival check */
+ gettimeofday (&now, (struct timezone *)NULL);
+- if (have && now.tv_sec - have->installed.tv_sec <= OSPF6_MIN_LS_ARRIVAL)
++ if (have && SEC_TVDIFF (&now, &have->installed) < OSPF6_MIN_LS_ARRIVAL)
+ {
+- if (IS_OSPF6_DUMP_DBEX)
+- zlog_info ("DBEX: [%s:%s] received LSA too soon: %s",
+- from->str, from->ospf6_interface->interface->name,
+- received->str);
++ //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);
+
+@@ -344,18 +353,20 @@
+ 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: [%s:%s] don't ack %s",
+- from->str, from->ospf6_interface->interface->name,
+- received->str);
++ zlog_info ("DBEX: No Ack to %s", from->str);
+ }
+
+ /* (f) */
+@@ -413,6 +424,9 @@
+ 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);
+ }
+@@ -421,18 +435,20 @@
+ 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: [%s:%s] will no ack %s",
+- from->str, from->ospf6_interface->interface->name,
+- received->str);
++ zlog_info ("DBEX: No Ack to %s", from->str);
+ }
+ ospf6_lsa_delete (received);
+ }
+@@ -443,6 +459,9 @@
+ 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);
+@@ -455,83 +474,52 @@
+ struct ospf6_neighbor *from)
+ {
+ struct ospf6_interface *ospf6_interface;
+- struct ospf6_neighbor *nbr;
+- listnode n, m;
++ 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;
+ }
+- else if (ismore_recent < 0 &&
+- ! CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_FLOODBACK))
+- {
+- if (ospf6_interface->state == IFS_BDR)
+- {
+- if (ospf6_interface->dr == from->router_id)
+- {
+- return DELAYED_ACK;
+- }
+- else
+- {
+- return NO_ACK;
+- }
+- }
+- else
+- {
+- return DELAYED_ACK;
+- }
+- }
+- else if (CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_DUPLICATE) &&
+- CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_IMPLIEDACK))
+- {
+- if (ospf6_interface->state == IFS_BDR)
+- {
+- if (ospf6_interface->dr == from->router_id)
+- {
+- return DELAYED_ACK;
+- }
+- else
+- {
+- return NO_ACK;
+- }
+- }
+- else
+- {
+- return NO_ACK;
+- }
+- }
+- else if (CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_DUPLICATE) &&
+- ! CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_IMPLIEDACK))
+- {
+- return DIRECT_ACK;
+- }
+- else if (IS_LSA_MAXAGE (newp))
++
++ if (CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_DUPLICATE) &&
++ CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_IMPLIEDACK))
+ {
+- if (! ospf6_lsdb_lookup (newp->header->type, newp->header->id,
+- newp->header->adv_router,
+- ospf6_lsa_get_scope (newp->header->type,
+- from->ospf6_interface)))
+- {
+- for (n = listhead (from->ospf6_interface->area->if_list);
+- n; nextnode (n))
+- {
+- ospf6_interface = (struct ospf6_interface *) getdata (n);
+- for (m = listhead (ospf6_interface->neighbor_list);
+- m; nextnode (m))
+- {
+- nbr = (struct ospf6_neighbor *) getdata (m);
+- if (nbr->state == NBS_EXCHANGE || nbr->state == NBS_LOADING)
+- {
+- return NO_ACK;
+- }
+- }
+- }
+- return DIRECT_ACK;
+- }
++ 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;
+ }
+@@ -600,11 +588,13 @@
+
+ /* (2) */
+ if (addretrans == 0)
++ return; /* examin next interface */
++
++ if (from && from->ospf6_interface == o6i)
+ {
+- return; /* examin next interface */
+- }
+- else 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);
+ }
+@@ -624,7 +614,7 @@
+ return; /* examin next interface */
+
+ if (IS_OSPF6_DUMP_DBEX)
+- zlog_info (" Flood to interface %s", o6i->interface->name);
++ zlog_info ("Flood to interface %s", o6i->interface->name);
+
+ /* (5) send LinkState Update */
+ ospf6_send_lsupdate_flood (lsa, o6i);
+@@ -678,14 +668,13 @@
+
+ lsa_header = (struct ospf6_lsa_header *) lsa->lsa_hdr;
+
+- if (IS_OSPF6_DUMP_DBEX)
+- zlog_info ("Flood: %s", lsa->str);
+-
+ 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)))
+@@ -693,6 +682,8 @@
+ 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)))
+@@ -700,6 +691,8 @@
+ o6 = (struct ospf6 *) lsa->scope;
+ assert (o6);
+
++ if (IS_OSPF6_DUMP_DBEX)
++ zlog_info ("Flood AS");
+ ospf6_dbex_flood_as (lsa, o6, from);
+ }
+ else
+diff -x CVS -urN ospf6d.old/ospf6_interface.c ospf6d/ospf6_interface.c
+--- ospf6d.old/ospf6_interface.c Sat Apr 26 23:17:47 2003
++++ ospf6d/ospf6_interface.c Sat Nov 9 13:26:03 2002
+@@ -126,6 +126,9 @@
+
+ CALL_ADD_HOOK (&interface_hook, o6i);
+
++ /* Get the interface's link-local if any */
++ ospf6_interface_address_update(ifp);
++
+ return o6i;
+ }
+
+diff -x CVS -urN ospf6d.old/ospf6_lsa.c ospf6d/ospf6_lsa.c
+--- ospf6d.old/ospf6_lsa.c Sat Apr 26 23:17:47 2003
++++ ospf6d/ospf6_lsa.c Sat Nov 9 11:25:30 2002
+@@ -51,7 +51,6 @@
+ #include "ospf6_area.h"
+ #include "ospf6_interface.h"
+ #include "ospf6_neighbor.h"
+-#include "ospf6_redistribute.h"
+ #include "ospf6_ism.h"
+ #include "ospf6_nsm.h"
+ #include "ospf6_dbex.h"
+@@ -142,8 +141,11 @@
+
+ lsa->birth.tv_sec = now.tv_sec - ntohs (lsa->header->age);
+ lsa->birth.tv_usec = now.tv_usec;
+- lsa->expire = thread_add_timer (master, ospf6_lsa_expire, lsa,
+- lsa->birth.tv_sec + MAXAGE - now.tv_sec);
++ 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;
+ }
+
+@@ -692,38 +694,6 @@
+ ospf6_lsa_delete (lsa);
+ }
+
+-/* check necessity to update LSA:
+- returns 1 if it's necessary to reoriginate */
+-static int
+-ospf6_lsa_is_really_reoriginate (struct ospf6_lsa *new)
+-{
+- struct ospf6_lsa *old;
+- int diff;
+-
+- /* find previous LSA */
+- old = ospf6_lsdb_lookup (new->header->type, new->header->id,
+- new->header->adv_router, new->scope);
+- if (! old)
+- return 1;
+-
+- /* Check if this is refresh */
+- if (CHECK_FLAG (old->flag, OSPF6_LSA_FLAG_REFRESH))
+- {
+- zlog_warn ("LSA: reoriginate: %s: Refresh", new->str);
+- return 1;
+- }
+-
+- /* Are these contents different ? */
+- diff = ospf6_lsa_differ (new, old);
+-
+- if (diff)
+- return 1;
+-
+- if (IS_OSPF6_DUMP_LSA)
+- zlog_info ("LSA: Suppress updating %s", new->str);
+- return 0;
+-}
+-
+ void
+ ospf6_lsa_originate (u_int16_t type, u_int32_t id, u_int32_t adv_router,
+ char *data, int data_len, void *scope)
+@@ -731,6 +701,7 @@
+ 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));
+
+@@ -754,18 +725,37 @@
+
+ /* create LSA */
+ lsa = ospf6_lsa_create ((struct ospf6_lsa_header *) buffer);
+- lsa->refresh = thread_add_timer (master, ospf6_lsa_refresh, lsa,
+- OSPF6_LS_REFRESH_TIME);
+ lsa->scope = scope;
+
+- if (ospf6_lsa_is_really_reoriginate (lsa))
+- {
+- ospf6_dbex_remove_from_all_retrans_list (lsa);
+- ospf6_dbex_flood (lsa, NULL);
+- ospf6_lsdb_install (lsa);
++ /* 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;
++ }
+ }
+- else
+- ospf6_lsa_delete (lsa);
++
++ 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);
+ }
+
+
+@@ -1130,14 +1120,32 @@
+ return 0;
+ }
+
+-void
+-ospf6_lsa_router_update (u_int32_t area_id)
++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_lsa *old;
+ struct ospf6_area *o6a;
+ int count;
++ u_int32_t area_id;
+
+ struct ospf6_router_lsa *router_lsa;
+ struct ospf6_router_lsd *router_lsd;
+@@ -1145,22 +1153,22 @@
+ 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_warn ("Update Router-LSA: No such area: %s", buffer);
+- return;
++ zlog_info ("LSA: Update Router-LSA: No such area: %s", buffer);
++ return 0;
+ }
+
+- if (IS_OSPF6_DUMP_LSA)
+- zlog_info ("Update Router-LSA: for Area %s", o6a->str);
++ /* clear thread */
++ o6a->thread_router_lsa = NULL;
+
+- /* find previous LSA */
+- /* xxx, there may be multiple Router-LSAs */
+- old = ospf6_lsdb_lookup (htons (OSPF6_LSA_TYPE_ROUTER),
+- htonl (0), o6a->ospf6->router_id, o6a);
++ 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));
+@@ -1277,6 +1285,42 @@
+ 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
+@@ -1284,7 +1328,7 @@
+ {
+ struct ospf6_neighbor *o6n = neighbor;
+ if (o6n->ospf6_interface->area)
+- ospf6_lsa_router_update (o6n->ospf6_interface->area->area_id);
++ ospf6_lsa_schedule_router (o6n->ospf6_interface->area);
+ return 0;
+ }
+
+@@ -1293,7 +1337,7 @@
+ {
+ struct ospf6_interface *o6i = interface;
+ if (o6i->area)
+- ospf6_lsa_router_update (o6i->area->area_id);
++ ospf6_lsa_schedule_router (o6i->area);
+ return 0;
+ }
+
+@@ -1301,7 +1345,7 @@
+ ospf6_lsa_router_hook_area (void *area)
+ {
+ struct ospf6_area *o6a = area;
+- ospf6_lsa_router_update (o6a->area_id);
++ ospf6_lsa_schedule_router (o6a);
+ return 0;
+ }
+
+@@ -1315,7 +1359,7 @@
+ for (node = listhead (o6->area_list); node; nextnode (node))
+ {
+ o6a = getdata (node);
+- ospf6_lsa_router_update (o6a->area_id);
++ ospf6_lsa_schedule_router (o6a);
+ }
+ return 0;
+ }
+@@ -1327,7 +1371,7 @@
+ struct ospf6_area *o6a;
+
+ o6a = lsa->scope;
+- ospf6_lsa_router_update (o6a->area_id);
++ ospf6_lsa_schedule_router (o6a);
+ return 0;
+ }
+
+diff -x CVS -urN ospf6d.old/ospf6_lsa.h ospf6d/ospf6_lsa.h
+--- ospf6d.old/ospf6_lsa.h Sat Apr 26 23:17:47 2003
++++ ospf6d/ospf6_lsa.h Sat Nov 9 11:25:30 2002
+@@ -25,6 +25,13 @@
+
+ #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
+@@ -211,6 +218,7 @@
+ 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 */
+@@ -397,22 +405,22 @@
+
+ u_short ospf6_lsa_checksum (struct ospf6_lsa_header *);
+
+-void ospf6_lsa_update_router (u_int32_t area_id);
+ 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);
+
+-void ospf6_lsa_reoriginate (struct ospf6_lsa *);
+-void
+-ospf6_lsa_originate (u_int16_t, u_int32_t, u_int32_t, char *, int, void *);
+-
+ 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 -x CVS -urN ospf6d.old/ospf6_message.c ospf6d/ospf6_message.c
+--- ospf6d.old/ospf6_message.c Sat Apr 26 23:17:47 2003
++++ ospf6d/ospf6_message.c Sat Nov 9 11:25:30 2002
+@@ -1108,14 +1108,14 @@
+ if (!o6n)
+ {
+ if (IS_OSPF6_DUMP_LSACK)
+- zlog_info (" neighbor not found, reject");
++ zlog_info ("LSACK: 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");
++ if (IS_OSPF6_DUMP_LSACK)
++ zlog_info ("LSACK: From Secondary I/F of the neighbor: ignore");
+ return;
+ }
+
+@@ -1123,7 +1123,7 @@
+ if (o6n->state < NBS_EXCHANGE)
+ {
+ if (IS_OSPF6_DUMP_LSACK)
+- zlog_info (" neighbor state less than Exchange, reject");
++ zlog_info ("LSACK: neighbor state less than Exchange, reject");
+ return;
+ }
+
+@@ -1141,7 +1141,7 @@
+ if (!copy)
+ {
+ if (IS_OSPF6_DUMP_LSACK)
+- zlog_info ("no database copy, ignore");
++ zlog_info ("LSACK: no database copy, ignore");
+ continue;
+ }
+
+@@ -1152,7 +1152,7 @@
+ if (rem == NULL)
+ {
+ if (IS_OSPF6_DUMP_LSACK)
+- zlog_info ("not on %s's retranslist, ignore", o6n->str);
++ zlog_info ("LSACK: not on %s's retranslist, ignore", o6n->str);
+ continue;
+ }
+
+@@ -1167,7 +1167,13 @@
+ {
+ /* Log the questionable acknowledgement,
+ and examine the next one. */
+- zlog_warn ("LSAck: questionable acknowledge: LSAs differ");
++ 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 */
+@@ -1242,6 +1248,22 @@
+ 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)
+@@ -1252,10 +1274,6 @@
+ return;
+ }
+
+- /* message type check */
+- type = (ospf6_header->type >= OSPF6_MESSAGE_TYPE_MAX ?
+- OSPF6_MESSAGE_TYPE_UNKNOWN : ospf6_header->type);
+-
+ /* octet statistics relies on some asumption:
+ on ethernet, no IPv6 Extention header, etc */
+ #define OSPF6_IP6_HEADER_SIZE 40
+@@ -1280,12 +1298,14 @@
+ struct ospf6_header ospf6_header;
+ char buffer[OSPF6_MESSAGE_RECEIVE_BUFSIZE];
+ struct ospf6_interface *o6i;
+- char srcname[64], dstname[64];
+ 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));
+@@ -1302,22 +1322,10 @@
+ o6i = ospf6_interface_lookup_by_index (ifindex);
+ if (!o6i || !o6i->area)
+ {
+- zlog_warn ("*** received interface ospf6 disabled");
+- thread_add_read (master, ospf6_receive, NULL, sockfd);
++ //zlog_warn ("*** received interface ospf6 disabled");
+ return 0;
+ }
+
+- /* log */
+- if (IS_OSPF6_DUMP_MESSAGE (type))
+- {
+- 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);
+- }
+-
+ /* if not passive, process message */
+ if (! CHECK_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_PASSIVE))
+ ospf6_message_process (message, &src, &dst, o6i);
+@@ -1325,9 +1333,6 @@
+ zlog_info ("Ignore message on passive interface %s",
+ o6i->interface->name);
+
+- /* add next read thread */
+- thread_add_read (master, ospf6_receive, NULL, sockfd);
+-
+ return 0;
+ }
+
+@@ -1828,6 +1833,9 @@
+ 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++;
+
+@@ -1915,6 +1923,9 @@
+
+ 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;
+
+diff -x CVS -urN ospf6d.old/ospf6_neighbor.c ospf6d/ospf6_neighbor.c
+--- ospf6d.old/ospf6_neighbor.c Sat Apr 26 23:17:47 2003
++++ ospf6d/ospf6_neighbor.c Sat Nov 9 11:25:30 2002
+@@ -179,6 +179,13 @@
+ }
+
+ 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
+diff -x CVS -urN ospf6d.old/ospf6_network.c ospf6d/ospf6_network.c
+--- ospf6d.old/ospf6_network.c Sat Apr 26 23:17:47 2003
++++ ospf6d/ospf6_network.c Tue Oct 1 10:28:08 2002
+@@ -255,8 +255,10 @@
+ &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
+@@ -273,8 +275,10 @@
+ &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
+@@ -290,8 +294,10 @@
+ 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 */
+diff -x CVS -urN ospf6d.old/ospf6_route.h ospf6d/ospf6_route.h
+--- ospf6d.old/ospf6_route.h Sat Apr 26 23:17:47 2003
++++ ospf6d/ospf6_route.h Tue Oct 1 00:41:10 2002
+@@ -186,6 +186,9 @@
+ 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 *),
+diff -x CVS -urN ospf6d.old/ospf6_routemap.c ospf6d/ospf6_routemap.c
+--- ospf6d.old/ospf6_routemap.c Sat Apr 26 23:17:47 2003
++++ ospf6d/ospf6_routemap.c Tue Oct 1 00:41:10 2002
+@@ -22,9 +22,6 @@
+
+ #include <zebra.h>
+
+-#if 1
+-#include "ospf6d.h"
+-#else
+ #include "log.h"
+ #include "memory.h"
+ #include "linklist.h"
+@@ -32,11 +29,13 @@
+ #include "command.h"
+ #include "vty.h"
+ #include "routemap.h"
++#include "table.h"
+ #include "plist.h"
+
+-#include "ospf6_top.h"
+-#include "ospf6_redistribute.h"
+-#endif
++#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,
+@@ -70,7 +69,8 @@
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+ }
+
+-struct route_map_rule_cmd ospf6_routemap_rule_match_address_prefixlist_cmd =
++struct route_map_rule_cmd
++ospf6_routemap_rule_match_address_prefixlist_cmd =
+ {
+ "ipv6 address prefix-list",
+ ospf6_routemap_rule_match_address_prefixlist,
+@@ -83,15 +83,15 @@
+ route_map_object_t type, void *object)
+ {
+ char *metric_type = rule;
+- struct ospf6_route_req *route = object;
++ struct ospf6_external_info *info = object;
+
+ if (type != RMAP_OSPF6)
+ return RMAP_OKAY;
+
+ if (strcmp (metric_type, "type-2") == 0)
+- route->path.metric_type = 2;
++ info->metric_type = 2;
+ else
+- route->path.metric_type = 1;
++ info->metric_type = 1;
+
+ return RMAP_OKAY;
+ }
+@@ -108,7 +108,8 @@
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+ }
+
+-struct route_map_rule_cmd ospf6_routemap_rule_set_metric_type_cmd =
++struct route_map_rule_cmd
++ospf6_routemap_rule_set_metric_type_cmd =
+ {
+ "metric-type",
+ ospf6_routemap_rule_set_metric_type,
+@@ -121,14 +122,12 @@
+ route_map_object_t type, void *object)
+ {
+ char *metric = rule;
+- struct ospf6_route_req *route = object;
++ struct ospf6_external_info *info = object;
+
+ if (type != RMAP_OSPF6)
+ return RMAP_OKAY;
+
+- route->path.cost = atoi (metric);
+- route->path.cost_e2 = atoi (metric);
+-
++ info->metric = atoi (metric);
+ return RMAP_OKAY;
+ }
+
+@@ -144,7 +143,8 @@
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+ }
+
+-struct route_map_rule_cmd ospf6_routemap_rule_set_metric_cmd =
++struct route_map_rule_cmd
++ospf6_routemap_rule_set_metric_cmd =
+ {
+ "metric",
+ ospf6_routemap_rule_set_metric,
+@@ -157,14 +157,14 @@
+ route_map_object_t type, void *object)
+ {
+ char *forwarding = rule;
+- struct ospf6_route_req *route = object;
++ struct ospf6_external_info *info = object;
+
+ if (type != RMAP_OSPF6)
+ return RMAP_OKAY;
+
+- if (inet_pton (AF_INET6, forwarding, &route->nexthop.address) != 1)
++ if (inet_pton (AF_INET6, forwarding, &info->forwarding) != 1)
+ {
+- memset (&route->nexthop.address, 0, sizeof (struct in6_addr));
++ memset (&info->forwarding, 0, sizeof (struct in6_addr));
+ return RMAP_ERROR;
+ }
+
+@@ -183,7 +183,8 @@
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+ }
+
+-struct route_map_rule_cmd ospf6_routemap_rule_set_forwarding_cmd =
++struct route_map_rule_cmd
++ospf6_routemap_rule_set_forwarding_cmd =
+ {
+ "forwarding-address",
+ ospf6_routemap_rule_set_forwarding,
+@@ -331,8 +332,8 @@
+ {
+ route_map_init ();
+ route_map_init_vty ();
+- route_map_add_hook (ospf6_redistribute_routemap_update);
+- route_map_delete_hook (ospf6_redistribute_routemap_update);
++ 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);
+diff -x CVS -urN ospf6d.old/ospf6_spf.c ospf6d/ospf6_spf.c
+--- ospf6d.old/ospf6_spf.c Sat Apr 26 23:17:47 2003
++++ ospf6d/ospf6_spf.c Sat Nov 9 11:25:30 2002
+@@ -281,7 +281,7 @@
+ static struct in6_addr *
+ ospf6_spf_get_ipaddr (u_int32_t id, u_int32_t adv_router, u_int32_t ifindex)
+ {
+- char buf[64];
++ char buf[64], nhbuf[64];
+ struct ospf6_interface *o6i;
+ struct ospf6_neighbor *o6n;
+ struct ospf6_lsa *lsa;
+@@ -303,26 +303,30 @@
+ lsa = node.lsa;
+
+ /* return Linklocal Address field if the Link-LSA exists */
+- if (lsa)
++ 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, "
+- "use source address from his packet",
++ 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",
++ 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;
+ }
+
+@@ -478,18 +482,22 @@
+ inet_ntop (AF_INET, &adv_router, buf_router, sizeof (buf_router));
+ inet_ntop (AF_INET, &id, buf_id, sizeof (buf_id));
+
+- if (type == htons (OSPF6_LSA_TYPE_ROUTER))
+- zlog_err ("SPF: Can't find LSA for W (%s *): not found",
+- buf_router);
+- else
+- zlog_err ("SPF: Can't find LSA for W (%s %s): not found",
+- buf_router, 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))
+ {
+- zlog_err ("SPF: Associated LSA for W is MaxAge: %s", lsa->str);
++ if (IS_OSPF6_DUMP_SPF)
++ zlog_info ("SPF: Associated LSA for W is MaxAge: %s", lsa->str);
+ return (struct ospf6_vertex *) NULL;
+ }
+
+@@ -504,8 +512,9 @@
+ }
+ if (! backreference)
+ {
+- zlog_err ("SPF: Back reference failed: V: %s, W: %s",
+- V->lsa->str, lsa->str);
++ 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;
+ }
+
+diff -x CVS -urN ospf6d.old/ospf6_top.c ospf6d/ospf6_top.c
+--- ospf6d.old/ospf6_top.c Sat Apr 26 23:17:47 2003
++++ ospf6d/ospf6_top.c Tue Oct 1 00:51:40 2002
+@@ -43,7 +43,6 @@
+ #include "ospf6_area.h"
+ #include "ospf6_top.h"
+
+-#include "ospf6_redistribute.h"
+ #include "ospf6_route.h"
+ #include "ospf6_zebra.h"
+
+@@ -152,7 +151,7 @@
+ vty_out (vty, " Supports only single TOS(TOS0) routes%s", VTY_NEWLINE);
+
+ /* Redistribute config */
+- ospf6_redistribute_show_config (vty, ospf6);
++ ospf6_redistribute_show_config (vty);
+
+ /* LSAs */
+ vty_out (vty, " Number of AS scoped LSAs is %u%s",
+@@ -250,9 +249,6 @@
+
+ o6->lsdb = ospf6_lsdb_create ();
+
+- /* route table init */
+- ospf6_redistribute_init (o6);
+-
+ o6->foreach_area = ospf6_top_foreach_area;
+ o6->foreach_if = ospf6_top_foreach_interface;
+ o6->foreach_nei = ospf6_top_foreach_neighbor;
+@@ -264,12 +260,14 @@
+ 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);
+diff -x CVS -urN ospf6d.old/ospf6_zebra.c ospf6d/ospf6_zebra.c
+--- ospf6d.old/ospf6_zebra.c Sat Apr 26 23:17:47 2003
++++ ospf6d/ospf6_zebra.c Wed Oct 2 17:16:56 2002
+@@ -22,7 +22,7 @@
+ #include "ospf6d.h"
+
+ #include "ospf6_interface.h"
+-#include "ospf6_redistribute.h"
++#include "ospf6_asbr.h"
+
+ #include "ospf6_linklist.h"
+
+@@ -202,13 +202,14 @@
+ struct stream *s;
+ struct zapi_ipv6 api;
+ unsigned long ifindex;
+- struct in6_addr nexthop;
+ struct prefix_ipv6 p;
++ struct in6_addr *nexthop;
+ char prefixstr[128], nexthopstr[128];
+
+ s = zclient->ibuf;
+ ifindex = 0;
+- memset (&nexthop, 0, sizeof (struct in6_addr));
++ nexthop = NULL;
++ memset (&api, 0, sizeof (api));
+
+ /* Type, flags, message. */
+ api.type = stream_getc (s);
+@@ -225,7 +226,9 @@
+ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP))
+ {
+ api.nexthop_num = stream_getc (s);
+- stream_get (&nexthop, s, 16);
++ 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))
+ {
+@@ -256,11 +259,15 @@
+ zebra_route_name [api.type], prefixstr,
+ nexthopstr, ifindex);
+ }
+-
++
+ if (command == ZEBRA_IPV6_ROUTE_ADD)
+- ospf6_redistribute_route_add (api.type, ifindex, &p);
++ ospf6_asbr_route_add (api.type, ifindex, (struct prefix *) &p,
++ api.nexthop_num, nexthop);
+ else
+- ospf6_redistribute_route_remove (api.type, ifindex, &p);
++ ospf6_asbr_route_remove (api.type, ifindex, (struct prefix *) &p);
++
++ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP))
++ free (nexthop);
+
+ return 0;
+ }
+@@ -448,10 +455,6 @@
+
+ if (IS_OSPF6_DUMP_ZEBRA)
+ zlog_info ("ZEBRA: found alternative path to add");
+-
+- linklist_remove (nexthop, nexthop_list);
+- XFREE (MTYPE_OSPF6_OTHER, nexthop);
+- assert (nexthop_list->count == 0);
+
+ memcpy (&seconde_path, &route.path, sizeof (struct ospf6_path));
+ type = ADD;
+diff -x CVS -urN ospf6d.old/ospf6d.c ospf6d/ospf6d.c
+--- ospf6d.old/ospf6d.c Sat Apr 26 23:17:47 2003
++++ ospf6d/ospf6d.c Mon Mar 24 17:45:16 2003
+@@ -21,6 +21,8 @@
+
+ #include "ospf6d.h"
+
++#include "ospf6_damp.h"
++
+ /* global ospf6d variable */
+ int ospf6_sock;
+ list iflist;
+@@ -536,8 +538,8 @@
+ return CMD_SUCCESS;
+ }
+
+-DEFUN (area_range,
+- area_range_cmd,
++DEFUN (ospf6_area_range,
++ ospf6_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"
+@@ -689,6 +691,7 @@
+ 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))
+ {
+@@ -745,7 +748,7 @@
+ 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);
++ install_element (OSPF6_NODE, &ospf6_area_range_cmd);
+
+ /* Make empty list of top list. */
+ if_init ();
+@@ -757,6 +760,10 @@
+ prefix_list_init ();
+
+ ospf6_dump_init ();
++
++#ifdef HAVE_OSPF6_DAMP
++ ospf6_damp_init ();
++#endif /*HAVE_OSPF6_DAMP*/
+
+ ospf6_hook_init ();
+ ospf6_lsa_init ();
+diff -x CVS -urN ospf6d.old/ospf6d.h ospf6d/ospf6d.h
+--- ospf6d.old/ospf6d.h Sat Apr 26 23:17:47 2003
++++ ospf6d/ospf6d.h Fri Apr 25 11:40:31 2003
+@@ -59,7 +59,6 @@
+ #include "ospf6_neighbor.h"
+ #include "ospf6_ism.h"
+ #include "ospf6_nsm.h"
+-#include "ospf6_redistribute.h"
+ #include "ospf6_route.h"
+ #include "ospf6_dbex.h"
+ #include "ospf6_network.h"
+@@ -74,7 +73,7 @@
+ #define HASHVAL 64
+ #define MAXIOVLIST 1024
+
+-#define OSPF6_DAEMON_VERSION "0.9.6l"
++#define OSPF6_DAEMON_VERSION "0.9.6p"
+
+ #define AF_LINKSTATE 0xff
+