Initial revision
diff --git a/zebra/zserv.c b/zebra/zserv.c
new file mode 100644
index 0000000..47114ab
--- /dev/null
+++ b/zebra/zserv.c
@@ -0,0 +1,1806 @@
+/* Zebra daemon server routine.
+ * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "prefix.h"
+#include "command.h"
+#include "if.h"
+#include "thread.h"
+#include "stream.h"
+#include "memory.h"
+#include "table.h"
+#include "rib.h"
+#include "network.h"
+#include "sockunion.h"
+#include "log.h"
+#include "zclient.h"
+
+#include "zebra/zserv.h"
+#include "zebra/redistribute.h"
+#include "zebra/debug.h"
+#include "zebra/ipforward.h"
+
+/* Event list of zebra. */
+enum event { ZEBRA_SERV, ZEBRA_READ, ZEBRA_WRITE };
+
+/* Zebra client list. */
+list client_list;
+
+/* Default rtm_table for all clients */
+int rtm_table_default = 0;
+
+void zebra_event (enum event event, int sock, struct zserv *client);
+
+/* For logging of zebra meesages. */
+char *zebra_command_str [] =
+{
+  "NULL",
+  "ZEBRA_INTERFACE_ADD",
+  "ZEBRA_INTERFACE_DELETE",
+  "ZEBRA_INTERFACE_ADDRESS_ADD",
+  "ZEBRA_INTERFACE_ADDRESS_DELETE",
+  "ZEBRA_INTERFACE_UP",
+  "ZEBRA_INTERFACE_DOWN",
+  "ZEBRA_IPV4_ROUTE_ADD",
+  "ZEBRA_IPV4_ROUTE_DELETE",
+  "ZEBRA_IPV6_ROUTE_ADD",
+  "ZEBRA_IPV6_ROUTE_DELETE",
+  "ZEBRA_REDISTRIBUTE_ADD",
+  "ZEBRA_REDISTRIBUTE_DELETE",
+  "ZEBRA_REDISTRIBUTE_DEFAULT_ADD",
+  "ZEBRA_REDISTRIBUTE_DEFAULT_DELETE",
+  "ZEBRA_IPV4_NEXTHOP_LOOKUP",
+  "ZEBRA_IPV6_NEXTHOP_LOOKUP",
+  "ZEBRA_IPV4_IMPORT_LOOKUP",
+  "ZEBRA_IPV6_IMPORT_LOOKUP"
+};
+
+/* Interface is added. Send ZEBRA_INTERFACE_ADD to client. */
+int
+zsend_interface_add (struct zserv *client, struct interface *ifp)
+{
+  struct stream *s;
+
+  /* Check this client need interface information. */
+  if (! client->ifinfo)
+    return -1;
+
+  s = client->obuf;
+  stream_reset (s);
+
+  /* Place holder for size. */
+  stream_putw (s, 0);
+
+  /* Message type. */
+  stream_putc (s, ZEBRA_INTERFACE_ADD);
+
+  /* Interface information. */
+  stream_put (s, ifp->name, INTERFACE_NAMSIZ);
+  stream_putl (s, ifp->ifindex);
+  stream_putl (s, ifp->flags);
+  stream_putl (s, ifp->metric);
+  stream_putl (s, ifp->mtu);
+  stream_putl (s, ifp->bandwidth);
+#ifdef HAVE_SOCKADDR_DL
+  stream_put (s, &ifp->sdl, sizeof (ifp->sdl));
+#else
+  stream_putl (s, ifp->hw_addr_len);
+  if (ifp->hw_addr_len)
+    stream_put (s, ifp->hw_addr, ifp->hw_addr_len);
+#endif /* HAVE_SOCKADDR_DL */
+
+  /* Write packet size. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  return writen (client->sock, s->data, stream_get_endp (s));
+}
+
+/* Interface deletion from zebra daemon. */
+int
+zsend_interface_delete (struct zserv *client, struct interface *ifp)
+{
+  struct stream *s;
+
+  /* Check this client need interface information. */
+  if (! client->ifinfo)
+    return -1;
+
+  s = client->obuf;
+  stream_reset (s);
+
+  /* Packet length placeholder. */
+  stream_putw (s, 0);
+
+  /* Interface information. */
+  stream_putc (s, ZEBRA_INTERFACE_DELETE);
+  stream_put (s, ifp->name, INTERFACE_NAMSIZ);
+  stream_putl (s, ifp->ifindex);
+  stream_putl (s, ifp->flags);
+  stream_putl (s, ifp->metric);
+  stream_putl (s, ifp->mtu);
+  stream_putl (s, ifp->bandwidth);
+
+  /* Write packet length. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  return writen (client->sock, s->data, stream_get_endp (s));
+}
+
+/* Interface address is added. Send ZEBRA_INTERFACE_ADDRESS_ADD to the
+   client. */
+int
+zsend_interface_address_add (struct zserv *client, struct interface *ifp, 
+			     struct connected *ifc)
+{
+  int blen;
+  struct stream *s;
+  struct prefix *p;
+
+  /* Check this client need interface information. */
+  if (! client->ifinfo)
+    return -1;
+
+  s = client->obuf;
+  stream_reset (s);
+
+  /* Place holder for size. */
+  stream_putw (s, 0);
+
+  stream_putc (s, ZEBRA_INTERFACE_ADDRESS_ADD);
+  stream_putl (s, ifp->ifindex);
+
+  /* Interface address flag. */
+  stream_putc (s, ifc->flags);
+
+  /* Prefix information. */
+  p = ifc->address;
+  stream_putc (s, p->family);
+  blen = prefix_blen (p);
+  stream_put (s, &p->u.prefix, blen);
+  stream_putc (s, p->prefixlen);
+
+  /* Destination. */
+  p = ifc->destination;
+  if (p)
+    stream_put (s, &p->u.prefix, blen);
+  else
+    stream_put (s, NULL, blen);
+
+  /* Write packet size. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  return writen (client->sock, s->data, stream_get_endp (s));
+}
+
+/* Interface address is deleted. Send ZEBRA_INTERFACE_ADDRESS_DELETE
+   to the client. */
+int
+zsend_interface_address_delete (struct zserv *client, struct interface *ifp,
+				struct connected *ifc)
+{
+  int blen;
+  struct stream *s;
+  struct prefix *p;
+
+  /* Check this client need interface information. */
+  if (! client->ifinfo)
+    return -1;
+
+  s = client->obuf;
+  stream_reset (s);
+
+  /* Place holder for size. */
+  stream_putw (s, 0);
+
+  stream_putc (s, ZEBRA_INTERFACE_ADDRESS_DELETE);
+  stream_putl (s, ifp->ifindex);
+
+  /* Interface address flag. */
+  stream_putc (s, ifc->flags);
+
+  /* Prefix information. */
+  p = ifc->address;
+  stream_putc (s, p->family);
+  blen = prefix_blen (p);
+  stream_put (s, &p->u.prefix, blen);
+
+  p = ifc->destination;
+  if (p)
+    stream_put (s, &p->u.prefix, blen);
+  else
+    stream_put (s, NULL, blen);
+
+  /* Write packet size. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  return writen (client->sock, s->data, stream_get_endp (s));
+}
+
+int
+zsend_interface_up (struct zserv *client, struct interface *ifp)
+{
+  struct stream *s;
+
+  /* Check this client need interface information. */
+  if (! client->ifinfo)
+    return -1;
+
+  s = client->obuf;
+  stream_reset (s);
+
+  /* Place holder for size. */
+  stream_putw (s, 0);
+
+  /* Zebra command. */
+  stream_putc (s, ZEBRA_INTERFACE_UP);
+
+  /* Interface information. */
+  stream_put (s, ifp->name, INTERFACE_NAMSIZ);
+  stream_putl (s, ifp->ifindex);
+  stream_putl (s, ifp->flags);
+  stream_putl (s, ifp->metric);
+  stream_putl (s, ifp->mtu);
+  stream_putl (s, ifp->bandwidth);
+
+  /* Write packet size. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  return writen (client->sock, s->data, stream_get_endp (s));
+}
+
+int
+zsend_interface_down (struct zserv *client, struct interface *ifp)
+{
+  struct stream *s;
+
+  /* Check this client need interface information. */
+  if (! client->ifinfo)
+    return -1;
+
+  s = client->obuf;
+  stream_reset (s);
+
+  /* Place holder for size. */
+  stream_putw (s, 0);
+
+  /* Zebra command. */
+  stream_putc (s, ZEBRA_INTERFACE_DOWN);
+
+  /* Interface information. */
+  stream_put (s, ifp->name, INTERFACE_NAMSIZ);
+  stream_putl (s, ifp->ifindex);
+  stream_putl (s, ifp->flags);
+  stream_putl (s, ifp->metric);
+  stream_putl (s, ifp->mtu);
+  stream_putl (s, ifp->bandwidth);
+
+  /* Write packet size. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  return writen (client->sock, s->data, stream_get_endp (s));
+}
+
+int
+zsend_ipv4_add_multipath (struct zserv *client, struct prefix *p, 
+			  struct rib *rib)
+{
+  int psize;
+  struct stream *s;
+  struct nexthop *nexthop;
+  struct in_addr empty;
+
+  empty.s_addr = 0;
+  s = client->obuf;
+  stream_reset (s);
+
+  /* Place holder for size. */
+  stream_putw (s, 0);
+
+  /* Put command, type and nexthop. */
+  stream_putc (s, ZEBRA_IPV4_ROUTE_ADD);
+  stream_putc (s, rib->type);
+  stream_putc (s, rib->flags);
+  stream_putc (s, ZAPI_MESSAGE_NEXTHOP | ZAPI_MESSAGE_IFINDEX | ZAPI_MESSAGE_METRIC);
+
+  /* Prefix. */
+  psize = PSIZE (p->prefixlen);
+  stream_putc (s, p->prefixlen);
+  stream_write (s, (u_char *)&p->u.prefix, psize);
+
+  /* Nexthop */
+  for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+    {
+      if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
+	{
+	  stream_putc (s, 1);
+
+	  if (nexthop->type == NEXTHOP_TYPE_IPV4
+	      || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
+	    stream_put_in_addr (s, &nexthop->gate.ipv4);
+	  else
+	    stream_put_in_addr (s, &empty);
+
+	  /* Interface index. */
+	  stream_putc (s, 1);
+	  stream_putl (s, nexthop->ifindex);
+
+	  break;
+	}
+    }
+
+  /* Metric */
+  stream_putl (s, rib->metric);
+
+  /* Write packet size. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  return writen (client->sock, s->data, stream_get_endp (s));
+}
+
+int
+zsend_ipv4_delete_multipath (struct zserv *client, struct prefix *p,
+			     struct rib *rib)
+{
+  int psize;
+  struct stream *s;
+  struct nexthop *nexthop;
+  struct in_addr empty;
+
+  empty.s_addr = 0;
+
+  s = client->obuf;
+  stream_reset (s);
+
+  /* Place holder for size. */
+  stream_putw (s, 0);
+
+  /* Put command, type and nexthop. */
+  stream_putc (s, ZEBRA_IPV4_ROUTE_DELETE);
+  stream_putc (s, rib->type);
+  stream_putc (s, rib->flags);
+  stream_putc (s, ZAPI_MESSAGE_NEXTHOP|ZAPI_MESSAGE_IFINDEX);
+
+  /* Prefix. */
+  psize = PSIZE (p->prefixlen);
+  stream_putc (s, p->prefixlen);
+  stream_write (s, (u_char *)&p->u.prefix, psize);
+
+  /* Nexthop */
+  for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+    {
+      if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
+	{
+	  stream_putc (s, 1);
+
+	  if (nexthop->type == NEXTHOP_TYPE_IPV4)
+	    stream_put_in_addr (s, &nexthop->gate.ipv4);
+	  else
+	    stream_put_in_addr (s, &empty);
+
+	  /* Interface index. */
+	  stream_putc (s, 1);
+	  stream_putl (s, nexthop->ifindex);
+
+	  break;
+	}
+    }
+
+  /* Write packet size. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  return writen (client->sock, s->data, stream_get_endp (s));
+}
+
+int
+zsend_ipv4_add (struct zserv *client, int type, int flags,
+		struct prefix_ipv4 *p, struct in_addr *nexthop,
+		unsigned int ifindex)
+{
+  int psize;
+  struct stream *s;
+
+  s = client->obuf;
+  stream_reset (s);
+
+  /* Place holder for size. */
+  stream_putw (s, 0);
+
+  /* Put command, type and nexthop. */
+  stream_putc (s, ZEBRA_IPV4_ROUTE_ADD);
+  stream_putc (s, type);
+  stream_putc (s, flags);
+  stream_putc (s, ZAPI_MESSAGE_NEXTHOP|ZAPI_MESSAGE_IFINDEX);
+
+  /* Prefix. */
+  psize = PSIZE (p->prefixlen);
+  stream_putc (s, p->prefixlen);
+  stream_write (s, (u_char *)&p->prefix, psize);
+
+  /* Nexthop */
+  stream_putc (s, 1);
+  stream_put_in_addr (s, nexthop);
+
+  /* Interface index. */
+  stream_putc (s, 1);
+  stream_putl (s, ifindex);
+
+  /* Write packet size. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  return writen (client->sock, s->data, stream_get_endp (s));
+}
+
+int
+zsend_ipv4_delete (struct zserv *client, int type, int flags,
+		   struct prefix_ipv4 *p, struct in_addr *nexthop,
+		   unsigned int ifindex)
+{
+  int psize;
+  struct stream *s;
+
+  s = client->obuf;
+  stream_reset (s);
+
+  /* Place holder for size. */
+  stream_putw (s, 0);
+
+  /* Put command, type and nexthop. */
+  stream_putc (s, ZEBRA_IPV4_ROUTE_DELETE);
+  stream_putc (s, type);
+  stream_putc (s, flags);
+  stream_putc (s, ZAPI_MESSAGE_NEXTHOP|ZAPI_MESSAGE_IFINDEX);
+
+  /* Prefix. */
+  psize = PSIZE (p->prefixlen);
+  stream_putc (s, p->prefixlen);
+  stream_write (s, (u_char *)&p->prefix, psize);
+
+  /* Nexthop */
+  stream_putc (s, 1);
+  stream_put_in_addr (s, nexthop);
+
+  /* Interface index. */
+  stream_putc (s, 1);
+  stream_putl (s, ifindex);
+
+  /* Write packet size. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  return writen (client->sock, s->data, stream_get_endp (s));
+}
+
+#ifdef HAVE_IPV6
+int
+zsend_ipv6_add (struct zserv *client, int type, int flags,
+		struct prefix_ipv6 *p, struct in6_addr *nexthop,
+		unsigned int ifindex)
+{
+  int psize;
+  struct stream *s;
+
+  s = client->obuf;
+  stream_reset (s);
+
+  /* Place holder for size. */
+  stream_putw (s, 0);
+
+  /* Put command, type and nexthop. */
+  stream_putc (s, ZEBRA_IPV6_ROUTE_ADD);
+  stream_putc (s, type);
+  stream_putc (s, flags);
+  stream_putc (s, ZAPI_MESSAGE_NEXTHOP|ZAPI_MESSAGE_IFINDEX);
+
+  /* Prefix. */
+  psize = PSIZE (p->prefixlen);
+  stream_putc (s, p->prefixlen);
+  stream_write (s, (u_char *)&p->prefix, psize);
+
+  /* Nexthop */
+  stream_putc (s, 1);
+  stream_write (s, (u_char *)nexthop, 16);
+
+  /* Interface index. */
+  stream_putc (s, 1);
+  stream_putl (s, ifindex);
+
+  /* Write packet size. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  return writen (client->sock, s->data, stream_get_endp (s));
+}
+
+int
+zsend_ipv6_add_multipath (struct zserv *client, struct prefix *p,
+			  struct rib *rib)
+{
+  int psize;
+  struct stream *s;
+  struct nexthop *nexthop;
+  struct in6_addr empty;
+
+  memset (&empty, 0, sizeof (struct in6_addr));
+  s = client->obuf;
+  stream_reset (s);
+
+  /* Place holder for size. */
+  stream_putw (s, 0);
+
+  /* Put command, type and nexthop. */
+  stream_putc (s, ZEBRA_IPV6_ROUTE_ADD);
+  stream_putc (s, rib->type);
+  stream_putc (s, rib->flags);
+  stream_putc (s, ZAPI_MESSAGE_NEXTHOP | ZAPI_MESSAGE_IFINDEX | ZAPI_MESSAGE_METRIC);
+
+  /* Prefix. */
+  psize = PSIZE (p->prefixlen);
+  stream_putc (s, p->prefixlen);
+  stream_write (s, (u_char *) &p->u.prefix, psize);
+
+  /* Nexthop */
+  for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+    {
+      if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
+	{
+	  stream_putc (s, 1);
+
+	  if (nexthop->type == NEXTHOP_TYPE_IPV6)
+	    stream_write (s, (u_char *) &nexthop->gate.ipv6, 16);
+	  else
+	    stream_write (s, (u_char *) &empty, 16);
+
+	  /* Interface index. */
+	  stream_putc (s, 1);
+	  stream_putl (s, nexthop->ifindex);
+
+	  break;
+	}
+    }
+
+  /* Metric */
+  stream_putl (s, rib->metric);
+
+  /* Write packet size. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  return writen (client->sock, s->data, stream_get_endp (s));
+}
+
+int
+zsend_ipv6_delete (struct zserv *client, int type, int flags,
+		   struct prefix_ipv6 *p, struct in6_addr *nexthop,
+		   unsigned int ifindex)
+{
+  int psize;
+  struct stream *s;
+
+  s = client->obuf;
+  stream_reset (s);
+
+  /* Place holder for size. */
+  stream_putw (s, 0);
+
+  /* Put command, type and nexthop. */
+  stream_putc (s, ZEBRA_IPV6_ROUTE_DELETE);
+  stream_putc (s, type);
+  stream_putc (s, flags);
+  stream_putc (s, ZAPI_MESSAGE_NEXTHOP|ZAPI_MESSAGE_IFINDEX);
+
+  /* Prefix. */
+  psize = PSIZE (p->prefixlen);
+  stream_putc (s, p->prefixlen);
+  stream_write (s, (u_char *)&p->prefix, psize);
+
+  /* Nexthop */
+  stream_putc (s, 1);
+  stream_write (s, (u_char *)nexthop, 16);
+
+  /* Interface index. */
+  stream_putc (s, 1);
+  stream_putl (s, ifindex);
+
+  /* Write packet size. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  return writen (client->sock, s->data, stream_get_endp (s));
+}
+
+int
+zsend_ipv6_delete_multipath (struct zserv *client, struct prefix *p,
+			     struct rib *rib)
+{
+  int psize;
+  struct stream *s;
+  struct nexthop *nexthop;
+  struct in6_addr empty;
+
+  memset (&empty, 0, sizeof (struct in6_addr));
+  s = client->obuf;
+  stream_reset (s);
+
+  /* Place holder for size. */
+  stream_putw (s, 0);
+
+  /* Put command, type and nexthop. */
+  stream_putc (s, ZEBRA_IPV6_ROUTE_DELETE);
+  stream_putc (s, rib->type);
+  stream_putc (s, rib->flags);
+  stream_putc (s, ZAPI_MESSAGE_NEXTHOP|ZAPI_MESSAGE_IFINDEX);
+
+  /* Prefix. */
+  psize = PSIZE (p->prefixlen);
+  stream_putc (s, p->prefixlen);
+  stream_write (s, (u_char *)&p->u.prefix, psize);
+
+  /* Nexthop */
+  for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+    {
+      if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
+	{
+	  stream_putc (s, 1);
+
+	  if (nexthop->type == NEXTHOP_TYPE_IPV6)
+	    stream_write (s, (u_char *) &nexthop->gate.ipv6, 16);
+	  else
+	    stream_write (s, (u_char *) &empty, 16);
+
+	  /* Interface index. */
+	  stream_putc (s, 1);
+	  stream_putl (s, nexthop->ifindex);
+
+	  break;
+	}
+    }
+
+  /* Write packet size. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  return writen (client->sock, s->data, stream_get_endp (s));
+}
+
+int
+zsend_ipv6_nexthop_lookup (struct zserv *client, struct in6_addr *addr)
+{
+  struct stream *s;
+  struct rib *rib;
+  unsigned long nump;
+  u_char num;
+  struct nexthop *nexthop;
+
+  /* Lookup nexthop. */
+  rib = rib_match_ipv6 (addr);
+
+  /* Get output stream. */
+  s = client->obuf;
+  stream_reset (s);
+
+  /* Fill in result. */
+  stream_putw (s, 0);
+  stream_putc (s, ZEBRA_IPV6_NEXTHOP_LOOKUP);
+  stream_put (s, &addr, 16);
+
+  if (rib)
+    {
+      stream_putl (s, rib->metric);
+      num = 0;
+      nump = s->putp;
+      stream_putc (s, 0);
+      for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+	if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
+	  {
+	    stream_putc (s, nexthop->type);
+	    switch (nexthop->type)
+	      {
+	      case ZEBRA_NEXTHOP_IPV6:
+		stream_put (s, &nexthop->gate.ipv6, 16);
+		break;
+	      case ZEBRA_NEXTHOP_IPV6_IFINDEX:
+	      case ZEBRA_NEXTHOP_IPV6_IFNAME:
+		stream_put (s, &nexthop->gate.ipv6, 16);
+		stream_putl (s, nexthop->ifindex);
+		break;
+	      case ZEBRA_NEXTHOP_IFINDEX:
+	      case ZEBRA_NEXTHOP_IFNAME:
+		stream_putl (s, nexthop->ifindex);
+		break;
+	      }
+	    num++;
+	  }
+      stream_putc_at (s, nump, num);
+    }
+  else
+    {
+      stream_putl (s, 0);
+      stream_putc (s, 0);
+    }
+
+  stream_putw_at (s, 0, stream_get_endp (s));
+  
+  return writen (client->sock, s->data, stream_get_endp (s));
+}
+#endif /* HAVE_IPV6 */
+
+int
+zsend_ipv4_nexthop_lookup (struct zserv *client, struct in_addr addr)
+{
+  struct stream *s;
+  struct rib *rib;
+  unsigned long nump;
+  u_char num;
+  struct nexthop *nexthop;
+
+  /* Lookup nexthop. */
+  rib = rib_match_ipv4 (addr);
+
+  /* Get output stream. */
+  s = client->obuf;
+  stream_reset (s);
+
+  /* Fill in result. */
+  stream_putw (s, 0);
+  stream_putc (s, ZEBRA_IPV4_NEXTHOP_LOOKUP);
+  stream_put_in_addr (s, &addr);
+
+  if (rib)
+    {
+      stream_putl (s, rib->metric);
+      num = 0;
+      nump = s->putp;
+      stream_putc (s, 0);
+      for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+	if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
+	  {
+	    stream_putc (s, nexthop->type);
+	    switch (nexthop->type)
+	      {
+	      case ZEBRA_NEXTHOP_IPV4:
+		stream_put_in_addr (s, &nexthop->gate.ipv4);
+		break;
+	      case ZEBRA_NEXTHOP_IFINDEX:
+	      case ZEBRA_NEXTHOP_IFNAME:
+		stream_putl (s, nexthop->ifindex);
+		break;
+	      }
+	    num++;
+	  }
+      stream_putc_at (s, nump, num);
+    }
+  else
+    {
+      stream_putl (s, 0);
+      stream_putc (s, 0);
+    }
+
+  stream_putw_at (s, 0, stream_get_endp (s));
+  
+  return writen (client->sock, s->data, stream_get_endp (s));
+}
+
+int
+zsend_ipv4_import_lookup (struct zserv *client, struct prefix_ipv4 *p)
+{
+  struct stream *s;
+  struct rib *rib;
+  unsigned long nump;
+  u_char num;
+  struct nexthop *nexthop;
+
+  /* Lookup nexthop. */
+  rib = rib_lookup_ipv4 (p);
+
+  /* Get output stream. */
+  s = client->obuf;
+  stream_reset (s);
+
+  /* Fill in result. */
+  stream_putw (s, 0);
+  stream_putc (s, ZEBRA_IPV4_IMPORT_LOOKUP);
+  stream_put_in_addr (s, &p->prefix);
+
+  if (rib)
+    {
+      stream_putl (s, rib->metric);
+      num = 0;
+      nump = s->putp;
+      stream_putc (s, 0);
+      for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+	if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
+	  {
+	    stream_putc (s, nexthop->type);
+	    switch (nexthop->type)
+	      {
+	      case ZEBRA_NEXTHOP_IPV4:
+		stream_put_in_addr (s, &nexthop->gate.ipv4);
+		break;
+	      case ZEBRA_NEXTHOP_IFINDEX:
+	      case ZEBRA_NEXTHOP_IFNAME:
+		stream_putl (s, nexthop->ifindex);
+		break;
+	      }
+	    num++;
+	  }
+      stream_putc_at (s, nump, num);
+    }
+  else
+    {
+      stream_putl (s, 0);
+      stream_putc (s, 0);
+    }
+
+  stream_putw_at (s, 0, stream_get_endp (s));
+  
+  return writen (client->sock, s->data, stream_get_endp (s));
+}
+
+/* Register zebra server interface information.  Send current all
+   interface and address information. */
+void
+zread_interface_add (struct zserv *client, u_short length)
+{
+  listnode ifnode;
+  listnode cnode;
+  struct interface *ifp;
+  struct connected *c;
+
+  /* Interface information is needed. */
+  client->ifinfo = 1;
+
+  for (ifnode = listhead (iflist); ifnode; ifnode = nextnode (ifnode))
+    {
+      ifp = getdata (ifnode);
+
+      /* Skip pseudo interface. */
+      if (! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
+	continue;
+
+      zsend_interface_add (client, ifp);
+
+      for (cnode = listhead (ifp->connected); cnode; nextnode (cnode))
+	{
+	  c = getdata (cnode);
+	  if (CHECK_FLAG (c->conf, ZEBRA_IFC_REAL))
+	    zsend_interface_address_add (client, ifp, c);
+	}
+    }
+}
+
+/* Unregister zebra server interface information. */
+void
+zread_interface_delete (struct zserv *client, u_short length)
+{
+  client->ifinfo = 0;
+}
+
+/* This function support multiple nexthop. */
+void
+zread_ipv4_add (struct zserv *client, u_short length)
+{
+  int i;
+  struct rib *rib;
+  struct prefix_ipv4 p;
+  u_char message;
+  struct in_addr nexthop;
+  u_char nexthop_num;
+  u_char nexthop_type;
+  struct stream *s;
+  unsigned int ifindex;
+  u_char ifname_len;
+
+  /* Get input stream.  */
+  s = client->ibuf;
+
+  /* Allocate new rib. */
+  rib = XMALLOC (MTYPE_RIB, sizeof (struct rib));
+  memset (rib, 0, sizeof (struct rib));
+
+  /* Type, flags, message. */
+  rib->type = stream_getc (s);
+  rib->flags = stream_getc (s);
+  message = stream_getc (s);
+  rib->uptime = time (NULL);
+
+  /* IPv4 prefix. */
+  memset (&p, 0, sizeof (struct prefix_ipv4));
+  p.family = AF_INET;
+  p.prefixlen = stream_getc (s);
+  stream_get (&p.prefix, s, PSIZE (p.prefixlen));
+
+  /* Nexthop parse. */
+  if (CHECK_FLAG (message, ZAPI_MESSAGE_NEXTHOP))
+    {
+      nexthop_num = stream_getc (s);
+
+      for (i = 0; i < nexthop_num; i++)
+	{
+	  nexthop_type = stream_getc (s);
+
+	  switch (nexthop_type)
+	    {
+	    case ZEBRA_NEXTHOP_IFINDEX:
+	      ifindex = stream_getl (s);
+	      nexthop_ifindex_add (rib, ifindex);
+	      break;
+	    case ZEBRA_NEXTHOP_IFNAME:
+	      ifname_len = stream_getc (s);
+	      stream_forward (s, ifname_len);
+	      break;
+	    case ZEBRA_NEXTHOP_IPV4:
+	      nexthop.s_addr = stream_get_ipv4 (s);
+	      nexthop_ipv4_add (rib, &nexthop);
+	      break;
+	    case ZEBRA_NEXTHOP_IPV6:
+	      stream_forward (s, IPV6_MAX_BYTELEN);
+	      break;
+	    case ZEBRA_NEXTHOP_BLACKHOLE:
+	      nexthop_blackhole_add (rib);
+	      break;
+	    }
+	}
+    }
+
+  /* Distance. */
+  if (CHECK_FLAG (message, ZAPI_MESSAGE_DISTANCE))
+    rib->distance = stream_getc (s);
+
+  /* Metric. */
+  if (CHECK_FLAG (message, ZAPI_MESSAGE_METRIC))
+    rib->metric = stream_getl (s);
+    
+  rib_add_ipv4_multipath (&p, rib);
+}
+
+/* Zebra server IPv4 prefix delete function. */
+void
+zread_ipv4_delete (struct zserv *client, u_short length)
+{
+  int i;
+  struct stream *s;
+  struct zapi_ipv4 api;
+  struct in_addr nexthop;
+  unsigned long ifindex;
+  struct prefix_ipv4 p;
+  u_char nexthop_num;
+  u_char nexthop_type;
+  u_char ifname_len;
+  
+  s = client->ibuf;
+  ifindex = 0;
+  nexthop.s_addr = 0;
+
+  /* Type, flags, message. */
+  api.type = stream_getc (s);
+  api.flags = stream_getc (s);
+  api.message = stream_getc (s);
+
+  /* IPv4 prefix. */
+  memset (&p, 0, sizeof (struct prefix_ipv4));
+  p.family = AF_INET;
+  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))
+    {
+      nexthop_num = stream_getc (s);
+
+      for (i = 0; i < nexthop_num; i++)
+	{
+	  nexthop_type = stream_getc (s);
+
+	  switch (nexthop_type)
+	    {
+	    case ZEBRA_NEXTHOP_IFINDEX:
+	      ifindex = stream_getl (s);
+	      break;
+	    case ZEBRA_NEXTHOP_IFNAME:
+	      ifname_len = stream_getc (s);
+	      stream_forward (s, ifname_len);
+	      break;
+	    case ZEBRA_NEXTHOP_IPV4:
+	      nexthop.s_addr = stream_get_ipv4 (s);
+	      break;
+	    case ZEBRA_NEXTHOP_IPV6:
+	      stream_forward (s, IPV6_MAX_BYTELEN);
+	      break;
+	    }
+	}
+    }
+
+  /* Distance. */
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
+    api.distance = stream_getc (s);
+  else
+    api.distance = 0;
+
+  /* Metric. */
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
+    api.metric = stream_getl (s);
+  else
+    api.metric = 0;
+    
+  rib_delete_ipv4 (api.type, api.flags, &p, &nexthop, ifindex,
+		   client->rtm_table);
+}
+
+/* Nexthop lookup for IPv4. */
+void
+zread_ipv4_nexthop_lookup (struct zserv *client, u_short length)
+{
+  struct in_addr addr;
+
+  addr.s_addr = stream_get_ipv4 (client->ibuf);
+  zsend_ipv4_nexthop_lookup (client, addr);
+}
+
+/* Nexthop lookup for IPv4. */
+void
+zread_ipv4_import_lookup (struct zserv *client, u_short length)
+{
+  struct prefix_ipv4 p;
+
+  p.family = AF_INET;
+  p.prefixlen = stream_getc (client->ibuf);
+  p.prefix.s_addr = stream_get_ipv4 (client->ibuf);
+
+  zsend_ipv4_import_lookup (client, &p);
+}
+
+#ifdef HAVE_IPV6
+/* Zebra server IPv6 prefix add function. */
+void
+zread_ipv6_add (struct zserv *client, u_short length)
+{
+  int i;
+  struct stream *s;
+  struct zapi_ipv6 api;
+  struct in6_addr nexthop;
+  unsigned long ifindex;
+  struct prefix_ipv6 p;
+  
+  s = client->ibuf;
+  ifindex = 0;
+  memset (&nexthop, 0, sizeof (struct in6_addr));
+
+  /* Type, flags, message. */
+  api.type = stream_getc (s);
+  api.flags = stream_getc (s);
+  api.message = stream_getc (s);
+
+  /* IPv4 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))
+    {
+      u_char nexthop_type;
+
+      api.nexthop_num = stream_getc (s);
+      for (i = 0; i < api.nexthop_num; i++)
+	{
+	  nexthop_type = stream_getc (s);
+
+	  switch (nexthop_type)
+	    {
+	    case ZEBRA_NEXTHOP_IPV6:
+	      stream_get (&nexthop, s, 16);
+	      break;
+	    case ZEBRA_NEXTHOP_IFINDEX:
+	      ifindex = stream_getl (s);
+	      break;
+	    }
+	}
+    }
+
+  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;
+    
+  if (IN6_IS_ADDR_UNSPECIFIED (&nexthop))
+    rib_add_ipv6 (api.type, api.flags, &p, NULL, ifindex, 0);
+  else
+    rib_add_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, 0);
+}
+
+/* Zebra server IPv6 prefix delete function. */
+void
+zread_ipv6_delete (struct zserv *client, u_short length)
+{
+  int i;
+  struct stream *s;
+  struct zapi_ipv6 api;
+  struct in6_addr nexthop;
+  unsigned long ifindex;
+  struct prefix_ipv6 p;
+  
+  s = client->ibuf;
+  ifindex = 0;
+  memset (&nexthop, 0, sizeof (struct in6_addr));
+
+  /* Type, flags, message. */
+  api.type = stream_getc (s);
+  api.flags = stream_getc (s);
+  api.message = stream_getc (s);
+
+  /* IPv4 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))
+    {
+      u_char nexthop_type;
+
+      api.nexthop_num = stream_getc (s);
+      for (i = 0; i < api.nexthop_num; i++)
+	{
+	  nexthop_type = stream_getc (s);
+
+	  switch (nexthop_type)
+	    {
+	    case ZEBRA_NEXTHOP_IPV6:
+	      stream_get (&nexthop, s, 16);
+	      break;
+	    case ZEBRA_NEXTHOP_IFINDEX:
+	      ifindex = stream_getl (s);
+	      break;
+	    }
+	}
+    }
+
+  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;
+    
+  if (IN6_IS_ADDR_UNSPECIFIED (&nexthop))
+    rib_delete_ipv6 (api.type, api.flags, &p, NULL, ifindex, 0);
+  else
+    rib_delete_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, 0);
+}
+
+void
+zebra_read_ipv6 (int command, struct zserv *client, u_short length)
+{
+  u_char type;
+  u_char flags;
+  struct in6_addr nexthop, *gate;
+  u_char *lim;
+  u_char *pnt;
+  unsigned int ifindex;
+
+  pnt = stream_pnt (client->ibuf);
+  lim = pnt + length;
+
+  type = stream_getc (client->ibuf);
+  flags = stream_getc (client->ibuf);
+  stream_get (&nexthop, client->ibuf, sizeof (struct in6_addr));
+  
+  while (stream_pnt (client->ibuf) < lim)
+    {
+      int size;
+      struct prefix_ipv6 p;
+      
+      ifindex = stream_getl (client->ibuf);
+
+      memset (&p, 0, sizeof (struct prefix_ipv6));
+      p.family = AF_INET6;
+      p.prefixlen = stream_getc (client->ibuf);
+      size = PSIZE(p.prefixlen);
+      stream_get (&p.prefix, client->ibuf, size);
+
+      if (IN6_IS_ADDR_UNSPECIFIED (&nexthop))
+        gate = NULL;
+      else
+        gate = &nexthop;
+
+      if (command == ZEBRA_IPV6_ROUTE_ADD)
+	rib_add_ipv6 (type, flags, &p, gate, ifindex, 0);
+      else
+	rib_delete_ipv6 (type, flags, &p, gate, ifindex, 0);
+    }
+}
+
+void
+zread_ipv6_nexthop_lookup (struct zserv *client, u_short length)
+{
+  struct in6_addr addr;
+  char buf[BUFSIZ];
+
+  stream_get (&addr, client->ibuf, 16);
+  printf ("DEBUG %s\n", inet_ntop (AF_INET6, &addr, buf, BUFSIZ));
+
+  zsend_ipv6_nexthop_lookup (client, &addr);
+}
+#endif /* HAVE_IPV6 */
+
+/* Close zebra client. */
+void
+zebra_client_close (struct zserv *client)
+{
+  /* Close file descriptor. */
+  if (client->sock)
+    {
+      close (client->sock);
+      client->sock = -1;
+    }
+
+  /* Free stream buffers. */
+  if (client->ibuf)
+    stream_free (client->ibuf);
+  if (client->obuf)
+    stream_free (client->obuf);
+
+  /* Release threads. */
+  if (client->t_read)
+    thread_cancel (client->t_read);
+  if (client->t_write)
+    thread_cancel (client->t_write);
+
+  /* Free client structure. */
+  listnode_delete (client_list, client);
+  XFREE (0, client);
+}
+
+/* Make new client. */
+void
+zebra_client_create (int sock)
+{
+  struct zserv *client;
+
+  client = XCALLOC (0, sizeof (struct zserv));
+
+  /* Make client input/output buffer. */
+  client->sock = sock;
+  client->ibuf = stream_new (ZEBRA_MAX_PACKET_SIZ);
+  client->obuf = stream_new (ZEBRA_MAX_PACKET_SIZ);
+
+  /* Set table number. */
+  client->rtm_table = rtm_table_default;
+
+  /* Add this client to linked list. */
+  listnode_add (client_list, client);
+  
+  /* Make new read thread. */
+  zebra_event (ZEBRA_READ, sock, client);
+}
+
+/* Handler of zebra service request. */
+int
+zebra_client_read (struct thread *thread)
+{
+  int sock;
+  struct zserv *client;
+  int nbyte;
+  u_short length;
+  u_char command;
+
+  /* Get thread data.  Reset reading thread because I'm running. */
+  sock = THREAD_FD (thread);
+  client = THREAD_ARG (thread);
+  client->t_read = NULL;
+
+  /* Read length and command. */
+  nbyte = stream_read (client->ibuf, sock, 3);
+  if (nbyte <= 0) 
+    {
+      if (IS_ZEBRA_DEBUG_EVENT)
+	zlog_info ("connection closed socket [%d]", sock);
+      zebra_client_close (client);
+      return -1;
+    }
+  length = stream_getw (client->ibuf);
+  command = stream_getc (client->ibuf);
+
+  if (length < 3) 
+    {
+      if (IS_ZEBRA_DEBUG_EVENT)
+	zlog_info ("length %d is less than 3 ", length);
+      zebra_client_close (client);
+      return -1;
+    }
+
+  length -= 3;
+
+  /* Read rest of data. */
+  if (length)
+    {
+      nbyte = stream_read (client->ibuf, sock, length);
+      if (nbyte <= 0) 
+	{
+	  if (IS_ZEBRA_DEBUG_EVENT)
+	    zlog_info ("connection closed [%d] when reading zebra data", sock);
+	  zebra_client_close (client);
+	  return -1;
+	}
+    }
+
+  /* Debug packet information. */
+  if (IS_ZEBRA_DEBUG_EVENT)
+    zlog_info ("zebra message comes from socket [%d]", sock);
+
+  if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV)
+    zlog_info ("zebra message received [%s] %d", 
+	       zebra_command_str[command], length);
+
+  switch (command) 
+    {
+    case ZEBRA_INTERFACE_ADD:
+      zread_interface_add (client, length);
+      break;
+    case ZEBRA_INTERFACE_DELETE:
+      zread_interface_delete (client, length);
+      break;
+    case ZEBRA_IPV4_ROUTE_ADD:
+      zread_ipv4_add (client, length);
+      break;
+    case ZEBRA_IPV4_ROUTE_DELETE:
+      zread_ipv4_delete (client, length);
+      break;
+#ifdef HAVE_IPV6
+    case ZEBRA_IPV6_ROUTE_ADD:
+      zread_ipv6_add (client, length);
+      break;
+    case ZEBRA_IPV6_ROUTE_DELETE:
+      zread_ipv6_delete (client, length);
+      break;
+#endif /* HAVE_IPV6 */
+    case ZEBRA_REDISTRIBUTE_ADD:
+      zebra_redistribute_add (command, client, length);
+      break;
+    case ZEBRA_REDISTRIBUTE_DELETE:
+      zebra_redistribute_delete (command, client, length);
+      break;
+    case ZEBRA_REDISTRIBUTE_DEFAULT_ADD:
+      zebra_redistribute_default_add (command, client, length);
+      break;
+    case ZEBRA_REDISTRIBUTE_DEFAULT_DELETE:
+      zebra_redistribute_default_delete (command, client, length);
+      break;
+    case ZEBRA_IPV4_NEXTHOP_LOOKUP:
+      zread_ipv4_nexthop_lookup (client, length);
+      break;
+#ifdef HAVE_IPV6
+    case ZEBRA_IPV6_NEXTHOP_LOOKUP:
+      zread_ipv6_nexthop_lookup (client, length);
+      break;
+#endif /* HAVE_IPV6 */
+    case ZEBRA_IPV4_IMPORT_LOOKUP:
+      zread_ipv4_import_lookup (client, length);
+      break;
+    default:
+      zlog_info ("Zebra received unknown command %d", command);
+      break;
+    }
+
+  stream_reset (client->ibuf);
+  zebra_event (ZEBRA_READ, sock, client);
+
+  return 0;
+}
+
+/* Write output buffer to the socket. */
+void
+zebra_write (struct thread *thread)
+{
+  int sock;
+  struct zserv *client;
+
+  /* Thread treatment. */
+  sock = THREAD_FD (thread);
+  client = THREAD_ARG (thread);
+  client->t_write = NULL;
+
+  stream_flush (client->obuf, sock);
+}
+
+/* Accept code of zebra server socket. */
+int
+zebra_accept (struct thread *thread)
+{
+  int accept_sock;
+  int client_sock;
+  struct sockaddr_in client;
+  socklen_t len;
+
+  accept_sock = THREAD_FD (thread);
+
+  len = sizeof (struct sockaddr_in);
+  client_sock = accept (accept_sock, (struct sockaddr *) &client, &len);
+
+  if (client_sock < 0)
+    {
+      zlog_warn ("Can't accept zebra socket: %s", strerror (errno));
+      return -1;
+    }
+
+  /* Create new zebra client. */
+  zebra_client_create (client_sock);
+
+  /* Register myself. */
+  zebra_event (ZEBRA_SERV, accept_sock, NULL);
+
+  return 0;
+}
+
+/* Make zebra's server socket. */
+void
+zebra_serv ()
+{
+  int ret;
+  int accept_sock;
+  struct sockaddr_in addr;
+
+  accept_sock = socket (AF_INET, SOCK_STREAM, 0);
+
+  if (accept_sock < 0) 
+    {
+      zlog_warn ("Can't bind to socket: %s", strerror (errno));
+      zlog_warn ("zebra can't provice full functionality due to above error");
+      return;
+    }
+
+  memset (&addr, 0, sizeof (struct sockaddr_in));
+  addr.sin_family = AF_INET;
+  addr.sin_port = htons (ZEBRA_PORT);
+#ifdef HAVE_SIN_LEN
+  addr.sin_len = sizeof (struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+  addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+
+  sockopt_reuseaddr (accept_sock);
+  sockopt_reuseport (accept_sock);
+
+  ret  = bind (accept_sock, (struct sockaddr *)&addr, 
+	       sizeof (struct sockaddr_in));
+  if (ret < 0)
+    {
+      zlog_warn ("Can't bind to socket: %s", strerror (errno));
+      zlog_warn ("zebra can't provice full functionality due to above error");
+      close (accept_sock);      /* Avoid sd leak. */
+      return;
+    }
+
+  ret = listen (accept_sock, 1);
+  if (ret < 0)
+    {
+      zlog_warn ("Can't listen to socket: %s", strerror (errno));
+      zlog_warn ("zebra can't provice full functionality due to above error");
+      close (accept_sock);	/* Avoid sd leak. */
+      return;
+    }
+
+  zebra_event (ZEBRA_SERV, accept_sock, NULL);
+}
+
+/* For sockaddr_un. */
+#include <sys/un.h>
+
+/* zebra server UNIX domain socket. */
+void
+zebra_serv_un (char *path)
+{
+  int ret;
+  int sock, len;
+  struct sockaddr_un serv;
+  mode_t old_mask;
+
+  /* First of all, unlink existing socket */
+  unlink (path);
+
+  /* Set umask */
+  old_mask = umask (0077);
+
+  /* Make UNIX domain socket. */
+  sock = socket (AF_UNIX, SOCK_STREAM, 0);
+  if (sock < 0)
+    {
+      perror ("sock");
+      return;
+    }
+
+  /* Make server socket. */
+  memset (&serv, 0, sizeof (struct sockaddr_un));
+  serv.sun_family = AF_UNIX;
+  strncpy (serv.sun_path, path, strlen (path));
+#ifdef HAVE_SUN_LEN
+  len = serv.sun_len = SUN_LEN(&serv);
+#else
+  len = sizeof (serv.sun_family) + strlen (serv.sun_path);
+#endif /* HAVE_SUN_LEN */
+
+  ret = bind (sock, (struct sockaddr *) &serv, len);
+  if (ret < 0)
+    {
+      perror ("bind");
+      close (sock);
+      return;
+    }
+
+  ret = listen (sock, 5);
+  if (ret < 0)
+    {
+      perror ("listen");
+      close (sock);
+      return;
+    }
+
+  umask (old_mask);
+
+  zebra_event (ZEBRA_SERV, sock, NULL);
+}
+
+/* Zebra's event management function. */
+extern struct thread_master *master;
+
+void
+zebra_event (enum event event, int sock, struct zserv *client)
+{
+  switch (event)
+    {
+    case ZEBRA_SERV:
+      thread_add_read (master, zebra_accept, client, sock);
+      break;
+    case ZEBRA_READ:
+      client->t_read = 
+	thread_add_read (master, zebra_client_read, client, sock);
+      break;
+    case ZEBRA_WRITE:
+      /**/
+      break;
+    }
+}
+
+/* Display default rtm_table for all clients. */
+DEFUN (show_table,
+       show_table_cmd,
+       "show table",
+       SHOW_STR
+       "default routing table to use for all clients\n")
+{
+  vty_out (vty, "table %d%s", rtm_table_default,
+	   VTY_NEWLINE);
+  return CMD_SUCCESS;
+}
+
+DEFUN (config_table, 
+       config_table_cmd,
+       "table TABLENO",
+       "Configure target kernel routing table\n"
+       "TABLE integer\n")
+{
+  rtm_table_default = strtol (argv[0], (char**)0, 10);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_forwarding,
+       no_ip_forwarding_cmd,
+       "no ip forwarding",
+       NO_STR
+       IP_STR
+       "Turn off IP forwarding")
+{
+  int ret;
+
+  ret = ipforward ();
+
+  if (ret == 0)
+    {
+      vty_out (vty, "IP forwarding is already off%s", VTY_NEWLINE); 
+      return CMD_ERR_NOTHING_TODO;
+    }
+
+  ret = ipforward_off ();
+  if (ret != 0)
+    {
+      vty_out (vty, "Can't turn off IP forwarding%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return CMD_SUCCESS;
+}
+
+/* This command is for debugging purpose. */
+DEFUN (show_zebra_client,
+       show_zebra_client_cmd,
+       "show zebra client",
+       SHOW_STR
+       "Zebra information"
+       "Client information")
+{
+  listnode node;
+  struct zserv *client;
+
+  for (node = listhead (client_list); node; nextnode (node))
+    {
+      client = getdata (node);
+      vty_out (vty, "Client fd %d%s", client->sock, VTY_NEWLINE);
+    }
+  return CMD_SUCCESS;
+}
+
+/* Table configuration write function. */
+int
+config_write_table (struct vty *vty)
+{
+  if (rtm_table_default)
+    vty_out (vty, "table %d%s", rtm_table_default,
+	     VTY_NEWLINE);
+  return 0;
+}
+
+/* table node for routing tables. */
+struct cmd_node table_node =
+{
+  TABLE_NODE,
+  "",				/* This node has no interface. */
+  1
+};
+
+/* Only display ip forwarding is enabled or not. */
+DEFUN (show_ip_forwarding,
+       show_ip_forwarding_cmd,
+       "show ip forwarding",
+       SHOW_STR
+       IP_STR
+       "IP forwarding status\n")
+{
+  int ret;
+
+  ret = ipforward ();
+
+  if (ret == 0)
+    vty_out (vty, "IP forwarding is off%s", VTY_NEWLINE);
+  else
+    vty_out (vty, "IP forwarding is on%s", VTY_NEWLINE);
+  return CMD_SUCCESS;
+}
+
+#ifdef HAVE_IPV6
+/* Only display ipv6 forwarding is enabled or not. */
+DEFUN (show_ipv6_forwarding,
+       show_ipv6_forwarding_cmd,
+       "show ipv6 forwarding",
+       SHOW_STR
+       "IPv6 information\n"
+       "Forwarding status\n")
+{
+  int ret;
+
+  ret = ipforward_ipv6 ();
+
+  switch (ret)
+    {
+    case -1:
+      vty_out (vty, "ipv6 forwarding is unknown%s", VTY_NEWLINE);
+      break;
+    case 0:
+      vty_out (vty, "ipv6 forwarding is %s%s", "off", VTY_NEWLINE);
+      break;
+    case 1:
+      vty_out (vty, "ipv6 forwarding is %s%s", "on", VTY_NEWLINE);
+      break;
+    default:
+      vty_out (vty, "ipv6 forwarding is %s%s", "off", VTY_NEWLINE);
+      break;
+    }
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_forwarding,
+       no_ipv6_forwarding_cmd,
+       "no ipv6 forwarding",
+       NO_STR
+       IP_STR
+       "Doesn't forward IPv6 protocol packet")
+{
+  int ret;
+
+  ret = ipforward_ipv6_off ();
+  if (ret != 0)
+    {
+      vty_out (vty, "Can't turn off IPv6 forwarding%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return CMD_SUCCESS;
+}
+
+#endif /* HAVE_IPV6 */
+
+/* IPForwarding configuration write function. */
+int
+config_write_forwarding (struct vty *vty)
+{
+  if (! ipforward ())
+    vty_out (vty, "no ip forwarding%s", VTY_NEWLINE);
+#ifdef HAVE_IPV6
+  if (! ipforward_ipv6 ())
+    vty_out (vty, "no ipv6 forwarding%s", VTY_NEWLINE);
+#endif /* HAVE_IPV6 */
+  vty_out (vty, "!%s", VTY_NEWLINE);
+  return 0;
+}
+
+/* table node for routing tables. */
+struct cmd_node forwarding_node =
+{
+  FORWARDING_NODE,
+  "",				/* This node has no interface. */
+  1
+};
+
+
+/* Initialisation of zebra and installation of commands. */
+void
+zebra_init ()
+{
+  /* Client list init. */
+  client_list = list_new ();
+
+  /* Forwarding is on by default. */
+  ipforward_on ();
+#ifdef HAVE_IPV6
+  ipforward_ipv6_on ();
+#endif /* HAVE_IPV6 */
+
+  /* Make zebra server socket. */
+#ifdef HAVE_TCP_ZEBRA
+  zebra_serv ();
+#else
+  zebra_serv_un (ZEBRA_SERV_PATH);
+#endif /* HAVE_TCP_ZEBRA */
+
+  /* Install configuration write function. */
+  install_node (&table_node, config_write_table);
+  install_node (&forwarding_node, config_write_forwarding);
+
+  install_element (VIEW_NODE, &show_ip_forwarding_cmd);
+  install_element (ENABLE_NODE, &show_ip_forwarding_cmd);
+  install_element (CONFIG_NODE, &no_ip_forwarding_cmd);
+  install_element (ENABLE_NODE, &show_zebra_client_cmd);
+
+#ifdef HAVE_NETLINK
+  install_element (VIEW_NODE, &show_table_cmd);
+  install_element (ENABLE_NODE, &show_table_cmd);
+  install_element (CONFIG_NODE, &config_table_cmd);
+#endif /* HAVE_NETLINK */
+
+#ifdef HAVE_IPV6
+  install_element (VIEW_NODE, &show_ipv6_forwarding_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_forwarding_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_forwarding_cmd);
+#endif /* HAVE_IPV6 */
+}