[ospf6d] GNU Zebra #3562: ABR Crash fix, memory fixes, route table debugs

2006-02-22  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>

	* valgrind check and memory fix
	* route table identification string added
	* ospf6d.h: version 0.9.7q
diff --git a/ospf6d/ChangeLog b/ospf6d/ChangeLog
index 2676a3f..01064aa 100644
--- a/ospf6d/ChangeLog
+++ b/ospf6d/ChangeLog
@@ -1,3 +1,9 @@
+2006-02-22  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* valgrind check and memory fix
+	* route table identification string added
+	* ospf6d.h: version 0.9.7q
+
 2005-10-20  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
 
 	* ospf6_neighbor.c: add the calling of ospf6_maxage_remove ()
diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c
index 833a1bc..180a204 100644
--- a/ospf6d/ospf6_abr.c
+++ b/ospf6d/ospf6_abr.c
@@ -538,6 +538,8 @@
   char buf[64];
   int is_debug = 0;
 
+  memset (&prefix, 0, sizeof (prefix));
+
   if (lsa->header->type == htons (OSPF6_LSTYPE_INTER_PREFIX))
     {
       struct ospf6_inter_prefix_lsa *prefix_lsa;
@@ -593,7 +595,8 @@
       if (route->path.area_id == oa->area_id &&
           route->path.origin.type == lsa->header->type &&
           route->path.origin.id == lsa->header->id &&
-          route->path.origin.adv_router == lsa->header->adv_router)
+          route->path.origin.adv_router == lsa->header->adv_router &&
+          ! CHECK_FLAG (route->flag, OSPF6_ROUTE_WAS_REMOVED))
         old = route;
       route = ospf6_route_next (route);
     }
diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c
index 9368def..94283db 100644
--- a/ospf6d/ospf6_area.c
+++ b/ospf6d/ospf6_area.c
@@ -149,14 +149,19 @@
   oa->lsdb->hook_remove = ospf6_area_lsdb_hook_remove;
   oa->lsdb_self = ospf6_lsdb_create (oa);
 
-  oa->spf_table = ospf6_route_table_create ();
-  oa->route_table = ospf6_route_table_create ();
+  oa->spf_table = OSPF6_ROUTE_TABLE_CREATE (AREA, SPF_RESULTS);
+  oa->spf_table->scope = oa;
+  oa->route_table = OSPF6_ROUTE_TABLE_CREATE (AREA, ROUTES);
+  oa->route_table->scope = oa;
   oa->route_table->hook_add = ospf6_area_route_hook_add;
   oa->route_table->hook_remove = ospf6_area_route_hook_remove;
 
-  oa->range_table = ospf6_route_table_create ();
-  oa->summary_prefix = ospf6_route_table_create ();
-  oa->summary_router = ospf6_route_table_create ();
+  oa->range_table = OSPF6_ROUTE_TABLE_CREATE (AREA, PREFIX_RANGES);
+  oa->range_table->scope = oa;
+  oa->summary_prefix = OSPF6_ROUTE_TABLE_CREATE (AREA, SUMMARY_PREFIXES);
+  oa->summary_prefix->scope = oa;
+  oa->summary_router = OSPF6_ROUTE_TABLE_CREATE (AREA, SUMMARY_ROUTERS);
+  oa->summary_router->scope = oa;
 
   /* set default options */
   OSPF6_OPT_SET (oa->options, OSPF6_OPT_V6);
@@ -719,7 +724,7 @@
   tmp_debug_ospf6_spf = conf_debug_ospf6_spf;
   conf_debug_ospf6_spf = 0;
 
-  spf_table = ospf6_route_table_create ();
+  spf_table = OSPF6_ROUTE_TABLE_CREATE (NONE, SPF_RESULTS);
   ospf6_spf_calculation (router_id, spf_table, oa);
 
   conf_debug_ospf6_spf = tmp_debug_ospf6_spf;
diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c
index 3ca5e2d..95464b6 100644
--- a/ospf6d/ospf6_interface.c
+++ b/ospf6d/ospf6_interface.c
@@ -139,7 +139,8 @@
   oi->lsdb->hook_remove = ospf6_interface_lsdb_hook;
   oi->lsdb_self = ospf6_lsdb_create (oi);
 
-  oi->route_connected = ospf6_route_table_create ();
+  oi->route_connected = OSPF6_ROUTE_TABLE_CREATE (INTERFACE, CONNECTED_ROUTES);
+  oi->route_connected->scope = oi;
 
   /* link both */
   oi->interface = ifp;
diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c
index 0be88f0..ffd9c72 100644
--- a/ospf6d/ospf6_intra.c
+++ b/ospf6d/ospf6_intra.c
@@ -721,7 +721,7 @@
   intra_prefix_lsa->ref_id = htonl (0);
   intra_prefix_lsa->ref_adv_router = oa->ospf6->router_id;
 
-  route_advertise = ospf6_route_table_create ();
+  route_advertise = ospf6_route_table_create (0, 0);
 
   for (ALL_LIST_ELEMENTS_RO (oa->if_list, i, oi))
     {
@@ -900,7 +900,7 @@
     }
 
   /* connected prefix to advertise */
-  route_advertise = ospf6_route_table_create ();
+  route_advertise = ospf6_route_table_create (0, 0);
 
   type = ntohs (OSPF6_LSTYPE_LINK);
   for (lsa = ospf6_lsdb_type_head (type, oi->lsdb); lsa;
@@ -1239,6 +1239,58 @@
 }
 
 void
+ospf6_brouter_debug_print (struct ospf6_route *brouter)
+{
+  u_int32_t brouter_id;
+  char brouter_name[16];
+  char area_name[16];
+  char destination[64];
+  char installed[16], changed[16];
+  struct timeval now, res;
+  char id[16], adv_router[16];
+  char capa[16], options[16];
+
+  brouter_id = ADV_ROUTER_IN_PREFIX (&brouter->prefix);
+  inet_ntop (AF_INET, &brouter_id, brouter_name, sizeof (brouter_name));
+  inet_ntop (AF_INET, &brouter->path.area_id, area_name, sizeof (area_name));
+  ospf6_linkstate_prefix2str (&brouter->prefix, destination,
+                              sizeof (destination));
+
+  gettimeofday (&now, (struct timezone *) NULL);
+  timersub (&now, &brouter->installed, &res);
+  timerstring (&res, installed, sizeof (installed));
+
+  gettimeofday (&now, (struct timezone *) NULL);
+  timersub (&now, &brouter->changed, &res);
+  timerstring (&res, changed, sizeof (changed));
+
+  inet_ntop (AF_INET, &brouter->path.origin.id, id, sizeof (id));
+  inet_ntop (AF_INET, &brouter->path.origin.adv_router, adv_router,
+             sizeof (adv_router));
+
+  ospf6_options_printbuf (brouter->path.options, options, sizeof (options));
+  ospf6_capability_printbuf (brouter->path.router_bits, capa, sizeof (capa));
+
+  zlog_info ("Brouter: %s via area %s", brouter_name, area_name);
+  zlog_info ("  memory: prev: %p this: %p next: %p parent rnode: %p",
+             brouter->prev, brouter, brouter->next, brouter->rnode);
+  zlog_info ("  type: %d prefix: %s installed: %s changed: %s",
+             brouter->type, destination, installed, changed);
+  zlog_info ("  lock: %d flags: %s%s%s%s", brouter->lock,
+           (CHECK_FLAG (brouter->flag, OSPF6_ROUTE_BEST)   ? "B" : "-"),
+           (CHECK_FLAG (brouter->flag, OSPF6_ROUTE_ADD)    ? "A" : "-"),
+           (CHECK_FLAG (brouter->flag, OSPF6_ROUTE_REMOVE) ? "R" : "-"),
+           (CHECK_FLAG (brouter->flag, OSPF6_ROUTE_CHANGE) ? "C" : "-"));
+  zlog_info ("  path type: %s ls-origin %s id: %s adv-router %s",
+             OSPF6_PATH_TYPE_NAME (brouter->path.type),
+             ospf6_lstype_name (brouter->path.origin.type),
+             id, adv_router);
+  zlog_info ("  options: %s router-bits: %s metric-type: %d metric: %d/%d",
+             options, capa, brouter->path.metric_type,
+             brouter->path.cost, brouter->path.cost_e2);
+}
+
+void
 ospf6_intra_brouter_calculation (struct ospf6_area *oa)
 {
   struct ospf6_route *brouter, *copy;
@@ -1259,14 +1311,27 @@
   for (brouter = ospf6_route_head (oa->ospf6->brouter_table); brouter;
        brouter = ospf6_route_next (brouter))
     {
+      brouter_id = ADV_ROUTER_IN_PREFIX (&brouter->prefix);
+      inet_ntop (AF_INET, &brouter_id, brouter_name, sizeof (brouter_name));
       if (brouter->path.area_id != oa->area_id)
         continue;
       brouter->flag = OSPF6_ROUTE_REMOVE;
+
+      if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID (brouter_id) ||
+          IS_OSPF6_DEBUG_ROUTE (MEMORY))
+        {
+          zlog_info ("%p: mark as removing: area %s brouter %s",
+                     brouter, oa->name, brouter_name);
+          ospf6_brouter_debug_print (brouter);
+        }
     }
 
   for (brouter = ospf6_route_head (oa->spf_table); brouter;
        brouter = ospf6_route_next (brouter))
     {
+      brouter_id = ADV_ROUTER_IN_PREFIX (&brouter->prefix);
+      inet_ntop (AF_INET, &brouter_id, brouter_name, sizeof (brouter_name));
+
       if (brouter->type != OSPF6_DEST_TYPE_LINKSTATE)
         continue;
       if (ospf6_linkstate_prefix_id (&brouter->prefix) != htonl (0))
@@ -1279,6 +1344,14 @@
       copy->type = OSPF6_DEST_TYPE_ROUTER;
       copy->path.area_id = oa->area_id;
       ospf6_route_add (copy, oa->ospf6->brouter_table);
+
+      if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID (brouter_id) ||
+          IS_OSPF6_DEBUG_ROUTE (MEMORY))
+        {
+          zlog_info ("%p: transfer: area %s brouter %s",
+                     brouter, oa->name, brouter_name);
+          ospf6_brouter_debug_print (brouter);
+        }
     }
 
   oa->ospf6->brouter_table->hook_add = hook_add;
