Ospf6d merge from Zebra repository with added privs stuff and merged
zclient changes.
diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c
index b3abedc..73bdac2 100644
--- a/ospf6d/ospf6_route.c
+++ b/ospf6d/ospf6_route.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1999 Yasuhiro Ohara
+ * Copyright (C) 2003 Yasuhiro Ohara
  *
  * This file is part of GNU Zebra.
  *
@@ -19,1118 +19,1119 @@
  * Boston, MA 02111-1307, USA.  
  */
 
+#include <zebra.h>
+
+#include "log.h"
+#include "memory.h"
+#include "prefix.h"
+#include "table.h"
+#include "vty.h"
+#include "command.h"
+
 #include "ospf6d.h"
+#include "ospf6_proto.h"
+#include "ospf6_lsa.h"
+#include "ospf6_route.h"
 
-char *
-dtype_name[OSPF6_DEST_TYPE_MAX] =
+unsigned char conf_debug_ospf6_route = 0;
+
+void
+ospf6_linkstate_prefix (u_int32_t adv_router, u_int32_t id,
+                        struct prefix *prefix)
 {
-  "Unknown", "Router", "Network", "Discard"
-};
-#define DTYPE_NAME(x) \
-  (0 < (x) && (x) < sizeof (dtype_name) ? \
-   dtype_name[(x)] : dtype_name[0])
-
-char *
-dtype_abname[OSPF6_DEST_TYPE_MAX] =
-{
-  "?", "R", "N", "D"
-};
-#define DTYPE_ABNAME(x) \
-  (0 < (x) && (x) < sizeof (dtype_abname) ? \
-   dtype_abname[(x)] : dtype_abname[0])
-
-char *
-ptype_name[OSPF6_PATH_TYPE_MAX] =
-{
-  "Unknown", "Intra", "Inter", "External-1", "External-2",
-  "System", "Kernel", "Connect", "Static", "RIP", "RIPng",
-  "OSPF", "OSPF6", "BGP"
-};
-#define PTYPE_NAME(x) \
-  (0 < (x) && (x) < sizeof (ptype_name) ? \
-   ptype_name[(x)] : ptype_name[0])
-
-char *
-ptype_abname[OSPF6_PATH_TYPE_MAX] =
-{
-  "??", "Ia", "Ie", "E1", "E2",
-  "-X", "-K", "-C", "-S", "-R", "-R",
-  "-O", "-O", "-B"
-};
-#define PTYPE_ABNAME(x) \
-  (0 < (x) && (x) < sizeof (ptype_abname) ? \
-   ptype_abname[(x)] : ptype_abname[0])
-
-
-
-int
-ospf6_path_cmp (void *arg1, void *arg2)
-{
-  struct ospf6_path_node *pn1 = arg1;
-  struct ospf6_path_node *pn2 = arg2;
-  struct ospf6_path *p1 = &pn1->path;
-  struct ospf6_path *p2 = &pn2->path;
-
-  if (p1->type < p2->type)
-    return -1;
-  else if (p1->type > p2->type)
-    return 1;
-
-  if (p1->type == OSPF6_PATH_TYPE_EXTERNAL2)
-    {
-      if (p1->cost_e2 < p2->cost_e2)
-        return -1;
-      else if (p1->cost_e2 > p2->cost_e2)
-        return 1;
-    }
-
-  if (p1->cost < p2->cost)
-    return -1;
-  else if (p1->cost > p2->cost)
-    return 1;
-
-  /* if from the same source, recognize as identical
-     (and treat this as update) */
-  if (! memcmp (&p1->origin, &p2->origin, sizeof (struct ls_origin)) &&
-      p1->area_id == p2->area_id)
-    return 0;
-
-  /* else, always prefer left */
-  return -1;
+  memset (prefix, 0, sizeof (struct prefix));
+  prefix->family = AF_INET6;
+  prefix->prefixlen = 64;
+  memcpy (&prefix->u.prefix6.s6_addr[0], &adv_router, 4);
+  memcpy (&prefix->u.prefix6.s6_addr[4], &id, 4);
 }
 
-int
-ospf6_nexthop_cmp (void *arg1, void *arg2)
+void
+ospf6_linkstate_prefix2str (struct prefix *prefix, char *buf, int size)
 {
-  int i, ret = 0;
-  struct ospf6_nexthop_node *nn1 = arg1;
-  struct ospf6_nexthop_node *nn2 = arg2;
-  struct ospf6_nexthop *n1 = &nn1->nexthop;
-  struct ospf6_nexthop *n2 = &nn2->nexthop;
-
-  if (memcmp (n1, n2, sizeof (struct ospf6_nexthop)) == 0)
-    return 0;
-
-  for (i = 0; i < sizeof (struct in6_addr); i++)
-    {
-      if (nn1->nexthop.address.s6_addr[i] != nn2->nexthop.address.s6_addr[i])
-        {
-          ret = nn1->nexthop.address.s6_addr[i] -
-                nn2->nexthop.address.s6_addr[i];
-          break;
-        }
-    }
-
-  if (ret == 0)
-    ret = -1;
-
-  return ret;
+  u_int32_t adv_router, id;
+  char adv_router_str[16];
+  memcpy (&adv_router, &prefix->u.prefix6.s6_addr[0], 4);
+  memcpy (&id, &prefix->u.prefix6.s6_addr[4], 4);
+  inet_ntop (AF_INET, &adv_router, adv_router_str, sizeof (adv_router_str));
+  snprintf (buf, size, "%s(%lu)", adv_router_str, (u_long) ntohl (id));
 }
 
-static void
-ospf6_route_request (struct ospf6_route_req *request,
-                     struct ospf6_route_node   *rn,
-                     struct ospf6_path_node    *pn,
-                     struct ospf6_nexthop_node *nn)
+/* Global strings for logging */
+char *ospf6_dest_type_str[OSPF6_DEST_TYPE_MAX] =
+{ "Unknown", "Router", "Network", "Discard", "Linkstate", };
+
+char *ospf6_dest_type_substr[OSPF6_DEST_TYPE_MAX] =
+{ "?", "R", "N", "D", "L", };
+
+char *ospf6_path_type_str[OSPF6_PATH_TYPE_MAX] =
+{ "Unknown", "Intra-Area", "Inter-Area", "External-1", "External-2", };
+
+char *ospf6_path_type_substr[OSPF6_PATH_TYPE_MAX] =
+{ "??", "Ia", "Ie", "E1", "E2", };
+
+
+struct ospf6_route *
+ospf6_route_create ()
 {
-  assert (request);
-  assert (rn && pn && nn);
-
-  request->route_node = rn->route_node;
-
-  linklist_head (rn->path_list, &request->path_lnode);
-  while (request->path_lnode.data != pn)
-    {
-      //assert (! linklist_end (&request->path_lnode));
-      if (linklist_end (&request->path_lnode))
-        {
-          struct linklist_node node;
-
-          zlog_info ("rn: %p, pn: %p", rn, pn);
-          zlog_info ("origin: %hx %x %x bits: %x opt: %x%x%x popt: %x area: %x type: %d cost  %d %d %d",
-          pn->path.origin.type, pn->path.origin.id, pn->path.origin.adv_router, (int)pn->path.router_bits, (int)pn->path.capability[0],
-          (int)pn->path.capability[1], (int)pn->path.capability[2],
-          (int)pn->path.prefix_options, pn->path.area_id,
-          pn->path.type, pn->path.metric_type, pn->path.cost, pn->path.cost_e2);
-
-          for (linklist_head (rn->path_list, &node); ! linklist_end (&node);
-               linklist_next (&node))
-            {
-              struct ospf6_path_node *pn2 = node.data;
-
-              zlog_info (" %p: path data with pn(%p): %s", pn2, pn,
-                         (memcmp (&pn->path, &pn2->path,
-                                  sizeof (struct ospf6_path)) ?
-                          "different" : "same"));
-
-          zlog_info ("  origin: %hx %x %x bits: %x opt: %x%x%x popt: %x area: %x type: %d cost  %d %d %d",
-          pn2->path.origin.type, pn2->path.origin.id, pn2->path.origin.adv_router, (int)pn2->path.router_bits, (int)pn2->path.capability[0],
-          (int)pn2->path.capability[1], (int)pn2->path.capability[2],
-          (int)pn2->path.prefix_options, pn2->path.area_id,
-          pn2->path.type, pn2->path.metric_type, pn2->path.cost, pn2->path.cost_e2);
-
-              if (! memcmp (&pn->path, &pn2->path, sizeof (struct ospf6_path)))
-                {
-                  pn = pn2;
-                  request->nexthop_lnode.data = pn2;
-                }
-            }
-          break;
-        }
-      linklist_next (&request->path_lnode);
-    }
-  assert (request->path_lnode.data == pn);
-
-  linklist_head (pn->nexthop_list, &request->nexthop_lnode);
-  while (request->nexthop_lnode.data != nn)
-    {
-      assert (! linklist_end (&request->nexthop_lnode));
-      linklist_next (&request->nexthop_lnode);
-    }
-  assert (request->nexthop_lnode.data == nn);
-
-  request->table = rn->table;
-  request->count = rn->count;
-  request->route_id = rn->route_id;
-  memcpy (&request->route,   &rn->route,   sizeof (struct ospf6_route));
-  memcpy (&request->path,    &pn->path,    sizeof (struct ospf6_path));
-  memcpy (&request->nexthop, &nn->nexthop, sizeof (struct ospf6_nexthop));
+  struct ospf6_route *route;
+  route = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_route));
+  return route;
 }
 
