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 */