@@ -1320,6 +1393,7 @@
               IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID (oa->area_id))
             zlog_info ("brouter %s appears via area %s",
                        brouter_name, oa->name);
+
           /* newly added */
           if (hook_add)
             (*hook_add) (brouter);
diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c
index fbda675..6ece88b 100644
--- a/ospf6d/ospf6_message.c
+++ b/ospf6d/ospf6_message.c
@@ -1120,10 +1120,9 @@
 		    on->name);
 
       ospf6_decrement_retrans_count (mine);
-      ospf6_lsdb_remove (mine, on->retrans_list);
       if (OSPF6_LSA_IS_MAXAGE (mine))
         ospf6_maxage_remove (on->ospf6_if->area->ospf6);
-
+      ospf6_lsdb_remove (mine, on->retrans_list);
       ospf6_lsa_delete (his);
     }
 
@@ -1186,6 +1185,9 @@
   thread_add_read (master, ospf6_receive, NULL, sockfd);
 
   /* initialize */
+  memset (&src, 0, sizeof (src));
+  memset (&dst, 0, sizeof (dst));
+  ifindex = 0;
   memset (recvbuf, 0, iobuflen);
   iovector[0].iov_base = recvbuf;
   iovector[0].iov_len = iobuflen;
diff --git a/ospf6d/ospf6_network.c b/ospf6d/ospf6_network.c
index 4df7c9d..8c0cbf5 100644
--- a/ospf6d/ospf6_network.c
+++ b/ospf6d/ospf6_network.c
@@ -254,6 +254,7 @@
   /* scmsgp = CMSG_NXTHDR (&smsghdr, scmsgp); */
 
   /* send msg hdr */