-int
-ospf6_route_count (struct ospf6_route_req *request)
+void
+ospf6_route_delete (struct ospf6_route *route)
 {
-  return request->count;
+  XFREE (MTYPE_OSPF6_ROUTE, route);
 }
 
-int
-ospf6_route_lookup (struct ospf6_route_req *request,
-                    struct prefix *prefix,
+struct ospf6_route *
+ospf6_route_copy (struct ospf6_route *route)
+{
+  struct ospf6_route *new;
+
+  new = ospf6_route_create ();
+  memcpy (new, route, sizeof (struct ospf6_route));
+  new->rnode = NULL;
+  new->prev = NULL;
+  new->next = NULL;
+  new->lock = 0;
+  return new;
+}
+
+void
+ospf6_route_lock (struct ospf6_route *route)
+{
+  route->lock++;
+}
+
+void
+ospf6_route_unlock (struct ospf6_route *route)
+{
+  assert (route->lock > 0);
+  route->lock--;
+  if (route->lock == 0)
+    ospf6_route_delete (route);
+}
+
+/* Route compare function. If ra is more preferred, it returns
+   less than 0. If rb is more preferred returns greater than 0.
+   Otherwise (neither one is preferred), returns 0 */
+static int
+ospf6_route_cmp (struct ospf6_route *ra, struct ospf6_route *rb)
+{
+  assert (ospf6_route_is_same (ra, rb));
+  assert (OSPF6_PATH_TYPE_NONE < ra->path.type &&
+          ra->path.type < OSPF6_PATH_TYPE_MAX);
+  assert (OSPF6_PATH_TYPE_NONE < rb->path.type &&
+          rb->path.type < OSPF6_PATH_TYPE_MAX);
+
+  if (ra->type != rb->type)
+    return (ra->type - rb->type);
+
+  if (ra->path.area_id != rb->path.area_id)
+    return (ntohl (ra->path.area_id) - ntohl (rb->path.area_id));
+
+  if (ra->path.type != rb->path.type)
+    return (ra->path.type - rb->path.type);
+
+  if (ra->path.type == OSPF6_PATH_TYPE_EXTERNAL2)
+    {
+      if (ra->path.cost_e2 != rb->path.cost_e2)
+        return (ra->path.cost_e2 - rb->path.cost_e2);
+    }
+  else
+    {
+      if (ra->path.cost != rb->path.cost)
+        return (ra->path.cost - rb->path.cost);
+    }
+
+  return 0;
+}
+
+struct ospf6_route *
+ospf6_route_lookup (struct prefix *prefix,
                     struct ospf6_route_table *table)
 {
   struct route_node *node;
-  struct ospf6_route_node   *rn = NULL;
-  struct ospf6_path_node    *pn = NULL;
-  struct ospf6_nexthop_node *nn = NULL;
-  struct linklist_node lnode;
-
-  if (request)
-    memset ((void *) request, 0, sizeof (struct ospf6_route_req));
+  struct ospf6_route *route;
 
   node = route_node_lookup (table->table, prefix);
-  if (! node)
-    return 0;
+  if (node == NULL)
+    return NULL;
 
-  rn = (struct ospf6_route_node *) node->info;
-  if (! rn)
-    return 0;
-
-  if (request)
-    {
-      linklist_head (rn->path_list, &lnode);
-      pn = lnode.data;
-      linklist_head (pn->nexthop_list, &lnode);
-      nn = lnode.data;
-
-      ospf6_route_request (request, rn, pn, nn);
-    }
-
-  return 1;
+  route = (struct ospf6_route *) node->info;
+  return route;
 }
 
-void
-ospf6_route_head (struct ospf6_route_req *request,
-                  struct ospf6_route_table *table)
+struct ospf6_route *
+ospf6_route_lookup_identical (struct ospf6_route *route,
+                              struct ospf6_route_table *table)
+{
+  struct ospf6_route *target;
+
+  for (target = ospf6_route_lookup (&route->prefix, table);
+       target; target = target->next)
+    {
+      if (ospf6_route_is_identical (target, route))
+        return target;
+    }
+  return NULL;
+}
+
+struct ospf6_route *
+ospf6_route_lookup_bestmatch (struct prefix *prefix,
+                              struct ospf6_route_table *table)
 {
   struct route_node *node;
-  struct ospf6_route_node   *rn = NULL;
-  struct ospf6_path_node    *pn = NULL;
-  struct ospf6_nexthop_node *nn = NULL;
-  struct linklist_node lnode;
+  struct ospf6_route *route;
 
-  if (request)
-    memset (request, 0, sizeof (struct ospf6_route_req));
+  node = route_node_match (table->table, prefix);
+  if (node == NULL)
+    return NULL;
+  route_unlock_node (node);
 
-  node = route_top (table->table);
-  if (! node)
-    return;
-
-  while (node && node->info == NULL)
-    node = route_next (node);
-  if (! node)
-    return;
-
-  rn = (struct ospf6_route_node *) node->info;
-  linklist_head (rn->path_list, &lnode);
-  pn = lnode.data;
-  linklist_head (pn->nexthop_list, &lnode);
-  nn = lnode.data;
-
-  ospf6_route_request (request, rn, pn, nn);
+  route = (struct ospf6_route *) node->info;
+  return route;
 }
 
-int
-ospf6_route_end (struct ospf6_route_req *request)
+#ifndef NDEBUG
+static void
+_route_count_assert (struct ospf6_route_table *table)
 {
-  if (request->route_node == NULL &&
-      linklist_end (&request->path_lnode) &&
-      linklist_end (&request->nexthop_lnode) &&
-      request->nexthop.ifindex == 0 &&
-      IN6_IS_ADDR_UNSPECIFIED (&request->nexthop.address))
-    return 1;
-  return 0;
+  struct ospf6_route *debug;
+  int num = 0;
+  for (debug = ospf6_route_head (table); debug;
+       debug = ospf6_route_next (debug))
+    num++;
+  assert (num == table->count);
 }
+#define ospf6_route_count_assert(t) (_route_count_assert (t))
+#else
+#define ospf6_route_count_assert(t) ((void) 0)
+#endif /*NDEBUG*/
 
-void
-ospf6_route_next (struct ospf6_route_req *request)
-{
-  struct ospf6_route_node   *route_node = NULL;
-  struct ospf6_path_node    *path_node = NULL;
-  struct ospf6_nexthop_node *nexthop_node = NULL;
-
-  linklist_next (&request->nexthop_lnode);
-  if (linklist_end (&request->nexthop_lnode))
-    {
-      linklist_next (&request->path_lnode);
-      if (linklist_end (&request->path_lnode))
-        {
-          request->route_node = route_next (request->route_node);
-          while (request->route_node && request->route_node->info == NULL)
-            request->route_node = route_next (request->route_node);
-          if (request->route_node)
-            {
-              route_node = request->route_node->info;
-              if (route_node)
-                linklist_head (route_node->path_list, &request->path_lnode);
-            }
-        }
-
-      path_node = request->path_lnode.data;
-      if (path_node)
-        linklist_head (path_node->nexthop_list, &request->nexthop_lnode);
-    }
-
-  nexthop_node = request->nexthop_lnode.data;
-
-  if (nexthop_node == NULL)
-    {
-      assert (path_node == NULL);
-      assert (route_node == NULL);
-
-      memset (&request->route,   0, sizeof (struct ospf6_route));
-      memset (&request->path,    0, sizeof (struct ospf6_path));
-      memset (&request->nexthop, 0, sizeof (struct ospf6_nexthop));
-    }
-  else
-    {
-      path_node = request->path_lnode.data;
-      route_node = request->route_node->info;
-
-      assert (path_node != NULL);
-      assert (route_node != NULL);
-
-      memcpy (&request->route,   &route_node->route,
-              sizeof (struct ospf6_route));
-      memcpy (&request->path,    &path_node->path,
-              sizeof (struct ospf6_path));
-      memcpy (&request->nexthop, &nexthop_node->nexthop,
-              sizeof (struct ospf6_nexthop));
-    }
-}
-
-#define ADD    0
-#define CHANGE 1
-#define REMOVE 2
-
-void
-ospf6_route_hook_call (int type,
-                       struct ospf6_route_req *request,
-                       struct ospf6_route_table *table)
-{
-  struct linklist_node node;
-  void (*func) (struct ospf6_route_req *);
-
-  for (linklist_head (table->hook_list[type], &node);
-       ! linklist_end (&node);
-       linklist_next (&node))
-    {
-      func = node.data;
-      (*func) (request);
-    }
-}
-
-void
-ospf6_route_hook_register (void (*add)    (struct ospf6_route_req *),
-                           void (*change) (struct ospf6_route_req *),
-                           void (*remove) (struct ospf6_route_req *),
-                           struct ospf6_route_table *table)
-{
-  linklist_add (add,    table->hook_list[ADD]);
-  linklist_add (change, table->hook_list[CHANGE]);
-  linklist_add (remove, table->hook_list[REMOVE]);
-}
-
-void
-ospf6_route_hook_unregister (void (*add)    (struct ospf6_route_req *),
-                             void (*change) (struct ospf6_route_req *),
-                             void (*remove) (struct ospf6_route_req *),
-                             struct ospf6_route_table *table)
-{
-  linklist_remove (add,    table->hook_list[ADD]);
-  linklist_remove (change, table->hook_list[CHANGE]);
-  linklist_remove (remove, table->hook_list[REMOVE]);
-}
-
-
-int
-prefix_ls2str (struct prefix *p, char *str, int size)
-{
-  char id[BUFSIZ], adv_router[BUFSIZ];
-  struct prefix_ls *pl = (struct prefix_ls *) p;
-
-  inet_ntop (AF_INET, &pl->id, id, BUFSIZ);
-  inet_ntop (AF_INET, &pl->adv_router, adv_router, BUFSIZ);
-  snprintf (str, size, "%s-%s", adv_router, id);
-  return 0;
-}
-
-void
-ospf6_route_log_request (char *what, char *where,
-                         struct ospf6_route_req *request)
-{
-  char prefix[64];
-  char area_id[16];
-  char type[16], id[16], adv[16];
-  char address[64], ifname[IFNAMSIZ];
-
-  if (request->route.prefix.family != AF_INET &&
-      request->route.prefix.family != AF_INET6)
-    prefix_ls2str (&request->route.prefix, prefix, sizeof (prefix));
-  else
-    prefix2str (&request->route.prefix, prefix, sizeof (prefix));
-
-  inet_ntop (AF_INET, &request->path.area_id, area_id, sizeof (area_id));
-
-  ospf6_lsa_type_string (request->path.origin.type, type, sizeof (type));
-  inet_ntop (AF_INET, &request->path.origin.id, id, sizeof (id));
-  inet_ntop (AF_INET, &request->path.origin.adv_router, adv, sizeof (adv));
-
-  inet_ntop (AF_INET6, &request->nexthop.address, address, sizeof (address));
-
-  zlog_info ("ROUTE: %s %s %s %s %s",
-             what, DTYPE_ABNAME (request->route.type), prefix,
-             ((strcmp ("Add", what) == 0) ? "to" : "from"), where);
-  zlog_info ("ROUTE:     Area: %s type: %s cost: %lu (E2: %lu)",
-             area_id, PTYPE_NAME (request->path.type),
-             (u_long) request->path.cost, (u_long) request->path.cost_e2);
-  zlog_info ("ROUTE:     Origin: Type: %s", type);
-  zlog_info ("ROUTE:     Origin: Id: %s Adv: %s", id, adv);
-  zlog_info ("ROUTE:     Nexthop: %s", address);
-  zlog_info ("ROUTE:     Nexthop: Ifindex: %u (%s)",
-             request->nexthop.ifindex,
-             if_indextoname (request->nexthop.ifindex, ifname));
-}
-
-struct ospf6_path_node *
-ospf6_route_find_path_node (struct ospf6_route_req *request,
-                            struct ospf6_route_node *rn)
-{
-  struct linklist_node node;
-
-  for (linklist_head (rn->path_list, &node); ! linklist_end (&node);
-       linklist_next (&node))
-    {
-      struct ospf6_path_node *path_node = node.data;
-
-      if (path_node->path.area_id == request->path.area_id &&
-          path_node->path.origin.type == request->path.origin.type &&
-          path_node->path.origin.id == request->path.origin.id &&
-          path_node->path.origin.adv_router == request->path.origin.adv_router)
-        return path_node;
-    }
-
-#if 0
-  zlog_info ("req path : area: %#x origin: type: %d, id: %d, adv_router: %#x",
-             request->path.area_id, request->path.origin.type,
-             request->path.origin.id, request->path.origin.adv_router);
-  for (linklist_head (rn->path_list, &node); ! linklist_end (&node);
-       linklist_next (&node))
-    {
-      struct ospf6_path_node *path_node = node.data;
-      zlog_info ("  path : area: %#x origin: type: %d, id: %d, adv_router: %#x",
-                 path_node->path.area_id, path_node->path.origin.type,
-                 path_node->path.origin.id, path_node->path.origin.adv_router);
-    }
-#endif
-
-  return NULL;
-}
-
-struct ospf6_nexthop_node *
-ospf6_route_find_nexthop_node (struct ospf6_route_req *request,
-                               struct ospf6_path_node *pn)
-{
-  struct linklist_node node;
-  for (linklist_head (pn->nexthop_list, &node); ! linklist_end (&node);
-       linklist_next (&node))
-    {
-      struct ospf6_nexthop_node *nexthop_node = node.data;
-
-      if (! memcmp (&nexthop_node->nexthop, &request->nexthop,
-          sizeof (struct ospf6_nexthop)))
-        return nexthop_node;
-    }
-  return NULL;
-}
-
-void
-ospf6_route_add (struct ospf6_route_req *request,
+struct ospf6_route *
+ospf6_route_add (struct ospf6_route *route,
                  struct ospf6_route_table *table)
 {
-  struct ospf6_route_node   *rn;
-  struct ospf6_path_node    *pn;
-  struct ospf6_nexthop_node *nn;
-  struct route_node *route_node;
+  struct route_node *node, *nextnode, *prevnode;
+  struct ospf6_route *current = NULL;
+  struct ospf6_route *prev = NULL, *old = NULL, *next = NULL;
+  char buf[64];
+  struct timeval now;
 
-  struct ospf6_route_req route;
+  assert (route->rnode == NULL);
+  assert (route->lock == 0);
+  assert (route->next == NULL);
+  assert (route->prev == NULL);
 
-  int route_change   = 0;
-  int path_change    = 0;
-  int nexthop_change = 0;
+  if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
+    ospf6_linkstate_prefix2str (&route->prefix, buf, sizeof (buf));
+  else
+    prefix2str (&route->prefix, buf, sizeof (buf));
 
-  /* find the requested route */
-  route_node = route_node_get (table->table, &request->route.prefix);
-  rn = (struct ospf6_route_node *) route_node->info;
+  if (IS_OSPF6_DEBUG_ROUTE (TABLE))
+    zlog_info ("route add %s", buf);
 
-  if (rn)
+  gettimeofday (&now, NULL);
+
+  node = route_node_get (table->table, &route->prefix);
+  route->rnode = node;
+
+  /* find place to insert */
+  for (current = node->info; current; current = current->next)
     {
-      if (memcmp (&rn->route, &request->route, sizeof (struct ospf6_route)))
-        {
-          memcpy (&rn->route, &request->route, sizeof (struct ospf6_route));
-          route_change++;
-        }
+      if (! ospf6_route_is_same (current, route))
+        next = current;
+      else if (current->type != route->type)
+        prev = current;
+      else if (ospf6_route_is_same_origin (current, route))
+        old = current;
+      else if (ospf6_route_cmp (current, route) > 0)
+        next = current;
+      else
+        prev = current;
+
+      if (old || next)
+        break;
     }
+
+  if (old)
+    {
+      /* if route does not actually change, return unchanged */
+      if (ospf6_route_is_identical (old, route))
+        {
+          if (IS_OSPF6_DEBUG_ROUTE (TABLE))
+            zlog_info ("  identical route found, ignore");
+
+          ospf6_route_delete (route);
+          SET_FLAG (old->flag, OSPF6_ROUTE_ADD);
+          ospf6_route_count_assert (table);
+          return old;
+        }
+
+      if (IS_OSPF6_DEBUG_ROUTE (TABLE))
+        zlog_info ("  old route found, replace");
+
+      /* replace old one if exists */
+      if (node->info == old)
+        {
+          node->info = route;
+          SET_FLAG (route->flag, OSPF6_ROUTE_BEST);
+        }
+
+      if (old->prev)
+        old->prev->next = route;
+      route->prev = old->prev;
+      if (old->next)
+        old->next->prev = route;
+      route->next = old->next;
+
+      route->installed = old->installed;
+      route->changed = now;
+
+      ospf6_route_unlock (old); /* will be deleted later */
+      ospf6_route_lock (route);
+
+      SET_FLAG (route->flag, OSPF6_ROUTE_CHANGE);
+      if (table->hook_add)
+        (*table->hook_add) (route);
+
+      ospf6_route_count_assert (table);
+      return route;
+    }
+
+  /* insert if previous or next node found */
+  if (prev || next)
+    {
+      if (IS_OSPF6_DEBUG_ROUTE (TABLE))
+        zlog_info ("  another path found, insert");
+
+      if (prev == NULL)
+        prev = next->prev;
+      if (next == NULL)
+        next = prev->next;
+
+      if (prev)
+        prev->next = route;
+      route->prev = prev;
+      if (next)
+        next->prev = route;
+      route->next = next;
+
+      if (node->info == next)
+        {
+          assert (next->rnode == node);
+          node->info = route;
+          UNSET_FLAG (next->flag, OSPF6_ROUTE_BEST);
+          SET_FLAG (route->flag, OSPF6_ROUTE_BEST);
+        }
+
+      route->installed = now;
+      route->changed = now;
+
+      ospf6_route_lock (route);
+      table->count++;
+
+      SET_FLAG (route->flag, OSPF6_ROUTE_ADD);
+      if (table->hook_add)
+        (*table->hook_add) (route);
+
+      ospf6_route_count_assert (table);
+      return route;
+    }
+
+  /* Else, this is the brand new route regarding to the prefix */
+  if (IS_OSPF6_DEBUG_ROUTE (TABLE))
+    zlog_info ("  brand new route, add");
+
+  assert (node->info == NULL);
+  node->info = route;
+  SET_FLAG (route->flag, OSPF6_ROUTE_BEST);
+  ospf6_route_lock (route);
+  route->installed = now;
+  route->changed = now;
+
+  /* lookup real existing next route */
+  nextnode = node;
+  route_lock_node (nextnode);
+  do {
+    nextnode = route_next (nextnode);
+  } while (nextnode && nextnode->info == NULL);
+
+  /* set next link */
+  if (nextnode == NULL)
+    route->next = NULL;
   else
     {
-      rn = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_route_node));
-      rn->table = table;
-      rn->route_node = route_node;
-      rn->route_id = table->route_id++;
-      rn->path_list = linklist_create ();
-      rn->path_list->cmp = ospf6_path_cmp;
-      memcpy (&rn->route, &request->route, sizeof (struct ospf6_route));
-      route_node->info = rn;
+      route_unlock_node (nextnode);
+
+      next = nextnode->info;
+      route->next = next;
+      next->prev = route;
     }
 
-  /* find the same path */
-  pn = ospf6_route_find_path_node (request, rn);
+  /* lookup real existing prev route */
+  prevnode = node;
+  route_lock_node (prevnode);
+  do {
+    prevnode = route_prev (prevnode);
+  } while (prevnode && prevnode->info == NULL);
 
-  if (pn)
-    {
-      if (memcmp (&pn->path, &request->path, sizeof (struct ospf6_path)))
-        {
-          memcpy (&pn->path, &request->path, sizeof (struct ospf6_path));
-          path_change++;
-        }
-    }
+  /* set prev link */
+  if (prevnode == NULL)
+    route->prev = NULL;
   else
     {
-      pn = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_path_node));
-      pn->route_node = rn;
-      pn->nexthop_list = linklist_create ();
-      pn->nexthop_list->cmp = ospf6_nexthop_cmp;
-      memcpy (&pn->path, &request->path, sizeof (struct ospf6_path));
-      linklist_add (pn, rn->path_list);
+      route_unlock_node (prevnode);
+
+      prev = prevnode->info;
+      while (prev->next && ospf6_route_is_same (prev, prev->next))
+        prev = prev->next;
+      route->prev = prev;
+      prev->next = route;
     }
 
