From 718e3744195351130f4ce7dbe0613f4b3e23df93 Mon Sep 17 00:00:00 2001 From: paul Date: Fri, 13 Dec 2002 20:15:29 +0000 Subject: Initial revision --- zebra/.cvsignore | 8 + zebra/ChangeLog | 1221 +++++++++++++++++++++++ zebra/GNOME-PRODUCT-ZEBRA-MIB | 78 ++ zebra/GNOME-SMI | 53 + zebra/Makefile.am | 57 ++ zebra/Makefile.in | 493 +++++++++ zebra/client_main.c | 225 +++++ zebra/connected.c | 394 ++++++++ zebra/connected.h | 60 ++ zebra/debug.c | 272 +++++ zebra/debug.h | 52 + zebra/if_ioctl.c | 438 ++++++++ zebra/if_netlink.c | 33 + zebra/if_proc.c | 246 +++++ zebra/if_sysctl.c | 148 +++ zebra/interface.c | 1387 ++++++++++++++++++++++++++ zebra/interface.h | 180 ++++ zebra/ioctl.c | 540 ++++++++++ zebra/ioctl.h | 46 + zebra/ipforward.h | 35 + zebra/ipforward_aix.c | 64 ++ zebra/ipforward_ews.c | 60 ++ zebra/ipforward_proc.c | 155 +++ zebra/ipforward_solaris.c | 77 ++ zebra/ipforward_sysctl.c | 146 +++ zebra/irdp.c | 569 +++++++++++ zebra/irdp.h | 148 +++ zebra/kernel_netlink.c | 20 + zebra/kernel_socket.c | 811 +++++++++++++++ zebra/main.c | 316 ++++++ zebra/mtu_kvm.c | 97 ++ zebra/redistribute.c | 410 ++++++++ zebra/redistribute.h | 49 + zebra/rib.h | 251 +++++ zebra/rt.h | 40 + zebra/rt_ioctl.c | 558 +++++++++++ zebra/rt_netlink.c | 1482 +++++++++++++++++++++++++++ zebra/rt_socket.c | 441 +++++++++ zebra/rtadv.c | 1112 +++++++++++++++++++++ zebra/rtadv.h | 49 + zebra/rtread_getmsg.c | 229 +++++ zebra/rtread_netlink.c | 31 + zebra/rtread_proc.c | 169 ++++ zebra/rtread_sysctl.c | 75 ++ zebra/zebra.conf.sample | 25 + zebra/zebra_rib.c | 2199 +++++++++++++++++++++++++++++++++++++++++ zebra/zebra_snmp.c | 550 +++++++++++ zebra/zebra_vty.c | 1554 +++++++++++++++++++++++++++++ zebra/zserv.c | 1806 +++++++++++++++++++++++++++++++++ zebra/zserv.h | 132 +++ 50 files changed, 19591 insertions(+) create mode 100644 zebra/.cvsignore create mode 100644 zebra/ChangeLog create mode 100644 zebra/GNOME-PRODUCT-ZEBRA-MIB create mode 100644 zebra/GNOME-SMI create mode 100644 zebra/Makefile.am create mode 100644 zebra/Makefile.in create mode 100644 zebra/client_main.c create mode 100644 zebra/connected.c create mode 100644 zebra/connected.h create mode 100644 zebra/debug.c create mode 100644 zebra/debug.h create mode 100644 zebra/if_ioctl.c create mode 100644 zebra/if_netlink.c create mode 100644 zebra/if_proc.c create mode 100644 zebra/if_sysctl.c create mode 100644 zebra/interface.c create mode 100644 zebra/interface.h create mode 100644 zebra/ioctl.c create mode 100644 zebra/ioctl.h create mode 100644 zebra/ipforward.h create mode 100644 zebra/ipforward_aix.c create mode 100644 zebra/ipforward_ews.c create mode 100644 zebra/ipforward_proc.c create mode 100644 zebra/ipforward_solaris.c create mode 100644 zebra/ipforward_sysctl.c create mode 100644 zebra/irdp.c create mode 100644 zebra/irdp.h create mode 100644 zebra/kernel_netlink.c create mode 100644 zebra/kernel_socket.c create mode 100644 zebra/main.c create mode 100644 zebra/mtu_kvm.c create mode 100644 zebra/redistribute.c create mode 100644 zebra/redistribute.h create mode 100644 zebra/rib.h create mode 100644 zebra/rt.h create mode 100644 zebra/rt_ioctl.c create mode 100644 zebra/rt_netlink.c create mode 100644 zebra/rt_socket.c create mode 100644 zebra/rtadv.c create mode 100644 zebra/rtadv.h create mode 100644 zebra/rtread_getmsg.c create mode 100644 zebra/rtread_netlink.c create mode 100644 zebra/rtread_proc.c create mode 100644 zebra/rtread_sysctl.c create mode 100644 zebra/zebra.conf.sample create mode 100644 zebra/zebra_rib.c create mode 100644 zebra/zebra_snmp.c create mode 100644 zebra/zebra_vty.c create mode 100644 zebra/zserv.c create mode 100644 zebra/zserv.h (limited to 'zebra') diff --git a/zebra/.cvsignore b/zebra/.cvsignore new file mode 100644 index 00000000..95401bfa --- /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 00000000..b5383f1d --- /dev/null +++ b/zebra/ChangeLog @@ -0,0 +1,1221 @@ +2002-09-28 Akihiro Mizutani + + * zebra_rib.c (static_add_ipv4): Null0 static route is added. + +2002-09-10 Jochen Friedrich + + * rt_netlink.c: Add check for EAGAIN. + * kernel_socket.c: Likewise + +2002-06-12 Israel Keys + + * 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 + + * rtadv.c (rtadv_make_socket): setsockopt(IPV6_CHECKSUM) does not + work for ICMPv6 socket. + +2001-10-24 Kunihiro Ishiguro + + * rib.c (rib_process): Select connected route any case. + +2001-10-23 Kunihiro Ishiguro + + * interface.c (no_ip_address_secondary): Add "no" to command. + +2001-10-18 NOGUCHI Kay + + * 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 + + * rtadv.c: Do not send RA to loopback interface. + +2001-08-20 Kunihiro Ishiguro + + * ioctl.c (if_set_prefix): Remove Linux 2.0 specific connected + route treatment. + +2001-08-19 Kunihiro Ishiguro + + * zebra-0.92a released. + +2001-08-17 Kunihiro Ishiguro + + * rib.c: Kernel route is treated as EGP routes in nexthop active + check. + +2001-08-15 Kunihiro Ishiguro + + * zebra-0.92 released. + +2001-08-08 "Akihiro Mizutani" + + * rib.c (show_ip_route_prefix_longer): Add longer-prefix option to + show route commands. + +2001-07-29 Yon Uriarte + + * zserv.c (zsend_ipv4_add_multipath): Add + NEXTHOP_TYPE_IPV4_IFINDEX check. + +2001-07-29 NOGUCHI Kay + + * 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 + + * rtadv.c (ipv6_nd_ra_interval): Add "ipv6 nd ra-interval SECONDS" + command. + +2001-07-24 Jun-ichiro itojun Hagino + + * rt_socket.c (kernel_rtm_ipv4): Add KAME/NetBSD151 equal cost + multicast FIB support both IPv4 and IPv6. + +2001-07-24 Hal Snyder + + * 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 + + * 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 + + * ioctl.c (if_ioctl): Change ioctl argument from int to u_long. + + * rt_ioctl.c: Likewise. + +2001-07-23 Jun-ichiro itojun Hagino + + * kernel_socket.c (rtm_write): Only set RTF_CLONING when the + interface is not p2p. + +2001-04-23 Kunihiro Ishiguro + + * ioctl.c (if_prefix_add_ipv6): Fix argument type. + +2001-04-06 Toshiaki Takada + + * zserv.c (zsend_interface_delete): Use client->obuf instead of + allocating new stream. + +2001-03-10 Kunihiro Ishiguro + + * rt_netlink.c: Revert RTPROT_BOOT change. + +2001-03-08 Kunihiro Ishiguro + + * rt_netlink.c (netlink_route_change): Skip RTPROT_BOOT route. + (netlink_routing_table): Likewise. + +2001-03-07 "Akihiro Mizutani" + + * zserv.c (zsend_ipv4_add_multipath): Send metric value to + protocol daemons. + +2001-02-18 Kunihiro Ishiguro + + * rt_netlink.c (netlink_routing_table): Do not return + tb[RTA_GATEWAY] is NULL. Reported by: "Michael O'Keefe" + . + +2001-02-08 Kunihiro Ishiguro + + * if_ioctl.c (interface_list_ioctl): Call if_add_update(). + Suggested by: Chris Dunlop . + +2001-02-01 Kunihiro Ishiguro + + * 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 + + * kernel_socket.c (rtm_read): Filter cloned route. Suggested by: + Jun-ichiro itojun Hagino + +2001-01-30 Kunihiro Ishiguro + + * 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 + + * zserv.c (zebra_serv): Add missing close() call. Reported by: + David Waitzman . + +2001-01-24 Kunihiro Ishiguro + + * rib.c (rib_lookup_ipv4): New function for checking exact match + IGP route. + +2001-01-23 Kunihiro Ishiguro + + * rib.c (show_ipv6_route_protocol): Fix bug of "show ip route + route-type". + +2001-01-22 Kunihiro Ishiguro + + * 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 + + * 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 + + * 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 . + + * rib.c (static_ipv6_nexthop_same): Add check for + NEXTHOP_TYPE_IPV6_IFNAME. + +2001-01-15 Kunihiro Ishiguro + + * rib.h (NEW_RIB): Turn on NEW_RIB flag. IPv6 new RIB code are + taken into place. + +2001-01-14 Kunihiro Ishiguro + + * 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 . + (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 + + * 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 + + * 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 + + * 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 + + * interface.c: Remove HAVE_IF_PSEUDO part. + + * rib.h: Likewise. + + * rt_netlink.c (netlink_link_change): Likewise. + +2001-01-10 Kunihiro Ishiguro + + * zserv.c: Remove OLD_RIB codes. + +2001-01-09 Kunihiro Ishiguro + + * zebra-0.90 is released. + +2001-01-09 Matthew Grant + + * 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 + + * interface.c (if_dump_vty): When HAVE_NET_RT_IFLIST is defined, + NetBSD also use this function. Suggested by Jasper Wallace + . + +2001-01-07 Kunihiro Ishiguro + + * rib.c (nexthop_active_ipv4): Move back to set methodo to old + one. + +2001-01-05 Kunihiro Ishiguro + + * rib.c (rib_add_ipv4): EBGP multihop set ZEBRA_FLAG_INTERNAL + flag, so treat it. + +2001-01-04 Kunihiro Ishiguro + + * 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 + + * zserv.h (ZEBRA_SERV_PATH): Change "/tmp/zebra" to "/tmp/.zebra". + Change "/tmp/zserv" to "/tmp/.zserv". + +2000-12-29 Frank van Maarseveen + + * 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 + + * rib.c (vty_show_ip_route): Show uptime of the RIP,OSPF,BGP + routes. + +2000-12-27 Kunihiro Ishiguro + + * 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 + + * rib.h: Remove MULTIPATH_NUM. It is defined by configure script. + +2000-12-25 Michael Rozhavsky + + * rib.c (rib_if_up): Call rib_fib_set instead of RIB_FIB_SET for + proper redistribution. + +2000-12-19 Kunihiro Ishiguro + + * 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 + + * 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 + + * rib.c (nexthop_active_ipv4): Check indirect nexthop. + + * redistribute.c (redistribute_add_multipath): Redistribution + works with new rib code. + +2000-12-14 Kunihiro Ishiguro + + * 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 + + * rib.c (ip_route): New RIB prototype. + +2000-11-16 Yon Uriarte + + * zserv.c (zsend_interface_add): Send hardware address when + hw_addr_len is greater than 0. + +2000-11-07 Kunihiro Ishiguro + + * 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 + + * rt_netlink.c (netlink_interface_addr): Revert Harald Welte + 's ptop patch then back to original code to + avoid duplicated connected route problem. Suggested by Frank van + Maarseveen . + + * kernel_socket.c (rtm_read): Make behavior consistent even #ifdef + DEBUG is defined. Reported by Jun-ichiro itojun Hagino + . + +2000-10-23 Jochen Friedrich + + * main.c (main): Call zebra_snmp_init() when it is enabled. + +2000-10-23 Kunihiro Ishiguro + + * zserv.c (zebra_serv_un): UNIX domain socket server of zebra + protocol. + +2000-10-19 Kunihiro Ishiguro + + * rib.c (rib_add_ipv4): Same check bug is fixed. + +2000-10-03 Kunihiro Ishiguro + + * 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 + + * zebra-0.89 is released. + +2000-09-24 Harald Welte + + * rt_netlink.c (netlink_interface_addr): Fix point-to-point address + treatment in netlink interface. + +2000-09-21 David Lipovkov + + * 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 + + * if_ioctl.c (if_getaddrs): New function for looking up + interface's address by getifaddrs(). + +2000-09-10 Kunihiro Ishiguro + + * 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 + + * 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 + + * zebra-0.88 is released. + +2000-08-15 "Akihiro Mizutani" + + * 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 + + * 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 + + * rib.c (rib_add_ipv4): Do not install distance 255 route. + +2000-08-10 Toshiaki Takada + + * 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" + + * interface.c (bandwidth_if): Fix help string. + +2000-08-07 Matthew Grant + + * 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 + + * rib.c (show_ip_route_protocol): "show ip route + (bgp|connected|kernel|ospf|rip|static)" is added. + +2000-08-07 Kunihiro Ishiguro + + * 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 + + * redistribute.c (redistribute_delete): Fix bug of default route + redistribute treatment. + +2000-08-05 Kunihiro Ishiguro + + * 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 + + * 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 + + * 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 + + * interface.c: Use install_default() for common VTY commands. + +2000-07-23 Kunihiro Ishiguro + + * 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 + + * if_ioctl.c (if_get_index): Add check for HAVE_BROKEN_ALIASES. + +2000-07-04 Kunihiro Ishiguro + + * zserv.c (zebra_client_read): Add ZEBRA_REDISTRIBUTE_{ADD,DELETE} + message handling. + +2000-07-02 David Lipovkov + + * zserv.c: "ip route A.B.C.D/M unknown" command is added. + +2000-06-28 Michael Rozhavsky + + * rib.c: Remove old kernel route when new route comes in. + +2000-06-13 David Lipovkov + + * rib.c (rib_if_up): Add check for unknown interface. + +2000-06-13 Kunihiro Ishiguro + + * rib.h: Define INTERFACE_UNKNOWN. + +2000-06-08 Kunihiro Ishiguro + + * Makefile.am (EXTRA_DIST): Move irdp.c until implementation is + finished. + +2000-06-05 David Lipovkov + + * 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 + + * if_ioctl.c (interface_info_ioctl): Check interface's flag before + checking interface's address. + +2000-04-26 Jochen Friedrich + + * GNOME-PRODUCT-ZEBRA-MIB: New file. + + * GNOME-SMI: New file. + +2000-04-23 Kunihiro Ishiguro + + * irdp.c: New file from 1997 development code. + * irdp.h: Likewise. + +2000-04-19 Kunihiro Ishiguro + + * rtadv.c (rtadv_send_packet): Enclose router advertisement + logging with IS_ZEBRA_DEBUG_PACKET. + +2000-04-17 Kunihiro Ishiguro + + * zserv.c (zebra_client_close): Remove client structure from + client_list when connection is terminated. + +2000-03-21 David Lipovkov + + * 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 + + * rtread_getmsg.c: Set some definition for Solaris 2.5 and Solaris + 2.5.1. + +2000-01-21 Kunihiro Ishiguro + + * rib.c (no_ipv6_route_ifname): Fix buf of cheking return value + from str2prefix_ipv6(). + +2000-01-14 Kunihiro Ishiguro + + * 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 + * interface.*: dynamic int up/down support + +1999-12-09 Kunihiro Ishiguro + + * 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 + + * kernel_socket.c (rtm_read): When message is RTM_GET, it has own + process's pid. + +1999-12-04 Kunihiro Ishiguro + + * main.c (main): Change to default log output to ZLOG_STDOUT. + + * zserv.c (zebra_serv): More detailed error print. + +1999-11-30 Kunihiro Ishiguro + + * kernel_socket.c (rtm_read): Check old pid for static route + insertion check. + +1999-11-30 Kunihiro Ishiguro + + * 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 + + * kernel_socket.c (rtm_write): Set RTF_CLONING flag for + route to the directly connected interface. + +1999-11-27 Kunihiro Ishiguro + + * rt_socket.c: Delete USE_HOST_BIT definition. + +1999-11-21 Michael Handler + + * rtread_getmsg.c: Undef some definition to resolve conflict. + +1999-11-27 Kunihiro Ishiguro + + * kernel_socket.c (rtm_write): Change to use pre stored struct_dl + value for gateway specification. + +1999-11-25 Kunihiro Ishiguro + + * 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 + + * Makefile.am (EXTRA_DIST): Add rtread_getmsg.c. + +1999-11-21 Michael Handler + + * rtread_getmsg.c: Added for Solaris 2.6 support. + +1999-11-18 Kunihiro Ishiguro + + * 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 + + * client_main.c: Disable making obsolete zebra test `client' + command. + +1999-10-18 Kunihiro Ishiguro + + * 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 + + * 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 + + * Fix serious bug of IPv6 route deletion. + +1999-09-11 Kunihiro Ishiguro + + * ioctl.c (if_set_prefix): Properly set broadcast address. + +1999-09-04 Yasuhiro Ohara + + * rib.c (rib_add_ipv6, rib_delete_ipv6): now protocol daemons + can install connected route to kernel via zebra + +1999-08-24 VOP + + * rib.c: Include "sockunion.h" + +1999-08-22 Kunihiro Ishiguro + + * 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 + + * zebra.h (ZEBRA_INTERFACE_ADDRESS_ADD): + ZEBRA_INTERFACE_{ADD,DELETE} added. + +1999-08-15 Kunihiro Ishiguro + + * 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 + + * zebra.h: New Zebra message ZEBRA_INTERFACE_{ADD,DELETE} added. + +1999-08-09 Kunihiro Ishiguro + + * interface.h: New file. + * Makefile.am: Add interface.h + +1999-08-04 Yasuhiro Ohara + + * redistribute.c (zebra_redistribute): give ifindex to client. + +1999-08-02 Kunihiro Ishiguro + + * main.c (longopts): -k, --keep_kernel option added. + +1999-07-18 Yasuhiro Ohara + + * rt_socket.c (rtm_write): forgot closing socket bug fixed. + +1999-07-17 Yasuhiro Ohara + + * rib.c (show_ipv6_cmd): if rib is link show interface name. + +1999-07-17 Yasuhiro Ohara + + * rt_socket.c (rtm_write): use sockaddr_dl when null gateway. + +1999-07-16 Yasuhiro Ohara + + * rt_socket.c (rtm_write): ipv6 route table bug fixed. + +1999-07-15 Yasuhiro Ohara + + * zebra.c (zebra_read_ipv6): read link prefix from ospf6 support + +1999-07-15 Yasuhiro Ohara + + * rt_socket.c (kernel_rtm_ipv6): gate treatment bug fixed. + +1999-07-15 Kunihiro Ishiguro + + * if_sysctl.c (ifm_read): Clear sockunion argument before fetching + data. Suggested by "Chris P. Ross" + +1999-07-08 HEO SeonMeyong + + * interface.c (if_tun_add): Add KAME's gif tunnel setting codes. + +1999-06-26 Kunihiro Ishiguro + + * zebra.c (zebra_serv): Only accept loopback address connection. + +1999-06-25 Kunihiro Ishiguro + + * zebra.h (ZEBRA_ROUTE_EXTERNAL): Add zebra messages flags + +1999-06-17 Kunihiro Ishiguro + + * ipforward_proc.c: ipforward_on () and ipforward_off () added. + +1999-06-14 Kunihiro Ishiguro + + * ipforward_proc.c (ipforward_ipv6): Check for IPv6 forwarding + using /proc file system is added. + +1999-06-06 Kunihiro Ishiguro + + * if_ioctl.c (if_get_index): Interface index set bug is fixed by + adding #else at the middle of function. Suggested by David Luyer + . + +1999-05-29 + + * rt_ioctl.c: Comment out #include . + +1999-05-26 Kunihiro Ishiguro + + * zebra.h (ZEBRA_ROUTE_MAX): Add new define for the max value of + the sort of routes. + +1999-05-25 Patrick Koppen + + * 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 + + * redistribute.c (zebra_check_addr): Added for loopback address + check. + +1999-05-15 Kunihiro Ishiguro + + * 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 + + * 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 + + * rt_netlink.c: Change log () to zlog (). + +1999-05-07 + + * zebra.h (ZEBRA_ROUTE_OSPF6): Added for ospf6d route. + +1999-04-20 Kunihiro Ishiguro + + * interface.c: Add `no ip address' command. + +1999-04-10 Kunihiro Ishiguro + + * rt_netlink.c (kernel_read): Function added for asynchronous + zebra between kernel communication. + +1999-03-25 Kunihiro Ishiguro + + * rtread_sysctl.c (rtm_read): Fix address memcopy overrun bug. + Reported by Achim Patzner . + +1999-03-03 Kunihiro Ishiguro + + * Makefile.am: Install configuration sample with 600 permission. + +1999-03-02 Kunihiro Ishiguro + + * Makefile.am: Add -I.. to INCLUDES. + +1999-02-18 Peter Galbavy + + * syslog support added + +1999-02-17 Peter Galbavy + + * 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 + + * interface.c: Header include added. + +1998-12-14 Kunihiro Ishiguro + + * rt.h (kernel_delete_ipv6): change int index to unsigned int index. + +1998-12-13 Kunihiro Ishiguro + + * if_ioctl.c (interface_list_ioctl): interface flag must be + checked before check addresses of the interface. + +1998-12-07 Kunihiro Ishiguro + + * Makefile.am (INCLUDES): add @INCLUDES@ for Linux IPv6. + +1998-10-14 Kunihiro Ishiguro + + * ioctl.c: Linux version before 2.1.0 need interface route setup. + +1998-09-15 HEO SeonMeyong + + * change HYDRANGEA to KAME + +1998-09-01 Kunihiro Ishiguro + + * 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 + + * main.c (main): batch mode option '-b' added. + +1998-08-16 Kunihiro Ishiguro + + * 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 + + * rib.c (rib_add_ipv6): delete rib_add_in6. + +1998-07-27 Kunihiro Ishiguro + + * main.c: retain flag is added. + +1998-07-08 Kunihiro Ishiguro + + * rtable.[ch]: merged with rib.[ch] + +1998-07-07 Kunihiro Ishiguro + + * connected.h: renamed from ifa.h. + +1998-06-09 Kunihiro Ishiguro + + * 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 + + * rt_netlink.c: renamed from krt_netlink.c + + * fib.c: deleted. + * rt_kvm.c: deleted. + * rtread_getmsg.c: deleted. + +1998-06-07 Kunihiro Ishiguro + + * if.c (multicast): add multicast flag [un]set fucntion. + +1998-05-19 Yamshita TAKAO + + * 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 + + * zebra.c: Modify for compile on Solaris. + +1998-05-03 Kunihiro Ishiguro + + * main.c: change CONFDIR to SYSCONFDIR. + +1998-05-01 Kunihiro Ishiguro + + * .cvsignore: added. + +1998-04-02 Kunihiro Ishiguro + + * client.c: moves to ../lib. + +1998-03-30 Kunihiro Ishiguro + + * if_ioctl.c (if_get_addr): Change address copy from memcopy() to + structure assignment. + +1998-03-30 URA Hiroshi + + * if_sysctl.c (ifm_interface_add): sdl->sdl_data copy bug fixed. + +1998-02-23 "Hannes R. Boehm" + + * if.c (if_init): add config_exit_cmd and config_help_cmd. + +1998-01-24 Kunihiro Ishiguro + + * rt_ioctl.c (route_ioctl): EPERM treatment added. + +1998-01-05 Kunihiro Ishiguro + + * rt_socket.c (kernel_read): communication port zebra between + kernel is now handled by kernel_read. + +1998-01-02 Kunihiro Ishiguro + + * main.c (main): zebra [-P port] can specify vty port number. + +1997-12-25 Kunihiro Ishiguro + + * zebra.c: change select will be block. + +1997-12-04 Kunihiro Ishiguro + + * add static route treatment. + +1997-11-25 Kunihiro Ishiguro + + * rt_netlink.c: add netlink support over GNU/Linux system. + +1997-11-23 Kunihiro Ishiguro + + * all inet_addr is changed to inet_aton. + + * zebra.c (ip_route): add ip route command for static routes. + +1997-11-20 Kunihiro Ishiguro + + * if.c (if_flag_dump): Linux port of if_flag_dump and _vty. + +1997-11-19 Kunihiro Ishiguro + + * if.c: add interface command. + +1997-11-18 Kunihiro Ishiguro + + * ipforward_proc.c : Now works on Linux. + +1997-10-25 Kunihiro Ishiguro + + * command.c : add completion feature. + +1997-10-18 Kunihiro Ishiguro + + * vty.c (vty_command): add vty interface. + +1997-10-13 Kunihiro Ishiguro + + * zebra.c: add verbose mode. + +1997-10-12 SonMyong Ho + + * Hydrangea for FreeBSD supported + * in.h: add some prototype. + +1997-10-11 Kunihiro Ishiguro + + * rt_socket.c and rtread.c completely rewritten. + +1997-10-05 Kunihiro Ishiguro + + * rt_socket.c: rename kernel_sock to routing_socket + +1997-10-04 Kunihiro Ishiguro + + * if.c (if_new): interface structure change from linklist to vector. + +1997-10-03 Kunihiro Ishiguro + + * vector.c (vector_init): create vector related function + +1997-09-25 Kunihiro Ishiguro + + * 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 00000000..96bcec57 --- /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 00000000..164732bb --- /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 00000000..6214767d --- /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 00000000..ad35b383 --- /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 00000000..c319aac7 --- /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 + +#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 00000000..cb43074b --- /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 + +#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 00000000..7bf13baf --- /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 00000000..fc99623a --- /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 +#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 00000000..6eaa9572 --- /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 00000000..46f53011 --- /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 + +#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 + +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 00000000..c9c14760 --- /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 + +/* 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 00000000..117859fd --- /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 + +#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 00000000..1441dfcc --- /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 + +#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 00000000..5629ebb3 --- /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 + +#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 00000000..dbfa8221 --- /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 00000000..13afba29 --- /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 + +#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 00000000..157fc44e --- /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 00000000..a772337b --- /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 00000000..c79e7f1c --- /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 + +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 00000000..c872000a --- /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 + +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 00000000..eb8cef01 --- /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 + +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 00000000..99b0e1a8 --- /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 + +#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 00000000..828eb865 --- /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 + +#ifdef NRL +#include +#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 00000000..1b3bf232 --- /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 + +#include + +#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 00000000..0fad581d --- /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 00000000..23b2153e --- /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 00000000..a47f4f63 --- /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 + +#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 00000000..25d8b6de --- /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 + +#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 00000000..3731dab6 --- /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 + +#include +#include +#include + +#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 00000000..a3d4bad1 --- /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 + +#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 00000000..8b45cf3b --- /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 00000000..f5012610 --- /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 00000000..faaddab9 --- /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 00000000..d470572b --- /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 + +#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 + +#if defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1 +/* struct in6_rtmsg will be declared in net/route.h. */ +#else +#include +#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 00000000..baca1751 --- /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 + +/* 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, */ +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, */ +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 00000000..fe88be81 --- /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 + +#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 00000000..8f4b3778 --- /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 + +#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 00000000..859b2d7e --- /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 00000000..435eed80 --- /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 + +#include "prefix.h" +#include "log.h" +#include "if.h" + +#include "zebra/rib.h" + +#include +#include + +/* Solaris defines these in both and , sigh */ +#ifdef SUNOS_5 +#include +#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 +#include +#include + +/* 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 . "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 00000000..0b255a53 --- /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 + +/* 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 00000000..320152e7 --- /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 + +#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 00000000..970c0aa1 --- /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 + +#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 00000000..a5d0732f --- /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 00000000..ec07e2e3 --- /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 + +#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 00000000..d160bfa7 --- /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 + +#ifdef HAVE_SNMP +#include +#include +#include + +#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 00000000..f6e7f51d --- /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 + +#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 /, 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 /, 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 00000000..47114ab3 --- /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 + +#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 + +/* 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 00000000..c7622808 --- /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 */ -- cgit v1.2.1