+  memset (&smsghdr, 0, sizeof (smsghdr));
   smsghdr.msg_iov = message;
   smsghdr.msg_iovlen = iov_count (message);
   smsghdr.msg_name = (caddr_t) &dst_sin6;
@@ -291,6 +292,7 @@
   /* rcmsgp = CMSG_NXTHDR (&rmsghdr, rcmsgp); */
 
   /* receive msg hdr */
+  memset (&rmsghdr, 0, sizeof (rmsghdr));
   rmsghdr.msg_iov = message;
   rmsghdr.msg_iovlen = iov_count (message);
   rmsghdr.msg_name = (caddr_t) &src_sin6;
diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c
index 521d8ad..38fdd51 100644
--- a/ospf6d/ospf6_route.c
+++ b/ospf6d/ospf6_route.c
@@ -27,15 +27,112 @@
 #include "table.h"
 #include "vty.h"
 #include "command.h"
+#include "linklist.h"
 
 #include "ospf6_proto.h"
 #include "ospf6_lsa.h"
 #include "ospf6_lsdb.h"
 #include "ospf6_route.h"
+#include "ospf6_top.h"
+#include "ospf6_area.h"
+#include "ospf6_interface.h"
 #include "ospf6d.h"
 
 unsigned char conf_debug_ospf6_route = 0;
 
+static char *
+ospf6_route_table_name (struct ospf6_route_table *table)
+{
+  static char name[32];
+  switch (table->scope_type)
+    {
+      case OSPF6_SCOPE_TYPE_GLOBAL:
+        {
+          switch (table->table_type)
+            {
+              case OSPF6_TABLE_TYPE_ROUTES:
+                snprintf (name, sizeof (name), "global route table");
+                break;
+              case OSPF6_TABLE_TYPE_BORDER_ROUTERS:
+                snprintf (name, sizeof (name), "global brouter table");
+                break;
+              case OSPF6_TABLE_TYPE_EXTERNAL_ROUTES:
+                snprintf (name, sizeof (name), "global external table");
+                break;
+              default:
+                snprintf (name, sizeof (name), "global unknown table");
+                break;
+            }
+        }
+        break;
+
+      case OSPF6_SCOPE_TYPE_AREA:
+        {
+          struct ospf6_area *oa = (struct ospf6_area *) table->scope;
+          switch (table->table_type)
+            {
+              case OSPF6_TABLE_TYPE_SPF_RESULTS:
+                snprintf (name, sizeof (name),
+                          "area %s spf table", oa->name);
+                break;
+              case OSPF6_TABLE_TYPE_ROUTES:
+                snprintf (name, sizeof (name),
+                          "area %s route table", oa->name);
+                break;
+              case OSPF6_TABLE_TYPE_PREFIX_RANGES:
+                snprintf (name, sizeof (name),
+                          "area %s range table", oa->name);
+                break;
+              case OSPF6_TABLE_TYPE_SUMMARY_PREFIXES:
+                snprintf (name, sizeof (name),
+                          "area %s summary prefix table", oa->name);
+                break;
+              case OSPF6_TABLE_TYPE_SUMMARY_ROUTERS:
+                snprintf (name, sizeof (name),
+                          "area %s summary router table", oa->name);
+                break;
+              default:
+                snprintf (name, sizeof (name),
+                          "area %s unknown table", oa->name);
+                break;
+            }
+        }
+        break;
+
+      case OSPF6_SCOPE_TYPE_INTERFACE:
+        {
+          struct ospf6_interface *oi = (struct ospf6_interface *) table->scope;
+          switch (table->table_type)
+            {
+              case OSPF6_TABLE_TYPE_CONNECTED_ROUTES:
+                snprintf (name, sizeof (name), "interface %s connected table",
+                          oi->interface->name);
+                break;
+              default:
+                snprintf (name, sizeof (name), "interface %s unknown table",
+                          oi->interface->name);
+                break;
+            }
+        }
+        break;
+
+      default:
+        {
+          switch (table->table_type)
+            {
+              case OSPF6_TABLE_TYPE_SPF_RESULTS:
+                snprintf (name, sizeof (name), "temporary spf table");
+                break;
+              default:
+                snprintf (name, sizeof (name), "temporary unknown table");
+                break;
+            }
+        }
+        break;
+    }
+  return name;
+}
+
 void
 ospf6_linkstate_prefix (u_int32_t adv_router, u_int32_t id,
                         struct prefix *prefix)