-  /* find the same nexthop */
-  nn = ospf6_route_find_nexthop_node (request, pn);
+  table->count++;
 
-  if (nn)
-    {
-      if (memcmp (&nn->nexthop, &request->nexthop,
-                  sizeof (struct ospf6_nexthop)))
-        {
-          memcpy (&nn->nexthop, &request->nexthop,
-                  sizeof (struct ospf6_nexthop));
-          nexthop_change++;
-          gettimeofday (&nn->installed, (struct timezone *) NULL);
-        }
-    }
-  else
-    {
-      nn = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_nexthop_node));
-      nn->path_node = pn;
-      memcpy (&nn->nexthop, &request->nexthop, sizeof (struct ospf6_nexthop));
-      linklist_add (nn, pn->nexthop_list);
-      rn->count++;
-      gettimeofday (&nn->installed, (struct timezone *) NULL);
-    }
+  SET_FLAG (route->flag, OSPF6_ROUTE_ADD);
+  if (table->hook_add)
+    (*table->hook_add) (route);
 
-  SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ADD);
-  if (route_change)
-    SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ROUTE_CHANGE);
-  if (path_change)
-    SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_PATH_CHANGE);
-  if (nexthop_change)
-    SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE);
-
-  if (table->freeze)
-    return;
-
-  if (IS_OSPF6_DUMP_ROUTE)
-    {
-      ospf6_route_log_request ("Add", table->name, request);
-
-      if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ROUTE_CHANGE))
-        zlog_info ("ROUTE:   route attribute change");
-      if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_PATH_CHANGE))
-        zlog_info ("ROUTE:   path attribute change");
-      if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE))
-        zlog_info ("ROUTE:   nexthop attribute change");
-    }
-
-  if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ROUTE_CHANGE) ||
-      CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_PATH_CHANGE))
-    SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE);
-
-  /* Call hooks */
-  ospf6_route_request (&route, rn, pn, nn);
-  if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ADD))
-    ospf6_route_hook_call (ADD, &route, table);
-  else if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE))
-    ospf6_route_hook_call (CHANGE, &route, table);
-
-  if (table->hook_add &&
-      CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ADD))
-    (*table->hook_add) (&route);
-  else if (table->hook_change &&
-           CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE))
-    (*table->hook_change) (&route);
-
-  /* clear flag */
-  nn->flag = 0;
+  ospf6_route_count_assert (table);
+  return route;
 }
 
 void
