Initial revision
diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c
new file mode 100644
index 0000000..7b8a8dc
--- /dev/null
+++ b/ospf6d/ospf6_zebra.c
@@ -0,0 +1,727 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#include "ospf6d.h"
+
+#include "ospf6_interface.h"
+#include "ospf6_asbr.h"
+
+#include "ospf6_linklist.h"
+
+/* information about zebra. */
+struct zclient *zclient = NULL;
+
+/* redistribute function */
+void
+ospf6_zebra_redistribute (int type)
+{
+  int top_change = 0;
+
+  if (zclient->redist[type])
+    return;
+
+  if (! ospf6_is_asbr (ospf6))
+    top_change = 1;
+
+  zclient->redist[type] = 1;
+
+  if (zclient->sock > 0)
+    zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient->sock, type);
+
+  if (top_change)
+    CALL_CHANGE_HOOK (&top_hook, ospf6);
+}
+
+void
+ospf6_zebra_no_redistribute (int type)
+{
+  int top_change = 0;
+
+  if (!zclient->redist[type])
+    return;
+
+  if (ospf6_is_asbr (ospf6))
+    top_change = 1;
+
+  zclient->redist[type] = 0;
+
+  if (zclient->sock > 0)
+    zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient->sock, type);
+
+  if (top_change)
+    CALL_CHANGE_HOOK (&top_hook, ospf6);
+}
+
+int
+ospf6_zebra_is_redistribute (int type)
+{
+  return zclient->redist[type];
+}
+
+
+/* Inteface addition message from zebra. */
+int
+ospf6_zebra_if_add (int command, struct zclient *zclient, zebra_size_t length)
+{
+  struct interface *ifp;
+
+  ifp = zebra_interface_add_read (zclient->ibuf);
+
+  /* log */
+  if (IS_OSPF6_DUMP_ZEBRA)
+    zlog_info ("ZEBRA: I/F add: %s index %d mtu %d",
+               ifp->name, ifp->ifindex, ifp->mtu);
+
+  ospf6_interface_if_add (ifp);
+
+  return 0;
+}
+
+int
+ospf6_zebra_if_del (int command, struct zclient *zclient, zebra_size_t length)
+{
+#if 0
+  struct interface *ifp = NULL;
+
+  ifp = zebra_interface_delete_read (zclient->ibuf);
+
+  /* log */
+  if (IS_OSPF6_DUMP_ZEBRA)
+    zlog_info ("ZEBRA: I/F delete: %s index %d mtu %d",
+               ifp->name, ifp->ifindex, ifp->mtu);
+
+  ospf6_interface_if_del (ifp);
+#endif
+
+  return 0;
+}
+
+int
+ospf6_zebra_if_state_update (int command, struct zclient *zclient,
+                             zebra_size_t length)
+{
+  struct interface *ifp;
+
+  ifp = zebra_interface_state_read (zclient->ibuf);
+
+  /* log */
+  if (IS_OSPF6_DUMP_ZEBRA)
+    zlog_info ("ZEBRA: I/F %s state change: index %d flags %ld metric %d mtu %d",
+               ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu);
+
+  ospf6_interface_state_update (ifp);
+  return 0;
+}
+
+int
+ospf6_zebra_if_address_update_add (int command, struct zclient *zclient,
+                               zebra_size_t length)
+{
+  struct connected *c;
+  char buf[128];
+
+  c = zebra_interface_address_add_read (zclient->ibuf);
+  if (c == NULL)
+    return 0;
+
+  if (IS_OSPF6_DUMP_ZEBRA)
+    zlog_info ("ZEBRA: I/F %s address add: %5s %s/%d",
+               c->ifp->name, prefix_family_str (c->address),
+               inet_ntop (c->address->family, &c->address->u.prefix,
+                          buf, sizeof (buf)), c->address->prefixlen);
+
+  if (c->address->family == AF_INET6)
+    ospf6_interface_address_update (c->ifp);
+
+  return 0;
+}
+
+int
+ospf6_zebra_if_address_update_delete (int command, struct zclient *zclient,
+                               zebra_size_t length)
+{
+  struct connected *c;
+  char buf[128];
+
+  c = zebra_interface_address_delete_read (zclient->ibuf);
+  if (c == NULL)
+    return 0;
+
+  if (IS_OSPF6_DUMP_ZEBRA)
+    zlog_info ("ZEBRA: I/F %s address del: %5s %s/%d",
+               c->ifp->name, prefix_family_str (c->address),
+               inet_ntop (c->address->family, &c->address->u.prefix,
+                          buf, sizeof (buf)), c->address->prefixlen);
+
+  if (c->address->family == AF_INET6)
+    ospf6_interface_address_update (c->ifp);
+
+  return 0;
+}
+
+
+
+const char *zebra_route_name[ZEBRA_ROUTE_MAX] =
+{
+  "System",
+  "Kernel",
+  "Connect",
+  "Static",
+  "RIP",
+  "RIPng",
+  "OSPF",
+  "OSPF6",
+  "BGP",
+};
+
+const char *zebra_route_abname[ZEBRA_ROUTE_MAX] =
+  { "X", "K", "C", "S", "r", "R", "o", "O", "B" };
+
+int
+ospf6_zebra_read_ipv6 (int command, struct zclient *zclient,
+                       zebra_size_t length)
+{
+  struct stream *s;
+  struct zapi_ipv6 api;
+  unsigned long ifindex;
+  struct prefix_ipv6 p;
+  struct in6_addr *nexthop;
+  char prefixstr[128], nexthopstr[128];
+
+  s = zclient->ibuf;
+  ifindex = 0;
+  nexthop = NULL;
+  memset (&api, 0, sizeof (api));
+
+  /* Type, flags, message. */
+  api.type = stream_getc (s);
+  api.flags = stream_getc (s);
+  api.message = stream_getc (s);
+
+  /* IPv6 prefix. */
+  memset (&p, 0, sizeof (struct prefix_ipv6));
+  p.family = AF_INET6;
+  p.prefixlen = stream_getc (s);
+  stream_get (&p.prefix, s, PSIZE (p.prefixlen));
+
+  /* Nexthop, ifindex, distance, metric. */
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP))
+    {
+      api.nexthop_num = stream_getc (s);
+      nexthop = (struct in6_addr *)
+        malloc (api.nexthop_num * sizeof (struct in6_addr));
+      stream_get (nexthop, s, api.nexthop_num * sizeof (struct in6_addr));
+    }
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX))
+    {
+      api.ifindex_num = stream_getc (s);
+      ifindex = stream_getl (s);
+    }
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
+    api.distance = stream_getc (s);
+  else
+    api.distance = 0;
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
+    api.metric = stream_getl (s);
+  else
+    api.metric = 0;
+
+  /* log */
+  if (IS_OSPF6_DUMP_ZEBRA)
+    {
+      prefix2str ((struct prefix *)&p, prefixstr, sizeof (prefixstr));
+      inet_ntop (AF_INET6, &nexthop, nexthopstr, sizeof (nexthopstr));
+
+      if (command == ZEBRA_IPV6_ROUTE_ADD)
+	zlog_info ("ZEBRA: Receive add %s route: %s nexthop:%s ifindex:%ld",
+		   zebra_route_name [api.type], prefixstr,
+		   nexthopstr, ifindex);
+      else
+	zlog_info ("ZEBRA: Receive remove %s route: %s nexthop:%s ifindex:%ld",
+		   zebra_route_name [api.type], prefixstr,
+		   nexthopstr, ifindex);
+    }
+ 
+  if (command == ZEBRA_IPV6_ROUTE_ADD)
+    ospf6_asbr_route_add (api.type, ifindex, (struct prefix *) &p,
+                          api.nexthop_num, nexthop);
+  else
+    ospf6_asbr_route_remove (api.type, ifindex, (struct prefix *) &p);
+
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP))
+    free (nexthop);
+
+  return 0;
+}
+
+
+DEFUN (show_zebra,
+       show_zebra_cmd,
+       "show zebra",
+       SHOW_STR
+       "Zebra information\n")
+{
+  int i;
+  if (!zclient)
+    vty_out (vty, "Not connected to zebra%s", VTY_NEWLINE);
+
+  vty_out (vty, "Zebra Infomation%s", VTY_NEWLINE);
+  vty_out (vty, "  enable: %d%s", zclient->enable, VTY_NEWLINE);
+  vty_out (vty, "  fail: %d%s", zclient->fail, VTY_NEWLINE);
+  vty_out (vty, "  redistribute default: %d%s", zclient->redist_default,
+           VTY_NEWLINE);
+  for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+    vty_out (vty, "    RouteType: %s - %s%s", zebra_route_name[i],
+             zclient->redist[i] ? "redistributed" : "not redistributed",
+             VTY_NEWLINE);
+  return CMD_SUCCESS;
+}
+
+DEFUN (router_zebra,
+       router_zebra_cmd,
+       "router zebra",
+       "Enable a routing process\n"
+       "Make connection to zebra daemon\n")
+{
+  if (IS_OSPF6_DUMP_CONFIG)
+    zlog_info ("Config: router zebra");
+
+  vty->node = ZEBRA_NODE;
+  zclient->enable = 1;
+  zclient_start (zclient);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_router_zebra,
+       no_router_zebra_cmd,
+       "no router zebra",
+       NO_STR
+       "Configure routing process\n"
+       "Disable connection to zebra daemon\n")
+{
+  if (IS_OSPF6_DUMP_CONFIG)
+    zlog_info ("no router zebra");
+
+  zclient->enable = 0;
+  zclient_stop (zclient);
+  return CMD_SUCCESS;
+}
+
+/* Zebra configuration write function. */
+int
+ospf6_zebra_config_write (struct vty *vty)
+{
+  if (! zclient->enable)
+    {
+      vty_out (vty, "no router zebra%s", VTY_NEWLINE);
+      return 1;
+    }
+  else if (! zclient->redist[ZEBRA_ROUTE_OSPF6])
+    {
+      vty_out (vty, "router zebra%s", VTY_NEWLINE);
+      vty_out (vty, " no redistribute ospf6%s", VTY_NEWLINE);
+      return 1;
+    }
+  return 0;
+}
+
+/* Zebra node structure. */
+struct cmd_node zebra_node =
+{
+  ZEBRA_NODE,
+  "%s(config-zebra)# ",
+};
+
+#define ADD    0
+#define CHANGE 1
+#define REMOVE 2
+
+static void
+ospf6_zebra_route_update (int type, struct ospf6_route_req *request)
+{
+  char buf[96], ifname[IFNAMSIZ];
+
+  struct zapi_ipv6 api;
+  struct ospf6_route_req route;
+  struct linklist *nexthop_list;
+  struct linklist_node node;
+  struct ospf6_nexthop *nexthop = NULL;
+  struct in6_addr **nexthops;
+  unsigned int *ifindexes;
+  struct prefix_ipv6 *p;
+  int i, ret = 0;
+
+  if (IS_OSPF6_DUMP_ZEBRA)
+    {
+      prefix2str (&request->route.prefix, buf, sizeof (buf));
+      if (type == REMOVE)
+        zlog_info ("ZEBRA: Send remove route: %s", buf);
+      else
+        zlog_info ("ZEBRA: Send add route: %s", buf);
+    }
+
+  if (zclient->sock < 0)
+    {
+      if (IS_OSPF6_DUMP_ZEBRA)
+        zlog_info ("ZEBRA:   failed: not connected to zebra");
+      return;
+    }
+
+  if (request->path.origin.adv_router == ospf6->router_id &&
+      (request->path.type == OSPF6_PATH_TYPE_EXTERNAL1 ||
+       request->path.type == OSPF6_PATH_TYPE_EXTERNAL2))
+    {
+      if (IS_OSPF6_DUMP_ZEBRA)
+        zlog_info ("ZEBRA:   self originated external route, ignore");
+      return;
+    }
+
+  /* Only the best path (i.e. the first path of the path-list
+     in 'struct ospf6_route') will be sent to zebra. */
+  ospf6_route_lookup (&route, &request->route.prefix, request->table);
+  if (memcmp (&route.path, &request->path, sizeof (route.path)))
+    {
+      /* this is not preferred best route, ignore */
+      if (IS_OSPF6_DUMP_ZEBRA)
+        zlog_info ("ZEBRA:   not best path, ignore");
+      return;
+    }
+
+  nexthop_list = linklist_create ();
+
+  /* for each nexthop */
+  for (ospf6_route_lookup (&route, &request->route.prefix, request->table);
+       ! ospf6_route_end (&route); ospf6_route_next (&route))
+    {
+      if (memcmp (&route.path, &request->path, sizeof (route.path)))
+        break;
+
+      #define IN6_IS_ILLEGAL_NEXTHOP(a)\
+        ((*(u_int32_t *)(void *)(&(a)->s6_addr[0]) == 0xffffffff) &&\
+        (*(u_int32_t *)(void *)(&(a)->s6_addr[4]) == 0xffffffff) &&\
+        (*(u_int32_t *)(void *)(&(a)->s6_addr[8]) == 0xffffffff) &&\
+        (*(u_int32_t *)(void *)(&(a)->s6_addr[12]) == 0xffffffff))
+      if (IN6_IS_ILLEGAL_NEXTHOP (&route.nexthop.address))
+        {
+          zlog_warn ("ZEBRA: Illegal nexthop");
+          continue;
+        }
+
+      if (type == REMOVE && ! memcmp (&route.nexthop, &request->nexthop,
+                                      sizeof (struct ospf6_nexthop)))
+        continue;
+
+      nexthop = XCALLOC (MTYPE_OSPF6_OTHER, sizeof (struct ospf6_nexthop));
+      if (! nexthop)
+        {
+          zlog_warn ("ZEBRA: Can't update nexthop: malloc failed");
+          continue;
+        }
+
+      memcpy (nexthop, &route.nexthop, sizeof (struct ospf6_nexthop));
+      linklist_add (nexthop, nexthop_list);
+    }
+
+  if (type == REMOVE && nexthop_list->count != 0)
+    type = ADD;
+  else if (type == REMOVE && nexthop_list->count == 0)
+    {
+      if (IS_OSPF6_DUMP_ZEBRA)
+        zlog_info ("ZEBRA:   all nexthop with the selected path has gone");
+
+      if (! memcmp (&request->route, &route.route,
+                    sizeof (struct ospf6_route)))
+        {
+          /* send 'add' of alternative route */
+          struct ospf6_path seconde_path;
+
+          if (IS_OSPF6_DUMP_ZEBRA)
+            zlog_info ("ZEBRA:   found alternative path to add");
+
+          memcpy (&seconde_path, &route.path, sizeof (struct ospf6_path));
+          type = ADD;
+
+          while (! memcmp (&seconde_path, &route.path,
+                           sizeof (struct ospf6_path)))
+            {
+              nexthop = XCALLOC (MTYPE_OSPF6_OTHER,
+                                 sizeof (struct ospf6_nexthop));
+              if (! nexthop)
+                zlog_warn ("ZEBRA:   Can't update nexthop: malloc failed");
+              else
+                {
+                  memcpy (nexthop, &route.nexthop,
+                          sizeof (struct ospf6_nexthop));
+                  linklist_add (nexthop, nexthop_list);
+                }
+
+              ospf6_route_next (&route);
+            }
+        }
+      else
+        {
+          /* there is no alternative route. send 'remove' to zebra for
+             requested route */
+          if (IS_OSPF6_DUMP_ZEBRA)
+            zlog_info ("ZEBRA:   can't find alternative path, remove");
+
+          if (IS_OSPF6_DUMP_ZEBRA)
+            {
+              zlog_info ("ZEBRA:   Debug: walk over the route ?");
+              ospf6_route_log_request ("Debug route", "***", &route);
+              ospf6_route_log_request ("Debug request", "***", request);
+            }
+
+          nexthop = XCALLOC (MTYPE_OSPF6_OTHER,
+                             sizeof (struct ospf6_nexthop));
+          if (! nexthop)
+            zlog_warn ("ZEBRA:   Can't update nexthop: malloc failed");
+          else
+            {
+              memcpy (nexthop, &request->nexthop,
+                      sizeof (struct ospf6_nexthop));
+              linklist_add (nexthop, nexthop_list);
+            }
+        }
+    }
+
+  if (nexthop_list->count == 0)
+    {
+      if (IS_OSPF6_DUMP_ZEBRA)
+        zlog_info ("ZEBRA:   no nexthop, ignore");
+      linklist_delete (nexthop_list);
+      return;
+    }
+
+  /* allocate memory for nexthop_list */
+  nexthops = XCALLOC (MTYPE_OSPF6_OTHER,
+                      nexthop_list->count * sizeof (struct in6_addr *));
+  if (! nexthops)
+    {
+      zlog_warn ("ZEBRA:   Can't update zebra route: malloc failed");
+      for (linklist_head (nexthop_list, &node); !linklist_end (&node);
+           linklist_next (&node))
+        XFREE (MTYPE_OSPF6_OTHER, node.data);
+      linklist_delete (nexthop_list);
+      return;
+    }
+
+  /* allocate memory for ifindex_list */
+  ifindexes = XCALLOC (MTYPE_OSPF6_OTHER,
+                       nexthop_list->count * sizeof (unsigned int));
+  if (! ifindexes)
+    {
+      zlog_warn ("ZEBRA: Can't update zebra route: malloc failed");
+      for (linklist_head (nexthop_list, &node); !linklist_end (&node);
+           linklist_next (&node))
+        XFREE (MTYPE_OSPF6_OTHER, node.data);
+      linklist_delete (nexthop_list);
+      XFREE (MTYPE_OSPF6_OTHER, nexthops);
+      return;
+    }
+
+  i = 0;
+  for (linklist_head (nexthop_list, &node); ! linklist_end (&node);
+       linklist_next (&node))
+    {
+      nexthop = node.data;
+      if (IS_OSPF6_DUMP_ZEBRA)
+        {
+          inet_ntop (AF_INET6, &nexthop->address, buf, sizeof (buf));
+          if_indextoname (nexthop->ifindex, ifname);
+          zlog_info ("ZEBRA:   nexthop: %s%%%s(%d)",
+                     buf, ifname, nexthop->ifindex);
+        }
+      nexthops[i] = &nexthop->address;
+      ifindexes[i] = nexthop->ifindex;
+      i++;
+    }
+
+  api.type = ZEBRA_ROUTE_OSPF6;
+  api.flags = 0;
+  api.message = 0;
+  SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
+  SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX);
+  api.nexthop_num = nexthop_list->count;
+  api.nexthop = nexthops;
+  api.ifindex_num = nexthop_list->count;
+  api.ifindex = ifindexes;
+
+  p = (struct prefix_ipv6 *) &request->route.prefix;
+  if (type == REMOVE && nexthop_list->count == 1)
+    ret = zapi_ipv6_delete (zclient, p, &api);
+  else
+    ret = zapi_ipv6_add (zclient, p, &api);
+
+  if (ret < 0)
+    zlog_err ("ZEBRA: zapi_ipv6_add () failed: %s", strerror (errno));
+
+  for (linklist_head (nexthop_list, &node); !linklist_end (&node);
+       linklist_next (&node))
+    XFREE (MTYPE_OSPF6_OTHER, node.data);
+  linklist_delete (nexthop_list);
+  XFREE (MTYPE_OSPF6_OTHER, nexthops);
+  XFREE (MTYPE_OSPF6_OTHER, ifindexes);
+
+  return;
+}
+
+void
+ospf6_zebra_route_update_add (struct ospf6_route_req *request)
+{
+  ospf6_zebra_route_update (ADD, request);
+}
+
+void
+ospf6_zebra_route_update_remove (struct ospf6_route_req *request)
+{
+  ospf6_zebra_route_update (REMOVE, request);
+}
+
+static void
+ospf6_zebra_redistribute_ospf6 ()
+{
+  struct route_node *node;
+
+  for (node = route_top (ospf6->route_table->table); node;
+       node = route_next (node))
+    {
+      if (! node || ! node->info)
+        continue;
+      ospf6_zebra_route_update_add (node->info);
+    }
+}
+
+static void
+ospf6_zebra_no_redistribute_ospf6 ()
+{
+  struct route_node *node;
+
+  if (! ospf6)
+    return;
+
+  for (node = route_top (ospf6->route_table->table); node;
+       node = route_next (node))
+    {
+      if (! node || ! node->info)
+        continue;
+
+      ospf6_zebra_route_update_remove (node->info);
+    }
+}
+
+
+DEFUN (redistribute_ospf6,
+       redistribute_ospf6_cmd,
+       "redistribute ospf6",
+       "Redistribute control\n"
+       "OSPF6 route\n")
+{
+  /* log */
+  if (IS_OSPF6_DUMP_CONFIG)
+    zlog_info ("Config: redistribute ospf6");
+
+  zclient->redist[ZEBRA_ROUTE_OSPF6] = 1;
+
+  /* set zebra route table */
+  ospf6_zebra_redistribute_ospf6 ();
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_redistribute_ospf6,
+       no_redistribute_ospf6_cmd,
+       "no redistribute ospf6",
+       NO_STR
+       "Redistribute control\n"
+       "OSPF6 route\n")
+{
+  /* log */
+  if (IS_OSPF6_DUMP_CONFIG)
+    zlog_info ("Config: no redistribute ospf6");
+
+  zclient->redist[ZEBRA_ROUTE_OSPF6] = 0;
+
+  if (! ospf6)
+    return CMD_SUCCESS;
+
+  /* clean up zebra route table */
+  ospf6_zebra_no_redistribute_ospf6 ();
+
+  ospf6_route_hook_unregister (ospf6_zebra_route_update_add,
+                               ospf6_zebra_route_update_add,
+                               ospf6_zebra_route_update_remove,
+                               ospf6->route_table);
+
+  return CMD_SUCCESS;
+}
+
+void
+ospf6_zebra_init ()
+{
+  /* Allocate zebra structure. */
+  zclient = zclient_new ();
+  zclient_init (zclient, ZEBRA_ROUTE_OSPF6);
+  zclient->interface_add = ospf6_zebra_if_add;
+  zclient->interface_delete = ospf6_zebra_if_del;
+  zclient->interface_up = ospf6_zebra_if_state_update;
+  zclient->interface_down = ospf6_zebra_if_state_update;
+  zclient->interface_address_add = ospf6_zebra_if_address_update_add;
+  zclient->interface_address_delete = ospf6_zebra_if_address_update_delete;
+  zclient->ipv4_route_add = NULL;
+  zclient->ipv4_route_delete = NULL;
+  zclient->ipv6_route_add = ospf6_zebra_read_ipv6;
+  zclient->ipv6_route_delete = ospf6_zebra_read_ipv6;
+
+  /* redistribute connected route by default */
+  /* ospf6_zebra_redistribute (ZEBRA_ROUTE_CONNECT); */
+
+  /* Install zebra node. */
+  install_node (&zebra_node, ospf6_zebra_config_write);
+
+  /* Install command element for zebra node. */
+  install_element (VIEW_NODE, &show_zebra_cmd);
+  install_element (ENABLE_NODE, &show_zebra_cmd);
+  install_element (CONFIG_NODE, &router_zebra_cmd);
+  install_element (CONFIG_NODE, &no_router_zebra_cmd);
+  install_default (ZEBRA_NODE);
+  install_element (ZEBRA_NODE, &redistribute_ospf6_cmd);
+  install_element (ZEBRA_NODE, &no_redistribute_ospf6_cmd);
+
+#if 0
+  hook.name = "ZebraRouteUpdate";
+  hook.hook_add = ospf6_zebra_route_update_add;
+  hook.hook_change = ospf6_zebra_route_update_add;
+  hook.hook_remove = ospf6_zebra_route_update_remove;
+  ospf6_hook_register (&hook, &route_hook);
+#endif
+
+  return;
+}
+
+void
+ospf6_zebra_finish ()
+{
+  zclient_stop (zclient);
+  zclient_free (zclient);
+  zclient = (struct zclient *) NULL;
+}
+