@@ -100,6 +197,7 @@
   new->rnode = NULL;
   new->prev = NULL;
   new->next = NULL;
+  new->table = NULL;
   new->lock = 0;
   return new;
 }
@@ -116,7 +214,13 @@
   assert (route->lock > 0);
   route->lock--;
   if (route->lock == 0)
-    ospf6_route_delete (route);
+    {
+      /* Can't detach from the table until here
+         because ospf6_route_next () will use
+         the 'route->table' pointer for logging */
+      route->table = NULL;
+      ospf6_route_delete (route);
+    }
 }
 
 /* Route compare function. If ra is more preferred, it returns
@@ -202,33 +306,50 @@
 
 #ifndef NDEBUG
 static void
-_route_count_assert (struct ospf6_route_table *table)
+route_table_assert (struct ospf6_route_table *table)
 {
-  struct ospf6_route *debug;
+  struct ospf6_route *prev, *r, *next;
   char buf[64];
-  unsigned int num = 0;
-  for (debug = ospf6_route_head (table); debug;
-       debug = ospf6_route_next (debug))
+  unsigned int link_error = 0, num = 0;
+  
+  r = ospf6_route_head (table);
+  prev = NULL;
+  while (r)
+    {
+      if (r->prev != prev)
+        link_error++;
+      
+      next = ospf6_route_next (r);
+      
+      if (r->next != next)
+        link_error++;
+      
+      prev = r;
+      r = next;
+    }
+  
+  for (r = ospf6_route_head (table); r; r = ospf6_route_next (r))
     num++;
-
-  if (num == table->count)
+  
+  if (link_error == 0 && num == table->count)
     return;
 
-  zlog_debug ("PANIC !! table[%p]->count = %d, real = %d",
-	      table, table->count, num);
-  for (debug = ospf6_route_head (table); debug;
-       debug = ospf6_route_next (debug))
+  zlog_err ("PANIC !!");
+  zlog_err ("Something has gone wrong with ospf6_route_table[%p]", table);
+  zlog_debug ("table count = %d, real number = %d", table->count, num);
+  zlog_debug ("DUMP START");
+  for (r = ospf6_route_head (table); r; r = ospf6_route_next (r))
     {
-      prefix2str (&debug->prefix, buf, sizeof (buf));
-      zlog_debug ("%p %p %s", debug->prev, debug->next, buf);
+      prefix2str (&r->prefix, buf, sizeof (buf));
+      zlog_info ("%p<-[%p]->%p : %s", r->prev, r, r->next, buf);
     }
   zlog_debug ("DUMP END");
 
-  assert (num == table->count);
+  assert (link_error == 0 && num == table->count);
 }
-#define ospf6_route_count_assert(t) (_route_count_assert (t))
+#define ospf6_route_table_assert(t) (route_table_assert (t))
 #else
-#define ospf6_route_count_assert(t) ((void) 0)
+#define ospf6_route_table_assert(t) ((void) 0)
 #endif /*NDEBUG*/
 
 struct ospf6_route *
@@ -251,8 +372,11 @@
   else
     prefix2str (&route->prefix, buf, sizeof (buf));
 
-  if (IS_OSPF6_DEBUG_ROUTE (TABLE))
-    zlog_debug ("route add %s", buf);
+  if (IS_OSPF6_DEBUG_ROUTE (MEMORY))
+    zlog_debug ("%s %p: route add %p: %s", ospf6_route_table_name (table),
+                table, route, buf);
+  else if (IS_OSPF6_DEBUG_ROUTE (TABLE))
+    zlog_debug ("%s: route add: %s", ospf6_route_table_name (table), buf);
 
   gettimeofday (&now, NULL);
 