-ospf6_route_remove (struct ospf6_route_req *request,
+ospf6_route_remove (struct ospf6_route *route,
                     struct ospf6_route_table *table)
 {
-  struct ospf6_route_node   *rn;
-  struct ospf6_path_node    *pn;
-  struct ospf6_nexthop_node *nn;
-  struct route_node *route_node;
-  struct ospf6_route_req route;
+  struct route_node *node;
+  struct ospf6_route *current;
+  char buf[64];
 
-  /* find the requested route */
-  route_node = route_node_get (table->table, &request->route.prefix);
-  rn = (struct ospf6_route_node *) route_node->info;
+  if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
+    ospf6_linkstate_prefix2str (&route->prefix, buf, sizeof (buf));
+  else
+    prefix2str (&route->prefix, buf, sizeof (buf));
 
-  if (! rn)
+  if (IS_OSPF6_DEBUG_ROUTE (TABLE))
+    zlog_info ("route remove: %s", buf);
+
+  node = route_node_lookup (table->table, &route->prefix);
+  assert (node);
+
+  /* find the route to remove, making sure that the route pointer
+     is from the route table. */
+  current = node->info;
+  while (current && ospf6_route_is_same (current, route))
     {
-      if (IS_OSPF6_DUMP_ROUTE)
+      if (current == route)
+        break;
+      current = current->next;
+    }
+  assert (current == route);
+
+  /* adjust doubly linked list */
+  if (route->prev)
+    route->prev->next = route->next;
+  if (route->next)
+    route->next->prev = route->prev;
+
+  if (node->info == route)
+    {
+      if (route->next && ospf6_route_is_same (route->next, route))
         {
-          ospf6_route_log_request ("Remove", table->name, request);
-          zlog_info ("ROUTE:   Can't remove: No such route");
+          node->info = route->next;
+          SET_FLAG (route->next->flag, OSPF6_ROUTE_BEST);
         }
-      return;
+      else
+        node->info = NULL; /* should unlock route_node here ? */
     }
 
-  pn = ospf6_route_find_path_node (request, rn);
-  if (! pn)
-    {
-      if (IS_OSPF6_DUMP_ROUTE)
-        {
-          ospf6_route_log_request ("Remove", table->name, request);
-          zlog_info ("ROUTE:   Can't remove: No such path");
-        }
-      return;
-    }
-
-  if (pn->path.area_id != request->path.area_id ||
-      pn->path.origin.type != request->path.origin.type ||
-      pn->path.origin.id != request->path.origin.id ||
-      pn->path.origin.adv_router != request->path.origin.adv_router)
-    {
-      if (IS_OSPF6_DUMP_ROUTE)
-        {
-          ospf6_route_log_request ("Remove", table->name, request);
-          zlog_info ("ROUTE:   Can't remove: Path differ");
-          {
-            char *s, *e, *c;
-            char line[512], *p;
-
-            p = line;
-            s = (char *) &pn->path;
-            e = s + sizeof (struct ospf6_path);
-            for (c = s; c < e; c++)
-              {
-                if ((c - s) % 4 == 0)
-		{
-                  snprintf (p, line + sizeof (line) - p, " ");
-		  p++;
-		}
-                snprintf (p, line + sizeof (line) - p, "%02x", *c);
-                p += 2;
-              }
-            zlog_info ("ROUTE:     path: %s", line);
-
-            p = line;
-            s = (char *) &request->path;
-            e = s + sizeof (struct ospf6_path);
-            for (c = s; c < e; c++)
-              {
-                if ((c - s) % 4 == 0)
-		{
-                  snprintf (p, line + sizeof (line) - p, " ");
-		  p++;
-		}
-                snprintf (p, line + sizeof (line) - p, "%02x", *c);
-                p += 2;
-              }
-            zlog_info ("ROUTE:     req : %s", line);
-
-          }
-        }
-      return;
-    }
-
-  nn = ospf6_route_find_nexthop_node (request, pn);
-  if (! nn)
-    {
-      if (IS_OSPF6_DUMP_ROUTE)
-        {
-          ospf6_route_log_request ("Remove", table->name, request);
-          zlog_info ("ROUTE:   Can't remove: No such nexthop");
-        }
-      return;
-    }
-
-  if (memcmp (&nn->nexthop, &request->nexthop, sizeof (struct ospf6_nexthop)))
-    {
-      if (IS_OSPF6_DUMP_ROUTE)
-        {
-          ospf6_route_log_request ("Remove", table->name, request);
-          zlog_info ("ROUTE:   Can't remove: Nexthop differ");
-        }
-      return;
-    }
-
-  SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_REMOVE);
-
-  if (table->freeze)
-    return;
-
-  if (IS_OSPF6_DUMP_ROUTE)
-    ospf6_route_log_request ("Remove", table->name, request);
-
-  ospf6_route_request (&route, rn, pn, nn);
-  ospf6_route_hook_call (REMOVE, &route, table);
   if (table->hook_remove)
-    (*table->hook_remove) (&route);
+    (*table->hook_remove) (route);
 
-  /* clear flag */
-  nn->flag = 0;
+  ospf6_route_unlock (route);
+  table->count--;
 
-  /* remove nexthop */
-  linklist_remove (nn, pn->nexthop_list);
-  rn->count--;
-  XFREE (MTYPE_OSPF6_ROUTE, nn);
+  ospf6_route_count_assert (table);
+}
 
