Initial revision
diff --git a/zebra/.cvsignore b/zebra/.cvsignore
new file mode 100644
index 0000000..95401bf
--- /dev/null
+++ b/zebra/.cvsignore
@@ -0,0 +1,8 @@
+Makefile
+*.o
+zebra
+zebra.conf
+client
+tags
+TAGS
+.deps
diff --git a/zebra/ChangeLog b/zebra/ChangeLog
new file mode 100644
index 0000000..b5383f1
--- /dev/null
+++ b/zebra/ChangeLog
@@ -0,0 +1,1221 @@
+2002-09-28  Akihiro Mizutani <mizutani@net-chef.net>
+
+	* zebra_rib.c (static_add_ipv4): Null0 static route is added.
+
+2002-09-10  Jochen Friedrich <chris+zebra@scram.de>
+
+	* rt_netlink.c: Add check for EAGAIN.
+	* kernel_socket.c: Likewise
+
+2002-06-12  Israel Keys <ikeys@oz.agile.tv>
+
+	* rt_netlink.c: Setting the NLM_F_ACK flag on the netlink command
+	  message so that we get an ACK for successful netlink commands.
+	  Change the netlink socket to BLOCKING while we wait for a
+	  response; be it an ACK or an NLMSG_ERROR.  Change
+	  netlink_parse_info to deal with ACK messages.
+
+2001-11-01  Jun-ichiro itojun Hagino <itojun@iijlab.net>
+
+	* rtadv.c (rtadv_make_socket): setsockopt(IPV6_CHECKSUM) does not
+	work for ICMPv6 socket.
+
+2001-10-24  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+	* rib.c (rib_process): Select connected route any case.
+
+2001-10-23  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+	* interface.c (no_ip_address_secondary): Add "no" to command.
+
+2001-10-18  NOGUCHI Kay  <kay@v6.access.co.jp>
+
+	* ioctl.c (if_prefix_add_ipv6): Set the prefered and valid lifetime
+	to infinity as the freebsd4.4 workaroud.
+
+2001-08-26  mihail.balikov@interbgc.com
+
+	* zebra_snmp.c: Fix snmpwalk problem such as IPv4 address
+	A.B.C.255.
+
+2001-08-22  NOGUCHI Kay <kay@v6.access.co.jp>
+
+	* rtadv.c: Do not send RA to loopback interface.
+
+2001-08-20  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+	* ioctl.c (if_set_prefix): Remove Linux 2.0 specific connected
+	route treatment.
+
+2001-08-19  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+	* zebra-0.92a released.
+
+2001-08-17  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+	* rib.c: Kernel route is treated as EGP routes in nexthop active
+	check.
+
+2001-08-15  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+	* zebra-0.92 released.
+
+2001-08-08  "Akihiro Mizutani" <mizutani@dml.com>
+
+	* rib.c (show_ip_route_prefix_longer): Add longer-prefix option to
+	show route commands.
+
+2001-07-29  Yon Uriarte <havanna_moon@gmx.net>
+
+	* zserv.c (zsend_ipv4_add_multipath): Add
+	NEXTHOP_TYPE_IPV4_IFINDEX check.
+
+2001-07-29  NOGUCHI Kay <kay@v6.access.co.jp>
+
+	* rtadv.c: Apply valid lifetime, preferred lifetime, onilnk flag,
+	autonomous address-configuration flag patch.
+	(no_ipv6_nd_suppress_ra): Change "ipv6 nd send-ra" to "no ipv6 nd
+	suppress-ra".
+
+2001-07-24  NOGUCHI Kay <kay@v6.access.co.jp>
+
+	* rtadv.c (ipv6_nd_ra_interval): Add "ipv6 nd ra-interval SECONDS"
+	command.
+
+2001-07-24  Jun-ichiro itojun Hagino <itojun@iijlab.net>
+
+	* rt_socket.c (kernel_rtm_ipv4): Add KAME/NetBSD151 equal cost
+	multicast FIB support both IPv4 and IPv6.
+
+2001-07-24  Hal Snyder <hal@vailsys.com>
+
+	* if_ioctl.c (interface_list_ioctl): Fix bug of failing to get the
+	full list of interfaces on some configurations of OpenBSD.
+
+2001-07-23  NOGUCHI Kay <kay@v6.access.co.jp>
+
+	* rtadv.c (ipv6_nd_send_ra): Apply [zebra 9320] to fix "ipv6 nd
+	send-ra" bug.
+	(ipv6_nd_ra_lifetime): "ipv6 nd ra-lifetime 0" for default router
+	availability.
+	(ipv6_nd_managed_config_flag): "ipv6 nd managed-config-flag" is
+	added.
+	(ipv6_nd_other_config_flag): "ipv6 nd other-config-flag" is added.
+	
+2001-07-23  Jun-ichiro itojun Hagino <itojun@iijlab.net>
+
+	* ioctl.c (if_ioctl): Change ioctl argument from int to u_long.
+
+	* rt_ioctl.c: Likewise.
+
+2001-07-23  Jun-ichiro itojun Hagino <itojun@iijlab.net>
+
+	* kernel_socket.c (rtm_write): Only set RTF_CLONING when the
+	interface is not p2p.
+
+2001-04-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ioctl.c (if_prefix_add_ipv6): Fix argument type.
+
+2001-04-06  Toshiaki Takada  <takada@zebra.org>
+
+	* zserv.c (zsend_interface_delete): Use client->obuf instead of
+	allocating new stream.
+
+2001-03-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rt_netlink.c: Revert RTPROT_BOOT change.
+
+2001-03-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rt_netlink.c (netlink_route_change): Skip RTPROT_BOOT route.
+	(netlink_routing_table): Likewise.
+
+2001-03-07  "Akihiro Mizutani" <mizutani@dml.com>
+
+	* zserv.c (zsend_ipv4_add_multipath): Send metric value to
+	protocol daemons.
+
+2001-02-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rt_netlink.c (netlink_routing_table): Do not return
+	tb[RTA_GATEWAY] is NULL.  Reported by: "Michael O'Keefe"
+	<mokeefe@qualcomm.com>.
+
+2001-02-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* if_ioctl.c (interface_list_ioctl): Call if_add_update().
+	Suggested by: Chris Dunlop <chris@onthe.net.au>.
+
+2001-02-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rib.c (nexthop_active_ipv4): When nexthop type is
+	NEXTHOP_TYPE_IPV4_IFINDEX, propery set the ifindex to rifindex.
+
+	* zserv.c: Initialize rtm_table_default with 0.
+
+	* zebra-0.91 is released.
+
+2001-01-31  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* kernel_socket.c (rtm_read): Filter cloned route.  Suggested by:
+	Jun-ichiro itojun Hagino <itojun@iijlab.net>
+
+2001-01-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* connected.c (connected_up_ipv6): When point-to-point destination
+	address is ::, use local address for connected network.
+	(connected_down_ipv6): Likewise.
+
+2001-01-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zserv.c (zebra_serv): Add missing close() call.  Reported by:
+	David Waitzman <djw@vineyard.net>.
+
+2001-01-24  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rib.c (rib_lookup_ipv4): New function for checking exact match
+	IGP route.
+
+2001-01-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rib.c (show_ipv6_route_protocol): Fix bug of "show ip route
+	route-type".
+
+2001-01-22  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* interface.c (zebra_interface): Do not call
+	zebra_interface_add_update for inactive interface.
+
+	* zserv.c (zsend_interface_address_add): Send interface address
+	flag.
+	(zsend_interface_address_delete): Likewise.
+
+2001-01-19  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* interface.c (if_addr_add):  Add flags.
+
+	* connected.c (ifa_add_ipv4): Add new function for interface
+	address handling.
+	(ifa_delete_ipv4): Likewise.
+
+2001-01-16  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rib.c (rib_update): Update IPv6 RIB.
+
+	* kernel_socket.c (ifam_read): Call if_refresh() for update
+	interface flag status.  This is for implicit interface up on *BSD.
+
+	* interface.c (if_refresh): Add interface flag refresh function.
+
+	* kernel_socket.c (rtm_read): Fetch link-local address interface
+	index.
+	(ifan_read): We need to fetch interface information.  Suggested
+	by: Yasuhiro Ohara <yasu@sfc.wide.ad.jp>.
+
+	* rib.c (static_ipv6_nexthop_same): Add check for
+	NEXTHOP_TYPE_IPV6_IFNAME.
+
+2001-01-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rib.h (NEW_RIB): Turn on NEW_RIB flag.  IPv6 new RIB code are
+	taken into place.
+
+2001-01-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rib.c (static_ipv6_write): Display STATIC_IPV6_GATEWAY_IFNAME
+	configuration.
+	(rib_delete_ipv6): Handle same route conter for IPv6 connected
+	route.
+	(show_ipv6_route_protocol): New command.
+	(show_ipv6_route_addr): Likewise.
+	(show_ipv6_route_prefix): Likewise.
+	(rib_update): Sweep kernel route when it is cleaned up.
+
+	* rt_socket.c (kernel_add_ipv6): Add NEXTHOP_IPV6_IFNAME
+	treatmenet.
+
+	* rt_netlink.c (kernel_init): Likewise.
+
+	* rt_ioctl.c (kernel_ioctl_ipv6_multipath): Likewise.
+
+	* rib.c (rib_add_ipv4): Cope with same connected route on a
+	interface.  Suggested by: Matthew Grant <grantma@anathoth.gen.nz>.
+	(nexthop_ipv6_ifname_add): Add NEXTHOP_IPV6_IFNAME treatmenet.
+
+	* rib.h (struct new_rib): Add refcnt to keep track on the
+	reference of same connected route.
+
+	* ioctl.c (if_set_prefix): Add check for GNU_LINUX.
+
+2001-01-13  Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+	* kernel_socket.c (ifan_read, rtm_type_str): Add RTM_OIFINFO check.
+	(rtm_type_str): Add RTM_IFANNOUNCE check.
+	(ifan_read): New function.
+	(kernel_read): Add case for RTM_IFANNOUNCE.
+
+2001-01-13  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rt_ioctl.c (kernel_ioctl_ipv6_multipath): New function.
+
+	* rt_netlink.c (netlink_route_multipath): IPv6 address ifindex
+	treatment.
+
+	* connected.c (connected_up_ipv6): Add dest value check.
+
+	* rib.c (nexthop_active_ipv6): Do not touch IPv6 nexthop's
+	ifindex.
+	(rib_add_ipv4): Import rib_add_ipv6() same route check code.
+	(nexthop_active_check): NEXTHOP_TYPE_IPV6_IFINDEX activity is only
+	checked by ifindex.
+
+	* rt_socket.c (kernel_rtm_ipv6_multipath): New function.
+
+	* redistribute.c (redistribute_add): Use
+	zsend_ipv6_add_multipath().
+	(redistribute_delete_multipath): Use
+	zsend_ipv6_delete_multipath().
+
+	* interface.c (ip_address): Check current IP address to avoid
+	duplicate.
+
+	* rib.c (rib_delete_ipv4): When deleted route is connected route,
+	check ifindex.
+	(rib_add_ipv4): When connected route is added do not perform
+	implicit withdraw.
+	(rib_delete_ipv4): Check ifindex for connected route.
+
+	* kernel_socket.c (rtm_read): When route has RTF_STATIC, set
+	ZEBRA_FLAG_STATIC for indicate as persistent route.
+	(ifam_read): Unset interface index from link-local address when
+	IPv6 stack is KAME.
+
+	* rib.c (rib_update): Do not delete persistent kernel route.
+
+	* rib.h (struct new_rib): Integrate RIB_FLAG_* to ZEBRA_FLAG_*.
+
+	* rt_socket.c (kernel_add_ipv6_multipath): Add placeholder.
+	(kernel_delete_ipv6_multipath): Likewise.
+
+	* rt_netlink.c (netlink_talk): Give struct nlsock to netlink_talk.
+
+2001-01-12  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rib.c (rib_update): Revert Matthew Grant's patch
+	zebra_cvs_newribfix.patch.  Use struct rib->ifindex for kernel
+	interface index.  Introduce NEXTHOP_TYPE_IPV4_IFINDEX to support
+	that.  Add support for address deletion situation.
+
+2001-01-11  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* interface.c: Remove HAVE_IF_PSEUDO part.
+
+	* rib.h: Likewise.
+
+	* rt_netlink.c (netlink_link_change): Likewise.
+
+2001-01-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zserv.c: Remove OLD_RIB codes.
+
+2001-01-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zebra-0.90 is released.
+
+2001-01-09  Matthew Grant <grantma@anathoth.gen.nz>
+
+	* interface.c (if_new_intern_ifindex): Allocate a new internal
+	interface index.
+	(if_addr_refresh): Fix up ip addresses configured via zebra.
+	(if_add_update): Handle an interface addition.
+	(if_delete_update): Handle an interface delete event.
+
+	* rib.c (nexthop_ipv4_add): Add kernel route deletion process when
+	interface goes down.
+
+2001-01-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* interface.c (if_dump_vty): When HAVE_NET_RT_IFLIST is defined,
+	NetBSD also use this function.  Suggested by Jasper Wallace
+	<jasper@ivision.co.uk>.
+
+2001-01-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rib.c (nexthop_active_ipv4): Move back to set methodo to old
+	one.
+
+2001-01-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rib.c (rib_add_ipv4): EBGP multihop set ZEBRA_FLAG_INTERNAL
+	flag, so treat it.
+
+2001-01-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rt_netlink.c (netlink_talk_ipv6): When IPv6 route message is
+	sent from netlink_cmd, the same message comes from netlink.  To
+	avoid confusion, temporary netlink_talk_ipv6 use netlink.sock
+	instead of netlink_cmd.sock.
+
+2001-01-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zserv.h (ZEBRA_SERV_PATH): Change "/tmp/zebra" to "/tmp/.zebra".
+	Change "/tmp/zserv" to "/tmp/.zserv".
+	
+2000-12-29  Frank van Maarseveen <F.vanMaarseveen@inter.NL.net>
+
+	* rt_netlink.c (struct nlsock): Divide kernel message into listen
+	socket and command socket.
+	(netlink_talk): Remove socket listen code.  Use netlink_parse_info
+	for read kernel response.
+
+2000-12-29  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rib.c (vty_show_ip_route): Show uptime of the RIP,OSPF,BGP
+	routes.
+
+2000-12-27  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rt_netlink.c (netlink_route_multipath): Metric value is
+	reflected to kernel routing table.
+
+	* rt_ioctl.c (kernel_ioctl_ipv4_multipath): Likewise.
+
+	* kernel_socket.c (rtm_write): Likewise.
+
+	* rib.c (nexthop_active_ipv4): Only iBGP route perform recursive
+	nexthop lookup.
+
+	* rt_ioctl.c (kernel_ioctl_ipv4_multipath): Add ioctl version of
+	new RIB implementation.
+
+2000-12-26  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rib.h: Remove MULTIPATH_NUM.  It is defined by configure script.
+
+2000-12-25  Michael Rozhavsky <mrozhavsky@opticalaccess.com>
+
+	* rib.c (rib_if_up): Call rib_fib_set instead of RIB_FIB_SET for
+	proper redistribution.
+
+2000-12-19  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rib.c (nexthop_active_ipv4): Add self lookup nexthop check.
+	(show_ip_route_protocol): Support new RIB.
+
+	* rt_netlink.c (netlink_route_change): Do not return when gate is
+	NULL.
+
+2000-12-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rib.c (rib_lookup_ipv4_nexthop): IBGP nexthop check function is
+	updated.
+	(rib_add_ipv4): Free implicit withdraw route's RIB.
+
+2000-12-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rib.c (nexthop_active_ipv4): Check indirect nexthop.
+
+	* redistribute.c (redistribute_add_multipath): Redistribution
+	works with new rib code.
+
+2000-12-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rt_netlink.c (netlink_route_multipath): Check useful nexthop
+	number.
+	(netlink_route_multipath): Clear rtnh_flags and rtnh_hops.
+
+	* rib.c (nexthop_active_update): Set flag for the rib's nexthop
+	activity is changed.
+	(nexthop_active_check): Before checking interface is up, make it
+	sure the interface exist.
+
+2000-11-20  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rib.c (ip_route): New RIB prototype.
+
+2000-11-16  Yon Uriarte <ukl2@rz.uni-karlsruhe.de>
+
+	* zserv.c (zsend_interface_add): Send hardware address when
+	hw_addr_len is greater than 0.
+
+2000-11-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* connected.c (connected_up_ipv4): Fix ptop bug.  The destination
+	network should be installed into routing table.
+	(connected_down_ipv4): Likewise.
+	(connected_add_ipv4): Change to use connected_up_ipv4.
+	(connected_delete_ipv4): Likewise.
+
+2000-11-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rt_netlink.c (netlink_interface_addr): Revert Harald Welte
+	<laforge@gnumonks.org>'s ptop patch then back to original code to
+	avoid duplicated connected route problem.  Suggested by Frank van
+	Maarseveen <F.vanMaarseveen@inter.NL.net>.
+
+	* kernel_socket.c (rtm_read): Make behavior consistent even #ifdef
+	DEBUG is defined.  Reported by Jun-ichiro itojun Hagino
+	<itojun@iijlab.net>.
+
+2000-10-23  Jochen Friedrich <jochen@scram.de>
+
+	* main.c (main): Call zebra_snmp_init() when it is enabled.
+
+2000-10-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zserv.c (zebra_serv_un): UNIX domain socket server of zebra
+	protocol.
+
+2000-10-19  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rib.c (rib_add_ipv4): Same check bug is fixed.
+
+2000-10-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rib.c (rib_if_down): Remove kernel route when the interface goes
+	down.
+
+	* debug.c: New command "debug zebra kernel" is added.
+
+2000-10-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zebra-0.89 is released.
+
+2000-09-24  Harald Welte <laforge@gnumonks.org>
+
+	* rt_netlink.c (netlink_interface_addr): Fix point-to-point address
+	treatment in netlink interface.
+
+2000-09-21  David Lipovkov <dlipovkov@OpticalAccess.com>
+
+	* rib.c (rib_if_down): Pull static route only.  Protocol daemon
+	must withdraw routes when interface goes down.
+	(rib_add_ipv4): Check nexthop when replace route.
+
+2000-09-21  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* if_ioctl.c (if_getaddrs): New function for looking up
+	interface's address by getifaddrs().
+
+2000-09-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* connected.c (connected_delete_ipv4): Add check for connected
+	address is found or not.
+	(connected_add_ipv6): Reflect IPv6 connected address change to
+	protocol daemons.
+	(connected_delete_ipv6): Likewise.
+
+2000-09-07  David Lipovkov <davidl@nbase.co.il>
+
+	* rib.c (rib_delete_ipv4): Reverted the change from pseudo
+	interface patch to original.  Because ospfd deletes routes using
+	zero ifindex.
+
+2000-08-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zebra-0.88 is released.
+
+2000-08-15  "Akihiro Mizutani" <mizutani@dml.com>
+
+	* rib.c (show_ip_route_protocol): Help string correction.
+	(show_ip_route_prefix): Check prefix mask.
+	(show_ip_route_vty_detail): Display distance and metric.
+
+2000-08-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zserv.c (zsend_interface_add): Change ifindex store size from
+	two octet to four.
+	(zsend_interface_delete): Likewise.
+	(zsend_interface_address_add): Likewise.
+	(zsend_interface_address_delete): Likewise.
+	(zsend_interface_up): Likewise.
+	(zsend_interface_down): Likewise.
+
+2000-08-13  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rib.c (rib_add_ipv4): Do not install distance 255 route.
+
+2000-08-10  Toshiaki Takada  <takada@zebra.org>
+
+	* interface.c (bandwidth_if), (no_bandwidth_if):  Call
+	zebra_interface_up_update () instead of using if_up() and if_down().
+
+2000-08-07  "Akihiro Mizutani" <mizutani@dml.com>
+
+	* interface.c (bandwidth_if): Fix help string.
+
+2000-08-07  Matthew Grant <grantma@anathoth.gen.nz>
+
+	* interface.c (if_dump_vty): Display bandwidth value.
+	(bandwidth_if): New command "bandwidth <1-10000000>" is added.
+	When interface is up, force protocol daemons to recalculate routes
+	due to cost change.
+	(no_bandwidth_if): Likewise.
+	(if_config_write): Output bandwidth configuration.
+
+	* zserv.c (zsend_interface_add): Send bandwidth value.
+	(zsend_interface_up): Likewise.
+	(zsend_interface_down): Likewise.
+
+
+2000-08-07  Michael Rozhavsky <mike@nbase.co.il>
+
+	* rib.c (show_ip_route_protocol): "show ip route
+	(bgp|connected|kernel|ospf|rip|static)" is added.
+
+2000-08-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rib.c (rib_lookup_ipv4_nexthop): Check parent node until IGP
+	nexthop is found.
+	(rib_add_ipv4_internal): Set fib ifindex to rib ifindex.
+
+2000-08-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* redistribute.c (redistribute_delete): Fix bug of default route
+	redistribute treatment.
+
+2000-08-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rib.c (rib_init): Install ip_node in rib.c instead of zserv.c.
+	Change default distance value.
+
+                    Old         New
+	------------------------------------------
+	system      10           0
+	kernel      20           0
+	connected   30           0
+	static      40           1
+	rip         50         120
+	ripng       50         120
+	ospf        60         110
+	ospf6       49         110
+	bgp         70         200(iBGP)  20(eBGP)
+	------------------------------------------
+
+	* zserv.c (client_lookup): Function removed.
+	(zsend_interface_add): Use client's output buffer.  Check ifinfo
+	flag.
+	(zsend_interface_delete): Likewise.
+	Delete ipv4_static_radix and ipv6_static_radix.
+
+2000-08-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zserv.h (struct zebra_client): When client request interface
+	information, ifinfo is set.
+
+	* rib.c: Temporary Revert changes for pseudo interface.
+
+	* rib.h: Likewise.
+
+	* zserv.c: Likewise.
+
+	* interface.c: Likewise.
+	
+2000-08-02  David Lipovkov <davidl@nbase.co.il>
+
+	* interface.c (zebra_if_init): Install interface "pseudo"
+	commands.
+
+	* rib.c (rib_create): ifname argument is added.
+	(rib_add_ipv4_pseudo): New function is added.
+	(rib_delete_ipv4_pseudo): Likewise.
+
+	* rib.h : Delete INTERFACE_UNKNOWN definition.  Add prototype for
+	pseudo interface functions.
+
+	* rt_netlink.c (netlink_link_change): Check for pseudo interface.
+
+	* zserv.c (ip_route): When destination is pseudo interface, call
+	rib_add_ipv4_pseudo().
+
+	* zserv.c (no_ip_route): Trim "unknown" argument.
+
+2000-07-26  kunitake@dti.ad.jp
+
+	* if_ioctl.c (if_get_hwaddr): Fix hardware address length from 8
+	to 6.
+
+	* rtadv.c (rtadv_send_packet): Fix shift bug for hardware address.
+
+2000-07-24  Akihiro Mizutani <mizutani@dml.com>
+
+	* interface.c: Use install_default() for common VTY commands.
+
+2000-07-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* if_ioctl.c (interface_list_ioctl): A interface list size is
+	calculated from ifreq->if_addr.sa_len.  This is for OpenBSD.
+
+	* ioctl.c (if_get_mtu): Remove codes for SIOCGIFDATA.
+
+2000-07-09  Chris Dunlop <chris@onthe.net.au>
+
+	* if_ioctl.c (if_get_index): Add check for HAVE_BROKEN_ALIASES.
+
+2000-07-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zserv.c (zebra_client_read): Add ZEBRA_REDISTRIBUTE_{ADD,DELETE}
+	message handling.
+
+2000-07-02  David Lipovkov <davidl@nbase.co.il>
+
+	* zserv.c: "ip route A.B.C.D/M unknown" command is added.
+
+2000-06-28  Michael Rozhavsky <mike@nbase.co.il>
+
+	* rib.c: Remove old kernel route when new route comes in.
+
+2000-06-13  David Lipovkov <davidl@nbase.co.il>
+
+	* rib.c (rib_if_up): Add check for unknown interface.
+
+2000-06-13 Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rib.h: Define INTERFACE_UNKNOWN.
+
+2000-06-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* Makefile.am (EXTRA_DIST): Move irdp.c until implementation is
+	finished.
+
+2000-06-05  David Lipovkov <davidl@nbase.co.il>
+
+	* interface.c (if_zebra_delete_hook): Call rib_if_delete().
+
+	* redistribute.c (zebra_interface_delete_update): New function.
+
+	* redistribute.h (zebra_interface_delete_update): New function
+	prototype.
+
+	* rib.c (rib_if_delete): New function.  Walk down all routes and
+	delete all on the interface.
+
+	* rib.h: New function prototype.
+
+	* rt_netlink.c (netlink_link_change): Call
+	zebra_interface_delete_update ().
+
+2000-05-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* if_ioctl.c (interface_info_ioctl): Check interface's flag before
+	checking interface's address.
+
+2000-04-26  Jochen Friedrich <jochen@nwe.de>
+
+	* GNOME-PRODUCT-ZEBRA-MIB: New file.
+
+	* GNOME-SMI: New file.
+
+2000-04-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* irdp.c: New file from 1997 development code.
+	* irdp.h: Likewise.
+
+2000-04-19  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rtadv.c (rtadv_send_packet): Enclose router advertisement
+	logging with IS_ZEBRA_DEBUG_PACKET.
+
+2000-04-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zserv.c (zebra_client_close): Remove client structure from
+	client_list when connection is terminated.
+
+2000-03-21  David Lipovkov <davidl@nbase.co.il>
+
+	* connected.c (connected_add_ipv4): Allows all necessary structure
+	updates for connected route, but doesn't insert it into rib if
+	it's interface is down.
+
+2000-01-21  Hideto Yamakawa <hideto.yamakawa@soliton.co.jp>
+
+	* rtread_getmsg.c: Set some definition for Solaris 2.5 and Solaris
+	2.5.1.
+
+2000-01-21  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rib.c (no_ipv6_route_ifname): Fix buf of cheking return value
+	from str2prefix_ipv6().
+
+2000-01-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rt_socket.c: Revert to use RTF_HOST for IPv4 with /32 route and
+	IPv6 with /128 routes.
+	(kernel_rtm_ipv4): In case of /32 route's gateway is interface. It
+	should have mask for cloning.
+
+1999-12-26  Jochen.Friedrich@genorz.de
+
+	* interface.c (if_dump_vty): Fix a bug of missing VTY_NEWLINE.
+
+1999-12-23  Alex Zinin <zinin@amt.ru>
+	* interface.*: dynamic int up/down support
+
+1999-12-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ipforward_proc.c (dropline): Move dropline() from lib/dropline.c
+
+	* rtread_proc.c (proc_route_read): Don't use dropline().
+
+1999-12-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* kernel_socket.c (rtm_read): When message is RTM_GET, it has own
+	process's pid.
+
+1999-12-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* main.c (main): Change to default log output to ZLOG_STDOUT.
+
+	* zserv.c (zebra_serv): More detailed error print.
+
+1999-11-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* kernel_socket.c (rtm_read): Check old pid for static route
+	insertion check.
+
+1999-11-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* interface.c (if_dump_vty): BSDI/OS uses 64bit for interface
+	statistics counter.
+
+	* mtu_kvm.c: New file added.
+
+1999-11-27  Vladimir B. Grebenschikov <vova@express.ru>
+
+	* kernel_socket.c (rtm_write): Set RTF_CLONING flag for
+	route to the directly connected interface.
+
+1999-11-27  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rt_socket.c: Delete USE_HOST_BIT definition.
+
+1999-11-21  Michael Handler <handler@sub-rosa.com>
+
+	* rtread_getmsg.c: Undef some definition to resolve conflict.
+
+1999-11-27  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* kernel_socket.c (rtm_write): Change to use pre stored struct_dl
+	value for gateway specification.
+
+1999-11-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rt_socket.c (kernel_rtm_ipv4): Even mask is 32 under IPv4 or
+	128 under IPv6, don't use RTF_HOST.
+
+1999-11-21  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* Makefile.am (EXTRA_DIST): Add rtread_getmsg.c.
+
+1999-11-21  Michael Handler <handler@sub-rosa.com>
+
+	* rtread_getmsg.c: Added for Solaris 2.6 support.
+
+1999-11-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rtread_sysctl.c (rtm_read_route): RTM_DELETE handling added.
+
+	* rt_socket.c (kernel_read): Better BSD routing socket support.
+
+1999-10-19  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* client_main.c: Disable making obsolete zebra test `client'
+	command.
+
+1999-10-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zebra.c: Renamed to zserv.c.
+
+	* zebra.h: Global definitions are moved to lib/zebra.h.  Then
+	renamed to zserv.h.
+
+1999-10-15  Jordan Mendelson <jordy@wserv.com>
+
+	* if_ioctl.c: Add Linux 2.2.X's alias support and dynamic
+	interface.  Remove ugly MAX_INTERFACE handling codes.
+
+1999-09-17  Satosi KOBAYASI <kobayasi@north.ad.jp>
+
+	* Fix serious bug of IPv6 route deletion.
+
+1999-09-11  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ioctl.c (if_set_prefix): Properly set broadcast address.
+
+1999-09-04  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* rib.c (rib_add_ipv6, rib_delete_ipv6): now protocol daemons
+	can install connected route to kernel via zebra
+
+1999-08-24  VOP <vop@unity.net>
+
+	* rib.c: Include "sockunion.h"
+
+1999-08-22  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ipforward.h: New file.
+
+	* zebra.h: Obsolete message ZEBRA_GET_ALL_INTERFACE,
+	ZEBRA_GET_ONE_INTERFACE, ZEBRA_GET_HOSTINFO are deleted.
+
+1999-08-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zebra.h (ZEBRA_INTERFACE_ADDRESS_ADD):
+	ZEBRA_INTERFACE_{ADD,DELETE} added.
+
+1999-08-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rib.c: show ip route A.B.C.D works.
+
+	* zebra.c (zebra_read_ipv4): Add ifindex to zebra messages.
+
+1999-08-12  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zebra.h: New Zebra message ZEBRA_INTERFACE_{ADD,DELETE} added.
+
+1999-08-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* interface.h: New file.
+	* Makefile.am: Add interface.h
+
+1999-08-04  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* redistribute.c (zebra_redistribute): give ifindex to client.
+
+1999-08-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* main.c (longopts): -k, --keep_kernel option added.
+
+1999-07-18  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* rt_socket.c (rtm_write): forgot closing socket bug fixed.
+
+1999-07-17  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* rib.c (show_ipv6_cmd): if rib is link show interface name.
+
+1999-07-17  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* rt_socket.c (rtm_write): use sockaddr_dl when null gateway.
+
+1999-07-16  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* rt_socket.c (rtm_write): ipv6 route table bug fixed.
+
+1999-07-15  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* zebra.c (zebra_read_ipv6): read link prefix from ospf6 support
+
+1999-07-15  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* rt_socket.c (kernel_rtm_ipv6): gate treatment bug fixed.
+
+1999-07-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* if_sysctl.c (ifm_read): Clear sockunion argument before fetching
+	data.  Suggested by "Chris P. Ross" <cross@eng.us.uu.net>
+
+1999-07-08  HEO SeonMeyong <seirios@Matrix.IRI.Co.Jp>
+
+	* interface.c (if_tun_add): Add KAME's gif tunnel setting codes.
+
+1999-06-26  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zebra.c (zebra_serv): Only accept loopback address connection.
+
+1999-06-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zebra.h (ZEBRA_ROUTE_EXTERNAL): Add zebra messages flags
+
+1999-06-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ipforward_proc.c: ipforward_on () and ipforward_off () added.
+
+1999-06-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ipforward_proc.c (ipforward_ipv6): Check for IPv6 forwarding
+	using /proc file system is added.
+
+1999-06-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* if_ioctl.c (if_get_index): Interface index set bug is fixed by
+	adding #else at the middle of function.  Suggested by David Luyer
+	<luyer@ucs.uwa.edu.au>.
+
+1999-05-29    <kunihiro@zebra.org>
+
+	* rt_ioctl.c: Comment out #include <linux/ipv6_route.h>.
+
+1999-05-26  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zebra.h (ZEBRA_ROUTE_MAX): Add new define for the max value of
+	the sort of routes.
+
+1999-05-25  Patrick Koppen <koppen@rhrk.uni-kl.de>
+
+	* rt_netlink.c (netlink_socket): Make netlink socket non-blocking.
+	(netlink_parse_info): If errno is EWOULDBLOCK then continue to
+	parse the message.
+	(netlink_talk): Likewise
+	
+1999-05-17    <kunihiro@zebra.org>
+
+	* redistribute.c (zebra_check_addr): Added for loopback address
+	check.
+
+1999-05-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rt_netlink.c (netlink_route_change): Tempolary bypass ipv6 route
+	change treatment.
+
+	* Makefile.am (noinst_HEADERS): redistribute.h added.
+
+	* redistribute.h: New file.
+
+1999-05-14  Stephen R. van den Berg <srb@cuci.nl>
+
+	* zebra.c (show_table): Show all table configuration DEFUN.
+	(config_table): Config table number DEFUN.
+
+	* rt_netlink.c: Add support for multiple routing table.
+
+	* rib.c (rib_weed_table): New function added for delete all
+	routes from specified routing table.
+
+	* main.c (signal_init): SIGTERM call sigint.
+	(sigint): Loggging more better message.
+
+1999-05-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rt_netlink.c: Change log () to zlog ().
+
+1999-05-07    <kunihiro@zebra.org>
+
+	* zebra.h (ZEBRA_ROUTE_OSPF6): Added for ospf6d route.
+
+1999-04-20  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* interface.c: Add `no ip address' command.
+
+1999-04-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rt_netlink.c (kernel_read): Function added for asynchronous
+	zebra between kernel communication.
+
+1999-03-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rtread_sysctl.c (rtm_read): Fix address memcopy overrun bug.
+	Reported by Achim Patzner <ap@bnc.net>.
+
+1999-03-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* Makefile.am: Install configuration sample with 600 permission.
+
+1999-03-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* Makefile.am: Add -I.. to INCLUDES.
+
+1999-02-18  Peter Galbavy  <Peter.Galbavy@knowledge.com>
+
+	* syslog support added
+
+1999-02-17 Peter Galbavy <Peter.Galbavy@knowledge.com>
+
+	* if_sysctl.c (interface_list): allocated memory free when unknown
+	ifm_type is returned.
+
+	* ioctl.c (if_get_mtu): added SIOCGIFDATA treatment.
+	
+1998-12-15  Magnus Ahltorp <map@stacken.kth.se>
+
+	* interface.c: Header include added.
+
+1998-12-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rt.h (kernel_delete_ipv6): change int index to unsigned int index.
+
+1998-12-13  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* if_ioctl.c (interface_list_ioctl): interface flag must be
+	checked before check addresses of the interface.
+
+1998-12-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* Makefile.am (INCLUDES): add @INCLUDES@ for Linux IPv6.
+
+1998-10-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ioctl.c: Linux version before 2.1.0 need interface route setup.
+
+1998-09-15  HEO SeonMeyong  <seirios@matrix.iri.co.jp>
+
+	* change HYDRANGEA to KAME
+
+1998-09-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* if_ioctl.c (if_addr_ioctl): set address family for getting
+	interface's address.
+	(if_get_index): silently return when can't get interface's index.
+
+1998-08-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* main.c (main): batch mode option '-b' added.
+
+1998-08-16  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ioctl.c (if_set_prefix): add `ip address IPV4ADDR' command.
+	* interface.c (shutdown_if): add interface shutdown and no
+	shutdown command.
+
+1998-08-12  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rib.c (rib_add_ipv6): delete rib_add_in6.
+
+1998-07-27  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* main.c: retain flag is added.
+
+1998-07-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rtable.[ch]: merged with rib.[ch]
+
+1998-07-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* connected.h: renamed from ifa.h.
+
+1998-06-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rename if.c to interface.c
+	* rename ifa.c to connected.c
+
+	* Porting to Debian GNU/Linux 2.0 (hamm).
+
+1998-06-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rt_netlink.c: renamed from krt_netlink.c
+	
+	* fib.c: deleted.
+	* rt_kvm.c: deleted.
+	* rtread_getmsg.c: deleted.
+
+1998-06-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* if.c (multicast): add multicast flag [un]set fucntion.
+
+1998-05-19  Yamshita TAKAO  <jargon@lares.dti.ne.jp>
+
+	* rt_socket.c: Modify for compile on Solaris, but dont't work it.
+	  rt_socket.c have some undefined function, so add directive "IMPLEMENT"
+
+1998-05-18  Yamshita TAKAO  <jargon@lares.dti.ne.jp>
+
+	* zebra.c: Modify for compile on Solaris.
+
+1998-05-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* main.c: change CONFDIR to SYSCONFDIR.
+
+1998-05-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* .cvsignore: added.
+
+1998-04-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* client.c: moves to ../lib.
+
+1998-03-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* if_ioctl.c (if_get_addr): Change address copy from memcopy() to
+	structure assignment.
+
+1998-03-30  URA Hiroshi <ura@yamato.ibm.co.jp>
+
+	* if_sysctl.c (ifm_interface_add): sdl->sdl_data copy bug fixed.
+
+1998-02-23  "Hannes R. Boehm" <hannes@boehm.org>
+
+	* if.c (if_init): add config_exit_cmd and config_help_cmd.
+
+1998-01-24  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rt_ioctl.c (route_ioctl): EPERM treatment added.
+
+1998-01-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rt_socket.c (kernel_read): communication port zebra between
+	kernel is now handled by kernel_read.
+
+1998-01-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* main.c (main): zebra [-P port] can specify vty port number.
+
+1997-12-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zebra.c: change select will be block.
+
+1997-12-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* add static route treatment.
+
+1997-11-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rt_netlink.c: add netlink support over GNU/Linux system.
+
+1997-11-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* all inet_addr is changed to inet_aton.
+
+	* zebra.c (ip_route): add ip route command for static routes.
+
+1997-11-20  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* if.c (if_flag_dump): Linux port of if_flag_dump and _vty.
+
+1997-11-19  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* if.c: add interface command.
+
+1997-11-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ipforward_proc.c : Now works on Linux.
+
+1997-10-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.c : add completion feature.
+
+1997-10-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* vty.c (vty_command): add vty interface.
+
+1997-10-13  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zebra.c: add verbose mode.
+
+1997-10-12 SonMyong Ho <s-ho@Matrix.IRI.Co.Jp>
+
+	* Hydrangea for FreeBSD supported
+	* in.h: add some prototype.
+
+1997-10-11  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rt_socket.c and rtread.c completely rewritten.
+
+1997-10-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rt_socket.c: rename kernel_sock to routing_socket
+
+1997-10-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* if.c (if_new): interface structure change from linklist to vector.
+
+1997-10-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* vector.c (vector_init): create vector related function
+
+1997-09-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* Makefile.in: add tags target
+
+	* start IPv6 support for INRIA FreeBSD.
+
diff --git a/zebra/GNOME-PRODUCT-ZEBRA-MIB b/zebra/GNOME-PRODUCT-ZEBRA-MIB
new file mode 100644
index 0000000..96bcec5
--- /dev/null
+++ b/zebra/GNOME-PRODUCT-ZEBRA-MIB
@@ -0,0 +1,78 @@
+GNOME-PRODUCT-ZEBRA-MIB DEFINITIONS ::= BEGIN

+

+IMPORTS

+	MODULE-IDENTITY,

+	OBJECT-IDENTITY

+		FROM SNMPv2-SMI

+	gnomeProducts

+		FROM GNOME-SMI;

+

+zebra MODULE-IDENTITY

+	LAST-UPDATED "200004250000Z"

+	ORGANIZATION "GNOME project"

+	CONTACT-INFO

+		"GNU Network Object Model Environment project

+		

+		see http://www.gnome.org for contact persons of a particular

+		area or subproject of GNOME.

+

+		Administrative contact for MIB module:

+

+		Jochen Friedrich

+		Wingertstr. 70/1

+		68809 Neulussheim

+		Germany 

+

+		email: snmp@gnome.org"

+	DESCRIPTION

+		"The product registrations for the various zebra subdeamons.

+		These registrations are guaranteed to be unique and are used

+		for SMUX registration by default (if not overridden manually)."

+	::= { gnomeProducts 2 }

+

+zserv OBJECT-IDENTITY

+	STATUS  current

+	DESCRIPTION

+		"zserv is part of the zebra project which again is a GNU

+		endorsed internet routing program.

+		zserv is the main zebra process which implements routing

+		entries with the kernel and handles routing updates between

+		other routing protocols."

+	::= { zebra 1 }

+

+bgpd OBJECT-IDENTITY

+	STATUS  current

+	DESCRIPTION

+		"bgpd is part of the zebra project which again is a GNU

+		endorsed internet routing program."

+	::= { zebra 2 }

+

+ripd OBJECT-IDENTITY

+	STATUS  current

+	DESCRIPTION

+		"ripd is part of the zebra project which again is a GNU

+		endorsed internet routing program."

+	::= { zebra 3 }

+

+ripngd OBJECT-IDENTITY

+	STATUS  current

+	DESCRIPTION

+		"ripngd is part of the zebra project which again is a GNU

+		endorsed internet routing program."

+	::= { zebra 4 }

+

+ospfd OBJECT-IDENTITY

+	STATUS  current

+	DESCRIPTION

+		"ospfd is part of the zebra project which again is a GNU

+		endorsed internet routing program."

+	::= { zebra 5 }

+

+ospf6d OBJECT-IDENTITY

+	STATUS  current

+	DESCRIPTION

+		"ospf6d is part of the zebra project which again is a GNU

+		endorsed internet routing program."

+	::= { zebra 6 }

+

+END

diff --git a/zebra/GNOME-SMI b/zebra/GNOME-SMI
new file mode 100644
index 0000000..164732b
--- /dev/null
+++ b/zebra/GNOME-SMI
@@ -0,0 +1,53 @@
+GNOME-SMI DEFINITIONS ::= BEGIN

+

+IMPORTS

+	MODULE-IDENTITY,

+	OBJECT-IDENTITY,

+	enterprises

+		FROM SNMPv2-SMI;

+

+gnome MODULE-IDENTITY

+	LAST-UPDATED "9809010000Z"

+	ORGANIZATION "GNOME project"

+	CONTACT-INFO

+		"GNU Network Object Model Environment project

+		

+		see http://www.gnome.org for contact persons of a particular

+		area or subproject of GNOME.

+

+		Administrative contact for MIB module:

+

+		Jochen Friedrich

+		Wingertstr. 70/1

+		68809 Neulussheim

+		Germany 

+

+		email: snmp@gnome.org"

+	DESCRIPTION

+		"The Structure of GNOME."

+	::= { enterprises 3317 }	-- assigned by IANA

+

+gnomeProducts OBJECT-IDENTITY

+	STATUS	current

+	DESCRIPTION

+		"gnomeProducts is the root OBJECT IDENTIFIER from

+		which sysObjectID values are assigned."

+	::= { gnome 1 }

+

+gnomeMgmt OBJECT-IDENTITY

+	STATUS  current

+	DESCRIPTION

+		"gnomeMgmt defines the subtree for production GNOME related

+		MIB registrations."

+	::= { gnome 2 }

+

+gnomeTest OBJECT-IDENTITY

+	STATUS  current

+	DESCRIPTION

+		"gnomeTest defines the subtree for testing GNOME related

+		MIB registrations."

+	::= { gnome 3 }

+

+-- more to come if necessary.

+

+END

diff --git a/zebra/Makefile.am b/zebra/Makefile.am
new file mode 100644
index 0000000..6214767
--- /dev/null
+++ b/zebra/Makefile.am
@@ -0,0 +1,57 @@
+## Process this file with automake to produce Makefile.in.
+
+INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib
+DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -DMULTIPATH_NUM=@MULTIPATH_NUM@
+INSTALL_SDATA=@INSTALL@ -m 600
+
+LIB_IPV6 = @LIB_IPV6@
+
+ipforward = @IPFORWARD@
+if_method = @IF_METHOD@
+if_proc = @IF_PROC@
+rt_method = @RT_METHOD@
+rtread_method = @RTREAD_METHOD@
+kernel_method = @KERNEL_METHOD@
+other_method = @OTHER_METHOD@
+
+otherobj = $(ipforward) $(if_method) $(if_proc) $(rt_method) \
+	$(rtread_method) $(kernel_method) $(other_method)
+
+sbin_PROGRAMS = zebra
+
+zebra_SOURCES = \
+	zserv.c main.c interface.c connected.c ioctl.c zebra_rib.c \
+	redistribute.c debug.c rtadv.c zebra_snmp.c zebra_vty.c
+
+noinst_HEADERS = \
+	connected.h ioctl.h rib.h rt.h zserv.h redistribute.h debug.h rtadv.h \
+	interface.h ipforward.h irdp.h
+
+zebra_LDADD = ../lib/libzebra.a $(otherobj) $(LIB_IPV6)
+
+zebra_DEPENDENCIES = $(otherobj)
+
+sysconf_DATA = zebra.conf.sample
+
+EXTRA_DIST = $(sysconf_DATA) if_ioctl.c if_netlink.c if_proc.c if_sysctl.c \
+	ipforward_aix.c ipforward_ews.c ipforward_proc.c \
+	ipforward_solaris.c ipforward_sysctl.c rt_ioctl.c rt_netlink.c \
+	rt_socket.c rtread_netlink.c rtread_proc.c rtread_sysctl.c \
+	rtread_getmsg.c kernel_socket.c kernel_netlink.c mtu_kvm.c \
+	GNOME-SMI GNOME-PRODUCT-ZEBRA-MIB irdp.c
+
+#client : client_main.o ../lib/libzebra.a
+#	$(CC) -g -o client client_main.o ../lib/libzebra.a $(LIBS) $(LIB_IPV6)
+
+install-sysconfDATA: $(sysconf_DATA)
+	@$(NORMAL_INSTALL)
+	$(mkinstalldirs) $(DESTDIR)$(sysconfdir)
+	@list='$(sysconf_DATA)'; for p in $$list; do \
+	  if test -f $(srcdir)/$$p; then \
+	    echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \
+	    $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \
+	  else if test -f $$p; then \
+	    echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \
+	    $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \
+	  fi; fi; \
+	done
diff --git a/zebra/Makefile.in b/zebra/Makefile.in
new file mode 100644
index 0000000..ad35b38
--- /dev/null
+++ b/zebra/Makefile.in
@@ -0,0 +1,493 @@
+# Makefile.in generated by automake 1.7 from Makefile.am.
+# @configure_input@
+
+# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
+# Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_triplet = @host@
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BGPD = @BGPD@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CURSES = @CURSES@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -DMULTIPATH_NUM=@MULTIPATH_NUM@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+IF_METHOD = @IF_METHOD@
+IF_PROC = @IF_PROC@
+
+INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPFORWARD = @IPFORWARD@
+KERNEL_METHOD = @KERNEL_METHOD@
+LDFLAGS = @LDFLAGS@
+LIBPAM = @LIBPAM@
+LIBS = @LIBS@
+
+LIB_IPV6 = @LIB_IPV6@
+LIB_REGEX = @LIB_REGEX@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MULTIPATH_NUM = @MULTIPATH_NUM@
+OBJEXT = @OBJEXT@
+OSPF6D = @OSPF6D@
+OSPFD = @OSPFD@
+OTHER_METHOD = @OTHER_METHOD@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+RIPD = @RIPD@
+RIPNGD = @RIPNGD@
+RTREAD_METHOD = @RTREAD_METHOD@
+RT_METHOD = @RT_METHOD@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+VTYSH = @VTYSH@
+ZEBRA = @ZEBRA@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__include = @am__include@
+am__quote = @am__quote@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+INSTALL_SDATA = @INSTALL@ -m 600
+
+ipforward = @IPFORWARD@
+if_method = @IF_METHOD@
+if_proc = @IF_PROC@
+rt_method = @RT_METHOD@
+rtread_method = @RTREAD_METHOD@
+kernel_method = @KERNEL_METHOD@
+other_method = @OTHER_METHOD@
+
+otherobj = $(ipforward) $(if_method) $(if_proc) $(rt_method) \
+	$(rtread_method) $(kernel_method) $(other_method)
+
+
+sbin_PROGRAMS = zebra
+
+zebra_SOURCES = \
+	zserv.c main.c interface.c connected.c ioctl.c zebra_rib.c \
+	redistribute.c debug.c rtadv.c zebra_snmp.c zebra_vty.c
+
+
+noinst_HEADERS = \
+	connected.h ioctl.h rib.h rt.h zserv.h redistribute.h debug.h rtadv.h \
+	interface.h ipforward.h irdp.h
+
+
+zebra_LDADD = ../lib/libzebra.a $(otherobj) $(LIB_IPV6)
+
+zebra_DEPENDENCIES = $(otherobj)
+
+sysconf_DATA = zebra.conf.sample
+
+EXTRA_DIST = $(sysconf_DATA) if_ioctl.c if_netlink.c if_proc.c if_sysctl.c \
+	ipforward_aix.c ipforward_ews.c ipforward_proc.c \
+	ipforward_solaris.c ipforward_sysctl.c rt_ioctl.c rt_netlink.c \
+	rt_socket.c rtread_netlink.c rtread_proc.c rtread_sysctl.c \
+	rtread_getmsg.c kernel_socket.c kernel_netlink.c mtu_kvm.c \
+	GNOME-SMI GNOME-PRODUCT-ZEBRA-MIB irdp.c
+
+subdir = zebra
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+sbin_PROGRAMS = zebra$(EXEEXT)
+PROGRAMS = $(sbin_PROGRAMS)
+
+am_zebra_OBJECTS = zserv.$(OBJEXT) main.$(OBJEXT) interface.$(OBJEXT) \
+	connected.$(OBJEXT) ioctl.$(OBJEXT) zebra_rib.$(OBJEXT) \
+	redistribute.$(OBJEXT) debug.$(OBJEXT) rtadv.$(OBJEXT) \
+	zebra_snmp.$(OBJEXT) zebra_vty.$(OBJEXT)
+zebra_OBJECTS = $(am_zebra_OBJECTS)
+zebra_LDFLAGS =
+
+DEFAULT_INCLUDES =  -I. -I$(srcdir) -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/connected.Po ./$(DEPDIR)/debug.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/interface.Po ./$(DEPDIR)/ioctl.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/main.Po ./$(DEPDIR)/redistribute.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/rtadv.Po ./$(DEPDIR)/zebra_rib.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/zebra_snmp.Po ./$(DEPDIR)/zebra_vty.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/zserv.Po
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+DIST_SOURCES = $(zebra_SOURCES)
+DATA = $(sysconf_DATA)
+
+HEADERS = $(noinst_HEADERS)
+
+DIST_COMMON = $(noinst_HEADERS) ChangeLog Makefile.am Makefile.in
+SOURCES = $(zebra_SOURCES)
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .o .obj
+$(srcdir)/Makefile.in:  Makefile.am  $(top_srcdir)/configure.in $(ACLOCAL_M4)
+	cd $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign  zebra/Makefile
+Makefile:  $(srcdir)/Makefile.in  $(top_builddir)/config.status
+	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)
+sbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+install-sbinPROGRAMS: $(sbin_PROGRAMS)
+	@$(NORMAL_INSTALL)
+	$(mkinstalldirs) $(DESTDIR)$(sbindir)
+	@list='$(sbin_PROGRAMS)'; for p in $$list; do \
+	  p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+	  if test -f $$p \
+	  ; then \
+	    f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+	   echo " $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f"; \
+	   $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f || exit 1; \
+	  else :; fi; \
+	done
+
+uninstall-sbinPROGRAMS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(sbin_PROGRAMS)'; for p in $$list; do \
+	  f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+	  echo " rm -f $(DESTDIR)$(sbindir)/$$f"; \
+	  rm -f $(DESTDIR)$(sbindir)/$$f; \
+	done
+
+clean-sbinPROGRAMS:
+	-test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS)
+zebra$(EXEEXT): $(zebra_OBJECTS) $(zebra_DEPENDENCIES) 
+	@rm -f zebra$(EXEEXT)
+	$(LINK) $(zebra_LDFLAGS) $(zebra_OBJECTS) $(zebra_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT) core *.core
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/connected.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/debug.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/interface.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ioctl.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/redistribute.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtadv.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zebra_rib.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zebra_snmp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zebra_vty.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zserv.Po@am__quote@
+
+distclean-depend:
+	-rm -rf ./$(DEPDIR)
+
+.c.o:
+@am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \
+@am__fastdepCC_TRUE@	  -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \
+@am__fastdepCC_TRUE@	then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \
+@am__fastdepCC_TRUE@	else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \
+@am__fastdepCC_TRUE@	fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$<
+
+.c.obj:
+@am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \
+@am__fastdepCC_TRUE@	  -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'`; \
+@am__fastdepCC_TRUE@	then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \
+@am__fastdepCC_TRUE@	else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \
+@am__fastdepCC_TRUE@	fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'`
+uninstall-info-am:
+sysconfDATA_INSTALL = $(INSTALL_DATA)
+
+uninstall-sysconfDATA:
+	@$(NORMAL_UNINSTALL)
+	@list='$(sysconf_DATA)'; for p in $$list; do \
+	  f="`echo $$p | sed -e 's|^.*/||'`"; \
+	  echo " rm -f $(DESTDIR)$(sysconfdir)/$$f"; \
+	  rm -f $(DESTDIR)$(sysconfdir)/$$f; \
+	done
+
+ETAGS = etags
+ETAGSFLAGS =
+
+CTAGS = ctags
+CTAGSFLAGS =
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	mkid -fID $$unique
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(ETAGS_ARGS)$$tags$$unique" \
+	  || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	     $$tags $$unique
+
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(CTAGS_ARGS)$$tags$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$tags $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && cd $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+
+top_distdir = ..
+distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+	list='$(DISTFILES)'; for file in $$list; do \
+	  case $$file in \
+	    $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+	  esac; \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+	  if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+	    dir="/$$dir"; \
+	    $(mkinstalldirs) "$(distdir)$$dir"; \
+	  else \
+	    dir=''; \
+	  fi; \
+	  if test -d $$d/$$file; then \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    fi; \
+	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || cp -p $$d/$$file $(distdir)/$$file \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS) $(DATA) $(HEADERS)
+
+installdirs:
+	$(mkinstalldirs) $(DESTDIR)$(sbindir) $(DESTDIR)$(sysconfdir)
+
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-rm -f Makefile $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-sbinPROGRAMS mostlyclean-am
+
+distclean: distclean-am
+
+distclean-am: clean-am distclean-compile distclean-depend \
+	distclean-generic distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am: install-sbinPROGRAMS install-sysconfDATA
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-sbinPROGRAMS \
+	uninstall-sysconfDATA
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+	clean-sbinPROGRAMS ctags distclean distclean-compile \
+	distclean-depend distclean-generic distclean-tags distdir dvi \
+	dvi-am info info-am install install-am install-data \
+	install-data-am install-exec install-exec-am install-info \
+	install-info-am install-man install-sbinPROGRAMS install-strip \
+	install-sysconfDATA installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \
+	tags uninstall uninstall-am uninstall-info-am \
+	uninstall-sbinPROGRAMS uninstall-sysconfDATA
+
+
+#client : client_main.o ../lib/libzebra.a
+#	$(CC) -g -o client client_main.o ../lib/libzebra.a $(LIBS) $(LIB_IPV6)
+
+install-sysconfDATA: $(sysconf_DATA)
+	@$(NORMAL_INSTALL)
+	$(mkinstalldirs) $(DESTDIR)$(sysconfdir)
+	@list='$(sysconf_DATA)'; for p in $$list; do \
+	  if test -f $(srcdir)/$$p; then \
+	    echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \
+	    $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \
+	  else if test -f $$p; then \
+	    echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \
+	    $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \
+	  fi; fi; \
+	done
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/zebra/client_main.c b/zebra/client_main.c
new file mode 100644
index 0000000..c319aac
--- /dev/null
+++ b/zebra/client_main.c
@@ -0,0 +1,225 @@
+/*
+ * $Id: client_main.c,v 1.1 2002/12/13 20:15:30 paul Exp $
+ *
+ * GNU Zebra client test main routine.
+ * Copyright (C) 1997 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 "stream.h"
+#include "zclient.h"
+#include "thread.h"
+#include "table.h"
+#include "zebra/rib.h"
+#include "zebra/zserv.h"
+
+struct thread *master;
+
+/* Zebra client structure. */
+struct zclient *zclient = NULL;
+
+/* Zebra socket. */
+int sock;
+
+/* IPv4 route add and delete test. */
+void
+zebra_test_ipv4 (int command, int type, char *prefix, char *gateway,
+		 u_char distance)
+{
+  struct zapi_ipv4 api;
+  struct prefix_ipv4 p;
+  struct in_addr gate;
+  struct in_addr *gpnt;
+
+  str2prefix_ipv4 (prefix, &p);
+  inet_aton (gateway, &gate);
+  gpnt = &gate;
+
+  api.type = type;
+  api.flags = 0;
+
+  api.message = 0;
+  SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
+  api.nexthop_num = 1;
+  api.nexthop = &gpnt;
+  api.ifindex_num = 0;
+  if (distance)
+    {
+      SET_FLAG (api.message, ZAPI_MESSAGE_DISTANCE);
+      api.distance = distance;
+    }
+  
+
+  switch (command)
+    {
+    case ZEBRA_IPV4_ROUTE_ADD:
+      zapi_ipv4_add (zclient, &p, &api);
+      break;
+    case ZEBRA_IPV4_ROUTE_DELETE:
+      zapi_ipv4_delete (zclient, &p, &api);
+      break;
+    }
+}
+
+#ifdef HAVE_IPV6
+/* IPv6 route add and delete test. */
+void
+zebra_test_v6 (int sock)
+{
+  struct prefix_ipv6 p;
+  struct in6_addr nexthop;
+
+  str2prefix_ipv6 ("3ffe:506::2/128", &p);
+  inet_pton (AF_INET6, "::1", &nexthop);
+
+  /* zebra_ipv6_add (sock, ZEBRA_ROUTE_STATIC, 0, &p, &nexthop, 1); */
+
+  sleep (5);
+  /* zebra_ipv6_delete (sock, ZEBRA_ROUTE_STATIC, 0, &p, &nexthop, 1); */
+}
+#endif /* HAVE_IPV6 */
+
+/* Print out usage and exit. */
+void
+usage_exit ()
+{
+  fprintf (stderr, "Usage: client filename\n");
+  exit (1);
+}
+
+struct zebra_info 
+{
+  char *str;
+  int type;
+} zebra_type[] = 
+{
+  { "static", ZEBRA_ROUTE_STATIC },
+  { "rip",    ZEBRA_ROUTE_RIP },
+  { "ripng",  ZEBRA_ROUTE_RIPNG },
+  { "ospf",   ZEBRA_ROUTE_OSPF },
+  { "ospf6",  ZEBRA_ROUTE_OSPF6 },
+  { "bgp",    ZEBRA_ROUTE_BGP },
+  { NULL,     0 }
+};
+
+/* Zebra route simulator. */
+void
+zebra_sim (FILE *fp)
+{
+  char buf[BUFSIZ];
+  char distance_str[BUFSIZ];
+  u_char distance;
+
+  while (fgets (buf, sizeof buf, fp))
+    {
+      int i;
+      int ret;
+      int type;
+      char str[BUFSIZ], command[BUFSIZ], prefix[BUFSIZ], gateway[BUFSIZ];
+
+      distance = 0;
+
+      if (*buf == '#')
+	continue;
+
+      type = ZEBRA_ROUTE_STATIC;
+
+      ret = sscanf (buf, "%s %s %s %s %s\n", command, str, prefix, gateway,
+		    distance_str);
+
+      if (ret == 5)
+	{
+	  distance = atoi (distance_str);
+	}
+      else
+	{
+	  ret = sscanf (buf, "%s %s %s %s\n", command, str, prefix, gateway);
+
+	  if (ret != 4)
+	    continue;
+	}
+
+      for (i = 0; i < 10; i++)
+	{
+	  if (!zebra_type[i].str)
+	    break;
+	  if (strcmp (zebra_type[i].str, str) == 0)
+	    {
+	      type = zebra_type[i].type;
+	      break;
+	    }
+	}
+      
+      if (strcmp (command, "add") == 0)
+	{
+	  zebra_test_ipv4 (ZEBRA_IPV4_ROUTE_ADD, type, prefix, gateway,
+			   distance);
+	  printf ("%s", buf);
+	  continue;
+	}
+
+      if (strcmp (command, "del") == 0)
+	{
+	  zebra_test_ipv4 (ZEBRA_IPV4_ROUTE_DELETE, type, prefix, gateway,
+			   distance);
+	  printf ("%s", buf);
+	  continue;
+	}
+    }
+}
+
+/* Test zebra client main routine. */
+int
+main (int argc, char **argv)
+{
+  FILE *fp;
+
+  if (argc == 1)
+      usage_exit ();
+
+  /* Establish connection to zebra. */
+  zclient = zclient_new ();
+  zclient->enable = 1;
+#ifdef HAVE_TCP_ZEBRA
+  zclient->sock = zclient_socket ();
+#else
+  zclient->sock = zclient_socket_un (ZEBRA_SERV_PATH);
+#endif /* HAVE_TCP_ZEBRA */
+
+  /* Open simulation file. */
+  fp = fopen (argv[1], "r");
+  if (fp == NULL)
+    {
+      fprintf (stderr, "can't open %s\n", argv[1]);
+      exit (1);
+    }
+
+  /* Do main work. */
+  zebra_sim (fp);
+
+  sleep (100);
+
+  fclose (fp);
+  close (sock);
+
+  return 0;
+}
diff --git a/zebra/connected.c b/zebra/connected.c
new file mode 100644
index 0000000..cb43074
--- /dev/null
+++ b/zebra/connected.c
@@ -0,0 +1,394 @@
+/*
+ * Address linked list routine.
+ * Copyright (C) 1997, 98 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 "linklist.h"
+#include "if.h"
+#include "table.h"
+#include "rib.h"
+#include "table.h"
+#include "log.h"
+
+#include "zebra/zserv.h"
+#include "zebra/redistribute.h"
+
+/* If same interface address is already exist... */
+struct connected *
+connected_check_ipv4 (struct interface *ifp, struct prefix *p)
+{
+  struct connected *ifc;
+  listnode node;
+
+  for (node = listhead (ifp->connected); node; node = nextnode (node))
+    {
+      ifc = getdata (node);
+
+      if (prefix_same (ifc->address, p))
+	return ifc;
+    }
+  return NULL;
+}
+
+/* Called from if_up(). */
+void
+connected_up_ipv4 (struct interface *ifp, struct connected *ifc)
+{
+  struct prefix_ipv4 p;
+  struct prefix_ipv4 *addr;
+  struct prefix_ipv4 *dest;
+
+  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
+    return;
+
+  addr = (struct prefix_ipv4 *) ifc->address;
+  dest = (struct prefix_ipv4 *) ifc->destination;
+
+  memset (&p, 0, sizeof (struct prefix_ipv4));
+  p.family = AF_INET;
+  p.prefixlen = addr->prefixlen;
+
+  /* Point-to-point check. */
+  if (if_is_pointopoint (ifp))
+    p.prefix = dest->prefix;
+  else
+    p.prefix = addr->prefix;
+
+  /* Apply mask to the network. */
+  apply_mask_ipv4 (&p);
+
+  /* In case of connected address is 0.0.0.0/0 we treat it tunnel
+     address. */
+  if (prefix_ipv4_any (&p))
+    return;
+
+  rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0, 0, 0);
+
+  rib_update ();
+}
+
+/* Add connected IPv4 route to the interface. */
+void
+connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr, 
+		    int prefixlen, struct in_addr *broad, char *label)
+{
+  struct prefix_ipv4 *p;
+  struct connected *ifc;
+  struct connected *current;
+
+  /* Make connected structure. */
+  ifc = connected_new ();
+  ifc->ifp = ifp;
+  ifc->flags = flags;
+
+  /* Allocate new connected address. */
+  p = prefix_ipv4_new ();
+  p->family = AF_INET;
+  p->prefix = *addr;
+  p->prefixlen = prefixlen;
+  ifc->address = (struct prefix *) p;
+
+  /* If there is broadcast or pointopoint address. */
+  if (broad)
+    {
+      p = prefix_ipv4_new ();
+      p->family = AF_INET;
+      p->prefix = *broad;
+      ifc->destination = (struct prefix *) p;
+    }
+
+  /* Label of this address. */
+  if (label)
+    ifc->label = strdup (label);
+
+  /* Check same connected route. */
+  current = connected_check_ipv4 (ifp, (struct prefix *) ifc->address);
+  if (current)
+    {
+      connected_free (ifc);
+      ifc = current;
+    }
+  else
+    {
+      listnode_add (ifp->connected, ifc);
+    }
+
+  /* Update interface address information to protocol daemon. */
+  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
+    {
+      SET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
+
+      zebra_interface_address_add_update (ifp, ifc);
+
+      if (if_is_up(ifp))
+	connected_up_ipv4 (ifp, ifc);
+    }
+}
+
+void
+connected_down_ipv4 (struct interface *ifp, struct connected *ifc)
+{
+  struct prefix_ipv4 p;
+  struct prefix_ipv4 *addr;
+  struct prefix_ipv4 *dest;
+
+  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
+    return;
+
+  addr = (struct prefix_ipv4 *)ifc->address;
+  dest = (struct prefix_ipv4 *)ifc->destination;
+
+  memset (&p, 0, sizeof (struct prefix_ipv4));
+  p.family = AF_INET;
+  p.prefixlen = addr->prefixlen;
+
+  if (if_is_pointopoint (ifp))
+    p.prefix = dest->prefix;
+  else
+    p.prefix = addr->prefix;
+
+  /* Apply mask to the network. */
+  apply_mask_ipv4 (&p);
+
+  /* In case of connected address is 0.0.0.0/0 we treat it tunnel
+     address. */
+  if (prefix_ipv4_any (&p))
+    return;
+
+  rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0);
+
+  rib_update ();
+}
+
+/* Delete connected IPv4 route to the interface. */
+void
+connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
+		       int prefixlen, struct in_addr *broad, char *label)
+{
+  struct prefix_ipv4 p;
+  struct connected *ifc;
+
+  memset (&p, 0, sizeof (struct prefix_ipv4));
+  p.family = AF_INET;
+  p.prefix = *addr;
+  p.prefixlen = prefixlen;
+
+  ifc = connected_check_ipv4 (ifp, (struct prefix *) &p);
+  if (! ifc)
+    return;
+
+  /* Update interface address information to protocol daemon. */
+  if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
+    {
+      zebra_interface_address_delete_update (ifp, ifc);
+
+      connected_down_ipv4 (ifp, ifc);
+
+      UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
+    }
+
+  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
+    {
+      listnode_delete (ifp->connected, ifc);
+      connected_free (ifc);
+    }
+}
+
+#ifdef HAVE_IPV6
+/* If same interface address is already exist... */
+struct connected *
+connected_check_ipv6 (struct interface *ifp, struct prefix *p)
+{
+  struct connected *ifc;
+  listnode node;
+
+  for (node = listhead (ifp->connected); node; node = nextnode (node))
+    {
+      ifc = getdata (node);
+
+      if (prefix_same (ifc->address, p))
+	return ifc;
+    }
+  return 0;
+}
+
+void
+connected_up_ipv6 (struct interface *ifp, struct connected *ifc)
+{
+  struct prefix_ipv6 p;
+  struct prefix_ipv6 *addr;
+  struct prefix_ipv6 *dest;
+
+  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
+    return;
+
+  addr = (struct prefix_ipv6 *) ifc->address;
+  dest = (struct prefix_ipv6 *) ifc->destination;
+
+  memset (&p, 0, sizeof (struct prefix_ipv6));
+  p.family = AF_INET6;
+  p.prefixlen = addr->prefixlen;
+
+  if (if_is_pointopoint (ifp) && dest)
+    {
+      if (IN6_IS_ADDR_UNSPECIFIED (&dest->prefix))
+	p.prefix = addr->prefix;
+      else
+	p.prefix = dest->prefix;
+    }
+  else
+    p.prefix = addr->prefix;
+
+  /* Apply mask to the network. */
+  apply_mask_ipv6 (&p);
+
+  if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix))
+    return;
+
+  rib_add_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0);
+
+  rib_update ();
+}
+
+/* Add connected IPv6 route to the interface. */
+void
+connected_add_ipv6 (struct interface *ifp, struct in6_addr *addr,
+		    int prefixlen, struct in6_addr *broad)
+{
+  struct prefix_ipv6 *p;
+  struct connected *ifc;
+  struct connected *current;
+
+  /* Make connected structure. */
+  ifc = connected_new ();
+  ifc->ifp = ifp;
+
+  /* Allocate new connected address. */
+  p = prefix_ipv6_new ();
+  p->family = AF_INET6;
+  IPV6_ADDR_COPY (&p->prefix, addr);
+  p->prefixlen = prefixlen;
+  ifc->address = (struct prefix *) p;
+
+  /* If there is broadcast or pointopoint address. */
+  if (broad)
+    {
+      p = prefix_ipv6_new ();
+      p->family = AF_INET6;
+      IPV6_ADDR_COPY (&p->prefix, broad);
+      ifc->destination = (struct prefix *) p;
+    }
+
+  current = connected_check_ipv6 (ifp, (struct prefix *) ifc->address);
+  if (current)
+    {
+      connected_free (ifc);
+      ifc = current;
+    }
+  else
+    {
+      listnode_add (ifp->connected, ifc);
+    }
+
+  /* Update interface address information to protocol daemon. */
+  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
+    {
+      SET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
+
+      zebra_interface_address_add_update (ifp, ifc);
+
+      if (if_is_up(ifp))
+	connected_up_ipv6 (ifp, ifc);
+    }
+}
+
+void
+connected_down_ipv6 (struct interface *ifp, struct connected *ifc)
+{
+  struct prefix_ipv6 p;
+  struct prefix_ipv6 *addr;
+  struct prefix_ipv6 *dest;
+
+  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
+    return;
+
+  addr = (struct prefix_ipv6 *) ifc->address;
+  dest = (struct prefix_ipv6 *) ifc->destination;
+
+  memset (&p, 0, sizeof (struct prefix_ipv6));
+  p.family = AF_INET6;
+  p.prefixlen = addr->prefixlen;
+
+  if (if_is_pointopoint (ifp) && dest)
+    {
+      if (IN6_IS_ADDR_UNSPECIFIED (&dest->prefix))
+	p.prefix = addr->prefix;
+      else
+	p.prefix = dest->prefix;
+    }
+  else
+    p.prefix = addr->prefix;
+
+  apply_mask_ipv6 (&p);
+
+  if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix))
+    return;
+
+  rib_delete_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0);
+
+  rib_update ();
+}
+
+void
+connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address,
+                    int prefixlen, struct in6_addr *broad)
+{
+  struct prefix_ipv6 p;
+  struct connected *ifc;
+  
+  memset (&p, 0, sizeof (struct prefix_ipv6));
+  p.family = AF_INET6;
+  memcpy (&p.prefix, address, sizeof (struct in6_addr));
+  p.prefixlen = prefixlen;
+
+  ifc = connected_check_ipv6 (ifp, (struct prefix *) &p);
+  if (! ifc)
+    return;
+
+  /* Update interface address information to protocol daemon. */
+  if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
+    {
+      zebra_interface_address_delete_update (ifp, ifc);
+
+      connected_down_ipv6 (ifp, ifc);
+
+      UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
+    }
+
+  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
+    {
+      listnode_delete (ifp->connected, ifc);
+      connected_free (ifc);
+    }
+}
+#endif /* HAVE_IPV6 */
diff --git a/zebra/connected.h b/zebra/connected.h
new file mode 100644
index 0000000..7bf13ba
--- /dev/null
+++ b/zebra/connected.h
@@ -0,0 +1,60 @@
+/*
+ * Interface's address and mask.
+ * Copyright (C) 1997 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.  
+ */
+
+#ifndef _ZEBRA_CONNECTED_H
+#define _ZEBRA_CONNECTED_H
+
+struct connected *
+connected_check_ipv4 (struct interface *ifp, struct prefix *p);
+
+void
+connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr, 
+		    int prefixlen, struct in_addr *broad, char *label);
+
+void
+connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
+		       int prefixlen, struct in_addr *broad, char *label);
+
+void
+connected_up_ipv4 (struct interface *, struct connected *);
+void
+connected_down_ipv4 (struct interface *, struct connected *);
+
+#ifdef HAVE_IPV6
+struct connected *
+connected_check_ipv6 (struct interface *ifp, struct prefix *p);
+
+void
+connected_add_ipv6 (struct interface *ifp, struct in6_addr *address,
+		    int prefixlen, struct in6_addr *broad);
+void
+connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address,
+		       int prefixlen, struct in6_addr *broad);
+void
+connected_up_ipv6 (struct interface *, struct connected *);
+
+void
+connected_down_ipv6 (struct interface *ifp, struct connected *);
+
+#endif /* HAVE_IPV6 */
+
+#endif /*_ZEBRA_CONNECTED_H */
diff --git a/zebra/debug.c b/zebra/debug.c
new file mode 100644
index 0000000..fc99623
--- /dev/null
+++ b/zebra/debug.c
@@ -0,0 +1,272 @@
+/*
+ * Zebra debug related function
+ * Copyright (C) 1999 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 "command.h"
+#include "debug.h"
+
+/* For debug statement. */
+unsigned long zebra_debug_event;
+unsigned long zebra_debug_packet;
+unsigned long zebra_debug_kernel;
+
+DEFUN (show_debugging_zebra,
+       show_debugging_zebra_cmd,
+       "show debugging zebra",
+       SHOW_STR
+       "Zebra configuration\n"
+       "Debugging information\n")
+{
+  vty_out (vty, "Zebra debugging status:%s", VTY_NEWLINE);
+
+  if (IS_ZEBRA_DEBUG_EVENT)
+    vty_out (vty, "  Zebra event debugging is on%s", VTY_NEWLINE);
+
+  if (IS_ZEBRA_DEBUG_PACKET)
+    {
+      if (IS_ZEBRA_DEBUG_SEND && IS_ZEBRA_DEBUG_RECV)
+	{
+	  vty_out (vty, "  Zebra packet%s debugging is on%s",
+		   IS_ZEBRA_DEBUG_DETAIL ? " detail" : "",
+		   VTY_NEWLINE);
+	}
+      else
+	{
+	  if (IS_ZEBRA_DEBUG_SEND)
+	    vty_out (vty, "  Zebra packet send%s debugging is on%s",
+		     IS_ZEBRA_DEBUG_DETAIL ? " detail" : "",
+		     VTY_NEWLINE);
+	  else
+	    vty_out (vty, "  Zebra packet receive%s debugging is on%s",
+		     IS_ZEBRA_DEBUG_DETAIL ? " detail" : "",
+		     VTY_NEWLINE);
+	}
+    }
+
+  if (IS_ZEBRA_DEBUG_KERNEL)
+    vty_out (vty, "  Zebra kernel debugging is on%s", VTY_NEWLINE);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (debug_zebra_events,
+       debug_zebra_events_cmd,
+       "debug zebra events",
+       DEBUG_STR
+       "Zebra configuration\n"
+       "Debug option set for zebra events\n")
+{
+  zebra_debug_event = ZEBRA_DEBUG_EVENT;
+  return CMD_WARNING;
+}
+
+DEFUN (debug_zebra_packet,
+       debug_zebra_packet_cmd,
+       "debug zebra packet",
+       DEBUG_STR
+       "Zebra configuration\n"
+       "Debug option set for zebra packet\n")
+{
+  zebra_debug_packet = ZEBRA_DEBUG_PACKET;
+  zebra_debug_packet |= ZEBRA_DEBUG_SEND;
+  zebra_debug_packet |= ZEBRA_DEBUG_RECV;
+  return CMD_SUCCESS;
+}
+
+DEFUN (debug_zebra_packet_direct,
+       debug_zebra_packet_direct_cmd,
+       "debug zebra packet (recv|send)",
+       DEBUG_STR
+       "Zebra configuration\n"
+       "Debug option set for zebra packet\n"
+       "Debug option set for receive packet\n"
+       "Debug option set for send packet\n")
+{
+  zebra_debug_packet = ZEBRA_DEBUG_PACKET;
+  if (strncmp ("send", argv[0], strlen (argv[0])) == 0)
+    zebra_debug_packet |= ZEBRA_DEBUG_SEND;
+  if (strncmp ("recv", argv[0], strlen (argv[0])) == 0)
+    zebra_debug_packet |= ZEBRA_DEBUG_RECV;
+  zebra_debug_packet &= ~ZEBRA_DEBUG_DETAIL;
+  return CMD_SUCCESS;
+}
+
+DEFUN (debug_zebra_packet_detail,
+       debug_zebra_packet_detail_cmd,
+       "debug zebra packet (recv|send) detail",
+       DEBUG_STR
+       "Zebra configuration\n"
+       "Debug option set for zebra packet\n"
+       "Debug option set for receive packet\n"
+       "Debug option set for send packet\n"
+       "Debug option set detaied information\n")
+{
+  zebra_debug_packet = ZEBRA_DEBUG_PACKET;
+  if (strncmp ("send", argv[0], strlen (argv[0])) == 0)
+    zebra_debug_packet |= ZEBRA_DEBUG_SEND;
+  if (strncmp ("recv", argv[0], strlen (argv[0])) == 0)
+    zebra_debug_packet |= ZEBRA_DEBUG_RECV;
+  zebra_debug_packet |= ZEBRA_DEBUG_DETAIL;
+  return CMD_SUCCESS;
+}
+
+DEFUN (debug_zebra_kernel,
+       debug_zebra_kernel_cmd,
+       "debug zebra kernel",
+       DEBUG_STR
+       "Zebra configuration\n"
+       "Debug option set for zebra between kernel interface\n")
+{
+  zebra_debug_kernel = ZEBRA_DEBUG_KERNEL;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_zebra_events,
+       no_debug_zebra_events_cmd,
+       "no debug zebra events",
+       NO_STR
+       DEBUG_STR
+       "Zebra configuration\n"
+       "Debug option set for zebra events\n")
+{
+  zebra_debug_event = 0;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_zebra_packet,
+       no_debug_zebra_packet_cmd,
+       "no debug zebra packet",
+       NO_STR
+       DEBUG_STR
+       "Zebra configuration\n"
+       "Debug option set for zebra packet\n")
+{
+  zebra_debug_packet = 0;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_zebra_packet_direct,
+       no_debug_zebra_packet_direct_cmd,
+       "no debug zebra packet (recv|send)",
+       NO_STR
+       DEBUG_STR
+       "Zebra configuration\n"
+       "Debug option set for zebra packet\n"
+       "Debug option set for receive packet\n"
+       "Debug option set for send packet\n")
+{
+  if (strncmp ("send", argv[0], strlen (argv[0])) == 0)
+    zebra_debug_packet &= ~ZEBRA_DEBUG_SEND;
+  if (strncmp ("recv", argv[0], strlen (argv[0])) == 0)
+    zebra_debug_packet &= ~ZEBRA_DEBUG_RECV;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_zebra_kernel,
+       no_debug_zebra_kernel_cmd,
+       "no debug zebra kernel",
+       NO_STR
+       DEBUG_STR
+       "Zebra configuration\n"
+       "Debug option set for zebra between kernel interface\n")
+{
+  zebra_debug_kernel = 0;
+  return CMD_SUCCESS;
+}
+
+/* Debug node. */
+struct cmd_node debug_node =
+{
+  DEBUG_NODE,
+  "",				/* Debug node has no interface. */
+  1
+};
+
+int
+config_write_debug (struct vty *vty)
+{
+  int write = 0;
+
+  if (IS_ZEBRA_DEBUG_EVENT)
+    {
+      vty_out (vty, "debug zebra events%s", VTY_NEWLINE);
+      write++;
+    }
+  if (IS_ZEBRA_DEBUG_PACKET)
+    {
+      if (IS_ZEBRA_DEBUG_SEND && IS_ZEBRA_DEBUG_RECV)
+	{
+	  vty_out (vty, "debug zebra packet%s%s",
+		   IS_ZEBRA_DEBUG_DETAIL ? " detail" : "",
+		   VTY_NEWLINE);
+	  write++;
+	}
+      else
+	{
+	  if (IS_ZEBRA_DEBUG_SEND)
+	    vty_out (vty, "debug zebra packet send%s%s",
+		     IS_ZEBRA_DEBUG_DETAIL ? " detail" : "",
+		     VTY_NEWLINE);
+	  else
+	    vty_out (vty, "debug zebra packet recv%s%s",
+		     IS_ZEBRA_DEBUG_DETAIL ? " detail" : "",
+		     VTY_NEWLINE);
+	  write++;
+	}
+    }
+  if (IS_ZEBRA_DEBUG_KERNEL)
+    {
+      vty_out (vty, "debug zebra kernel%s", VTY_NEWLINE);
+      write++;
+    }
+  return write;
+}
+
+void
+zebra_debug_init ()
+{
+  zebra_debug_event = 0;
+  zebra_debug_packet = 0;
+
+  install_node (&debug_node, config_write_debug);
+
+  install_element (VIEW_NODE, &show_debugging_zebra_cmd);
+
+  install_element (ENABLE_NODE, &show_debugging_zebra_cmd);
+  install_element (ENABLE_NODE, &debug_zebra_events_cmd);
+  install_element (ENABLE_NODE, &debug_zebra_packet_cmd);
+  install_element (ENABLE_NODE, &debug_zebra_packet_direct_cmd);
+  install_element (ENABLE_NODE, &debug_zebra_packet_detail_cmd);
+  install_element (ENABLE_NODE, &debug_zebra_kernel_cmd);
+  install_element (ENABLE_NODE, &no_debug_zebra_events_cmd);
+  install_element (ENABLE_NODE, &no_debug_zebra_packet_cmd);
+  install_element (ENABLE_NODE, &no_debug_zebra_kernel_cmd);
+
+  install_element (CONFIG_NODE, &debug_zebra_events_cmd);
+  install_element (CONFIG_NODE, &debug_zebra_packet_cmd);
+  install_element (CONFIG_NODE, &debug_zebra_packet_direct_cmd);
+  install_element (CONFIG_NODE, &debug_zebra_packet_detail_cmd);
+  install_element (CONFIG_NODE, &debug_zebra_kernel_cmd);
+  install_element (CONFIG_NODE, &no_debug_zebra_events_cmd);
+  install_element (CONFIG_NODE, &no_debug_zebra_packet_cmd);
+  install_element (CONFIG_NODE, &no_debug_zebra_kernel_cmd);
+}
diff --git a/zebra/debug.h b/zebra/debug.h
new file mode 100644
index 0000000..6eaa957
--- /dev/null
+++ b/zebra/debug.h
@@ -0,0 +1,52 @@
+/*
+ * Zebra debug related function
+ * Copyright (C) 1999 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.  
+ */
+
+#ifndef _ZEBRA_DEBUG_H
+#define _ZEBRA_DEBUG_H
+
+/* Debug flags. */
+#define ZEBRA_DEBUG_EVENT   0x01
+
+#define ZEBRA_DEBUG_PACKET  0x01
+#define ZEBRA_DEBUG_SEND    0x20
+#define ZEBRA_DEBUG_RECV    0x40
+#define ZEBRA_DEBUG_DETAIL  0x80
+
+#define ZEBRA_DEBUG_KERNEL  0x01
+
+/* Debug related macro. */
+#define IS_ZEBRA_DEBUG_EVENT  (zebra_debug_event & ZEBRA_DEBUG_EVENT)
+
+#define IS_ZEBRA_DEBUG_PACKET (zebra_debug_packet & ZEBRA_DEBUG_PACKET)
+#define IS_ZEBRA_DEBUG_SEND   (zebra_debug_packet & ZEBRA_DEBUG_SEND)
+#define IS_ZEBRA_DEBUG_RECV   (zebra_debug_packet & ZEBRA_DEBUG_RECV)
+#define IS_ZEBRA_DEBUG_DETAIL (zebra_debug_packet & ZEBRA_DEBUG_DETAIL)
+
+#define IS_ZEBRA_DEBUG_KERNEL (zebra_debug_kernel & ZEBRA_DEBUG_KERNEL)
+
+extern unsigned long zebra_debug_event;
+extern unsigned long zebra_debug_packet;
+extern unsigned long zebra_debug_kernel;
+
+void zebra_debug_init ();
+
+#endif /* _ZEBRA_DEBUG_H */
diff --git a/zebra/if_ioctl.c b/zebra/if_ioctl.c
new file mode 100644
index 0000000..46f5301
--- /dev/null
+++ b/zebra/if_ioctl.c
@@ -0,0 +1,438 @@
+/*
+ * Interface looking up by ioctl ().
+ * Copyright (C) 1997, 98 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 "if.h"
+#include "sockunion.h"
+#include "prefix.h"
+#include "ioctl.h"
+#include "connected.h"
+#include "memory.h"
+#include "log.h"
+
+#include "zebra/interface.h"
+
+/* Interface looking up using infamous SIOCGIFCONF. */
+int
+interface_list_ioctl ()
+{
+  int ret;
+  int sock;
+#define IFNUM_BASE 32
+  int ifnum;
+  struct ifreq *ifreq;
+  struct ifconf ifconf;
+  struct interface *ifp;
+  int n;
+  int lastlen;
+
+  /* Normally SIOCGIFCONF works with AF_INET socket. */
+  sock = socket (AF_INET, SOCK_DGRAM, 0);
+  if (sock < 0) 
+    {
+      zlog_warn ("Can't make AF_INET socket stream: %s", strerror (errno));
+      return -1;
+    }
+
+  /* Set initial ifreq count.  This will be double when SIOCGIFCONF
+     fail.  Solaris has SIOCGIFNUM. */
+#ifdef SIOCGIFNUM
+  ret = ioctl (sock, SIOCGIFNUM, &ifnum);
+  if (ret < 0)
+    ifnum = IFNUM_BASE;
+  else
+    ifnum++;
+#else
+  ifnum = IFNUM_BASE;
+#endif /* SIOCGIFNUM */
+
+  ifconf.ifc_buf = NULL;
+
+  lastlen = 0;
+  /* Loop until SIOCGIFCONF success. */
+  for (;;) 
+    {
+      ifconf.ifc_len = sizeof (struct ifreq) * ifnum;
+      ifconf.ifc_buf = XREALLOC(MTYPE_TMP, ifconf.ifc_buf, ifconf.ifc_len);
+
+      ret = ioctl(sock, SIOCGIFCONF, &ifconf);
+
+      if (ret < 0) 
+	{
+	  zlog_warn ("SIOCGIFCONF: %s", strerror(errno));
+	  goto end;
+	}
+      /* Repeatedly get info til buffer fails to grow. */
+      if (ifconf.ifc_len > lastlen)
+	{
+          lastlen = ifconf.ifc_len;
+	  ifnum += 10;
+	  continue;
+	}
+      /* Success. */
+      break;
+    }
+
+  /* Allocate interface. */
+  ifreq = ifconf.ifc_req;
+
+#ifdef OPEN_BSD
+  for (n = 0; n < ifconf.ifc_len; )
+    {
+      int size;
+
+      ifreq = (struct ifreq *)((caddr_t) ifconf.ifc_req + n);
+      ifp = if_get_by_name (ifreq->ifr_name);
+      if_add_update (ifp);
+      size = ifreq->ifr_addr.sa_len;
+      if (size < sizeof (ifreq->ifr_addr))
+	size = sizeof (ifreq->ifr_addr);
+      size += sizeof (ifreq->ifr_name);
+      n += size;
+    }
+#else
+  for (n = 0; n < ifconf.ifc_len; n += sizeof(struct ifreq))
+    {
+      ifp = if_get_by_name (ifreq->ifr_name);
+      if_add_update (ifp);
+      ifreq++;
+    }
+#endif /* OPEN_BSD */
+
+ end:
+  close (sock);
+  XFREE (MTYPE_TMP, ifconf.ifc_buf);
+
+  return ret;
+}
+
+/* Get interface's index by ioctl. */
+int
+if_get_index (struct interface *ifp)
+{
+  static int if_fake_index = 1;
+
+#ifdef HAVE_BROKEN_ALIASES
+  /* Linux 2.2.X does not provide individual interface index for aliases. */
+  ifp->ifindex = if_fake_index++;
+  return ifp->ifindex;
+#else
+#ifdef SIOCGIFINDEX
+  int ret;
+  struct ifreq ifreq;
+
+  ifreq_set_name (&ifreq, ifp);
+
+  ret = if_ioctl (SIOCGIFINDEX, (caddr_t) &ifreq);
+  if (ret < 0)
+    {
+      /* Linux 2.0.X does not have interface index. */
+      ifp->ifindex = if_fake_index++;
+      return ifp->ifindex;
+    }
+
+  /* OK we got interface index. */
+#ifdef ifr_ifindex
+  ifp->ifindex = ifreq.ifr_ifindex;
+#else
+  ifp->ifindex = ifreq.ifr_index;
+#endif
+  return ifp->ifindex;
+
+#else
+  ifp->ifindex = if_fake_index++;
+  return ifp->ifindex;
+#endif /* SIOCGIFINDEX */
+#endif /* HAVE_BROKEN_ALIASES */
+}
+
+#ifdef SIOCGIFHWADDR
+int
+if_get_hwaddr (struct interface *ifp)
+{
+  int ret;
+  struct ifreq ifreq;
+  int i;
+
+  strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ);
+  ifreq.ifr_addr.sa_family = AF_INET;
+
+  /* Fetch Hardware address if available. */
+  ret = if_ioctl (SIOCGIFHWADDR, (caddr_t) &ifreq);
+  if (ret < 0)
+    ifp->hw_addr_len = 0;
+  else
+    {
+      memcpy (ifp->hw_addr, ifreq.ifr_hwaddr.sa_data, 6);
+
+      for (i = 0; i < 6; i++)
+	if (ifp->hw_addr[i] != 0)
+	  break;
+
+      if (i == 6)
+	ifp->hw_addr_len = 0;
+      else
+	ifp->hw_addr_len = 6;
+    }
+  return 0;
+}
+#endif /* SIOCGIFHWADDR */
+
+#ifdef HAVE_GETIFADDRS
+#include <ifaddrs.h>
+
+int
+if_getaddrs ()
+{
+  int ret;
+  struct ifaddrs *ifap;
+  struct ifaddrs *ifapfree;
+  struct interface *ifp;
+  int prefixlen;
+
+  ret = getifaddrs (&ifap); 
+  if (ret != 0)
+    {
+      zlog_err ("getifaddrs(): %s", strerror (errno));
+      return -1;
+    }
+
+  for (ifapfree = ifap; ifap; ifap = ifap->ifa_next)
+    {
+      ifp = if_lookup_by_name (ifap->ifa_name);
+      if (ifp == NULL)
+	{
+	  zlog_err ("if_getaddrs(): Can't lookup interface %s\n",
+		    ifap->ifa_name);
+	  continue;
+	}
+
+      if (ifap->ifa_addr->sa_family == AF_INET)
+	{
+	  struct sockaddr_in *addr;
+	  struct sockaddr_in *mask;
+	  struct sockaddr_in *dest;
+	  struct in_addr *dest_pnt;
+
+	  addr = (struct sockaddr_in *) ifap->ifa_addr;
+	  mask = (struct sockaddr_in *) ifap->ifa_netmask;
+	  prefixlen = ip_masklen (mask->sin_addr);
+
+	  dest_pnt = NULL;
+
+	  if (ifap->ifa_flags & IFF_POINTOPOINT) 
+	    {
+	      dest = (struct sockaddr_in *) ifap->ifa_dstaddr;
+	      dest_pnt = &dest->sin_addr;
+	    }
+
+	  if (ifap->ifa_flags & IFF_BROADCAST)
+	    {
+	      dest = (struct sockaddr_in *) ifap->ifa_broadaddr;
+	      dest_pnt = &dest->sin_addr;
+	    }
+
+	  connected_add_ipv4 (ifp, 0, &addr->sin_addr,
+			      prefixlen, dest_pnt, NULL);
+	}
+#ifdef HAVE_IPV6
+      if (ifap->ifa_addr->sa_family == AF_INET6)
+	{
+	  struct sockaddr_in6 *addr;
+	  struct sockaddr_in6 *mask;
+	  struct sockaddr_in6 *dest;
+	  struct in6_addr *dest_pnt;
+
+	  addr = (struct sockaddr_in6 *) ifap->ifa_addr;
+	  mask = (struct sockaddr_in6 *) ifap->ifa_netmask;
+	  prefixlen = ip6_masklen (mask->sin6_addr);
+
+	  dest_pnt = NULL;
+
+	  if (ifap->ifa_flags & IFF_POINTOPOINT) 
+	    {
+	      if (ifap->ifa_dstaddr)
+		{
+		  dest = (struct sockaddr_in6 *) ifap->ifa_dstaddr;
+		  dest_pnt = &dest->sin6_addr;
+		}
+	    }
+
+	  if (ifap->ifa_flags & IFF_BROADCAST)
+	    {
+	      if (ifap->ifa_broadaddr)
+		{
+		  dest = (struct sockaddr_in6 *) ifap->ifa_broadaddr;
+		  dest_pnt = &dest->sin6_addr;
+		}
+	    }
+
+	  connected_add_ipv6 (ifp, &addr->sin6_addr, prefixlen, dest_pnt);
+	}
+#endif /* HAVE_IPV6 */
+    }
+
+  freeifaddrs (ifapfree);
+
+  return 0; 
+}
+#else /* HAVE_GETIFADDRS */
+/* Interface address lookup by ioctl.  This function only looks up
+   IPv4 address. */
+int
+if_get_addr (struct interface *ifp)
+{
+  int ret;
+  struct ifreq ifreq;
+  struct sockaddr_in addr;
+  struct sockaddr_in mask;
+  struct sockaddr_in dest;
+  struct in_addr *dest_pnt;
+  u_char prefixlen;
+
+  /* Interface's name and address family. */
+  strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ);
+  ifreq.ifr_addr.sa_family = AF_INET;
+
+  /* Interface's address. */
+  ret = if_ioctl (SIOCGIFADDR, (caddr_t) &ifreq);
+  if (ret < 0) 
+    {
+      if (errno != EADDRNOTAVAIL)
+	{
+	  zlog_warn ("SIOCGIFADDR fail: %s", strerror (errno));
+	  return ret;
+	}
+      return 0;
+    }
+  memcpy (&addr, &ifreq.ifr_addr, sizeof (struct sockaddr_in));
+
+  /* Interface's network mask. */
+  ret = if_ioctl (SIOCGIFNETMASK, (caddr_t) &ifreq);
+  if (ret < 0) 
+    {
+      if (errno != EADDRNOTAVAIL) 
+	{
+	  zlog_warn ("SIOCGIFNETMASK fail: %s", strerror (errno));
+	  return ret;
+	}
+      return 0;
+    }
+#ifdef ifr_netmask
+  memcpy (&mask, &ifreq.ifr_netmask, sizeof (struct sockaddr_in));
+#else
+  memcpy (&mask, &ifreq.ifr_addr, sizeof (struct sockaddr_in));
+#endif /* ifr_netmask */
+  prefixlen = ip_masklen (mask.sin_addr);
+
+  /* Point to point or borad cast address pointer init. */
+  dest_pnt = NULL;
+
+  if (ifp->flags & IFF_POINTOPOINT) 
+    {
+      ret = if_ioctl (SIOCGIFDSTADDR, (caddr_t) &ifreq);
+      if (ret < 0) 
+	{
+	  if (errno != EADDRNOTAVAIL) 
+	    {
+	      zlog_warn ("SIOCGIFDSTADDR fail: %s", strerror (errno));
+	      return ret;
+	    }
+	  return 0;
+	}
+      memcpy (&dest, &ifreq.ifr_dstaddr, sizeof (struct sockaddr_in));
+      dest_pnt = &dest.sin_addr;
+    }
+  if (ifp->flags & IFF_BROADCAST)
+    {
+      ret = if_ioctl (SIOCGIFBRDADDR, (caddr_t) &ifreq);
+      if (ret < 0) 
+	{
+	  if (errno != EADDRNOTAVAIL) 
+	    {
+	      zlog_warn ("SIOCGIFBRDADDR fail: %s", strerror (errno));
+	      return ret;
+	    }
+	  return 0;
+	}
+      memcpy (&dest, &ifreq.ifr_broadaddr, sizeof (struct sockaddr_in));
+      dest_pnt = &dest.sin_addr;
+    }
+
+
+  /* Set address to the interface. */
+  connected_add_ipv4 (ifp, 0, &addr.sin_addr, prefixlen, dest_pnt, NULL);
+
+  return 0;
+}
+#endif /* HAVE_GETIFADDRS */
+
+/* Fetch interface information via ioctl(). */
+static void
+interface_info_ioctl ()
+{
+  listnode node;
+  struct interface *ifp;
+  
+  for (node = listhead (iflist); node; node = nextnode (node))
+    {
+      ifp = getdata (node);
+
+      if_get_index (ifp);
+#ifdef SIOCGIFHWADDR
+      if_get_hwaddr (ifp);
+#endif /* SIOCGIFHWADDR */
+      if_get_flags (ifp);
+#ifndef HAVE_GETIFADDRS
+      if_get_addr (ifp);
+#endif /* ! HAVE_GETIFADDRS */
+      if_get_mtu (ifp);
+      if_get_metric (ifp);
+    }
+}
+
+/* Lookup all interface information. */
+void
+interface_list ()
+{
+  /* Linux can do both proc & ioctl, ioctl is the only way to get
+     interface aliases in 2.2 series kernels. */
+#ifdef HAVE_PROC_NET_DEV
+  interface_list_proc ();
+#endif /* HAVE_PROC_NET_DEV */
+  interface_list_ioctl ();
+
+  /* After listing is done, get index, address, flags and other
+     interface's information. */
+  interface_info_ioctl ();
+
+#ifdef HAVE_GETIFADDRS
+  if_getaddrs ();
+#endif /* HAVE_GETIFADDRS */
+
+#if defined(HAVE_IPV6) && defined(HAVE_PROC_NET_IF_INET6)
+  /* Linux provides interface's IPv6 address via
+     /proc/net/if_inet6. */
+  ifaddr_proc_ipv6 ();
+#endif /* HAVE_IPV6 && HAVE_PROC_NET_IF_INET6 */
+}
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c
new file mode 100644
index 0000000..c9c1476
--- /dev/null
+++ b/zebra/if_netlink.c
@@ -0,0 +1,33 @@
+/*
+ * Interface looking up by netlink.
+ * Copyright (C) 1998 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>
+
+/* Extern from rt_netlink.c */  
+void interface_lookup_netlink ();  
+
+/* Interface information read by netlink. */
+void
+interface_list ()
+{
+  interface_lookup_netlink ();  
+}
diff --git a/zebra/if_proc.c b/zebra/if_proc.c
new file mode 100644
index 0000000..117859f
--- /dev/null
+++ b/zebra/if_proc.c
@@ -0,0 +1,246 @@
+/* Interface name and statistics get function using proc file system
+ * Copyright (C) 1999 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 "if.h"
+#include "prefix.h"
+#include "log.h"
+
+#include "zebra/ioctl.h"
+#include "zebra/connected.h"
+#include "zebra/interface.h"
+
+/* Proc filesystem one line buffer. */
+#define PROCBUFSIZ                  1024
+
+/* Path to device proc file system. */
+#ifndef _PATH_PROC_NET_DEV
+#define _PATH_PROC_NET_DEV        "/proc/net/dev"
+#endif /* _PATH_PROC_NET_DEV */
+
+/* Return statistics data pointer. */
+static char *
+interface_name_cut (char *buf, char **name)
+{
+  char *stat;
+
+  /* Skip white space.  Line will include header spaces. */
+  while (*buf == ' ')
+    buf++;
+  *name = buf;
+
+  /* Cut interface name. */
+  stat = strrchr (buf, ':');
+  *stat++ = '\0';
+
+  return stat;
+}
+
+/* Fetch each statistics field. */
+static int
+ifstat_dev_fields (int version, char *buf, struct interface *ifp)
+{
+  switch (version) 
+    {
+    case 3:
+      sscanf(buf,
+	     "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld",
+	     &ifp->stats.rx_bytes,
+	     &ifp->stats.rx_packets,
+	     &ifp->stats.rx_errors,
+	     &ifp->stats.rx_dropped,
+	     &ifp->stats.rx_fifo_errors,
+	     &ifp->stats.rx_frame_errors,
+	     &ifp->stats.rx_compressed,
+	     &ifp->stats.rx_multicast,
+
+	     &ifp->stats.tx_bytes,
+	     &ifp->stats.tx_packets,
+	     &ifp->stats.tx_errors,
+	     &ifp->stats.tx_dropped,
+	     &ifp->stats.tx_fifo_errors,
+	     &ifp->stats.collisions,
+	     &ifp->stats.tx_carrier_errors,
+	     &ifp->stats.tx_compressed);
+      break;
+    case 2:
+      sscanf(buf, "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld",
+	     &ifp->stats.rx_bytes,
+	     &ifp->stats.rx_packets,
+	     &ifp->stats.rx_errors,
+	     &ifp->stats.rx_dropped,
+	     &ifp->stats.rx_fifo_errors,
+	     &ifp->stats.rx_frame_errors,
+
+	     &ifp->stats.tx_bytes,
+	     &ifp->stats.tx_packets,
+	     &ifp->stats.tx_errors,
+	     &ifp->stats.tx_dropped,
+	     &ifp->stats.tx_fifo_errors,
+	     &ifp->stats.collisions,
+	     &ifp->stats.tx_carrier_errors);
+      ifp->stats.rx_multicast = 0;
+      break;
+    case 1:
+      sscanf(buf, "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld",
+	     &ifp->stats.rx_packets,
+	     &ifp->stats.rx_errors,
+	     &ifp->stats.rx_dropped,
+	     &ifp->stats.rx_fifo_errors,
+	     &ifp->stats.rx_frame_errors,
+
+	     &ifp->stats.tx_packets,
+	     &ifp->stats.tx_errors,
+	     &ifp->stats.tx_dropped,
+	     &ifp->stats.tx_fifo_errors,
+	     &ifp->stats.collisions,
+	     &ifp->stats.tx_carrier_errors);
+      ifp->stats.rx_bytes = 0;
+      ifp->stats.tx_bytes = 0;
+      ifp->stats.rx_multicast = 0;
+      break;
+    }
+  return 0;
+}
+
+/* Update interface's statistics. */
+int
+ifstat_update_proc ()
+{
+  FILE *fp;
+  char buf[PROCBUFSIZ];
+  int version;
+  struct interface *ifp;
+  char *stat;
+  char *name;
+
+  /* Open /proc/net/dev. */
+  fp = fopen (_PATH_PROC_NET_DEV, "r");
+  if (fp == NULL)
+    {
+      zlog_warn ("Can't open proc file %s: %s",
+		 _PATH_PROC_NET_DEV, strerror (errno));
+      return -1;
+    }
+
+  /* Drop header lines. */
+  fgets (buf, PROCBUFSIZ, fp);
+  fgets (buf, PROCBUFSIZ, fp);
+
+  /* To detect proc format veresion, parse second line. */
+  if (strstr (buf, "compressed"))
+    version = 3;
+  else if (strstr (buf, "bytes"))
+    version = 2;
+  else
+    version = 1;
+
+  /* Update each interface's statistics. */
+  while (fgets (buf, PROCBUFSIZ, fp) != NULL)
+    {
+      stat = interface_name_cut (buf, &name);
+      ifp = if_get_by_name (name);
+      ifstat_dev_fields (version, stat, ifp);
+    }
+
+  return 0;
+}
+
+/* Interface structure allocation by proc filesystem. */
+int
+interface_list_proc ()
+{
+  FILE *fp;
+  char buf[PROCBUFSIZ];
+  struct interface *ifp;
+  char *name;
+
+  /* Open /proc/net/dev. */
+  fp = fopen (_PATH_PROC_NET_DEV, "r");
+  if (fp == NULL)
+    {
+      zlog_warn ("Can't open proc file %s: %s",
+		 _PATH_PROC_NET_DEV, strerror (errno));
+      return -1;
+    }
+
+  /* Drop header lines. */
+  fgets (buf, PROCBUFSIZ, fp);
+  fgets (buf, PROCBUFSIZ, fp);
+
+  /* Only allocate interface structure.  Other jobs will be done in
+     if_ioctl.c. */
+  while (fgets (buf, PROCBUFSIZ, fp) != NULL)
+    {
+      interface_name_cut (buf, &name);
+      ifp = if_get_by_name (name);
+      if_add_update (ifp);
+    }
+  return 0;
+}
+
+#if defined(HAVE_IPV6) && defined(HAVE_PROC_NET_IF_INET6)
+
+#ifndef _PATH_PROC_NET_IF_INET6
+#define _PATH_PROC_NET_IF_INET6          "/proc/net/if_inet6"
+#endif /* _PATH_PROC_NET_IF_INET6 */
+
+int
+ifaddr_proc_ipv6 ()
+{
+  FILE *fp;
+  char buf[PROCBUFSIZ];
+  int n;
+  char addr[33];
+  char ifname[20];
+  int ifindex, plen, scope, status;
+  struct interface *ifp;
+  struct prefix_ipv6 p;
+
+  /* Open proc file system. */
+  fp = fopen (_PATH_PROC_NET_IF_INET6, "r");
+  if (fp == NULL)
+    {
+      zlog_warn ("Can't open proc file %s: %s",
+		 _PATH_PROC_NET_IF_INET6, strerror (errno));
+      return -1;
+    }
+  
+  /* Get interface's IPv6 address. */
+  while (fgets (buf, PROCBUFSIZ, fp) != NULL)
+    {
+      n = sscanf (buf, "%32s %02x %02x %02x %02x %20s", 
+		  addr, &ifindex, &plen, &scope, &status, ifname);
+      if (n != 6)
+	continue;
+
+      ifp = if_get_by_name (ifname);
+
+      /* Fetch interface's IPv6 address. */
+      str2in6_addr (addr, &p.prefix);
+      p.prefixlen = plen;
+
+      connected_add_ipv6 (ifp, &p.prefix, p.prefixlen, NULL);
+    }
+  return 0;
+}
+#endif /* HAVE_IPV6 && HAVE_PROC_NET_IF_INET6 */
diff --git a/zebra/if_sysctl.c b/zebra/if_sysctl.c
new file mode 100644
index 0000000..1441dfc
--- /dev/null
+++ b/zebra/if_sysctl.c
@@ -0,0 +1,148 @@
+/*
+ * Get interface's address and mask information by sysctl() function.
+ * Copyright (C) 1997, 98 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 "if.h"
+#include "sockunion.h"
+#include "prefix.h"
+#include "connected.h"
+#include "memory.h"
+#include "ioctl.h"
+#include "log.h"
+
+int
+ifstat_update_sysctl ()
+{
+  caddr_t ref, buf, end;
+  size_t bufsiz;
+  struct if_msghdr *ifm;
+  struct interface *ifp;
+
+#define MIBSIZ 6
+  int mib[MIBSIZ] =
+  { 
+    CTL_NET,
+    PF_ROUTE,
+    0,
+    0, /*  AF_INET & AF_INET6 */
+    NET_RT_IFLIST,
+    0 
+  };
+
+  /* Query buffer size. */
+  if (sysctl (mib, MIBSIZ, NULL, &bufsiz, NULL, 0) < 0) 
+    {
+      zlog_warn ("sysctl() error by %s", strerror (errno));
+      return -1;
+    }
+
+  /* We free this memory at the end of this function. */
+  ref = buf = XMALLOC (MTYPE_TMP, bufsiz);
+
+  /* Fetch interface informations into allocated buffer. */
+  if (sysctl (mib, MIBSIZ, buf, &bufsiz, NULL, 0) < 0) 
+    {
+      zlog (NULL, LOG_WARNING, "sysctl error by %s", strerror (errno));
+      return -1;
+    }
+
+  /* Parse both interfaces and addresses. */
+  for (end = buf + bufsiz; buf < end; buf += ifm->ifm_msglen) 
+    {
+      ifm = (struct if_msghdr *) buf;
+      if (ifm->ifm_type == RTM_IFINFO)
+	{
+	  ifp = if_lookup_by_index (ifm->ifm_index);
+	  if (ifp)
+	    ifp->stats = ifm->ifm_data;
+	}
+    }
+
+  /* Free sysctl buffer. */
+  XFREE (MTYPE_TMP, ref);
+
+  return 0;
+}
+
+/* Interface listing up function using sysctl(). */
+void
+interface_list ()
+{
+  caddr_t ref, buf, end;
+  size_t bufsiz;
+  struct if_msghdr *ifm;
+  int ifm_read (struct if_msghdr *);
+  int ifam_read (struct ifa_msghdr *);
+
+#define MIBSIZ 6
+  int mib[MIBSIZ] =
+  { 
+    CTL_NET,
+    PF_ROUTE,
+    0,
+    0, /*  AF_INET & AF_INET6 */
+    NET_RT_IFLIST,
+    0 
+  };
+
+  /* Query buffer size. */
+  if (sysctl (mib, MIBSIZ, NULL, &bufsiz, NULL, 0) < 0) 
+    {
+      zlog (NULL, LOG_WARNING, "sysctl() error by %s", strerror (errno));
+      return;
+    }
+
+  /* We free this memory at the end of this function. */
+  ref = buf = XMALLOC (MTYPE_TMP, bufsiz);
+
+  /* Fetch interface informations into allocated buffer. */
+  if (sysctl (mib, MIBSIZ, buf, &bufsiz, NULL, 0) < 0) 
+    {
+      zlog (NULL, LOG_WARNING, "sysctl error by %s", strerror (errno));
+      return;
+    }
+
+  /* Parse both interfaces and addresses. */
+  for (end = buf + bufsiz; buf < end; buf += ifm->ifm_msglen) 
+    {
+      ifm = (struct if_msghdr *) buf;
+
+      switch (ifm->ifm_type) 
+	{
+	case RTM_IFINFO:
+	  ifm_read (ifm);
+	  break;
+	case RTM_NEWADDR:
+	  ifam_read ((struct ifa_msghdr *) ifm);
+	  break;
+	default:
+	  zlog_info ("interfaces_list(): unexpected message type");
+	  XFREE (MTYPE_TMP, ref);
+	  return;
+	  break;
+	}
+    }
+
+  /* Free sysctl buffer. */
+  XFREE (MTYPE_TMP, ref);
+}
diff --git a/zebra/interface.c b/zebra/interface.c
new file mode 100644
index 0000000..5629ebb
--- /dev/null
+++ b/zebra/interface.c
@@ -0,0 +1,1387 @@
+/*
+ * Interface function.
+ * Copyright (C) 1997, 1999 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 "if.h"
+#include "vty.h"
+#include "sockunion.h"
+#include "prefix.h"
+#include "command.h"
+#include "memory.h"
+#include "ioctl.h"
+#include "connected.h"
+#include "log.h"
+#include "zclient.h"
+
+#include "zebra/interface.h"
+#include "zebra/rtadv.h"
+#include "zebra/rib.h"
+#include "zebra/zserv.h"
+#include "zebra/redistribute.h"
+#include "zebra/debug.h"
+
+/* Allocate a new internal interface index 
+ * This works done from the top so that %d macros
+ * print a - sign! 
+ */
+static unsigned int
+if_new_intern_ifindex (void)
+{
+  /* Start here so that first one assigned is 0xFFFFFFFF */
+  static unsigned int ifindex = IFINDEX_INTERNBASE + 1;
+
+  for (;;) 
+    {
+      ifindex--;
+      if ( ifindex <= IFINDEX_INTERNBASE )
+       ifindex = 0xFFFFFFFF;
+
+      if (if_lookup_by_index(ifindex) == NULL)
+       return ifindex;
+    }
+}
+
+/* Called when new interface is added. */
+int
+if_zebra_new_hook (struct interface *ifp)
+{
+  struct zebra_if *zebra_if;
+
+  zebra_if = XMALLOC (MTYPE_TMP, sizeof (struct zebra_if));
+  memset (zebra_if, 0, sizeof (struct zebra_if));
+
+  zebra_if->multicast = IF_ZEBRA_MULTICAST_UNSPEC;
+  zebra_if->shutdown = IF_ZEBRA_SHUTDOWN_UNSPEC;
+
+#ifdef RTADV
+  {
+    /* Set default router advertise values. */
+    struct rtadvconf *rtadv;
+
+    rtadv = &zebra_if->rtadv;
+
+    rtadv->AdvSendAdvertisements = 0;
+    rtadv->MaxRtrAdvInterval = RTADV_MAX_RTR_ADV_INTERVAL;
+    rtadv->MinRtrAdvInterval = RTADV_MIN_RTR_ADV_INTERVAL;
+    rtadv->AdvIntervalTimer = 0;
+    rtadv->AdvManagedFlag = 0;
+    rtadv->AdvOtherConfigFlag = 0;
+    rtadv->AdvLinkMTU = 0;
+    rtadv->AdvReachableTime = 0;
+    rtadv->AdvRetransTimer = 0;
+    rtadv->AdvCurHopLimit = 0;
+    rtadv->AdvDefaultLifetime = RTADV_ADV_DEFAULT_LIFETIME;
+
+    rtadv->AdvPrefixList = list_new ();
+  }    
+#endif /* RTADV */
+
+  ifp->info = zebra_if;
+  return 0;
+}
+
+/* Called when interface is deleted. */
+int
+if_zebra_delete_hook (struct interface *ifp)
+{
+  if (ifp->info)
+    XFREE (MTYPE_TMP, ifp->info);
+  return 0;
+}
+
+/* Wake up configured address if it is not in current kernel
+   address. */
+void
+if_addr_wakeup (struct interface *ifp)
+{
+  struct listnode *node;
+  struct connected *ifc;
+  struct prefix *p;
+  int ret;
+
+  for (node = listhead (ifp->connected); node; nextnode (node))
+    {
+      ifc = getdata (node);
+      p = ifc->address;
+	
+      if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED)
+	  && ! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
+	{
+	  /* Address check. */
+	  if (p->family == AF_INET)
+	    {
+	      if (! if_is_up (ifp))
+		{
+		  if_set_flags (ifp, IFF_UP | IFF_RUNNING);
+		  if_refresh (ifp);
+		}
+
+	      ret = if_set_prefix (ifp, ifc);
+	      if (ret < 0)
+		{
+		  zlog_warn ("Can't set interface's address: %s", 
+			     strerror(errno));
+		  continue;
+		}
+	      SET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
+
+	      zebra_interface_address_add_update (ifp, ifc);
+
+	      if (if_is_up(ifp))
+		connected_up_ipv4 (ifp, ifc);
+	    }
+#ifdef HAVE_IPV6
+	  if (p->family == AF_INET6)
+	    {
+	      if (! if_is_up (ifp))
+		{
+		  if_set_flags (ifp, IFF_UP | IFF_RUNNING);
+		  if_refresh (ifp);
+		}
+
+	      ret = if_prefix_add_ipv6 (ifp, ifc);
+	      if (ret < 0)
+		{
+		  zlog_warn ("Can't set interface's address: %s", 
+			     strerror(errno));
+		  continue;
+		}
+	      SET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
+
+	      zebra_interface_address_add_update (ifp, ifc);
+
+	      if (if_is_up(ifp))
+		connected_up_ipv6 (ifp, ifc);
+	    }
+#endif /* HAVE_IPV6 */
+	}
+    }
+}
+
+/* Handle interface addition */
+void
+if_add_update (struct interface *ifp)
+{
+  zebra_interface_add_update (ifp);
+
+  if (! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
+    {
+      SET_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE);
+
+      if_addr_wakeup (ifp);
+
+      if (IS_ZEBRA_DEBUG_KERNEL)
+	zlog_info ("interface %s index %d becomes active.", 
+		   ifp->name, ifp->ifindex);
+    }
+  else
+    {
+      if (IS_ZEBRA_DEBUG_KERNEL)
+	zlog_info ("interface %s index %d is added.", ifp->name, ifp->ifindex);
+    }
+}
+
+/* Handle an interface delete event */
+void 
+if_delete_update (struct interface *ifp)
+{
+  struct listnode *node;
+  struct listnode *next;
+  struct connected *ifc;
+  struct prefix *p;
+
+  if (if_is_up(ifp))
+    {
+      zlog_err ("interface %s index %d is still up while being deleted.",
+	    ifp->name, ifp->ifindex);
+      return;
+    }
+
+  /* Mark interface as inactive */
+  UNSET_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE);
+  
+  if (IS_ZEBRA_DEBUG_KERNEL)
+    zlog_info ("interface %s index %d is now inactive.",
+	       ifp->name, ifp->ifindex);
+
+  /* Delete connected routes from the kernel. */
+  if (ifp->connected)
+    {
+      for (node = listhead (ifp->connected); node; node = next)
+	{
+	  next = node->next;
+	  ifc = getdata (node);
+	  p = ifc->address;
+
+	  if (p->family == AF_INET)
+	    connected_down_ipv4 (ifp, ifc);
+#ifdef HAVE_IPV6
+	  else if (p->family == AF_INET6)
+	    connected_down_ipv6 (ifp, ifc);
+#endif /* HAVE_IPV6 */
+
+	  zebra_interface_address_delete_update (ifp, ifc);
+
+	  UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
+	  
+	  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
+	    {      
+	      listnode_delete (ifp->connected, ifc);
+	      connected_free (ifc);
+	    }
+	}
+    }
+  zebra_interface_delete_update (ifp);
+}
+
+/* Interface is up. */
+void
+if_up (struct interface *ifp)
+{
+  listnode node;
+  listnode next;
+  struct connected *ifc;
+  struct prefix *p;
+
+  /* Notify the protocol daemons. */
+  zebra_interface_up_update (ifp);
+
+  /* Install connected routes to the kernel. */
+  if (ifp->connected)
+    {
+      for (node = listhead (ifp->connected); node; node = next)
+	{
+	  next = node->next;
+	  ifc = getdata (node);
+	  p = ifc->address;
+
+	  if (p->family == AF_INET)
+	    connected_up_ipv4 (ifp, ifc);
+#ifdef HAVE_IPV6
+	  else if (p->family == AF_INET6)
+	    connected_up_ipv6 (ifp, ifc);
+#endif /* HAVE_IPV6 */
+	}
+    }
+
+  /* Examine all static routes. */
+  rib_update ();
+}
+
+/* Interface goes down.  We have to manage different behavior of based
+   OS. */
+void
+if_down (struct interface *ifp)
+{
+  listnode node;
+  listnode next;
+  struct connected *ifc;
+  struct prefix *p;
+
+  /* Notify to the protocol daemons. */
+  zebra_interface_down_update (ifp);
+
+  /* Delete connected routes from the kernel. */
+  if (ifp->connected)
+    {
+      for (node = listhead (ifp->connected); node; node = next)
+	{
+	  next = node->next;
+	  ifc = getdata (node);
+	  p = ifc->address;
+
+	  if (p->family == AF_INET)
+	    connected_down_ipv4 (ifp, ifc);
+#ifdef HAVE_IPV6
+	  else if (p->family == AF_INET6)
+	    connected_down_ipv6 (ifp, ifc);
+#endif /* HAVE_IPV6 */
+	}
+    }
+
+  /* Examine all static routes which direct to the interface. */
+  rib_update ();
+}
+
+void
+if_refresh (struct interface *ifp)
+{
+  if (if_is_up (ifp))
+    {
+      if_get_flags (ifp);
+      if (! if_is_up (ifp))
+	if_down (ifp);
+    }
+  else
+    {
+      if_get_flags (ifp);
+      if (if_is_up (ifp))
+	if_up (ifp);
+    }
+}
+
+/* Printout flag information into vty */
+void
+if_flag_dump_vty (struct vty *vty, unsigned long flag)
+{
+  int separator = 0;
+
+#define IFF_OUT_VTY(X, Y) \
+  if ((X) && (flag & (X))) \
+    { \
+      if (separator) \
+	vty_out (vty, ","); \
+      else \
+	separator = 1; \
+      vty_out (vty, Y); \
+    }
+
+  vty_out (vty, "<");
+  IFF_OUT_VTY (IFF_UP, "UP");
+  IFF_OUT_VTY (IFF_BROADCAST, "BROADCAST");
+  IFF_OUT_VTY (IFF_DEBUG, "DEBUG");
+  IFF_OUT_VTY (IFF_LOOPBACK, "LOOPBACK");
+  IFF_OUT_VTY (IFF_POINTOPOINT, "POINTOPOINT");
+  IFF_OUT_VTY (IFF_NOTRAILERS, "NOTRAILERS");
+  IFF_OUT_VTY (IFF_RUNNING, "RUNNING");
+  IFF_OUT_VTY (IFF_NOARP, "NOARP");
+  IFF_OUT_VTY (IFF_PROMISC, "PROMISC");
+  IFF_OUT_VTY (IFF_ALLMULTI, "ALLMULTI");
+  IFF_OUT_VTY (IFF_OACTIVE, "OACTIVE");
+  IFF_OUT_VTY (IFF_SIMPLEX, "SIMPLEX");
+  IFF_OUT_VTY (IFF_LINK0, "LINK0");
+  IFF_OUT_VTY (IFF_LINK1, "LINK1");
+  IFF_OUT_VTY (IFF_LINK2, "LINK2");
+  IFF_OUT_VTY (IFF_MULTICAST, "MULTICAST");
+  vty_out (vty, ">");
+}
+
+/* Output prefix string to vty. */
+int
+prefix_vty_out (struct vty *vty, struct prefix *p)
+{
+  char str[INET6_ADDRSTRLEN];
+
+  inet_ntop (p->family, &p->u.prefix, str, sizeof (str));
+  vty_out (vty, "%s", str);
+  return strlen (str);
+}
+
+/* Dump if address information to vty. */
+void
+connected_dump_vty (struct vty *vty, struct connected *connected)
+{
+  struct prefix *p;
+  struct interface *ifp;
+
+  /* Set interface pointer. */
+  ifp = connected->ifp;
+
+  /* Print interface address. */
+  p = connected->address;
+  vty_out (vty, "  %s ", prefix_family_str (p));
+  prefix_vty_out (vty, p);
+  vty_out (vty, "/%d", p->prefixlen);
+
+  /* If there is destination address, print it. */
+  p = connected->destination;
+  if (p)
+    {
+      if (p->family == AF_INET)
+	if (ifp->flags & IFF_BROADCAST)
+	  {
+	    vty_out (vty, " broadcast ");
+	    prefix_vty_out (vty, p);
+	  }
+
+      if (ifp->flags & IFF_POINTOPOINT)
+	{
+	  vty_out (vty, " pointopoint ");
+	  prefix_vty_out (vty, p);
+	}
+    }
+
+  if (CHECK_FLAG (connected->flags, ZEBRA_IFA_SECONDARY))
+    vty_out (vty, " secondary");
+
+  if (connected->label)
+    vty_out (vty, " %s", connected->label);
+
+  vty_out (vty, "%s", VTY_NEWLINE);
+}
+
+#ifdef RTADV
+/* Dump interface ND information to vty. */
+void
+nd_dump_vty (struct vty *vty, struct interface *ifp)
+{
+  struct zebra_if *zif;
+  struct rtadvconf *rtadv;
+
+  zif = (struct zebra_if *) ifp->info;
+  rtadv = &zif->rtadv;
+
+  if (rtadv->AdvSendAdvertisements)
+    {
+      vty_out (vty, "  ND advertised reachable time is %d milliseconds%s",
+	       rtadv->AdvReachableTime, VTY_NEWLINE);
+      vty_out (vty, "  ND advertised retransmit interval is %d milliseconds%s",
+	       rtadv->AdvRetransTimer, VTY_NEWLINE);
+      vty_out (vty, "  ND router advertisements are sent every %d seconds%s",
+	       rtadv->MaxRtrAdvInterval, VTY_NEWLINE);
+      vty_out (vty, "  ND router advertisements live for %d seconds%s",
+	       rtadv->AdvDefaultLifetime, VTY_NEWLINE);
+      if (rtadv->AdvManagedFlag)
+	vty_out (vty, "  Hosts use DHCP to obtain routable addresses.%s",
+		 VTY_NEWLINE);
+      else
+	vty_out (vty, "  Hosts use stateless autoconfig for addresses.%s",
+		 VTY_NEWLINE);
+    }
+}
+#endif /* RTADV */
+
+/* Interface's information print out to vty interface. */
+void
+if_dump_vty (struct vty *vty, struct interface *ifp)
+{
+#ifdef HAVE_SOCKADDR_DL
+  struct sockaddr_dl *sdl;
+#endif /* HAVE_SOCKADDR_DL */
+  struct connected *connected;
+  listnode node;
+
+  vty_out (vty, "Interface %s%s", ifp->name,
+	   VTY_NEWLINE);
+  if (ifp->desc)
+    vty_out (vty, "  Description: %s%s", ifp->desc,
+	     VTY_NEWLINE);
+  if (ifp->ifindex <= 0)
+    {
+      vty_out(vty, "  index %d pseudo interface%s", ifp->ifindex, VTY_NEWLINE);
+      return;
+    }
+  else if (! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
+    {
+      vty_out(vty, "  index %d inactive interface%s", 
+	      ifp->ifindex, 
+	      VTY_NEWLINE);
+      return;
+    }
+
+  vty_out (vty, "  index %d metric %d mtu %d ",
+	   ifp->ifindex, ifp->metric, ifp->mtu);
+  if_flag_dump_vty (vty, ifp->flags);
+  vty_out (vty, "%s", VTY_NEWLINE);
+
+  /* Hardware address. */
+#ifdef HAVE_SOCKADDR_DL
+  sdl = &ifp->sdl;
+  if (sdl != NULL && sdl->sdl_alen != 0)
+    {
+      int i;
+      u_char *ptr;
+
+      vty_out (vty, "  HWaddr: ");
+      for (i = 0, ptr = LLADDR (sdl); i < sdl->sdl_alen; i++, ptr++)
+	vty_out (vty, "%s%02x", i == 0 ? "" : ":", *ptr);
+      vty_out (vty, "%s", VTY_NEWLINE);
+    }
+#else
+  if (ifp->hw_addr_len != 0)
+    {
+      int i;
+
+      vty_out (vty, "  HWaddr: ");
+      for (i = 0; i < ifp->hw_addr_len; i++)
+	vty_out (vty, "%s%02x", i == 0 ? "" : ":", ifp->hw_addr[i]);
+      vty_out (vty, "%s", VTY_NEWLINE);
+    }
+#endif /* HAVE_SOCKADDR_DL */
+  
+  /* Bandwidth in kbps */
+  if (ifp->bandwidth != 0)
+    {
+      vty_out(vty, "  bandwidth %u kbps", ifp->bandwidth);
+      vty_out(vty, "%s", VTY_NEWLINE);
+    }
+
+  for (node = listhead (ifp->connected); node; nextnode (node))
+    {
+      connected = getdata (node);
+      if (CHECK_FLAG (connected->conf, ZEBRA_IFC_REAL))
+	connected_dump_vty (vty, connected);
+    }
+
+#ifdef RTADV
+  nd_dump_vty (vty, ifp);
+#endif /* RTADV */
+
+#ifdef HAVE_PROC_NET_DEV
+  /* Statistics print out using proc file system. */
+  vty_out (vty, "    input packets %lu, bytes %lu, dropped %lu,"
+	   " multicast packets %lu%s",
+	   ifp->stats.rx_packets, ifp->stats.rx_bytes, 
+	   ifp->stats.rx_dropped, ifp->stats.rx_multicast, VTY_NEWLINE);
+
+  vty_out (vty, "    input errors %lu, length %lu, overrun %lu,"
+	   " CRC %lu, frame %lu, fifo %lu, missed %lu%s",
+	   ifp->stats.rx_errors, ifp->stats.rx_length_errors,
+	   ifp->stats.rx_over_errors, ifp->stats.rx_crc_errors,
+	   ifp->stats.rx_frame_errors, ifp->stats.rx_fifo_errors,
+	   ifp->stats.rx_missed_errors, VTY_NEWLINE);
+
+  vty_out (vty, "    output packets %lu, bytes %lu, dropped %lu%s",
+	   ifp->stats.tx_packets, ifp->stats.tx_bytes,
+	   ifp->stats.tx_dropped, VTY_NEWLINE);
+
+  vty_out (vty, "    output errors %lu, aborted %lu, carrier %lu,"
+	   " fifo %lu, heartbeat %lu, window %lu%s",
+	   ifp->stats.tx_errors, ifp->stats.tx_aborted_errors,
+	   ifp->stats.tx_carrier_errors, ifp->stats.tx_fifo_errors,
+	   ifp->stats.tx_heartbeat_errors, ifp->stats.tx_window_errors,
+	   VTY_NEWLINE);
+
+  vty_out (vty, "    collisions %lu%s", ifp->stats.collisions, VTY_NEWLINE);
+#endif /* HAVE_PROC_NET_DEV */
+
+#ifdef HAVE_NET_RT_IFLIST
+#if defined (__bsdi__) || defined (__NetBSD__)
+  /* Statistics print out using sysctl (). */
+  vty_out (vty, "    input packets %qu, bytes %qu, dropped %qu,"
+	   " multicast packets %qu%s",
+	   ifp->stats.ifi_ipackets, ifp->stats.ifi_ibytes,
+	   ifp->stats.ifi_iqdrops, ifp->stats.ifi_imcasts,
+	   VTY_NEWLINE);
+
+  vty_out (vty, "    input errors %qu%s",
+	   ifp->stats.ifi_ierrors, VTY_NEWLINE);
+
+  vty_out (vty, "    output packets %qu, bytes %qu, multicast packets %qu%s",
+	   ifp->stats.ifi_opackets, ifp->stats.ifi_obytes,
+	   ifp->stats.ifi_omcasts, VTY_NEWLINE);
+
+  vty_out (vty, "    output errors %qu%s",
+	   ifp->stats.ifi_oerrors, VTY_NEWLINE);
+
+  vty_out (vty, "    collisions %qu%s",
+	   ifp->stats.ifi_collisions, VTY_NEWLINE);
+#else
+  /* Statistics print out using sysctl (). */
+  vty_out (vty, "    input packets %lu, bytes %lu, dropped %lu,"
+	   " multicast packets %lu%s",
+	   ifp->stats.ifi_ipackets, ifp->stats.ifi_ibytes,
+	   ifp->stats.ifi_iqdrops, ifp->stats.ifi_imcasts,
+	   VTY_NEWLINE);
+
+  vty_out (vty, "    input errors %lu%s",
+	   ifp->stats.ifi_ierrors, VTY_NEWLINE);
+
+  vty_out (vty, "    output packets %lu, bytes %lu, multicast packets %lu%s",
+	   ifp->stats.ifi_opackets, ifp->stats.ifi_obytes,
+	   ifp->stats.ifi_omcasts, VTY_NEWLINE);
+
+  vty_out (vty, "    output errors %lu%s",
+	   ifp->stats.ifi_oerrors, VTY_NEWLINE);
+
+  vty_out (vty, "    collisions %lu%s",
+	   ifp->stats.ifi_collisions, VTY_NEWLINE);
+#endif /* __bsdi__ || __NetBSD__ */
+#endif /* HAVE_NET_RT_IFLIST */
+}
+
+/* Check supported address family. */
+int
+if_supported_family (int family)
+{
+  if (family == AF_INET)
+    return 1;
+#ifdef HAVE_IPV6
+  if (family == AF_INET6)
+    return 1;
+#endif /* HAVE_IPV6 */
+  return 0;
+}
+
+/* Wrapper hook point for zebra daemon so that ifindex can be set 
+ * DEFUN macro not used as extract.pl HAS to ignore this
+ * See also interface_cmd in lib/if.c
+ */ 
+DEFUN_NOSH (zebra_interface,
+	    zebra_interface_cmd,
+	    "interface IFNAME",
+	    "Select an interface to configure\n"
+	    "Interface's name\n")
+{
+  int ret;
+  struct interface * ifp;
+  
+  /* Call lib interface() */
+  ret = interface_cmd.func (self, vty, argc, argv);
+
+  ifp = vty->index;  
+
+  /* Set ifindex 
+     this only happens if interface is NOT in kernel */
+  if (ifp->ifindex == 0)
+    {
+      ifp->ifindex = if_new_intern_ifindex ();
+      UNSET_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE);
+    }
+
+  return ret;
+}
+
+DEFUN (no_zebra_interface,
+       no_zebra_interface_cmd,
+       "no interface IFNAME",
+       "Delete a pseudo interface's configuration\n"
+       "Interface's name\n")
+{
+  struct interface *ifp;
+  
+  ifp = if_lookup_by_name(argv[0]);
+  
+  if (ifp == NULL) 
+    {
+      vty_out (vty, "Inteface %s does not exist%s", 
+              argv[0],
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
+    {
+      vty_out(vty, "Only inactive interfaces can be deleted%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Delete interface */
+  if_delete(ifp);
+
+  return CMD_SUCCESS;
+} 
+
+struct cmd_node interface_node =
+{
+  INTERFACE_NODE,
+  "%s(config-if)# ",
+  1
+};
+
+/* Show all or specified interface to vty. */
+DEFUN (show_interface, show_interface_cmd,
+       "show interface [IFNAME]",  
+       SHOW_STR
+       "Interface status and configuration\n"
+       "Inteface name\n")
+{
+  listnode node;
+  struct interface *ifp;
+  
+#ifdef HAVE_PROC_NET_DEV
+  /* If system has interface statistics via proc file system, update
+     statistics. */
+  ifstat_update_proc ();
+#endif /* HAVE_PROC_NET_DEV */
+#ifdef HAVE_NET_RT_IFLIST
+  ifstat_update_sysctl ();
+#endif /* HAVE_NET_RT_IFLIST */
+
+  /* Specified interface print. */
+  if (argc != 0)
+    {
+      ifp = if_lookup_by_name (argv[0]);
+      if (ifp == NULL) 
+	{
+	  vty_out (vty, "%% Can't find interface %s%s", argv[0],
+		   VTY_NEWLINE);
+	  return CMD_WARNING;
+	}
+      if_dump_vty (vty, ifp);
+      return CMD_SUCCESS;
+    }
+
+  /* All interface print. */
+  for (node = listhead (iflist); node; nextnode (node))
+    if_dump_vty (vty, getdata (node));
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (multicast,
+       multicast_cmd,
+       "multicast",
+       "Set multicast flag to interface\n")
+{
+  int ret;
+  struct interface *ifp;
+  struct zebra_if *if_data;
+
+  ifp = (struct interface *) vty->index;
+  ret = if_set_flags (ifp, IFF_MULTICAST);
+  if (ret < 0)
+    {
+      vty_out (vty, "Can't set multicast flag%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  if_refresh (ifp);
+  if_data = ifp->info;
+  if_data->multicast = IF_ZEBRA_MULTICAST_ON;
+  
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_multicast,
+       no_multicast_cmd,
+       "no multicast",
+       NO_STR
+       "Unset multicast flag to interface\n")
+{
+  int ret;
+  struct interface *ifp;
+  struct zebra_if *if_data;
+
+  ifp = (struct interface *) vty->index;
+  ret = if_unset_flags (ifp, IFF_MULTICAST);
+  if (ret < 0)
+    {
+      vty_out (vty, "Can't unset multicast flag%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  if_refresh (ifp);
+  if_data = ifp->info;
+  if_data->multicast = IF_ZEBRA_MULTICAST_OFF;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (shutdown_if,
+       shutdown_if_cmd,
+       "shutdown",
+       "Shutdown the selected interface\n")
+{
+  int ret;
+  struct interface *ifp;
+  struct zebra_if *if_data;
+
+  ifp = (struct interface *) vty->index;
+  ret = if_unset_flags (ifp, IFF_UP);
+  if (ret < 0)
+    {
+      vty_out (vty, "Can't shutdown interface%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  if_refresh (ifp);
+  if_data = ifp->info;
+  if_data->shutdown = IF_ZEBRA_SHUTDOWN_ON;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_shutdown_if,
+       no_shutdown_if_cmd,
+       "no shutdown",
+       NO_STR
+       "Shutdown the selected interface\n")
+{
+  int ret;
+  struct interface *ifp;
+  struct zebra_if *if_data;
+
+  ifp = (struct interface *) vty->index;
+  ret = if_set_flags (ifp, IFF_UP | IFF_RUNNING);
+  if (ret < 0)
+    {
+      vty_out (vty, "Can't up interface%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  if_refresh (ifp);
+  if_data = ifp->info;
+  if_data->shutdown = IF_ZEBRA_SHUTDOWN_OFF;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (bandwidth_if,
+       bandwidth_if_cmd,
+       "bandwidth <1-10000000>",
+       "Set bandwidth informational parameter\n"
+       "Bandwidth in kilobits\n")
+{
+  struct interface *ifp;   
+  unsigned int bandwidth;
+  
+  ifp = (struct interface *) vty->index;
+  bandwidth = strtol(argv[0], NULL, 10);
+
+  /* bandwidth range is <1-10000000> */
+  if (bandwidth < 1 || bandwidth > 10000000)
+    {
+      vty_out (vty, "Bandwidth is invalid%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  
+  ifp->bandwidth = bandwidth;
+
+  /* force protocols to recalculate routes due to cost change */
+  if (if_is_up (ifp))
+    zebra_interface_up_update (ifp);
+  
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_bandwidth_if,
+       no_bandwidth_if_cmd,
+       "no bandwidth",
+       NO_STR
+       "Set bandwidth informational parameter\n")
+{
+  struct interface *ifp;   
+  
+  ifp = (struct interface *) vty->index;
+
+  ifp->bandwidth = 0;
+  
+  /* force protocols to recalculate routes due to cost change */
+  if (if_is_up (ifp))
+    zebra_interface_up_update (ifp);
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_bandwidth_if,
+       no_bandwidth_if_val_cmd,
+       "no bandwidth <1-10000000>",
+       NO_STR
+       "Set bandwidth informational parameter\n"
+       "Bandwidth in kilobits\n")
+
+int
+ip_address_install (struct vty *vty, struct interface *ifp, char *addr_str,
+		    char *peer_str, char *label, int secondary)
+{
+  struct prefix_ipv4 cp;
+  struct connected *ifc;
+  struct prefix_ipv4 *p;
+  struct in_addr mask;
+  int ret;
+
+  ret = str2prefix_ipv4 (addr_str, &cp);
+  if (ret <= 0)
+    {
+      vty_out (vty, "%% Malformed address %s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ifc = connected_check_ipv4 (ifp, (struct prefix *) &cp);
+  if (! ifc)
+    {
+      ifc = connected_new ();
+      ifc->ifp = ifp;
+
+      /* Address. */
+      p = prefix_ipv4_new ();
+      *p = cp;
+      ifc->address = (struct prefix *) p;
+
+      /* Broadcast. */
+      if (p->prefixlen <= 30)
+	{
+	  p = prefix_ipv4_new ();
+	  *p = cp;
+	  masklen2ip (p->prefixlen, &mask);
+	  p->prefix.s_addr |= ~mask.s_addr;
+	  ifc->destination = (struct prefix *) p;
+	}
+
+      /* Secondary. */
+      if (secondary)
+	SET_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY);
+
+      /* Label. */
+      if (label)
+	ifc->label = strdup (label);
+
+      /* Add to linked list. */
+      listnode_add (ifp->connected, ifc);
+    }
+
+  /* This address is configured from zebra. */
+  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
+    SET_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED);
+
+  /* In case of this route need to install kernel. */
+  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)
+      && CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
+    {
+      /* Some system need to up the interface to set IP address. */
+      if (! if_is_up (ifp))
+	{
+	  if_set_flags (ifp, IFF_UP | IFF_RUNNING);
+	  if_refresh (ifp);
+	}
+
+      ret = if_set_prefix (ifp, ifc);
+      if (ret < 0)
+	{
+	  vty_out (vty, "%% Can't set interface IP address: %s.%s", 
+		   strerror(errno), VTY_NEWLINE);
+	  return CMD_WARNING;
+	}
+
+      /* IP address propery set. */
+      SET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
+
+      /* Update interface address information to protocol daemon. */
+      zebra_interface_address_add_update (ifp, ifc);
+
+      /* If interface is up register connected route. */
+      if (if_is_up(ifp))
+	connected_up_ipv4 (ifp, ifc);
+    }
+
+  return CMD_SUCCESS;
+}
+
+int
+ip_address_uninstall (struct vty *vty, struct interface *ifp, char *addr_str,
+		      char *peer_str, char *label, int secondry)
+{
+  struct prefix_ipv4 cp;
+  struct connected *ifc;
+  int ret;
+
+  /* Convert to prefix structure. */
+  ret = str2prefix_ipv4 (addr_str, &cp);
+  if (ret <= 0)
+    {
+      vty_out (vty, "%% Malformed address %s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Check current interface address. */
+  ifc = connected_check_ipv4 (ifp, (struct prefix *) &cp);
+  if (! ifc)
+    {
+      vty_out (vty, "%% Can't find address%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* This is not configured address. */
+  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
+    return CMD_WARNING;
+
+  /* This is not real address or interface is not active. */
+  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)
+      || ! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
+    {
+      listnode_delete (ifp->connected, ifc);
+      connected_free (ifc);
+      return CMD_WARNING;
+    }
+
+  /* This is real route. */
+  ret = if_unset_prefix (ifp, ifc);
+  if (ret < 0)
+    {
+      vty_out (vty, "%% Can't unset interface IP address: %s.%s", 
+	       strerror(errno), VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Redistribute this information. */
+  zebra_interface_address_delete_update (ifp, ifc);
+
+  /* Remove connected route. */
+  connected_down_ipv4 (ifp, ifc);
+
+  /* Free address information. */
+  listnode_delete (ifp->connected, ifc);
+  connected_free (ifc);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ip_address,
+       ip_address_cmd,
+       "ip address A.B.C.D/M",
+       "Interface Internet Protocol config commands\n"
+       "Set the IP address of an interface\n"
+       "IP address (e.g. 10.0.0.1/8)\n")
+{
+  return ip_address_install (vty, vty->index, argv[0], NULL, NULL, 0);
+}
+
+DEFUN (no_ip_address,
+       no_ip_address_cmd,
+       "no ip address A.B.C.D/M",
+       NO_STR
+       "Interface Internet Protocol config commands\n"
+       "Set the IP address of an interface\n"
+       "IP Address (e.g. 10.0.0.1/8)")
+{
+  return ip_address_uninstall (vty, vty->index, argv[0], NULL, NULL, 0);
+}
+
+#ifdef HAVE_NETLINK
+DEFUN (ip_address_secondary,
+       ip_address_secondary_cmd,
+       "ip address A.B.C.D/M secondary",
+       "Interface Internet Protocol config commands\n"
+       "Set the IP address of an interface\n"
+       "IP address (e.g. 10.0.0.1/8)\n"
+       "Secondary IP address\n")
+{
+  return ip_address_install (vty, vty->index, argv[0], NULL, NULL, 1);
+}
+
+DEFUN (ip_address_label,
+       ip_address_label_cmd,
+       "ip address A.B.C.D/M label LINE",
+       "Interface Internet Protocol config commands\n"
+       "Set the IP address of an interface\n"
+       "IP address (e.g. 10.0.0.1/8)\n"
+       "Label of this address\n"
+       "Label\n")
+{
+  return ip_address_install (vty, vty->index, argv[0], NULL, argv[1], 1);
+}
+
+DEFUN (no_ip_address_secondary,
+       no_ip_address_secondary_cmd,
+       "no ip address A.B.C.D/M secondary",
+       NO_STR
+       "Interface Internet Protocol config commands\n"
+       "Set the IP address of an interface\n"
+       "IP address (e.g. 10.0.0.1/8)\n"
+       "Secondary IP address\n")
+{
+  return ip_address_uninstall (vty, vty->index, argv[0], NULL, NULL, 1);
+}
+
+DEFUN (no_ip_address_label,
+       no_ip_address_label_cmd,
+       "no ip address A.B.C.D/M label LINE",
+       NO_STR
+       "Interface Internet Protocol config commands\n"
+       "Set the IP address of an interface\n"
+       "IP address (e.g. 10.0.0.1/8)\n"
+       "Label of this address\n"
+       "Label\n")
+{
+  return ip_address_uninstall (vty, vty->index, argv[0], NULL, argv[1], 1);
+}
+#endif /* HAVE_NETLINK */
+
+#ifdef HAVE_IPV6
+int
+ipv6_address_install (struct vty *vty, struct interface *ifp, char *addr_str,
+		      char *peer_str, char *label, int secondary)
+{
+  struct prefix_ipv6 cp;
+  struct connected *ifc;
+  struct prefix_ipv6 *p;
+  int ret;
+
+  ret = str2prefix_ipv6 (addr_str, &cp);
+  if (ret <= 0)
+    {
+      vty_out (vty, "%% Malformed address %s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ifc = connected_check_ipv6 (ifp, (struct prefix *) &cp);
+  if (! ifc)
+    {
+      ifc = connected_new ();
+      ifc->ifp = ifp;
+
+      /* Address. */
+      p = prefix_ipv6_new ();
+      *p = cp;
+      ifc->address = (struct prefix *) p;
+
+      /* Secondary. */
+      if (secondary)
+	SET_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY);
+
+      /* Label. */
+      if (label)
+	ifc->label = strdup (label);
+
+      /* Add to linked list. */
+      listnode_add (ifp->connected, ifc);
+    }
+
+  /* This address is configured from zebra. */
+  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
+    SET_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED);
+
+  /* In case of this route need to install kernel. */
+  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)
+      && CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
+    {
+      /* Some system need to up the interface to set IP address. */
+      if (! if_is_up (ifp))
+	{
+	  if_set_flags (ifp, IFF_UP | IFF_RUNNING);
+	  if_refresh (ifp);
+	}
+
+      ret = if_prefix_add_ipv6 (ifp, ifc);
+
+      if (ret < 0)
+	{
+	  vty_out (vty, "%% Can't set interface IP address: %s.%s", 
+		   strerror(errno), VTY_NEWLINE);
+	  return CMD_WARNING;
+	}
+
+      /* IP address propery set. */
+      SET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
+
+      /* Update interface address information to protocol daemon. */
+      zebra_interface_address_add_update (ifp, ifc);
+
+      /* If interface is up register connected route. */
+      if (if_is_up(ifp))
+	connected_up_ipv6 (ifp, ifc);
+    }
+
+  return CMD_SUCCESS;
+}
+
+int
+ipv6_address_uninstall (struct vty *vty, struct interface *ifp, char *addr_str,
+			char *peer_str, char *label, int secondry)
+{
+  struct prefix_ipv6 cp;
+  struct connected *ifc;
+  int ret;
+
+  /* Convert to prefix structure. */
+  ret = str2prefix_ipv6 (addr_str, &cp);
+  if (ret <= 0)
+    {
+      vty_out (vty, "%% Malformed address %s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Check current interface address. */
+  ifc = connected_check_ipv6 (ifp, (struct prefix *) &cp);
+  if (! ifc)
+    {
+      vty_out (vty, "%% Can't find address%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* This is not configured address. */
+  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
+    return CMD_WARNING;
+
+  /* This is not real address or interface is not active. */
+  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)
+      || ! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
+    {
+      listnode_delete (ifp->connected, ifc);
+      connected_free (ifc);
+      return CMD_WARNING;
+    }
+
+  /* This is real route. */
+  ret = if_prefix_delete_ipv6 (ifp, ifc);
+  if (ret < 0)
+    {
+      vty_out (vty, "%% Can't unset interface IP address: %s.%s", 
+	       strerror(errno), VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Redistribute this information. */
+  zebra_interface_address_delete_update (ifp, ifc);
+
+  /* Remove connected route. */
+  connected_down_ipv6 (ifp, ifc);
+
+  /* Free address information. */
+  listnode_delete (ifp->connected, ifc);
+  connected_free (ifc);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ipv6_address,
+       ipv6_address_cmd,
+       "ipv6 address X:X::X:X/M",
+       "Interface Internet Protocol config commands\n"
+       "Set the IP address of an interface\n"
+       "IPv6 address (e.g. 3ffe:506::1/48)\n")
+{
+  return ipv6_address_install (vty, vty->index, argv[0], NULL, NULL, 0);
+}
+
+DEFUN (no_ipv6_address,
+       no_ipv6_address_cmd,
+       "no ipv6 address X:X::X:X/M",
+       NO_STR
+       "Interface Internet Protocol config commands\n"
+       "Set the IP address of an interface\n"
+       "IPv6 address (e.g. 3ffe:506::1/48)\n")
+{
+  return ipv6_address_uninstall (vty, vty->index, argv[0], NULL, NULL, 0);
+}
+#endif /* HAVE_IPV6 */
+
+#ifdef KAME
+DEFUN (ip_tunnel,
+       ip_tunnel_cmd,
+       "ip tunnel IP_address IP_address",
+       "KAME ip tunneling configuration commands\n"
+       "Set FROM IP address and TO IP address\n")
+{
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_tunnel, no_ip_tunnel_cmd,
+       "no ip tunnel",
+       NO_STR
+       "Set FROM IP address and TO IP address\n")
+{
+  return CMD_SUCCESS;
+}
+#endif /* KAME */
+
+int
+if_config_write (struct vty *vty)
+{
+  listnode node;
+  struct interface *ifp;
+  char buf[BUFSIZ];
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      struct zebra_if *if_data;
+      listnode addrnode;
+      struct connected *ifc;
+      struct prefix *p;
+
+      ifp = getdata (node);
+      if_data = ifp->info;
+      
+      vty_out (vty, "interface %s%s", ifp->name,
+	       VTY_NEWLINE);
+
+      if (ifp->desc)
+	vty_out (vty, " description %s%s", ifp->desc,
+		 VTY_NEWLINE);
+
+      /* Assign bandwidth here to avoid unnecessary interface flap
+	 while processing config script */
+      if (ifp->bandwidth != 0)
+	vty_out(vty, " bandwidth %u%s", ifp->bandwidth, VTY_NEWLINE); 
+
+      for (addrnode = listhead (ifp->connected); addrnode; nextnode (addrnode))
+	  {
+	    ifc = getdata (addrnode);
+	    if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
+	      {
+		p = ifc->address;
+		vty_out (vty, " ip%s address %s/%d",
+			 p->family == AF_INET ? "" : "v6",
+			 inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
+			 p->prefixlen);
+
+		if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY))
+		  vty_out (vty, " secondary");
+		  
+		if (ifc->label)
+		  vty_out (vty, " label %s", ifc->label);
+
+		vty_out (vty, "%s", VTY_NEWLINE);
+	      }
+	  }
+
+      if (if_data)
+	{
+	  if (if_data->shutdown == IF_ZEBRA_SHUTDOWN_ON)
+	    vty_out (vty, " shutdown%s", VTY_NEWLINE);
+
+	  if (if_data->multicast != IF_ZEBRA_MULTICAST_UNSPEC)
+	    vty_out (vty, " %smulticast%s",
+		     if_data->multicast == IF_ZEBRA_MULTICAST_ON ? "" : "no ",
+		     VTY_NEWLINE);
+	}
+
+#ifdef RTADV
+      rtadv_config_write (vty, ifp);
+#endif /* RTADV */
+
+      vty_out (vty, "!%s", VTY_NEWLINE);
+    }
+  return 0;
+}
+
+/* Allocate and initialize interface vector. */
+void
+zebra_if_init ()
+{
+  /* Initialize interface and new hook. */
+  if_init ();
+  if_add_hook (IF_NEW_HOOK, if_zebra_new_hook);
+  if_add_hook (IF_DELETE_HOOK, if_zebra_delete_hook);
+  
+  /* Install configuration write function. */
+  install_node (&interface_node, if_config_write);
+
+  install_element (VIEW_NODE, &show_interface_cmd);
+  install_element (ENABLE_NODE, &show_interface_cmd);
+  install_element (CONFIG_NODE, &zebra_interface_cmd);
+  install_element (CONFIG_NODE, &no_zebra_interface_cmd);
+  install_default (INTERFACE_NODE);
+  install_element (INTERFACE_NODE, &interface_desc_cmd);
+  install_element (INTERFACE_NODE, &no_interface_desc_cmd);
+  install_element (INTERFACE_NODE, &multicast_cmd);
+  install_element (INTERFACE_NODE, &no_multicast_cmd);
+  install_element (INTERFACE_NODE, &shutdown_if_cmd);
+  install_element (INTERFACE_NODE, &no_shutdown_if_cmd);
+  install_element (INTERFACE_NODE, &bandwidth_if_cmd);
+  install_element (INTERFACE_NODE, &no_bandwidth_if_cmd);
+  install_element (INTERFACE_NODE, &no_bandwidth_if_val_cmd);
+  install_element (INTERFACE_NODE, &ip_address_cmd);
+  install_element (INTERFACE_NODE, &no_ip_address_cmd);
+#ifdef HAVE_IPV6
+  install_element (INTERFACE_NODE, &ipv6_address_cmd);
+  install_element (INTERFACE_NODE, &no_ipv6_address_cmd);
+#endif /* HAVE_IPV6 */
+#ifdef KAME
+  install_element (INTERFACE_NODE, &ip_tunnel_cmd);
+  install_element (INTERFACE_NODE, &no_ip_tunnel_cmd);
+#endif /* KAME */
+#ifdef HAVE_NETLINK
+  install_element (INTERFACE_NODE, &ip_address_secondary_cmd);
+  install_element (INTERFACE_NODE, &ip_address_label_cmd);
+  install_element (INTERFACE_NODE, &no_ip_address_secondary_cmd);
+  install_element (INTERFACE_NODE, &no_ip_address_label_cmd);
+#endif /* HAVE_NETLINK */
+}
diff --git a/zebra/interface.h b/zebra/interface.h
new file mode 100644
index 0000000..dbfa822
--- /dev/null
+++ b/zebra/interface.h
@@ -0,0 +1,180 @@
+/* Interface function header.
+ * Copyright (C) 1999 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.  
+ */
+
+/* For interface multicast configuration. */
+#define IF_ZEBRA_MULTICAST_UNSPEC 0
+#define IF_ZEBRA_MULTICAST_ON     1
+#define IF_ZEBRA_MULTICAST_OFF    2
+
+/* For interface shutdown configuration. */
+#define IF_ZEBRA_SHUTDOWN_UNSPEC 0
+#define IF_ZEBRA_SHUTDOWN_ON     1
+#define IF_ZEBRA_SHUTDOWN_OFF    2
+
+/* Router advertisement feature. */
+#if (defined(LINUX_IPV6) && (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1)) || defined(KAME)
+#define RTADV
+#endif
+
+#ifdef RTADV
+/* Router advertisement parameter.  From RFC2461. */
+struct rtadvconf
+{
+  /* A flag indicating whether or not the router sends periodic Router
+     Advertisements and responds to Router Solicitations.
+     Default: FALSE */
+  int AdvSendAdvertisements;
+
+  /* The maximum time allowed between sending unsolicited multicast
+     Router Advertisements from the interface, in seconds.  MUST be no
+     less than 4 seconds and no greater than 1800 seconds. 
+
+     Default: 600 seconds */
+  int MaxRtrAdvInterval;
+#define RTADV_MAX_RTR_ADV_INTERVAL 600
+
+  /* The minimum time allowed between sending unsolicited multicast
+     Router Advertisements from the interface, in seconds.  MUST be no
+     less than 3 seconds and no greater than .75 * MaxRtrAdvInterval.
+
+     Default: 0.33 * MaxRtrAdvInterval */
+  int MinRtrAdvInterval;
+#define RTADV_MIN_RTR_ADV_INTERVAL (0.33 * RTADV_MAX_RTR_ADV_INTERVAL)
+
+  /* Unsolicited Router Advertisements' interval timer. */
+  int AdvIntervalTimer;
+
+  /* The TRUE/FALSE value to be placed in the "Managed address
+     configuration" flag field in the Router Advertisement.  See
+     [ADDRCONF].
+ 
+     Default: FALSE */
+  int AdvManagedFlag;
+
+
+  /* The TRUE/FALSE value to be placed in the "Other stateful
+     configuration" flag field in the Router Advertisement.  See
+     [ADDRCONF].
+
+     Default: FALSE */
+  int AdvOtherConfigFlag;
+
+  /* The value to be placed in MTU options sent by the router.  A
+     value of zero indicates that no MTU options are sent.
+
+     Default: 0 */
+  int AdvLinkMTU;
+
+
+  /* The value to be placed in the Reachable Time field in the Router
+     Advertisement messages sent by the router.  The value zero means
+     unspecified (by this router).  MUST be no greater than 3,600,000
+     milliseconds (1 hour).
+
+     Default: 0 */
+  u_int32_t AdvReachableTime;
+#define RTADV_MAX_REACHABLE_TIME 3600000
+
+
+  /* The value to be placed in the Retrans Timer field in the Router
+     Advertisement messages sent by the router.  The value zero means
+     unspecified (by this router).
+
+     Default: 0 */
+  int AdvRetransTimer;
+
+  /* The default value to be placed in the Cur Hop Limit field in the
+     Router Advertisement messages sent by the router.  The value
+     should be set to that current diameter of the Internet.  The
+     value zero means unspecified (by this router).
+
+     Default: The value specified in the "Assigned Numbers" RFC
+     [ASSIGNED] that was in effect at the time of implementation. */
+  int AdvCurHopLimit;
+
+  /* The value to be placed in the Router Lifetime field of Router
+     Advertisements sent from the interface, in seconds.  MUST be
+     either zero or between MaxRtrAdvInterval and 9000 seconds.  A
+     value of zero indicates that the router is not to be used as a
+     default router.
+
+     Default: 3 * MaxRtrAdvInterval */
+  int AdvDefaultLifetime;
+#define RTADV_ADV_DEFAULT_LIFETIME (3 * RTADV_MAX_RTR_ADV_INTERVAL)
+
+
+  /* A list of prefixes to be placed in Prefix Information options in
+     Router Advertisement messages sent from the interface.
+
+     Default: all prefixes that the router advertises via routing
+     protocols as being on-link for the interface from which the
+     advertisement is sent. The link-local prefix SHOULD NOT be
+     included in the list of advertised prefixes. */
+  list AdvPrefixList;
+};
+
+#endif /* RTADV */
+
+/* `zebra' daemon local interface structure. */
+struct zebra_if
+{
+  /* Shutdown configuration. */
+  u_char shutdown;
+
+  /* Multicast configuration. */
+  u_char multicast;
+
+  /* Router advertise configuration. */
+  u_char rtadv_enable;
+
+  /* Interface's address. */
+  list address;
+
+#ifdef RTADV
+  struct rtadvconf rtadv;
+#endif /* RTADV */
+};
+
+void if_delete_update (struct interface *ifp);
+void if_add_update (struct interface *ifp);
+void if_up (struct interface *);
+void if_down (struct interface *);
+void if_refresh (struct interface *);
+void zebra_interface_up_update (struct interface *ifp);
+void zebra_interface_down_update (struct interface *ifp);
+
+#ifdef HAVE_PROC_NET_DEV
+int ifstat_update_proc ();
+#endif /* HAVE_PROC_NET_DEV */
+#ifdef HAVE_NET_RT_IFLIST
+void ifstat_update_sysctl ();
+
+#endif /* HAVE_NET_RT_IFLIST */
+#ifdef HAVE_PROC_NET_DEV
+int interface_list_proc ();
+#endif /* HAVE_PROC_NET_DEV */
+#ifdef HAVE_PROC_NET_IF_INET6
+int ifaddr_proc_ipv6 ();
+#endif /* HAVE_PROC_NET_IF_INET6 */
+
+#ifdef BSDI
+int if_kvm_get_mtu (struct interface *);
+#endif /* BSDI */
diff --git a/zebra/ioctl.c b/zebra/ioctl.c
new file mode 100644
index 0000000..13afba2
--- /dev/null
+++ b/zebra/ioctl.c
@@ -0,0 +1,540 @@
+/*
+ * Common ioctl functions.
+ * Copyright (C) 1997, 98 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 "linklist.h"
+#include "if.h"
+#include "prefix.h"
+#include "ioctl.h"
+#include "log.h"
+
+#include "zebra/rib.h"
+#include "zebra/rt.h"
+
+/* clear and set interface name string */
+void
+ifreq_set_name (struct ifreq *ifreq, struct interface *ifp)
+{
+  strncpy (ifreq->ifr_name, ifp->name, IFNAMSIZ);
+}
+
+/* call ioctl system call */
+int
+if_ioctl (u_long request, caddr_t buffer)
+{
+  int sock;
+  int ret = 0;
+  int err = 0;
+
+  sock = socket (AF_INET, SOCK_DGRAM, 0);
+  if (sock < 0)
+    {
+      perror ("socket");
+      exit (1);
+    }
+
+  ret = ioctl (sock, request, buffer);
+  if (ret < 0)
+    {
+      err = errno;
+    }
+  close (sock);
+  
+  if (ret < 0) 
+    {
+      errno = err;
+      return ret;
+    }
+  return 0;
+}
+
+#ifdef HAVE_IPV6
+int
+if_ioctl_ipv6 (u_long request, caddr_t buffer)
+{
+  int sock;
+  int ret = 0;
+  int err = 0;
+
+  sock = socket (AF_INET6, SOCK_DGRAM, 0);
+  if (sock < 0)
+    {
+      perror ("socket");
+      exit (1);
+    }
+
+  ret = ioctl (sock, request, buffer);
+  if (ret < 0)
+    {
+      err = errno;
+    }
+  close (sock);
+  
+  if (ret < 0) 
+    {
+      errno = err;
+      return ret;
+    }
+  return 0;
+}
+#endif /* HAVE_IPV6 */
+
+/*
+ * get interface metric
+ *   -- if value is not avaliable set -1
+ */
+void
+if_get_metric (struct interface *ifp)
+{
+#ifdef SIOCGIFMETRIC
+  struct ifreq ifreq;
+
+  ifreq_set_name (&ifreq, ifp);
+
+  if (if_ioctl (SIOCGIFMETRIC, (caddr_t) &ifreq) < 0) 
+    return;
+  ifp->metric = ifreq.ifr_metric;
+  if (ifp->metric == 0)
+    ifp->metric = 1;
+#else /* SIOCGIFMETRIC */
+  ifp->metric = -1;
+#endif /* SIOCGIFMETRIC */
+}
+
+/* get interface MTU */
+void
+if_get_mtu (struct interface *ifp)
+{
+  struct ifreq ifreq;
+
+  ifreq_set_name (&ifreq, ifp);
+
+#if defined(SIOCGIFMTU)
+  if (if_ioctl (SIOCGIFMTU, (caddr_t) & ifreq) < 0) 
+    {
+      zlog_info ("Can't lookup mtu by ioctl(SIOCGIFMTU)");
+      ifp->mtu = -1;
+      return;
+    }
+
+#ifdef SUNOS_5
+  ifp->mtu = ifreq.ifr_metric;
+#else
+  ifp->mtu = ifreq.ifr_mtu;
+#endif /* SUNOS_5 */
+
+#else
+  zlog (NULL, LOG_INFO, "Can't lookup mtu on this system");
+  ifp->mtu = -1;
+#endif
+}
+
+#ifdef HAVE_NETLINK
+/* Interface address setting via netlink interface. */
+int
+if_set_prefix (struct interface *ifp, struct connected *ifc)
+{
+  return kernel_address_add_ipv4 (ifp, ifc);
+}
+
+/* Interface address is removed using netlink interface. */
+int
+if_unset_prefix (struct interface *ifp, struct connected *ifc)
+{
+  return kernel_address_delete_ipv4 (ifp, ifc);
+}
+#else /* ! HAVE_NETLINK */
+#ifdef HAVE_IFALIASREQ
+/* Set up interface's IP address, netmask (and broadcas? ).  *BSD may
+   has ifaliasreq structure.  */
+int
+if_set_prefix (struct interface *ifp, struct connected *ifc)
+{
+  int ret;
+  struct ifaliasreq addreq;
+  struct sockaddr_in addr;
+  struct sockaddr_in mask;
+  struct prefix_ipv4 *p;
+
+  p = (struct prefix_ipv4 *) ifc->address;
+
+  memset (&addreq, 0, sizeof addreq);
+  strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name);
+
+  memset (&addr, 0, sizeof (struct sockaddr_in));
+  addr.sin_addr = p->prefix;
+  addr.sin_family = p->family;
+#ifdef HAVE_SIN_LEN
+  addr.sin_len = sizeof (struct sockaddr_in);
+#endif
+  memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in));
+
+  memset (&mask, 0, sizeof (struct sockaddr_in));
+  masklen2ip (p->prefixlen, &mask.sin_addr);
+  mask.sin_family = p->family;
+#ifdef HAVE_SIN_LEN
+  mask.sin_len = sizeof (struct sockaddr_in);
+#endif
+  memcpy (&addreq.ifra_mask, &mask, sizeof (struct sockaddr_in));
+  
+  ret = if_ioctl (SIOCAIFADDR, (caddr_t) &addreq);
+  if (ret < 0)
+    return ret;
+  return 0;
+}
+
+/* Set up interface's IP address, netmask (and broadcas? ).  *BSD may
+   has ifaliasreq structure.  */
+int
+if_unset_prefix (struct interface *ifp, struct connected *ifc)
+{
+  int ret;
+  struct ifaliasreq addreq;
+  struct sockaddr_in addr;
+  struct sockaddr_in mask;
+  struct prefix_ipv4 *p;
+
+  p = (struct prefix_ipv4 *)ifc->address;
+
+  memset (&addreq, 0, sizeof addreq);
+  strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name);
+
+  memset (&addr, 0, sizeof (struct sockaddr_in));
+  addr.sin_addr = p->prefix;
+  addr.sin_family = p->family;
+#ifdef HAVE_SIN_LEN
+  addr.sin_len = sizeof (struct sockaddr_in);
+#endif
+  memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in));
+
+  memset (&mask, 0, sizeof (struct sockaddr_in));
+  masklen2ip (p->prefixlen, &mask.sin_addr);
+  mask.sin_family = p->family;
+#ifdef HAVE_SIN_LEN
+  mask.sin_len = sizeof (struct sockaddr_in);
+#endif
+  memcpy (&addreq.ifra_mask, &mask, sizeof (struct sockaddr_in));
+  
+  ret = if_ioctl (SIOCDIFADDR, (caddr_t) &addreq);
+  if (ret < 0)
+    return ret;
+  return 0;
+}
+#else
+/* Set up interface's address, netmask (and broadcas? ).  Linux or
+   Solaris uses ifname:number semantics to set IP address aliases. */
+int
+if_set_prefix (struct interface *ifp, struct connected *ifc)
+{
+  int ret;
+  struct ifreq ifreq;
+  struct sockaddr_in addr;
+  struct sockaddr_in broad;
+  struct sockaddr_in mask;
+  struct prefix_ipv4 ifaddr;
+  struct prefix_ipv4 *p;
+
+  p = (struct prefix_ipv4 *) ifc->address;
+
+  ifaddr = *p;
+
+  ifreq_set_name (&ifreq, ifp);
+
+  addr.sin_addr = p->prefix;
+  addr.sin_family = p->family;
+  memcpy (&ifreq.ifr_addr, &addr, sizeof (struct sockaddr_in));
+  ret = if_ioctl (SIOCSIFADDR, (caddr_t) &ifreq);
+  if (ret < 0)
+    return ret;
+  
+  /* We need mask for make broadcast addr. */
+  masklen2ip (p->prefixlen, &mask.sin_addr);
+
+  if (if_is_broadcast (ifp))
+    {
+      apply_mask_ipv4 (&ifaddr);
+      addr.sin_addr = ifaddr.prefix;
+
+      broad.sin_addr.s_addr = (addr.sin_addr.s_addr | ~mask.sin_addr.s_addr);
+      broad.sin_family = p->family;
+
+      memcpy (&ifreq.ifr_broadaddr, &broad, sizeof (struct sockaddr_in));
+      ret = if_ioctl (SIOCSIFBRDADDR, (caddr_t) &ifreq);
+      if (ret < 0)
+	return ret;
+    }
+
+  mask.sin_family = p->family;
+#ifdef SUNOS_5
+  memcpy (&mask, &ifreq.ifr_addr, sizeof (mask));
+#else
+  memcpy (&ifreq.ifr_netmask, &mask, sizeof (struct sockaddr_in));
+#endif /* SUNOS5 */
+  ret = if_ioctl (SIOCSIFNETMASK, (caddr_t) &ifreq);
+  if (ret < 0)
+    return ret;
+
+  return 0;
+}
+
+/* Set up interface's address, netmask (and broadcas? ).  Linux or
+   Solaris uses ifname:number semantics to set IP address aliases. */
+int
+if_unset_prefix (struct interface *ifp, struct connected *ifc)
+{
+  int ret;
+  struct ifreq ifreq;
+  struct sockaddr_in addr;
+  struct prefix_ipv4 *p;
+
+  p = (struct prefix_ipv4 *) ifc->address;
+
+  ifreq_set_name (&ifreq, ifp);
+
+  memset (&addr, 0, sizeof (struct sockaddr_in));
+  addr.sin_family = p->family;
+  memcpy (&ifreq.ifr_addr, &addr, sizeof (struct sockaddr_in));
+  ret = if_ioctl (SIOCSIFADDR, (caddr_t) &ifreq);
+  if (ret < 0)
+    return ret;
+
+  return 0;
+}
+#endif /* HAVE_IFALIASREQ */
+#endif /* HAVE_NETLINK */
+
+/* get interface flags */
+void
+if_get_flags (struct interface *ifp)
+{
+  int ret;
+  struct ifreq ifreq;
+
+  ifreq_set_name (&ifreq, ifp);
+
+  ret = if_ioctl (SIOCGIFFLAGS, (caddr_t) &ifreq);
+  if (ret < 0) 
+    {
+      perror ("ioctl");
+      return;
+    }
+
+  ifp->flags = ifreq.ifr_flags & 0x0000ffff;
+}
+
+/* Set interface flags */
+int
+if_set_flags (struct interface *ifp, unsigned long flags)
+{
+  int ret;
+  struct ifreq ifreq;
+
+  ifreq_set_name (&ifreq, ifp);
+
+  ifreq.ifr_flags = ifp->flags;
+  ifreq.ifr_flags |= flags;
+
+  ret = if_ioctl (SIOCSIFFLAGS, (caddr_t) &ifreq);
+
+  if (ret < 0)
+    {
+      zlog_info ("can't set interface flags");
+      return ret;
+    }
+  return 0;
+}
+
+/* Unset interface's flag. */
+int
+if_unset_flags (struct interface *ifp, unsigned long flags)
+{
+  int ret;
+  struct ifreq ifreq;
+
+  ifreq_set_name (&ifreq, ifp);
+
+  ifreq.ifr_flags = ifp->flags;
+  ifreq.ifr_flags &= ~flags;
+
+  ret = if_ioctl (SIOCSIFFLAGS, (caddr_t) &ifreq);
+
+  if (ret < 0)
+    {
+      zlog_info ("can't unset interface flags");
+      return ret;
+    }
+  return 0;
+}
+
+#ifdef HAVE_IPV6
+
+#ifdef LINUX_IPV6
+#ifndef _LINUX_IN6_H
+/* linux/include/net/ipv6.h */
+struct in6_ifreq 
+{
+  struct in6_addr ifr6_addr;
+  u_int32_t ifr6_prefixlen;
+  int ifr6_ifindex;
+};
+#endif /* _LINUX_IN6_H */
+
+/* Interface's address add/delete functions. */
+int
+if_prefix_add_ipv6 (struct interface *ifp, struct connected *ifc)
+{
+  int ret;
+  struct prefix_ipv6 *p;
+  struct in6_ifreq ifreq;
+
+  p = (struct prefix_ipv6 *) ifc->address;
+
+  memset (&ifreq, 0, sizeof (struct in6_ifreq));
+
+  memcpy (&ifreq.ifr6_addr, &p->prefix, sizeof (struct in6_addr));
+  ifreq.ifr6_ifindex = ifp->ifindex;
+  ifreq.ifr6_prefixlen = p->prefixlen;
+
+  ret = if_ioctl_ipv6 (SIOCSIFADDR, (caddr_t) &ifreq);
+
+  return ret;
+}
+
+int
+if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc)
+{
+  int ret;
+  struct prefix_ipv6 *p;
+  struct in6_ifreq ifreq;
+
+  p = (struct prefix_ipv6 *) ifc->address;
+
+  memset (&ifreq, 0, sizeof (struct in6_ifreq));
+
+  memcpy (&ifreq.ifr6_addr, &p->prefix, sizeof (struct in6_addr));
+  ifreq.ifr6_ifindex = ifp->ifindex;
+  ifreq.ifr6_prefixlen = p->prefixlen;
+
+  ret = if_ioctl_ipv6 (SIOCDIFADDR, (caddr_t) &ifreq);
+
+  return ret;
+}
+#else /* LINUX_IPV6 */
+#ifdef HAVE_IN6_ALIASREQ
+#ifndef ND6_INFINITE_LIFETIME
+#define ND6_INFINITE_LIFETIME 0xffffffffL
+#endif /* ND6_INFINITE_LIFETIME */
+int
+if_prefix_add_ipv6 (struct interface *ifp, struct connected *ifc)
+{
+  int ret;
+  struct in6_aliasreq addreq;
+  struct sockaddr_in6 addr;
+  struct sockaddr_in6 mask;
+  struct prefix_ipv6 *p;
+
+  p = (struct prefix_ipv6 * ) ifc->address;
+
+  memset (&addreq, 0, sizeof addreq);
+  strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name);
+
+  memset (&addr, 0, sizeof (struct sockaddr_in6));
+  addr.sin6_addr = p->prefix;
+  addr.sin6_family = p->family;
+#ifdef HAVE_SIN_LEN
+  addr.sin6_len = sizeof (struct sockaddr_in6);
+#endif
+  memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in6));
+
+  memset (&mask, 0, sizeof (struct sockaddr_in6));
+  masklen2ip6 (p->prefixlen, &mask.sin6_addr);
+  mask.sin6_family = p->family;
+#ifdef HAVE_SIN_LEN
+  mask.sin6_len = sizeof (struct sockaddr_in6);
+#endif
+  memcpy (&addreq.ifra_prefixmask, &mask, sizeof (struct sockaddr_in6));
+  
+  addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; 
+  addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; 
+
+  ret = if_ioctl_ipv6 (SIOCAIFADDR_IN6, (caddr_t) &addreq);
+  if (ret < 0)
+    return ret;
+  return 0;
+}
+
+int
+if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc)
+{
+  int ret;
+  struct in6_aliasreq addreq;
+  struct sockaddr_in6 addr;
+  struct sockaddr_in6 mask;
+  struct prefix_ipv6 *p;
+
+  p = (struct prefix_ipv6 *) ifc->address;
+
+  memset (&addreq, 0, sizeof addreq);
+  strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name);
+
+  memset (&addr, 0, sizeof (struct sockaddr_in6));
+  addr.sin6_addr = p->prefix;
+  addr.sin6_family = p->family;
+#ifdef HAVE_SIN_LEN
+  addr.sin6_len = sizeof (struct sockaddr_in6);
+#endif
+  memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in6));
+
+  memset (&mask, 0, sizeof (struct sockaddr_in6));
+  masklen2ip6 (p->prefixlen, &mask.sin6_addr);
+  mask.sin6_family = p->family;
+#ifdef HAVE_SIN_LEN
+  mask.sin6_len = sizeof (struct sockaddr_in6);
+#endif
+  memcpy (&addreq.ifra_prefixmask, &mask, sizeof (struct sockaddr_in6));
+
+  addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; 
+  addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; 
+
+  ret = if_ioctl_ipv6 (SIOCDIFADDR_IN6, (caddr_t) &addreq);
+  if (ret < 0)
+    return ret;
+  return 0;
+}
+#else
+int
+if_prefix_add_ipv6 (struct interface *ifp, struct connected *ifc)
+{
+  return 0;
+}
+
+int
+if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc)
+{
+  return 0;
+}
+#endif /* HAVE_IN6_ALIASREQ */
+
+#endif /* LINUX_IPV6 */
+
+#endif /* HAVE_IPV6 */
diff --git a/zebra/ioctl.h b/zebra/ioctl.h
new file mode 100644
index 0000000..157fc44
--- /dev/null
+++ b/zebra/ioctl.h
@@ -0,0 +1,46 @@
+/*
+ * Common ioctl functions.
+ * Copyright (C) 1998 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.  
+ */
+
+#ifndef _ZEBRA_IOCTL_H
+#define _ZEBRA_IOCTL_H
+
+/* Prototypes. */
+void ifreq_set_name (struct ifreq *, struct interface *);
+int if_ioctl (u_long, caddr_t);
+
+int if_set_flags (struct interface *, unsigned long);
+int if_unset_flags (struct interface *, unsigned long);
+void if_get_flags (struct interface *);
+
+int if_set_prefix (struct interface *, struct connected *);
+int if_unset_prefix (struct interface *, struct connected *);
+
+void if_get_metric (struct interface *);
+void if_get_mtu (struct interface *);
+
+#ifdef HAVE_IPV6
+int if_prefix_add_ipv6 (struct interface *, struct connected *);
+int if_prefix_delete_ipv6 (struct interface *, struct connected *);
+
+#endif /* HAVE_IPV6 */
+
+#endif /* _ZEBRA_IOCTL_H */
diff --git a/zebra/ipforward.h b/zebra/ipforward.h
new file mode 100644
index 0000000..a772337
--- /dev/null
+++ b/zebra/ipforward.h
@@ -0,0 +1,35 @@
+/* IP forward settings.
+ * Copyright (C) 1999 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.  
+ */
+
+#ifndef _ZEBRA_IPFORWARD_H
+#define _ZEBRA_IPFORWARD_H
+
+int ipforward ();
+int ipforward_on ();
+int ipforward_off ();
+
+#ifdef HAVE_IPV6
+int ipforward_ipv6 ();
+int ipforward_ipv6_on ();
+int ipforward_ipv6_off ();
+#endif /* HAVE_IPV6 */
+
+#endif /* _ZEBRA_IPFORWARD_H */
diff --git a/zebra/ipforward_aix.c b/zebra/ipforward_aix.c
new file mode 100644
index 0000000..c79e7f1
--- /dev/null
+++ b/zebra/ipforward_aix.c
@@ -0,0 +1,64 @@
+/*
+ * ipforward value get function for aix.
+ * Copyright (C) 1997 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>
+
+int
+ipforward ()
+{
+  int fd, ret;
+  int af = AF_INET;
+  char netopt[] = "ipforwarding";
+  struct optreq oq;
+
+  fd = socket(af, SOCK_DGRAM, 0);
+  if (fd < 0) {
+    /* need logging here */
+    return -1;
+  }
+
+  strcpy (oq.name, netopt);
+  oq.getnext = 0;
+
+  ret = ioctl (fd, SIOCGNETOPT, (caddr_t)&oq);
+  close(fd);
+
+  if (ret < 0) {
+    /* need logging here */
+    return -1;
+  }
+
+  ret = atoi (oq.data);
+  return ret;
+}
+
+int
+ipforward_on ()
+{
+  ;
+}
+
+int
+ipforward_off ()
+{
+  ;
+}
diff --git a/zebra/ipforward_ews.c b/zebra/ipforward_ews.c
new file mode 100644
index 0000000..c872000
--- /dev/null
+++ b/zebra/ipforward_ews.c
@@ -0,0 +1,60 @@
+/*
+ * Ipforward value get function for NEC EWS.
+ * Copyright (C) 1997 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>
+
+int
+ipforward ()
+{
+  int fd;
+  char buf[BUFSIZ];
+  struct mioc_rksym rks;
+
+  fd = open ("/dev/kmem", O_RDWR);
+  if (fd < 0) {
+    /* need logging here */
+    return -1;
+  }
+
+  rks.mirk_symname = "ipforwarding";
+  rks.mirk_buf = buf;
+  rks.mirk_buflen = sizeof (int);
+
+  if (ioctl (fd, MIOC_READKSYM, &rks) < 0) {
+    /* need logging here */
+    return -1;
+  }
+  close (fd);
+  return *(int *)buf;
+}
+
+int
+ipforward_on ()
+{
+  ;
+}
+
+int
+ipforward_off ()
+{
+  ;
+}
diff --git a/zebra/ipforward_proc.c b/zebra/ipforward_proc.c
new file mode 100644
index 0000000..eb8cef0
--- /dev/null
+++ b/zebra/ipforward_proc.c
@@ -0,0 +1,155 @@
+/*
+ * Fetch ipforward value by reading /proc filesystem.
+ * Copyright (C) 1997 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>
+
+char proc_net_snmp[] = "/proc/net/snmp";
+
+static void
+dropline (FILE *fp)
+{
+  int c;
+
+  while ((c = getc (fp)) != '\n')
+    ;
+}
+
+int
+ipforward ()
+{
+  FILE *fp;
+  int ipforwarding = 0;
+  char *pnt;
+  char buf[10];
+
+  fp = fopen (proc_net_snmp, "r");
+
+  if (fp == NULL)
+    return -1;
+
+  /* We don't care about the first line. */
+  dropline (fp);
+  
+  /* Get ip_statistics.IpForwarding : 
+     1 => ip forwarding enabled 
+     2 => ip forwarding off. */
+  pnt = fgets (buf, 6, fp);
+  sscanf (buf, "Ip: %d", &ipforwarding);
+
+  if (ipforwarding == 1)
+    return 1;
+
+  return 0;
+}
+
+/* char proc_ipv4_forwarding[] = "/proc/sys/net/ipv4/conf/all/forwarding"; */
+char proc_ipv4_forwarding[] = "/proc/sys/net/ipv4/ip_forward";
+
+int
+ipforward_on ()
+{
+  FILE *fp;
+
+  fp = fopen (proc_ipv4_forwarding, "w");
+  
+  if (fp == NULL)
+    return -1;
+
+  fprintf (fp, "1\n");
+
+  fclose (fp);
+
+  return ipforward ();
+}
+
+int
+ipforward_off ()
+{
+  FILE *fp;
+
+  fp = fopen (proc_ipv4_forwarding, "w");
+  
+  if (fp == NULL)
+    return -1;
+
+  fprintf (fp, "0\n");
+
+  fclose (fp);
+
+  return ipforward ();
+}
+#ifdef HAVE_IPV6
+
+char proc_ipv6_forwarding[] = "/proc/sys/net/ipv6/conf/all/forwarding";
+
+int
+ipforward_ipv6 ()
+{
+  FILE *fp;
+  char buf[5];
+  int ipforwarding = 0;
+
+  fp = fopen (proc_ipv6_forwarding, "r");
+
+  if (fp == NULL)
+    return -1;
+
+  fgets (buf, 2, fp);
+  sscanf (buf, "%d", &ipforwarding);
+
+  return ipforwarding;
+}
+
+int
+ipforward_ipv6_on ()
+{
+  FILE *fp;
+
+  fp = fopen (proc_ipv6_forwarding, "w");
+  
+  if (fp == NULL)
+    return -1;
+
+  fprintf (fp, "1\n");
+
+  fclose (fp);
+
+  return ipforward_ipv6 ();
+}
+
+int
+ipforward_ipv6_off ()
+{
+  FILE *fp;
+
+  fp = fopen (proc_ipv6_forwarding, "w");
+  
+  if (fp == NULL)
+    return -1;
+
+  fprintf (fp, "0\n");
+
+  fclose (fp);
+
+  return ipforward_ipv6 ();
+}
+#endif /* HAVE_IPV6 */
diff --git a/zebra/ipforward_solaris.c b/zebra/ipforward_solaris.c
new file mode 100644
index 0000000..99b0e1a
--- /dev/null
+++ b/zebra/ipforward_solaris.c
@@ -0,0 +1,77 @@
+/*
+ * ipforward value get function for solaris.
+ * Copyright (C) 1997 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 "memory.h"
+
+int
+ipforward ()
+{
+  int fd, ret;
+  int ipforwarding = 0;
+  char forward[] = "ip_forwarding";
+  char *buf;
+  struct strioctl si;
+
+  buf = (char *) XMALLOC (MTYPE_TMP, sizeof forward + 1);
+  strcpy (buf, forward);
+
+  fd = open ("/dev/ip", O_RDWR);
+  if (fd < 0) {
+    free (buf);
+    /* need logging here */
+    /* "I can't get ipforwarding value because can't open /dev/ip" */
+    return -1;
+  }
+
+  si.ic_cmd = ND_GET;
+  si.ic_timout = 0;
+  si.ic_len = strlen (buf) + 1;
+  si.ic_dp = (caddr_t) buf;
+
+  ret = ioctl (fd, I_STR, &si);
+  close (fd);
+
+  if (ret < 0) {
+    free (buf);
+    /* need logging here */
+    /* can't get ipforwarding value : ioctl failed */
+    return -1;
+  }
+
+  ipforwarding = atoi (buf);
+  free (buf);
+  return ipforwarding;
+}
+
+int
+ipforward_on ()
+{
+  return 0;
+}
+
+int
+ipforward_off ()
+{
+  return 0;
+}
diff --git a/zebra/ipforward_sysctl.c b/zebra/ipforward_sysctl.c
new file mode 100644
index 0000000..828eb86
--- /dev/null
+++ b/zebra/ipforward_sysctl.c
@@ -0,0 +1,146 @@
+/* IP forward control by sysctl function.
+ * Copyright (C) 1997, 1999 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>
+
+#ifdef NRL
+#include <netinet6/in6.h>
+#endif /* NRL */
+
+#include "log.h"
+
+#define MIB_SIZ 4
+
+/* IPv4 forwarding control MIB. */
+int mib[MIB_SIZ] =
+{
+  CTL_NET,
+  PF_INET,
+  IPPROTO_IP,
+  IPCTL_FORWARDING
+};
+
+int
+ipforward ()
+{
+  int len;
+  int ipforwarding = 0;
+
+  len = sizeof ipforwarding;
+  if (sysctl (mib, MIB_SIZ, &ipforwarding, &len, 0, 0) < 0) 
+    {
+      zlog_warn ("Can't get ipforwarding value");
+      return -1;
+    }
+  return ipforwarding;
+}
+
+int
+ipforward_on ()
+{
+  int len;
+  int ipforwarding = 1;
+
+  len = sizeof ipforwarding;
+  if (sysctl (mib, MIB_SIZ, NULL, NULL, &ipforwarding, len) < 0) 
+    {
+      zlog_warn ("Can't set ipforwarding on");
+      return -1;
+    }
+  return ipforwarding;
+}
+
+int
+ipforward_off ()
+{
+  int len;
+  int ipforwarding = 0;
+
+  len = sizeof ipforwarding;
+  if (sysctl (mib, MIB_SIZ, NULL, NULL, &ipforwarding, len) < 0) 
+    {
+      zlog_warn ("Can't set ipforwarding on");
+      return -1;
+    }
+  return ipforwarding;
+}
+
+#ifdef HAVE_IPV6
+
+/* IPv6 forwarding control MIB. */
+int mib_ipv6[MIB_SIZ] = 
+{
+  CTL_NET,
+  PF_INET6,
+#if defined(KAME) || (defined(__bsdi__) && _BSDI_VERSION >= 199802 ) || defined(NRL)
+  IPPROTO_IPV6,
+  IPV6CTL_FORWARDING
+#else /* NOT KAME */
+  IPPROTO_IP,
+  IP6CTL_FORWARDING
+#endif /* KAME */
+}; 
+
+int
+ipforward_ipv6 ()
+{
+  int len;
+  int ip6forwarding = 0;
+
+  len = sizeof ip6forwarding;
+  if (sysctl (mib_ipv6, MIB_SIZ, &ip6forwarding, &len, 0, 0) < 0) 
+    {
+      zlog_warn ("can't get ip6forwarding value");
+      return -1;
+    }
+  return ip6forwarding;
+}
+
+int
+ipforward_ipv6_on ()
+{
+  int len;
+  int ip6forwarding = 1;
+
+  len = sizeof ip6forwarding;
+  if (sysctl (mib_ipv6, MIB_SIZ, NULL, NULL, &ip6forwarding, len) < 0) 
+    {
+      zlog_warn ("can't get ip6forwarding value");
+      return -1;
+    }
+  return ip6forwarding;
+}
+
+int
+ipforward_ipv6_off ()
+{
+  int len;
+  int ip6forwarding = 0;
+
+  len = sizeof ip6forwarding;
+  if (sysctl (mib_ipv6, MIB_SIZ, NULL, NULL, &ip6forwarding, len) < 0) 
+    {
+      zlog_warn ("can't get ip6forwarding value");
+      return -1;
+    }
+  return ip6forwarding;
+}
+#endif /* HAVE_IPV6 */
diff --git a/zebra/irdp.c b/zebra/irdp.c
new file mode 100644
index 0000000..1b3bf23
--- /dev/null
+++ b/zebra/irdp.c
@@ -0,0 +1,569 @@
+/* ICMP Router Discovery Messages
+ * Copyright (C) 1997, 2000 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 <netinet/ip_icmp.h>
+
+#include "if.h"
+#include "stream.h"
+#include "memory.h"
+#include "command.h"
+#include "log.h"
+#include "sockunion.h"
+#include "sockopt.h"
+
+#include "zebra/irdp.h"
+
+/* Default does nothing. */
+int irdp_mode = IRDP_NONE;
+
+/* Timer interval of irdp. */
+int irdp_timer_interval = IRDP_DEFAULT_INTERVAL;
+
+/* Max solicitations */
+int max_solicitations = MAX_SOLICITATIONS;
+
+#define IRDP_SOLICIT_PACKET_SIZE 8
+
+static struct irdp *irdp_head = NULL;
+
+extern int in_cksum (void *ptr, int nbytes);
+
+char *icmp_type_str[] = 
+{
+  "Echo Reply",
+  "ICMP 1",
+  "ICMP 2",
+  "Dest Unreachable",
+  "Source Quench",
+  "Redirect",
+  "ICMP 6",
+  "ICMP 7",
+  "Echo",
+  "Router Advertise",
+  "Router Solicitation",
+  "Time Exceeded",
+  "Parameter Problem",
+  "Timestamp",
+  "Timestamp Reply",
+  "Info Request",
+  "Info Reply",
+  "Netmask Request",
+  "Netmask Reply",
+};
+
+char *
+icmp_type (int type)
+{
+  if (type < 0 || type >= (sizeof icmp_type_str / sizeof (char *))) {
+    return "OUT-OF-RANGE";
+  }
+  return icmp_type_str [type];
+}
+
+/* */
+void
+irdp_add_interface ()
+{
+  ;
+}
+
+/* */
+void
+irdp_delete_interface ()
+{
+
+}
+
+struct irdp *
+irdp_route_new ()
+{
+  struct irdp *new = XMALLOC (0, sizeof (struct irdp));
+  memset (new, 0, sizeof (struct irdp));
+  return new;
+}
+
+void
+irdp_route_free (struct irdp *route)
+{
+  XFREE (0, route);
+}
+
+void
+route_delete ()
+{
+
+}
+
+void
+route_init ()
+{
+  
+}
+
+void
+route_add (struct in_addr addr, unsigned long pref)
+{
+  struct irdp *new = irdp_route_new();
+  
+  new->prefix = addr;
+  new->pref = pref;
+
+  printf ("address %s\n", inet_ntoa (new->prefix));
+  printf ("pref %ld\n", new->pref);
+}
+
+void
+route_age (int time)
+{
+  struct irdp *p;
+
+  for (p = irdp_head; p != NULL; p = p->next) {
+    if (p->timer < time) {
+      /* fire */
+    } else {
+      p->timer -= time;
+    }
+  }
+}
+
+#define FLAG_TEST(a)  ((ifp->flags & (a)) == (a))
+
+void
+send_multicast (struct interface *ifp, int sock, struct stream *s, int size)
+{
+  struct sockaddr_in sin;
+  struct in_addr addr;
+  int nbytes;
+  struct connected *connected;
+  listnode node;
+  
+  for (node = listhead (ifp->connected); node; nextnode (node))
+    {
+      connected = getdata (node);
+    }
+
+  if (setsockopt_multicast_ipv4 (sock, IP_MULTICAST_IF,
+		  addr, 0, ifp->ifindex) < 0) 
+    {
+      perror ("setsockopt");
+      exit (1);
+    }
+
+  sin.sin_addr.s_addr = htonl (INADDR_ALLRTRS_GROUP);
+  sin.sin_family = AF_INET;
+
+  nbytes = sendto (sock, s->data, size, 0,
+		   (struct sockaddr *) &sin, sizeof (struct sockaddr));
+
+  if (nbytes != size) 
+    {
+      perror ("sendto");
+      exit (1);
+    }
+}
+
+void
+send_broadcast ()
+{
+  struct sockaddr_in sin;
+
+  printf ("broadcast\n");
+  inet_aton ("255.255.255.255", &sin.sin_addr);
+}
+
+void
+irdp_send_solicit (int sock, struct stream *s, int size)
+{
+  struct interface *ifp;
+  listnode node;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+      if (FLAG_TEST (IFF_UP | IFF_MULTICAST)) 
+	{
+	  send_multicast (ifp, sock, s, size);
+	}
+      else if (FLAG_TEST (IFF_UP | IFF_BROADCAST)) 
+	{
+	  send_broadcast ();
+	}
+    }
+}
+
+int
+ipv4_multicast_join (int sock, 
+		     struct in_addr group, 
+		     struct in_addr ifa,
+		     unsigned int ifindex)
+{
+  int ret;
+
+  ret = setsockopt_multicast_ipv4 (sock, IP_ADD_MEMBERSHIP, 
+		    ifa, group.saddr, ifindex);
+
+  if (ret < 0) 
+    zlog (NULL, LOG_INFO, "can't setsockopt IP_ADD_MEMBERSHIP");
+
+  return ret;
+}
+
+/* multicast packet recieve socket */
+int
+irdp_multicast_socket (int sock, struct in_addr group)
+{
+  struct interface *ifp;
+  listnode node;
+  struct in_addr addr;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+
+      if ((ifp->flags & IFF_UP) && (ifp->flags & IFF_MULTICAST)) 
+	{
+	  ipv4_multicast_join (sock, group, addr, ifp->ifindex);
+	}
+    }
+  return 0;
+}
+
+struct 
+{
+  u_char type;
+  u_char code;
+  u_int16_t checksum;
+  u_char number;
+  u_char entry;
+  u_int16_t lifetime;
+} radv;
+
+void
+irdp_set (int sock)
+{
+  struct in_addr irdp_group;
+
+  switch (irdp_mode) 
+    {
+    case IRDP_HOST:
+      irdp_group.s_addr = htonl (INADDR_ALLHOSTS_GROUP);
+      break;
+    case IRDP_ROUTER:
+      irdp_group.s_addr = htonl (INADDR_ALLRTRS_GROUP);
+      break;
+    case IRDP_NONE:
+    default:
+      return;
+    }
+  irdp_multicast_socket (sock, irdp_group);
+}
+
+/* Make ICMP Router Solicitation Message. */
+int
+make_solicit_packet (struct stream *s)
+{
+  int size;
+  int checksum;
+
+  stream_putc (s, ICMP_ROUTERSOLICIT); /* Type. */
+  stream_putc (s, 0);		/* Code. */
+  stream_putw (s, 0);		/* Checksum. */
+  stream_putl (s, 0);		/* Reserved. */
+
+  /* in_cksum return network byte order value */
+  size = IRDP_SOLICIT_PACKET_SIZE;
+  checksum = in_cksum (s->data, size);
+  stream_putw_at (s, checksum, 2);
+
+  return IRDP_SOLICIT_PACKET_SIZE;
+}
+
+void
+irdp_solicit (int sock)
+{
+  struct stream *s;
+
+  s = stream_new (IRDP_SOLICIT_PACKET_SIZE);
+  make_solicit_packet (s);
+  irdp_send_solicit (sock, s, IRDP_SOLICIT_PACKET_SIZE);
+}
+
+#define ICMP_MINLEN 8
+
+/* check validity of the packet */
+int
+irdp_valid_check (char *packet, size_t size, struct sockaddr_in *from)
+{
+  struct icmp *icmp;
+
+  icmp = (struct icmp *) packet;
+
+  if (in_cksum (packet, size)) {
+    zlog_warn ("ICMP %s packet from %s: Bad checksum, silently ignored",
+	       icmp_type (icmp->icmp_type),
+	       inet_ntoa (from->sin_addr));
+    return -1;
+  }
+
+  if (icmp->icmp_code != 0) {
+    zlog_warn ("ICMP %s packet from %s: Bad ICMP type code, silently ignored",
+	       icmp_type (icmp->icmp_type),
+	       inet_ntoa (from->sin_addr));
+    return -1;
+  }
+
+  if (size < ICMP_MINLEN) {
+    zlog_warn ("ICMP %s packet from %s: IMCP message length is short",
+	       icmp_type (icmp->icmp_type),
+	       inet_ntoa (from->sin_addr));
+    return -1;
+  }
+  return 0;
+}
+
+int
+irdp_solicit_recv (struct stream *s, int size, struct sockaddr_in *from)
+{
+  if (irdp_valid_check (s->data, size, from)) {
+    return 1;
+  }
+  return 0;
+}
+
+void
+irdp_advert_recv (struct stream *s, int size, struct sockaddr_in *from)
+{
+  int i;
+  struct in_addr addr;
+  long pref;
+
+  if (irdp_valid_check (s->data, size, from) < 0) {
+    return;
+  }
+
+  radv.type = stream_getc (s);
+  radv.code =  stream_getc (s);
+  radv.checksum = stream_getw (s);
+  radv.number = stream_getc (s);
+  radv.entry = stream_getc (s);
+  radv.lifetime = stream_getw (s);
+
+  printf ("type : %s\n", icmp_type (radv.type));
+  printf ("number: %d\n", radv.number);
+  printf ("entry: %d\n", radv.entry);
+  printf ("lifetime: %d\n", radv.entry);
+
+  for (i = 0; i < radv.number; i++) 
+    {
+      addr.s_addr = stream_getl (s);
+      pref = stream_getl (s);
+      route_add (addr, ntohl (pref));
+    }
+  /* Packet size check is needed at here. */
+}
+
+void
+irdp_packet_process (char *buf, int size, struct sockaddr_in *from)
+{
+  struct ip *ip;
+  struct icmp *icmp;
+  int hlen;
+  struct stream *s = NULL;
+
+  ip = (struct ip *)buf;
+  hlen = ip->ip_hl << 2;
+
+  if (size < hlen + ICMP_MINLEN)
+    zlog_err ("ICMP relpy length is short\n");
+
+  icmp = (struct icmp *)(buf + hlen);
+
+  stream_forward (s, hlen);
+  
+  switch (icmp->icmp_type) 
+    {
+    case ICMP_ROUTERADVERT:
+      irdp_advert_recv (s, size - hlen, from);
+      break;
+    case ICMP_ROUTERSOLICIT:
+      irdp_solicit_recv (s, size - hlen, from);
+      break;
+    }
+}
+
+/* Make socket for ICMP Router Discovery. */
+int
+irdp_make_socket ()
+{
+  int sock;
+  struct protoent *pent;
+
+  if ((pent = getprotobyname ("icmp")) == NULL) {
+    perror ("getprotobyname");
+    exit (1);
+  }
+
+  if ((sock = socket (AF_INET, SOCK_RAW, pent->p_proto)) < 0) 
+    {
+      perror ("socket");
+      exit (1);
+    }
+
+  return sock;
+}
+
+/* recv routine */
+int
+irdp_recv (int sock)
+{
+#define PACKET_BUF 4096
+  int nbytes;
+  struct sockaddr_in from;
+  int fromlen;
+  char buf[PACKET_BUF];
+
+  fromlen = sizeof (from);
+  nbytes = recvfrom (sock, (char *)buf, PACKET_BUF, 0,
+		     (struct sockaddr *)&from, &fromlen);
+
+  if (nbytes < 0) 
+    {
+      perror ("recvfrom");
+      exit (1);
+    }
+
+  irdp_packet_process (buf, nbytes, &from);
+
+  return 0;
+}
+
+/* irdp packet recv loop */
+void
+irdp_loop (int sock)
+{
+  while (1) 
+    {
+      irdp_recv (sock);
+    }
+}
+
+DEFUN (ip_irdp,
+       ip_irdp_cmd,
+       "ip irdp",
+       IP_STR
+       "ICMP Router discovery on this interface\n")
+{
+  return CMD_SUCCESS;
+}
+
+DEFUN (ip_irdp_multicast,
+       ip_irdp_multicast_cmd,
+       "ip irdp multicast",
+       IP_STR
+       "ICMP Router discovery on this interface\n"
+       "Send IRDP advertisement to the multicast address\n")
+{
+  return CMD_SUCCESS;
+}
+
+DEFUN (ip_irdp_holdtime,
+       ip_irdp_holdtime_cmd,
+       "ip irdp holdtime <0-9000>",
+       IP_STR
+       "ICMP Router discovery on this interface\n"
+       "Set holdtime value\n"
+       "Holdtime value in seconds. Default is 1800 seconds\n")
+{
+  return CMD_SUCCESS;
+}
+
+DEFUN (ip_irdp_maxadvertinterval,
+       ip_irdp_maxadvertinterval_cmd,
+       "ip irdp maxadvertinterval (0|<4-1800>)",
+       IP_STR
+       "ICMP Router discovery on this interface\n"
+       "Set maximum time between advertisement\n"
+       "Maximum advertisement interval in seconds\n")
+{
+  return CMD_SUCCESS;
+}
+
+DEFUN (ip_irdp_minadvertinterval,
+       ip_irdp_minadvertinterval_cmd,
+       "ip irdp minadvertinterval <3-1800>",
+       IP_STR
+       "ICMP Router discovery on this interface\n"
+       "Set minimum time between advertisement\n"
+       "Minimum advertisement interval in seconds\n")
+{
+  return CMD_SUCCESS;
+}
+
+DEFUN (ip_irdp_preference,
+       ip_irdp_preference_cmd,
+       /* "ip irdp preference <-2147483648-2147483647>", */
+       "ip irdp preference <0-2147483647>",
+       IP_STR
+       "ICMP Router discovery on this interface\n"
+       "Set default preference level for this interface\n"
+       "Preference level\n")
+{
+  return CMD_SUCCESS;
+}
+
+#if 0
+DEFUN (ip_irdp_address,
+       ip_irdp_address_cmd,
+       "ip irdp address A.B.C.D",
+       IP_STR
+       "ICMP Router discovery on this interface\n"
+       "Specify IRDP address and preference to proxy-advertise\n"
+       "Set IRDP address for proxy-advertise\n")
+{
+  return CMD_SUCCESS;
+}
+#endif /* 0 */
+
+DEFUN (ip_irdp_address_preference,
+       ip_irdp_address_preference_cmd,
+       "ip irdp address A.B.C.D <0-2147483647>",
+       IP_STR
+       "ICMP Router discovery on this interface\n"
+       "Specify IRDP address and preference to proxy-advertise\n"
+       "Set IRDP address for proxy-advertise\n"
+       "Preference level\n")
+{
+  return CMD_SUCCESS;
+}
+
+void
+irdp_init ()
+{
+  install_element (INTERFACE_NODE, &ip_irdp_cmd);
+  install_element (INTERFACE_NODE, &ip_irdp_multicast_cmd);
+  install_element (INTERFACE_NODE, &ip_irdp_holdtime_cmd);
+  install_element (INTERFACE_NODE, &ip_irdp_maxadvertinterval_cmd);
+  install_element (INTERFACE_NODE, &ip_irdp_minadvertinterval_cmd);
+  install_element (INTERFACE_NODE, &ip_irdp_preference_cmd);
+  install_element (INTERFACE_NODE, &ip_irdp_address_preference_cmd);
+}
diff --git a/zebra/irdp.h b/zebra/irdp.h
new file mode 100644
index 0000000..0fad581
--- /dev/null
+++ b/zebra/irdp.h
@@ -0,0 +1,148 @@
+/* ICMP Router Discovery Messages
+ * Copyright (C) 1997, 2000 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.  
+ */
+
+/* ICMP Messages */
+#ifndef ICMP_ROUTERADVERT
+#define ICMP_ROUTERADVERT 9
+#endif /* ICMP_ROUTERADVERT */
+
+#ifndef ICMP_ROUTERSOLICIT
+#define ICMP_ROUTERSOLICIT 10
+#endif /* ICMP_ROUTERSOLICT */
+
+/* Multicast groups */
+#ifndef INADDR_ALLHOSTS_GROUP
+#define INADDR_ALLHOSTS_GROUP 0xe0000001    /* 224.0.0.1 */
+#endif /* INADDR_ALLHOSTS_GROUP */
+
+#ifndef INADDR_ALLRTRS_GROUP
+#define INADDR_ALLRTRS_GROUP  0xe0000002    /* 224.0.0.2 */
+#endif /* INADDR_ALLRTRS_GROUP */
+
+/* Comments comes from RFC1256 ICMP Router Discovery Messages. */
+struct irdp_router_interface 
+{
+  /* The IP destination address to be used for multicast Router
+     Advertisements sent from the interface.  The only permissible
+     values are the all-systems multicast address, 224.0.0.1, or the
+     limited-broadcast address, 255.255.255.255.  (The all-systems
+     address is preferred wherever possible, i.e., on any link where
+     all listening hosts support IP multicast.)
+
+     Default: 224.0.0.1 if the router supports IP multicast on the
+     interface, else 255.255.255.255 */
+
+  struct in_addr AdvertisementAddress;
+
+  /* The maximum time allowed between sending multicast Router
+     Advertisements from the interface, in seconds.  Must be no less
+     than 4 seconds and no greater than 1800 seconds.
+
+     Default: 600 seconds */
+
+  unsigned long MaxAdvertisementInterval;
+
+  /* The minimum time allowed between sending unsolicited multicast
+     Router Advertisements from the interface, in seconds.  Must be no
+     less than 3 seconds and no greater than MaxAdvertisementInterval.
+
+     Default: 0.75 * MaxAdvertisementInterval */
+
+  unsigned long MinAdvertisementInterval;
+
+
+  /* The value to be placed in the Lifetime field of Router
+     Advertisements sent from the interface, in seconds.  Must be no
+     less than MaxAdvertisementInterval and no greater than 9000
+     seconds.
+
+     Default: 3 * MaxAdvertisementInterval */
+
+  unsigned long AdvertisementLifetime;
+
+  /* A flag indicating whether or not the address is to be advertised.
+
+     Default: TRUE */
+
+  int Advertise;
+
+
+  /* The preferability of the address as a default router address,
+     relative to other router addresses on the same subnet.  A 32-bit,
+     signed, twos-complement integer, with higher values meaning more
+     preferable.  The minimum value (hex 80000000) is used to indicate
+     that the address, even though it may be advertised, is not to be
+     used by neighboring hosts as a default router address.
+
+     Default: 0 */
+
+  unsigned long PreferenceLevel;
+};
+
+struct irdp_host_interface 
+{
+  /* A flag indicating whether or not the host is to perform ICMP router
+     discovery on the interface. */
+  int PerformRouerDiscovery;
+  
+  /* The IP destination address to be used for sending Router
+     Solicitations from the interface.  The only permissible values
+     are the all-routers multicast address, 224.0.0.2, or the
+     limited-broadcast address, 255.255.255.255.  (The all-routers
+     address is preferred wherever possible, i.e., on any link where
+     all advertising routers support IP multicast.)  */
+  unsigned long SolicitationAddress;
+};
+
+
+/* Route preference structure */
+struct irdp 
+{
+  struct in_addr prefix;
+  long pref;		/* preference level */
+  long timer;			/* lifetime timer */
+
+  struct irdp *next;		/* doubly linked list */
+  struct irdp *prev;		/* doubly linked list */
+};
+
+/* Default irdp packet interval */
+#define IRDP_DEFAULT_INTERVAL 300
+
+/* Router constants from RFC1256 */
+#define MAX_INITIAL_ADVERT_INTERVAL 16
+#define MAX_INITIAL_ADVERTISEMENTS   3
+#define MAX_RESPONSE_DELAY           2
+
+/* Host constants from RFC1256 */
+#define MAX_SOLICITATION_DELAY       1
+#define SOLICITATION_INTERVAL        3
+#define MAX_SOLICITATIONS            3
+
+enum
+{
+  IRDP_NONE,
+  IRDP_ROUTER,
+  IRDP_HOST,
+};
+
+/* default is host mode */
+extern int irdp_mode;
diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c
new file mode 100644
index 0000000..23b2153
--- /dev/null
+++ b/zebra/kernel_netlink.c
@@ -0,0 +1,20 @@
+/* Kernel communication using netlink interface.
+ * Copyright (C) 1999 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.  
+ */
diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c
new file mode 100644
index 0000000..a47f4f6
--- /dev/null
+++ b/zebra/kernel_socket.c
@@ -0,0 +1,811 @@
+/* Kernel communication using routing socket.
+ * Copyright (C) 1999 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 "if.h"
+#include "prefix.h"
+#include "sockunion.h"
+#include "connected.h"
+#include "memory.h"
+#include "ioctl.h"
+#include "log.h"
+#include "str.h"
+#include "table.h"
+#include "rib.h"
+
+#include "zebra/interface.h"
+#include "zebra/zserv.h"
+#include "zebra/debug.h"
+
+/* Socket length roundup function. */
+#define ROUNDUP(a) \
+  ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+
+/* And this macro is wrapper for handling sa_len. */
+#ifdef HAVE_SA_LEN
+#define WRAPUP(X)   ROUNDUP(((struct sockaddr *)(X))->sa_len)
+#else
+#define WRAPUP(X)   ROUNDUP(sizeof (struct sockaddr))
+#endif /* HAVE_SA_LEN */
+
+/* Routing socket message types. */
+struct message rtm_type_str[] =
+{
+  {RTM_ADD,      "RTM_ADD"},
+  {RTM_DELETE,   "RTM_DELETE"},
+  {RTM_CHANGE,   "RTM_CHANGE"},
+  {RTM_GET,      "RTM_GET"},
+  {RTM_LOSING,   "RTM_LOSING"},
+  {RTM_REDIRECT, "RTM_REDIRECT"},
+  {RTM_MISS,     "RTM_MISS"},
+  {RTM_LOCK,     "RTM_LOCK"},
+  {RTM_OLDADD,   "RTM_OLDADD"},
+  {RTM_OLDDEL,   "RTM_OLDDEL"},
+  {RTM_RESOLVE,  "RTM_RESOLVE"},
+  {RTM_NEWADDR,  "RTM_NEWADDR"},
+  {RTM_DELADDR,  "RTM_DELADDR"},
+  {RTM_IFINFO,   "RTM_IFINFO"},
+#ifdef RTM_OIFINFO
+  {RTM_OIFINFO,   "RTM_OIFINFO"},
+#endif /* RTM_OIFINFO */
+#ifdef RTM_NEWMADDR
+  {RTM_NEWMADDR, "RTM_NEWMADDR"},
+#endif /* RTM_NEWMADDR */
+#ifdef RTM_DELMADDR
+  {RTM_DELMADDR, "RTM_DELMADDR"},
+#endif /* RTM_DELMADDR */
+#ifdef RTM_IFANNOUNCE
+  {RTM_IFANNOUNCE, "RTM_IFANNOUNCE"},
+#endif /* RTM_IFANNOUNCE */
+  {0,            NULL}
+};
+
+struct message rtm_flag_str[] =
+{
+  {RTF_UP,        "UP"},
+  {RTF_GATEWAY,   "GATEWAY"},
+  {RTF_HOST,      "HOST"},
+  {RTF_REJECT,    "REJECT"},
+  {RTF_DYNAMIC,   "DYNAMIC"},
+  {RTF_MODIFIED,  "MODIFIED"},
+  {RTF_DONE,      "DONE"},
+#ifdef RTF_MASK
+  {RTF_MASK,      "MASK"},
+#endif /* RTF_MASK */
+  {RTF_CLONING,   "CLONING"},
+  {RTF_XRESOLVE,  "XRESOLVE"},
+  {RTF_LLINFO,    "LLINFO"},
+  {RTF_STATIC,    "STATIC"},
+  {RTF_BLACKHOLE, "BLACKHOLE"},
+  {RTF_PROTO1,    "PROTO1"},
+  {RTF_PROTO2,    "PROTO2"},
+#ifdef RTF_PRCLONING
+  {RTF_PRCLONING, "PRCLONING"},
+#endif /* RTF_PRCLONING */
+#ifdef RTF_WASCLONED
+  {RTF_WASCLONED, "WASCLONED"},
+#endif /* RTF_WASCLONED */
+#ifdef RTF_PROTO3
+  {RTF_PROTO3,    "PROTO3"},
+#endif /* RTF_PROTO3 */
+#ifdef RTF_PINNED
+  {RTF_PINNED,    "PINNED"},
+#endif /* RTF_PINNED */
+#ifdef RTF_LOCAL
+  {RTF_LOCAL,    "LOCAL"},
+#endif /* RTF_LOCAL */
+#ifdef RTF_BROADCAST
+  {RTF_BROADCAST, "BROADCAST"},
+#endif /* RTF_BROADCAST */
+#ifdef RTF_MULTICAST
+  {RTF_MULTICAST, "MULTICAST"},
+#endif /* RTF_MULTICAST */
+  {0,             NULL}
+};
+
+/* Kernel routing update socket. */
+int routing_sock = -1;
+
+/* Yes I'm checking ugly routing socket behavior. */
+/* #define DEBUG */
+
+/* Supported address family check. */
+static int
+af_check (int family)
+{
+  if (family == AF_INET)
+    return 1;
+#ifdef HAVE_IPV6
+  if (family == AF_INET6)
+    return 1;
+#endif /* HAVE_IPV6 */
+  return 0;
+}
+
+/* Dump routing table flag for debug purpose. */
+void
+rtm_flag_dump (int flag)
+{
+  struct message *mes;
+  static char buf[BUFSIZ];
+
+  for (mes = rtm_flag_str; mes->key != 0; mes++)
+    {
+      if (mes->key & flag)
+	{
+	  strlcat (buf, mes->str, BUFSIZ);
+	  strlcat (buf, " ", BUFSIZ);
+	}
+    }
+  zlog_info ("Kernel: %s", buf);
+}
+
+#ifdef RTM_IFANNOUNCE
+/* Interface adding function */
+int
+ifan_read (struct if_announcemsghdr *ifan)
+{
+  struct interface *ifp;
+
+  ifp = if_lookup_by_index (ifan->ifan_index);
+  if (ifp == NULL && ifan->ifan_what == IFAN_ARRIVAL)
+    {
+      /* Create Interface */
+      ifp = if_get_by_name (ifan->ifan_name);
+      ifp->ifindex = ifan->ifan_index;
+
+      if_add_update (ifp);
+    }
+  else if (ifp != NULL && ifan->ifan_what == IFAN_DEPARTURE)
+    {
+      if_delete_update (ifp);
+      if_delete (ifp);
+    }
+
+  if_get_flags (ifp);
+  if_get_mtu (ifp);
+  if_get_metric (ifp);
+
+  if (IS_ZEBRA_DEBUG_KERNEL)
+    zlog_info ("interface %s index %d", ifp->name, ifp->ifindex);
+
+  return 0;
+}
+#endif /* RTM_IFANNOUNCE */
+
+/* Interface adding function called from interface_list. */
+int
+ifm_read (struct if_msghdr *ifm)
+{
+  struct interface *ifp;
+  struct sockaddr_dl *sdl = NULL;
+
+  sdl = (struct sockaddr_dl *)(ifm + 1);
+
+  /* Use sdl index. */
+  ifp = if_lookup_by_index (ifm->ifm_index);
+
+  if (ifp == NULL)
+    {
+      /* Check interface's address.*/
+      if (! (ifm->ifm_addrs & RTA_IFP))
+	{
+	  zlog_warn ("There must be RTA_IFP address for ifindex %d\n",
+		     ifm->ifm_index);
+	  return -1;
+	}
+
+      ifp = if_create ();
+
+      strncpy (ifp->name, sdl->sdl_data, sdl->sdl_nlen);
+      ifp->ifindex = ifm->ifm_index;
+      ifp->flags = ifm->ifm_flags;
+#if defined(__bsdi__)
+      if_kvm_get_mtu (ifp);
+#else
+      if_get_mtu (ifp);
+#endif /* __bsdi__ */
+      if_get_metric (ifp);
+
+      /* Fetch hardware address. */
+      if (sdl->sdl_family != AF_LINK)
+	{
+	  zlog_warn ("sockaddr_dl->sdl_family is not AF_LINK");
+	  return -1;
+	}
+      memcpy (&ifp->sdl, sdl, sizeof (struct sockaddr_dl));
+
+      if_add_update (ifp);
+    }
+  else
+    {
+      /* There is a case of promisc, allmulti flag modification. */
+      if (if_is_up (ifp))
+	{
+	  ifp->flags = ifm->ifm_flags;
+	  if (! if_is_up (ifp))
+	    if_down (ifp);
+	}
+      else
+	{
+	  ifp->flags = ifm->ifm_flags;
+	  if (if_is_up (ifp))
+	    if_up (ifp);
+	}
+    }
+  
+#ifdef HAVE_NET_RT_IFLIST
+  ifp->stats = ifm->ifm_data;
+#endif /* HAVE_NET_RT_IFLIST */
+
+  if (IS_ZEBRA_DEBUG_KERNEL)
+    zlog_info ("interface %s index %d", ifp->name, ifp->ifindex);
+
+  return 0;
+}
+
+/* Address read from struct ifa_msghdr. */
+void
+ifam_read_mesg (struct ifa_msghdr *ifm,
+		union sockunion *addr,
+		union sockunion *mask,
+		union sockunion *dest)
+{
+  caddr_t pnt, end;
+
+  pnt = (caddr_t)(ifm + 1);
+  end = ((caddr_t)ifm) + ifm->ifam_msglen;
+
+#define IFAMADDRGET(X,R) \
+    if (ifm->ifam_addrs & (R)) \
+      { \
+        int len = WRAPUP(pnt); \
+        if (((X) != NULL) && af_check (((struct sockaddr *)pnt)->sa_family)) \
+          memcpy ((caddr_t)(X), pnt, len); \
+        pnt += len; \
+      }
+#define IFAMMASKGET(X,R) \
+    if (ifm->ifam_addrs & (R)) \
+      { \
+	int len = WRAPUP(pnt); \
+        if ((X) != NULL) \
+	  memcpy ((caddr_t)(X), pnt, len); \
+	pnt += len; \
+      }
+
+  /* Be sure structure is cleared */
+  memset (mask, 0, sizeof (union sockunion));
+  memset (addr, 0, sizeof (union sockunion));
+  memset (dest, 0, sizeof (union sockunion));
+
+  /* We fetch each socket variable into sockunion. */
+  IFAMADDRGET (NULL, RTA_DST);
+  IFAMADDRGET (NULL, RTA_GATEWAY);
+  IFAMMASKGET (mask, RTA_NETMASK);
+  IFAMADDRGET (NULL, RTA_GENMASK);
+  IFAMADDRGET (NULL, RTA_IFP);
+  IFAMADDRGET (addr, RTA_IFA);
+  IFAMADDRGET (NULL, RTA_AUTHOR);
+  IFAMADDRGET (dest, RTA_BRD);
+
+  /* Assert read up end point matches to end point */
+  if (pnt != end)
+    zlog_warn ("ifam_read() does't read all socket data");
+}
+
+/* Interface's address information get. */
+int
+ifam_read (struct ifa_msghdr *ifam)
+{
+  struct interface *ifp;
+  union sockunion addr, mask, gate;
+
+  /* Check does this interface exist or not. */
+  ifp = if_lookup_by_index (ifam->ifam_index);
+  if (ifp == NULL) 
+    {
+      zlog_warn ("no interface for index %d", ifam->ifam_index); 
+      return -1;
+    }
+
+  /* Allocate and read address information. */
+  ifam_read_mesg (ifam, &addr, &mask, &gate);
+
+  /* Check interface flag for implicit up of the interface. */
+  if_refresh (ifp);
+
+  /* Add connected address. */
+  switch (sockunion_family (&addr))
+    {
+    case AF_INET:
+      if (ifam->ifam_type == RTM_NEWADDR)
+	connected_add_ipv4 (ifp, 0, &addr.sin.sin_addr, 
+			    ip_masklen (mask.sin.sin_addr),
+			    &gate.sin.sin_addr, NULL);
+      else
+	connected_delete_ipv4 (ifp, 0, &addr.sin.sin_addr, 
+			       ip_masklen (mask.sin.sin_addr),
+			       &gate.sin.sin_addr, NULL);
+      break;
+#ifdef HAVE_IPV6
+    case AF_INET6:
+      /* Unset interface index from link-local address when IPv6 stack
+	 is KAME. */
+      if (IN6_IS_ADDR_LINKLOCAL (&addr.sin6.sin6_addr))
+	SET_IN6_LINKLOCAL_IFINDEX (addr.sin6.sin6_addr, 0);
+
+      if (ifam->ifam_type == RTM_NEWADDR)
+	connected_add_ipv6 (ifp,
+			    &addr.sin6.sin6_addr, 
+			    ip6_masklen (mask.sin6.sin6_addr),
+			    &gate.sin6.sin6_addr);
+      else
+	connected_delete_ipv6 (ifp,
+			       &addr.sin6.sin6_addr, 
+			       ip6_masklen (mask.sin6.sin6_addr),
+			       &gate.sin6.sin6_addr);
+      break;
+#endif /* HAVE_IPV6 */
+    default:
+      /* Unsupported family silently ignore... */
+      break;
+    }
+  return 0;
+}
+
+/* Interface function for reading kernel routing table information. */
+int
+rtm_read_mesg (struct rt_msghdr *rtm,
+	       union sockunion *dest,
+	       union sockunion *mask,
+	       union sockunion *gate)
+{
+  caddr_t pnt, end;
+
+  /* Pnt points out socket data start point. */
+  pnt = (caddr_t)(rtm + 1);
+  end = ((caddr_t)rtm) + rtm->rtm_msglen;
+
+  /* rt_msghdr version check. */
+  if (rtm->rtm_version != RTM_VERSION) 
+      zlog (NULL, LOG_WARNING,
+	      "Routing message version different %d should be %d."
+	      "This may cause problem\n", rtm->rtm_version, RTM_VERSION);
+
+#define RTMADDRGET(X,R) \
+    if (rtm->rtm_addrs & (R)) \
+      { \
+	int len = WRAPUP (pnt); \
+        if (((X) != NULL) && af_check (((struct sockaddr *)pnt)->sa_family)) \
+	  memcpy ((caddr_t)(X), pnt, len); \
+	pnt += len; \
+      }
+#define RTMMASKGET(X,R) \
+    if (rtm->rtm_addrs & (R)) \
+      { \
+	int len = WRAPUP (pnt); \
+        if ((X) != NULL) \
+	  memcpy ((caddr_t)(X), pnt, len); \
+	pnt += len; \
+      }
+
+  /* Be sure structure is cleared */
+  memset (dest, 0, sizeof (union sockunion));
+  memset (gate, 0, sizeof (union sockunion));
+  memset (mask, 0, sizeof (union sockunion));
+
+  /* We fetch each socket variable into sockunion. */
+  RTMADDRGET (dest, RTA_DST);
+  RTMADDRGET (gate, RTA_GATEWAY);
+  RTMMASKGET (mask, RTA_NETMASK);
+  RTMADDRGET (NULL, RTA_GENMASK);
+  RTMADDRGET (NULL, RTA_IFP);
+  RTMADDRGET (NULL, RTA_IFA);
+  RTMADDRGET (NULL, RTA_AUTHOR);
+  RTMADDRGET (NULL, RTA_BRD);
+
+  /* If there is netmask information set it's family same as
+     destination family*/
+  if (rtm->rtm_addrs & RTA_NETMASK)
+    mask->sa.sa_family = dest->sa.sa_family;
+
+  /* Assert read up to the end of pointer. */
+  if (pnt != end) 
+      zlog (NULL, LOG_WARNING, "rtm_read() does't read all socket data.");
+
+  return rtm->rtm_flags;
+}
+
+void
+rtm_read (struct rt_msghdr *rtm)
+{
+  int flags;
+  u_char zebra_flags;
+  union sockunion dest, mask, gate;
+
+  zebra_flags = 0;
+
+  /* Discard self send message. */
+  if (rtm->rtm_type != RTM_GET 
+      && (rtm->rtm_pid == pid || rtm->rtm_pid == old_pid))
+    return;
+
+  /* Read destination and netmask and gateway from rtm message
+     structure. */
+  flags = rtm_read_mesg (rtm, &dest, &mask, &gate);
+
+#ifdef RTF_CLONED	/*bsdi, netbsd 1.6*/
+  if (flags & RTF_CLONED)
+    return;
+#endif
+#ifdef RTF_WASCLONED	/*freebsd*/
+  if (flags & RTF_WASCLONED)
+    return;
+#endif
+
+  if ((rtm->rtm_type == RTM_ADD) && ! (flags & RTF_UP))
+    return;
+
+  /* This is connected route. */
+  if (! (flags & RTF_GATEWAY))
+      return;
+
+  if (flags & RTF_PROTO1)
+    SET_FLAG (zebra_flags, ZEBRA_FLAG_SELFROUTE);
+
+  /* This is persistent route. */
+  if (flags & RTF_STATIC)
+    SET_FLAG (zebra_flags, ZEBRA_FLAG_STATIC);
+
+  if (dest.sa.sa_family == AF_INET)
+    {
+      struct prefix_ipv4 p;
+
+      p.family = AF_INET;
+      p.prefix = dest.sin.sin_addr;
+      if (flags & RTF_HOST)
+	p.prefixlen = IPV4_MAX_PREFIXLEN;
+      else
+	p.prefixlen = ip_masklen (mask.sin.sin_addr);
+
+      if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD)
+	rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, 
+		      &p, &gate.sin.sin_addr, 0, 0, 0, 0);
+      else
+	rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, 
+		      &p, &gate.sin.sin_addr, 0, 0);
+    }
+#ifdef HAVE_IPV6
+  if (dest.sa.sa_family == AF_INET6)
+    {
+      struct prefix_ipv6 p;
+      unsigned int ifindex = 0;
+
+      p.family = AF_INET6;
+      p.prefix = dest.sin6.sin6_addr;
+      if (flags & RTF_HOST)
+	p.prefixlen = IPV6_MAX_PREFIXLEN;
+      else
+	p.prefixlen = ip6_masklen (mask.sin6.sin6_addr);
+
+#ifdef KAME
+      if (IN6_IS_ADDR_LINKLOCAL (&gate.sin6.sin6_addr))
+	{
+	  ifindex = IN6_LINKLOCAL_IFINDEX (gate.sin6.sin6_addr);
+	  SET_IN6_LINKLOCAL_IFINDEX (gate.sin6.sin6_addr, 0);
+	}
+#endif /* KAME */
+
+      if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD)
+	rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags,
+		      &p, &gate.sin6.sin6_addr, ifindex, 0);
+      else
+	rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags,
+			 &p, &gate.sin6.sin6_addr, ifindex, 0);
+    }
+#endif /* HAVE_IPV6 */
+}
+
+/* Interface function for the kernel routing table updates.  Support
+   for RTM_CHANGE will be needed. */
+int
+rtm_write (int message,
+	   union sockunion *dest,
+	   union sockunion *mask,
+	   union sockunion *gate,
+	   unsigned int index,
+	   int zebra_flags,
+	   int metric)
+{
+  int ret;
+  caddr_t pnt;
+  struct interface *ifp;
+  struct sockaddr_in tmp_gate;
+#ifdef HAVE_IPV6
+  struct sockaddr_in6 tmp_gate6;
+#endif /* HAVE_IPV6 */
+
+  /* Sequencial number of routing message. */
+  static int msg_seq = 0;
+
+  /* Struct of rt_msghdr and buffer for storing socket's data. */
+  struct 
+  {
+    struct rt_msghdr rtm;
+    char buf[512];
+  } msg;
+  
+  memset (&tmp_gate, 0, sizeof (struct sockaddr_in));
+  tmp_gate.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+  tmp_gate.sin_len = sizeof (struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+
+#ifdef HAVE_IPV6
+  memset (&tmp_gate6, 0, sizeof (struct sockaddr_in6));
+  tmp_gate6.sin6_family = AF_INET6;
+#ifdef SIN6_LEN
+  tmp_gate6.sin6_len = sizeof (struct sockaddr_in6);
+#endif /* SIN6_LEN */
+#endif /* HAVE_IPV6 */
+
+  if (routing_sock < 0)
+    return ZEBRA_ERR_EPERM;
+
+  /* Clear and set rt_msghdr values */
+  memset (&msg, 0, sizeof (struct rt_msghdr));
+  msg.rtm.rtm_version = RTM_VERSION;
+  msg.rtm.rtm_type = message;
+  msg.rtm.rtm_seq = msg_seq++;
+  msg.rtm.rtm_addrs = RTA_DST;
+  msg.rtm.rtm_addrs |= RTA_GATEWAY;
+  msg.rtm.rtm_flags = RTF_UP;
+  msg.rtm.rtm_index = index;
+
+  if (metric != 0)
+    {
+      msg.rtm.rtm_rmx.rmx_hopcount = metric;
+      msg.rtm.rtm_inits |= RTV_HOPCOUNT;
+    }
+
+  ifp = if_lookup_by_index (index);
+
+  if (gate && message == RTM_ADD)
+    msg.rtm.rtm_flags |= RTF_GATEWAY;
+
+  if (! gate && message == RTM_ADD && ifp &&
+      (ifp->flags & IFF_POINTOPOINT) == 0)
+    msg.rtm.rtm_flags |= RTF_CLONING;
+
+  /* If no protocol specific gateway is specified, use link
+     address for gateway. */
+  if (! gate)
+    {
+      if (!ifp)
+        {
+          zlog_warn ("no gateway found for interface index %d", index);
+          return -1;
+        }
+      gate = (union sockunion *) & ifp->sdl;
+    }
+
+  if (mask)
+    msg.rtm.rtm_addrs |= RTA_NETMASK;
+  else if (message == RTM_ADD) 
+    msg.rtm.rtm_flags |= RTF_HOST;
+
+  /* Tagging route with flags */
+  msg.rtm.rtm_flags |= (RTF_PROTO1);
+
+  /* Additional flags. */
+  if (zebra_flags & ZEBRA_FLAG_BLACKHOLE)
+    msg.rtm.rtm_flags |= RTF_BLACKHOLE;
+
+#ifdef HAVE_SIN_LEN
+#define SOCKADDRSET(X,R) \
+  if (msg.rtm.rtm_addrs & (R)) \
+    { \
+      int len = ROUNDUP ((X)->sa.sa_len); \
+      memcpy (pnt, (caddr_t)(X), len); \
+      pnt += len; \
+    }
+#else 
+#define SOCKADDRSET(X,R) \
+  if (msg.rtm.rtm_addrs & (R)) \
+    { \
+      int len = ROUNDUP (sizeof((X)->sa)); \
+      memcpy (pnt, (caddr_t)(X), len); \
+      pnt += len; \
+    }
+#endif /* HAVE_SIN_LEN */
+
+  pnt = (caddr_t) msg.buf;
+
+  /* Write each socket data into rtm message buffer */
+  SOCKADDRSET (dest, RTA_DST);
+  SOCKADDRSET (gate, RTA_GATEWAY);
+  SOCKADDRSET (mask, RTA_NETMASK);
+
+  msg.rtm.rtm_msglen = pnt - (caddr_t) &msg;
+
+  ret = write (routing_sock, &msg, msg.rtm.rtm_msglen);
+
+  if (ret != msg.rtm.rtm_msglen) 
+    {
+      if (errno == EEXIST) 
+	return ZEBRA_ERR_RTEXIST;
+      if (errno == ENETUNREACH)
+	return ZEBRA_ERR_RTUNREACH;
+      
+      zlog_warn ("write : %s (%d)", strerror (errno), errno);
+      return -1;
+    }
+  return 0;
+}
+
+
+#include "thread.h"
+#include "zebra/zserv.h"
+
+extern struct thread_master *master;
+
+/* For debug purpose. */
+void
+rtmsg_debug (struct rt_msghdr *rtm)
+{
+  char *type = "Unknown";
+  struct message *mes;
+
+  for (mes = rtm_type_str; mes->str; mes++)
+    if (mes->key == rtm->rtm_type)
+      {
+	type = mes->str;
+	break;
+      }
+
+  zlog_info ("Kernel: Len: %d Type: %s", rtm->rtm_msglen, type);
+  rtm_flag_dump (rtm->rtm_flags);
+  zlog_info ("Kernel: message seq %d", rtm->rtm_seq);
+  zlog_info ("Kernel: pid %d", rtm->rtm_pid);
+}
+
+/* This is pretty gross, better suggestions welcome -- mhandler */
+#ifndef RTAX_MAX
+#ifdef RTA_NUMBITS
+#define RTAX_MAX	RTA_NUMBITS
+#else
+#define RTAX_MAX	8
+#endif /* RTA_NUMBITS */
+#endif /* RTAX_MAX */
+
+/* Kernel routing table and interface updates via routing socket. */
+int
+kernel_read (struct thread *thread)
+{
+  int sock;
+  int nbytes;
+  struct rt_msghdr *rtm;
+
+  union 
+  {
+    /* Routing information. */
+    struct 
+    {
+      struct rt_msghdr rtm;
+      struct sockaddr addr[RTAX_MAX];
+    } r;
+
+    /* Interface information. */
+    struct
+    {
+      struct if_msghdr ifm;
+      struct sockaddr addr[RTAX_MAX];
+    } im;
+
+    /* Interface address information. */
+    struct
+    {
+      struct ifa_msghdr ifa;
+      struct sockaddr addr[RTAX_MAX];
+    } ia;
+
+#ifdef RTM_IFANNOUNCE
+    /* Interface arrival/departure */
+    struct
+    {
+      struct if_announcemsghdr ifan;
+      struct sockaddr addr[RTAX_MAX];
+    } ian;
+#endif /* RTM_IFANNOUNCE */
+
+  } buf;
+
+  /* Fetch routing socket. */
+  sock = THREAD_FD (thread);
+
+  nbytes= read (sock, &buf, sizeof buf);
+
+  if (nbytes <= 0)
+    {
+      if (nbytes < 0 && errno != EWOULDBLOCK && errno != EAGAIN)
+	zlog_warn ("routing socket error: %s", strerror (errno));
+      return 0;
+    }
+
+  thread_add_read (master, kernel_read, NULL, sock);
+
+#ifdef DEBUG
+  rtmsg_debug (&buf.r.rtm);
+#endif /* DEBUG */
+
+  rtm = &buf.r.rtm;
+
+  switch (rtm->rtm_type)
+    {
+    case RTM_ADD:
+    case RTM_DELETE:
+      rtm_read (rtm);
+      break;
+    case RTM_IFINFO:
+      ifm_read (&buf.im.ifm);
+      break;
+    case RTM_NEWADDR:
+    case RTM_DELADDR:
+      ifam_read (&buf.ia.ifa);
+      break;
+#ifdef RTM_IFANNOUNCE
+    case RTM_IFANNOUNCE:
+      ifan_read (&buf.ian.ifan);
+      break;
+#endif /* RTM_IFANNOUNCE */
+    default:
+      break;
+    }
+  return 0;
+}
+
+/* Make routing socket. */
+void
+routing_socket ()
+{
+  routing_sock = socket (AF_ROUTE, SOCK_RAW, 0);
+
+  if (routing_sock < 0) 
+    {
+      zlog_warn ("Can't init kernel routing socket");
+      return;
+    }
+
+  if (fcntl (routing_sock, F_SETFL, O_NONBLOCK) < 0) 
+    zlog_warn ("Can't set O_NONBLOCK to routing socket");
+
+  /* kernel_read needs rewrite. */
+  thread_add_read (master, kernel_read, NULL, routing_sock);
+}
+
+/* Exported interface function.  This function simply calls
+   routing_socket (). */
+void
+kernel_init ()
+{
+  routing_socket ();
+}
diff --git a/zebra/main.c b/zebra/main.c
new file mode 100644
index 0000000..25d8b6d
--- /dev/null
+++ b/zebra/main.c
@@ -0,0 +1,316 @@
+/*
+ * zebra daemon main routine.
+ * Copyright (C) 1997, 98 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 "version.h"
+#include "getopt.h"
+#include "command.h"
+#include "thread.h"
+#include "filter.h"
+#include "memory.h"
+#include "prefix.h"
+#include "log.h"
+
+#include "zebra/rib.h"
+#include "zebra/zserv.h"
+#include "zebra/debug.h"
+#include "zebra/rib.h"
+
+/* Master of threads. */
+struct thread_master *master;
+
+/* process id. */
+pid_t old_pid;
+pid_t pid;
+
+/* Route retain mode flag. */
+int retain_mode = 0;
+
+/* Don't delete kernel route. */
+int keep_kernel_mode = 0;
+
+/* Command line options. */
+struct option longopts[] = 
+{
+  { "batch",       no_argument,       NULL, 'b'},
+  { "daemon",      no_argument,       NULL, 'd'},
+  { "keep_kernel", no_argument,       NULL, 'k'},
+  { "log_mode",    no_argument,       NULL, 'l'},
+  { "config_file", required_argument, NULL, 'f'},
+  { "pid_file",    required_argument, NULL, 'i'},
+  { "help",        no_argument,       NULL, 'h'},
+  { "vty_addr",    required_argument, NULL, 'A'},
+  { "vty_port",    required_argument, NULL, 'P'},
+  { "retain",      no_argument,       NULL, 'r'},
+  { "version",     no_argument,       NULL, 'v'},
+  { 0 }
+};
+
+/* Default configuration file path. */
+char config_current[] = DEFAULT_CONFIG_FILE;
+char config_default[] = SYSCONFDIR DEFAULT_CONFIG_FILE;
+
+/* Process ID saved for use by init system */
+char *pid_file = PATH_ZEBRA_PID;
+
+/* Help information display. */
+static void
+usage (char *progname, int status)
+{
+  if (status != 0)
+    fprintf (stderr, "Try `%s --help' for more information.\n", progname);
+  else
+    {    
+      printf ("Usage : %s [OPTION...]\n\n\
+Daemon which manages kernel routing table management and \
+redistribution between different routing protocols.\n\n\
+-b, --batch        Runs in batch mode\n\
+-d, --daemon       Runs in daemon mode\n\
+-f, --config_file  Set configuration file name\n\
+-i, --pid_file     Set process identifier file name\n\
+-k, --keep_kernel  Don't delete old routes which installed by zebra.\n\
+-l, --log_mode     Set verbose log mode flag\n\
+-A, --vty_addr     Set vty's bind address\n\
+-P, --vty_port     Set vty's port number\n\
+-r, --retain       When program terminates, retain added route by zebra.\n\
+-v, --version      Print program version\n\
+-h, --help         Display this help and exit\n\
+\n\
+Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS);
+    }
+
+  exit (status);
+}
+
+/* SIGHUP handler. */
+void 
+sighup (int sig)
+{
+  zlog_info ("SIGHUP received");
+
+  /* Reload of config file. */
+  ;
+}
+
+/* SIGINT handler. */
+void
+sigint (int sig)
+{
+  /* Decrared in rib.c */
+  void rib_close ();
+
+  zlog_info ("Terminating on signal");
+
+  if (!retain_mode)
+    rib_close ();
+
+  exit (0);
+}
+
+/* SIGUSR1 handler. */
+void
+sigusr1 (int sig)
+{
+  zlog_rotate (NULL);
+}
+
+/* Signale wrapper. */
+RETSIGTYPE *
+signal_set (int signo, void (*func)(int))
+{
+  int ret;
+  struct sigaction sig;
+  struct sigaction osig;
+
+  sig.sa_handler = func;
+  sigemptyset (&sig.sa_mask);
+  sig.sa_flags = 0;
+#ifdef SA_RESTART
+  sig.sa_flags |= SA_RESTART;
+#endif /* SA_RESTART */
+
+  ret = sigaction (signo, &sig, &osig);
+
+  if (ret < 0) 
+    return (SIG_ERR);
+  else
+    return (osig.sa_handler);
+}
+
+/* Initialization of signal handles. */
+void
+signal_init ()
+{
+  signal_set (SIGHUP, sighup);
+  signal_set (SIGINT, sigint);
+  signal_set (SIGTERM, sigint);
+  signal_set (SIGPIPE, SIG_IGN);
+  signal_set (SIGUSR1, sigusr1);
+}
+
+/* Main startup routine. */
+int
+main (int argc, char **argv)
+{
+  char *p;
+  char *vty_addr = NULL;
+  int vty_port = 0;
+  int batch_mode = 0;
+  int daemon_mode = 0;
+  char *config_file = NULL;
+  char *progname;
+  struct thread thread;
+  void rib_weed_tables ();
+  void zebra_vty_init ();
+
+  /* Set umask before anything for security */
+  umask (0027);
+
+  /* preserve my name */
+  progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]);
+
+  zlog_default = openzlog (progname, ZLOG_STDOUT, ZLOG_ZEBRA,
+			   LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON);
+
+  while (1) 
+    {
+      int opt;
+  
+      opt = getopt_long (argc, argv, "bdklf:hA:P:rv", longopts, 0);
+
+      if (opt == EOF)
+	break;
+
+      switch (opt) 
+	{
+	case 0:
+	  break;
+	case 'b':
+	  batch_mode = 1;
+	case 'd':
+	  daemon_mode = 1;
+	  break;
+	case 'k':
+	  keep_kernel_mode = 1;
+	  break;
+	case 'l':
+	  /* log_mode = 1; */
+	  break;
+	case 'f':
+	  config_file = optarg;
+	  break;
+	case 'A':
+	  vty_addr = optarg;
+	  break;
+        case 'i':
+          pid_file = optarg;
+          break;
+	case 'P':
+	  vty_port = atoi (optarg);
+	  break;
+	case 'r':
+	  retain_mode = 1;
+	  break;
+	case 'v':
+	  print_version (progname);
+	  exit (0);
+	  break;
+	case 'h':
+	  usage (progname, 0);
+	  break;
+	default:
+	  usage (progname, 1);
+	  break;
+	}
+    }
+
+  /* Make master thread emulator. */
+  master = thread_master_create ();
+
+  /* Vty related initialize. */
+  signal_init ();
+  cmd_init (1);
+  vty_init ();
+  memory_init ();
+
+  /* Zebra related initialize. */
+  zebra_init ();
+  rib_init ();
+  zebra_if_init ();
+  zebra_debug_init ();
+  zebra_vty_init ();
+  access_list_init ();
+  rtadv_init ();
+
+  /* For debug purpose. */
+  /* SET_FLAG (zebra_debug_event, ZEBRA_DEBUG_EVENT); */
+
+  /* Make kernel routing socket. */
+  kernel_init ();
+  interface_list ();
+  route_read ();
+
+  /* Sort VTY commands. */
+  sort_node ();
+
+#ifdef HAVE_SNMP
+  zebra_snmp_init ();
+#endif /* HAVE_SNMP */
+
+  /* Clean up self inserted route. */
+  if (! keep_kernel_mode)
+    rib_sweep_route ();
+
+  /* Configuration file read*/
+  vty_read_config (config_file, config_current, config_default);
+
+  /* Clean up rib. */
+  rib_weed_tables ();
+
+  /* Exit when zebra is working in batch mode. */
+  if (batch_mode)
+    exit (0);
+
+  /* Needed for BSD routing socket. */
+  old_pid = getpid ();
+
+  /* Daemonize. */
+  if (daemon_mode)
+    daemon (0, 0);
+
+  /* Output pid of zebra. */
+  pid_output (pid_file);
+
+  /* Needed for BSD routing socket. */
+  pid = getpid ();
+
+  /* Make vty server socket. */
+  vty_serv_sock (vty_addr,
+		 vty_port ? vty_port : ZEBRA_VTY_PORT, ZEBRA_VTYSH_PATH);
+
+  while (thread_fetch (master, &thread))
+    thread_call (&thread);
+
+  /* Not reached... */
+  exit (0);
+}
diff --git a/zebra/mtu_kvm.c b/zebra/mtu_kvm.c
new file mode 100644
index 0000000..3731dab
--- /dev/null
+++ b/zebra/mtu_kvm.c
@@ -0,0 +1,97 @@
+/* MTU get using kvm_read.
+ * Copyright (C) 1999 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 <kvm.h>
+#include <limits.h>
+#include <fcntl.h>
+
+#include "if.h"
+
+/* get interface MTU to use kvm_read */
+void
+if_kvm_get_mtu (struct interface *ifp)
+{
+  kvm_t *kvmd;
+  struct ifnet ifnet;
+  unsigned long ifnetaddr;
+  int len;
+ 
+  char ifname[IFNAMSIZ];
+  char tname[INTERFACE_NAMSIZ + 1];
+  char buf[_POSIX2_LINE_MAX];
+ 
+  struct nlist nl[] = 
+  {
+    {"_ifnet"},
+    {""}
+  };
+
+  ifp->mtu = -1;
+  
+  kvmd = kvm_openfiles (NULL, NULL, NULL, O_RDONLY, buf);
+
+  if (kvmd == NULL) 
+    return ;
+  
+  kvm_nlist(kvmd, nl);
+ 
+  ifnetaddr = nl[0].n_value;
+ 
+  if (kvm_read(kvmd, ifnetaddr, (char *)&ifnetaddr, sizeof ifnetaddr) < 0) 
+    {
+      kvm_close (kvmd);
+      return ;
+    }
+ 
+  while(ifnetaddr != 0) 
+    {
+      if (kvm_read (kvmd, ifnetaddr, (char *)&ifnet, sizeof ifnet) < 0) 
+	{
+	  kvm_close (kvmd);
+	  return ;
+	}
+
+      if (kvm_read (kvmd, (u_long)ifnet.if_name, ifname, IFNAMSIZ) < 0) 
+	{
+	  kvm_close (kvmd);
+	  return ;
+	}
+
+      len = snprintf (tname, INTERFACE_NAMSIZ + 1, 
+		      "%s%d", ifname, ifnet.if_unit);
+
+      if (strncmp (tname, ifp->name, len) == 0)
+	break;
+
+      ifnetaddr = (u_long)ifnet.if_next;
+    }
+
+  kvm_close (kvmd);
+
+  if (ifnetaddr == 0) 
+    {
+      return ;
+    }
+
+  ifp->mtu = ifnet.if_mtu;
+}
diff --git a/zebra/redistribute.c b/zebra/redistribute.c
new file mode 100644
index 0000000..a3d4bad
--- /dev/null
+++ b/zebra/redistribute.c
@@ -0,0 +1,410 @@
+/* Redistribution Handler
+ * Copyright (C) 1998 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 "vector.h"
+#include "vty.h"
+#include "command.h"
+#include "prefix.h"
+#include "table.h"
+#include "stream.h"
+#include "zclient.h"
+#include "linklist.h"
+#include "log.h"
+
+#include "zebra/rib.h"
+#include "zebra/zserv.h"
+#include "zebra/redistribute.h"
+#include "zebra/debug.h"
+
+int
+zebra_check_addr (struct prefix *p)
+{
+  if (p->family == AF_INET)
+    {
+      u_int32_t addr;
+
+      addr = p->u.prefix4.s_addr;
+      addr = ntohl (addr);
+
+      if (IPV4_NET127 (addr) || IN_CLASSD (addr))
+	return 0;
+    }
+#ifdef HAVE_IPV6
+  if (p->family == AF_INET6)
+    {
+      if (IN6_IS_ADDR_LOOPBACK (&p->u.prefix6))
+	return 0;
+      if (IN6_IS_ADDR_LINKLOCAL(&p->u.prefix6))
+	return 0;
+    }
+#endif /* HAVE_IPV6 */
+  return 1;
+}
+
+int
+is_default (struct prefix *p)
+{
+  if (p->family == AF_INET)
+    if (p->u.prefix4.s_addr == 0 && p->prefixlen == 0)
+      return 1;
+#ifdef HAVE_IPV6
+#if 0  /* IPv6 default separation is now pending until protocol daemon
+          can handle that. */
+  if (p->family == AF_INET6)
+    if (IN6_IS_ADDR_UNSPECIFIED (&p->u.prefix6) && p->prefixlen == 0)
+      return 1;
+#endif /* 0 */
+#endif /* HAVE_IPV6 */
+  return 0;
+}
+
+void
+zebra_redistribute_default (struct zserv *client)
+{
+  struct prefix_ipv4 p;
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *newrib;
+#ifdef HAVE_IPV6
+  struct prefix_ipv6 p6;
+#endif /* HAVE_IPV6 */
+
+
+  /* Lookup default route. */
+  memset (&p, 0, sizeof (struct prefix_ipv4));
+  p.family = AF_INET;
+
+  /* Lookup table.  */
+  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  if (table)
+    {
+      rn = route_node_lookup (table, (struct prefix *)&p);
+      if (rn)
+	{
+	  for (newrib = rn->info; newrib; newrib = newrib->next)
+	    if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED)
+		&& newrib->distance != DISTANCE_INFINITY)
+	      zsend_ipv4_add_multipath (client, &rn->p, newrib);
+	  route_unlock_node (rn);
+	}
+    }
+
+#ifdef HAVE_IPV6
+  /* Lookup default route. */
+  memset (&p6, 0, sizeof (struct prefix_ipv6));
+  p6.family = AF_INET6;
+
+  /* Lookup table.  */
+  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
+  if (table)
+    {
+      rn = route_node_lookup (table, (struct prefix *)&p6);
+      if (rn)
+	{
+	  for (newrib = rn->info; newrib; newrib = newrib->next)
+	    if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED)
+		&& newrib->distance != DISTANCE_INFINITY)
+	      zsend_ipv6_add_multipath (client, &rn->p, newrib);
+	  route_unlock_node (rn);
+	}
+    }
+#endif /* HAVE_IPV6 */
+}
+
+/* Redistribute routes. */
+void
+zebra_redistribute (struct zserv *client, int type)
+{
+  struct rib *newrib;
+  struct route_table *table;
+  struct route_node *rn;
+
+  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  if (table)
+    for (rn = route_top (table); rn; rn = route_next (rn))
+      for (newrib = rn->info; newrib; newrib = newrib->next)
+	if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED) 
+	    && newrib->type == type 
+	    && newrib->distance != DISTANCE_INFINITY
+	    && zebra_check_addr (&rn->p))
+	  zsend_ipv4_add_multipath (client, &rn->p, newrib);
+  
+#ifdef HAVE_IPV6
+  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
+  if (table)
+    for (rn = route_top (table); rn; rn = route_next (rn))
+      for (newrib = rn->info; newrib; newrib = newrib->next)
+	if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED)
+	    && newrib->type == type 
+	    && newrib->distance != DISTANCE_INFINITY
+	    && zebra_check_addr (&rn->p))
+	  zsend_ipv6_add_multipath (client, &rn->p, newrib);
+#endif /* HAVE_IPV6 */
+}
+
+extern list client_list;
+
+void
+redistribute_add (struct prefix *p, struct rib *rib)
+{
+  listnode node;
+  struct zserv *client;
+
+  for (node = listhead (client_list); node; nextnode (node))
+    if ((client = getdata (node)) != NULL)
+      {
+	if (is_default (p))
+	  {
+	    if (client->redist_default || client->redist[rib->type])
+	      {
+		if (p->family == AF_INET)
+		  zsend_ipv4_add_multipath (client, p, rib);
+#ifdef HAVE_IPV6
+		if (p->family == AF_INET6)
+		  zsend_ipv6_add_multipath (client, p, rib);
+#endif /* HAVE_IPV6 */	  
+	      }
+	  }
+	else if (client->redist[rib->type])
+	  {
+	    if (p->family == AF_INET)
+	      zsend_ipv4_add_multipath (client, p, rib);
+#ifdef HAVE_IPV6
+	    if (p->family == AF_INET6)
+	      zsend_ipv6_add_multipath (client, p, rib);
+#endif /* HAVE_IPV6 */	  
+	  }
+      }
+}
+
+void
+redistribute_delete (struct prefix *p, struct rib *rib)
+{
+  listnode node;
+  struct zserv *client;
+
+  /* Add DISTANCE_INFINITY check. */
+  if (rib->distance == DISTANCE_INFINITY)
+    return;
+
+  for (node = listhead (client_list); node; nextnode (node))
+    if ((client = getdata (node)) != NULL)
+      {
+	if (is_default (p))
+	  {
+	    if (client->redist_default || client->redist[rib->type])
+	      {
+		if (p->family == AF_INET)
+		  zsend_ipv4_delete_multipath (client, p, rib);
+#ifdef HAVE_IPV6
+		if (p->family == AF_INET6)
+		  zsend_ipv6_delete_multipath (client, p, rib);
+#endif /* HAVE_IPV6 */	  
+	      }
+	  }
+	else if (client->redist[rib->type])
+	  {
+	    if (p->family == AF_INET)
+	      zsend_ipv4_delete_multipath (client, p, rib);
+#ifdef HAVE_IPV6
+	    if (p->family == AF_INET6)
+	      zsend_ipv6_delete_multipath (client, p, rib);
+#endif /* HAVE_IPV6 */	  
+	  }
+      }
+}
+
+void
+zebra_redistribute_add (int command, struct zserv *client, int length)
+{
+  int type;
+
+  type = stream_getc (client->ibuf);
+
+  switch (type)
+    {
+    case ZEBRA_ROUTE_KERNEL:
+    case ZEBRA_ROUTE_CONNECT:
+    case ZEBRA_ROUTE_STATIC:
+    case ZEBRA_ROUTE_RIP:
+    case ZEBRA_ROUTE_RIPNG:
+    case ZEBRA_ROUTE_OSPF:
+    case ZEBRA_ROUTE_OSPF6:
+    case ZEBRA_ROUTE_BGP:
+      if (! client->redist[type])
+	{
+	  client->redist[type] = 1;
+	  zebra_redistribute (client, type);
+	}
+      break;
+    default:
+      break;
+    }
+}     
+
+void
+zebra_redistribute_delete (int command, struct zserv *client, int length)
+{
+  int type;
+
+  type = stream_getc (client->ibuf);
+
+  switch (type)
+    {
+    case ZEBRA_ROUTE_KERNEL:
+    case ZEBRA_ROUTE_CONNECT:
+    case ZEBRA_ROUTE_STATIC:
+    case ZEBRA_ROUTE_RIP:
+    case ZEBRA_ROUTE_RIPNG:
+    case ZEBRA_ROUTE_OSPF:
+    case ZEBRA_ROUTE_OSPF6:
+    case ZEBRA_ROUTE_BGP:
+      client->redist[type] = 0;
+      break;
+    default:
+      break;
+    }
+}     
+
+void
+zebra_redistribute_default_add (int command, struct zserv *client, int length)
+{
+  client->redist_default = 1;
+  zebra_redistribute_default (client);
+}     
+
+void
+zebra_redistribute_default_delete (int command, struct zserv *client,
+				   int length)
+{
+  client->redist_default = 0;;
+}     
+
+/* Interface up information. */
+void
+zebra_interface_up_update (struct interface *ifp)
+{
+  listnode node;
+  struct zserv *client;
+
+  if (IS_ZEBRA_DEBUG_EVENT)
+    zlog_info ("MESSAGE: ZEBRA_INTERFACE_UP %s", ifp->name);
+
+  for (node = listhead (client_list); node; nextnode (node))
+    if ((client = getdata (node)) != NULL)
+      zsend_interface_up (client, ifp);
+}
+
+/* Interface down information. */
+void
+zebra_interface_down_update (struct interface *ifp)
+{
+  listnode node;
+  struct zserv *client;
+
+  if (IS_ZEBRA_DEBUG_EVENT)
+    zlog_info ("MESSAGE: ZEBRA_INTERFACE_DOWN %s", ifp->name);
+
+  for (node = listhead (client_list); node; nextnode (node))
+    if ((client = getdata (node)) != NULL)
+      zsend_interface_down (client, ifp);
+}
+
+/* Interface information update. */
+void
+zebra_interface_add_update (struct interface *ifp)
+{
+  listnode node;
+  struct zserv *client;
+
+  if (IS_ZEBRA_DEBUG_EVENT)
+    zlog_info ("MESSAGE: ZEBRA_INTERFACE_ADD %s", ifp->name);
+    
+  for (node = listhead (client_list); node; nextnode (node))
+    if ((client = getdata (node)) != NULL)
+      if (client->ifinfo)
+	zsend_interface_add (client, ifp);
+}
+
+void
+zebra_interface_delete_update (struct interface *ifp)
+{
+  listnode node;
+  struct zserv *client;
+
+  if (IS_ZEBRA_DEBUG_EVENT)
+    zlog_info ("MESSAGE: ZEBRA_INTERFACE_DELETE %s", ifp->name);
+
+  for (node = listhead (client_list); node; nextnode (node))
+    if ((client = getdata (node)) != NULL)
+      if (client->ifinfo)
+	zsend_interface_delete (client, ifp);
+}
+
+/* Interface address addition. */
+void
+zebra_interface_address_add_update (struct interface *ifp,
+				    struct connected *ifc)
+{
+  listnode node;
+  struct zserv *client;
+  struct prefix *p;
+  char buf[BUFSIZ];
+
+  if (IS_ZEBRA_DEBUG_EVENT)
+    {
+      p = ifc->address;
+      zlog_info ("MESSAGE: ZEBRA_INTERFACE_ADDRESS_ADD %s/%d on %s",
+		 inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
+		 p->prefixlen, ifc->ifp->name);
+    }
+
+  for (node = listhead (client_list); node; nextnode (node))
+    if ((client = getdata (node)) != NULL)
+      if (client->ifinfo && CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
+	zsend_interface_address_add (client, ifp, ifc);
+}
+
+/* Interface address deletion. */
+void
+zebra_interface_address_delete_update (struct interface *ifp,
+				       struct connected *ifc)
+{
+  listnode node;
+  struct zserv *client;
+  struct prefix *p;
+  char buf[BUFSIZ];
+
+  if (IS_ZEBRA_DEBUG_EVENT)
+    {
+      p = ifc->address;
+      zlog_info ("MESSAGE: ZEBRA_INTERFACE_ADDRESS_DELETE %s/%d on %s",
+		 inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
+		 p->prefixlen, ifc->ifp->name);
+    }
+
+  for (node = listhead (client_list); node; nextnode (node))
+    if ((client = getdata (node)) != NULL)
+      if (client->ifinfo && CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
+	zsend_interface_address_delete (client, ifp, ifc);
+}
diff --git a/zebra/redistribute.h b/zebra/redistribute.h
new file mode 100644
index 0000000..8b45cf3
--- /dev/null
+++ b/zebra/redistribute.h
@@ -0,0 +1,49 @@
+/*
+ * Redistribution Handler
+ * Copyright (C) 1999 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.  
+ */
+
+#ifndef _ZEBRA_REDISTRIBUTE_H
+#define _ZEBRA_REDISTRIBUTE_H
+
+#include "table.h"
+
+void zebra_redistribute_add (int, struct zserv *, int);
+void zebra_redistribute_delete (int, struct zserv *, int);
+
+void zebra_redistribute_default_add (int, struct zserv *, int);
+void zebra_redistribute_default_delete (int, struct zserv *, int);
+
+void redistribute_add (struct prefix *, struct rib *);
+void redistribute_delete (struct prefix *, struct rib *);
+
+void zebra_interface_up_update (struct interface *);
+void zebra_interface_down_update (struct interface *);
+
+void zebra_interface_add_update (struct interface *);
+void zebra_interface_delete_update (struct interface *);
+
+void zebra_interface_address_add_update (struct interface *,
+					 struct connected *);
+void zebra_interface_address_delete_update (struct interface *,
+					    struct connected *c);
+
+#endif /* _ZEBRA_REDISTRIBUTE_H */
+
diff --git a/zebra/rib.h b/zebra/rib.h
new file mode 100644
index 0000000..f501261
--- /dev/null
+++ b/zebra/rib.h
@@ -0,0 +1,251 @@
+/*
+ * Routing Information Base header
+ * Copyright (C) 1997 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.  
+ */
+
+#ifndef _ZEBRA_RIB_H
+#define _ZEBRA_RIB_H
+
+#define DISTANCE_INFINITY  255
+
+/* Routing information base. */
+struct rib
+{
+  /* Link list. */
+  struct rib *next;
+  struct rib *prev;
+
+  /* Type fo this route. */
+  int type;
+
+  /* Which routing table */
+  int table;			
+
+  /* Distance. */
+  u_char distance;
+
+  /* Flags of this route.  This flag's definition is in lib/zebra.h
+     ZEBRA_FLAG_* */
+  u_char flags;
+
+  /* Metric */
+  u_int32_t metric;
+
+  /* Uptime. */
+  time_t uptime;
+
+  /* Refrence count. */
+  unsigned long refcnt;
+
+  /* Nexthop information. */
+  u_char nexthop_num;
+  u_char nexthop_active_num;
+  u_char nexthop_fib_num;
+
+  struct nexthop *nexthop;
+};
+
+/* Static route information. */
+struct static_ipv4
+{
+  /* For linked list. */
+  struct static_ipv4 *prev;
+  struct static_ipv4 *next;
+
+  /* Administrative distance. */
+  u_char distance;
+
+  /* Flag for this static route's type. */
+  u_char type;
+#define STATIC_IPV4_GATEWAY     1
+#define STATIC_IPV4_IFNAME      2
+#define STATIC_IPV4_BLACKHOLE   3
+
+  /* Nexthop value. */
+  union 
+  {
+    struct in_addr ipv4;
+    char *ifname;
+  } gate;
+};
+
+#ifdef HAVE_IPV6
+/* Static route information. */
+struct static_ipv6
+{
+  /* For linked list. */
+  struct static_ipv6 *prev;
+  struct static_ipv6 *next;
+
+  /* Administrative distance. */
+  u_char distance;
+
+  /* Flag for this static route's type. */
+  u_char type;
+#define STATIC_IPV6_GATEWAY          1
+#define STATIC_IPV6_GATEWAY_IFNAME   2
+#define STATIC_IPV6_IFNAME           3
+
+  /* Nexthop value. */
+  struct in6_addr ipv6;
+  char *ifname;
+};
+#endif /* HAVE_IPV6 */
+
+/* Nexthop structure. */
+struct nexthop
+{
+  struct nexthop *next;
+  struct nexthop *prev;
+
+  u_char type;
+#define NEXTHOP_TYPE_IFINDEX        1 /* Directly connected.  */
+#define NEXTHOP_TYPE_IFNAME         2 /* Interface route.  */
+#define NEXTHOP_TYPE_IPV4           3 /* IPv4 nexthop.  */
+#define NEXTHOP_TYPE_IPV4_IFINDEX   4 /* IPv4 nexthop with ifindex.  */
+#define NEXTHOP_TYPE_IPV4_IFNAME    5 /* IPv4 nexthop with ifname.  */
+#define NEXTHOP_TYPE_IPV6           6 /* IPv6 nexthop.  */
+#define NEXTHOP_TYPE_IPV6_IFINDEX   7 /* IPv6 nexthop with ifindex.  */
+#define NEXTHOP_TYPE_IPV6_IFNAME    8 /* IPv6 nexthop with ifname.  */
+#define NEXTHOP_TYPE_BLACKHOLE      9 /* Null0 nexthop.  */
+
+  u_char flags;
+#define NEXTHOP_FLAG_ACTIVE     (1 << 0) /* This nexthop is alive. */
+#define NEXTHOP_FLAG_FIB        (1 << 1) /* FIB nexthop. */
+#define NEXTHOP_FLAG_RECURSIVE  (1 << 2) /* Recursive nexthop. */
+
+  /* Interface index. */
+  unsigned int ifindex;
+  char *ifname;
+
+  /* Nexthop address or interface name. */
+  union
+  {
+    struct in_addr ipv4;
+#ifdef HAVE_IPV6
+    struct in6_addr ipv6;
+#endif /* HAVE_IPV6*/
+  } gate;
+
+  /* Recursive lookup nexthop. */
+  u_char rtype;
+  unsigned int rifindex;
+  union
+  {
+    struct in_addr ipv4;
+#ifdef HAVE_IPV6
+    struct in6_addr ipv6;
+#endif /* HAVE_IPV6 */
+  } rgate;
+
+  struct nexthop *indirect;
+};
+
+/* Routing table instance.  */
+struct vrf
+{
+  /* Identifier.  This is same as routing table vector index.  */
+  u_int32_t id;
+
+  /* Routing table name.  */
+  char *name;
+
+  /* Description.  */
+  char *desc;
+
+  /* FIB identifier.  */
+  u_char fib_id;
+
+  /* Routing table.  */
+  struct route_table *table[AFI_MAX][SAFI_MAX];
+
+  /* Static route configuration.  */
+  struct route_table *stable[AFI_MAX][SAFI_MAX];
+};
+
+struct nexthop *nexthop_ifindex_add (struct rib *, unsigned int);
+struct nexthop *nexthop_ifname_add (struct rib *, char *);
+struct nexthop *nexthop_blackhole_add (struct rib *);
+struct nexthop *nexthop_ipv4_add (struct rib *, struct in_addr *);
+#ifdef HAVE_IPV6
+struct nexthop *nexthop_ipv6_add (struct rib *, struct in6_addr *);
+#endif /* HAVE_IPV6 */
+
+struct vrf *vrf_lookup (u_int32_t);
+struct route_table *vrf_table (afi_t afi, safi_t safi, u_int32_t id);
+struct route_table *vrf_static_table (afi_t afi, safi_t safi, u_int32_t id);
+
+int
+rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, 
+	      struct in_addr *gate, unsigned int ifindex, u_int32_t vrf_id,
+	      u_int32_t, u_char);
+
+int
+rib_add_ipv4_multipath (struct prefix_ipv4 *, struct rib *);
+
+int
+rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p,
+		 struct in_addr *gate, unsigned int ifindex, u_int32_t);
+
+struct rib *
+rib_match_ipv4 (struct in_addr);
+
+struct rib *
+rib_lookup_ipv4 (struct prefix_ipv4 *);
+
+void rib_update ();
+void rib_sweep_route ();
+void rib_close ();
+void rib_init ();
+
+int
+static_add_ipv4 (struct prefix *p, struct in_addr *gate, char *ifname,
+		 u_char distance, u_int32_t vrf_id);
+
+int
+static_delete_ipv4 (struct prefix *p, struct in_addr *gate, char *ifname,
+		    u_char distance, u_int32_t vrf_id);
+
+#ifdef HAVE_IPV6
+int
+rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p,
+	      struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id);
+
+int
+rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p,
+		 struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id);
+
+struct rib *rib_lookup_ipv6 (struct in6_addr *);
+
+struct rib *rib_match_ipv6 (struct in6_addr *);
+
+extern struct route_table *rib_table_ipv6;
+
+int
+static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
+		 char *ifname, u_char distance, u_int32_t vrf_id);
+
+int
+static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
+		    char *ifname, u_char distance, u_int32_t vrf_id);
+
+#endif /* HAVE_IPV6 */
+
+#endif /*_ZEBRA_RIB_H */
diff --git a/zebra/rt.h b/zebra/rt.h
new file mode 100644
index 0000000..faaddab
--- /dev/null
+++ b/zebra/rt.h
@@ -0,0 +1,40 @@
+/*
+ * kernel routing table update prototype.
+ * Copyright (C) 1998 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.  
+ */
+
+#ifndef _ZEBRA_RT_H
+#define _ZEBRA_RT_H
+
+int kernel_add_ipv4 (struct prefix *, struct rib *);
+int kernel_delete_ipv4 (struct prefix *, struct rib *);
+int kernel_add_route (struct prefix_ipv4 *, struct in_addr *, int, int);
+int kernel_address_add_ipv4 (struct interface *, struct connected *);
+int kernel_address_delete_ipv4 (struct interface *, struct connected *);
+
+#ifdef HAVE_IPV6
+int kernel_add_ipv6 (struct prefix *, struct rib *);
+int kernel_delete_ipv6 (struct prefix *, struct rib *);
+int kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
+			    unsigned int index, int flags, int table);
+
+#endif /* HAVE_IPV6 */
+
+#endif /* _ZEBRA_RT_H */
diff --git a/zebra/rt_ioctl.c b/zebra/rt_ioctl.c
new file mode 100644
index 0000000..d470572
--- /dev/null
+++ b/zebra/rt_ioctl.c
@@ -0,0 +1,558 @@
+/*
+ * kernel routing table update by ioctl().
+ * Copyright (C) 1997, 98 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 "log.h"
+#include "if.h"
+
+#include "zebra/rib.h"
+#include "zebra/debug.h"
+
+/* Initialize of kernel interface.  There is no kernel communication
+   support under ioctl().  So this is dummy stub function. */
+void
+kernel_init ()
+{
+  return;
+}
+
+/* Dummy function of routing socket. */
+void
+kernel_read (int sock)
+{
+  return;
+}
+
+#if 0
+/* Initialization prototype of struct sockaddr_in. */
+static struct sockaddr_in sin_proto =
+{
+#ifdef HAVE_SIN_LEN
+  sizeof (struct sockaddr_in), 
+#endif /* HAVE_SIN_LEN */
+  AF_INET, 0, {0}, {0}
+};
+#endif /* 0 */
+
+/* Solaris has ortentry. */
+#ifdef HAVE_OLD_RTENTRY
+#define rtentry ortentry
+#endif /* HAVE_OLD_RTENTRY */
+
+/* Interface to ioctl route message. */
+int
+kernel_add_route (struct prefix_ipv4 *dest, struct in_addr *gate,
+		  int index, int flags)
+{
+  int ret;
+  int sock;
+  struct rtentry rtentry;
+  struct sockaddr_in sin_dest, sin_mask, sin_gate;
+
+  memset (&rtentry, 0, sizeof (struct rtentry));
+
+  /* Make destination. */
+  memset (&sin_dest, 0, sizeof (struct sockaddr_in));
+  sin_dest.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+  sin_dest.sin_len = sizeof (struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+  sin_dest.sin_addr = dest->prefix;
+
+  /* Make gateway. */
+  if (gate)
+    {
+      memset (&sin_gate, 0, sizeof (struct sockaddr_in));
+      sin_gate.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+      sin_gate.sin_len = sizeof (struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+      sin_gate.sin_addr = *gate;
+    }
+
+  memset (&sin_mask, 0, sizeof (struct sockaddr_in));
+  sin_mask.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+      sin_gate.sin_len = sizeof (struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+  masklen2ip (dest->prefixlen, &sin_mask.sin_addr);
+
+  /* Set destination address, mask and gateway.*/
+  memcpy (&rtentry.rt_dst, &sin_dest, sizeof (struct sockaddr_in));
+  if (gate)
+    memcpy (&rtentry.rt_gateway, &sin_gate, sizeof (struct sockaddr_in));
+#ifndef SUNOS_5
+  memcpy (&rtentry.rt_genmask, &sin_mask, sizeof (struct sockaddr_in));
+#endif /* SUNOS_5 */
+
+  /* Routing entry flag set. */
+  if (dest->prefixlen == 32)
+    rtentry.rt_flags |= RTF_HOST;
+
+  if (gate && gate->s_addr != INADDR_ANY)
+    rtentry.rt_flags |= RTF_GATEWAY;
+
+  rtentry.rt_flags |= RTF_UP;
+
+  /* Additional flags */
+  rtentry.rt_flags |= flags;
+
+
+  /* For tagging route. */
+  /* rtentry.rt_flags |= RTF_DYNAMIC; */
+
+  /* Open socket for ioctl. */
+  sock = socket (AF_INET, SOCK_DGRAM, 0);
+  if (sock < 0)
+    {
+      zlog_warn ("can't make socket\n");
+      return -1;
+    }
+
+  /* Send message by ioctl(). */
+  ret = ioctl (sock, SIOCADDRT, &rtentry);
+  if (ret < 0)
+    {
+      switch (errno) 
+	{
+	case EEXIST:
+	  close (sock);
+	  return ZEBRA_ERR_RTEXIST;
+	  break;
+	case ENETUNREACH:
+	  close (sock);
+	  return ZEBRA_ERR_RTUNREACH;
+	  break;
+	case EPERM:
+	  close (sock);
+	  return ZEBRA_ERR_EPERM;
+	  break;
+	}
+
+      close (sock);
+      zlog_warn ("write : %s (%d)", strerror (errno), errno);
+      return 1;
+    }
+  close (sock);
+
+  return ret;
+}
+
+/* Interface to ioctl route message. */
+int
+kernel_ioctl_ipv4 (u_long cmd, struct prefix *p, struct rib *rib, int family)
+{
+  int ret;
+  int sock;
+  struct rtentry rtentry;
+  struct sockaddr_in sin_dest, sin_mask, sin_gate;
+  struct nexthop *nexthop;
+  int nexthop_num = 0;
+  struct interface *ifp;
+
+  memset (&rtentry, 0, sizeof (struct rtentry));
+
+  /* Make destination. */
+  memset (&sin_dest, 0, sizeof (struct sockaddr_in));
+  sin_dest.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+  sin_dest.sin_len = sizeof (struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+  sin_dest.sin_addr = p->u.prefix4;
+
+  if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE))
+    {
+      SET_FLAG (rtentry.rt_flags, RTF_REJECT);
+
+      if (cmd == SIOCADDRT)
+	for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+	  SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+
+      goto skip;
+    }
+
+  memset (&sin_gate, 0, sizeof (struct sockaddr_in));
+
+  /* Make gateway. */
+  for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+    {
+      if ((cmd == SIOCADDRT 
+	   && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+	  || (cmd == SIOCDELRT
+	      && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
+	{
+	  if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+	    {
+	      if (nexthop->rtype == NEXTHOP_TYPE_IPV4 ||
+		  nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
+		{
+		  sin_gate.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+		  sin_gate.sin_len = sizeof (struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+		  sin_gate.sin_addr = nexthop->rgate.ipv4;
+		  rtentry.rt_flags |= RTF_GATEWAY;
+		}
+	      if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
+		  || nexthop->rtype == NEXTHOP_TYPE_IFNAME)
+		{
+		  ifp = if_lookup_by_index (nexthop->rifindex);
+		  if (ifp)
+		    rtentry.rt_dev = ifp->name;
+		  else
+		    return -1;
+		}
+	    }
+	  else
+	    {
+	      if (nexthop->type == NEXTHOP_TYPE_IPV4 ||
+		  nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
+		{
+		  sin_gate.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+		  sin_gate.sin_len = sizeof (struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+		  sin_gate.sin_addr = nexthop->gate.ipv4;
+		  rtentry.rt_flags |= RTF_GATEWAY;
+		}
+	      if (nexthop->type == NEXTHOP_TYPE_IFINDEX
+		  || nexthop->type == NEXTHOP_TYPE_IFNAME)
+		{
+		  ifp = if_lookup_by_index (nexthop->ifindex);
+		  if (ifp)
+		    rtentry.rt_dev = ifp->name;
+		  else
+		    return -1;
+		}
+	    }
+
+	  if (cmd == SIOCADDRT)
+	    SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+
+	  nexthop_num++;
+	  break;
+	}
+    }
+
+  /* If there is no useful nexthop then return. */
+  if (nexthop_num == 0)
+    {
+      if (IS_ZEBRA_DEBUG_KERNEL)
+	zlog_info ("netlink_route_multipath(): No useful nexthop.");
+      return 0;
+    }
+
+ skip:
+
+  memset (&sin_mask, 0, sizeof (struct sockaddr_in));
+  sin_mask.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+  sin_mask.sin_len = sizeof (struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+  masklen2ip (p->prefixlen, &sin_mask.sin_addr);
+
+  /* Set destination address, mask and gateway.*/
+  memcpy (&rtentry.rt_dst, &sin_dest, sizeof (struct sockaddr_in));
+
+  if (rtentry.rt_flags & RTF_GATEWAY)
+    memcpy (&rtentry.rt_gateway, &sin_gate, sizeof (struct sockaddr_in));
+
+#ifndef SUNOS_5
+  memcpy (&rtentry.rt_genmask, &sin_mask, sizeof (struct sockaddr_in));
+#endif /* SUNOS_5 */
+
+  /* Metric.  It seems metric minus one value is installed... */
+  rtentry.rt_metric = rib->metric;
+
+  /* Routing entry flag set. */
+  if (p->prefixlen == 32)
+    rtentry.rt_flags |= RTF_HOST;
+
+  rtentry.rt_flags |= RTF_UP;
+
+  /* Additional flags */
+  /* rtentry.rt_flags |= flags; */
+
+  /* For tagging route. */
+  /* rtentry.rt_flags |= RTF_DYNAMIC; */
+
+  /* Open socket for ioctl. */
+  sock = socket (AF_INET, SOCK_DGRAM, 0);
+  if (sock < 0)
+    {
+      zlog_warn ("can't make socket\n");
+      return -1;
+    }
+
+  /* Send message by ioctl(). */
+  ret = ioctl (sock, cmd, &rtentry);
+  if (ret < 0)
+    {
+      switch (errno) 
+	{
+	case EEXIST:
+	  close (sock);
+	  return ZEBRA_ERR_RTEXIST;
+	  break;
+	case ENETUNREACH:
+	  close (sock);
+	  return ZEBRA_ERR_RTUNREACH;
+	  break;
+	case EPERM:
+	  close (sock);
+	  return ZEBRA_ERR_EPERM;
+	  break;
+	}
+
+      close (sock);
+      zlog_warn ("write : %s (%d)", strerror (errno), errno);
+      return ret;
+    }
+  close (sock);
+
+  return ret;
+}
+
+int
+kernel_add_ipv4 (struct prefix *p, struct rib *rib)
+{
+  return kernel_ioctl_ipv4 (SIOCADDRT, p, rib, AF_INET);
+}
+
+int
+kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
+{
+  return kernel_ioctl_ipv4 (SIOCDELRT, p, rib, AF_INET);
+}
+
+#ifdef HAVE_IPV6
+
+/* Below is hack for GNU libc definition and Linux 2.1.X header. */
+#undef RTF_DEFAULT
+#undef RTF_ADDRCONF
+
+#include <asm/types.h>
+
+#if defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1
+/* struct in6_rtmsg will be declared in net/route.h. */
+#else
+#include <linux/ipv6_route.h>
+#endif
+
+int
+kernel_ioctl_ipv6 (u_long type, struct prefix_ipv6 *dest, struct in6_addr *gate,
+		   int index, int flags)
+{
+  int ret;
+  int sock;
+  struct in6_rtmsg rtm;
+    
+  memset (&rtm, 0, sizeof (struct in6_rtmsg));
+
+  rtm.rtmsg_flags |= RTF_UP;
+  rtm.rtmsg_metric = 1;
+  memcpy (&rtm.rtmsg_dst, &dest->prefix, sizeof (struct in6_addr));
+  rtm.rtmsg_dst_len = dest->prefixlen;
+
+  /* We need link local index. But this should be done caller...
+  if (IN6_IS_ADDR_LINKLOCAL(&rtm.rtmsg_gateway))
+    {
+      index = if_index_address (&rtm.rtmsg_gateway);
+      rtm.rtmsg_ifindex = index;
+    }
+  else
+    rtm.rtmsg_ifindex = 0;
+  */
+
+  rtm.rtmsg_flags |= RTF_GATEWAY;
+
+  /* For tagging route. */
+  /* rtm.rtmsg_flags |= RTF_DYNAMIC; */
+
+  memcpy (&rtm.rtmsg_gateway, gate, sizeof (struct in6_addr));
+
+  if (index)
+    rtm.rtmsg_ifindex = index;
+  else
+    rtm.rtmsg_ifindex = 0;
+
+  rtm.rtmsg_metric = 1;
+  
+  sock = socket (AF_INET6, SOCK_DGRAM, 0);
+  if (sock < 0)
+    {
+      zlog_warn ("can't make socket\n");
+      return -1;
+    }
+
+  /* Send message via ioctl. */
+  ret = ioctl (sock, type, &rtm);
+  if (ret < 0)
+    {
+      zlog_warn ("can't %s ipv6 route: %s\n", type == SIOCADDRT ? "add" : "delete", 
+	   strerror(errno));
+      ret = errno;
+      close (sock);
+      return ret;
+    }
+  close (sock);
+
+  return ret;
+}
+
+int
+kernel_ioctl_ipv6_multipath (u_long cmd, struct prefix *p, struct rib *rib,
+			     int family)
+{
+  int ret;
+  int sock;
+  struct in6_rtmsg rtm;
+  struct nexthop *nexthop;
+  int nexthop_num = 0;
+    
+  memset (&rtm, 0, sizeof (struct in6_rtmsg));
+
+  rtm.rtmsg_flags |= RTF_UP;
+  rtm.rtmsg_metric = rib->metric;
+  memcpy (&rtm.rtmsg_dst, &p->u.prefix, sizeof (struct in6_addr));
+  rtm.rtmsg_dst_len = p->prefixlen;
+
+  /* We need link local index. But this should be done caller...
+  if (IN6_IS_ADDR_LINKLOCAL(&rtm.rtmsg_gateway))
+    {
+      index = if_index_address (&rtm.rtmsg_gateway);
+      rtm.rtmsg_ifindex = index;
+    }
+  else
+    rtm.rtmsg_ifindex = 0;
+  */
+
+  rtm.rtmsg_flags |= RTF_GATEWAY;
+
+  /* For tagging route. */
+  /* rtm.rtmsg_flags |= RTF_DYNAMIC; */
+
+  /* Make gateway. */
+  for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+    {
+      if ((cmd == SIOCADDRT 
+	   && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+	  || (cmd == SIOCDELRT
+	      && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
+	{
+	  if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+	    {
+	      if (nexthop->rtype == NEXTHOP_TYPE_IPV6
+		  || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
+		  || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
+		{
+		  memcpy (&rtm.rtmsg_gateway, &nexthop->rgate.ipv6,
+			  sizeof (struct in6_addr));
+		}
+	      if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
+		  || nexthop->rtype == NEXTHOP_TYPE_IFNAME
+		  || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
+		  || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
+		rtm.rtmsg_ifindex = nexthop->rifindex;
+	      else
+		rtm.rtmsg_ifindex = 0;
+	      
+	    }
+	  else
+	    {
+	      if (nexthop->type == NEXTHOP_TYPE_IPV6
+		  || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
+		  || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
+		{
+		  memcpy (&rtm.rtmsg_gateway, &nexthop->gate.ipv6,
+			  sizeof (struct in6_addr));
+		}
+	      if (nexthop->type == NEXTHOP_TYPE_IFINDEX
+		  || nexthop->type == NEXTHOP_TYPE_IFNAME
+		  || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
+		  || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
+		rtm.rtmsg_ifindex = nexthop->ifindex;
+	      else
+		rtm.rtmsg_ifindex = 0;
+	    }
+
+	  if (cmd == SIOCADDRT)
+	    SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+
+	  nexthop_num++;
+	  break;
+	}
+    }
+
+  /* If there is no useful nexthop then return. */
+  if (nexthop_num == 0)
+    {
+      if (IS_ZEBRA_DEBUG_KERNEL)
+	zlog_info ("netlink_route_multipath(): No useful nexthop.");
+      return 0;
+    }
+
+  sock = socket (AF_INET6, SOCK_DGRAM, 0);
+  if (sock < 0)
+    {
+      zlog_warn ("can't make socket\n");
+      return -1;
+    }
+
+  /* Send message via ioctl. */
+  ret = ioctl (sock, cmd, &rtm);
+  if (ret < 0)
+    {
+      zlog_warn ("can't %s ipv6 route: %s\n",
+		 cmd == SIOCADDRT ? "add" : "delete", 
+	   strerror(errno));
+      ret = errno;
+      close (sock);
+      return ret;
+    }
+  close (sock);
+
+  return ret;
+}
+
+int
+kernel_add_ipv6 (struct prefix *p, struct rib *rib)
+{
+  return kernel_ioctl_ipv6_multipath (SIOCADDRT, p, rib, AF_INET6);
+}
+
+int
+kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
+{
+  return kernel_ioctl_ipv6_multipath (SIOCDELRT, p, rib, AF_INET6);
+}
+
+/* Delete IPv6 route from the kernel. */
+int
+kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
+		    int index, int flags, int table)
+{
+  return kernel_ioctl_ipv6 (SIOCDELRT, dest, gate, index, flags);
+}
+#endif /* HAVE_IPV6 */
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
new file mode 100644
index 0000000..baca175
--- /dev/null
+++ b/zebra/rt_netlink.c
@@ -0,0 +1,1482 @@
+/* Kernel routing table updates using netlink over GNU/Linux system.
+ * 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>
+
+/* Hack for GNU libc version 2. */
+#ifndef MSG_TRUNC
+#define MSG_TRUNC      0x20
+#endif /* MSG_TRUNC */
+
+#include "linklist.h"
+#include "if.h"
+#include "log.h"
+#include "prefix.h"
+#include "connected.h"
+#include "table.h"
+#include "rib.h"
+
+#include "zebra/zserv.h"
+#include "zebra/redistribute.h"
+#include "zebra/interface.h"
+#include "zebra/debug.h"
+
+/* Socket interface to kernel */
+struct nlsock
+{
+  int sock;
+  int seq;
+  struct sockaddr_nl snl;
+  char *name;
+} netlink =	{ -1, 0, {0}, "netlink-listen" },	/* kernel messages */
+  netlink_cmd = { -1, 0, {0}, "netlink-cmd" },          /* command channel */
+  netlink_addr = {-1, 0, {0}, "netlink-addr" };		/* address channel */
+
+struct message nlmsg_str[] =
+{
+  {RTM_NEWROUTE, "RTM_NEWROUTE"},
+  {RTM_DELROUTE, "RTM_DELROUTE"},
+  {RTM_GETROUTE, "RTM_GETROUTE"},
+  {RTM_NEWLINK,  "RTM_NEWLINK"},
+  {RTM_DELLINK,  "RTM_DELLINK"},
+  {RTM_GETLINK,  "RTM_GETLINK"},
+  {RTM_NEWADDR,  "RTM_NEWADDR"},
+  {RTM_DELADDR,  "RTM_DELADDR"},
+  {RTM_GETADDR,  "RTM_GETADDR"},
+  {0,            NULL}
+};
+
+extern int rtm_table_default;
+
+/* Make socket for Linux netlink interface. */
+static int
+netlink_socket (struct nlsock *nl, unsigned long groups)
+{
+  int ret;
+  struct sockaddr_nl snl;
+  int sock;
+  int namelen;
+
+  sock = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (sock < 0)
+    {
+      zlog (NULL, LOG_ERR, "Can't open %s socket: %s", nl->name,
+	    strerror (errno));
+      return -1;
+    }
+
+  ret = fcntl (sock, F_SETFL, O_NONBLOCK);
+  if (ret < 0)
+    {
+      zlog (NULL, LOG_ERR, "Can't set %s socket flags: %s", nl->name,
+	    strerror (errno));
+      close (sock);
+      return -1;
+    }
+  
+  memset (&snl, 0, sizeof snl);
+  snl.nl_family = AF_NETLINK;
+  snl.nl_groups = groups;
+
+  /* Bind the socket to the netlink structure for anything. */
+  ret = bind (sock, (struct sockaddr *) &snl, sizeof snl);
+  if (ret < 0)
+    {
+      zlog (NULL, LOG_ERR, "Can't bind %s socket to group 0x%x: %s", 
+	    nl->name, snl.nl_groups, strerror (errno));
+      close (sock);
+      return -1;
+    }
+
+  /* multiple netlink sockets will have different nl_pid */
+  namelen = sizeof snl;
+  ret = getsockname (sock, (struct sockaddr *) &snl, &namelen);
+  if (ret < 0 || namelen != sizeof snl)
+    {
+      zlog (NULL, LOG_ERR, "Can't get %s socket name: %s", nl->name,
+	    strerror (errno));
+      close (sock);
+      return -1;
+    }
+
+  nl->snl = snl;
+  nl->sock = sock;
+  return ret;
+}
+
+/* Get type specified information from netlink. */
+static int
+netlink_request (int family, int type, struct nlsock *nl)
+{
+  int ret;
+  struct sockaddr_nl snl;
+
+  struct
+  {
+    struct nlmsghdr nlh;
+    struct rtgenmsg g;
+  } req;
+
+
+  /* Check netlink socket. */
+  if (nl->sock < 0)
+    {
+      zlog (NULL, LOG_ERR, "%s socket isn't active.", nl->name);
+      return -1;
+    }
+
+  memset (&snl, 0, sizeof snl);
+  snl.nl_family = AF_NETLINK;
+
+  req.nlh.nlmsg_len = sizeof req;
+  req.nlh.nlmsg_type = type;
+  req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
+  req.nlh.nlmsg_pid = 0;
+  req.nlh.nlmsg_seq = ++nl->seq;
+  req.g.rtgen_family = family;
+ 
+  ret = sendto (nl->sock, (void*) &req, sizeof req, 0, 
+		(struct sockaddr*) &snl, sizeof snl);
+  if (ret < 0)
+    {
+      zlog (NULL, LOG_ERR, "%s sendto failed: %s", nl->name, strerror (errno));
+      return -1;
+    }
+  return 0;
+}
+
+/* Receive message from netlink interface and pass those information
+   to the given function. */
+static int
+netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *),
+		    struct nlsock *nl)
+{
+  int status;
+  int ret = 0;
+  int error;
+
+  while (1)
+    {
+      char buf[4096];
+      struct iovec iov = { buf, sizeof buf };
+      struct sockaddr_nl snl;
+      struct msghdr msg = { (void*)&snl, sizeof snl, &iov, 1, NULL, 0, 0};
+      struct nlmsghdr *h;
+
+      status = recvmsg (nl->sock, &msg, 0);
+
+      if (status < 0)
+	{
+	  if (errno == EINTR)
+	    continue;
+	  if (errno == EWOULDBLOCK || errno == EAGAIN)
+	    break;
+	  zlog (NULL, LOG_ERR, "%s recvmsg overrun", nl->name);
+	  continue;
+	}
+
+      if (status == 0)
+	{
+	  zlog (NULL, LOG_ERR, "%s EOF", nl->name);
+	  return -1;
+	}
+
+      if (msg.msg_namelen != sizeof snl)
+	{
+	  zlog (NULL, LOG_ERR, "%s sender address length error: length %d",
+	       nl->name, msg.msg_namelen);
+	  return -1;
+	}
+
+      for (h = (struct nlmsghdr *) buf; NLMSG_OK (h, status); 
+	   h = NLMSG_NEXT (h, status))
+	{
+	  /* Finish of reading. */
+	  if (h->nlmsg_type == NLMSG_DONE)
+	    return ret;
+
+	  /* Error handling. */
+	  if (h->nlmsg_type == NLMSG_ERROR)
+	    {
+	      struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h);
+	      
+              /* If the error field is zero, then this is an ACK */
+              if (err->error == 0) 
+                {
+                  if (IS_ZEBRA_DEBUG_KERNEL) 
+                    {  
+                      zlog_info("%s: %s ACK: type=%s(%u), seq=%u, pid=%d", 
+                        __FUNCTION__, nl->name,
+                        lookup (nlmsg_str, err->msg.nlmsg_type),
+                        err->msg.nlmsg_type, err->msg.nlmsg_seq,
+		        err->msg.nlmsg_pid);
+                    }
+                
+                  /* return if not a multipart message, otherwise continue */  
+                  if(!(h->nlmsg_flags & NLM_F_MULTI)) 
+                    { 
+                      return 0;    
+                    }
+                  continue; 
+                }
+              
+              if (h->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr)))
+		{
+		  zlog (NULL, LOG_ERR, "%s error: message truncated",
+			nl->name);
+		  return -1;
+		}
+	      zlog (NULL, LOG_ERR, "%s error: %s, type=%s(%u), seq=%u, pid=%d",
+		    nl->name, strerror (-err->error),
+		    lookup (nlmsg_str, err->msg.nlmsg_type),
+		    err->msg.nlmsg_type, err->msg.nlmsg_seq,
+		    err->msg.nlmsg_pid);
+	      /*
+	      ret = -1;
+	      continue;
+	      */
+	      return -1;
+	    }
+
+	  /* OK we got netlink message. */
+	  if (IS_ZEBRA_DEBUG_KERNEL)
+	    zlog_info ("netlink_parse_info: %s type %s(%u), seq=%u, pid=%d",
+		      nl->name,
+		      lookup (nlmsg_str, h->nlmsg_type), h->nlmsg_type,
+		      h->nlmsg_seq, h->nlmsg_pid);
+
+	  /* skip unsolicited messages originating from command socket */
+	  if (nl != &netlink_cmd && h->nlmsg_pid == netlink_cmd.snl.nl_pid)
+	    {
+	      if (IS_ZEBRA_DEBUG_KERNEL)
+		zlog_info ("netlink_parse_info: %s packet comes from %s",
+			  nl->name, netlink_cmd.name);
+	      continue;
+	    }
+
+	  error = (*filter) (&snl, h);
+	  if (error < 0)
+	    {
+	      zlog (NULL, LOG_ERR, "%s filter function error", nl->name);
+	      ret = error;
+	    }
+	}
+
+      /* After error care. */
+      if (msg.msg_flags & MSG_TRUNC)
+	{
+	  zlog (NULL, LOG_ERR, "%s error: message truncated", nl->name);
+	  continue;
+	}
+      if (status)
+	{
+	  zlog (NULL, LOG_ERR, "%s error: data remnant size %d", nl->name,
+		status);
+	  return -1;
+	}
+    }
+  return ret;
+}
+
+/* Utility function for parse rtattr. */
+static void
+netlink_parse_rtattr (struct rtattr **tb, int max, struct rtattr *rta, int len)
+{
+  while (RTA_OK(rta, len)) 
+    {
+      if (rta->rta_type <= max)
+	tb[rta->rta_type] = rta;
+      rta = RTA_NEXT(rta,len);
+    }
+}
+
+/* Called from interface_lookup_netlink().  This function is only used
+   during bootstrap. */
+int
+netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h)
+{
+  int len;
+  struct ifinfomsg *ifi;
+  struct rtattr *tb[IFLA_MAX + 1];
+  struct interface *ifp;
+  char *name;
+  int i;
+
+  ifi = NLMSG_DATA (h);
+
+  if (h->nlmsg_type != RTM_NEWLINK)
+    return 0;
+
+  len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
+  if (len < 0)
+    return -1;
+
+  /* Looking up interface name. */
+  memset (tb, 0, sizeof tb);
+  netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
+  if (tb[IFLA_IFNAME] == NULL)
+    return -1;
+  name = (char *)RTA_DATA(tb[IFLA_IFNAME]);
+
+  /* Add interface. */
+  ifp = if_get_by_name (name);
+  
+  ifp->ifindex = ifi->ifi_index;
+  ifp->flags = ifi->ifi_flags & 0x0000fffff;
+  ifp->mtu = *(int *)RTA_DATA (tb[IFLA_MTU]);
+  ifp->metric = 1;
+
+  /* Hardware type and address. */
+  ifp->hw_type = ifi->ifi_type;
+
+  if (tb[IFLA_ADDRESS])
+    {
+      int hw_addr_len;
+
+      hw_addr_len = RTA_PAYLOAD(tb[IFLA_ADDRESS]);
+
+      if (hw_addr_len > INTERFACE_HWADDR_MAX)
+	zlog_warn ("Hardware address is too large: %d", hw_addr_len);
+      else
+	{      
+	  ifp->hw_addr_len = hw_addr_len;
+	  memcpy (ifp->hw_addr, RTA_DATA(tb[IFLA_ADDRESS]), hw_addr_len);
+
+	  for (i = 0; i < hw_addr_len; i++)
+	    if (ifp->hw_addr[i] != 0)
+	      break;
+
+	  if (i == hw_addr_len)
+	    ifp->hw_addr_len = 0;
+	  else
+	    ifp->hw_addr_len = hw_addr_len;
+	}
+    }
+
+  if_add_update (ifp);
+
+  return 0;
+}
+
+/* Lookup interface IPv4/IPv6 address. */
+int
+netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h)
+{
+  int len;
+  struct ifaddrmsg *ifa;
+  struct rtattr *tb [IFA_MAX + 1];
+  struct interface *ifp;
+  void *addr = NULL;
+  void *broad = NULL;
+  u_char flags = 0;
+  char *label = NULL;
+
+  ifa = NLMSG_DATA (h);
+
+  if (ifa->ifa_family != AF_INET 
+#ifdef HAVE_IPV6
+      && ifa->ifa_family != AF_INET6
+#endif /* HAVE_IPV6 */
+      )
+    return 0;
+
+  if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)
+    return 0;
+
+  len = h->nlmsg_len - NLMSG_LENGTH(sizeof (struct ifaddrmsg));
+  if (len < 0)
+    return -1;
+
+  memset (tb, 0, sizeof tb);
+  netlink_parse_rtattr (tb, IFA_MAX, IFA_RTA (ifa), len);
+
+  ifp = if_lookup_by_index (ifa->ifa_index);
+  if (ifp == NULL)
+    {
+      zlog_err ("netlink_interface_addr can't find interface by index %d",
+		ifa->ifa_index);
+      return -1;
+    }
+
+  if (tb[IFA_ADDRESS] == NULL)
+    tb[IFA_ADDRESS] = tb[IFA_LOCAL];
+
+  if (ifp->flags & IFF_POINTOPOINT)
+    {
+      if (tb[IFA_LOCAL])
+	{
+	  addr = RTA_DATA (tb[IFA_LOCAL]);
+	  if (tb[IFA_ADDRESS]) 
+	    broad = RTA_DATA (tb[IFA_ADDRESS]);
+	  else
+	    broad = NULL;
+	}
+      else
+	{
+	  if (tb[IFA_ADDRESS])
+	    addr = RTA_DATA (tb[IFA_ADDRESS]);
+	  else
+	    addr = NULL;
+	}
+    }
+  else
+    {
+      if (tb[IFA_ADDRESS])
+	addr = RTA_DATA (tb[IFA_ADDRESS]);
+      else
+	addr = NULL;
+
+      if (tb[IFA_BROADCAST])
+	broad = RTA_DATA(tb[IFA_BROADCAST]);
+      else
+	broad = NULL;
+    }
+
+  /* Flags. */
+  if (ifa->ifa_flags & IFA_F_SECONDARY)
+    SET_FLAG (flags, ZEBRA_IFA_SECONDARY);
+
+  /* Label */
+  if (tb[IFA_LABEL])
+    label = (char *) RTA_DATA (tb[IFA_LABEL]);
+
+  if (ifp && label && strcmp (ifp->name, label) == 0)
+    label = NULL;
+
+  /* Register interface address to the interface. */
+  if (ifa->ifa_family == AF_INET)
+    {
+      if (h->nlmsg_type == RTM_NEWADDR) 
+	connected_add_ipv4 (ifp, flags,
+			    (struct in_addr *) addr, ifa->ifa_prefixlen, 
+			    (struct in_addr *) broad, label);
+      else 
+	connected_delete_ipv4 (ifp, flags,
+			       (struct in_addr *) addr, ifa->ifa_prefixlen, 
+			       (struct in_addr *) broad, label);
+    }
+#ifdef HAVE_IPV6
+  if (ifa->ifa_family == AF_INET6)
+    {
+      if (h->nlmsg_type == RTM_NEWADDR)
+	connected_add_ipv6 (ifp, 
+			    (struct in6_addr *) addr, ifa->ifa_prefixlen, 
+			    (struct in6_addr *) broad);
+      else
+	connected_delete_ipv6 (ifp, 
+			       (struct in6_addr *) addr, ifa->ifa_prefixlen, 
+			       (struct in6_addr *) broad);
+    }
+#endif /* HAVE_IPV6*/
+
+  return 0;
+}
+
+/* Looking up routing table by netlink interface. */
+int
+netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
+{
+  int len;
+  struct rtmsg *rtm;
+  struct rtattr *tb [RTA_MAX + 1];
+  u_char flags = 0;
+  
+  char anyaddr[16] = {0};
+
+  int index;
+  int table;
+  void *dest;
+  void *gate;
+
+  rtm = NLMSG_DATA (h);
+
+  if (h->nlmsg_type != RTM_NEWROUTE)
+    return 0;
+  if (rtm->rtm_type != RTN_UNICAST)
+    return 0;
+
+  table = rtm->rtm_table;
+#if 0		/* we weed them out later in rib_weed_tables () */
+  if (table != RT_TABLE_MAIN && table != rtm_table_default)
+    return 0;
+#endif
+
+  len = h->nlmsg_len - NLMSG_LENGTH(sizeof (struct rtmsg));
+  if (len < 0)
+    return -1;
+
+  memset (tb, 0, sizeof tb);
+  netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
+
+  if (rtm->rtm_flags & RTM_F_CLONED)
+    return 0;
+  if (rtm->rtm_protocol == RTPROT_REDIRECT)
+    return 0;
+  if (rtm->rtm_protocol == RTPROT_KERNEL)
+    return 0;
+
+  if (rtm->rtm_src_len != 0)
+    return 0;
+
+  /* Route which inserted by Zebra. */
+  if (rtm->rtm_protocol == RTPROT_ZEBRA)
+    flags |= ZEBRA_FLAG_SELFROUTE;
+  
+  index = 0;
+  dest = NULL;
+  gate = NULL;
+
+  if (tb[RTA_OIF])
+    index = *(int *) RTA_DATA (tb[RTA_OIF]);
+
+  if (tb[RTA_DST])
+    dest = RTA_DATA (tb[RTA_DST]);
+  else
+    dest = anyaddr;
+
+  /* Multipath treatment is needed. */
+  if (tb[RTA_GATEWAY])
+    gate = RTA_DATA (tb[RTA_GATEWAY]);
+
+  if (rtm->rtm_family == AF_INET)
+    {
+      struct prefix_ipv4 p;
+      p.family = AF_INET;
+      memcpy (&p.prefix, dest, 4);
+      p.prefixlen = rtm->rtm_dst_len;
+
+      rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table, 0, 0);
+    }
+#ifdef HAVE_IPV6
+  if (rtm->rtm_family == AF_INET6)
+    {
+      struct prefix_ipv6 p;
+      p.family = AF_INET6;
+      memcpy (&p.prefix, dest, 16);
+      p.prefixlen = rtm->rtm_dst_len;
+
+      rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table);
+    }
+#endif /* HAVE_IPV6 */
+
+  return 0;
+}
+
+struct message rtproto_str [] = 
+{
+  {RTPROT_REDIRECT, "redirect"},
+  {RTPROT_KERNEL,   "kernel"},
+  {RTPROT_BOOT,     "boot"},
+  {RTPROT_STATIC,   "static"},
+  {RTPROT_GATED,    "GateD"},
+  {RTPROT_RA,       "router advertisement"},
+  {RTPROT_MRT,      "MRT"},
+  {RTPROT_ZEBRA,    "Zebra"},
+#ifdef RTPROT_BIRD
+  {RTPROT_BIRD,     "BIRD"},
+#endif /* RTPROT_BIRD */
+  {0,               NULL}
+};
+
+/* Routing information change from the kernel. */
+int
+netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
+{
+  int len;
+  struct rtmsg *rtm;
+  struct rtattr *tb [RTA_MAX + 1];
+  
+  char anyaddr[16] = {0};
+
+  int index;
+  int table;
+  void *dest;
+  void *gate;
+
+  rtm = NLMSG_DATA (h);
+
+  if (! (h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE))
+    {
+      /* If this is not route add/delete message print warning. */
+      zlog_warn ("Kernel message: %d\n", h->nlmsg_type);
+      return 0;
+    }
+
+  /* Connected route. */
+  if (IS_ZEBRA_DEBUG_KERNEL)
+    zlog_info ("%s %s %s proto %s",
+	       h->nlmsg_type == RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
+	       rtm->rtm_family == AF_INET ? "ipv4" : "ipv6",
+	       rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast",
+	       lookup (rtproto_str, rtm->rtm_protocol));
+
+  if (rtm->rtm_type != RTN_UNICAST)
+    {
+      return 0;
+    }
+
+  table = rtm->rtm_table;
+  if (table != RT_TABLE_MAIN && table != rtm_table_default)
+    {
+      return 0;
+    }
+
+  len = h->nlmsg_len - NLMSG_LENGTH(sizeof (struct rtmsg));
+  if (len < 0)
+    return -1;
+
+  memset (tb, 0, sizeof tb);
+  netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
+
+  if (rtm->rtm_flags & RTM_F_CLONED)
+    return 0;
+  if (rtm->rtm_protocol == RTPROT_REDIRECT)
+    return 0;
+  if (rtm->rtm_protocol == RTPROT_KERNEL)
+    return 0;
+
+  if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE)
+    return 0;
+
+  if (rtm->rtm_src_len != 0)
+    {
+      zlog_warn ("netlink_route_change(): no src len");
+      return 0;
+    }
+  
+  index = 0;
+  dest = NULL;
+  gate = NULL;
+
+  if (tb[RTA_OIF])
+    index = *(int *) RTA_DATA (tb[RTA_OIF]);
+
+  if (tb[RTA_DST])
+    dest = RTA_DATA (tb[RTA_DST]);
+  else
+    dest = anyaddr;
+
+  if (tb[RTA_GATEWAY])
+    gate = RTA_DATA (tb[RTA_GATEWAY]);
+
+  if (rtm->rtm_family == AF_INET)
+    {
+      struct prefix_ipv4 p;
+      p.family = AF_INET;
+      memcpy (&p.prefix, dest, 4);
+      p.prefixlen = rtm->rtm_dst_len;
+
+      if (IS_ZEBRA_DEBUG_KERNEL)
+	{
+	  if (h->nlmsg_type == RTM_NEWROUTE)
+	    zlog_info ("RTM_NEWROUTE %s/%d",
+		       inet_ntoa (p.prefix), p.prefixlen);
+	  else
+	    zlog_info ("RTM_DELROUTE %s/%d",
+		       inet_ntoa (p.prefix), p.prefixlen);
+	}
+
+      if (h->nlmsg_type == RTM_NEWROUTE)
+	rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, 0, 0);
+      else
+	rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table);
+    }
+
+#ifdef HAVE_IPV6
+  if (rtm->rtm_family == AF_INET6)
+    {
+      struct prefix_ipv6 p;
+      char buf[BUFSIZ];
+
+      p.family = AF_INET6;
+      memcpy (&p.prefix, dest, 16);
+      p.prefixlen = rtm->rtm_dst_len;
+
+      if (IS_ZEBRA_DEBUG_KERNEL)
+	{
+	  if (h->nlmsg_type == RTM_NEWROUTE)
+	    zlog_info ("RTM_NEWROUTE %s/%d",
+		       inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
+		       p.prefixlen);
+	  else
+	    zlog_info ("RTM_DELROUTE %s/%d",
+		       inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
+		       p.prefixlen);
+	}
+
+      if (h->nlmsg_type == RTM_NEWROUTE)
+	rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0);
+      else
+	rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0);
+    }
+#endif /* HAVE_IPV6 */
+
+  return 0;
+}
+
+int
+netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
+{
+  int len;
+  struct ifinfomsg *ifi;
+  struct rtattr *tb [IFLA_MAX + 1];
+  struct interface *ifp;
+  char *name;
+
+  ifi = NLMSG_DATA (h);
+
+  if (! (h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK))
+    {
+      /* If this is not link add/delete message so print warning. */
+      zlog_warn ("netlink_link_change: wrong kernel message %d\n",
+		 h->nlmsg_type);
+      return 0;
+    }
+
+  len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
+  if (len < 0)
+    return -1;
+
+  /* Looking up interface name. */
+  memset (tb, 0, sizeof tb);
+  netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
+  if (tb[IFLA_IFNAME] == NULL)
+    return -1;
+  name = (char *)RTA_DATA(tb[IFLA_IFNAME]);
+
+  /* Add interface. */
+  if (h->nlmsg_type == RTM_NEWLINK)
+    {
+      ifp = if_lookup_by_name (name);
+
+      if (ifp == NULL || ! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
+	{
+	  if (ifp == NULL)
+	    ifp = if_get_by_name (name);
+
+	  ifp->ifindex = ifi->ifi_index;
+	  ifp->flags = ifi->ifi_flags & 0x0000fffff;
+	  ifp->mtu = *(int *)RTA_DATA (tb[IFLA_MTU]);
+	  ifp->metric = 1;
+
+	  /* If new link is added. */
+	  if_add_update(ifp);
+	}      
+      else
+	{
+	  /* Interface status change. */
+	  ifp->ifindex = ifi->ifi_index;
+	  ifp->mtu = *(int *)RTA_DATA (tb[IFLA_MTU]);
+	  ifp->metric = 1;
+
+	  if (if_is_up (ifp))
+	    {
+	      ifp->flags = ifi->ifi_flags & 0x0000fffff;
+	      if (! if_is_up (ifp))
+		if_down (ifp);
+	    }
+	  else
+	    {
+	      ifp->flags = ifi->ifi_flags & 0x0000fffff;
+	      if (if_is_up (ifp))
+		if_up (ifp);
+	    }
+	}
+    }
+  else
+    {
+      /* RTM_DELLINK. */
+      ifp = if_lookup_by_name (name);
+
+      if (ifp == NULL)
+	{
+	  zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find",
+                name);
+	  return 0;
+	}
+      
+      if_delete_update (ifp);
+    }
+
+  return 0;
+}
+
+int
+netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h)
+{
+  switch (h->nlmsg_type)
+    {
+    case RTM_NEWROUTE:
+      return netlink_route_change (snl, h);
+      break;
+    case RTM_DELROUTE:
+      return netlink_route_change (snl, h);
+      break;
+    case RTM_NEWLINK:
+      return netlink_link_change (snl, h);
+      break;
+    case RTM_DELLINK:
+      return netlink_link_change (snl, h);
+      break;
+    case RTM_NEWADDR:
+      return netlink_interface_addr (snl, h);
+      break;
+    case RTM_DELADDR:
+      return netlink_interface_addr (snl, h);
+      break;
+    default:
+      zlog_warn ("Unknown netlink nlmsg_type %d\n", h->nlmsg_type);
+      break;
+    }
+  return 0;
+}
+
+/* Interface lookup by netlink socket. */
+int
+interface_lookup_netlink ()
+{
+  int ret;
+
+  /* Get interface information. */
+  ret = netlink_request (AF_PACKET, RTM_GETLINK, &netlink_cmd);
+  if (ret < 0)
+    return ret;
+  ret = netlink_parse_info (netlink_interface, &netlink_cmd);
+  if (ret < 0)
+    return ret;
+
+  /* Get IPv4 address of the interfaces. */
+  ret = netlink_request (AF_INET, RTM_GETADDR, &netlink_cmd);
+  if (ret < 0)
+    return ret;
+  ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
+  if (ret < 0)
+    return ret;
+
+#ifdef HAVE_IPV6
+  /* Get IPv6 address of the interfaces. */
+  ret = netlink_request (AF_INET6, RTM_GETADDR, &netlink_cmd);
+  if (ret < 0)
+    return ret;
+  ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
+  if (ret < 0)
+    return ret;
+#endif /* HAVE_IPV6 */
+
+  return 0;
+}
+
+/* Routing table read function using netlink interface.  Only called
+   bootstrap time. */
+int
+netlink_route_read ()
+{
+  int ret;
+
+  /* Get IPv4 routing table. */
+  ret = netlink_request (AF_INET, RTM_GETROUTE, &netlink_cmd);
+  if (ret < 0)
+    return ret;
+  ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
+  if (ret < 0)
+    return ret;
+
+#ifdef HAVE_IPV6
+  /* Get IPv6 routing table. */
+  ret = netlink_request (AF_INET6, RTM_GETROUTE, &netlink_cmd);
+  if (ret < 0)
+    return ret;
+  ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
+  if (ret < 0)
+    return ret;
+#endif /* HAVE_IPV6 */
+
+  return 0;
+}
+
+/* Utility function  comes from iproute2. 
+   Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
+int
+addattr_l (struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
+{
+  int len;
+  struct rtattr *rta;
+
+  len = RTA_LENGTH(alen);
+
+  if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen)
+    return -1;
+
+  rta = (struct rtattr*) (((char*)n) + NLMSG_ALIGN (n->nlmsg_len));
+  rta->rta_type = type;
+  rta->rta_len = len;
+  memcpy (RTA_DATA(rta), data, alen);
+  n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
+
+  return 0;
+}
+
+int
+rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen)
+{
+  int len;
+  struct rtattr *subrta;
+
+  len = RTA_LENGTH(alen);
+
+  if (RTA_ALIGN(rta->rta_len) + len > maxlen)
+    return -1;
+
+  subrta = (struct rtattr*) (((char*)rta) + RTA_ALIGN (rta->rta_len));
+  subrta->rta_type = type;
+  subrta->rta_len = len;
+  memcpy (RTA_DATA(subrta), data, alen);
+  rta->rta_len = NLMSG_ALIGN (rta->rta_len) + len;
+
+  return 0;
+}
+
+/* Utility function comes from iproute2. 
+   Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
+int
+addattr32 (struct nlmsghdr *n, int maxlen, int type, int data)
+{
+  int len;
+  struct rtattr *rta;
+  
+  len = RTA_LENGTH(4);
+  
+  if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
+    return -1;
+
+  rta = (struct rtattr*) (((char*)n) + NLMSG_ALIGN (n->nlmsg_len));
+  rta->rta_type = type;
+  rta->rta_len = len;
+  memcpy (RTA_DATA(rta), &data, 4);
+  n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
+
+  return 0;
+}
+
+static int
+netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h)
+{
+  zlog_warn ("netlink_talk: ignoring message type 0x%04x", h->nlmsg_type);
+  return 0;
+}
+
+/* sendmsg() to netlink socket then recvmsg(). */
+int
+netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
+{
+  int status;
+  struct sockaddr_nl snl;
+  struct iovec iov = { (void*) n, n->nlmsg_len };
+  struct msghdr msg = {(void*) &snl, sizeof snl, &iov, 1, NULL, 0, 0};
+  int flags = 0;
+  
+  memset (&snl, 0, sizeof snl);
+  snl.nl_family = AF_NETLINK;
+  
+  n->nlmsg_seq = ++netlink_cmd.seq;
+
+  /* Request an acknowledgement by setting NLM_F_ACK */
+  n->nlmsg_flags |= NLM_F_ACK;
+  
+  if (IS_ZEBRA_DEBUG_KERNEL) 
+    zlog_info ("netlink_talk: %s type %s(%u), seq=%u", netlink_cmd.name,
+	      lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type,
+	      n->nlmsg_seq);
+
+  /* Send message to netlink interface. */
+  status = sendmsg (nl->sock, &msg, 0);
+  if (status < 0)
+    {
+      zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s",
+	    strerror (errno));
+      return -1;
+    }
+  
+  /* 
+   * Change socket flags for blocking I/O. 
+   * This ensures we wait for a reply in netlink_parse_info().
+   */
+  if((flags = fcntl(nl->sock, F_GETFL, 0)) < 0) 
+    {
+      zlog (NULL, LOG_ERR, "%s:%i F_GETFL error: %s", 
+              __FUNCTION__, __LINE__, strerror (errno));
+    }
+  flags &= ~O_NONBLOCK;
+  if(fcntl(nl->sock, F_SETFL, flags) < 0) 
+    {
+      zlog (NULL, LOG_ERR, "%s:%i F_SETFL error: %s", 
+              __FUNCTION__, __LINE__, strerror (errno));
+    }
+
+  /* 
+   * Get reply from netlink socket. 
+   * The reply should either be an acknowlegement or an error.
+   */
+  status = netlink_parse_info (netlink_talk_filter, nl);
+  
+  /* Restore socket flags for nonblocking I/O */
+  flags |= O_NONBLOCK;
+  if(fcntl(nl->sock, F_SETFL, flags) < 0) 
+    {
+      zlog (NULL, LOG_ERR, "%s:%i F_SETFL error: %s", 
+              __FUNCTION__, __LINE__, strerror (errno));
+    }
+  
+  return status;
+}
+
+/* Routing table change via netlink interface. */
+int
+netlink_route (int cmd, int family, void *dest, int length, void *gate,
+	       int index, int zebra_flags, int table)
+{
+  int ret;
+  int bytelen;
+  struct sockaddr_nl snl;
+  int discard;
+
+  struct 
+  {
+    struct nlmsghdr n;
+    struct rtmsg r;
+    char buf[1024];
+  } req;
+
+  memset (&req, 0, sizeof req);
+
+  bytelen = (family == AF_INET ? 4 : 16);
+
+  req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
+  req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
+  req.n.nlmsg_type = cmd;
+  req.r.rtm_family = family;
+  req.r.rtm_table = table;
+  req.r.rtm_dst_len = length;
+
+  if (zebra_flags & ZEBRA_FLAG_BLACKHOLE)
+    discard = 1;
+  else
+    discard = 0;
+
+  if (cmd == RTM_NEWROUTE) 
+    {
+      req.r.rtm_protocol = RTPROT_ZEBRA;
+      req.r.rtm_scope = RT_SCOPE_UNIVERSE;
+
+      if (discard)
+	req.r.rtm_type = RTN_BLACKHOLE;
+      else
+	req.r.rtm_type = RTN_UNICAST;
+    }
+
+  if (dest)
+    addattr_l (&req.n, sizeof req, RTA_DST, dest, bytelen);
+
+  if (! discard)
+    {
+      if (gate)
+	addattr_l (&req.n, sizeof req, RTA_GATEWAY, gate, bytelen);
+      if (index > 0)
+	addattr32 (&req.n, sizeof req, RTA_OIF, index);
+    }
+
+  /* Destination netlink address. */
+  memset (&snl, 0, sizeof snl);
+  snl.nl_family = AF_NETLINK;
+
+  /* Talk to netlink socket. */
+  ret = netlink_talk (&req.n, &netlink);
+  if (ret < 0)
+    return -1;
+
+  return 0;
+}
+
+/* Routing table change via netlink interface. */
+int
+netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
+			 int family)
+{
+  int bytelen;
+  struct sockaddr_nl snl;
+  struct nexthop *nexthop = NULL;
+  int nexthop_num = 0;
+  struct nlsock *nl;
+  int discard;
+
+  struct 
+  {
+    struct nlmsghdr n;
+    struct rtmsg r;
+    char buf[1024];
+  } req;
+
+  memset (&req, 0, sizeof req);
+
+  bytelen = (family == AF_INET ? 4 : 16);
+
+  req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
+  req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
+  req.n.nlmsg_type = cmd;
+  req.r.rtm_family = family;
+  req.r.rtm_table = rib->table;
+  req.r.rtm_dst_len = p->prefixlen;
+
+  if (rib->flags & ZEBRA_FLAG_BLACKHOLE)
+    discard = 1;
+  else
+    discard = 0;
+
+  if (cmd == RTM_NEWROUTE) 
+    {
+      req.r.rtm_protocol = RTPROT_ZEBRA;
+      req.r.rtm_scope = RT_SCOPE_UNIVERSE;
+
+      if (discard)
+	req.r.rtm_type = RTN_BLACKHOLE;
+      else
+	req.r.rtm_type = RTN_UNICAST;
+    }
+
+  addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
+
+  /* Metric. */
+  addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric);
+
+  if (discard)
+    {
+      if (cmd == RTM_NEWROUTE)
+	for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+	  SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+      goto skip;
+    }
+
+  /* Multipath case. */
+  if (rib->nexthop_active_num == 1 || MULTIPATH_NUM == 1)
+    {
+      for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+	{
+	  if ((cmd == RTM_NEWROUTE 
+	       && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+	      || (cmd == RTM_DELROUTE
+		  && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
+	    {
+	      if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+		{
+		  if (nexthop->rtype == NEXTHOP_TYPE_IPV4 
+		      || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
+		    addattr_l (&req.n, sizeof req, RTA_GATEWAY,
+			       &nexthop->rgate.ipv4, bytelen);
+#ifdef HAVE_IPV6
+		  if (nexthop->rtype == NEXTHOP_TYPE_IPV6 
+		      || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX 
+		      || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
+		    addattr_l (&req.n, sizeof req, RTA_GATEWAY,
+			       &nexthop->rgate.ipv6, bytelen);
+#endif /* HAVE_IPV6 */
+		  if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
+		      || nexthop->rtype == NEXTHOP_TYPE_IFNAME
+		      || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
+		      || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
+		      || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
+		    addattr32 (&req.n, sizeof req, RTA_OIF,
+			       nexthop->rifindex);
+		}
+	      else
+		{
+		  if (nexthop->type == NEXTHOP_TYPE_IPV4 
+		      || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
+		    addattr_l (&req.n, sizeof req, RTA_GATEWAY,
+			       &nexthop->gate.ipv4, bytelen);
+#ifdef HAVE_IPV6
+		  if (nexthop->type == NEXTHOP_TYPE_IPV6 
+		      || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
+		      || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
+		    addattr_l (&req.n, sizeof req, RTA_GATEWAY,
+			       &nexthop->gate.ipv6, bytelen);
+#endif /* HAVE_IPV6 */
+		  if (nexthop->type == NEXTHOP_TYPE_IFINDEX
+		      || nexthop->type == NEXTHOP_TYPE_IFNAME
+		      || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
+		      || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
+		      || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
+		    addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
+		}
+
+	      if (cmd == RTM_NEWROUTE)
+		SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+
+	      nexthop_num++;
+	      break;
+	    }
+	}
+    }
+  else
+    {
+      char buf[1024];
+      struct rtattr *rta = (void *) buf;
+      struct rtnexthop *rtnh;
+
+      rta->rta_type = RTA_MULTIPATH;
+      rta->rta_len = RTA_LENGTH(0);
+      rtnh = RTA_DATA(rta);
+
+      nexthop_num = 0;
+      for (nexthop = rib->nexthop;
+	   nexthop && (MULTIPATH_NUM == 0 || nexthop_num < MULTIPATH_NUM);
+	   nexthop = nexthop->next)
+	{
+	  if ((cmd == RTM_NEWROUTE 
+	       && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+	      || (cmd == RTM_DELROUTE
+		  && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
+	    {
+	      nexthop_num++;
+
+	      rtnh->rtnh_len = sizeof (*rtnh);
+	      rtnh->rtnh_flags = 0;
+	      rtnh->rtnh_hops = 0;
+	      rta->rta_len += rtnh->rtnh_len;
+
+	      if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+		{
+		  if (nexthop->rtype == NEXTHOP_TYPE_IPV4
+		      || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
+		    {
+		      rta_addattr_l (rta, 4096, RTA_GATEWAY,
+				     &nexthop->rgate.ipv4, bytelen);
+		      rtnh->rtnh_len += sizeof (struct rtattr) + 4;
+		    }
+#ifdef HAVE_IPV6
+		  if (nexthop->rtype == NEXTHOP_TYPE_IPV6
+		      || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
+		      || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
+		    rta_addattr_l (rta, 4096, RTA_GATEWAY,
+				   &nexthop->rgate.ipv6, bytelen);
+#endif /* HAVE_IPV6 */
+		  /* ifindex */
+		  if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
+		      || nexthop->rtype == NEXTHOP_TYPE_IFNAME
+		      || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
+		      || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
+		      || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
+		    rtnh->rtnh_ifindex = nexthop->rifindex;
+		  else
+		    rtnh->rtnh_ifindex = 0;
+		}
+	      else
+		{
+		  if (nexthop->type == NEXTHOP_TYPE_IPV4
+		      || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
+		    {
+		      rta_addattr_l (rta, 4096, RTA_GATEWAY,
+				     &nexthop->gate.ipv4, bytelen);
+		      rtnh->rtnh_len += sizeof (struct rtattr) + 4;
+		    }
+#ifdef HAVE_IPV6
+		  if (nexthop->type == NEXTHOP_TYPE_IPV6
+		      || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
+		      || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
+		    rta_addattr_l (rta, 4096, RTA_GATEWAY,
+				   &nexthop->gate.ipv6, bytelen);
+#endif /* HAVE_IPV6 */
+		  /* ifindex */
+		  if (nexthop->type == NEXTHOP_TYPE_IFINDEX
+		      || nexthop->type == NEXTHOP_TYPE_IFNAME
+		      || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
+		      || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
+		      || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
+		    rtnh->rtnh_ifindex = nexthop->ifindex;
+		  else
+		    rtnh->rtnh_ifindex = 0;
+		}
+	      rtnh = RTNH_NEXT(rtnh);
+
+	      if (cmd == RTM_NEWROUTE)
+		SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+	    }
+	}
+
+      if (rta->rta_len > RTA_LENGTH (0))
+	addattr_l (&req.n, 1024, RTA_MULTIPATH, RTA_DATA(rta),
+		   RTA_PAYLOAD(rta));
+    }
+
+  /* If there is no useful nexthop then return. */
+  if (nexthop_num == 0)
+    {
+      if (IS_ZEBRA_DEBUG_KERNEL)
+	zlog_info ("netlink_route_multipath(): No useful nexthop.");
+      return 0;
+    }
+
+ skip:
+
+  /* Destination netlink address. */
+  memset (&snl, 0, sizeof snl);
+  snl.nl_family = AF_NETLINK;
+
+  if (family == AF_INET)
+    nl = &netlink_cmd;
+  else
+    nl = &netlink;
+
+  /* Talk to netlink socket. */
+  return netlink_talk (&req.n, nl);
+}
+
+int
+kernel_add_ipv4 (struct prefix *p, struct rib *rib)
+{
+  return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET);
+}
+
+int
+kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
+{
+  return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET);
+}
+
+#ifdef HAVE_IPV6
+int
+kernel_add_ipv6 (struct prefix *p, struct rib *rib)
+{
+  return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6);
+}
+
+int
+kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
+{
+  return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6);
+}
+
+/* Delete IPv6 route from the kernel. */
+int
+kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
+			int index, int flags, int table)
+{
+  return netlink_route (RTM_DELROUTE, AF_INET6, &dest->prefix, dest->prefixlen,
+			gate, index, flags, table);
+}
+#endif /* HAVE_IPV6 */
+
+/* Interface address modification. */
+int
+netlink_address (int cmd, int family, struct interface *ifp,
+		 struct connected *ifc)
+{
+  int bytelen;
+  struct prefix *p;
+
+  struct 
+  {
+    struct nlmsghdr n;
+    struct ifaddrmsg ifa;
+    char buf[1024];
+  } req;
+
+  p = ifc->address;
+  memset (&req, 0, sizeof req);
+
+  bytelen = (family == AF_INET ? 4 : 16);
+
+  req.n.nlmsg_len = NLMSG_LENGTH (sizeof(struct ifaddrmsg));
+  req.n.nlmsg_flags = NLM_F_REQUEST;
+  req.n.nlmsg_type = cmd;
+  req.ifa.ifa_family = family;
+
+  req.ifa.ifa_index = ifp->ifindex;
+  req.ifa.ifa_prefixlen = p->prefixlen;
+
+  addattr_l (&req.n, sizeof req, IFA_LOCAL, &p->u.prefix, bytelen);
+
+  if (family == AF_INET && cmd == RTM_NEWADDR)
+    {
+      if (if_is_broadcast (ifp) && ifc->destination)
+	{
+	  p = ifc->destination;
+	  addattr_l(&req.n, sizeof req, IFA_BROADCAST, &p->u.prefix, bytelen);
+	}
+    }
+
+  if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY))
+    SET_FLAG (req.ifa.ifa_flags, IFA_F_SECONDARY);
+    
+  if (ifc->label)
+    addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label,
+	       strlen (ifc->label) + 1);
+
+  return netlink_talk (&req.n, &netlink_cmd);
+}
+
+int
+kernel_address_add_ipv4 (struct interface *ifp, struct connected *ifc)
+{
+  return netlink_address (RTM_NEWADDR, AF_INET, ifp, ifc);
+}
+
+int
+kernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc)
+{
+  return netlink_address (RTM_DELADDR, AF_INET, ifp, ifc);
+}
+
+#include "thread.h"
+
+extern struct thread_master *master;
+
+/* Kernel route reflection. */
+int
+kernel_read (struct thread *thread)
+{
+  int ret;
+  int sock;
+
+  sock = THREAD_FD (thread);
+  ret = netlink_parse_info (netlink_information_fetch, &netlink);
+  thread_add_read (master, kernel_read, NULL, netlink.sock);
+
+  return 0;
+}
+
+/* Exported interface function.  This function simply calls
+   netlink_socket (). */
+void
+kernel_init ()
+{
+  unsigned long groups;
+
+  groups = RTMGRP_LINK|RTMGRP_IPV4_ROUTE|RTMGRP_IPV4_IFADDR;
+#ifdef HAVE_IPV6
+  groups |= RTMGRP_IPV6_ROUTE|RTMGRP_IPV6_IFADDR;
+#endif /* HAVE_IPV6 */
+  netlink_socket (&netlink, groups);
+  netlink_socket (&netlink_cmd, 0);
+
+  /* Register kernel socket. */
+  if (netlink.sock > 0)
+    thread_add_read (master, kernel_read, NULL, netlink.sock);
+}
diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c
new file mode 100644
index 0000000..fe88be8
--- /dev/null
+++ b/zebra/rt_socket.c
@@ -0,0 +1,441 @@
+/*
+ * Kernel routing table updates by routing socket.
+ * Copyright (C) 1997, 98 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 "if.h"
+#include "prefix.h"
+#include "sockunion.h"
+#include "log.h"
+#include "str.h"
+
+#include "zebra/debug.h"
+#include "zebra/rib.h"
+
+int
+rtm_write (int message,
+	   union sockunion *dest,
+	   union sockunion *mask,
+	   union sockunion *gate,
+	   unsigned int index,
+	   int zebra_flags,
+	   int metric);
+
+/* Adjust netmask socket length. Return value is a adjusted sin_len
+   value. */
+int
+sin_masklen (struct in_addr mask)
+{
+  char *p, *lim;
+  int len;
+  struct sockaddr_in sin;
+
+  if (mask.s_addr == 0) 
+    return sizeof (long);
+
+  sin.sin_addr = mask;
+  len = sizeof (struct sockaddr_in);
+
+  lim = (char *) &sin.sin_addr;
+  p = lim + sizeof (sin.sin_addr);
+
+  while (*--p == 0 && p >= lim) 
+    len--;
+  return len;
+}
+
+/* Interface between zebra message and rtm message. */
+int
+kernel_rtm_ipv4 (int cmd, struct prefix *p, struct rib *rib, int family)
+
+{
+  struct sockaddr_in *mask;
+  struct sockaddr_in sin_dest, sin_mask, sin_gate;
+  struct nexthop *nexthop;
+  int nexthop_num = 0;
+  unsigned int ifindex = 0;
+  int gate = 0;
+  int error;
+
+  memset (&sin_dest, 0, sizeof (struct sockaddr_in));
+  sin_dest.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+  sin_dest.sin_len = sizeof (struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+  sin_dest.sin_addr = p->u.prefix4;
+
+  memset (&sin_mask, 0, sizeof (struct sockaddr_in));
+
+  memset (&sin_gate, 0, sizeof (struct sockaddr_in));
+  sin_gate.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+  sin_gate.sin_len = sizeof (struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+
+  /* Make gateway. */
+  for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+    {
+      gate = 0;
+
+      if ((cmd == RTM_ADD
+	   && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+	  || (cmd == RTM_DELETE
+#if 0
+	      && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
+#endif
+	      ))
+	{
+	  if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+	    {
+	      if (nexthop->rtype == NEXTHOP_TYPE_IPV4 ||
+		  nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
+		{
+		  sin_gate.sin_addr = nexthop->rgate.ipv4;
+		  gate = 1;
+		}
+	      if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
+		  || nexthop->rtype == NEXTHOP_TYPE_IFNAME
+		  || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
+		ifindex = nexthop->rifindex;
+	    }
+	  else
+	    {
+	      if (nexthop->type == NEXTHOP_TYPE_IPV4 ||
+		  nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
+		{
+		  sin_gate.sin_addr = nexthop->gate.ipv4;
+		  gate = 1;
+		}
+	      if (nexthop->type == NEXTHOP_TYPE_IFINDEX
+		  || nexthop->type == NEXTHOP_TYPE_IFNAME
+		  || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
+		ifindex = nexthop->ifindex;
+	      if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE)
+		{
+		  struct in_addr loopback;
+
+		  loopback.s_addr = htonl (INADDR_LOOPBACK);
+		  sin_gate.sin_addr = loopback;
+		  gate = 1;
+		}
+	    }
+
+	  if (cmd == RTM_ADD)
+	    SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+
+	  if (gate && p->prefixlen == 32)
+	    mask = NULL;
+	  else
+	    {
+	      masklen2ip (p->prefixlen, &sin_mask.sin_addr);
+	      sin_mask.sin_family = AF_UNSPEC;
+#ifdef HAVE_SIN_LEN
+	      sin_mask.sin_len = sin_masklen (sin_mask.sin_addr);
+#endif /* HAVE_SIN_LEN */
+	      mask = &sin_mask;
+	    }
+	}
+
+      error = rtm_write (cmd,
+			(union sockunion *)&sin_dest, 
+			(union sockunion *)mask, 
+			gate ? (union sockunion *)&sin_gate : NULL,
+			ifindex,
+			rib->flags,
+			rib->metric);
+
+#if 0
+      if (error)
+	{
+	  zlog_info ("kernel_rtm_ipv4(): nexthop %d add error=%d.",
+	    nexthop_num, error);
+	}
+#endif
+
+      nexthop_num++;
+    }
+
+  /* If there is no useful nexthop then return. */
+  if (nexthop_num == 0)
+    {
+      if (IS_ZEBRA_DEBUG_KERNEL)
+	zlog_info ("kernel_rtm_ipv4(): No useful nexthop.");
+      return 0;
+    }
+
+  return 0; /*XXX*/
+}
+
+int
+kernel_add_ipv4 (struct prefix *p, struct rib *rib)
+{
+  return kernel_rtm_ipv4 (RTM_ADD, p, rib, AF_INET);
+}
+
+int
+kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
+{
+  return kernel_rtm_ipv4 (RTM_DELETE, p, rib, AF_INET);
+}
+
+#ifdef HAVE_IPV6
+
+/* Calculate sin6_len value for netmask socket value. */
+int
+sin6_masklen (struct in6_addr mask)
+{
+  struct sockaddr_in6 sin6;
+  char *p, *lim;
+  int len;
+
+#if defined (INRIA)
+  if (IN_ANYADDR6 (mask)) 
+    return sizeof (long);
+#else /* ! INRIA */
+  if (IN6_IS_ADDR_UNSPECIFIED (&mask)) 
+    return sizeof (long);
+#endif /* ! INRIA */
+
+  sin6.sin6_addr = mask;
+  len = sizeof (struct sockaddr_in6);
+
+  lim = (char *) & sin6.sin6_addr;
+  p = lim + sizeof (sin6.sin6_addr);
+
+  while (*--p == 0 && p >= lim) 
+    len--;
+
+  return len;
+}
+
+/* Interface between zebra message and rtm message. */
+int
+kernel_rtm_ipv6 (int message, struct prefix_ipv6 *dest,
+		 struct in6_addr *gate, int index, int flags)
+{
+  struct sockaddr_in6 *mask;
+  struct sockaddr_in6 sin_dest, sin_mask, sin_gate;
+
+  memset (&sin_dest, 0, sizeof (struct sockaddr_in6));
+  sin_dest.sin6_family = AF_INET6;
+#ifdef SIN6_LEN
+  sin_dest.sin6_len = sizeof (struct sockaddr_in6);
+#endif /* SIN6_LEN */
+
+  memset (&sin_mask, 0, sizeof (struct sockaddr_in6));
+
+  memset (&sin_gate, 0, sizeof (struct sockaddr_in6));
+  sin_gate.sin6_family = AF_INET6;
+#ifdef SIN6_LEN
+  sin_gate.sin6_len = sizeof (struct sockaddr_in6);
+#endif /* SIN6_LEN */
+
+  sin_dest.sin6_addr = dest->prefix;
+
+  if (gate)
+    memcpy (&sin_gate.sin6_addr, gate, sizeof (struct in6_addr));
+
+  /* Under kame set interface index to link local address. */
+#ifdef KAME
+
+#define SET_IN6_LINKLOCAL_IFINDEX(a, i) \
+  do { \
+    (a).s6_addr[2] = ((i) >> 8) & 0xff; \
+    (a).s6_addr[3] = (i) & 0xff; \
+  } while (0)
+
+  if (gate && IN6_IS_ADDR_LINKLOCAL(gate))
+    SET_IN6_LINKLOCAL_IFINDEX (sin_gate.sin6_addr, index);
+#endif /* KAME */
+
+  if (gate && dest->prefixlen == 128)
+    mask = NULL;
+  else
+    {
+      masklen2ip6 (dest->prefixlen, &sin_mask.sin6_addr);
+      sin_mask.sin6_family = AF_UNSPEC;
+#ifdef SIN6_LEN
+      sin_mask.sin6_len = sin6_masklen (sin_mask.sin6_addr);
+#endif /* SIN6_LEN */
+      mask = &sin_mask;
+    }
+
+  return rtm_write (message, 
+		    (union sockunion *) &sin_dest,
+		    (union sockunion *) mask,
+		    gate ? (union sockunion *)&sin_gate : NULL,
+		    index,
+		    flags,
+		    0);
+}
+
+/* Interface between zebra message and rtm message. */
+int
+kernel_rtm_ipv6_multipath (int cmd, struct prefix *p, struct rib *rib,
+			   int family)
+{
+  struct sockaddr_in6 *mask;
+  struct sockaddr_in6 sin_dest, sin_mask, sin_gate;
+  struct nexthop *nexthop;
+  int nexthop_num = 0;
+  unsigned int ifindex = 0;
+  int gate = 0;
+  int error;
+
+  memset (&sin_dest, 0, sizeof (struct sockaddr_in6));
+  sin_dest.sin6_family = AF_INET6;
+#ifdef SIN6_LEN
+  sin_dest.sin6_len = sizeof (struct sockaddr_in6);
+#endif /* SIN6_LEN */
+  sin_dest.sin6_addr = p->u.prefix6;
+
+  memset (&sin_mask, 0, sizeof (struct sockaddr_in6));
+
+  memset (&sin_gate, 0, sizeof (struct sockaddr_in6));
+  sin_gate.sin6_family = AF_INET6;
+#ifdef HAVE_SIN_LEN
+  sin_gate.sin6_len = sizeof (struct sockaddr_in6);
+#endif /* HAVE_SIN_LEN */
+
+  /* Make gateway. */
+  for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+    {
+      gate = 0;
+
+      if ((cmd == RTM_ADD
+	   && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+	  || (cmd == RTM_DELETE
+#if 0
+	      && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
+#endif
+	      ))
+	{
+	  if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+	    {
+	      if (nexthop->rtype == NEXTHOP_TYPE_IPV6
+		  || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
+		  || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
+		{
+		  sin_gate.sin6_addr = nexthop->rgate.ipv6;
+		  gate = 1;
+		}
+	      if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
+		  || nexthop->rtype == NEXTHOP_TYPE_IFNAME
+		  || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
+		  || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
+		ifindex = nexthop->rifindex;
+	    }
+	  else
+	    {
+	      if (nexthop->type == NEXTHOP_TYPE_IPV6
+		  || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
+		  || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
+		{
+		  sin_gate.sin6_addr = nexthop->gate.ipv6;
+		  gate = 1;
+		}
+	      if (nexthop->type == NEXTHOP_TYPE_IFINDEX
+		  || nexthop->type == NEXTHOP_TYPE_IFNAME
+		  || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
+		  || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
+		ifindex = nexthop->ifindex;
+	    }
+
+	  if (cmd == RTM_ADD)
+	    SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+	}
+
+      /* Under kame set interface index to link local address. */
+#ifdef KAME
+
+#define SET_IN6_LINKLOCAL_IFINDEX(a, i) \
+      do { \
+	(a).s6_addr[2] = ((i) >> 8) & 0xff; \
+	(a).s6_addr[3] = (i) & 0xff; \
+      } while (0)
+
+      if (gate && IN6_IS_ADDR_LINKLOCAL(&sin_gate.sin6_addr))
+	SET_IN6_LINKLOCAL_IFINDEX (sin_gate.sin6_addr, ifindex);
+#endif /* KAME */
+
+      if (gate && p->prefixlen == 128)
+	mask = NULL;
+      else
+	{
+	  masklen2ip6 (p->prefixlen, &sin_mask.sin6_addr);
+	  sin_mask.sin6_family = AF_UNSPEC;
+#ifdef SIN6_LEN
+	  sin_mask.sin6_len = sin6_masklen (sin_mask.sin6_addr);
+#endif /* SIN6_LEN */
+	  mask = &sin_mask;
+	}
+
+      error = rtm_write (cmd,
+			(union sockunion *) &sin_dest,
+			(union sockunion *) mask,
+			gate ? (union sockunion *)&sin_gate : NULL,
+			ifindex,
+			rib->flags,
+			rib->metric);
+
+#if 0
+      if (error)
+	{
+	  zlog_info ("kernel_rtm_ipv6_multipath(): nexthop %d add error=%d.",
+	    nexthop_num, error);
+	}
+#endif
+
+      nexthop_num++;
+    }
+
+  /* If there is no useful nexthop then return. */
+  if (nexthop_num == 0)
+    {
+      if (IS_ZEBRA_DEBUG_KERNEL)
+	zlog_info ("kernel_rtm_ipv6_multipath(): No useful nexthop.");
+      return 0;
+    }
+
+  return 0; /*XXX*/
+}
+
+int
+kernel_add_ipv6 (struct prefix *p, struct rib *rib)
+{
+  return kernel_rtm_ipv6_multipath (RTM_ADD, p, rib, AF_INET6);
+}
+
+int
+kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
+{
+  return kernel_rtm_ipv6_multipath (RTM_DELETE, p, rib, AF_INET6);
+}
+
+/* Delete IPv6 route from the kernel. */
+int
+kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
+		    int index, int flags, int table)
+{
+  return kernel_rtm_ipv6 (RTM_DELETE, dest, gate, index, flags);
+}
+#endif /* HAVE_IPV6 */
diff --git a/zebra/rtadv.c b/zebra/rtadv.c
new file mode 100644
index 0000000..8f4b377
--- /dev/null
+++ b/zebra/rtadv.c
@@ -0,0 +1,1112 @@
+/* Router advertisement
+ * Copyright (C) 1999 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 "memory.h"
+#include "sockopt.h"
+#include "thread.h"
+#include "if.h"
+#include "log.h"
+#include "prefix.h"
+#include "linklist.h"
+#include "command.h"
+
+#include "zebra/interface.h"
+#include "zebra/rtadv.h"
+#include "zebra/debug.h"
+
+#if defined (HAVE_IPV6) && defined (RTADV)
+
+/* If RFC2133 definition is used. */
+#ifndef IPV6_JOIN_GROUP
+#define IPV6_JOIN_GROUP  IPV6_ADD_MEMBERSHIP 
+#endif
+#ifndef IPV6_LEAVE_GROUP
+#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP 
+#endif
+
+#define ALLNODE   "ff02::1"
+#define ALLROUTER "ff02::2"
+
+enum rtadv_event {RTADV_START, RTADV_STOP, RTADV_TIMER, RTADV_READ};
+
+void rtadv_event (enum rtadv_event, int);
+
+int if_join_all_router (int, struct interface *);
+int if_leave_all_router (int, struct interface *);
+
+/* Structure which hold status of router advertisement. */
+struct rtadv
+{
+  int sock;
+
+  int adv_if_count;
+
+  struct thread *ra_read;
+  struct thread *ra_timer;
+};
+
+struct rtadv *rtadv = NULL;
+
+struct rtadv *
+rtadv_new ()
+{
+  struct rtadv *new;
+  new = XMALLOC (MTYPE_TMP, sizeof (struct rtadv));
+  memset (new, 0, sizeof (struct rtadv));
+  return new;
+}
+
+void
+rtadv_free (struct rtadv *rtadv)
+{
+  XFREE (MTYPE_TMP, rtadv);
+}
+
+int
+rtadv_recv_packet (int sock, u_char *buf, int buflen,
+		   struct sockaddr_in6 *from, unsigned int *ifindex,
+		   int *hoplimit)
+{
+  int ret;
+  struct msghdr msg;
+  struct iovec iov;
+  struct cmsghdr  *cmsgptr;
+  struct in6_addr dst;
+
+  char adata[1024];
+
+  /* Fill in message and iovec. */
+  msg.msg_name = (void *) from;
+  msg.msg_namelen = sizeof (struct sockaddr_in6);
+  msg.msg_iov = &iov;
+  msg.msg_iovlen = 1;
+  msg.msg_control = (void *) adata;
+  msg.msg_controllen = sizeof adata;
+  iov.iov_base = buf;
+  iov.iov_len = buflen;
+
+  /* If recvmsg fail return minus value. */
+  ret = recvmsg (sock, &msg, 0);
+  if (ret < 0)
+    return ret;
+
+  for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL;
+       cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) 
+    {
+      /* I want interface index which this packet comes from. */
+      if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
+	  cmsgptr->cmsg_type == IPV6_PKTINFO) 
+	{
+	  struct in6_pktinfo *ptr;
+	  
+	  ptr = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
+	  *ifindex = ptr->ipi6_ifindex;
+	  memcpy(&dst, &ptr->ipi6_addr, sizeof(ptr->ipi6_addr));
+        }
+
+      /* Incoming packet's hop limit. */
+      if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
+	  cmsgptr->cmsg_type == IPV6_HOPLIMIT)
+	*hoplimit = *((int *) CMSG_DATA (cmsgptr));
+    }
+  return ret;
+}
+
+#define RTADV_MSG_SIZE 4096
+
+/* Send router advertisement packet. */
+void
+rtadv_send_packet (int sock, struct interface *ifp)
+{
+  struct msghdr msg;
+  struct iovec iov;
+  struct cmsghdr  *cmsgptr;
+  struct in6_pktinfo *pkt;
+  struct sockaddr_in6 addr;
+#if HAVE_SOCKADDR_DL
+  struct sockaddr_dl *sdl;
+#endif /* HAVE_SOCKADDR_DL */
+  char adata [sizeof (struct cmsghdr) + sizeof (struct in6_pktinfo)];
+  unsigned char buf[RTADV_MSG_SIZE];
+  struct nd_router_advert *rtadv;
+  int ret;
+  int len = 0;
+  struct zebra_if *zif;
+  u_char all_nodes_addr[] = {0xff,0x02,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
+  listnode node;
+
+  /* Logging of packet. */
+  if (IS_ZEBRA_DEBUG_PACKET)
+    zlog_info ("Router advertisement send to %s", ifp->name);
+
+  /* Fill in sockaddr_in6. */
+  memset (&addr, 0, sizeof (struct sockaddr_in6));
+  addr.sin6_family = AF_INET6;
+#ifdef SIN6_LEN
+  addr.sin6_len = sizeof (struct sockaddr_in6);
+#endif /* SIN6_LEN */
+  addr.sin6_port = htons (IPPROTO_ICMPV6);
+  memcpy (&addr.sin6_addr, all_nodes_addr, sizeof (struct in6_addr));
+
+  /* Fetch interface information. */
+  zif = ifp->info;
+
+  /* Make router advertisement message. */
+  rtadv = (struct nd_router_advert *) buf;
+
+  rtadv->nd_ra_type = ND_ROUTER_ADVERT;
+  rtadv->nd_ra_code = 0;
+  rtadv->nd_ra_cksum = 0;
+
+  rtadv->nd_ra_curhoplimit = 64;
+  rtadv->nd_ra_flags_reserved = 0;
+  if (zif->rtadv.AdvManagedFlag)
+    rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_MANAGED;
+  if (zif->rtadv.AdvOtherConfigFlag)
+    rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_OTHER;
+  rtadv->nd_ra_router_lifetime = htons (zif->rtadv.AdvDefaultLifetime);
+  rtadv->nd_ra_reachable = htonl (zif->rtadv.AdvReachableTime);
+  rtadv->nd_ra_retransmit = htonl (0);
+
+  len = sizeof (struct nd_router_advert);
+
+  /* Fill in prefix. */
+  for (node = listhead (zif->rtadv.AdvPrefixList); node; node = nextnode (node))
+    {
+      struct nd_opt_prefix_info *pinfo;
+      struct rtadv_prefix *rprefix;
+
+      rprefix = getdata (node);
+
+      pinfo = (struct nd_opt_prefix_info *) (buf + len);
+
+      pinfo->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
+      pinfo->nd_opt_pi_len = 4;
+      pinfo->nd_opt_pi_prefix_len = rprefix->prefix.prefixlen;
+
+      pinfo->nd_opt_pi_flags_reserved = 0;
+      if (rprefix->AdvOnLinkFlag)
+	pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_ONLINK;
+      if (rprefix->AdvAutonomousFlag)
+	pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_AUTO;
+
+      pinfo->nd_opt_pi_valid_time = htonl (rprefix->AdvValidLifetime);
+      pinfo->nd_opt_pi_preferred_time = htonl (rprefix->AdvPreferredLifetime);
+      pinfo->nd_opt_pi_reserved2 = 0;
+
+      memcpy (&pinfo->nd_opt_pi_prefix, &rprefix->prefix.u.prefix6,
+	      sizeof (struct in6_addr));
+
+#ifdef DEBUG
+      {
+	u_char buf[INET6_ADDRSTRLEN];
+
+	zlog_info ("DEBUG %s", inet_ntop (AF_INET6, &pinfo->nd_opt_pi_prefix, buf, INET6_ADDRSTRLEN));
+
+      }
+#endif /* DEBUG */
+
+      len += sizeof (struct nd_opt_prefix_info);
+    }
+
+  /* Hardware address. */
+#ifdef HAVE_SOCKADDR_DL
+  sdl = &ifp->sdl;
+  if (sdl != NULL && sdl->sdl_alen != 0)
+    {
+      buf[len++] = ND_OPT_SOURCE_LINKADDR;
+      buf[len++] = (sdl->sdl_alen + 2) >> 3;
+
+      memcpy (buf + len, LLADDR (sdl), sdl->sdl_alen);
+      len += sdl->sdl_alen;
+    }
+#else
+  if (ifp->hw_addr_len != 0)
+    {
+      buf[len++] = ND_OPT_SOURCE_LINKADDR;
+      buf[len++] = (ifp->hw_addr_len + 2) >> 3;
+
+      memcpy (buf + len, ifp->hw_addr, ifp->hw_addr_len);
+      len += ifp->hw_addr_len;
+    }
+#endif /* HAVE_SOCKADDR_DL */
+
+  msg.msg_name = (void *) &addr;
+  msg.msg_namelen = sizeof (struct sockaddr_in6);
+  msg.msg_iov = &iov;
+  msg.msg_iovlen = 1;
+  msg.msg_control = (void *) adata;
+  msg.msg_controllen = sizeof adata;
+  iov.iov_base = buf;
+  iov.iov_len = len;
+
+  cmsgptr = (struct cmsghdr *)adata;
+  cmsgptr->cmsg_len = sizeof adata;
+  cmsgptr->cmsg_level = IPPROTO_IPV6;
+  cmsgptr->cmsg_type = IPV6_PKTINFO;
+  pkt = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
+  memset (&pkt->ipi6_addr, 0, sizeof (struct in6_addr));
+  pkt->ipi6_ifindex = ifp->ifindex;
+
+  ret = sendmsg (sock, &msg, 0);
+  if (ret <0)
+    perror ("sendmsg");
+}
+
+int
+rtadv_timer (struct thread *thread)
+{
+  listnode node;
+  struct interface *ifp;
+  struct zebra_if *zif;
+
+  rtadv->ra_timer = NULL;
+  rtadv_event (RTADV_TIMER, 1);
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+
+      if (if_is_loopback (ifp))
+	continue;
+
+      zif = ifp->info;
+
+      if (zif->rtadv.AdvSendAdvertisements)
+	if (--zif->rtadv.AdvIntervalTimer <= 0)
+	  {
+	    zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
+	    rtadv_send_packet (rtadv->sock, ifp);
+	  }
+    }
+  return 0;
+}
+
+void
+rtadv_process_solicit (struct interface *ifp)
+{
+  zlog_info ("Router solicitation received on %s", ifp->name);
+
+  rtadv_send_packet (rtadv->sock, ifp);
+}
+
+void
+rtadv_process_advert ()
+{
+  zlog_info ("Router advertisement received");
+}
+
+void
+rtadv_process_packet (u_char *buf, int len, unsigned int ifindex, int hoplimit)
+{
+  struct icmp6_hdr *icmph;
+  struct interface *ifp;
+  struct zebra_if *zif;
+
+  /* Interface search. */
+  ifp = if_lookup_by_index (ifindex);
+  if (ifp == NULL)
+    {
+      zlog_warn ("Unknown interface index: %d", ifindex);
+      return;
+    }
+
+  if (if_is_loopback (ifp))
+    return;
+
+  /* Check interface configuration. */
+  zif = ifp->info;
+  if (! zif->rtadv.AdvSendAdvertisements)
+    return;
+
+  /* ICMP message length check. */
+  if (len < sizeof (struct icmp6_hdr))
+    {
+      zlog_warn ("Invalid ICMPV6 packet length: %d", len);
+      return;
+    }
+
+  icmph = (struct icmp6_hdr *) buf;
+
+  /* ICMP message type check. */
+  if (icmph->icmp6_type != ND_ROUTER_SOLICIT &&
+      icmph->icmp6_type != ND_ROUTER_ADVERT)
+    {
+      zlog_warn ("Unwanted ICMPV6 message type: %d", icmph->icmp6_type);
+      return;
+    }
+
+  /* Hoplimit check. */
+  if (hoplimit >= 0 && hoplimit != 255)
+    {
+      zlog_warn ("Invalid hoplimit %d for router advertisement ICMP packet",
+		 hoplimit);
+      return;
+    }
+
+  /* Check ICMP message type. */
+  if (icmph->icmp6_type == ND_ROUTER_SOLICIT)
+    rtadv_process_solicit (ifp);
+  else if (icmph->icmp6_type == ND_ROUTER_ADVERT)
+    rtadv_process_advert ();
+
+  return;
+}
+
+int
+rtadv_read (struct thread *thread)
+{
+  int sock;
+  int len;
+  u_char buf[RTADV_MSG_SIZE];
+  struct sockaddr_in6 from;
+  unsigned int ifindex;
+  int hoplimit = -1;
+
+  sock = THREAD_FD (thread);
+  rtadv->ra_read = NULL;
+
+  /* Register myself. */
+  rtadv_event (RTADV_READ, sock);
+
+  len = rtadv_recv_packet (sock, buf, BUFSIZ, &from, &ifindex, &hoplimit);
+
+  if (len < 0) 
+    {
+      zlog_warn ("router solicitation recv failed: %s.", strerror (errno));
+      return len;
+    }
+
+  rtadv_process_packet (buf, len, ifindex, hoplimit);
+
+  return 0;
+}
+
+int
+rtadv_make_socket (void)
+{
+  int sock;
+  int ret;
+  struct icmp6_filter filter;
+
+  sock = socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
+
+  /* When we can't make ICMPV6 socket simply back.  Router
+     advertisement feature will not be supported. */
+  if (sock < 0)
+    return -1;
+
+  ret = setsockopt_ipv6_pktinfo (sock, 1);
+  if (ret < 0)
+    return ret;
+  ret = setsockopt_ipv6_checksum (sock, 2);
+  if (ret < 0)
+    return ret;
+  ret = setsockopt_ipv6_multicast_loop (sock, 0);
+  if (ret < 0)
+    return ret;
+  ret = setsockopt_ipv6_unicast_hops (sock, 255);
+  if (ret < 0)
+    return ret;
+  ret = setsockopt_ipv6_multicast_hops (sock, 255);
+  if (ret < 0)
+    return ret;
+  ret = setsockopt_ipv6_hoplimit (sock, 1);
+  if (ret < 0)
+    return ret;
+
+  ICMP6_FILTER_SETBLOCKALL(&filter);
+  ICMP6_FILTER_SETPASS (ND_ROUTER_SOLICIT, &filter);
+  ICMP6_FILTER_SETPASS (ND_ROUTER_ADVERT, &filter);
+
+  ret = setsockopt (sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
+		    sizeof (struct icmp6_filter));
+  if (ret < 0)
+    {
+      zlog_info ("ICMP6_FILTER set fail: %s", strerror (errno));
+      return ret;
+    }
+
+  return sock;
+}
+
+struct rtadv_prefix *
+rtadv_prefix_new ()
+{
+  struct rtadv_prefix *new;
+
+  new = XMALLOC (MTYPE_RTADV_PREFIX, sizeof (struct rtadv_prefix));
+  memset (new, 0, sizeof (struct rtadv_prefix));
+
+  return new;
+}
+
+void
+rtadv_prefix_free (struct rtadv_prefix *rtadv_prefix)
+{
+  XFREE (MTYPE_RTADV_PREFIX, rtadv_prefix);
+}
+
+struct rtadv_prefix *
+rtadv_prefix_lookup (list rplist, struct prefix *p)
+{
+  listnode node;
+  struct rtadv_prefix *rprefix;
+
+  for (node = listhead (rplist); node; node = nextnode (node))
+    {
+      rprefix = getdata (node);
+      if (prefix_same (&rprefix->prefix, p))
+	return rprefix;
+    }
+  return NULL;
+}
+
+struct rtadv_prefix *
+rtadv_prefix_get (list rplist, struct prefix *p)
+{
+  struct rtadv_prefix *rprefix;
+  
+  rprefix = rtadv_prefix_lookup (rplist, p);
+  if (rprefix)
+    return rprefix;
+
+  rprefix = rtadv_prefix_new ();
+  memcpy (&rprefix->prefix, p, sizeof (struct prefix));
+  listnode_add (rplist, rprefix);
+
+  return rprefix;
+}
+
+void
+rtadv_prefix_set (struct zebra_if *zif, struct rtadv_prefix *rp)
+{
+  struct rtadv_prefix *rprefix;
+  
+  rprefix = rtadv_prefix_get (zif->rtadv.AdvPrefixList, &rp->prefix);
+
+  /* Set parameters. */
+  rprefix->AdvValidLifetime = rp->AdvValidLifetime;
+  rprefix->AdvPreferredLifetime = rp->AdvPreferredLifetime;
+  rprefix->AdvOnLinkFlag = rp->AdvOnLinkFlag;
+  rprefix->AdvAutonomousFlag = rp->AdvAutonomousFlag;
+}
+
+int
+rtadv_prefix_reset (struct zebra_if *zif, struct rtadv_prefix *rp)
+{
+  struct rtadv_prefix *rprefix;
+  
+  rprefix = rtadv_prefix_lookup (zif->rtadv.AdvPrefixList, &rp->prefix);
+  if (rprefix != NULL)
+    {
+      listnode_delete (zif->rtadv.AdvPrefixList, (void *) rprefix);
+      rtadv_prefix_free (rprefix);
+      return 1;
+    }
+  else
+    return 0;
+}
+
+DEFUN (ipv6_nd_suppress_ra,
+       ipv6_nd_suppress_ra_cmd,
+       "ipv6 nd suppress-ra",
+       IP_STR
+       "Neighbor discovery\n"
+       "Suppress Router Advertisement\n")
+{
+  struct interface *ifp;
+  struct zebra_if *zif;
+
+  ifp = vty->index;
+  zif = ifp->info;
+
+  if (if_is_loopback (ifp))
+    {
+      vty_out (vty, "Invalid interface%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (zif->rtadv.AdvSendAdvertisements)
+    {
+      zif->rtadv.AdvSendAdvertisements = 0;
+      zif->rtadv.AdvIntervalTimer = 0;
+      rtadv->adv_if_count--;
+
+      if_leave_all_router (rtadv->sock, ifp);
+
+      if (rtadv->adv_if_count == 0)
+	rtadv_event (RTADV_STOP, 0);
+    }
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (ipv6_nd_suppress_ra,
+       no_ipv6_nd_send_ra_cmd,
+       "no ipv6 nd send-ra",
+       NO_STR
+       IP_STR
+       "Neighbor discovery\n"
+       "Send Router Advertisement\n")
+
+DEFUN (no_ipv6_nd_suppress_ra,
+       no_ipv6_nd_suppress_ra_cmd,
+       "no ipv6 nd suppress-ra",
+       NO_STR
+       IP_STR
+       "Neighbor discovery\n"
+       "Suppress Router Advertisement\n")
+{
+  struct interface *ifp;
+  struct zebra_if *zif;
+
+  ifp = vty->index;
+  zif = ifp->info;
+
+  if (if_is_loopback (ifp))
+    {
+      vty_out (vty, "Invalid interface%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (! zif->rtadv.AdvSendAdvertisements)
+    {
+      zif->rtadv.AdvSendAdvertisements = 1;
+      zif->rtadv.AdvIntervalTimer = 0;
+      rtadv->adv_if_count++;
+
+      if_join_all_router (rtadv->sock, ifp);
+
+      if (rtadv->adv_if_count == 1)
+	rtadv_event (RTADV_START, rtadv->sock);
+    }
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ipv6_nd_suppress_ra,
+       ipv6_nd_send_ra_cmd,
+       "ipv6 nd send-ra",
+       IP_STR
+       "Neighbor discovery\n"
+       "Send Router Advertisement\n")
+
+DEFUN (ipv6_nd_ra_interval,
+       ipv6_nd_ra_interval_cmd,
+       "ipv6 nd ra-interval SECONDS",
+       IP_STR
+       "Neighbor discovery\n"
+       "Router Advertisement interval\n"
+       "Router Advertisement interval in seconds\n")
+{
+  int interval;
+  struct interface *ifp;
+  struct zebra_if *zif;
+
+  ifp = (struct interface *) vty->index;
+  zif = ifp->info;
+
+  interval = atoi (argv[0]);
+
+  if (interval < 0)
+    {
+      vty_out (vty, "Invalid Router Advertisement Interval%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  zif->rtadv.MaxRtrAdvInterval = interval;
+  zif->rtadv.MinRtrAdvInterval = 0.33 * interval;
+  zif->rtadv.AdvIntervalTimer = 0;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_nd_ra_interval,
+       no_ipv6_nd_ra_interval_cmd,
+       "no ipv6 nd ra-interval",
+       NO_STR
+       IP_STR
+       "Neighbor discovery\n"
+       "Router Advertisement interval\n")
+{
+  struct interface *ifp;
+  struct zebra_if *zif;
+
+  ifp = (struct interface *) vty->index;
+  zif = ifp->info;
+
+  zif->rtadv.MaxRtrAdvInterval = RTADV_MAX_RTR_ADV_INTERVAL;
+  zif->rtadv.MinRtrAdvInterval = RTADV_MIN_RTR_ADV_INTERVAL;
+  zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ipv6_nd_ra_lifetime,
+       ipv6_nd_ra_lifetime_cmd,
+       "ipv6 nd ra-lifetime SECONDS",
+       IP_STR
+       "Neighbor discovery\n"
+       "Router lifetime\n"
+       "Router lifetime in seconds\n")
+{
+  int lifetime;
+  struct interface *ifp;
+  struct zebra_if *zif;
+
+  ifp = (struct interface *) vty->index;
+  zif = ifp->info;
+
+  lifetime = atoi (argv[0]);
+
+  if (lifetime < 0 || lifetime > 0xffff)
+    {
+      vty_out (vty, "Invalid Router Lifetime%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  zif->rtadv.AdvDefaultLifetime = lifetime;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_nd_ra_lifetime,
+       no_ipv6_nd_ra_lifetime_cmd,
+       "no ipv6 nd ra-lifetime",
+       NO_STR
+       IP_STR
+       "Neighbor discovery\n"
+       "Router lifetime\n")
+{
+  struct interface *ifp;
+  struct zebra_if *zif;
+
+  ifp = (struct interface *) vty->index;
+  zif = ifp->info;
+
+  zif->rtadv.AdvDefaultLifetime = RTADV_ADV_DEFAULT_LIFETIME;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ipv6_nd_reachable_time,
+       ipv6_nd_reachable_time_cmd,
+       "ipv6 nd reachable-time MILLISECONDS",
+       IP_STR
+       "Neighbor discovery\n"
+       "Reachable time\n"
+       "Reachable time in milliseconds\n")
+{
+  u_int32_t rtime;
+  struct interface *ifp;
+  struct zebra_if *zif;
+
+  ifp = (struct interface *) vty->index;
+  zif = ifp->info;
+
+  rtime = (u_int32_t) atol (argv[0]);
+
+  if (rtime > RTADV_MAX_REACHABLE_TIME)
+    {
+      vty_out (vty, "Invalid Reachable time%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  zif->rtadv.AdvReachableTime = rtime;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_nd_reachable_time,
+       no_ipv6_nd_reachable_time_cmd,
+       "no ipv6 nd reachable-time",
+       NO_STR
+       IP_STR
+       "Neighbor discovery\n"
+       "Reachable time\n")
+{
+  struct interface *ifp;
+  struct zebra_if *zif;
+
+  ifp = (struct interface *) vty->index;
+  zif = ifp->info;
+
+  zif->rtadv.AdvReachableTime = 0;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ipv6_nd_managed_config_flag,
+       ipv6_nd_managed_config_flag_cmd,
+       "ipv6 nd managed-config-flag",
+       IP_STR
+       "Neighbor discovery\n"
+       "Managed address configuration flag\n")
+{
+  struct interface *ifp;
+  struct zebra_if *zif;
+
+  ifp = (struct interface *) vty->index;
+  zif = ifp->info;
+
+  zif->rtadv.AdvManagedFlag = 1;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_nd_managed_config_flag,
+       no_ipv6_nd_managed_config_flag_cmd,
+       "no ipv6 nd managed-config-flag",
+       NO_STR
+       IP_STR
+       "Neighbor discovery\n"
+       "Managed address configuration flag\n")
+{
+  struct interface *ifp;
+  struct zebra_if *zif;
+
+  ifp = (struct interface *) vty->index;
+  zif = ifp->info;
+
+  zif->rtadv.AdvManagedFlag = 0;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ipv6_nd_other_config_flag,
+       ipv6_nd_other_config_flag_cmd,
+       "ipv6 nd other-config-flag",
+       IP_STR
+       "Neighbor discovery\n"
+       "Other statefull configuration flag\n")
+{
+  struct interface *ifp;
+  struct zebra_if *zif;
+
+  ifp = (struct interface *) vty->index;
+  zif = ifp->info;
+
+  zif->rtadv.AdvOtherConfigFlag = 1;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_nd_other_config_flag,
+       no_ipv6_nd_other_config_flag_cmd,
+       "no ipv6 nd other-config-flag",
+       NO_STR
+       IP_STR
+       "Neighbor discovery\n"
+       "Other statefull configuration flag\n")
+{
+  struct interface *ifp;
+  struct zebra_if *zif;
+
+  ifp = (struct interface *) vty->index;
+  zif = ifp->info;
+
+  zif->rtadv.AdvOtherConfigFlag = 0;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ipv6_nd_prefix_advertisement,
+       ipv6_nd_prefix_advertisement_cmd,
+       "ipv6 nd prefix-advertisement IPV6PREFIX VALID PREFERRED [onlink] [autoconfig]",
+       IP_STR
+       "Neighbor discovery\n"
+       "Prefix information\n"
+       "IPv6 prefix\n"
+       "Valid lifetime in seconds\n"
+       "Preferred lifetime in seconds\n"
+       "On link flag\n"
+       "Autonomous address-configuration flag\n")
+{
+  int i;
+  int ret;
+  struct interface *ifp;
+  struct zebra_if *zebra_if;
+  struct rtadv_prefix rp;
+
+  ifp = (struct interface *) vty->index;
+  zebra_if = ifp->info;
+
+  ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &rp.prefix);
+  if (!ret)
+    {
+      vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (argc == 1)
+    {
+      rp.AdvValidLifetime = RTADV_VALID_LIFETIME;
+      rp.AdvPreferredLifetime = RTADV_PREFERRED_LIFETIME;
+      rp.AdvOnLinkFlag = 1;
+      rp.AdvAutonomousFlag = 1;
+    }
+  else
+    {
+      rp.AdvValidLifetime = (u_int32_t) atol (argv[1]);
+      rp.AdvPreferredLifetime = (u_int32_t) atol (argv[2]);
+      if (rp.AdvPreferredLifetime > rp.AdvValidLifetime)
+	{
+	  vty_out (vty, "Invalid preferred lifetime%s", VTY_NEWLINE);
+	  return CMD_WARNING;
+	}
+
+      rp.AdvOnLinkFlag = 0;
+      rp.AdvAutonomousFlag = 0;
+      for (i = 3; i < argc; i++)
+	{
+	  if (! strcmp (argv[i], "onlink"))
+	    rp.AdvOnLinkFlag = 1;
+	  else if (! strcmp (argv[i], "autoconfig"))
+	    rp.AdvAutonomousFlag = 1;
+	}
+    }
+
+  rtadv_prefix_set (zebra_if, &rp);
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (ipv6_nd_prefix_advertisement,
+       ipv6_nd_prefix_advertisement_no_val_cmd,
+       "ipv6 nd prefix-advertisement IPV6PREFIX",
+       IP_STR
+       "Neighbor discovery\n"
+       "Prefix information\n"
+       "IPv6 prefix\n")
+
+DEFUN (no_ipv6_nd_prefix_advertisement,
+       no_ipv6_nd_prefix_advertisement_cmd,
+       "no ipv6 nd prefix-advertisement IPV6PREFIX",
+       NO_STR
+       IP_STR
+       "Neighbor discovery\n"
+       "Prefix information\n"
+       "IPv6 prefix\n")
+{
+  int ret;
+  struct interface *ifp;
+  struct zebra_if *zebra_if;
+  struct rtadv_prefix rp;
+
+  ifp = (struct interface *) vty->index;
+  zebra_if = ifp->info;
+
+  ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &rp.prefix);
+  if (!ret)
+    {
+      vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ret = rtadv_prefix_reset (zebra_if, &rp);
+  if (!ret)
+    {
+      vty_out (vty, "Non-exist IPv6 prefix%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return CMD_SUCCESS;
+}
+
+/* Write configuration about router advertisement. */
+void
+rtadv_config_write (struct vty *vty, struct interface *ifp)
+{
+  struct zebra_if *zif;
+  listnode node;
+  struct rtadv_prefix *rprefix;
+  u_char buf[INET6_ADDRSTRLEN];
+
+  if (! rtadv)
+    return;
+
+  zif = ifp->info;
+
+  if (! if_is_loopback (ifp))
+    {
+      if (zif->rtadv.AdvSendAdvertisements)
+	vty_out (vty, " no ipv6 nd suppress-ra%s", VTY_NEWLINE);
+      else
+	vty_out (vty, " ipv6 nd suppress-ra%s", VTY_NEWLINE);
+    }
+
+  if (zif->rtadv.MaxRtrAdvInterval != RTADV_MAX_RTR_ADV_INTERVAL)
+    vty_out (vty, " ipv6 nd ra-interval %d%s", zif->rtadv.MaxRtrAdvInterval,
+	     VTY_NEWLINE);
+
+  if (zif->rtadv.AdvDefaultLifetime != RTADV_ADV_DEFAULT_LIFETIME)
+    vty_out (vty, " ipv6 nd ra-lifetime %d%s", zif->rtadv.AdvDefaultLifetime,
+	     VTY_NEWLINE);
+
+  if (zif->rtadv.AdvReachableTime)
+    vty_out (vty, " ipv6 nd reachable-time %d%s", zif->rtadv.AdvReachableTime,
+	     VTY_NEWLINE);
+
+  if (zif->rtadv.AdvManagedFlag)
+    vty_out (vty, " ipv6 nd managed-config-flag%s", VTY_NEWLINE);
+
+  if (zif->rtadv.AdvOtherConfigFlag)
+    vty_out (vty, " ipv6 nd other-config-flag%s", VTY_NEWLINE);
+
+  for (node = listhead(zif->rtadv.AdvPrefixList); node; node = nextnode (node))
+    {
+      rprefix = getdata (node);
+      vty_out (vty, " ipv6 nd prefix-advertisement %s/%d %d %d",
+	       inet_ntop (AF_INET6, &rprefix->prefix.u.prefix6, 
+			  buf, INET6_ADDRSTRLEN),
+	       rprefix->prefix.prefixlen,
+	       rprefix->AdvValidLifetime,
+	       rprefix->AdvPreferredLifetime);
+      if (rprefix->AdvOnLinkFlag)
+	vty_out (vty, " onlink");
+      if (rprefix->AdvAutonomousFlag)
+	vty_out (vty, " autoconfig");
+      vty_out (vty, "%s", VTY_NEWLINE);
+    }
+}
+
+extern struct thread_master *master;
+
+void
+rtadv_event (enum rtadv_event event, int val)
+{
+  switch (event)
+    {
+    case RTADV_START:
+      if (! rtadv->ra_read)
+	rtadv->ra_read = thread_add_read (master, rtadv_read, NULL, val);
+      if (! rtadv->ra_timer)
+	rtadv->ra_timer = thread_add_event (master, rtadv_timer, NULL, 0);
+      break;
+    case RTADV_STOP:
+      if (rtadv->ra_timer)
+	{
+	  thread_cancel (rtadv->ra_timer);
+	  rtadv->ra_timer = NULL;
+	}
+      if (rtadv->ra_read)
+	{
+	  thread_cancel (rtadv->ra_read);
+	  rtadv->ra_read = NULL;
+	}
+      break;
+    case RTADV_TIMER:
+      if (! rtadv->ra_timer)
+	rtadv->ra_timer = thread_add_timer (master, rtadv_timer, NULL, val);
+      break;
+    case RTADV_READ:
+      if (! rtadv->ra_read)
+	rtadv->ra_read = thread_add_read (master, rtadv_read, NULL, val);
+      break;
+    default:
+      break;
+    }
+  return;
+}
+
+void
+rtadv_init ()
+{
+  int sock;
+
+  sock = rtadv_make_socket ();
+  if (sock < 0)
+    return;
+
+  rtadv = rtadv_new ();
+  rtadv->sock = sock;
+
+  install_element (INTERFACE_NODE, &ipv6_nd_suppress_ra_cmd);
+  install_element (INTERFACE_NODE, &no_ipv6_nd_suppress_ra_cmd);
+  install_element (INTERFACE_NODE, &ipv6_nd_send_ra_cmd);
+  install_element (INTERFACE_NODE, &no_ipv6_nd_send_ra_cmd);
+  install_element (INTERFACE_NODE, &ipv6_nd_ra_interval_cmd);
+  install_element (INTERFACE_NODE, &no_ipv6_nd_ra_interval_cmd);
+  install_element (INTERFACE_NODE, &ipv6_nd_ra_lifetime_cmd);
+  install_element (INTERFACE_NODE, &no_ipv6_nd_ra_lifetime_cmd);
+  install_element (INTERFACE_NODE, &ipv6_nd_reachable_time_cmd);
+  install_element (INTERFACE_NODE, &no_ipv6_nd_reachable_time_cmd);
+  install_element (INTERFACE_NODE, &ipv6_nd_managed_config_flag_cmd);
+  install_element (INTERFACE_NODE, &no_ipv6_nd_managed_config_flag_cmd);
+  install_element (INTERFACE_NODE, &ipv6_nd_other_config_flag_cmd);
+  install_element (INTERFACE_NODE, &no_ipv6_nd_other_config_flag_cmd);
+  install_element (INTERFACE_NODE, &ipv6_nd_prefix_advertisement_cmd);
+  install_element (INTERFACE_NODE, &ipv6_nd_prefix_advertisement_no_val_cmd);
+  install_element (INTERFACE_NODE, &no_ipv6_nd_prefix_advertisement_cmd);
+}
+
+int
+if_join_all_router (int sock, struct interface *ifp)
+{
+  int ret;
+
+  struct ipv6_mreq mreq;
+
+  memset (&mreq, 0, sizeof (struct ipv6_mreq));
+  inet_pton (AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr);
+  mreq.ipv6mr_interface = ifp->ifindex;
+
+  ret = setsockopt (sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, 
+		    (char *) &mreq, sizeof mreq);
+  if (ret < 0)
+    zlog_warn ("can't setsockopt IPV6_JOIN_GROUP: %s", strerror (errno));
+
+  zlog_info ("rtadv: %s join to all-routers multicast group", ifp->name);
+
+  return 0;
+}
+
+int
+if_leave_all_router (int sock, struct interface *ifp)
+{
+  int ret;
+
+  struct ipv6_mreq mreq;
+
+  memset (&mreq, 0, sizeof (struct ipv6_mreq));
+  inet_pton (AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr);
+  mreq.ipv6mr_interface = ifp->ifindex;
+
+  ret = setsockopt (sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, 
+		    (char *) &mreq, sizeof mreq);
+  if (ret < 0)
+    zlog_warn ("can't setsockopt IPV6_LEAVE_GROUP: %s", strerror (errno));
+
+  zlog_info ("rtadv: %s leave from all-routers multicast group", ifp->name);
+
+  return 0;
+}
+
+#else
+void
+rtadv_init ()
+{
+  /* Empty.*/;
+}
+#endif /* RTADV && HAVE_IPV6 */
diff --git a/zebra/rtadv.h b/zebra/rtadv.h
new file mode 100644
index 0000000..859b2d7
--- /dev/null
+++ b/zebra/rtadv.h
@@ -0,0 +1,49 @@
+/* Router advertisement
+ * Copyright (C) 1999 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.  
+ */
+
+#ifndef _ZEBRA_RTADV_H
+#define _ZEBRA_RTADV_H
+
+/* Router advertisement prefix. */
+struct rtadv_prefix
+{
+  /* Prefix to be advertised. */
+  struct prefix prefix;
+  
+  /* The value to be placed in the Valid Lifetime in the Prefix */
+  u_int32_t AdvValidLifetime;
+#define RTADV_VALID_LIFETIME 2592000
+
+  /* The value to be placed in the on-link flag */
+  int AdvOnLinkFlag;
+
+  /* The value to be placed in the Preferred Lifetime in the Prefix
+     Information option, in seconds.*/
+  u_int32_t AdvPreferredLifetime;
+#define RTADV_PREFERRED_LIFETIME 604800
+
+  /* The value to be placed in the Autonomous Flag. */
+  int AdvAutonomousFlag;
+};
+
+void rtadv_config_write (struct vty *, struct interface *);
+
+#endif /* _ZEBRA_RTADV_H */
diff --git a/zebra/rtread_getmsg.c b/zebra/rtread_getmsg.c
new file mode 100644
index 0000000..435eed8
--- /dev/null
+++ b/zebra/rtread_getmsg.c
@@ -0,0 +1,229 @@
+/*
+ * Kernel routing table readup by getmsg(2)
+ * Copyright (C) 1999 Michael Handler
+ *
+ * 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 "log.h"
+#include "if.h"
+
+#include "zebra/rib.h"
+
+#include <sys/stream.h>
+#include <sys/tihdr.h>
+
+/* Solaris defines these in both <netinet/in.h> and <inet/in.h>, sigh */
+#ifdef SUNOS_5
+#include <sys/tiuser.h>
+#ifndef T_CURRENT
+#define T_CURRENT       MI_T_CURRENT
+#endif /* T_CURRENT */
+#ifndef IRE_CACHE
+#define IRE_CACHE               0x0020  /* Cached Route entry */
+#endif /* IRE_CACHE */
+#ifndef IRE_HOST_REDIRECT
+#define IRE_HOST_REDIRECT       0x0200  /* Host route entry from redirects */
+#endif /* IRE_HOST_REDIRECT */
+#ifndef IRE_CACHETABLE
+#define IRE_CACHETABLE          (IRE_CACHE | IRE_BROADCAST | IRE_LOCAL | \
+                                 IRE_LOOPBACK)
+#endif /* IRE_CACHETABLE */
+#undef IPOPT_EOL
+#undef IPOPT_NOP
+#undef IPOPT_LSRR
+#undef IPOPT_RR
+#undef IPOPT_SSRR
+#endif /* SUNOS_5 */
+
+#include <inet/common.h>
+#include <inet/ip.h>
+#include <inet/mib2.h>
+
+/* device to read IP routing table from */
+#ifndef _PATH_GETMSG_ROUTE
+#define _PATH_GETMSG_ROUTE	"/dev/ip"
+#endif /* _PATH_GETMSG_ROUTE */
+
+#define RT_BUFSIZ		8192
+
+void handle_route_entry (mib2_ipRouteEntry_t *routeEntry)
+{
+	struct prefix_ipv4	prefix;
+ 	struct in_addr		tmpaddr, gateway;
+	u_char			zebra_flags = 0;
+
+	if (routeEntry->ipRouteInfo.re_ire_type & IRE_CACHETABLE)
+		return;
+
+	if (routeEntry->ipRouteInfo.re_ire_type & IRE_HOST_REDIRECT)
+		zebra_flags |= ZEBRA_FLAG_SELFROUTE;
+
+	prefix.family = AF_INET;
+
+	tmpaddr.s_addr = routeEntry->ipRouteDest;
+	prefix.prefix = tmpaddr;
+
+	tmpaddr.s_addr = routeEntry->ipRouteMask;
+	prefix.prefixlen = ip_masklen (tmpaddr);
+
+	gateway.s_addr = routeEntry->ipRouteNextHop;
+
+	rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &prefix,
+		      &gateway, 0, 0, 0, 0);
+}
+
+void route_read ()
+{
+	char 			storage[RT_BUFSIZ];
+
+	struct T_optmgmt_req	*TLIreq = (struct T_optmgmt_req *) storage;
+	struct T_optmgmt_ack	*TLIack = (struct T_optmgmt_ack *) storage;
+	struct T_error_ack	*TLIerr = (struct T_error_ack *) storage;
+
+	struct opthdr		*MIB2hdr;
+
+	mib2_ipRouteEntry_t	*routeEntry, *lastRouteEntry;
+
+	struct strbuf		msgdata;
+	int			flags, dev, retval, process;
+
+	if ((dev = open (_PATH_GETMSG_ROUTE, O_RDWR)) == -1) {
+		zlog_warn ("can't open %s: %s", _PATH_GETMSG_ROUTE,
+			strerror (errno));
+		return;
+	}
+
+	TLIreq->PRIM_type = T_OPTMGMT_REQ;
+	TLIreq->OPT_offset = sizeof (struct T_optmgmt_req);
+	TLIreq->OPT_length = sizeof (struct opthdr);
+	TLIreq->MGMT_flags = T_CURRENT;
+
+	MIB2hdr = (struct opthdr *) &TLIreq[1];
+
+	MIB2hdr->level = MIB2_IP;
+	MIB2hdr->name = 0;
+	MIB2hdr->len = 0;
+	
+	msgdata.buf = storage;
+	msgdata.len = sizeof (struct T_optmgmt_req) + sizeof (struct opthdr);
+
+	flags = 0;
+
+	if (putmsg (dev, &msgdata, NULL, flags) == -1) {
+		zlog_warn ("putmsg failed: %s", strerror (errno));
+		goto exit;
+	}
+
+	MIB2hdr = (struct opthdr *) &TLIack[1];
+	msgdata.maxlen = sizeof (storage);
+
+	while (1) {
+		flags = 0;
+		retval = getmsg (dev, &msgdata, NULL, &flags);
+
+		if (retval == -1) {
+			zlog_warn ("getmsg(ctl) failed: %s", strerror (errno));
+			goto exit;
+		}
+
+		/* This is normal loop termination */
+		if (retval == 0 &&
+			msgdata.len >= sizeof (struct T_optmgmt_ack) &&
+			TLIack->PRIM_type == T_OPTMGMT_ACK &&
+			TLIack->MGMT_flags == T_SUCCESS &&
+			MIB2hdr->len == 0)
+			break;
+
+		if (msgdata.len >= sizeof (struct T_error_ack) &&
+			TLIerr->PRIM_type == T_ERROR_ACK) {
+			zlog_warn ("getmsg(ctl) returned T_ERROR_ACK: %s",
+				strerror ((TLIerr->TLI_error == TSYSERR)
+				? TLIerr->UNIX_error : EPROTO));
+			break;
+		}
+
+		/* should dump more debugging info to the log statement,
+		   like what GateD does in this instance, but not
+		   critical yet. */
+		if (retval != MOREDATA ||
+			msgdata.len < sizeof (struct T_optmgmt_ack) ||
+			TLIack->PRIM_type != T_OPTMGMT_ACK ||
+			TLIack->MGMT_flags != T_SUCCESS) {
+			errno = ENOMSG;
+			zlog_warn ("getmsg(ctl) returned bizarreness");
+			break;
+		}
+
+		/* MIB2_IP_21 is the the pseudo-MIB2 ipRouteTable
+		   entry, see <inet/mib2.h>. "This isn't the MIB data
+		   you're looking for." */
+		process = (MIB2hdr->level == MIB2_IP &&
+			MIB2hdr->name == MIB2_IP_21) ? 1 : 0;
+
+		/* getmsg writes the data buffer out completely, not
+		   to the closest smaller multiple. Unless reassembling
+		   data structures across buffer boundaries is your idea
+		   of a good time, set maxlen to the closest smaller
+		   multiple of the size of the datastructure you're
+		   retrieving. */
+		msgdata.maxlen = sizeof (storage) - (sizeof (storage)
+			% sizeof (mib2_ipRouteEntry_t));
+
+		msgdata.len = 0;
+		flags = 0;
+
+		do {
+			retval = getmsg (dev, NULL, &msgdata, &flags);
+
+			if (retval == -1) {
+				zlog_warn ("getmsg(data) failed: %s",
+					strerror (errno));
+				goto exit;
+			}
+
+			if (!(retval == 0 || retval == MOREDATA)) {
+				zlog_warn ("getmsg(data) returned %d", retval);
+				goto exit;
+			}
+
+			if (process) {
+				if (msgdata.len %
+					sizeof (mib2_ipRouteEntry_t) != 0) {
+					zlog_warn ("getmsg(data) returned "
+"msgdata.len = %d (%% sizeof (mib2_ipRouteEntry_t) != 0)", msgdata.len);
+					goto exit;
+				}
+
+				routeEntry = (mib2_ipRouteEntry_t *)
+					msgdata.buf;
+				lastRouteEntry = (mib2_ipRouteEntry_t *)
+					(msgdata.buf + msgdata.len);
+				do {
+					handle_route_entry (routeEntry);
+				} while (++routeEntry < lastRouteEntry);
+			}
+		} while (retval == MOREDATA);
+	}
+
+exit:
+	close (dev);
+}
diff --git a/zebra/rtread_netlink.c b/zebra/rtread_netlink.c
new file mode 100644
index 0000000..0b255a5
--- /dev/null
+++ b/zebra/rtread_netlink.c
@@ -0,0 +1,31 @@
+/*
+ * Kernel routing table readup by netlink
+ * Copyright (C) 1998 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>
+
+/* Extern from rt_netlink.c */
+void netlink_route_read ();
+
+void route_read ()
+{
+  netlink_route_read ();
+}
diff --git a/zebra/rtread_proc.c b/zebra/rtread_proc.c
new file mode 100644
index 0000000..320152e
--- /dev/null
+++ b/zebra/rtread_proc.c
@@ -0,0 +1,169 @@
+/*
+ * Kernel routing readup by /proc filesystem
+ * Copyright (C) 1997 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 "log.h"
+#include "if.h"
+#include "rib.h"
+
+/* Proc file system to read IPv4 routing table. */
+#ifndef _PATH_PROCNET_ROUTE
+#define _PATH_PROCNET_ROUTE      "/proc/net/route"
+#endif /* _PATH_PROCNET_ROUTE */
+
+/* Proc file system to read IPv6 routing table. */
+#ifndef _PATH_PROCNET_ROUTE6
+#define _PATH_PROCNET_ROUTE6     "/proc/net/ipv6_route"
+#endif /* _PATH_PROCNET_ROUTE6 */
+
+/* To read interface's name */
+#define INTERFACE_NAMSIZ 20  
+
+/* Reading buffer for one routing entry. */
+#define RT_BUFSIZ 1024
+
+/* Kernel routing table read up by /proc filesystem. */
+int
+proc_route_read ()
+{
+  FILE *fp;
+  char buf[RT_BUFSIZ];
+  char iface[INTERFACE_NAMSIZ], dest[9], gate[9], mask[9];
+  int flags, refcnt, use, metric, mtu, window, rtt;
+
+  /* Open /proc filesystem */
+  fp = fopen (_PATH_PROCNET_ROUTE, "r");
+  if (fp == NULL)
+    {
+      zlog_warn ("Can't open %s : %s\n", _PATH_PROCNET_ROUTE, strerror (errno));
+      return -1;
+    }
+  
+  /* Drop first label line. */
+  fgets (buf, RT_BUFSIZ, fp);
+
+  while (fgets (buf, RT_BUFSIZ, fp) != NULL)
+    {
+      int n;
+      struct prefix_ipv4 p;
+      struct in_addr tmpmask;
+      struct in_addr gateway;
+      u_char zebra_flags = 0;
+
+      n = sscanf (buf, "%s %s %s %x %d %d %d %s %d %d %d",
+		  iface, dest, gate, &flags, &refcnt, &use, &metric, 
+		  mask, &mtu, &window, &rtt);
+      if (n != 11)
+	{	
+	  zlog_warn ("can't read all of routing information\n");
+	  continue;
+	}
+      if (! (flags & RTF_UP))
+	continue;
+      if (! (flags & RTF_GATEWAY))
+	continue;
+
+      if (flags & RTF_DYNAMIC)
+	zebra_flags |= ZEBRA_FLAG_SELFROUTE;
+
+      p.family = AF_INET;
+      sscanf (dest, "%lX", (unsigned long *)&p.prefix);
+      sscanf (mask, "%lX", (unsigned long *)&tmpmask);
+      p.prefixlen = ip_masklen (tmpmask);
+      sscanf (gate, "%lX", (unsigned long *)&gateway);
+
+      rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gateway, 0, 0, 0, 0);
+    }
+
+  return 0;
+}
+
+#ifdef HAVE_IPV6
+int
+proc_ipv6_route_read ()
+{
+  FILE *fp;
+  char buf [RT_BUFSIZ];
+
+  /* Open /proc filesystem */
+  fp = fopen (_PATH_PROCNET_ROUTE6, "r");
+  if (fp == NULL)
+    {
+      zlog_warn ("Can't open %s : %s", _PATH_PROCNET_ROUTE6, 
+		strerror (errno));
+      return -1;
+    }
+  
+  /* There is no title line, so we don't drop first line.  */
+  while (fgets (buf, RT_BUFSIZ, fp) != NULL)
+    {
+      int n;
+      char dest[33], src[33], gate[33];
+      char iface[INTERFACE_NAMSIZ];
+      int dest_plen, src_plen;
+      int metric, use, refcnt, flags;
+      struct prefix_ipv6 p;
+      struct in6_addr gateway;
+      u_char zebra_flags = 0;
+
+      /* Linux 2.1.x write this information at net/ipv6/route.c
+         rt6_info_node () */
+      n = sscanf (buf, "%32s %02x %32s %02x %32s %08x %08x %08x %08x %s",
+		  dest, &dest_plen, src, &src_plen, gate,
+		  &metric, &use, &refcnt, &flags, iface);
+
+      if (n != 10)
+	{	
+	  /* zlog_warn ("can't read all of routing information %d\n%s\n", n, buf); */
+	  continue;
+	}
+
+      if (! (flags & RTF_UP))
+	continue;
+      if (! (flags & RTF_GATEWAY))
+	continue;
+
+      if (flags & RTF_DYNAMIC)
+	zebra_flags |= ZEBRA_FLAG_SELFROUTE;
+
+      p.family = AF_INET6;
+      str2in6_addr (dest, &p.prefix);
+      str2in6_addr (gate, &gateway);
+      p.prefixlen = dest_plen;
+
+      rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gateway, 0, 0);
+    }
+
+  return 0;
+}
+#endif /* HAVE_IPV6 */
+
+void
+route_read ()
+{
+  proc_route_read ();
+#ifdef HAVE_IPV6
+  proc_ipv6_route_read ();
+#endif /* HAVE_IPV6 */
+}
diff --git a/zebra/rtread_sysctl.c b/zebra/rtread_sysctl.c
new file mode 100644
index 0000000..970c0aa
--- /dev/null
+++ b/zebra/rtread_sysctl.c
@@ -0,0 +1,75 @@
+/*
+ * Kernel routing table read by sysctl function.
+ * Copyright (C) 1997, 98 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 "memory.h"
+#include "log.h"
+
+/* Kernel routing table read up by sysctl function. */
+int
+route_read ()
+{
+  caddr_t buf, end, ref;
+  size_t bufsiz;
+  struct rt_msghdr *rtm;
+  void rtm_read (struct rt_msghdr *);
+  
+#define MIBSIZ 6
+  int mib[MIBSIZ] = 
+  {
+    CTL_NET,
+    PF_ROUTE,
+    0,
+    0,
+    NET_RT_DUMP,
+    0
+  };
+		      
+  /* Get buffer size. */
+  if (sysctl (mib, MIBSIZ, NULL, &bufsiz, NULL, 0) < 0) 
+    {
+      zlog_warn ("sysctl fail: %s", strerror (errno));
+      return -1;
+    }
+
+  /* Allocate buffer. */
+  ref = buf = XMALLOC (MTYPE_TMP, bufsiz);
+  
+  /* Read routing table information by calling sysctl(). */
+  if (sysctl (mib, MIBSIZ, buf, &bufsiz, NULL, 0) < 0) 
+    {
+      zlog_warn ("sysctl() fail by %s", strerror (errno));
+      return -1;
+    }
+
+  for (end = buf + bufsiz; buf < end; buf += rtm->rtm_msglen) 
+    {
+      rtm = (struct rt_msghdr *) buf;
+      rtm_read (rtm);
+    }
+
+  /* Free buffer. */
+  XFREE (MTYPE_TMP, ref);
+
+  return 0;
+}
diff --git a/zebra/zebra.conf.sample b/zebra/zebra.conf.sample
new file mode 100644
index 0000000..a5d0732
--- /dev/null
+++ b/zebra/zebra.conf.sample
@@ -0,0 +1,25 @@
+! -*- zebra -*-
+!
+! zebra sample configuration file
+!
+! $Id: zebra.conf.sample,v 1.1 2002/12/13 20:15:30 paul Exp $
+!
+hostname Router
+password zebra
+enable password zebra
+!
+! Interface's description. 
+!
+!interface lo
+! description test of desc.
+!
+!interface sit0
+! multicast
+
+!
+! Static default route sample.
+!
+!ip route 0.0.0.0/0 203.181.89.241
+!
+
+!log file zebra.log
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
new file mode 100644
index 0000000..ec07e2e
--- /dev/null
+++ b/zebra/zebra_rib.c
@@ -0,0 +1,2199 @@
+/* Routing Information Base.
+ * Copyright (C) 1997, 98, 99, 2001 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 "table.h"
+#include "memory.h"
+#include "str.h"
+#include "command.h"
+#include "if.h"
+#include "log.h"
+#include "sockunion.h"
+
+#include "zebra/rib.h"
+#include "zebra/rt.h"
+#include "zebra/zserv.h"
+#include "zebra/redistribute.h"
+#include "zebra/debug.h"
+
+/* Default rtm_table for all clients */
+extern int rtm_table_default;
+
+/* Each route type's string and default distance value. */
+struct
+{  
+  int key;
+  int distance;
+} route_info[] =
+{
+  {ZEBRA_ROUTE_SYSTEM,    0},
+  {ZEBRA_ROUTE_KERNEL,    0},
+  {ZEBRA_ROUTE_CONNECT,   0},
+  {ZEBRA_ROUTE_STATIC,    1},
+  {ZEBRA_ROUTE_RIP,     120},
+  {ZEBRA_ROUTE_RIPNG,   120},
+  {ZEBRA_ROUTE_OSPF,    110},
+  {ZEBRA_ROUTE_OSPF6,   110},
+  {ZEBRA_ROUTE_BGP,      20  /* IBGP is 200. */}
+};
+
+/* Vector for routing table.  */
+vector vrf_vector;
+
+/* Allocate new VRF.  */
+struct vrf *
+vrf_alloc (char *name)
+{
+  struct vrf *vrf;
+
+  vrf = XCALLOC (MTYPE_VRF, sizeof (struct vrf));
+
+  /* Put name.  */
+  if (name)
+    vrf->name = XSTRDUP (MTYPE_VRF_NAME, name);
+
+  /* Allocate routing table and static table.  */
+  vrf->table[AFI_IP][SAFI_UNICAST] = route_table_init ();
+  vrf->table[AFI_IP6][SAFI_UNICAST] = route_table_init ();
+  vrf->stable[AFI_IP][SAFI_UNICAST] = route_table_init ();
+  vrf->stable[AFI_IP6][SAFI_UNICAST] = route_table_init ();
+
+  return vrf;
+}
+
+/* Free VRF.  */
+void
+vrf_free (struct vrf *vrf)
+{
+  if (vrf->name)
+    XFREE (MTYPE_VRF_NAME, vrf->name);
+  XFREE (MTYPE_VRF, vrf);
+}
+
+/* Lookup VRF by identifier.  */
+struct vrf *
+vrf_lookup (u_int32_t id)
+{
+  return vector_lookup (vrf_vector, id);
+}
+
+/* Lookup VRF by name.  */
+struct vrf *
+vrf_lookup_by_name (char *name)
+{
+  int i;
+  struct vrf *vrf;
+
+  for (i = 0; i < vector_max (vrf_vector); i++)
+    if ((vrf = vector_slot (vrf_vector, i)) != NULL)
+      if (vrf->name && name && strcmp (vrf->name, name) == 0)
+	return vrf;
+  return NULL;
+}
+
+/* Initialize VRF.  */
+void
+vrf_init ()
+{
+  struct vrf *default_table;
+
+  /* Allocate VRF vector.  */
+  vrf_vector = vector_init (1);
+
+  /* Allocate default main table.  */
+  default_table = vrf_alloc ("Default-IP-Routing-Table");
+
+  /* Default table index must be 0.  */
+  vector_set_index (vrf_vector, 0, default_table);
+}
+
+/* Lookup route table.  */
+struct route_table *
+vrf_table (afi_t afi, safi_t safi, u_int32_t id)
+{
+  struct vrf *vrf;
+
+  vrf = vrf_lookup (id);
+  if (! vrf)
+    return NULL;
+
+  return vrf->table[afi][safi];
+}
+
+/* Lookup static route table.  */
+struct route_table *
+vrf_static_table (afi_t afi, safi_t safi, u_int32_t id)
+{
+  struct vrf *vrf;
+
+  vrf = vrf_lookup (id);
+  if (! vrf)
+    return NULL;
+
+  return vrf->stable[afi][safi];
+}
+
+/* Add nexthop to the end of the list.  */
+void
+nexthop_add (struct rib *rib, struct nexthop *nexthop)
+{
+  struct nexthop *last;
+
+  for (last = rib->nexthop; last && last->next; last = last->next)
+    ;
+  if (last)
+    last->next = nexthop;
+  else
+    rib->nexthop = nexthop;
+  nexthop->prev = last;
+
+  rib->nexthop_num++;
+}
+
+/* Delete specified nexthop from the list. */
+void
+nexthop_delete (struct rib *rib, struct nexthop *nexthop)
+{
+  if (nexthop->next)
+    nexthop->next->prev = nexthop->prev;
+  if (nexthop->prev)
+    nexthop->prev->next = nexthop->next;
+  else
+    rib->nexthop = nexthop->next;
+  rib->nexthop_num--;
+}
+
+/* Free nexthop. */
+void
+nexthop_free (struct nexthop *nexthop)
+{
+  if (nexthop->type == NEXTHOP_TYPE_IFNAME && nexthop->ifname)
+    free (nexthop->ifname);
+  XFREE (MTYPE_NEXTHOP, nexthop);
+}
+
+struct nexthop *
+nexthop_ifindex_add (struct rib *rib, unsigned int ifindex)
+{
+  struct nexthop *nexthop;
+
+  nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+  memset (nexthop, 0, sizeof (struct nexthop));
+  nexthop->type = NEXTHOP_TYPE_IFINDEX;
+  nexthop->ifindex = ifindex;
+
+  nexthop_add (rib, nexthop);
+
+  return nexthop;
+}
+
+struct nexthop *
+nexthop_ifname_add (struct rib *rib, char *ifname)
+{
+  struct nexthop *nexthop;
+
+  nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+  memset (nexthop, 0, sizeof (struct nexthop));
+  nexthop->type = NEXTHOP_TYPE_IFNAME;
+  nexthop->ifname = strdup (ifname);
+
+  nexthop_add (rib, nexthop);
+
+  return nexthop;
+}
+
+struct nexthop *
+nexthop_ipv4_add (struct rib *rib, struct in_addr *ipv4)
+{
+  struct nexthop *nexthop;
+
+  nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+  memset (nexthop, 0, sizeof (struct nexthop));
+  nexthop->type = NEXTHOP_TYPE_IPV4;
+  nexthop->gate.ipv4 = *ipv4;
+
+  nexthop_add (rib, nexthop);
+
+  return nexthop;
+}
+
+struct nexthop *
+nexthop_ipv4_ifindex_add (struct rib *rib, struct in_addr *ipv4, 
+			  unsigned int ifindex)
+{
+  struct nexthop *nexthop;
+
+  nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+  memset (nexthop, 0, sizeof (struct nexthop));
+  nexthop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
+  nexthop->gate.ipv4 = *ipv4;
+  nexthop->ifindex = ifindex;
+
+  nexthop_add (rib, nexthop);
+
+  return nexthop;
+}
+
+#ifdef HAVE_IPV6
+struct nexthop *
+nexthop_ipv6_add (struct rib *rib, struct in6_addr *ipv6)
+{
+  struct nexthop *nexthop;
+
+  nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+  memset (nexthop, 0, sizeof (struct nexthop));
+  nexthop->type = NEXTHOP_TYPE_IPV6;
+  nexthop->gate.ipv6 = *ipv6;
+
+  nexthop_add (rib, nexthop);
+
+  return nexthop;
+}
+
+struct nexthop *
+nexthop_ipv6_ifname_add (struct rib *rib, struct in6_addr *ipv6,
+			 char *ifname)
+{
+  struct nexthop *nexthop;
+
+  nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+  memset (nexthop, 0, sizeof (struct nexthop));
+  nexthop->type = NEXTHOP_TYPE_IPV6_IFNAME;
+  nexthop->gate.ipv6 = *ipv6;
+  nexthop->ifname = XSTRDUP (0, ifname);
+
+  nexthop_add (rib, nexthop);
+
+  return nexthop;
+}
+
+struct nexthop *
+nexthop_ipv6_ifindex_add (struct rib *rib, struct in6_addr *ipv6,
+			  unsigned int ifindex)
+{
+  struct nexthop *nexthop;
+
+  nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+  memset (nexthop, 0, sizeof (struct nexthop));
+  nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
+  nexthop->gate.ipv6 = *ipv6;
+  nexthop->ifindex = ifindex;
+
+  nexthop_add (rib, nexthop);
+
+  return nexthop;
+}
+#endif /* HAVE_IPV6 */
+
+
+struct nexthop *
+nexthop_blackhole_add (struct rib *rib)
+{
+  struct nexthop *nexthop;
+
+  nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+  memset (nexthop, 0, sizeof (struct nexthop));
+  nexthop->type = NEXTHOP_TYPE_BLACKHOLE;
+  SET_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE);
+
+  nexthop_add (rib, nexthop);
+
+  return nexthop;
+}
+
+/* If force flag is not set, do not modify falgs at all for uninstall
+   the route from FIB. */
+int
+nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set,
+		     struct route_node *top)
+{
+  struct prefix_ipv4 p;
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *match;
+  struct nexthop *newhop;
+
+  if (nexthop->type == NEXTHOP_TYPE_IPV4)
+    nexthop->ifindex = 0;
+
+  if (set)
+    UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
+
+  /* Make lookup prefix. */
+  memset (&p, 0, sizeof (struct prefix_ipv4));
+  p.family = AF_INET;
+  p.prefixlen = IPV4_MAX_PREFIXLEN;
+  p.prefix = nexthop->gate.ipv4;
+
+  /* Lookup table.  */
+  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  if (! table)
+    return 0;
+
+  rn = route_node_match (table, (struct prefix *) &p);
+  while (rn)
+    {
+      route_unlock_node (rn);
+      
+      /* If lookup self prefix return immidiately. */
+      if (rn == top)
+	return 0;
+
+      /* Pick up selected route. */
+      for (match = rn->info; match; match = match->next)
+	if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
+	  break;
+
+      /* If there is no selected route or matched route is EGP, go up
+         tree. */
+      if (! match 
+	  || match->type == ZEBRA_ROUTE_BGP)
+	{
+	  do {
+	    rn = rn->parent;
+	  } while (rn && rn->info == NULL);
+	  if (rn)
+	    route_lock_node (rn);
+	}
+      else
+	{
+	  if (match->type == ZEBRA_ROUTE_CONNECT)
+	    {
+	      /* Directly point connected route. */
+	      newhop = match->nexthop;
+	      if (newhop && nexthop->type == NEXTHOP_TYPE_IPV4)
+		nexthop->ifindex = newhop->ifindex;
+	      
+	      return 1;
+	    }
+	  else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL))
+	    {
+	      for (newhop = match->nexthop; newhop; newhop = newhop->next)
+		if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)
+		    && ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE))
+		  {
+		    if (set)
+		      {
+			SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
+			nexthop->rtype = newhop->type;
+			if (newhop->type == NEXTHOP_TYPE_IPV4 ||
+			    newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
+			  nexthop->rgate.ipv4 = newhop->gate.ipv4;
+			if (newhop->type == NEXTHOP_TYPE_IFINDEX
+			    || newhop->type == NEXTHOP_TYPE_IFNAME
+			    || newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
+			  nexthop->rifindex = newhop->ifindex;
+		      }
+		    return 1;
+		  }
+	      return 0;
+	    }
+	  else
+	    {
+	      return 0;
+	    }
+	}
+    }
+  return 0;
+}
+
+#ifdef HAVE_IPV6
+/* If force flag is not set, do not modify falgs at all for uninstall
+   the route from FIB. */
+int
+nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set,
+		     struct route_node *top)
+{
+  struct prefix_ipv6 p;
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *match;
+  struct nexthop *newhop;
+
+  if (nexthop->type == NEXTHOP_TYPE_IPV6)
+    nexthop->ifindex = 0;
+
+  if (set)
+    UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
+
+  /* Make lookup prefix. */
+  memset (&p, 0, sizeof (struct prefix_ipv6));
+  p.family = AF_INET6;
+  p.prefixlen = IPV6_MAX_PREFIXLEN;
+  p.prefix = nexthop->gate.ipv6;
+
+  /* Lookup table.  */
+  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
+  if (! table)
+    return 0;
+
+  rn = route_node_match (table, (struct prefix *) &p);
+  while (rn)
+    {
+      route_unlock_node (rn);
+      
+      /* If lookup self prefix return immidiately. */
+      if (rn == top)
+	return 0;
+
+      /* Pick up selected route. */
+      for (match = rn->info; match; match = match->next)
+	if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
+	  break;
+
+      /* If there is no selected route or matched route is EGP, go up
+         tree. */
+      if (! match
+	  || match->type == ZEBRA_ROUTE_BGP)
+	{
+	  do {
+	    rn = rn->parent;
+	  } while (rn && rn->info == NULL);
+	  if (rn)
+	    route_lock_node (rn);
+	}
+      else
+	{
+	  if (match->type == ZEBRA_ROUTE_CONNECT)
+	    {
+	      /* Directly point connected route. */
+	      newhop = match->nexthop;
+
+	      if (newhop && nexthop->type == NEXTHOP_TYPE_IPV6)
+		nexthop->ifindex = newhop->ifindex;
+	      
+	      return 1;
+	    }
+	  else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL))
+	    {
+	      for (newhop = match->nexthop; newhop; newhop = newhop->next)
+		if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)
+		    && ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE))
+		  {
+		    if (set)
+		      {
+			SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
+			nexthop->rtype = newhop->type;
+			if (newhop->type == NEXTHOP_TYPE_IPV6
+			    || newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX
+			    || newhop->type == NEXTHOP_TYPE_IPV6_IFNAME)
+			  nexthop->rgate.ipv6 = newhop->gate.ipv6;
+			if (newhop->type == NEXTHOP_TYPE_IFINDEX
+			    || newhop->type == NEXTHOP_TYPE_IFNAME
+			    || newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX
+			    || newhop->type == NEXTHOP_TYPE_IPV6_IFNAME)
+			  nexthop->rifindex = newhop->ifindex;
+		      }
+		    return 1;
+		  }
+	      return 0;
+	    }
+	  else
+	    {
+	      return 0;
+	    }
+	}
+    }
+  return 0;
+}
+#endif /* HAVE_IPV6 */
+
+struct rib *
+rib_match_ipv4 (struct in_addr addr)
+{
+  struct prefix_ipv4 p;
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *match;
+  struct nexthop *newhop;
+
+  /* Lookup table.  */
+  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  if (! table)
+    return 0;
+
+  memset (&p, 0, sizeof (struct prefix_ipv4));
+  p.family = AF_INET;
+  p.prefixlen = IPV4_MAX_PREFIXLEN;
+  p.prefix = addr;
+
+  rn = route_node_match (table, (struct prefix *) &p);
+
+  while (rn)
+    {
+      route_unlock_node (rn);
+      
+      /* Pick up selected route. */
+      for (match = rn->info; match; match = match->next)
+	if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
+	  break;
+
+      /* If there is no selected route or matched route is EGP, go up
+         tree. */
+      if (! match 
+	  || match->type == ZEBRA_ROUTE_BGP)
+	{
+	  do {
+	    rn = rn->parent;
+	  } while (rn && rn->info == NULL);
+	  if (rn)
+	    route_lock_node (rn);
+	}
+      else
+	{
+	  if (match->type == ZEBRA_ROUTE_CONNECT)
+	    /* Directly point connected route. */
+	    return match;
+	  else
+	    {
+	      for (newhop = match->nexthop; newhop; newhop = newhop->next)
+		if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB))
+		  return match;
+	      return NULL;
+	    }
+	}
+    }
+  return NULL;
+}
+
+struct rib *
+rib_lookup_ipv4 (struct prefix_ipv4 *p)
+{
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *match;
+  struct nexthop *nexthop;
+
+  /* Lookup table.  */
+  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  if (! table)
+    return 0;
+
+  rn = route_node_lookup (table, (struct prefix *) p);
+
+  /* No route for this prefix. */
+  if (! rn)
+    return NULL;
+
+  /* Unlock node. */
+  route_unlock_node (rn);
+
+  /* Pick up selected route. */
+  for (match = rn->info; match; match = match->next)
+    if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
+      break;
+
+  if (! match || match->type == ZEBRA_ROUTE_BGP)
+    return NULL;
+
+  if (match->type == ZEBRA_ROUTE_CONNECT)
+    return match;
+  
+  for (nexthop = match->nexthop; nexthop; nexthop = nexthop->next)
+    if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
+      return match;
+
+  return NULL;
+}
+
+#ifdef HAVE_IPV6
+struct rib *
+rib_match_ipv6 (struct in6_addr *addr)
+{
+  struct prefix_ipv6 p;
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *match;
+  struct nexthop *newhop;
+
+  /* Lookup table.  */
+  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
+  if (! table)
+    return 0;
+
+  memset (&p, 0, sizeof (struct prefix_ipv6));
+  p.family = AF_INET6;
+  p.prefixlen = IPV6_MAX_PREFIXLEN;
+  IPV6_ADDR_COPY (&p.prefix, addr);
+
+  rn = route_node_match (table, (struct prefix *) &p);
+
+  while (rn)
+    {
+      route_unlock_node (rn);
+      
+      /* Pick up selected route. */
+      for (match = rn->info; match; match = match->next)
+	if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
+	  break;
+
+      /* If there is no selected route or matched route is EGP, go up
+         tree. */
+      if (! match 
+	  || match->type == ZEBRA_ROUTE_BGP)
+	{
+	  do {
+	    rn = rn->parent;
+	  } while (rn && rn->info == NULL);
+	  if (rn)
+	    route_lock_node (rn);
+	}
+      else
+	{
+	  if (match->type == ZEBRA_ROUTE_CONNECT)
+	    /* Directly point connected route. */
+	    return match;
+	  else
+	    {
+	      for (newhop = match->nexthop; newhop; newhop = newhop->next)
+		if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB))
+		  return match;
+	      return NULL;
+	    }
+	}
+    }
+  return NULL;
+}
+#endif /* HAVE_IPV6 */
+
+int
+nexthop_active_check (struct route_node *rn, struct rib *rib,
+		      struct nexthop *nexthop, int set)
+{
+  struct interface *ifp;
+
+  switch (nexthop->type)
+    {
+    case NEXTHOP_TYPE_IFINDEX:
+      ifp = if_lookup_by_index (nexthop->ifindex);
+      if (ifp && if_is_up (ifp))
+	SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+      else
+	UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+      break;
+    case NEXTHOP_TYPE_IFNAME:
+    case NEXTHOP_TYPE_IPV6_IFNAME:
+      ifp = if_lookup_by_name (nexthop->ifname);
+      if (ifp && if_is_up (ifp))
+	{
+	  if (set)
+	    nexthop->ifindex = ifp->ifindex;
+	  SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+	}
+      else
+	{
+	  if (set)
+	    nexthop->ifindex = 0;
+	  UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+	}
+      break;
+    case NEXTHOP_TYPE_IPV4:
+    case NEXTHOP_TYPE_IPV4_IFINDEX:
+      if (nexthop_active_ipv4 (rib, nexthop, set, rn))
+	SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+      else
+	UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+      break;
+#ifdef HAVE_IPV6
+    case NEXTHOP_TYPE_IPV6:
+      if (nexthop_active_ipv6 (rib, nexthop, set, rn))
+	SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+      else
+	UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+      break;
+    case NEXTHOP_TYPE_IPV6_IFINDEX:
+      if (IN6_IS_ADDR_LINKLOCAL (&nexthop->gate.ipv6))
+	{
+	  ifp = if_lookup_by_index (nexthop->ifindex);
+	  if (ifp && if_is_up (ifp))
+	    SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+	  else
+	    UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+	}
+      else
+	{
+	  if (nexthop_active_ipv6 (rib, nexthop, set, rn))
+	    SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+	  else
+	    UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+	}
+      break;
+#endif /* HAVE_IPV6 */
+    case NEXTHOP_TYPE_BLACKHOLE:
+      SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+      break;
+    default:
+      break;
+    }
+  return CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+}
+
+int
+nexthop_active_update (struct route_node *rn, struct rib *rib, int set)
+{
+  struct nexthop *nexthop;
+  int active;
+
+  rib->nexthop_active_num = 0;
+  UNSET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED);
+
+  for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+    {
+      active = CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+      rib->nexthop_active_num += nexthop_active_check (rn, rib, nexthop, set);
+      if (active != CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+	SET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED);
+    }
+  return rib->nexthop_active_num;
+}
+
+#define RIB_SYSTEM_ROUTE(R) \
+        ((R)->type == ZEBRA_ROUTE_KERNEL || (R)->type == ZEBRA_ROUTE_CONNECT)
+
+void
+newrib_free (struct rib *rib)
+{
+  struct nexthop *nexthop;
+  struct nexthop *next;
+
+  for (nexthop = rib->nexthop; nexthop; nexthop = next)
+    {
+      next = nexthop->next;
+      nexthop_free (nexthop);
+    }
+  XFREE (MTYPE_RIB, rib);
+}
+
+void
+rib_install_kernel (struct route_node *rn, struct rib *rib)
+{
+  int ret = 0;
+  struct nexthop *nexthop;
+
+  switch (PREFIX_FAMILY (&rn->p))
+    {
+    case AF_INET:
+      ret = kernel_add_ipv4 (&rn->p, rib);
+      break;
+#ifdef HAVE_IPV6
+    case AF_INET6:
+      ret = kernel_add_ipv6 (&rn->p, rib);
+      break;
+#endif /* HAVE_IPV6 */
+    }
+
+  if (ret < 0)
+    {
+      for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+	UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+    }
+}
+
+/* Uninstall the route from kernel. */
+int
+rib_uninstall_kernel (struct route_node *rn, struct rib *rib)
+{
+  int ret = 0;
+  struct nexthop *nexthop;
+
+  switch (PREFIX_FAMILY (&rn->p))
+    {
+    case AF_INET:
+      ret = kernel_delete_ipv4 (&rn->p, rib);
+      break;
+#ifdef HAVE_IPV6
+    case AF_INET6:
+      ret = kernel_delete_ipv6 (&rn->p, rib);
+      break;
+#endif /* HAVE_IPV6 */
+    }
+
+  for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+    UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+
+  return ret;
+}
+
+/* Uninstall the route from kernel. */
+void
+rib_uninstall (struct route_node *rn, struct rib *rib)
+{
+  if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+    {
+      redistribute_delete (&rn->p, rib);
+      if (! RIB_SYSTEM_ROUTE (rib))
+	rib_uninstall_kernel (rn, rib);
+      UNSET_FLAG (rib->flags, ZEBRA_FLAG_SELECTED);
+    }
+}
+
+/* Core function for processing routing information base. */
+void
+rib_process (struct route_node *rn, struct rib *del)
+{
+  struct rib *rib;
+  struct rib *next;
+  struct rib *fib = NULL;
+  struct rib *select = NULL;
+
+  for (rib = rn->info; rib; rib = next)
+    {
+      next = rib->next;
+
+      /* Currently installed rib. */
+      if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+	fib = rib;
+
+      /* Skip unreachable nexthop. */
+      if (! nexthop_active_update (rn, rib, 0))
+	continue;
+
+      /* Infinit distance. */
+      if (rib->distance == DISTANCE_INFINITY)
+	continue;
+
+      /* Newly selected rib. */
+      if (! select || rib->distance < select->distance 
+	  || rib->type == ZEBRA_ROUTE_CONNECT)
+	select = rib;
+    }
+
+  /* Deleted route check. */
+  if (del && CHECK_FLAG (del->flags, ZEBRA_FLAG_SELECTED))
+    fib = del;
+
+  /* Same route is selected. */
+  if (select && select == fib)
+    {
+      if (CHECK_FLAG (select->flags, ZEBRA_FLAG_CHANGED))
+	{
+	  redistribute_delete (&rn->p, select);
+	  if (! RIB_SYSTEM_ROUTE (select))
+	    rib_uninstall_kernel (rn, select);
+
+	  /* Set real nexthop. */
+	  nexthop_active_update (rn, select, 1);
+  
+	  if (! RIB_SYSTEM_ROUTE (select))
+	    rib_install_kernel (rn, select);
+	  redistribute_add (&rn->p, select);
+	}
+      return;
+    }
+
+  /* Uninstall old rib from forwarding table. */
+  if (fib)
+    {
+      redistribute_delete (&rn->p, fib);
+      if (! RIB_SYSTEM_ROUTE (fib))
+	rib_uninstall_kernel (rn, fib);
+      UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED);
+
+      /* Set real nexthop. */
+      nexthop_active_update (rn, fib, 1);
+    }
+
+  /* Install new rib into forwarding table. */
+  if (select)
+    {
+      /* Set real nexthop. */
+      nexthop_active_update (rn, select, 1);
+
+      if (! RIB_SYSTEM_ROUTE (select))
+	rib_install_kernel (rn, select);
+      SET_FLAG (select->flags, ZEBRA_FLAG_SELECTED);
+      redistribute_add (&rn->p, select);
+    }
+}
+
+/* Add RIB to head of the route node. */
+void
+rib_addnode (struct route_node *rn, struct rib *rib)
+{
+  struct rib *head;
+
+  head = rn->info;
+  if (head)
+    head->prev = rib;
+  rib->next = head;
+  rn->info = rib;
+}
+
+void
+rib_delnode (struct route_node *rn, struct rib *rib)
+{
+  if (rib->next)
+    rib->next->prev = rib->prev;
+  if (rib->prev)
+    rib->prev->next = rib->next;
+  else
+    rn->info = rib->next;
+}
+
+int
+rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, 
+	      struct in_addr *gate, unsigned int ifindex, u_int32_t vrf_id,
+	      u_int32_t metric, u_char distance)
+{
+  struct rib *rib;
+  struct rib *same = NULL;
+  struct route_table *table;
+  struct route_node *rn;
+  struct nexthop *nexthop;
+
+  /* Lookup table.  */
+  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  if (! table)
+    return 0;
+
+  /* Make it sure prefixlen is applied to the prefix. */
+  apply_mask_ipv4 (p);
+
+  /* Set default distance by route type. */
+  if (distance == 0)
+    {
+      distance = route_info[type].distance;
+
+      /* iBGP distance is 200. */
+      if (type == ZEBRA_ROUTE_BGP && CHECK_FLAG (flags, ZEBRA_FLAG_IBGP))
+	distance = 200;
+    }
+
+  /* Lookup route node.*/
+  rn = route_node_get (table, (struct prefix *) p);
+
+  /* If same type of route are installed, treat it as a implicit
+     withdraw. */
+  for (rib = rn->info; rib; rib = rib->next)
+    {
+      if (rib->type == ZEBRA_ROUTE_CONNECT)
+	{
+	  nexthop = rib->nexthop;
+
+	  /* Duplicate connected route comes in. */
+	  if (rib->type == type
+	      && nexthop && nexthop->type == NEXTHOP_TYPE_IFINDEX
+	      && nexthop->ifindex == ifindex)
+	    {
+	      rib->refcnt++;
+	      return 0 ;
+	    }
+	}
+      else if (rib->type == type)
+	{
+	  same = rib;
+	  rib_delnode (rn, same);
+	  route_unlock_node (rn);
+	  break;
+	}
+    }
+
+  /* Allocate new rib structure. */
+  rib = XMALLOC (MTYPE_RIB, sizeof (struct rib));
+  memset (rib, 0, sizeof (struct rib));
+  rib->type = type;
+  rib->distance = distance;
+  rib->flags = flags;
+  rib->metric = metric;
+  rib->nexthop_num = 0;
+  rib->uptime = time (NULL);
+
+  /* Nexthop settings. */
+  if (gate)
+    {
+      if (ifindex)
+	nexthop_ipv4_ifindex_add (rib, gate, ifindex);
+      else
+	nexthop_ipv4_add (rib, gate);
+    }
+  else
+    nexthop_ifindex_add (rib, ifindex);
+
+  /* If this route is kernel route, set FIB flag to the route. */
+  if (type == ZEBRA_ROUTE_KERNEL || type == ZEBRA_ROUTE_CONNECT)
+    for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+      SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+
+  /* Link new rib to node.*/
+  rib_addnode (rn, rib);
+
+  /* Process this route node. */
+  rib_process (rn, same);
+
+  /* Free implicit route.*/
+  if (same)
+    newrib_free (same);
+
+  return 0;
+}
+
+int
+rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib)
+{
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *same;
+  struct nexthop *nexthop;
+
+  /* Lookup table.  */
+  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  if (! table)
+    return 0;
+
+  /* Make it sure prefixlen is applied to the prefix. */
+  apply_mask_ipv4 (p);
+
+  /* Set default distance by route type. */
+  if (rib->distance == 0)
+    {
+      rib->distance = route_info[rib->type].distance;
+
+      /* iBGP distance is 200. */
+      if (rib->type == ZEBRA_ROUTE_BGP 
+	  && CHECK_FLAG (rib->flags, ZEBRA_FLAG_IBGP))
+	rib->distance = 200;
+    }
+
+  /* Lookup route node.*/
+  rn = route_node_get (table, (struct prefix *) p);
+
+  /* If same type of route are installed, treat it as a implicit
+     withdraw. */
+  for (same = rn->info; same; same = same->next)
+    {
+      if (same->type == rib->type && same->table == rib->table
+	  && same->type != ZEBRA_ROUTE_CONNECT)
+	{
+	  rib_delnode (rn, same);
+	  route_unlock_node (rn);
+	  break;
+	}
+    }
+
+  /* If this route is kernel route, set FIB flag to the route. */
+  if (rib->type == ZEBRA_ROUTE_KERNEL || rib->type == ZEBRA_ROUTE_CONNECT)
+    for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+      SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+
+  /* Link new rib to node.*/
+  rib_addnode (rn, rib);
+
+  /* Process this route node. */
+  rib_process (rn, same);
+
+  /* Free implicit route.*/
+  if (same)
+    newrib_free (same);
+
+  return 0;
+}
+
+int
+rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p,
+		 struct in_addr *gate, unsigned int ifindex, u_int32_t vrf_id)
+{
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *rib;
+  struct rib *fib = NULL;
+  struct rib *same = NULL;
+  struct nexthop *nexthop;
+  char buf1[BUFSIZ];
+  char buf2[BUFSIZ];
+
+  /* Lookup table.  */
+  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  if (! table)
+    return 0;
+
+  /* Apply mask. */
+  apply_mask_ipv4 (p);
+
+  /* Lookup route node. */
+  rn = route_node_lookup (table, (struct prefix *) p);
+  if (! rn)
+    {
+      if (IS_ZEBRA_DEBUG_KERNEL)
+	{
+	  if (gate)
+	    zlog_info ("route %s/%d via %s ifindex %d doesn't exist in rib",
+		       inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ),
+		       p->prefixlen,
+		       inet_ntop (AF_INET, gate, buf2, BUFSIZ),
+		       ifindex);
+	  else
+	    zlog_info ("route %s/%d ifindex %d doesn't exist in rib",
+		       inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ),
+		       p->prefixlen,
+		       ifindex);
+	}
+      return ZEBRA_ERR_RTNOEXIST;
+    }
+
+  /* Lookup same type route. */
+  for (rib = rn->info; rib; rib = rib->next)
+    {
+      if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+	fib = rib;
+
+      if (rib->type == ZEBRA_ROUTE_CONNECT)
+	{
+	  nexthop = rib->nexthop;
+
+	  if (rib->type == type
+	      && nexthop && nexthop->type == NEXTHOP_TYPE_IFINDEX
+	      && nexthop->ifindex == ifindex)
+	    {
+	      if (rib->refcnt)
+		{
+		  rib->refcnt--;
+		  route_unlock_node (rn);
+		  route_unlock_node (rn);
+		  return 0;
+		}
+	      same = rib;
+	      break;
+	    }
+	}
+      else
+	{
+	  if (rib->type == type)
+	    {
+	      same = rib;
+	      break;
+	    }
+	}
+    }
+
+  /* If same type of route can't be found and this message is from
+     kernel. */
+  if (! same)
+    {
+      if (fib && type == ZEBRA_ROUTE_KERNEL)
+	{
+	  /* Unset flags. */
+	  for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next)
+	    UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+
+	  UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED);
+	}
+      else
+	{
+	  if (IS_ZEBRA_DEBUG_KERNEL)
+	    {
+	      if (gate)
+		zlog_info ("route %s/%d via %s ifindex %d type %d doesn't exist in rib",
+			   inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ),
+			   p->prefixlen,
+			   inet_ntop (AF_INET, gate, buf2, BUFSIZ),
+			   ifindex,
+			   type);
+	      else
+		zlog_info ("route %s/%d ifindex %d type %d doesn't exist in rib",
+			   inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ),
+			   p->prefixlen,
+			   ifindex,
+			   type);
+	    }
+	  route_unlock_node (rn);
+	  return ZEBRA_ERR_RTNOEXIST;
+	}
+    }
+
+  if (same)
+    rib_delnode (rn, same);
+
+  /* Process changes. */
+  rib_process (rn, same);
+
+  if (same)
+    {
+      newrib_free (same);
+      route_unlock_node (rn);
+    }
+
+  route_unlock_node (rn);
+
+  return 0;
+}
+
+/* Install static route into rib. */
+void
+static_install_ipv4 (struct prefix *p, struct static_ipv4 *si)
+{
+  struct rib *rib;
+  struct route_node *rn;
+  struct route_table *table;
+
+  /* Lookup table.  */
+  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  if (! table)
+    return;
+
+  /* Lookup existing route */
+  rn = route_node_get (table, p);
+  for (rib = rn->info; rib; rib = rib->next)
+    if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance)
+      break;
+
+  if (rib)
+    {
+      /* Same distance static route is there.  Update it with new
+         nexthop. */
+      rib_uninstall (rn, rib);
+      route_unlock_node (rn);
+
+      switch (si->type)
+	{
+	case STATIC_IPV4_GATEWAY:
+	  nexthop_ipv4_add (rib, &si->gate.ipv4);
+	  break;
+	case STATIC_IPV4_IFNAME:
+	  nexthop_ifname_add (rib, si->gate.ifname);
+	  break;
+	case STATIC_IPV4_BLACKHOLE:
+	  nexthop_blackhole_add (rib);
+	  break;
+	}
+      rib_process (rn, NULL);
+    }
+  else
+    {
+      /* This is new static route. */
+      rib = XMALLOC (MTYPE_RIB, sizeof (struct rib));
+      memset (rib, 0, sizeof (struct rib));
+
+      rib->type = ZEBRA_ROUTE_STATIC;
+      rib->distance = si->distance;
+      rib->metric = 0;
+      rib->nexthop_num = 0;
+
+      switch (si->type)
+	{
+	case STATIC_IPV4_GATEWAY:
+	  nexthop_ipv4_add (rib, &si->gate.ipv4);
+	  break;
+	case STATIC_IPV4_IFNAME:
+	  nexthop_ifname_add (rib, si->gate.ifname);
+	  break;
+	case STATIC_IPV4_BLACKHOLE:
+	  nexthop_blackhole_add (rib);
+	  break;
+	}
+
+      /* Link this rib to the tree. */
+      rib_addnode (rn, rib);
+
+      /* Process this prefix. */
+      rib_process (rn, NULL);
+    }
+}
+
+int
+static_ipv4_nexthop_same (struct nexthop *nexthop, struct static_ipv4 *si)
+{
+  if (nexthop->type == NEXTHOP_TYPE_IPV4
+      && si->type == STATIC_IPV4_GATEWAY
+      && IPV4_ADDR_SAME (&nexthop->gate.ipv4, &si->gate.ipv4))
+    return 1;
+  if (nexthop->type == NEXTHOP_TYPE_IFNAME
+      && si->type == STATIC_IPV4_IFNAME
+      && strcmp (nexthop->ifname, si->gate.ifname) == 0)
+    return 1;
+  if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE
+      && si->type == STATIC_IPV4_BLACKHOLE)
+    return 1;
+  return 0;;
+}
+
+/* Uninstall static route from RIB. */
+void
+static_uninstall_ipv4 (struct prefix *p, struct static_ipv4 *si)
+{
+  struct route_node *rn;
+  struct rib *rib;
+  struct nexthop *nexthop;
+  struct route_table *table;
+
+  /* Lookup table.  */
+  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  if (! table)
+    return;
+
+  /* Lookup existing route with type and distance. */
+  rn = route_node_lookup (table, p);
+  if (! rn)
+    return;
+
+  for (rib = rn->info; rib; rib = rib->next)
+    if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance)
+      break;
+
+  if (! rib)
+    {
+      route_unlock_node (rn);
+      return;
+    }
+
+  /* Lookup nexthop. */
+  for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+    if (static_ipv4_nexthop_same (nexthop, si))
+      break;
+
+  /* Can't find nexthop. */
+  if (! nexthop)
+    {
+      route_unlock_node (rn);
+      return;
+    }
+  
+  /* Check nexthop. */
+  if (rib->nexthop_num == 1)
+    {
+      rib_delnode (rn, rib);
+      rib_process (rn, rib);
+      newrib_free (rib);
+      route_unlock_node (rn);
+    }
+  else
+    {
+      rib_uninstall (rn, rib);
+      nexthop_delete (rib, nexthop);
+      nexthop_free (nexthop);
+      rib_process (rn, rib);
+    }
+
+  /* Unlock node. */
+  route_unlock_node (rn);
+}
+
+/* Add static route into static route configuration. */
+int
+static_add_ipv4 (struct prefix *p, struct in_addr *gate, char *ifname,
+		 u_char distance, u_int32_t vrf_id)
+{
+  u_char type = 0;
+  struct route_node *rn;
+  struct static_ipv4 *si;
+  struct static_ipv4 *pp;
+  struct static_ipv4 *cp;
+  struct static_ipv4 *update = NULL;
+  struct route_table *stable;
+
+  /* Lookup table.  */
+  stable = vrf_static_table (AFI_IP, SAFI_UNICAST, vrf_id);
+  if (! stable)
+    return -1;
+  
+  /* Lookup static route prefix. */
+  rn = route_node_get (stable, p);
+
+  /* Make flags. */
+  if (gate)
+    type = STATIC_IPV4_GATEWAY;
+  else if (ifname)
+    type = STATIC_IPV4_IFNAME;
+  else
+    type = STATIC_IPV4_BLACKHOLE;
+
+  /* Do nothing if there is a same static route.  */
+  for (si = rn->info; si; si = si->next)
+    {
+      if (type == si->type
+	  && (! gate || IPV4_ADDR_SAME (gate, &si->gate.ipv4))
+	  && (! ifname || strcmp (ifname, si->gate.ifname) == 0))
+	{
+	  if (distance == si->distance)
+	    {
+	      route_unlock_node (rn);
+	      return 0;
+	    }
+	  else
+	    update = si;
+	}
+    }
+
+  /* Distance chaged.  */
+  if (update)
+    static_delete_ipv4 (p, gate, ifname, update->distance, vrf_id);
+
+  /* Make new static route structure. */
+  si = XMALLOC (MTYPE_STATIC_IPV4, sizeof (struct static_ipv4));
+  memset (si, 0, sizeof (struct static_ipv4));
+
+  si->type = type;
+  si->distance = distance;
+
+  if (gate)
+    si->gate.ipv4 = *gate;
+  if (ifname)
+    si->gate.ifname = XSTRDUP (0, ifname);
+
+  /* Add new static route information to the tree with sort by
+     distance value and gateway address. */
+  for (pp = NULL, cp = rn->info; cp; pp = cp, cp = cp->next)
+    {
+      if (si->distance < cp->distance)
+	break;
+      if (si->distance > cp->distance)
+	continue;
+      if (si->type == STATIC_IPV4_GATEWAY && cp->type == STATIC_IPV4_GATEWAY)
+	{
+	  if (ntohl (si->gate.ipv4.s_addr) < ntohl (cp->gate.ipv4.s_addr))
+	    break;
+	  if (ntohl (si->gate.ipv4.s_addr) > ntohl (cp->gate.ipv4.s_addr))
+	    continue;
+	}
+    }
+
+  /* Make linked list. */
+  if (pp)
+    pp->next = si;
+  else
+    rn->info = si;
+  if (cp)
+    cp->prev = si;
+  si->prev = pp;
+  si->next = cp;
+
+  /* Install into rib. */
+  static_install_ipv4 (p, si);
+
+  return 1;
+}
+
+/* Delete static route from static route configuration. */
+int
+static_delete_ipv4 (struct prefix *p, struct in_addr *gate, char *ifname,
+		    u_char distance, u_int32_t vrf_id)
+{
+  u_char type = 0;
+  struct route_node *rn;
+  struct static_ipv4 *si;
+  struct route_table *stable;
+
+  /* Lookup table.  */
+  stable = vrf_static_table (AFI_IP, SAFI_UNICAST, vrf_id);
+  if (! stable)
+    return -1;
+
+  /* Lookup static route prefix. */
+  rn = route_node_lookup (stable, p);
+  if (! rn)
+    return 0;
+
+  /* Make flags. */
+  if (gate)
+    type = STATIC_IPV4_GATEWAY;
+  else if (ifname)
+    type = STATIC_IPV4_IFNAME;
+  else
+    type = STATIC_IPV4_BLACKHOLE;
+
+  /* Find same static route is the tree */
+  for (si = rn->info; si; si = si->next)
+    if (type == si->type
+	&& (! gate || IPV4_ADDR_SAME (gate, &si->gate.ipv4))
+	&& (! ifname || strcmp (ifname, si->gate.ifname) == 0))
+      break;
+
+  /* Can't find static route. */
+  if (! si)
+    {
+      route_unlock_node (rn);
+      return 0;
+    }
+
+  /* Install into rib. */
+  static_uninstall_ipv4 (p, si);
+
+  /* Unlink static route from linked list. */
+  if (si->prev)
+    si->prev->next = si->next;
+  else
+    rn->info = si->next;
+  if (si->next)
+    si->next->prev = si->prev;
+  
+  /* Free static route configuration. */
+  XFREE (MTYPE_STATIC_IPV4, si);
+
+  return 1;
+}
+
+
+#ifdef HAVE_IPV6
+int
+rib_bogus_ipv6 (int type, struct prefix_ipv6 *p,
+		struct in6_addr *gate, unsigned int ifindex, int table)
+{
+  if (type == ZEBRA_ROUTE_CONNECT && IN6_IS_ADDR_UNSPECIFIED (&p->prefix))
+    return 1;
+  if (type == ZEBRA_ROUTE_KERNEL && IN6_IS_ADDR_UNSPECIFIED (&p->prefix)
+      && p->prefixlen == 96 && gate && IN6_IS_ADDR_UNSPECIFIED (gate))
+    {
+      kernel_delete_ipv6_old (p, gate, ifindex, 0, table);
+      return 1;
+    }
+  return 0;
+}
+
+int
+rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p,
+	      struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id)
+{
+  struct rib *rib;
+  struct rib *same = NULL;
+  struct route_table *table;
+  struct route_node *rn;
+  struct nexthop *nexthop;
+
+  int distance;
+  u_int32_t metric = 0;
+
+  /* Lookup table.  */
+  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
+  if (! table)
+    return 0;
+
+  /* Make sure mask is applied. */
+  apply_mask_ipv6 (p);
+
+  /* Set default distance by route type. */
+  distance = route_info[type].distance;
+  
+  if (type == ZEBRA_ROUTE_BGP && CHECK_FLAG (flags, ZEBRA_FLAG_IBGP))
+    distance = 200;
+
+  /* Filter bogus route. */
+  if (rib_bogus_ipv6 (type, p, gate, ifindex, 0))
+    return 0;
+
+  /* Lookup route node.*/
+  rn = route_node_get (table, (struct prefix *) p);
+
+  /* If same type of route are installed, treat it as a implicit
+     withdraw. */
+  for (rib = rn->info; rib; rib = rib->next)
+    {
+      if (rib->type == ZEBRA_ROUTE_CONNECT)
+	{
+	  nexthop = rib->nexthop;
+
+	  if (rib->type == type
+	      && nexthop && nexthop->type == NEXTHOP_TYPE_IFINDEX
+	      && nexthop->ifindex == ifindex)
+	  {
+	    rib->refcnt++;
+	    return 0;
+	  }
+	}
+      else if (rib->type == type)
+	{
+	  same = rib;
+	  rib_delnode (rn, same);
+	  route_unlock_node (rn);
+	  break;
+	}
+    }
+
+  /* Allocate new rib structure. */
+  rib = XMALLOC (MTYPE_RIB, sizeof (struct rib));
+  memset (rib, 0, sizeof (struct rib));
+  rib->type = type;
+  rib->distance = distance;
+  rib->flags = flags;
+  rib->metric = metric;
+  rib->nexthop_num = 0;
+  rib->uptime = time (NULL);
+
+  /* Nexthop settings. */
+  if (gate)
+    {
+      if (ifindex)
+	nexthop_ipv6_ifindex_add (rib, gate, ifindex);
+      else
+	nexthop_ipv6_add (rib, gate);
+    }
+  else
+    nexthop_ifindex_add (rib, ifindex);
+
+  /* If this route is kernel route, set FIB flag to the route. */
+  if (type == ZEBRA_ROUTE_KERNEL || type == ZEBRA_ROUTE_CONNECT)
+    for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+      SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+
+  /* Link new rib to node.*/
+  rib_addnode (rn, rib);
+
+  /* Process this route node. */
+  rib_process (rn, same);
+
+  /* Free implicit route.*/
+  if (same)
+    newrib_free (same);
+
+  return 0;
+}
+
+int
+rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p,
+		 struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id)
+{
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *rib;
+  struct rib *fib = NULL;
+  struct rib *same = NULL;
+  struct nexthop *nexthop;
+  char buf1[BUFSIZ];
+  char buf2[BUFSIZ];
+
+  /* Apply mask. */
+  apply_mask_ipv6 (p);
+
+  /* Lookup table.  */
+  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
+  if (! table)
+    return 0;
+
+  /* Lookup route node. */
+  rn = route_node_lookup (table, (struct prefix *) p);
+  if (! rn)
+    {
+      if (IS_ZEBRA_DEBUG_KERNEL)
+	{
+	  if (gate)
+	    zlog_info ("route %s/%d via %s ifindex %d doesn't exist in rib",
+		       inet_ntop (AF_INET6, &p->prefix, buf1, BUFSIZ),
+		       p->prefixlen,
+		       inet_ntop (AF_INET6, gate, buf2, BUFSIZ),
+		       ifindex);
+	  else
+	    zlog_info ("route %s/%d ifindex %d doesn't exist in rib",
+		       inet_ntop (AF_INET6, &p->prefix, buf1, BUFSIZ),
+		       p->prefixlen,
+		       ifindex);
+	}
+      return ZEBRA_ERR_RTNOEXIST;
+    }
+
+  /* Lookup same type route. */
+  for (rib = rn->info; rib; rib = rib->next)
+    {
+      if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+	fib = rib;
+
+      if (rib->type == ZEBRA_ROUTE_CONNECT)
+	{
+	  nexthop = rib->nexthop;
+
+	  if (rib->type == type
+	      && nexthop && nexthop->type == NEXTHOP_TYPE_IFINDEX
+	      && nexthop->ifindex == ifindex)
+	    {
+	      if (rib->refcnt)
+		{
+		  rib->refcnt--;
+		  route_unlock_node (rn);
+		  route_unlock_node (rn);
+		  return 0;
+		}
+	      same = rib;
+	      break;
+	    }
+	}
+      else
+	{
+	  if (rib->type == type)
+	    {
+	      same = rib;
+	      break;
+	    }
+	}
+    }
+
+  /* If same type of route can't be found and this message is from
+     kernel. */
+  if (! same)
+    {
+      if (fib && type == ZEBRA_ROUTE_KERNEL)
+	{
+	  /* Unset flags. */
+	  for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next)
+	    UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+
+	  UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED);
+	}
+      else
+	{
+	  if (IS_ZEBRA_DEBUG_KERNEL)
+	    {
+	      if (gate)
+		zlog_info ("route %s/%d via %s ifindex %d type %d doesn't exist in rib",
+			   inet_ntop (AF_INET6, &p->prefix, buf1, BUFSIZ),
+			   p->prefixlen,
+			   inet_ntop (AF_INET6, gate, buf2, BUFSIZ),
+			   ifindex,
+			   type);
+	      else
+		zlog_info ("route %s/%d ifindex %d type %d doesn't exist in rib",
+			   inet_ntop (AF_INET6, &p->prefix, buf1, BUFSIZ),
+			   p->prefixlen,
+			   ifindex,
+			   type);
+	    }
+	  route_unlock_node (rn);
+	  return ZEBRA_ERR_RTNOEXIST;
+	}
+    }
+
+  if (same)
+    rib_delnode (rn, same);
+
+  /* Process changes. */
+  rib_process (rn, same);
+
+  if (same)
+    {
+      newrib_free (same);
+      route_unlock_node (rn);
+    }
+
+  route_unlock_node (rn);
+
+  return 0;
+}
+
+/* Install static route into rib. */
+void
+static_install_ipv6 (struct prefix *p, struct static_ipv6 *si)
+{
+  struct rib *rib;
+  struct route_table *table;
+  struct route_node *rn;
+
+  /* Lookup table.  */
+  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
+  if (! table)
+    return;
+
+  /* Lookup existing route */
+  rn = route_node_get (table, p);
+  for (rib = rn->info; rib; rib = rib->next)
+    if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance)
+      break;
+
+  if (rib)
+    {
+      /* Same distance static route is there.  Update it with new
+         nexthop. */
+      rib_uninstall (rn, rib);
+      route_unlock_node (rn);
+
+      switch (si->type)
+	{
+	case STATIC_IPV6_GATEWAY:
+	  nexthop_ipv6_add (rib, &si->ipv6);
+	  break;
+	case STATIC_IPV6_IFNAME:
+	  nexthop_ifname_add (rib, si->ifname);
+	  break;
+	case STATIC_IPV6_GATEWAY_IFNAME:
+	  nexthop_ipv6_ifname_add (rib, &si->ipv6, si->ifname);
+	  break;
+	}
+      rib_process (rn, NULL);
+    }
+  else
+    {
+      /* This is new static route. */
+      rib = XMALLOC (MTYPE_RIB, sizeof (struct rib));
+      memset (rib, 0, sizeof (struct rib));
+
+      rib->type = ZEBRA_ROUTE_STATIC;
+      rib->distance = si->distance;
+      rib->metric = 0;
+      rib->nexthop_num = 0;
+
+      switch (si->type)
+	{
+	case STATIC_IPV6_GATEWAY:
+	  nexthop_ipv6_add (rib, &si->ipv6);
+	  break;
+	case STATIC_IPV6_IFNAME:
+	  nexthop_ifname_add (rib, si->ifname);
+	  break;
+	case STATIC_IPV6_GATEWAY_IFNAME:
+	  nexthop_ipv6_ifname_add (rib, &si->ipv6, si->ifname);
+	  break;
+	}
+
+      /* Link this rib to the tree. */
+      rib_addnode (rn, rib);
+
+      /* Process this prefix. */
+      rib_process (rn, NULL);
+    }
+}
+
+int
+static_ipv6_nexthop_same (struct nexthop *nexthop, struct static_ipv6 *si)
+{
+  if (nexthop->type == NEXTHOP_TYPE_IPV6
+      && si->type == STATIC_IPV6_GATEWAY
+      && IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->ipv6))
+    return 1;
+  if (nexthop->type == NEXTHOP_TYPE_IFNAME
+      && si->type == STATIC_IPV6_IFNAME
+      && strcmp (nexthop->ifname, si->ifname) == 0)
+    return 1;
+  if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
+      && si->type == STATIC_IPV6_GATEWAY_IFNAME
+      && IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->ipv6)
+      && strcmp (nexthop->ifname, si->ifname) == 0)
+    return 1;
+  return 0;;
+}
+
+void
+static_uninstall_ipv6 (struct prefix *p, struct static_ipv6 *si)
+{
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *rib;
+  struct nexthop *nexthop;
+
+  /* Lookup table.  */
+  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
+  if (! table)
+    return;
+
+  /* Lookup existing route with type and distance. */
+  rn = route_node_lookup (table, (struct prefix *) p);
+  if (! rn)
+    return;
+
+  for (rib = rn->info; rib; rib = rib->next)
+    if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance)
+      break;
+  if (! rib)
+    {
+      route_unlock_node (rn);
+      return;
+    }
+
+  /* Lookup nexthop. */
+  for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+    if (static_ipv6_nexthop_same (nexthop, si))
+      break;
+
+  /* Can't find nexthop. */
+  if (! nexthop)
+    {
+      route_unlock_node (rn);
+      return;
+    }
+  
+  /* Check nexthop. */
+  if (rib->nexthop_num == 1)
+    {
+      rib_delnode (rn, rib);
+      rib_process (rn, rib);
+      newrib_free (rib);
+      route_unlock_node (rn);
+    }
+  else
+    {
+      rib_uninstall (rn, rib);
+      nexthop_delete (rib, nexthop);
+      nexthop_free (nexthop);
+      rib_process (rn, rib);
+    }
+
+  /* Unlock node. */
+  route_unlock_node (rn);
+}
+
+/* Add static route into static route configuration. */
+int
+static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
+		 char *ifname, u_char distance, u_int32_t vrf_id)
+{
+  struct route_node *rn;
+  struct static_ipv6 *si;
+  struct static_ipv6 *pp;
+  struct static_ipv6 *cp;
+  struct route_table *stable;
+
+  /* Lookup table.  */
+  stable = vrf_static_table (AFI_IP6, SAFI_UNICAST, vrf_id);
+  if (! stable)
+    return -1;
+
+  /* Lookup static route prefix. */
+  rn = route_node_get (stable, p);
+
+  /* Do nothing if there is a same static route.  */
+  for (si = rn->info; si; si = si->next)
+    {
+      if (distance == si->distance 
+	  && type == si->type
+	  && (! gate || IPV6_ADDR_SAME (gate, &si->ipv6))
+	  && (! ifname || strcmp (ifname, si->ifname) == 0))
+	{
+	  route_unlock_node (rn);
+	  return 0;
+	}
+    }
+
+  /* Make new static route structure. */
+  si = XMALLOC (MTYPE_STATIC_IPV6, sizeof (struct static_ipv6));
+  memset (si, 0, sizeof (struct static_ipv6));
+
+  si->type = type;
+  si->distance = distance;
+
+  switch (type)
+    {
+    case STATIC_IPV6_GATEWAY:
+      si->ipv6 = *gate;
+      break;
+    case STATIC_IPV6_IFNAME:
+      si->ifname = XSTRDUP (0, ifname);
+      break;
+    case STATIC_IPV6_GATEWAY_IFNAME:
+      si->ipv6 = *gate;
+      si->ifname = XSTRDUP (0, ifname);
+      break;
+    }
+
+  /* Add new static route information to the tree with sort by
+     distance value and gateway address. */
+  for (pp = NULL, cp = rn->info; cp; pp = cp, cp = cp->next)
+    {
+      if (si->distance < cp->distance)
+	break;
+      if (si->distance > cp->distance)
+	continue;
+    }
+
+  /* Make linked list. */
+  if (pp)
+    pp->next = si;
+  else
+    rn->info = si;
+  if (cp)
+    cp->prev = si;
+  si->prev = pp;
+  si->next = cp;
+
+  /* Install into rib. */
+  static_install_ipv6 (p, si);
+
+  return 1;
+}
+
+/* Delete static route from static route configuration. */
+int
+static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
+		    char *ifname, u_char distance, u_int32_t vrf_id)
+{
+  struct route_node *rn;
+  struct static_ipv6 *si;
+  struct route_table *stable;
+
+  /* Lookup table.  */
+  stable = vrf_static_table (AFI_IP6, SAFI_UNICAST, vrf_id);
+  if (! stable)
+    return -1;
+
+  /* Lookup static route prefix. */
+  rn = route_node_lookup (stable, p);
+  if (! rn)
+    return 0;
+
+  /* Find same static route is the tree */
+  for (si = rn->info; si; si = si->next)
+    if (distance == si->distance 
+	&& type == si->type
+	&& (! gate || IPV6_ADDR_SAME (gate, &si->ipv6))
+	&& (! ifname || strcmp (ifname, si->ifname) == 0))
+      break;
+
+  /* Can't find static route. */
+  if (! si)
+    {
+      route_unlock_node (rn);
+      return 0;
+    }
+
+  /* Install into rib. */
+  static_uninstall_ipv6 (p, si);
+
+  /* Unlink static route from linked list. */
+  if (si->prev)
+    si->prev->next = si->next;
+  else
+    rn->info = si->next;
+  if (si->next)
+    si->next->prev = si->prev;
+  
+  /* Free static route configuration. */
+  XFREE (MTYPE_STATIC_IPV6, si);
+
+  return 1;
+}
+#endif /* HAVE_IPV6 */
+
+/* RIB update function. */
+void
+rib_update ()
+{
+  struct route_node *rn;
+  struct route_table *table;
+
+  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  if (table)
+    for (rn = route_top (table); rn; rn = route_next (rn))
+      rib_process (rn, NULL);
+
+  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
+  if (table)
+    for (rn = route_top (table); rn; rn = route_next (rn))
+      rib_process (rn, NULL);
+}
+
+/* Interface goes up. */
+void
+rib_if_up (struct interface *ifp)
+{
+  rib_update ();
+}
+
+/* Interface goes down. */
+void
+rib_if_down (struct interface *ifp)
+{
+  rib_update ();
+}
+
+/* Remove all routes which comes from non main table.  */
+void
+rib_weed_table (struct route_table *table)
+{
+  struct route_node *rn;
+  struct rib *rib;
+  struct rib *next;
+
+  if (table)
+    for (rn = route_top (table); rn; rn = route_next (rn))
+      for (rib = rn->info; rib; rib = next)
+	{
+	  next = rib->next;
+
+	  if (rib->table != rtm_table_default &&
+	      rib->table != RT_TABLE_MAIN)
+	    {
+	      rib_delnode (rn, rib);
+	      newrib_free (rib);
+	      route_unlock_node (rn);
+	    }
+	}
+}
+
+/* Delete all routes from non main table. */
+void
+rib_weed_tables ()
+{
+  rib_weed_table (vrf_table (AFI_IP, SAFI_UNICAST, 0));
+  rib_weed_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0));
+}
+
+/* Delete self installed routes after zebra is relaunched.  */
+void
+rib_sweep_table (struct route_table *table)
+{
+  struct route_node *rn;
+  struct rib *rib;
+  struct rib *next;
+  int ret = 0;
+
+  if (table)
+    for (rn = route_top (table); rn; rn = route_next (rn))
+      for (rib = rn->info; rib; rib = next)
+	{
+	  next = rib->next;
+
+	  if (rib->type == ZEBRA_ROUTE_KERNEL && 
+	      CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELFROUTE))
+	    {
+	      ret = rib_uninstall_kernel (rn, rib);
+	      if (! ret)
+		{
+		  rib_delnode (rn, rib);
+		  newrib_free (rib);
+		  route_unlock_node (rn);
+		}
+	    }
+	}
+}
+
+/* Sweep all RIB tables.  */
+void
+rib_sweep_route ()
+{
+  rib_sweep_table (vrf_table (AFI_IP, SAFI_UNICAST, 0));
+  rib_sweep_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0));
+}
+
+/* Close RIB and clean up kernel routes. */
+void
+rib_close_table (struct route_table *table)
+{
+  struct route_node *rn;
+  struct rib *rib;
+
+  if (table)
+    for (rn = route_top (table); rn; rn = route_next (rn))
+      for (rib = rn->info; rib; rib = rib->next)
+	if (! RIB_SYSTEM_ROUTE (rib)
+	    && CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+	  rib_uninstall_kernel (rn, rib);
+}
+
+/* Close all RIB tables.  */
+void
+rib_close ()
+{
+  rib_close_table (vrf_table (AFI_IP, SAFI_UNICAST, 0));
+  rib_close_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0));
+}
+
+/* Routing information base initialize. */
+void
+rib_init ()
+{
+  /* VRF initialization.  */
+  vrf_init ();
+}
diff --git a/zebra/zebra_snmp.c b/zebra/zebra_snmp.c
new file mode 100644
index 0000000..d160bfa
--- /dev/null
+++ b/zebra/zebra_snmp.c
@@ -0,0 +1,550 @@
+/* BGP4 SNMP support
+ * Copyright (C) 1999 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>
+
+#ifdef HAVE_SNMP
+#include <asn1.h>
+#include <snmp.h>
+#include <snmp_impl.h>
+
+#include "if.h"
+#include "log.h"
+#include "prefix.h"
+#include "command.h"
+#include "smux.h"
+#include "table.h"
+
+#include "zebra/rib.h"
+
+#define IPFWMIB 1,3,6,1,2,1,4,24
+#define ZEBRAOID 1,3,6,1,4,1,3317,1,2,1
+
+/* ipForwardTable */
+#define IPFORWARDDEST                         1
+#define IPFORWARDMASK                         2
+#define IPFORWARDPOLICY                       3
+#define IPFORWARDNEXTHOP                      4
+#define IPFORWARDIFINDEX                      5
+#define IPFORWARDTYPE                         6
+#define IPFORWARDPROTO                        7
+#define IPFORWARDAGE                          8
+#define IPFORWARDINFO                         9
+#define IPFORWARDNEXTHOPAS                   10
+#define IPFORWARDMETRIC1                     11
+#define IPFORWARDMETRIC2                     12
+#define IPFORWARDMETRIC3                     13
+#define IPFORWARDMETRIC4                     14
+#define IPFORWARDMETRIC5                     15
+
+/* ipCidrRouteTable */
+#define IPCIDRROUTEDEST                       1
+#define IPCIDRROUTEMASK                       2
+#define IPCIDRROUTETOS                        3
+#define IPCIDRROUTENEXTHOP                    4
+#define IPCIDRROUTEIFINDEX                    5
+#define IPCIDRROUTETYPE                       6
+#define IPCIDRROUTEPROTO                      7
+#define IPCIDRROUTEAGE                        8
+#define IPCIDRROUTEINFO                       9
+#define IPCIDRROUTENEXTHOPAS                 10
+#define IPCIDRROUTEMETRIC1                   11
+#define IPCIDRROUTEMETRIC2                   12
+#define IPCIDRROUTEMETRIC3                   13
+#define IPCIDRROUTEMETRIC4                   14
+#define IPCIDRROUTEMETRIC5                   15
+#define IPCIDRROUTESTATUS                    16
+
+#define INTEGER32 ASN_INTEGER
+#define GAUGE32 ASN_GAUGE
+#define ENUMERATION ASN_INTEGER
+#define ROWSTATUS ASN_INTEGER
+#define IPADDRESS ASN_IPADDRESS
+#define OBJECTIDENTIFIER ASN_OBJECT_ID
+
+oid ipfw_oid [] = { IPFWMIB };
+oid zebra_oid [] = { ZEBRAOID };
+
+/* Hook functions. */
+u_char * ipFwNumber ();
+u_char * ipFwTable ();
+u_char * ipCidrNumber ();
+u_char * ipCidrTable ();
+
+struct variable zebra_variables[] = 
+{
+  {0, GAUGE32, RONLY, ipFwNumber, 1, {1}},
+  {IPFORWARDDEST, IPADDRESS, RONLY, ipFwTable, 3, {2, 1, 1}},
+  {IPFORWARDMASK, IPADDRESS, RONLY, ipFwTable, 3, {2, 1, 2}},
+  {IPFORWARDPOLICY, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 3}},
+  {IPFORWARDNEXTHOP, IPADDRESS, RONLY, ipFwTable, 3, {2, 1, 4}},
+  {IPFORWARDIFINDEX, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 5}},
+  {IPFORWARDTYPE, ENUMERATION, RONLY, ipFwTable, 3, {2, 1, 6}},
+  {IPFORWARDPROTO, ENUMERATION, RONLY, ipFwTable, 3, {2, 1, 7}},
+  {IPFORWARDAGE, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 8}},
+  {IPFORWARDINFO, OBJECTIDENTIFIER, RONLY, ipFwTable, 3, {2, 1, 9}},
+  {IPFORWARDNEXTHOPAS, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 10}},
+  {IPFORWARDMETRIC1, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 11}},
+  {IPFORWARDMETRIC2, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 12}},
+  {IPFORWARDMETRIC3, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 13}},
+  {IPFORWARDMETRIC4, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 14}},
+  {IPFORWARDMETRIC5, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 15}},
+  {0, GAUGE32, RONLY, ipCidrNumber, 1, {3}},
+  {IPCIDRROUTEDEST, IPADDRESS, RONLY, ipCidrTable, 3, {4, 1, 1}},
+  {IPCIDRROUTEMASK, IPADDRESS, RONLY, ipCidrTable, 3, {4, 1, 2}},
+  {IPCIDRROUTETOS, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 3}},
+  {IPCIDRROUTENEXTHOP, IPADDRESS, RONLY, ipCidrTable, 3, {4, 1, 4}},
+  {IPCIDRROUTEIFINDEX, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 5}},
+  {IPCIDRROUTETYPE, ENUMERATION, RONLY, ipCidrTable, 3, {4, 1, 6}},
+  {IPCIDRROUTEPROTO, ENUMERATION, RONLY, ipCidrTable, 3, {4, 1, 7}},
+  {IPCIDRROUTEAGE, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 8}},
+  {IPCIDRROUTEINFO, OBJECTIDENTIFIER, RONLY, ipCidrTable, 3, {4, 1, 9}},
+  {IPCIDRROUTENEXTHOPAS, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 10}},
+  {IPCIDRROUTEMETRIC1, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 11}},
+  {IPCIDRROUTEMETRIC2, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 12}},
+  {IPCIDRROUTEMETRIC3, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 13}},
+  {IPCIDRROUTEMETRIC4, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 14}},
+  {IPCIDRROUTEMETRIC5, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 15}},
+  {IPCIDRROUTESTATUS, ROWSTATUS, RONLY, ipCidrTable, 3, {4, 1, 16}}
+};
+
+
+u_char *
+ipFwNumber (struct variable *v, oid objid[], size_t *objid_len,
+	    int exact, size_t *val_len, WriteMethod **write_method)
+{
+  static int result;
+  struct route_node *np;
+  struct rib *rib;
+
+  if (smux_header_generic(v, objid, objid_len, exact, val_len, write_method) == MATCH_FAILED)
+    return NULL;
+
+  /* Return number of routing entries. */
+  result = 0;
+  for (np = route_top (rib_table_ipv4); np; np = route_next (np))
+    for (rib = np->info; rib; rib = rib->next)
+      result++;
+
+  return (u_char *)&result;
+}
+
+u_char *
+ipCidrNumber (struct variable *v, oid objid[], size_t *objid_len,
+	    int exact, size_t *val_len, WriteMethod **write_method)
+{
+  static int result;
+  struct route_node *np;
+  struct rib *rib;
+
+  if (smux_header_generic(v, objid, objid_len, exact, val_len, write_method) == MATCH_FAILED)
+    return NULL;
+
+  /* Return number of routing entries. */
+  result = 0;
+  for (np = route_top (rib_table_ipv4); np; np = route_next (np))
+    for (rib = np->info; rib; rib = rib->next)
+      result++;
+
+  return (u_char *)&result;
+}
+
+int
+in_addr_cmp(u_char *p1, u_char *p2)
+{
+  int i;
+
+  for (i=0; i<4; i++)
+    {
+      if (*p1 < *p2)
+        return -1;
+      if (*p1 > *p2)
+        return 1;
+      p1++; p2++;
+    }
+  return 0;
+}
+
+int 
+in_addr_add(u_char *p, int num)
+{
+  int i, ip0;
+
+  ip0 = *p;
+  p += 4;
+  for (i = 3; 0 <= i; i--) {
+    p--;
+    if (*p + num > 255) {
+    	*p += num;
+    	num = 1;
+    } else {
+    	*p += num;
+    	return 1;
+    }
+  }
+  if (ip0 > *p) {
+  	/* ip + num > 0xffffffff */
+  	return 0;
+  }
+  
+  return 1;
+}
+
+int proto_trans(int type)
+{
+  switch (type)
+    {
+      case ZEBRA_ROUTE_SYSTEM:
+        return 1; /* other */
+      case ZEBRA_ROUTE_KERNEL:
+        return 1; /* other */
+      case ZEBRA_ROUTE_CONNECT:
+        return 2; /* local interface */
+      case ZEBRA_ROUTE_STATIC:
+        return 3; /* static route */
+      case ZEBRA_ROUTE_RIP:
+        return 8; /* rip */
+      case ZEBRA_ROUTE_RIPNG:
+        return 1; /* shouldn't happen */
+      case ZEBRA_ROUTE_OSPF:
+        return 13; /* ospf */
+      case ZEBRA_ROUTE_OSPF6:
+        return 1; /* shouldn't happen */
+      case ZEBRA_ROUTE_BGP:
+        return 14; /* bgp */
+      default:
+        return 1; /* other */
+    }
+}
+
+void
+check_replace(struct route_node *np2, struct rib *rib2, 
+              struct route_node **np, struct rib **rib)
+{
+  int proto, proto2;
+
+  if (!*np)
+    {
+      *np = np2;
+      *rib = rib2;
+      return;
+    }
+
+  if (in_addr_cmp(&(*np)->p.u.prefix, &np2->p.u.prefix) < 0)
+    return;
+  if (in_addr_cmp(&(*np)->p.u.prefix, &np2->p.u.prefix) > 0)
+    {
+      *np = np2;
+      *rib = rib2;
+      return;
+    }
+
+  proto = proto_trans((*rib)->type);
+  proto2 = proto_trans(rib2->type);
+
+  if (proto2 > proto)
+    return;
+  if (proto2 < proto)
+    {
+      *np = np2;
+      *rib = rib2;
+      return;
+    }
+
+  if (in_addr_cmp((u_char *)&(*rib)->nexthop->gate.ipv4, 
+                  (u_char *)&rib2->nexthop->gate.ipv4) <= 0)
+    return;
+
+  *np = np2;
+  *rib = rib2;
+  return;
+}
+
+void
+get_fwtable_route_node(struct variable *v, oid objid[], size_t *objid_len, 
+		       int exact, struct route_node **np, struct rib **rib)
+{
+  struct in_addr dest;
+  struct route_node *np2;
+  struct rib *rib2;
+  int proto;
+  int policy;
+  struct in_addr nexthop;
+  u_char *pnt;
+  int i;
+
+/* Init index variables */
+
+  pnt = (u_char *) &dest;
+  for (i = 0; i < 4; i++)
+    *pnt++ = 0;
+
+  pnt = (u_char *) &nexthop;
+  for (i = 0; i < 4; i++)
+    *pnt++ = 0;
+
+  proto = 0;
+  policy = 0;
+ 
+/* Init return variables */
+
+  *np = NULL;
+  *rib = NULL;
+
+/* Short circuit exact matches of wrong length */
+
+  if (exact && (*objid_len != v->namelen + 10))
+    return;
+
+/* Get INDEX information out of OID.
+ * ipForwardDest, ipForwardProto, ipForwardPolicy, ipForwardNextHop
+ */
+
+  if (*objid_len > v->namelen)
+    oid2in_addr (objid + v->namelen, MIN(4, *objid_len - v->namelen), &dest);
+
+  if (*objid_len > v->namelen + 4)
+    proto = objid[v->namelen + 4];
+
+  if (*objid_len > v->namelen + 5)
+    policy = objid[v->namelen + 5];
+
+  if (*objid_len > v->namelen + 6)
+    oid2in_addr (objid + v->namelen + 6, MIN(4, *objid_len - v->namelen - 6),
+      &nexthop);
+
+  /* Apply GETNEXT on not exact search */
+
+  if (!exact && (*objid_len >= v->namelen + 10))
+    {
+      if (! in_addr_add((u_char *) &nexthop, 1)) 
+        return;
+    }
+
+  /* For exact: search matching entry in rib table. */
+
+  if (exact)
+    {
+      if (policy) /* Not supported (yet?) */
+        return;
+      for (*np = route_top (rib_table_ipv4); *np; *np = route_next (*np))
+	{
+	  if (!in_addr_cmp(&(*np)->p.u.prefix, (u_char *)&dest))
+	    {
+	      for (*rib = (*np)->info; *rib; *rib = (*rib)->next)
+	        {
+		  if (!in_addr_cmp((u_char *)&(*rib)->nexthop->gate.ipv4,
+		    (u_char *)&nexthop))
+		    if (proto == proto_trans((*rib)->type))
+		      return;
+		}
+	    }
+	}
+      return;
+    }
+
+/* Search next best entry */
+
+  for (np2 = route_top (rib_table_ipv4); np2; np2 = route_next (np2))
+    {
+
+      /* Check destination first */
+      if (in_addr_cmp(&np2->p.u.prefix, (u_char *)&dest) > 0)
+        for (rib2 = np2->info; rib2; rib2 = rib2->next)
+	  check_replace(np2, rib2, np, rib);
+
+      if (in_addr_cmp(&np2->p.u.prefix, (u_char *)&dest) == 0)
+        { /* have to look at each rib individually */
+          for (rib2 = np2->info; rib2; rib2 = rib2->next)
+	    {
+	      int proto2, policy2;
+
+	      proto2 = proto_trans(rib2->type);
+	      policy2 = 0;
+
+	      if ((policy < policy2)
+		  || ((policy == policy2) && (proto < proto2))
+		  || ((policy == policy2) && (proto == proto2)
+		      && (in_addr_cmp((u_char *)&rib2->nexthop->gate.ipv4,
+				      (u_char *) &nexthop) >= 0)
+		      ))
+		check_replace(np2, rib2, np, rib);
+	    }
+	}
+    }
+
+  if (!*rib)
+    return;
+
+  policy = 0;
+  proto = proto_trans((*rib)->type);
+
+  *objid_len = v->namelen + 10;
+  pnt = (u_char *) &(*np)->p.u.prefix;
+  for (i = 0; i < 4; i++)
+    objid[v->namelen + i] = *pnt++;
+
+  objid[v->namelen + 4] = proto;
+  objid[v->namelen + 5] = policy;
+
+  {
+    struct nexthop *nexthop;
+
+    nexthop = (*rib)->nexthop;
+    if (nexthop)
+      {
+	pnt = (u_char *) &nexthop->gate.ipv4;
+	for (i = 0; i < 4; i++)
+	  objid[i + v->namelen + 6] = *pnt++;
+      }
+  }
+
+  return;
+}
+
+u_char *
+ipFwTable (struct variable *v, oid objid[], size_t *objid_len,
+	   int exact, size_t *val_len, WriteMethod **write_method)
+{
+  struct route_node *np;
+  struct rib *rib;
+  static int result;
+  static int resarr[2];
+  static struct in_addr netmask;
+  struct nexthop *nexthop;
+
+  get_fwtable_route_node(v, objid, objid_len, exact, &np, &rib);
+  if (!np)
+    return NULL;
+
+  nexthop = rib->nexthop;
+  if (! nexthop)
+    return NULL;
+
+  switch (v->magic)
+    {
+    case IPFORWARDDEST:
+      *val_len = 4;
+      return &np->p.u.prefix;
+      break;
+    case IPFORWARDMASK:
+      masklen2ip(np->p.prefixlen, &netmask);
+      *val_len = 4;
+      return (u_char *)&netmask;
+      break;
+    case IPFORWARDPOLICY:
+      result = 0;
+      *val_len  = sizeof(int);
+      return (u_char *)&result;
+      break;
+    case IPFORWARDNEXTHOP:
+      *val_len = 4;
+      return (u_char *)&nexthop->gate.ipv4;
+      break;
+    case IPFORWARDIFINDEX:
+      *val_len = sizeof(int);
+      return (u_char *)&nexthop->ifindex;
+      break;
+    case IPFORWARDTYPE:
+      if (nexthop->type == NEXTHOP_TYPE_IFINDEX
+	  || nexthop->type == NEXTHOP_TYPE_IFNAME)
+        result = 3;
+      else
+        result = 4;
+      *val_len  = sizeof(int);
+      return (u_char *)&result;
+      break;
+    case IPFORWARDPROTO:
+      result = proto_trans(rib->type);
+      *val_len  = sizeof(int);
+      return (u_char *)&result;
+      break;
+    case IPFORWARDAGE:
+      result = 0;
+      *val_len  = sizeof(int);
+      return (u_char *)&result;
+      break;
+    case IPFORWARDINFO:
+      resarr[0] = 0;
+      resarr[1] = 0;
+      *val_len  = 2 * sizeof(int);
+      return (u_char *)resarr;
+      break;
+    case IPFORWARDNEXTHOPAS:
+      result = -1;
+      *val_len  = sizeof(int);
+      return (u_char *)&result;
+      break;
+    case IPFORWARDMETRIC1:
+      result = 0;
+      *val_len  = sizeof(int);
+      return (u_char *)&result;
+      break;
+    case IPFORWARDMETRIC2:
+      result = 0;
+      *val_len  = sizeof(int);
+      return (u_char *)&result;
+      break;
+    case IPFORWARDMETRIC3:
+      result = 0;
+      *val_len  = sizeof(int);
+      return (u_char *)&result;
+      break;
+    case IPFORWARDMETRIC4:
+      result = 0;
+      *val_len  = sizeof(int);
+      return (u_char *)&result;
+      break;
+    case IPFORWARDMETRIC5:
+      result = 0;
+      *val_len  = sizeof(int);
+      return (u_char *)&result;
+      break;
+    default:
+      return NULL;
+      break;
+    }  
+  return NULL;
+}
+
+u_char *
+ipCidrTable (struct variable *v, oid objid[], size_t *objid_len,
+	   int exact, size_t *val_len, WriteMethod **write_method)
+{
+  switch (v->magic)
+    {
+    case IPCIDRROUTEDEST:
+      break;
+    default:
+      return NULL;
+      break;
+    }  
+  return NULL;
+}
+
+void
+zebra_snmp_init ()
+{
+  smux_init (zebra_oid, sizeof (zebra_oid) / sizeof (oid));
+  REGISTER_MIB("mibII/ipforward", zebra_variables, variable, ipfw_oid);
+  smux_start ();
+}
+#endif /* HAVE_SNMP */
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
new file mode 100644
index 0000000..f6e7f51
--- /dev/null
+++ b/zebra/zebra_vty.c
@@ -0,0 +1,1554 @@
+/* Zebra VTY functions
+ * Copyright (C) 2002 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 "if.h"
+#include "prefix.h"
+#include "command.h"
+#include "table.h"
+#include "rib.h"
+
+/* Return route type string for VTY output.  */
+const char *
+route_type_str (u_char type)
+{
+  switch (type)
+    {
+    case ZEBRA_ROUTE_SYSTEM:
+      return "system";
+    case ZEBRA_ROUTE_KERNEL:
+      return "kernel";
+    case ZEBRA_ROUTE_CONNECT:
+      return "connected";
+    case ZEBRA_ROUTE_STATIC:
+      return "static";
+    case ZEBRA_ROUTE_RIP:
+      return "rip";
+    case ZEBRA_ROUTE_RIPNG:
+      return "rip";
+    case ZEBRA_ROUTE_OSPF:
+      return "ospf";
+    case ZEBRA_ROUTE_OSPF6:
+      return "ospf";
+    case ZEBRA_ROUTE_BGP:
+      return "bgp";
+    default:
+      return "unknown";
+    }
+};
+
+/* Return route type string for VTY output.  */
+const char
+route_type_char (u_char type)
+{
+  switch (type)
+    {
+    case ZEBRA_ROUTE_SYSTEM:
+      return 'S';
+    case ZEBRA_ROUTE_KERNEL:
+      return 'K';
+    case ZEBRA_ROUTE_CONNECT:
+      return 'C';
+    case ZEBRA_ROUTE_STATIC:
+      return 'S';
+    case ZEBRA_ROUTE_RIP:
+      return 'R';
+    case ZEBRA_ROUTE_RIPNG:
+      return 'R';
+    case ZEBRA_ROUTE_OSPF:
+      return 'O';
+    case ZEBRA_ROUTE_OSPF6:
+      return 'O';
+    case ZEBRA_ROUTE_BGP:
+      return 'B';
+    default:
+      return '?';
+    }
+};
+
+/* General fucntion for static route. */
+int
+zebra_static_ipv4 (struct vty *vty, int add_cmd,
+		   char *dest_str, char *mask_str, char *gate_str,
+		   char *distance_str)
+{
+  int ret;
+  u_char distance;
+  struct prefix p;
+  struct in_addr gate;
+  struct in_addr mask;
+  char *ifname;
+  
+  ret = str2prefix (dest_str, &p);
+  if (ret <= 0)
+    {
+      vty_out (vty, "%% Malformed address%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Cisco like mask notation. */
+  if (mask_str)
+    {
+      ret = inet_aton (mask_str, &mask);
+      if (ret == 0)
+	{
+	  vty_out (vty, "%% Malformed address%s", VTY_NEWLINE);
+	  return CMD_WARNING;
+	}
+      p.prefixlen = ip_masklen (mask);
+    }
+
+  /* Apply mask for given prefix. */
+  apply_mask (&p);
+
+  /* Administrative distance. */
+  if (distance_str)
+    distance = atoi (distance_str);
+  else
+    distance = ZEBRA_STATIC_DISTANCE_DEFAULT;
+
+  /* Null0 static route.  */
+  if (strncasecmp (gate_str, "Null0", strlen (gate_str)) == 0)
+    {
+      if (add_cmd)
+	static_add_ipv4 (&p, NULL, NULL, distance, 0);
+      else
+	static_delete_ipv4 (&p, NULL, NULL, distance, 0);
+      return CMD_SUCCESS;
+    }
+
+  /* When gateway is A.B.C.D format, gate is treated as nexthop
+     address other case gate is treated as interface name. */
+  ret = inet_aton (gate_str, &gate);
+  if (ret)
+    ifname = NULL;
+  else
+    ifname = gate_str;
+
+  if (add_cmd)
+    static_add_ipv4 (&p, ifname ? NULL : &gate, ifname, distance, 0);
+  else
+    static_delete_ipv4 (&p, ifname ? NULL : &gate, ifname, distance, 0);
+
+  return CMD_SUCCESS;
+}
+
+/* Static route configuration.  */
+DEFUN (ip_route, 
+       ip_route_cmd,
+       "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0)",
+       IP_STR
+       "Establish static routes\n"
+       "IP destination prefix (e.g. 10.0.0.0/8)\n"
+       "IP gateway address\n"
+       "IP gateway interface name\n"
+       "Null interface\n")
+{
+  return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], NULL);
+}
+
+/* Mask as A.B.C.D format.  */
+DEFUN (ip_route_mask,
+       ip_route_mask_cmd,
+       "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0)",
+       IP_STR
+       "Establish static routes\n"
+       "IP destination prefix\n"
+       "IP destination prefix mask\n"
+       "IP gateway address\n"
+       "IP gateway interface name\n"
+       "Null interface\n")
+{
+  return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], NULL);
+}
+
+/* Distance option value.  */
+DEFUN (ip_route_distance,
+       ip_route_distance_cmd,
+       "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) <1-255>",
+       IP_STR
+       "Establish static routes\n"
+       "IP destination prefix (e.g. 10.0.0.0/8)\n"
+       "IP gateway address\n"
+       "IP gateway interface name\n"
+       "Null interface\n"
+       "Distance value for this route\n")
+{
+  return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], argv[2]);
+}
+
+DEFUN (ip_route_mask_distance,
+       ip_route_mask_distance_cmd,
+       "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) <1-255>",
+       IP_STR
+       "Establish static routes\n"
+       "IP destination prefix\n"
+       "IP destination prefix mask\n"
+       "IP gateway address\n"
+       "IP gateway interface name\n"
+       "Null interface\n"
+       "Distance value for this route\n")
+{
+  return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], argv[3]);
+}
+
+DEFUN (no_ip_route, 
+       no_ip_route_cmd,
+       "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0)",
+       NO_STR
+       IP_STR
+       "Establish static routes\n"
+       "IP destination prefix (e.g. 10.0.0.0/8)\n"
+       "IP gateway address\n"
+       "IP gateway interface name\n"
+       "Null interface\n")
+{
+  return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], NULL);
+}
+
+DEFUN (no_ip_route_mask,
+       no_ip_route_mask_cmd,
+       "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0)",
+       NO_STR
+       IP_STR
+       "Establish static routes\n"
+       "IP destination prefix\n"
+       "IP destination prefix mask\n"
+       "IP gateway address\n"
+       "IP gateway interface name\n"
+       "Null interface\n")
+{
+  return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], NULL);
+}
+
+DEFUN (no_ip_route_distance,
+       no_ip_route_distance_cmd,
+       "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) <1-255>",
+       NO_STR
+       IP_STR
+       "Establish static routes\n"
+       "IP destination prefix (e.g. 10.0.0.0/8)\n"
+       "IP gateway address\n"
+       "IP gateway interface name\n"
+       "Null interface\n"
+       "Distance value for this route\n")
+{
+  return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], argv[2]);
+}
+
+DEFUN (no_ip_route_mask_distance,
+       no_ip_route_mask_distance_cmd,
+       "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) <1-255>",
+       NO_STR
+       IP_STR
+       "Establish static routes\n"
+       "IP destination prefix\n"
+       "IP destination prefix mask\n"
+       "IP gateway address\n"
+       "IP gateway interface name\n"
+       "Null interface\n"
+       "Distance value for this route\n")
+{
+  return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], argv[3]);
+}
+
+/* New RIB.  Detailed information for IPv4 route. */
+void
+vty_show_ip_route_detail (struct vty *vty, struct route_node *rn)
+{
+  struct rib *rib;
+  struct nexthop *nexthop;
+
+  for (rib = rn->info; rib; rib = rib->next)
+    {
+      vty_out (vty, "Routing entry for %s/%d%s", 
+	       inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen,
+	       VTY_NEWLINE);
+      vty_out (vty, "  Known via \"%s\"", route_type_str (rib->type));
+      vty_out (vty, ", distance %d, metric %d", rib->distance, rib->metric);
+      if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+	vty_out (vty, ", best");
+      if (rib->refcnt)
+	vty_out (vty, ", refcnt %ld", rib->refcnt);
+      vty_out (vty, "%s", VTY_NEWLINE);
+
+#define ONE_DAY_SECOND 60*60*24
+#define ONE_WEEK_SECOND 60*60*24*7
+      if (rib->type == ZEBRA_ROUTE_RIP
+	  || rib->type == ZEBRA_ROUTE_OSPF
+	  || rib->type == ZEBRA_ROUTE_BGP)
+	{
+	  time_t uptime;
+	  struct tm *tm;
+
+	  uptime = time (NULL);
+	  uptime -= rib->uptime;
+	  tm = gmtime (&uptime);
+
+	  vty_out (vty, "  Last update ");
+
+	  if (uptime < ONE_DAY_SECOND)
+	    vty_out (vty,  "%02d:%02d:%02d", 
+		     tm->tm_hour, tm->tm_min, tm->tm_sec);
+	  else if (uptime < ONE_WEEK_SECOND)
+	    vty_out (vty, "%dd%02dh%02dm", 
+		     tm->tm_yday, tm->tm_hour, tm->tm_min);
+	  else
+	    vty_out (vty, "%02dw%dd%02dh", 
+		     tm->tm_yday/7,
+		     tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour);
+	  vty_out (vty, " ago%s", VTY_NEWLINE);
+	}
+
+      for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+	{
+	  vty_out (vty, "  %c",
+		   CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? '*' : ' ');
+
+	  switch (nexthop->type)
+	    {
+	    case NEXTHOP_TYPE_IPV4:
+	    case NEXTHOP_TYPE_IPV4_IFINDEX:
+	      vty_out (vty, " %s", inet_ntoa (nexthop->gate.ipv4));
+	      if (nexthop->ifindex)
+		vty_out (vty, ", via %s", ifindex2ifname (nexthop->ifindex));
+	      break;
+	    case NEXTHOP_TYPE_IFINDEX:
+	      vty_out (vty, " directly connected, %s",
+		       ifindex2ifname (nexthop->ifindex));
+	      break;
+	    case NEXTHOP_TYPE_IFNAME:
+	      vty_out (vty, " directly connected, %s", nexthop->ifname);
+	      break;
+	    case NEXTHOP_TYPE_BLACKHOLE:
+	      vty_out (vty, " directly connected, via Null0");
+	      break;
+	    default:
+	      break;
+	    }
+	  if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+	    vty_out (vty, " inactive");
+
+	  if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+	    {
+	      vty_out (vty, " (recursive");
+		
+	      switch (nexthop->rtype)
+		{
+		case NEXTHOP_TYPE_IPV4:
+		case NEXTHOP_TYPE_IPV4_IFINDEX:
+		  vty_out (vty, " via %s)", inet_ntoa (nexthop->rgate.ipv4));
+		  break;
+		case NEXTHOP_TYPE_IFINDEX:
+		case NEXTHOP_TYPE_IFNAME:
+		  vty_out (vty, " is directly connected, %s)",
+			   ifindex2ifname (nexthop->rifindex));
+		  break;
+		default:
+		  break;
+		}
+	    }
+	  vty_out (vty, "%s", VTY_NEWLINE);
+	}
+      vty_out (vty, "%s", VTY_NEWLINE);
+    }
+}
+
+void
+vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib)
+{
+  struct nexthop *nexthop;
+  int len = 0;
+  char buf[BUFSIZ];
+
+  /* Nexthop information. */
+  for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+    {
+      if (nexthop == rib->nexthop)
+	{
+	  /* Prefix information. */
+	  len = vty_out (vty, "%c%c%c %s/%d",
+			 route_type_char (rib->type),
+			 CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)
+			 ? '>' : ' ',
+			 CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
+			 ? '*' : ' ',
+			 inet_ntop (AF_INET, &rn->p.u.prefix, buf, BUFSIZ),
+			 rn->p.prefixlen);
+		
+	  /* Distance and metric display. */
+	  if (rib->type != ZEBRA_ROUTE_CONNECT 
+	      && rib->type != ZEBRA_ROUTE_KERNEL)
+	    len += vty_out (vty, " [%d/%d]", rib->distance,
+			    rib->metric);
+	}
+      else
+	vty_out (vty, "  %c%*c",
+		 CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
+		 ? '*' : ' ',
+		 len - 3, ' ');
+
+      switch (nexthop->type)
+	{
+	case NEXTHOP_TYPE_IPV4:
+	case NEXTHOP_TYPE_IPV4_IFINDEX:
+	  vty_out (vty, " via %s", inet_ntoa (nexthop->gate.ipv4));
+	  if (nexthop->ifindex)
+	    vty_out (vty, ", %s", ifindex2ifname (nexthop->ifindex));
+	  break;
+	case NEXTHOP_TYPE_IFINDEX:
+	  vty_out (vty, " is directly connected, %s",
+		   ifindex2ifname (nexthop->ifindex));
+	  break;
+	case NEXTHOP_TYPE_IFNAME:
+	  vty_out (vty, " is directly connected, %s", nexthop->ifname);
+	  break;
+	case NEXTHOP_TYPE_BLACKHOLE:
+	  vty_out (vty, " is directly connected, Null0");
+	default:
+	  break;
+	}
+      if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+	vty_out (vty, " inactive");
+
+      if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+	{
+	  vty_out (vty, " (recursive");
+		
+	  switch (nexthop->rtype)
+	    {
+	    case NEXTHOP_TYPE_IPV4:
+	    case NEXTHOP_TYPE_IPV4_IFINDEX:
+	      vty_out (vty, " via %s)", inet_ntoa (nexthop->rgate.ipv4));
+	      break;
+	    case NEXTHOP_TYPE_IFINDEX:
+	    case NEXTHOP_TYPE_IFNAME:
+	      vty_out (vty, " is directly connected, %s)",
+		       ifindex2ifname (nexthop->rifindex));
+	      break;
+	    default:
+	      break;
+	    }
+	}
+
+      if (rib->type == ZEBRA_ROUTE_RIP
+	  || rib->type == ZEBRA_ROUTE_OSPF
+	  || rib->type == ZEBRA_ROUTE_BGP)
+	{
+	  time_t uptime;
+	  struct tm *tm;
+
+	  uptime = time (NULL);
+	  uptime -= rib->uptime;
+	  tm = gmtime (&uptime);
+
+#define ONE_DAY_SECOND 60*60*24
+#define ONE_WEEK_SECOND 60*60*24*7
+
+	  if (uptime < ONE_DAY_SECOND)
+	    vty_out (vty,  ", %02d:%02d:%02d", 
+		     tm->tm_hour, tm->tm_min, tm->tm_sec);
+	  else if (uptime < ONE_WEEK_SECOND)
+	    vty_out (vty, ", %dd%02dh%02dm", 
+		     tm->tm_yday, tm->tm_hour, tm->tm_min);
+	  else
+	    vty_out (vty, ", %02dw%dd%02dh", 
+		     tm->tm_yday/7,
+		     tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour);
+	}
+      vty_out (vty, "%s", VTY_NEWLINE);
+    }
+}
+
+#define SHOW_ROUTE_V4_HEADER "Codes: K - kernel route, C - connected, S - static, R - RIP, O - OSPF,%s       B - BGP, > - selected route, * - FIB route%s%s"
+
+DEFUN (show_ip_route,
+       show_ip_route_cmd,
+       "show ip route",
+       SHOW_STR
+       IP_STR
+       "IP routing table\n")
+{
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *rib;
+  int first = 1;
+
+  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  if (! table)
+    return CMD_SUCCESS;
+
+  /* Show all IPv4 routes. */
+  for (rn = route_top (table); rn; rn = route_next (rn))
+    for (rib = rn->info; rib; rib = rib->next)
+      {
+	if (first)
+	  {
+	    vty_out (vty, SHOW_ROUTE_V4_HEADER, VTY_NEWLINE, VTY_NEWLINE,
+		     VTY_NEWLINE);
+	    first = 0;
+	  }
+	vty_show_ip_route (vty, rn, rib);
+      }
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_route_prefix_longer,
+       show_ip_route_prefix_longer_cmd,
+       "show ip route A.B.C.D/M longer-prefixes",
+       SHOW_STR
+       IP_STR
+       "IP routing table\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Show route matching the specified Network/Mask pair only\n")
+{
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *rib;
+  struct prefix p;
+  int ret;
+  int first = 1;
+
+  ret = str2prefix (argv[0], &p);
+  if (! ret)
+    {
+      vty_out (vty, "%% Malformed Prefix%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  
+  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  if (! table)
+    return CMD_SUCCESS;
+
+  /* Show matched type IPv4 routes. */
+  for (rn = route_top (table); rn; rn = route_next (rn))
+    for (rib = rn->info; rib; rib = rib->next)
+      if (prefix_match (&p, &rn->p))
+	{
+	  if (first)
+	    {
+	      vty_out (vty, SHOW_ROUTE_V4_HEADER, VTY_NEWLINE,
+		       VTY_NEWLINE, VTY_NEWLINE);
+	      first = 0;
+	    }
+	  vty_show_ip_route (vty, rn, rib);
+	}
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_route_supernets,
+       show_ip_route_supernets_cmd,
+       "show ip route supernets-only",
+       SHOW_STR
+       IP_STR
+       "IP routing table\n"
+       "Show supernet entries only\n")
+{
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *rib;
+  u_int32_t addr; 
+  int first = 1;
+
+  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  if (! table)
+    return CMD_SUCCESS;
+
+  /* Show matched type IPv4 routes. */
+  for (rn = route_top (table); rn; rn = route_next (rn))
+    for (rib = rn->info; rib; rib = rib->next)
+      {
+	addr = ntohl (rn->p.u.prefix4.s_addr);
+
+	if ((IN_CLASSC (addr) && rn->p.prefixlen < 24)
+	   || (IN_CLASSB (addr) && rn->p.prefixlen < 16)
+	   || (IN_CLASSA (addr) && rn->p.prefixlen < 8)) 
+	  {
+	    if (first)
+	      {
+		vty_out (vty, SHOW_ROUTE_V4_HEADER, VTY_NEWLINE,
+			 VTY_NEWLINE, VTY_NEWLINE);
+		first = 0;
+	      }
+	    vty_show_ip_route (vty, rn, rib);
+	  }
+      }
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_route_protocol,
+       show_ip_route_protocol_cmd,
+       "show ip route (bgp|connected|kernel|ospf|rip|static)",
+       SHOW_STR
+       IP_STR
+       "IP routing table\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Connected\n"
+       "Kernel\n"
+       "Open Shortest Path First (OSPF)\n"
+       "Routing Information Protocol (RIP)\n"
+       "Static routes\n")
+{
+  int type;
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *rib;
+  int first = 1;
+
+  if (strncmp (argv[0], "b", 1) == 0)
+    type = ZEBRA_ROUTE_BGP;
+  else if (strncmp (argv[0], "c", 1) == 0)
+    type = ZEBRA_ROUTE_CONNECT;
+  else if (strncmp (argv[0], "k", 1) ==0)
+    type = ZEBRA_ROUTE_KERNEL;
+  else if (strncmp (argv[0], "o", 1) == 0)
+    type = ZEBRA_ROUTE_OSPF;
+  else if (strncmp (argv[0], "r", 1) == 0)
+    type = ZEBRA_ROUTE_RIP;
+  else if (strncmp (argv[0], "s", 1) == 0)
+    type = ZEBRA_ROUTE_STATIC;
+  else 
+    {
+      vty_out (vty, "Unknown route type%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  
+  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  if (! table)
+    return CMD_SUCCESS;
+
+  /* Show matched type IPv4 routes. */
+  for (rn = route_top (table); rn; rn = route_next (rn))
+    for (rib = rn->info; rib; rib = rib->next)
+      if (rib->type == type)
+	{
+	  if (first)
+	    {
+	      vty_out (vty, SHOW_ROUTE_V4_HEADER,
+		       VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+	      first = 0;
+	    }
+	  vty_show_ip_route (vty, rn, rib);
+	}
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_route_addr,
+       show_ip_route_addr_cmd,
+       "show ip route A.B.C.D",
+       SHOW_STR
+       IP_STR
+       "IP routing table\n"
+       "Network in the IP routing table to display\n")
+{
+  int ret;
+  struct prefix_ipv4 p;
+  struct route_table *table;
+  struct route_node *rn;
+
+  ret = str2prefix_ipv4 (argv[0], &p);
+  if (ret <= 0)
+    {
+      vty_out (vty, "%% Malformed IPv4 address%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  if (! table)
+    return CMD_SUCCESS;
+
+  rn = route_node_match (table, (struct prefix *) &p);
+  if (! rn)
+    {
+      vty_out (vty, "%% Network not in table%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  vty_show_ip_route_detail (vty, rn);
+
+  route_unlock_node (rn);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_route_prefix,
+       show_ip_route_prefix_cmd,
+       "show ip route A.B.C.D/M",
+       SHOW_STR
+       IP_STR
+       "IP routing table\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+{
+  int ret;
+  struct prefix_ipv4 p;
+  struct route_table *table;
+  struct route_node *rn;
+
+  ret = str2prefix_ipv4 (argv[0], &p);
+  if (ret <= 0)
+    {
+      vty_out (vty, "%% Malformed IPv4 address%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  if (! table)
+    return CMD_SUCCESS;
+
+  rn = route_node_match (table, (struct prefix *) &p);
+  if (! rn || rn->p.prefixlen != p.prefixlen)
+    {
+      vty_out (vty, "%% Network not in table%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  vty_show_ip_route_detail (vty, rn);
+
+  route_unlock_node (rn);
+
+  return CMD_SUCCESS;
+}
+
+void
+zebra_show_ip_route (struct vty *vty, struct vrf *vrf)
+{
+  vty_out (vty, "IP routing table name is %s(%d)%s",
+	   vrf->name ? vrf->name : "", vrf->id, VTY_NEWLINE);
+
+  vty_out (vty, "Route Source    Networks%s", VTY_NEWLINE);
+  vty_out (vty, "connected       %d%s", 0, VTY_NEWLINE);
+  vty_out (vty, "static          %d%s", 0, VTY_NEWLINE);
+  vty_out (vty, "rip             %d%s", 0, VTY_NEWLINE);
+
+  vty_out (vty, "bgp             %d%s", 0, VTY_NEWLINE);
+  vty_out (vty, " External: %d Internal: %d Local: %d%s",
+	   0, 0, 0, VTY_NEWLINE);
+
+  vty_out (vty, "ospf            %d%s", 0, VTY_NEWLINE);
+  vty_out (vty,
+	   "  Intra-area: %d Inter-area: %d External-1: %d External-2: %d%s",
+	   0, 0, 0, 0, VTY_NEWLINE);
+  vty_out (vty, "  NSSA External-1: %d NSSA External-2: %d%s",
+	   0, 0, VTY_NEWLINE);
+
+  vty_out (vty, "internal        %d%s", 0, VTY_NEWLINE);
+  vty_out (vty, "Total           %d%s", 0, VTY_NEWLINE);
+}
+
+/* Show route summary.  */
+DEFUN (show_ip_route_summary,
+       show_ip_route_summary_cmd,
+       "show ip route summary",
+       SHOW_STR
+       IP_STR
+       "IP routing table\n"
+       "Summary of all routes\n")
+{
+  struct vrf *vrf;
+
+  /* Default table id is zero.  */
+  vrf = vrf_lookup (0);
+  if (! vrf)
+    {
+      vty_out (vty, "%% No Default-IP-Routing-Table%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  zebra_show_ip_route (vty, vrf);
+
+  return CMD_SUCCESS;
+}
+
+/* Write IPv4 static route configuration. */
+int
+static_config_ipv4 (struct vty *vty)
+{
+  struct route_node *rn;
+  struct static_ipv4 *si;  
+  struct route_table *stable;
+  int write;
+
+  write = 0;
+
+  /* Lookup table.  */
+  stable = vrf_static_table (AFI_IP, SAFI_UNICAST, 0);
+  if (! stable)
+    return -1;
+
+  for (rn = route_top (stable); rn; rn = route_next (rn))
+    for (si = rn->info; si; si = si->next)
+      {
+	vty_out (vty, "ip route %s/%d", inet_ntoa (rn->p.u.prefix4),
+		 rn->p.prefixlen);
+
+	switch (si->type)
+	  {
+	  case STATIC_IPV4_GATEWAY:
+	    vty_out (vty, " %s", inet_ntoa (si->gate.ipv4));
+	    break;
+	  case STATIC_IPV4_IFNAME:
+	    vty_out (vty, " %s", si->gate.ifname);
+	    break;
+	  case STATIC_IPV4_BLACKHOLE:
+	    vty_out (vty, " Null0");
+	    break;
+	  }
+
+	if (si->distance != ZEBRA_STATIC_DISTANCE_DEFAULT)
+	  vty_out (vty, " %d", si->distance);
+	vty_out (vty, "%s", VTY_NEWLINE);
+
+	write = 1;
+      }
+  return write;
+}
+
+#ifdef HAVE_IPV6
+/* General fucntion for IPv6 static route. */
+int
+static_ipv6_func (struct vty *vty, int add_cmd, char *dest_str,
+		  char *gate_str, char *ifname, char *distance_str)
+{
+  int ret;
+  u_char distance;
+  struct prefix p;
+  struct in6_addr *gate = NULL;
+  struct in6_addr gate_addr;
+  u_char type = 0;
+  int table = 0;
+  
+  ret = str2prefix (dest_str, &p);
+  if (ret <= 0)
+    {
+      vty_out (vty, "%% Malformed address%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Apply mask for given prefix. */
+  apply_mask (&p);
+
+  /* Administrative distance. */
+  if (distance_str)
+    distance = atoi (distance_str);
+  else
+    distance = ZEBRA_STATIC_DISTANCE_DEFAULT;
+
+  /* When gateway is valid IPv6 addrees, then gate is treated as
+     nexthop address other case gate is treated as interface name. */
+  ret = inet_pton (AF_INET6, gate_str, &gate_addr);
+
+  if (ifname)
+    {
+      /* When ifname is specified.  It must be come with gateway
+         address. */
+      if (ret != 1)
+	{
+	  vty_out (vty, "%% Malformed address%s", VTY_NEWLINE);
+	  return CMD_WARNING;
+	}
+      type = STATIC_IPV6_GATEWAY_IFNAME;
+      gate = &gate_addr;
+    }
+  else
+    {
+      if (ret == 1)
+	{
+	  type = STATIC_IPV6_GATEWAY;
+	  gate = &gate_addr;
+	}
+      else
+	{
+	  type = STATIC_IPV6_IFNAME;
+	  ifname = gate_str;
+	}
+    }
+
+  if (add_cmd)
+    static_add_ipv6 (&p, type, gate, ifname, distance, table);
+  else
+    static_delete_ipv6 (&p, type, gate, ifname, distance, table);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ipv6_route,
+       ipv6_route_cmd,
+       "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE)",
+       IP_STR
+       "Establish static routes\n"
+       "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+       "IPv6 gateway address\n"
+       "IPv6 gateway interface name\n")
+{
+  return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL);
+}
+
+DEFUN (ipv6_route_ifname,
+       ipv6_route_ifname_cmd,
+       "ipv6 route X:X::X:X/M X:X::X:X INTERFACE",
+       IP_STR
+       "Establish static routes\n"
+       "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+       "IPv6 gateway address\n"
+       "IPv6 gateway interface name\n")
+{
+  return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL);
+}
+
+DEFUN (ipv6_route_pref,
+       ipv6_route_pref_cmd,
+       "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) <1-255>",
+       IP_STR
+       "Establish static routes\n"
+       "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+       "IPv6 gateway address\n"
+       "IPv6 gateway interface name\n"
+       "Distance value for this prefix\n")
+{
+  return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2]);
+}
+
+DEFUN (ipv6_route_ifname_pref,
+       ipv6_route_ifname_pref_cmd,
+       "ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>",
+       IP_STR
+       "Establish static routes\n"
+       "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+       "IPv6 gateway address\n"
+       "IPv6 gateway interface name\n"
+       "Distance value for this prefix\n")
+{
+  return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3]);
+}
+
+DEFUN (no_ipv6_route,
+       no_ipv6_route_cmd,
+       "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE)",
+       NO_STR
+       IP_STR
+       "Establish static routes\n"
+       "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+       "IPv6 gateway address\n"
+       "IPv6 gateway interface name\n")
+{
+  return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL);
+}
+
+DEFUN (no_ipv6_route_ifname,
+       no_ipv6_route_ifname_cmd,
+       "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE",
+       NO_STR
+       IP_STR
+       "Establish static routes\n"
+       "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+       "IPv6 gateway address\n"
+       "IPv6 gateway interface name\n")
+{
+  return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL);
+}
+
+DEFUN (no_ipv6_route_pref,
+       no_ipv6_route_pref_cmd,
+       "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) <1-255>",
+       NO_STR
+       IP_STR
+       "Establish static routes\n"
+       "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+       "IPv6 gateway address\n"
+       "IPv6 gateway interface name\n"
+       "Distance value for this prefix\n")
+{
+  return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, argv[2]);
+}
+
+DEFUN (no_ipv6_route_ifname_pref,
+       no_ipv6_route_ifname_pref_cmd,
+       "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>",
+       NO_STR
+       IP_STR
+       "Establish static routes\n"
+       "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+       "IPv6 gateway address\n"
+       "IPv6 gateway interface name\n"
+       "Distance value for this prefix\n")
+{
+  return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], argv[3]);
+}
+
+/* New RIB.  Detailed information for IPv4 route. */
+void
+vty_show_ipv6_route_detail (struct vty *vty, struct route_node *rn)
+{
+  struct rib *rib;
+  struct nexthop *nexthop;
+  char buf[BUFSIZ];
+
+  for (rib = rn->info; rib; rib = rib->next)
+    {
+      vty_out (vty, "Routing entry for %s/%d%s", 
+	       inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ),
+	       rn->p.prefixlen,
+	       VTY_NEWLINE);
+      vty_out (vty, "  Known via \"%s\"", route_type_str (rib->type));
+      vty_out (vty, ", distance %d, metric %d", rib->distance, rib->metric);
+      if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+	vty_out (vty, ", best");
+      if (rib->refcnt)
+	vty_out (vty, ", refcnt %ld", rib->refcnt);
+      vty_out (vty, "%s", VTY_NEWLINE);
+
+#define ONE_DAY_SECOND 60*60*24
+#define ONE_WEEK_SECOND 60*60*24*7
+      if (rib->type == ZEBRA_ROUTE_RIPNG
+	  || rib->type == ZEBRA_ROUTE_OSPF6
+	  || rib->type == ZEBRA_ROUTE_BGP)
+	{
+	  time_t uptime;
+	  struct tm *tm;
+
+	  uptime = time (NULL);
+	  uptime -= rib->uptime;
+	  tm = gmtime (&uptime);
+
+	  vty_out (vty, "  Last update ");
+
+	  if (uptime < ONE_DAY_SECOND)
+	    vty_out (vty,  "%02d:%02d:%02d", 
+		     tm->tm_hour, tm->tm_min, tm->tm_sec);
+	  else if (uptime < ONE_WEEK_SECOND)
+	    vty_out (vty, "%dd%02dh%02dm", 
+		     tm->tm_yday, tm->tm_hour, tm->tm_min);
+	  else
+	    vty_out (vty, "%02dw%dd%02dh", 
+		     tm->tm_yday/7,
+		     tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour);
+	  vty_out (vty, " ago%s", VTY_NEWLINE);
+	}
+
+      for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+	{
+	  vty_out (vty, "  %c",
+		   CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? '*' : ' ');
+
+	  switch (nexthop->type)
+	    {
+	    case NEXTHOP_TYPE_IPV6:
+	    case NEXTHOP_TYPE_IPV6_IFINDEX:
+	    case NEXTHOP_TYPE_IPV6_IFNAME:
+	      vty_out (vty, " %s",
+		       inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
+	      if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
+		vty_out (vty, ", %s", nexthop->ifname);
+	      else if (nexthop->ifindex)
+		vty_out (vty, ", via %s", ifindex2ifname (nexthop->ifindex));
+	      break;
+	    case NEXTHOP_TYPE_IFINDEX:
+	      vty_out (vty, " directly connected, %s",
+		       ifindex2ifname (nexthop->ifindex));
+	      break;
+	    case NEXTHOP_TYPE_IFNAME:
+	      vty_out (vty, " directly connected, %s",
+		       nexthop->ifname);
+	      break;
+	    default:
+	      break;
+	    }
+	  if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+	    vty_out (vty, " inactive");
+
+	  if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+	    {
+	      vty_out (vty, " (recursive");
+		
+	      switch (nexthop->rtype)
+		{
+		case NEXTHOP_TYPE_IPV6:
+		case NEXTHOP_TYPE_IPV6_IFINDEX:
+		case NEXTHOP_TYPE_IPV6_IFNAME:
+		  vty_out (vty, " via %s)",
+			   inet_ntop (AF_INET6, &nexthop->rgate.ipv6,
+				      buf, BUFSIZ));
+		  if (nexthop->rifindex)
+		    vty_out (vty, ", %s", ifindex2ifname (nexthop->rifindex));
+		  break;
+		case NEXTHOP_TYPE_IFINDEX:
+		case NEXTHOP_TYPE_IFNAME:
+		  vty_out (vty, " is directly connected, %s)",
+			   ifindex2ifname (nexthop->rifindex));
+		  break;
+		default:
+		  break;
+		}
+	    }
+	  vty_out (vty, "%s", VTY_NEWLINE);
+	}
+      vty_out (vty, "%s", VTY_NEWLINE);
+    }
+}
+
+void
+vty_show_ipv6_route (struct vty *vty, struct route_node *rn,
+		     struct rib *rib)
+{
+  struct nexthop *nexthop;
+  int len = 0;
+  char buf[BUFSIZ];
+
+  /* Nexthop information. */
+  for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+    {
+      if (nexthop == rib->nexthop)
+	{
+	  /* Prefix information. */
+	  len = vty_out (vty, "%c%c%c %s/%d",
+			 route_type_char (rib->type),
+			 CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)
+			 ? '>' : ' ',
+			 CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
+			 ? '*' : ' ',
+			 inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ),
+			 rn->p.prefixlen);
+
+	  /* Distance and metric display. */
+	  if (rib->type != ZEBRA_ROUTE_CONNECT 
+	      && rib->type != ZEBRA_ROUTE_KERNEL)
+	    len += vty_out (vty, " [%d/%d]", rib->distance,
+			    rib->metric);
+	}
+      else
+	vty_out (vty, "  %c%*c",
+		 CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
+		 ? '*' : ' ',
+		 len - 3, ' ');
+
+      switch (nexthop->type)
+	{
+	case NEXTHOP_TYPE_IPV6:
+	case NEXTHOP_TYPE_IPV6_IFINDEX:
+	case NEXTHOP_TYPE_IPV6_IFNAME:
+	  vty_out (vty, " via %s",
+		   inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
+	  if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
+	    vty_out (vty, ", %s", nexthop->ifname);
+	  else if (nexthop->ifindex)
+	    vty_out (vty, ", %s", ifindex2ifname (nexthop->ifindex));
+	  break;
+	case NEXTHOP_TYPE_IFINDEX:
+	  vty_out (vty, " is directly connected, %s",
+		   ifindex2ifname (nexthop->ifindex));
+	  break;
+	case NEXTHOP_TYPE_IFNAME:
+	  vty_out (vty, " is directly connected, %s",
+		   nexthop->ifname);
+	  break;
+	default:
+	  break;
+	}
+      if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+	vty_out (vty, " inactive");
+
+      if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+	{
+	  vty_out (vty, " (recursive");
+		
+	  switch (nexthop->rtype)
+	    {
+	    case NEXTHOP_TYPE_IPV6:
+	    case NEXTHOP_TYPE_IPV6_IFINDEX:
+	    case NEXTHOP_TYPE_IPV6_IFNAME:
+	      vty_out (vty, " via %s)",
+		       inet_ntop (AF_INET6, &nexthop->rgate.ipv6,
+				  buf, BUFSIZ));
+	      if (nexthop->rifindex)
+		vty_out (vty, ", %s", ifindex2ifname (nexthop->rifindex));
+	      break;
+	    case NEXTHOP_TYPE_IFINDEX:
+	    case NEXTHOP_TYPE_IFNAME:
+	      vty_out (vty, " is directly connected, %s)",
+		       ifindex2ifname (nexthop->rifindex));
+	      break;
+	    default:
+	      break;
+	    }
+	}
+
+      if (rib->type == ZEBRA_ROUTE_RIPNG
+	  || rib->type == ZEBRA_ROUTE_OSPF6
+	  || rib->type == ZEBRA_ROUTE_BGP)
+	{
+	  time_t uptime;
+	  struct tm *tm;
+
+	  uptime = time (NULL);
+	  uptime -= rib->uptime;
+	  tm = gmtime (&uptime);
+
+#define ONE_DAY_SECOND 60*60*24
+#define ONE_WEEK_SECOND 60*60*24*7
+
+	  if (uptime < ONE_DAY_SECOND)
+	    vty_out (vty,  ", %02d:%02d:%02d", 
+		     tm->tm_hour, tm->tm_min, tm->tm_sec);
+	  else if (uptime < ONE_WEEK_SECOND)
+	    vty_out (vty, ", %dd%02dh%02dm", 
+		     tm->tm_yday, tm->tm_hour, tm->tm_min);
+	  else
+	    vty_out (vty, ", %02dw%dd%02dh", 
+		     tm->tm_yday/7,
+		     tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour);
+	}
+      vty_out (vty, "%s", VTY_NEWLINE);
+    }
+}
+
+#define SHOW_ROUTE_V6_HEADER "Codes: K - kernel route, C - connected, S - static, R - RIPng, O - OSPFv3,%s       B - BGP, * - FIB route.%s%s"
+
+DEFUN (show_ipv6_route,
+       show_ipv6_route_cmd,
+       "show ipv6 route",
+       SHOW_STR
+       IP_STR
+       "IPv6 routing table\n")
+{
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *rib;
+  int first = 1;
+
+  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
+  if (! table)
+    return CMD_SUCCESS;
+
+  /* Show all IPv6 route. */
+  for (rn = route_top (table); rn; rn = route_next (rn))
+    for (rib = rn->info; rib; rib = rib->next)
+      {
+	if (first)
+	  {
+	    vty_out (vty, SHOW_ROUTE_V6_HEADER, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+	    first = 0;
+	  }
+	vty_show_ipv6_route (vty, rn, rib);
+      }
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ipv6_route_prefix_longer,
+       show_ipv6_route_prefix_longer_cmd,
+       "show ipv6 route X:X::X:X/M longer-prefixes",
+       SHOW_STR
+       IP_STR
+       "IPv6 routing table\n"
+       "IPv6 prefix\n"
+       "Show route matching the specified Network/Mask pair only\n")
+{
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *rib;
+  struct prefix p;
+  int ret;
+  int first = 1;
+
+  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
+  if (! table)
+    return CMD_SUCCESS;
+
+  ret = str2prefix (argv[0], &p);
+  if (! ret)
+    {
+      vty_out (vty, "%% Malformed Prefix%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Show matched type IPv6 routes. */
+  for (rn = route_top (table); rn; rn = route_next (rn))
+    for (rib = rn->info; rib; rib = rib->next)
+      if (prefix_match (&p, &rn->p))
+	{
+	  if (first)
+	    {
+	      vty_out (vty, SHOW_ROUTE_V6_HEADER, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+	      first = 0;
+	    }
+	  vty_show_ipv6_route (vty, rn, rib);
+	}
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ipv6_route_protocol,
+       show_ipv6_route_protocol_cmd,
+       "show ipv6 route (bgp|connected|kernel|ospf6|ripng|static)",
+       SHOW_STR
+       IP_STR
+       "IP routing table\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Connected\n"
+       "Kernel\n"
+       "Open Shortest Path First (OSPFv3)\n"
+       "Routing Information Protocol (RIPng)\n"
+       "Static routes\n")
+{
+  int type;
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *rib;
+  int first = 1;
+
+  if (strncmp (argv[0], "b", 1) == 0)
+    type = ZEBRA_ROUTE_BGP;
+  else if (strncmp (argv[0], "c", 1) == 0)
+    type = ZEBRA_ROUTE_CONNECT;
+  else if (strncmp (argv[0], "k", 1) ==0)
+    type = ZEBRA_ROUTE_KERNEL;
+  else if (strncmp (argv[0], "o", 1) == 0)
+    type = ZEBRA_ROUTE_OSPF6;
+  else if (strncmp (argv[0], "r", 1) == 0)
+    type = ZEBRA_ROUTE_RIPNG;
+  else if (strncmp (argv[0], "s", 1) == 0)
+    type = ZEBRA_ROUTE_STATIC;
+  else 
+    {
+      vty_out (vty, "Unknown route type%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  
+  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
+  if (! table)
+    return CMD_SUCCESS;
+
+  /* Show matched type IPv6 routes. */
+  for (rn = route_top (table); rn; rn = route_next (rn))
+    for (rib = rn->info; rib; rib = rib->next)
+      if (rib->type == type)
+	{
+	  if (first)
+	    {
+	      vty_out (vty, SHOW_ROUTE_V6_HEADER, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+	      first = 0;
+	    }
+	  vty_show_ipv6_route (vty, rn, rib);
+	}
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ipv6_route_addr,
+       show_ipv6_route_addr_cmd,
+       "show ipv6 route X:X::X:X",
+       SHOW_STR
+       IP_STR
+       "IPv6 routing table\n"
+       "IPv6 Address\n")
+{
+  int ret;
+  struct prefix_ipv6 p;
+  struct route_table *table;
+  struct route_node *rn;
+
+  ret = str2prefix_ipv6 (argv[0], &p);
+  if (ret <= 0)
+    {
+      vty_out (vty, "Malformed IPv6 address%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
+  if (! table)
+    return CMD_SUCCESS;
+
+  rn = route_node_match (table, (struct prefix *) &p);
+  if (! rn)
+    {
+      vty_out (vty, "%% Network not in table%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  vty_show_ipv6_route_detail (vty, rn);
+
+  route_unlock_node (rn);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ipv6_route_prefix,
+       show_ipv6_route_prefix_cmd,
+       "show ipv6 route X:X::X:X/M",
+       SHOW_STR
+       IP_STR
+       "IPv6 routing table\n"
+       "IPv6 prefix\n")
+{
+  int ret;
+  struct prefix_ipv6 p;
+  struct route_table *table;
+  struct route_node *rn;
+
+  ret = str2prefix_ipv6 (argv[0], &p);
+  if (ret <= 0)
+    {
+      vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
+  if (! table)
+    return CMD_SUCCESS;
+
+  rn = route_node_match (table, (struct prefix *) &p);
+  if (! rn || rn->p.prefixlen != p.prefixlen)
+    {
+      vty_out (vty, "%% Network not in table%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  vty_show_ipv6_route_detail (vty, rn);
+
+  route_unlock_node (rn);
+
+  return CMD_SUCCESS;
+}
+
+
+/* Write IPv6 static route configuration. */
+int
+static_config_ipv6 (struct vty *vty)
+{
+  struct route_node *rn;
+  struct static_ipv6 *si;  
+  int write;
+  char buf[BUFSIZ];
+  struct route_table *stable;
+
+  write = 0;
+
+  /* Lookup table.  */
+  stable = vrf_static_table (AFI_IP6, SAFI_UNICAST, 0);
+  if (! stable)
+    return -1;
+
+  for (rn = route_top (stable); rn; rn = route_next (rn))
+    for (si = rn->info; si; si = si->next)
+      {
+	vty_out (vty, "ipv6 route %s/%d",
+		 inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ),
+		 rn->p.prefixlen);
+
+	switch (si->type)
+	  {
+	  case STATIC_IPV6_GATEWAY:
+	    vty_out (vty, " %s", inet_ntop (AF_INET6, &si->ipv6, buf, BUFSIZ));
+	    break;
+	  case STATIC_IPV6_IFNAME:
+	    vty_out (vty, " %s", si->ifname);
+	    break;
+	  case STATIC_IPV6_GATEWAY_IFNAME:
+	    vty_out (vty, " %s %s",
+		     inet_ntop (AF_INET6, &si->ipv6, buf, BUFSIZ), si->ifname);
+	    break;
+	  }
+
+	if (si->distance != ZEBRA_STATIC_DISTANCE_DEFAULT)
+	  vty_out (vty, " %d", si->distance);
+	vty_out (vty, "%s", VTY_NEWLINE);
+
+	write = 1;
+      }
+  return write;
+}
+#endif /* HAVE_IPV6 */
+
+/* Static ip route configuration write function. */
+int
+zebra_ip_config (struct vty *vty)
+{
+  int write = 0;
+
+  write += static_config_ipv4 (vty);
+#ifdef HAVE_IPV6
+  write += static_config_ipv6 (vty);
+#endif /* HAVE_IPV6 */
+
+  return write;
+}
+
+/* IP node for static routes. */
+struct cmd_node ip_node = { IP_NODE,  "",  1 };
+
+/* Route VTY.  */
+void
+zebra_vty_route_init ()
+{
+  install_node (&ip_node, zebra_ip_config);
+
+  install_element (CONFIG_NODE, &ip_route_cmd);
+  install_element (CONFIG_NODE, &ip_route_mask_cmd);
+  install_element (CONFIG_NODE, &no_ip_route_cmd);
+  install_element (CONFIG_NODE, &no_ip_route_mask_cmd);
+  install_element (CONFIG_NODE, &ip_route_distance_cmd);
+  install_element (CONFIG_NODE, &ip_route_mask_distance_cmd);
+  install_element (CONFIG_NODE, &no_ip_route_distance_cmd);
+  install_element (CONFIG_NODE, &no_ip_route_mask_distance_cmd);
+
+  install_element (VIEW_NODE, &show_ip_route_cmd);
+  install_element (VIEW_NODE, &show_ip_route_addr_cmd);
+  install_element (VIEW_NODE, &show_ip_route_prefix_cmd);
+  install_element (VIEW_NODE, &show_ip_route_prefix_longer_cmd);
+  install_element (VIEW_NODE, &show_ip_route_protocol_cmd);
+  install_element (VIEW_NODE, &show_ip_route_supernets_cmd);
+  install_element (ENABLE_NODE, &show_ip_route_cmd);
+  install_element (ENABLE_NODE, &show_ip_route_addr_cmd);
+  install_element (ENABLE_NODE, &show_ip_route_prefix_cmd);
+  install_element (ENABLE_NODE, &show_ip_route_prefix_longer_cmd);
+  install_element (ENABLE_NODE, &show_ip_route_protocol_cmd);
+  install_element (ENABLE_NODE, &show_ip_route_supernets_cmd);
+
+#if 0
+  install_element (VIEW_NODE, &show_ip_route_summary_cmd);
+  install_element (ENABLE_NODE, &show_ip_route_summary_cmd);
+#endif /* 0 */
+
+#ifdef HAVE_IPV6
+  install_element (CONFIG_NODE, &ipv6_route_cmd);
+  install_element (CONFIG_NODE, &ipv6_route_ifname_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_route_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_route_ifname_cmd);
+  install_element (CONFIG_NODE, &ipv6_route_pref_cmd);
+  install_element (CONFIG_NODE, &ipv6_route_ifname_pref_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_route_pref_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_route_ifname_pref_cmd);
+  install_element (VIEW_NODE, &show_ipv6_route_cmd);
+  install_element (VIEW_NODE, &show_ipv6_route_protocol_cmd);
+  install_element (VIEW_NODE, &show_ipv6_route_addr_cmd);
+  install_element (VIEW_NODE, &show_ipv6_route_prefix_cmd);
+  install_element (VIEW_NODE, &show_ipv6_route_prefix_longer_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_route_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_route_protocol_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_route_addr_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_route_prefix_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_route_prefix_longer_cmd);
+#endif /* HAVE_IPV6 */
+}
+
+void
+zebra_vty_init ()
+{
+  zebra_vty_route_init ();
+}
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 */
+}
diff --git a/zebra/zserv.h b/zebra/zserv.h
new file mode 100644
index 0000000..c762280
--- /dev/null
+++ b/zebra/zserv.h
@@ -0,0 +1,132 @@
+/* Zebra daemon server header.
+ * Copyright (C) 1997, 98 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.  
+ */
+
+#ifndef _ZEBRA_ZSERV_H
+#define _ZEBRA_ZSERV_H
+
+/* Default port information. */
+#define ZEBRA_PORT                    2600
+#define ZEBRA_VTY_PORT                2601
+#define ZEBRA_VTYSH_PATH              "/tmp/.zebra"
+#define ZEBRA_SERV_PATH               "/tmp/.zserv"
+
+/* Default configuration filename. */
+#define DEFAULT_CONFIG_FILE "zebra.conf"
+
+/* Client structure. */
+struct zserv
+{
+  /* Client file descriptor. */
+  int sock;
+
+  /* Input/output buffer to the client. */
+  struct stream *ibuf;
+  struct stream *obuf;
+
+  /* Threads for read/write. */
+  struct thread *t_read;
+  struct thread *t_write;
+
+  /* default routing table this client munges */
+  int rtm_table;
+
+  /* This client's redistribute flag. */
+  u_char redist[ZEBRA_ROUTE_MAX];
+
+  /* Redistribute default route flag. */
+  u_char redist_default;
+
+  /* Interface information. */
+  u_char ifinfo;
+};
+
+/* Count prefix size from mask length */
+#define PSIZE(a) (((a) + 7) / (8))
+
+/* Prototypes. */
+void zebra_init ();
+void zebra_if_init ();
+void hostinfo_get ();
+void rib_init ();
+void interface_list ();
+void kernel_init ();
+void route_read ();
+void rtadv_init ();
+void zebra_snmp_init ();
+
+int
+zsend_interface_add (struct zserv *, struct interface *);
+int
+zsend_interface_delete (struct zserv *, struct interface *);
+
+int
+zsend_interface_address_add (struct zserv *, struct interface *,
+			     struct connected *);
+
+int
+zsend_interface_address_delete (struct zserv *, struct interface *,
+				struct connected *);
+
+int
+zsend_interface_up (struct zserv *, struct interface *);
+
+int
+zsend_interface_down (struct zserv *, struct interface *);
+
+int
+zsend_ipv4_add (struct zserv *client, int type, int flags,
+		struct prefix_ipv4 *p, struct in_addr *nexthop,
+		unsigned int ifindex);
+
+int
+zsend_ipv4_delete (struct zserv *client, int type, int flags,
+		   struct prefix_ipv4 *p, struct in_addr *nexthop,
+		   unsigned int ifindex);
+
+int
+zsend_ipv4_add_multipath (struct zserv *, struct prefix *, struct rib *);
+
+int
+zsend_ipv4_delete_multipath (struct zserv *, struct prefix *, struct rib *);
+
+#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
+zsend_ipv6_delete (struct zserv *client, int type, int flags,
+		   struct prefix_ipv6 *p, struct in6_addr *nexthop,
+		   unsigned int ifindex);
+
+int
+zsend_ipv6_add_multipath (struct zserv *, struct prefix *, struct rib *);
+
+int
+zsend_ipv6_delete_multipath (struct zserv *, struct prefix *, struct rib *);
+
+#endif /* HAVE_IPV6 */
+
+extern pid_t pid;
+extern pid_t old_pid;
+
+#endif /* _ZEBRA_ZEBRA_H */