@@ -282,18 +406,26 @@
       /* if route does not actually change, return unchanged */
       if (ospf6_route_is_identical (old, route))
         {
-          if (IS_OSPF6_DEBUG_ROUTE (TABLE))
-            zlog_debug ("  identical route found, ignore");
+          if (IS_OSPF6_DEBUG_ROUTE (MEMORY))
+            zlog_debug ("%s %p: route add %p: needless update of %p",
+                        ospf6_route_table_name (table), table, route, old);
+          else if (IS_OSPF6_DEBUG_ROUTE (TABLE))
+            zlog_debug ("%s: route add: needless update",
+                        ospf6_route_table_name (table));
 
           ospf6_route_delete (route);
           SET_FLAG (old->flag, OSPF6_ROUTE_ADD);
-          ospf6_route_count_assert (table);
+          ospf6_route_table_assert (table);
 
           return old;
         }
 
-      if (IS_OSPF6_DEBUG_ROUTE (TABLE))
-        zlog_debug ("  old route found, replace");
+      if (IS_OSPF6_DEBUG_ROUTE (MEMORY))
+        zlog_debug ("%s %p: route add %p: update of %p",
+                    ospf6_route_table_name (table), table, route, old);
+      else if (IS_OSPF6_DEBUG_ROUTE (TABLE))
+        zlog_debug ("%s: route add: update",
+                    ospf6_route_table_name (table));
 
       /* replace old one if exists */
       if (node->info == old)
@@ -311,12 +443,14 @@
 
       route->installed = old->installed;
       route->changed = now;
+      assert (route->table == NULL);
+      route->table = table;
 
       ospf6_route_unlock (old); /* will be deleted later */
       ospf6_route_lock (route);
 
       SET_FLAG (route->flag, OSPF6_ROUTE_CHANGE);
-      ospf6_route_count_assert (table);
+      ospf6_route_table_assert (table);
 
       if (table->hook_add)
         (*table->hook_add) (route);
@@ -327,8 +461,12 @@
   /* insert if previous or next node found */
   if (prev || next)
     {
-      if (IS_OSPF6_DEBUG_ROUTE (TABLE))
-        zlog_debug ("  another path found, insert");
+      if (IS_OSPF6_DEBUG_ROUTE (MEMORY))
+        zlog_debug ("%s %p: route add %p: another path: prev %p, next %p",
+                   ospf6_route_table_name (table), table, route, prev, next);
+      else if (IS_OSPF6_DEBUG_ROUTE (TABLE))
+        zlog_debug ("%s: route add: another path found",
+                    ospf6_route_table_name (table));
 
       if (prev == NULL)
         prev = next->prev;
@@ -348,14 +486,19 @@
           node->info = route;
           UNSET_FLAG (next->flag, OSPF6_ROUTE_BEST);
           SET_FLAG (route->flag, OSPF6_ROUTE_BEST);
+          if (IS_OSPF6_DEBUG_ROUTE (MEMORY))
+            zlog_info ("%s %p: route add %p: replacing previous best: %p",
+                       ospf6_route_table_name (table), table, route, next);
         }
 
       route->installed = now;
       route->changed = now;
+      assert (route->table == NULL);
+      route->table = table;
 
       ospf6_route_lock (route);
       table->count++;
-      ospf6_route_count_assert (table);
+      ospf6_route_table_assert (table);
 
       SET_FLAG (route->flag, OSPF6_ROUTE_ADD);
       if (table->hook_add)
@@ -365,8 +508,12 @@
     }
 
   /* Else, this is the brand new route regarding to the prefix */
-  if (IS_OSPF6_DEBUG_ROUTE (TABLE))
-    zlog_debug ("  brand new route, add");
+  if (IS_OSPF6_DEBUG_ROUTE (MEMORY))
+    zlog_debug ("%s %p: route add %p: brand new route",
+                ospf6_route_table_name (table), table, route);
+  else if (IS_OSPF6_DEBUG_ROUTE (TABLE))
+    zlog_debug ("%s: route add: brand new route",
+                ospf6_route_table_name (table));
 
   assert (node->info == NULL);
   node->info = route;