-  /* remove path if there's no nexthop for the path */
-  if (pn->nexthop_list->count != 0)
-    return;
-  linklist_remove (pn, rn->path_list);
-  linklist_delete (pn->nexthop_list);
-  XFREE (MTYPE_OSPF6_ROUTE, pn);
+struct ospf6_route *
+ospf6_route_head (struct ospf6_route_table *table)
+{
+  struct route_node *node;
+  struct ospf6_route *route;
 
-  /* remove route if there's no path for the route */
-  if (rn->path_list->count != 0)
-    return;
-  route_node->info = NULL;
-  linklist_delete (rn->path_list);
-  XFREE (MTYPE_OSPF6_ROUTE, rn);
+  node = route_top (table->table);
+  if (node == NULL)
+    return NULL;
+
+  /* skip to the real existing entry */
+  while (node && node->info == NULL)
+    node = route_next (node);
+  if (node == NULL)
+    return NULL;
+
+  route_unlock_node (node);
+  assert (node->info);
+
+  route = (struct ospf6_route *) node->info;
+  assert (route->prev == NULL);
+  ospf6_route_lock (route);
+  return route;
+}
+
+struct ospf6_route *
+ospf6_route_next (struct ospf6_route *route)
+{
+  struct ospf6_route *next = route->next;
+
+  ospf6_route_unlock (route);
+  if (next)
+    ospf6_route_lock (next);
+
+  return next;
+}
+
+struct ospf6_route *
+ospf6_route_best_next (struct ospf6_route *route)
+{
+  struct route_node *rnode;
+  struct ospf6_route *next;
+
+  rnode = route->rnode;
+  route_lock_node (rnode);
+  rnode = route_next (rnode);
+  while (rnode && rnode->info == NULL)
+    rnode = route_next (rnode);
+  if (rnode == NULL)
+    return NULL;
+  route_unlock_node (rnode);
+
+  assert (rnode->info);
+  next = (struct ospf6_route *) rnode->info;
+  ospf6_route_unlock (route);
+  ospf6_route_lock (next);
+  return next;
+}
+
+/* Macro version of check_bit (). */
+#define CHECK_BIT(X,P) ((((u_char *)(X))[(P) / 8]) >> (7 - ((P) % 8)) & 1)
+
+struct ospf6_route *
+ospf6_route_match_head (struct prefix *prefix,
+                        struct ospf6_route_table *table)
+{
+  struct route_node *node;
+  struct ospf6_route *route;
+
+  /* Walk down tree. */
+  node = table->table->top;
+  while (node && node->p.prefixlen < prefix->prefixlen &&
+	 prefix_match (&node->p, prefix))
+    node = node->link[CHECK_BIT(&prefix->u.prefix, node->p.prefixlen)];
+
+  if (node)
+    route_lock_node (node);
+  while (node && node->info == NULL)
+    node = route_next (node);
+  if (node == NULL)
+    return NULL;
+  route_unlock_node (node);
+
+  if (! prefix_match (prefix, &node->p))
+    return NULL;
+
+  route = node->info;
+  ospf6_route_lock (route);
+  return route;
+}
+
+struct ospf6_route *
+ospf6_route_match_next (struct prefix *prefix,
+                        struct ospf6_route *route)
+{
+  struct ospf6_route *next;
+
+  next = ospf6_route_next (route);
+  if (next && ! prefix_match (prefix, &next->prefix))
+    {
+      ospf6_route_unlock (next);
+      next = NULL;
+    }
+
+  return next;
 }
 
 void
 ospf6_route_remove_all (struct ospf6_route_table *table)
 {
-  struct ospf6_route_req request;
-
-  for (ospf6_route_head (&request, table); ! ospf6_route_end (&request);
-       ospf6_route_next (&request))
-    ospf6_route_remove (&request, table);
+  struct ospf6_route *route;
+  for (route = ospf6_route_head (table); route;
+       route = ospf6_route_next (route))
+    ospf6_route_remove (route, table);
 }
 
-
 struct ospf6_route_table *
-ospf6_route_table_create (char *name)
+ospf6_route_table_create ()
 {
-  int i;
   struct ospf6_route_table *new;
-
   new = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_route_table));
-  snprintf (new->name, sizeof (new->name), "%s", name);
-
   new->table = route_table_init ();
-  for (i = 0; i < 3; i++)
-    new->hook_list[i] = linklist_create ();
-
   return new;
 }
 
 void
 ospf6_route_table_delete (struct ospf6_route_table *table)
 {
-  int i;
-
   ospf6_route_remove_all (table);
   route_table_finish (table->table);
-  for (i = 0; i < 3; i++)
-    linklist_delete (table->hook_list[i]);
   XFREE (MTYPE_OSPF6_ROUTE, table);
 }
 
-void
-ospf6_route_table_freeze (struct ospf6_route_table *route_table)
-{
-  if (IS_OSPF6_DUMP_ROUTE)
-    zlog_info ("ROUTE: Table freeze: %s", route_table->name);
-  assert (route_table->freeze == 0);
-  route_table->freeze = 1;
-}
-
-void
-ospf6_route_table_thaw (struct ospf6_route_table *route_table)
-{
-  struct route_node *node;
-  struct linklist_node pnode;
-  struct linklist_node nnode;
-
-  struct ospf6_route_node   *rn;
-  struct ospf6_path_node    *pn;
-  struct ospf6_nexthop_node *nn;
-
-  struct ospf6_route_req request;
-
-  if (IS_OSPF6_DUMP_ROUTE)
-    zlog_info ("ROUTE: Table thaw: %s", route_table->name);
-
-  assert (route_table->freeze == 1);
-  route_table->freeze = 0;
-
-  for (node = route_top (route_table->table); node;
-       node = route_next (node))
-    {
-      rn = node->info;
-      if (! rn)
-        continue;
-
-      for (linklist_head (rn->path_list, &pnode);
-           ! linklist_end (&pnode);
-           linklist_next (&pnode))
-        {
-          pn = pnode.data;
-
-          for (linklist_head (pn->nexthop_list, &nnode);
-               ! linklist_end (&nnode);
-               linklist_next (&nnode))
-            {
-              nn = nnode.data;
-
-              /* if the add and remove flag set without change flag,
-                 do nothing with this route */
-              if (! CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE) &&
-                  CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ADD) &&
-                  CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_REMOVE))
-                {
-                  nn->flag = 0;
-                  continue;
-                }
-
-              memset (&request, 0, sizeof (request));
-              memcpy (&request.route, &rn->route, sizeof (rn->route));
-              memcpy (&request.path, &pn->path, sizeof (pn->path));
-              memcpy (&request.nexthop, &nn->nexthop, sizeof (nn->nexthop));
-
-              if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ADD) ||
-                  CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE))
-                ospf6_route_add (&request, route_table);
-              else if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_REMOVE))
-                ospf6_route_remove (&request, route_table);
-            }
-        }
-    }
-}
 
 
 /* VTY commands */
+void
+ospf6_route_show (struct vty *vty, struct ospf6_route *route)
+{
+  int i;
+  char destination[64], nexthop[64];
+  char duration[16], ifname[IFNAMSIZ];
+  struct timeval now, res;
+
+  gettimeofday (&now, (struct timezone *) NULL);
+  timersub (&now, &route->changed, &res);
+  timerstring (&res, duration, sizeof (duration));
+
+  /* destination */
+  if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
+    ospf6_linkstate_prefix2str (&route->prefix, destination,
+                                sizeof (destination));
+  else if (route->type == OSPF6_DEST_TYPE_ROUTER)
+    inet_ntop (route->prefix.family, &route->prefix.u.prefix,
+               destination, sizeof (destination));
+  else
+    prefix2str (&route->prefix, destination, sizeof (destination));
+
+  /* nexthop */
+  inet_ntop (AF_INET6, &route->nexthop[0].address, nexthop,
+             sizeof (nexthop));
+  if (! if_indextoname (route->nexthop[0].ifindex, ifname))
+    snprintf (ifname, sizeof (ifname), "%d", route->nexthop[0].ifindex);
+
+  vty_out (vty, "%c%1s %2s %-30s %-25s %6s %s%s",
+           (ospf6_route_is_best (route) ? '*' : ' '),
+           OSPF6_DEST_TYPE_SUBSTR (route->type),
+           OSPF6_PATH_TYPE_SUBSTR (route->path.type),
+           destination, nexthop, ifname, duration, VTY_NEWLINE);
+
+  for (i = 1; ospf6_nexthop_is_set (&route->nexthop[i]) &&
+       i < OSPF6_MULTI_PATH_LIMIT; i++)
+    {
+      /* nexthop */
+      inet_ntop (AF_INET6, &route->nexthop[i].address, nexthop,
+                 sizeof (nexthop));
+      if (! if_indextoname (route->nexthop[i].ifindex, ifname))
+        snprintf (ifname, sizeof (ifname), "%d", route->nexthop[i].ifindex);
+
+      vty_out (vty, "%c%1s %2s %-30s %-25s %6s %s%s",
+               ' ', "", "", "", nexthop, ifname, "", VTY_NEWLINE);
+    }
+}
 
 void