@@ -374,6 +521,8 @@
   ospf6_route_lock (route);
   route->installed = now;
   route->changed = now;
+  assert (route->table == NULL);
+  route->table = table;
 
   /* lookup real existing next route */
   nextnode = node;
@@ -416,7 +565,7 @@
     }
 
   table->count++;
-  ospf6_route_count_assert (table);
+  ospf6_route_table_assert (table);
 
   SET_FLAG (route->flag, OSPF6_ROUTE_ADD);
   if (table->hook_add)
@@ -438,8 +587,11 @@
   else
     prefix2str (&route->prefix, buf, sizeof (buf));
 
-  if (IS_OSPF6_DEBUG_ROUTE (TABLE))
-    zlog_debug ("route remove: %s", buf);
+  if (IS_OSPF6_DEBUG_ROUTE (MEMORY))
+    zlog_debug ("%s %p: route remove %p: %s",
+                ospf6_route_table_name (table), table, route, buf);
+  else if (IS_OSPF6_DEBUG_ROUTE (TABLE))
+    zlog_debug ("%s: route remove: %s", ospf6_route_table_name (table), buf);
 
   node = route_node_lookup (table->table, &route->prefix);
   assert (node);
@@ -473,7 +625,7 @@
     }
 
   table->count--;
-  ospf6_route_count_assert (table);
+  ospf6_route_table_assert (table);
 
   SET_FLAG (route->flag, OSPF6_ROUTE_WAS_REMOVED);
 
@@ -504,7 +656,14 @@
 
   route = (struct ospf6_route *) node->info;
   assert (route->prev == NULL);
+  assert (route->table == table);
   ospf6_route_lock (route);
+
+  if (IS_OSPF6_DEBUG_ROUTE (MEMORY))
+    zlog_info ("%s %p: route head: %p<-[%p]->%p",
+               ospf6_route_table_name (table), table,
+               route->prev, route, route->next);
+
   return route;
 }
 
@@ -513,6 +672,11 @@
 {
   struct ospf6_route *next = route->next;
 
+  if (IS_OSPF6_DEBUG_ROUTE (MEMORY))
+    zlog_info ("%s %p: route next: %p<-[%p]->%p",
+               ospf6_route_table_name (route->table), route->table,
+               route->prev, route, route->next);
+
   ospf6_route_unlock (route);
   if (next)
     ospf6_route_lock (next);
@@ -600,11 +764,13 @@
 }
 
 struct ospf6_route_table *
-ospf6_route_table_create ()
+ospf6_route_table_create (int s, int t)
 {
   struct ospf6_route_table *new;
   new = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_route_table));
   new->table = route_table_init ();
+  new->scope_type = s;
+  new->table_type = t;
   return new;
 }
 
@@ -616,7 +782,6 @@
   XFREE (MTYPE_OSPF6_ROUTE, table);
 }
 
-
 
 /* VTY commands */
 void
diff --git a/ospf6d/ospf6_route.h b/ospf6d/ospf6_route.h
index d91cd7b..722fa15 100644
--- a/ospf6d/ospf6_route.h
+++ b/ospf6d/ospf6_route.h
@@ -29,6 +29,7 @@
 #define OSPF6_DEBUG_ROUTE_TABLE   0x01
 #define OSPF6_DEBUG_ROUTE_INTRA   0x02
 #define OSPF6_DEBUG_ROUTE_INTER   0x04
+#define OSPF6_DEBUG_ROUTE_MEMORY  0x80
 #define OSPF6_DEBUG_ROUTE_ON(level) \
   (conf_debug_ospf6_route |= (level))
 #define OSPF6_DEBUG_ROUTE_OFF(level) \