-ospf6_route_show (struct vty *vty, struct ospf6_route_node *rn)
+ospf6_route_show_detail (struct vty *vty, struct ospf6_route *route)
 {
-  struct linklist_node pnode;
-  struct linklist_node nnode;
-  struct ospf6_path_node    *pn;
-  struct ospf6_nexthop_node *nn;
-
+  char destination[64], nexthop[64], ifname[IFNAMSIZ];
+  char area_id[16], id[16], adv_router[16], capa[16], options[16];
   struct timeval now, res;
   char duration[16];
-
-  u_int pc = 0;
-  u_int nc = 0;
-#define HEAD (pc == 0 && nc == 0)
-
-  char prefix[64], nexthop[64], ifname[IFNAMSIZ];
+  int i;
 
   gettimeofday (&now, (struct timezone *) NULL);
 
   /* destination */
-  if (rn->route.prefix.family == AF_INET ||
-      rn->route.prefix.family == AF_INET6)
-    prefix2str (&rn->route.prefix, prefix, sizeof (prefix));
+  if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
+    ospf6_linkstate_prefix2str (&route->prefix, destination,
+                                sizeof (destination));
+  else if (route->type == OSPF6_DEST_TYPE_ROUTER)
+    inet_ntop (route->prefix.family, &route->prefix.u.prefix,
+               destination, sizeof (destination));
   else
-    prefix_ls2str (&rn->route.prefix, prefix, sizeof (prefix));
+    prefix2str (&route->prefix, destination, sizeof (destination));
+  vty_out (vty, "Destination: %s%s", destination, VTY_NEWLINE);
 
-  for (linklist_head (rn->path_list, &pnode); ! linklist_end (&pnode);
-       linklist_next (&pnode))
+  /* destination type */
+  vty_out (vty, "Destination type: %s%s",
+           OSPF6_DEST_TYPE_NAME (route->type),
+           VTY_NEWLINE);
+
+  /* Time */
+  timersub (&now, &route->installed, &res);
+  timerstring (&res, duration, sizeof (duration));
+  vty_out (vty, "Installed Time: %s ago%s", duration, VTY_NEWLINE);
+
+  timersub (&now, &route->changed, &res);
+  timerstring (&res, duration, sizeof (duration));
+  vty_out (vty, "  Changed Time: %s ago%s", duration, VTY_NEWLINE);
+
+  /* Debugging info */
+  vty_out (vty, "Lock: %d Flags: %s%s%s%s%s", route->lock,
+           (CHECK_FLAG (route->flag, OSPF6_ROUTE_BEST)   ? "B" : "-"),
+           (CHECK_FLAG (route->flag, OSPF6_ROUTE_ADD)    ? "A" : "-"),
+           (CHECK_FLAG (route->flag, OSPF6_ROUTE_REMOVE) ? "R" : "-"),
+           (CHECK_FLAG (route->flag, OSPF6_ROUTE_CHANGE) ? "C" : "-"),
+           VTY_NEWLINE);
+  vty_out (vty, "Memory: prev: %p this: %p next: %p%s",
+           route->prev, route, route->next, VTY_NEWLINE);
+
+  /* Path section */
+
+  /* Area-ID */
+  inet_ntop (AF_INET, &route->path.area_id, area_id, sizeof (area_id));
+  vty_out (vty, "Associated Area: %s%s", area_id, VTY_NEWLINE);
+
+  /* Path type */
+  vty_out (vty, "Path Type: %s%s",
+           OSPF6_PATH_TYPE_NAME (route->path.type), VTY_NEWLINE);
+
+  /* LS Origin */
+  inet_ntop (AF_INET, &route->path.origin.id, id, sizeof (id));
+  inet_ntop (AF_INET, &route->path.origin.adv_router, adv_router,
+             sizeof (adv_router));
+  vty_out (vty, "LS Origin: %s Id: %s Adv: %s%s",
+           OSPF6_LSTYPE_NAME (route->path.origin.type),
+           id, adv_router, VTY_NEWLINE);
+
+  /* Options */
+  ospf6_options_printbuf (route->path.options, options, sizeof (options));
+  vty_out (vty, "Options: %s%s", options, VTY_NEWLINE);
+
+  /* Router Bits */
+  ospf6_capability_printbuf (route->path.router_bits, capa, sizeof (capa));
+  vty_out (vty, "Router Bits: %s%s", capa, VTY_NEWLINE);
+
+  /* Prefix Options */
+  vty_out (vty, "Prefix Options: xxx%s", VTY_NEWLINE);
+
+  /* Metrics */
+  vty_out (vty, "Metric Type: %d%s", route->path.metric_type,
+           VTY_NEWLINE);
+  vty_out (vty, "Metric: %d (%d)%s",
+           route->path.cost, route->path.cost_e2, VTY_NEWLINE);
+
+  /* Nexthops */
+  vty_out (vty, "Nexthop:%s", VTY_NEWLINE);
+  for (i = 0; ospf6_nexthop_is_set (&route->nexthop[i]) &&
+       i < OSPF6_MULTI_PATH_LIMIT; i++)
     {
-      pn = pnode.data;
-
-      for (linklist_head (pn->nexthop_list, &nnode); ! linklist_end (&nnode);
-           linklist_next (&nnode))
-        {
-          nn = nnode.data;
-
-          inet_ntop (AF_INET6, &nn->nexthop.address, nexthop,
-                     sizeof (nexthop));
-          if (! if_indextoname (nn->nexthop.ifindex, ifname))
-            snprintf (ifname, sizeof (ifname), "%d", nn->nexthop.ifindex);
-
-          ospf6_timeval_sub (&now, &nn->installed, &res);
-          ospf6_timeval_string_summary (&res, duration, sizeof (duration));
-
-          vty_out (vty, "%c%1s %2s %-30s %-25s %6s %s%s",
-                   (HEAD ? '*' : ' '),
-                   DTYPE_ABNAME (rn->route.type),
-                   PTYPE_ABNAME (pn->path.type),
-                   prefix, nexthop, ifname, duration, VTY_NEWLINE);
-
-          nc++;
-        }
-      pc++;
+      /* nexthop */
+      inet_ntop (AF_INET6, &route->nexthop[i].address, nexthop,
+                 sizeof (nexthop));
+      if (! if_indextoname (route->nexthop[i].ifindex, ifname))
+        snprintf (ifname, sizeof (ifname), "%d", route->nexthop[i].ifindex);
+      vty_out (vty, "  %s %s%s", nexthop, ifname, VTY_NEWLINE);
     }
+  vty_out (vty, "%s", VTY_NEWLINE);
 }
 
 void
-ospf6_route_show_detail (struct vty *vty, struct ospf6_route_node *rn)
+ospf6_route_show_table_summary (struct vty *vty,
+                                struct ospf6_route_table *table)
 {
-  struct linklist_node pnode;
-  struct linklist_node nnode;
-  struct ospf6_path_node    *pn;
-  struct ospf6_nexthop_node *nn;
+  struct ospf6_route *route, *prev = NULL;
+  int i, pathtype[OSPF6_PATH_TYPE_MAX];
+  int number = 0;
+  int nhinval = 0, ecmp = 0;
+  int multipath = 0, destination = 0;
+  int desttype = 0, desttype_mismatch = 0;
 
-  u_int pc = 0;
-  u_int nc = 0;
+  for (i = 0; i < OSPF6_PATH_TYPE_MAX; i++)
+    pathtype[i] = 0;
 
-  char prefix[64], nexthop[64], ifname[IFNAMSIZ];
-  char area_id[16], type[16], id[16], adv[16];
-  char capa[64];
-
-  /* destination */
-  if (rn->route.prefix.family == AF_INET ||
-      rn->route.prefix.family == AF_INET6)
-    prefix2str (&rn->route.prefix, prefix, sizeof (prefix));
-  else
-    prefix_ls2str (&rn->route.prefix, prefix, sizeof (prefix));
-
-  vty_out (vty, "%s%s%s", VTY_NEWLINE, prefix, VTY_NEWLINE);
-  vty_out (vty, "    Destination Type: %s%s",
-           DTYPE_NAME (rn->route.type), VTY_NEWLINE);
-
-  for (linklist_head (rn->path_list, &pnode); ! linklist_end (&pnode);
-       linklist_next (&pnode))
+  for (route = ospf6_route_head (table); route;
+       route = ospf6_route_next (route))
     {
-      pn = pnode.data;
+      if (desttype == 0)
+        desttype = route->type;
+      else if (desttype != route->type)
+        desttype_mismatch++;
 
-      inet_ntop (AF_INET, &pn->path.area_id, area_id, sizeof (area_id));
-      ospf6_lsa_type_string (pn->path.origin.type, type, sizeof (type));
-      inet_ntop (AF_INET, &pn->path.origin.id, id, sizeof (id));
-      inet_ntop (AF_INET, &pn->path.origin.adv_router, adv, sizeof (adv));
-      ospf6_options_string (pn->path.capability, capa, sizeof (capa));
+      if (prev == NULL || ! ospf6_route_is_same (prev, route))
+        destination++;
+      else
+        multipath++;
 
-      vty_out (vty, "  Path:%s", VTY_NEWLINE);
-      vty_out (vty, "    Associated Area: %s%s", area_id, VTY_NEWLINE);
-      vty_out (vty, "    LS Origin: %s ID: %s Adv: %s%s",
-               type, id, adv, VTY_NEWLINE);
-      vty_out (vty, "    Path Type: %s%s",
-               PTYPE_NAME (pn->path.type), VTY_NEWLINE);
-      vty_out (vty, "    Metric Type: %d%s",
-               pn->path.metric_type, VTY_NEWLINE);
-      vty_out (vty, "    Cost: Type-1: %lu Type-2: %lu%s",
-               (u_long) pn->path.cost, (u_long) pn->path.cost_e2,
-               VTY_NEWLINE);
-      vty_out (vty, "    Router Bits: %s|%s|%s|%s%s",
-               (CHECK_FLAG (pn->path.router_bits, OSPF6_ROUTER_LSA_BIT_W) ?
-                "W" : "-"),
-               (CHECK_FLAG (pn->path.router_bits, OSPF6_ROUTER_LSA_BIT_V) ?
-                "V" : "-"),
-               (CHECK_FLAG (pn->path.router_bits, OSPF6_ROUTER_LSA_BIT_E) ?
-                "E" : "-"),
-               (CHECK_FLAG (pn->path.router_bits, OSPF6_ROUTER_LSA_BIT_B) ?
-                "B" : "-"), VTY_NEWLINE);
-      vty_out (vty, "    Optional Capabilities: %s%s", capa, VTY_NEWLINE);
-      vty_out (vty, "    Prefix Options: %s%s", "xxx", VTY_NEWLINE);
-      vty_out (vty, "    Next Hops:%s", VTY_NEWLINE);
+      if (! ospf6_nexthop_is_set (&route->nexthop[0]))
+        nhinval++;
+      else if (ospf6_nexthop_is_set (&route->nexthop[1]))
+        ecmp++;
 
-      for (linklist_head (pn->nexthop_list, &nnode); ! linklist_end (&nnode);
-           linklist_next (&nnode))
-        {
-          nn = nnode.data;
+      if (prev == NULL || ! ospf6_route_is_same (prev, route))
+        pathtype[route->path.type]++;
 
-          inet_ntop (AF_INET6, &nn->nexthop.address, nexthop,
-                     sizeof (nexthop));
-          if (! if_indextoname (nn->nexthop.ifindex, ifname))
-            snprintf (ifname, sizeof (ifname), "%d", nn->nexthop.ifindex);
-
-          vty_out (vty, "       %c%s%%%s%s",
-                   (HEAD ? '*' : ' '), nexthop, ifname, VTY_NEWLINE);
-
-          nc++;
-        }
-      pc++;
+      number++;
+      prev = route;
     }
-  vty_out (vty, "%s", VTY_NEWLINE);
+
+  assert (number == table->count);
+  vty_out (vty, "Number of Destination: %d (%d routes)%s",
+           destination, number, VTY_NEWLINE);
+  if (multipath)
+    vty_out (vty, "  Number of Multi-path: %d%s", multipath, VTY_NEWLINE);
+  if (desttype_mismatch)
+    vty_out (vty, "  Number of Different Dest-type: %d%s",
+             desttype_mismatch, VTY_NEWLINE);
+  if (ecmp)
+    vty_out (vty, "  Number of Equal Cost Multi Path: %d%s",
+             ecmp, VTY_NEWLINE);
+  if (ecmp)
+    vty_out (vty, "  Number of Invalid Nexthop: %d%s",
+             nhinval, VTY_NEWLINE);
+
+  for (i = 0; i < OSPF6_PATH_TYPE_MAX; i++)
+    {
+      if (pathtype[i])
+        vty_out (vty, "  Number of %s routes: %d%s",
+                 OSPF6_PATH_TYPE_NAME (i), pathtype[i], VTY_NEWLINE);
+    }
 }
 
 int
 ospf6_route_table_show (struct vty *vty, int argc, char **argv,
                         struct ospf6_route_table *table)
 {
+  unsigned char flag = 0;
+#define MATCH      0x01
+#define DETAIL     0x02
+#define PREFIX     0x04
+#define SUMMARY    0x08
   int i, ret;
-  unsigned long ret_ul;
-  char *endptr;
-  struct prefix prefix;
-  int detail = 0;
-  int arg_ipv6  = 0;
-  int arg_ipv4  = 0;
-  int arg_digit = 0;
-  struct prefix_ipv6 *p6 = (struct prefix_ipv6 *) &prefix;
-  struct prefix_ls   *pl = (struct prefix_ls *) &prefix;
-  struct route_node *node;
-
-  u_int route_count = 0;
-  u_int path_count = 0;
-  u_int route_redundant = 0;
+  struct prefix prefix, *p;
+  struct ospf6_route *route;
 
   memset (&prefix, 0, sizeof (struct prefix));
 
   for (i = 0; i < argc; i++)
     {
+      /* set "detail" */
+      if (! strcmp (argv[i], "summary"))
+        {
+          SET_FLAG (flag, SUMMARY);
+          continue;
+        }
+
+      /* set "detail" */
       if (! strcmp (argv[i], "detail"))
         {
-          detail++;
-          break;
+          SET_FLAG (flag, DETAIL);
+          continue;
         }
 
-      if (! arg_ipv6 && ! arg_ipv4 && ! arg_digit)
+      /* set "match" */
+      if (! strcmp (argv[i], "match"))
         {
-
-          if ((ret = inet_pton (AF_INET6, argv[i], &p6->prefix)) == 1)
-            {
-              p6->family = AF_INET6;
-              p6->prefixlen = 128;
-              arg_ipv6++;
-              continue;
-            }
-          else if ((ret = inet_pton (AF_INET, argv[i], &pl->adv_router)) == 1)
-            {
-              pl->family = AF_UNSPEC;
-              pl->prefixlen = 64; /* xxx */
-              arg_ipv4++;
-              continue;
-            }
-          else
-            {
-              ret_ul = strtoul (argv[i], &endptr, 10);
-              if (*endptr == '\0')
-                {
-                  pl->adv_router.s_addr = htonl (ret_ul);
-                  pl->family = AF_UNSPEC;
-                  pl->prefixlen = 64; /* xxx */
-                  arg_digit++;
-                  continue;
-                }
-              else
-                {
-                  vty_out (vty, "Malformed argument: %s%s",
-                           argv[i], VTY_NEWLINE);
-                  return CMD_SUCCESS;
-                }
-            }
+          SET_FLAG (flag, MATCH);
+          continue;
         }
 
-      if (arg_ipv4 || arg_digit)
+      if (prefix.family)
         {
-          if ((ret = inet_pton (AF_INET, argv[i], &pl->id)) == 1)
-            {
-              arg_ipv4++;
-            }
-          else
-            {
-              ret_ul = strtoul (argv[i], &endptr, 10);
-              if (*endptr == '\0')
-                {
-                  pl->id.s_addr = htonl (ret_ul);
-                  arg_digit++;
-                }
-              else
-                {
-                  vty_out (vty, "Malformed argument: %s%s",
-                           argv[i], VTY_NEWLINE);
-                  return CMD_SUCCESS;
-                }
-            }
+          vty_out (vty, "Invalid argument: %s%s", argv[i], VTY_NEWLINE);
+          return CMD_SUCCESS;
         }
+
+      ret = str2prefix (argv[i], &prefix);
+      if (ret != 1 || prefix.family != AF_INET6)
+        {
+          vty_out (vty, "Malformed argument: %s%s", argv[i], VTY_NEWLINE);
+          return CMD_SUCCESS;
+        }
+
+      if (strchr (argv[i], '/'))
+        SET_FLAG (flag, PREFIX);
     }
 
-  if (arg_ipv4 || arg_ipv6 || arg_digit)
+  /* Give summary of this route table */
+  if (CHECK_FLAG (flag, SUMMARY))
     {
-      node = route_node_match (table->table, &prefix);
-      if (node && node->info)
-        ospf6_route_show_detail (vty, node->info);
+      ospf6_route_show_table_summary (vty, table);
       return CMD_SUCCESS;
     }
 
-  if (! detail)
+  /* Give exact prefix-match route */
+  if (prefix.family && ! CHECK_FLAG (flag, MATCH))
     {
-      vty_out (vty, "%s%c%1s %2s %-30s %-25s %6s%s", VTY_NEWLINE,
-               ' ', " ", " ", "Destination", "Gateway", "I/F", VTY_NEWLINE);
-      vty_out (vty, "---------------------------%s", VTY_NEWLINE);
+      /* If exact address, give best matching route */
+      if (! CHECK_FLAG (flag, PREFIX))
+        route = ospf6_route_lookup_bestmatch (&prefix, table);
+      else
+        route = ospf6_route_lookup (&prefix, table);
+
+      if (route)
+        {
+          ospf6_route_lock (route);
+          p = &route->prefix;
+        }
+
+      while (route && ospf6_route_is_prefix (p, route))
+        {
+          /* Seaching an entry will always display details */
+          if (route)
+            ospf6_route_show_detail (vty, route);
+
+          route = ospf6_route_next (route);
+        }
+
+      return CMD_SUCCESS;
     }
 
-  for (node = route_top (table->table); node; node = route_next (node))
+  if (prefix.family == 0)
+    route = ospf6_route_head (table);
+  else
+    route = ospf6_route_match_head (&prefix, table);
+
+  while (route)
     {
-      struct ospf6_route_node *route = node->info;
-
-      if (! route)
-        continue;
-
-      if (detail)
+      if (CHECK_FLAG (flag, DETAIL))
         ospf6_route_show_detail (vty, route);
       else
         ospf6_route_show (vty, route);
 
-      route_count++;
-      path_count += route->path_list->count;
-      if (route->path_list->count > 1)
-        route_redundant++;
+      if (prefix.family == 0)
+        route = ospf6_route_next (route);
+      else
+        route = ospf6_route_match_next (&prefix, route);
     }
 
-  vty_out (vty, "===========%s", VTY_NEWLINE);
-  vty_out (vty, "Route: %d Path: %d Redundant: %d%s",
-           route_count, path_count, route_redundant, VTY_NEWLINE);
-
   return CMD_SUCCESS;
 }
 