@@ -112,7 +113,7 @@
 struct ospf6_route
 {
   struct route_node *rnode;
-
+  struct ospf6_route_table *table;
   struct ospf6_route *prev;
   struct ospf6_route *next;
 
@@ -162,6 +163,10 @@
 
 struct ospf6_route_table
 {
+  int scope_type;
+  int table_type;
+  void *scope;
+
   /* patricia tree */
   struct route_table *table;
 
@@ -173,6 +178,25 @@
   void (*hook_remove) (struct ospf6_route *);
 };
 
+#define OSPF6_SCOPE_TYPE_NONE      0
+#define OSPF6_SCOPE_TYPE_GLOBAL    1
+#define OSPF6_SCOPE_TYPE_AREA      2
+#define OSPF6_SCOPE_TYPE_INTERFACE 3
+
+#define OSPF6_TABLE_TYPE_NONE              0
+#define OSPF6_TABLE_TYPE_ROUTES            1
+#define OSPF6_TABLE_TYPE_BORDER_ROUTERS    2
+#define OSPF6_TABLE_TYPE_CONNECTED_ROUTES  3
+#define OSPF6_TABLE_TYPE_EXTERNAL_ROUTES   4
+#define OSPF6_TABLE_TYPE_SPF_RESULTS       5
+#define OSPF6_TABLE_TYPE_PREFIX_RANGES     6
+#define OSPF6_TABLE_TYPE_SUMMARY_PREFIXES  7
+#define OSPF6_TABLE_TYPE_SUMMARY_ROUTERS   8
+
+#define OSPF6_ROUTE_TABLE_CREATE(s, t) \
+  ospf6_route_table_create (OSPF6_SCOPE_TYPE_ ## s, \
+                            OSPF6_TABLE_TYPE_ ## t)
+
 extern const char *ospf6_dest_type_str[OSPF6_DEST_TYPE_MAX];
 extern const char *ospf6_dest_type_substr[OSPF6_DEST_TYPE_MAX];
 #define OSPF6_DEST_TYPE_NAME(x)                       \
@@ -258,7 +282,7 @@
                                             struct ospf6_route *route);
 
 void ospf6_route_remove_all (struct ospf6_route_table *);
-struct ospf6_route_table *ospf6_route_table_create ();
+struct ospf6_route_table *ospf6_route_table_create (int s, int t);
 void ospf6_route_table_delete (struct ospf6_route_table *);
 void ospf6_route_dump (struct ospf6_route_table *table);
 
diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c
index 66b1a12..a5efcb8 100644
--- a/ospf6d/ospf6_top.c
+++ b/ospf6d/ospf6_top.c
@@ -126,15 +126,19 @@
   o->lsdb->hook_add = ospf6_top_lsdb_hook_add;
   o->lsdb->hook_remove = ospf6_top_lsdb_hook_remove;
 
-  o->route_table = ospf6_route_table_create ();
+  o->route_table = OSPF6_ROUTE_TABLE_CREATE (GLOBAL, ROUTES);
+  o->route_table->scope = o;
   o->route_table->hook_add = ospf6_top_route_hook_add;
   o->route_table->hook_remove = ospf6_top_route_hook_remove;
 
-  o->brouter_table = ospf6_route_table_create ();
+  o->brouter_table = OSPF6_ROUTE_TABLE_CREATE (GLOBAL, BORDER_ROUTERS);
+  o->brouter_table->scope = o;
   o->brouter_table->hook_add = ospf6_top_brouter_hook_add;
   o->brouter_table->hook_remove = ospf6_top_brouter_hook_remove;
 
-  o->external_table = ospf6_route_table_create ();
+  o->external_table = OSPF6_ROUTE_TABLE_CREATE (GLOBAL, EXTERNAL_ROUTES);
+  o->external_table->scope = o;
+
   o->external_id_table = route_table_init ();
 
   return o;
diff --git a/ospf6d/ospf6d.h b/ospf6d/ospf6d.h
index 2346cc9..1dfd96b 100644
--- a/ospf6d/ospf6d.h
+++ b/ospf6d/ospf6d.h
@@ -22,7 +22,7 @@
 #ifndef OSPF6D_H
 #define OSPF6D_H
 
-#define OSPF6_DAEMON_VERSION    "0.9.7p"
+#define OSPF6_DAEMON_VERSION    "0.9.7q"
 
 /* global variables */
 extern int errno;