+
+int
+ospf6_lsentry_table_show (struct vty *vty, int argc, char **argv,
+                          struct ospf6_route_table *table)
+{
+  unsigned char flag = 0;
+#define MATCH      0x01
+#define DETAIL     0x02
+  int i, ret;
+  struct prefix adv_router, id, prefix;
+  struct ospf6_route *route;
+
+  memset (&adv_router, 0, sizeof (struct prefix));
+  memset (&id, 0, sizeof (struct prefix));
+
+  for (i = 0; i < argc; i++)
+    {
+      /* set "detail" */
+      if (! strcmp (argv[i], "detail"))
+        {
+          SET_FLAG (flag, DETAIL);
+          continue;
+        }
+
+      /* set "match" */
+      if (! strcmp (argv[i], "match"))
+        {
+          SET_FLAG (flag, MATCH);
+          continue;
+        }
+
+      if (adv_router.family && id.family)
+        {
+          vty_out (vty, "Invalid argument: %s%s", argv[i], VTY_NEWLINE);
+          return CMD_SUCCESS;
+        }
+
+      if (adv_router.family == 0)
+        {
+          ret = str2prefix (argv[i], &adv_router);
+          if (ret != 1)
+            {
+              if (! strcmp (argv[i], "*"))
+                {
+                  adv_router.family = AF_INET;
+                  adv_router.prefixlen = 0;
+                  ret = 1;
+                }
+            }
+          if (ret != 1)
+            {
+              vty_out (vty, "Invalid Router-ID: %s%s", argv[i], VTY_NEWLINE);
+              return CMD_SUCCESS;
+            }
+        }
+      else if (id.family == 0)
+        {
+          unsigned long val;
+          char *endptr;
+
+          ret = str2prefix (argv[i], &id);
+          if (ret != 1)
+            {
+              val = strtoul (argv[i], &endptr, 0);
+              if (val != ULONG_MAX && *endptr == '\0')
+                {
+                  id.u.prefix4.s_addr = val;
+                  ret = 1;
+                }
+            }
+
+          if (ret != 1)
+            {
+              vty_out (vty, "Invalid Link state ID: %s%s", argv[i],
+                       VTY_NEWLINE);
+              return CMD_WARNING;
+            }
+        }
+    }
+
+  /* Encode to linkstate prefix */
+  if (adv_router.family)
+    {
+      if (adv_router.prefixlen == 0 &&
+          id.family && id.prefixlen != IPV4_MAX_BITLEN)
+        {
+          vty_out (vty, "Specifying Link State ID by prefix is not allowed%s"
+                   "when specifying Router-ID as wildcard%s",
+                   VTY_NEWLINE, VTY_NEWLINE);
+          return CMD_SUCCESS;
+        }
+      else if (adv_router.prefixlen != 0 &&
+               adv_router.prefixlen != IPV4_MAX_BITLEN && id.family)
+        {
+          vty_out (vty, "Specifying Link State ID is not allowed%s"
+                   "when specifying Router-ID by prefix%s",
+                   VTY_NEWLINE, VTY_NEWLINE);
+          return CMD_SUCCESS;
+        }
+
+      if (adv_router.prefixlen == 0)
+        ospf6_linkstate_prefix (0, id.u.prefix4.s_addr, &prefix);
+      else if (adv_router.prefixlen != IPV4_MAX_BITLEN)
+        {
+          ospf6_linkstate_prefix (adv_router.u.prefix4.s_addr, 0, &prefix);
+          prefix.prefixlen = adv_router.prefixlen;
+          SET_FLAG (flag, MATCH);
+        }
+      else
+        {
+          ospf6_linkstate_prefix (adv_router.u.prefix4.s_addr,
+                                  id.u.prefix4.s_addr, &prefix);
+          prefix.prefixlen = adv_router.prefixlen + id.prefixlen;
+          if (prefix.prefixlen != 64)
+            SET_FLAG (flag, MATCH);
+        }
+    }
+
+  /* give exact match entry */
+  if (adv_router.family && adv_router.prefixlen == IPV4_MAX_BITLEN &&
+      id.family && id.prefixlen == IPV4_MAX_BITLEN)
+    {
+      route = ospf6_route_lookup (&prefix, table);
+      if (route)
+        ospf6_route_show_detail (vty, route);
+      return CMD_SUCCESS;
+    }
+
+  if (CHECK_FLAG (flag, MATCH))
+    route = ospf6_route_match_head (&prefix, table);
+  else
+    route = ospf6_route_head (table);
+
+  while (route)
+    {
+      if (! adv_router.family ||
+          (CHECK_FLAG (flag, MATCH) &&
+           prefix_match (&prefix, &route->prefix)) ||
+          (adv_router.prefixlen == 0 && id.family &&
+           ospf6_linkstate_prefix_id (&prefix) ==
+           ospf6_linkstate_prefix_id (&route->prefix)))
+        {
+          if (CHECK_FLAG (flag, DETAIL))
+            ospf6_route_show_detail (vty, route);
+          else
+            ospf6_route_show (vty, route);
+        }
+
+      if (CHECK_FLAG (flag, MATCH))
+        route = ospf6_route_match_next (&prefix, route);
+      else
+        route = ospf6_route_next (route);
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (debug_ospf6_route,
+       debug_ospf6_route_cmd,
+       "debug ospf6 route (table|intra-area|inter-area)",
+       DEBUG_STR
+       OSPF6_STR
+       "Debug route table calculation\n"
+       "Debug detail\n"
+       "Debug intra-area route calculation\n"
+       "Debug inter-area route calculation\n"
+       )
+{
+  unsigned char level = 0;
+
+  if (! strncmp (argv[0], "table", 5))
+    level = OSPF6_DEBUG_ROUTE_TABLE;
+  else if (! strncmp (argv[0], "intra", 5))
+    level = OSPF6_DEBUG_ROUTE_INTRA;
+  else if (! strncmp (argv[0], "inter", 5))
+    level = OSPF6_DEBUG_ROUTE_INTER;
+  OSPF6_DEBUG_ROUTE_ON (level);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_ospf6_route,
+       no_debug_ospf6_route_cmd,
+       "no debug ospf6 route (table|intra-area|inter-area)",
+       NO_STR
+       DEBUG_STR
+       OSPF6_STR
+       "Debug route table calculation\n"
+       "Debug intra-area route calculation\n")
+{
+  unsigned char level = 0;
+
+  if (! strncmp (argv[0], "table", 5))
+    level = OSPF6_DEBUG_ROUTE_TABLE;
+  else if (! strncmp (argv[0], "intra", 5))
+    level = OSPF6_DEBUG_ROUTE_INTRA;
+  else if (! strncmp (argv[0], "inter", 5))
+    level = OSPF6_DEBUG_ROUTE_INTER;
+  OSPF6_DEBUG_ROUTE_OFF (level);
+  return CMD_SUCCESS;
+}
+
+int
+config_write_ospf6_debug_route (struct vty *vty)
+{
+  if (IS_OSPF6_DEBUG_ROUTE (TABLE))
+    vty_out (vty, "debug ospf6 route table%s", VTY_NEWLINE);
+  if (IS_OSPF6_DEBUG_ROUTE (INTRA))
+    vty_out (vty, "debug ospf6 route intra-area%s", VTY_NEWLINE);
+  if (IS_OSPF6_DEBUG_ROUTE (INTER))
+    vty_out (vty, "debug ospf6 route inter-area%s", VTY_NEWLINE);
+  return 0;
+}
+
+void
+install_element_ospf6_debug_route ()
+{
+  install_element (ENABLE_NODE, &debug_ospf6_route_cmd);
+  install_element (ENABLE_NODE, &no_debug_ospf6_route_cmd);
+  install_element (CONFIG_NODE, &debug_ospf6_route_cmd);
+  install_element (CONFIG_NODE, &no_debug_ospf6_route_cmd);
+}
+
+
+