diff options
author | paul <paul> | 2002-12-13 20:15:29 +0000 |
---|---|---|
committer | paul <paul> | 2002-12-13 20:15:29 +0000 |
commit | 718e3744195351130f4ce7dbe0613f4b3e23df93 (patch) | |
tree | bac2ad39971cd43f31241ef123bd4e470f695ac9 /ripd |
Initial revision
Diffstat (limited to 'ripd')
-rw-r--r-- | ripd/.cvsignore | 7 | ||||
-rw-r--r-- | ripd/ChangeLog | 749 | ||||
-rw-r--r-- | ripd/Makefile.am | 37 | ||||
-rw-r--r-- | ripd/Makefile.in | 489 | ||||
-rw-r--r-- | ripd/RIPv2-MIB.txt | 530 | ||||
-rw-r--r-- | ripd/rip_debug.c | 290 | ||||
-rw-r--r-- | ripd/rip_debug.h | 54 | ||||
-rw-r--r-- | ripd/rip_interface.c | 2001 | ||||
-rw-r--r-- | ripd/rip_main.c | 270 | ||||
-rw-r--r-- | ripd/rip_offset.c | 414 | ||||
-rw-r--r-- | ripd/rip_peer.c | 211 | ||||
-rw-r--r-- | ripd/rip_routemap.c | 898 | ||||
-rw-r--r-- | ripd/rip_snmp.c | 577 | ||||
-rw-r--r-- | ripd/rip_zebra.c | 691 | ||||
-rw-r--r-- | ripd/ripd.c | 3536 | ||||
-rw-r--r-- | ripd/ripd.conf.sample | 24 | ||||
-rw-r--r-- | ripd/ripd.h | 408 |
17 files changed, 11186 insertions, 0 deletions
diff --git a/ripd/.cvsignore b/ripd/.cvsignore new file mode 100644 index 00000000..1f91515a --- /dev/null +++ b/ripd/.cvsignore @@ -0,0 +1,7 @@ +Makefile +*.o +ripd +ripd.conf +tags +TAGS +.deps diff --git a/ripd/ChangeLog b/ripd/ChangeLog new file mode 100644 index 00000000..42fced50 --- /dev/null +++ b/ripd/ChangeLog @@ -0,0 +1,749 @@ +2002-07-07 Kunihiro Ishiguro <kunihiro@ipinfusion.com> + + * zebra-0.93 released. + +2002-06-30 Kunihiro Ishiguro <kunihiro@ipinfusion.com> + + * ripd.c (rip_output_process): When outgoing interface is same as + next hop interface, announce RIPv2 next hop otherwise set next hop + to 0. Revert previous change then take 6WIND way. + +2001-09-14 Akihiro Mizutani <mizutani@dml.com> + + * ripd.c: RIP enabled interface's route is advertised by default. + +2001-08-28 NOGUCHI Kay <kay@v6.access.co.jp> + + * rip_snmp.c (rip_ifaddr_delete): Add route_node_lookup() return + value check. + + * rip_interface.c (rip_multicast_leave): Fix bug of multiple IP + address on one interface multicast join/leave bug. + +2001-08-26 NOGUCHI Kay <kay@v6.access.co.jp> + + * rip_interface.c (no_rip_passive_interface): Add NO_STR. + +2001-08-19 Kunihiro Ishiguro <kunihiro@ipinfusion.com> + + * zebra-0.92a released. + +2001-08-15 Kunihiro Ishiguro <kunihiro@ipinfusion.com> + + * zebra-0.92 released. + +2001-06-17 Kunihiro Ishiguro <kunihiro@zebra.org> + + * rip_routemap.c (route_match_ip_address_prefix_list): Add match + ip next-hop prefix-list WORD. + +2001-02-18 Kunihiro Ishiguro <kunihiro@zebra.org> + + * rip_interface.c (rip_passive_interface_clean): Call + rip_passive_interface_apply_all. + +2001-02-12 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ripd.c (rip_response_process): Multicast address nexthop check + is moved from rip_nexthop_check. + +2001-02-08 Matthew Grant <grantma@anathoth.gen.nz> + + * rip_interface.c (ipv4_multicast_join): Use + setsockopt_multicast_ipv4. + (ipv4_multicast_leave): Likewise. + (rip_if_ipv4_address_check): Interface which has IPv4 address can + be enabled. + +2001-02-08 Kunihiro Ishiguro <kunihiro@zebra.org> + + * rip_interface.c (rip_interface_delete): To support pseudo + interface do not free interface structure. + * ripd.c (rip_output_process): If output interface is in simple + password authentication mode, we need space for authentication + data. + +2001-02-01 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ripd.c (rip_nexthop_check): Fix multicast address nexthop check. + + * zebra-0.91 is released. + +2001-01-27 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ripd.c (show_ip_rip): Show metric infinity route's timeout. + (rip_rte_process): If current route is metric infinity, route is + replaced with received rte. + (rip_redistribute_delete): When redistribute route is deleted, + perform poisoned reverse. + (rip_redistribute_withdraw): Likewise. + +2001-01-25 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ripd.c (rip_response_process): RIPv2 routing table entry with + non directly reachable nexthop was dropped. The code is changed + to treat it as 0.0.0.0 nexthop. + (rip_destination_check): Check net 0 address destination. + (rip_nexthop_check): New function for checking nexthop address + validity. + +2001-01-15 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ripd.c (rip_request_process): Triggered update only send changed + route. + + * rip_interface.c: Delete RIP_API part until new implementation + comes out. + + * rip_snmp.: Likewise. + + * rip_zebra.c: Likewise. + + * ripd.c: Likewise. + +2001-01-11 Kunihiro Ishiguro <kunihiro@zebra.org> + + * rip_interface.c (rip_if_init): Remove HAVE_IF_PSEUDO part. + +2001-01-09 Kunihiro Ishiguro <kunihiro@zebra.org> + + * zebra-0.90 is released. + +2001-01-01 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ripd.h (RIP_VTYSH_PATH): Change "/tmp/ripd" to "/tmp/.ripd". + +2000-12-25 David Lipovkov <davidl@nbase.co.il> + + * ripd.c (rip_rte_process): When a route is in garbage collection + process (invalid with metric 16) and a router receives the same + route with valid metric then route was not installed into zebra + rib, but only into ripd rib. Moreover , it will never get into + zebra rib, because ripd wrongly assumes it's already there. + (rip_redistribute_add): When doing redistribute into rip other + route (e.g. connected) and the same route exists in ripd rib we + changed it in place - bug. Now we don't forget to remove old route + from zebra. + (rip_timeout): When removing routes from zebra I made sure that we + remove route with the metric we have in zebra and not the new + one. It doesn't make a difference now,but could be significant + when multipath support is done. + +2000-12-25 David Lipovkov <davidl@nbase.co.il> + + * rip_zebra.c (rip_metric_unset): Fix bug of metric value unset. + +2000-11-25 Frank van Maarseveen <F.vanMaarseveen@inter.NL.net> + + * ripd.c (rip_request_process): Check passive flag of the + interface. + +2000-11-23 Frank van Maarseveen <F.vanMaarseveen@inter.NL.net> + + * rip_interface.c (rip_multicast_join): When IP_ADD_MEMBERSHIP + failed do not set runnning flag to the interface. + +2000-11-16 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ripd.c (rip_output_process): Memory leak related classfull + network generation is fixed. + +2000-11-16 Frank van Maarseveen <F.vanMaarseveen@inter.NL.net> + + * rip_interface.c (if_check_address): Obsolete pointopoint address + check is removed. + +2000-11-02 Frank van Maarseveen <F.vanMaarseveen@inter.NL.net> + + * rip_interface.c (if_check_address): Add pointopoint address + check. + (rip_interface_up): Add check for passive interface when interface + goes up. + +2000-10-23 Jochen Friedrich <jochen@scram.de> + + * rip_snmp.c: rip_oid and ripd_oid are used in smux_open after it + is registered. So those variables must be static. + +2000-10-19 Kunihiro Ishiguro <kunihiro@zebra.org> + + * rip_interface.c: Change to "no ip rip (send|receive)" command + accept version number argument. + +2000-10-17 Akihiro Mizutani <mizutani@dml.com> + + * rip_routemap.c (route_set_ip_nexthop_compile): Change "match ip + next-hop" from IP address to access-list name. + +2000-10-17 Kunihiro Ishiguro <kunihiro@zebra.org> + + * rip_peer.c: Change ot use linklist.c instaed of newlist.c. + +2000-10-16 Kunihiro Ishiguro <kunihiro@zebra.org> + + * rip_offset.c: Change to use linklist.c instead of newlist.c. + +2000-10-02 Kunihiro Ishiguro <kunihiro@zebra.org> + + * zebra-0.89 is released. + +2000-09-26 Akihiro Mizutani <mizutani@dml.com> + + * rip_routemap.c (match_ip_nexthop): Add next-hop format check. + +2000-09-18 David Lipovkov <dlipovkov@OpticalAccess.com> + + * rip_interface.c (ripd_api_get_if_rx_version): Corrects rip SNMP + and rip API functions dealing with rip version. + + * rip_snmp.c (Status_Valid): SNMPv2-TC TEXTUAL-CONVENTION. + +2000-09-10 Kunihiro Ishiguro <kunihiro@zebra.org> + + * rip_snmp.c (rip2IfLookup): Use rip_ifaddr_lookup_next() instead + of rip_if_lookup_next(). + + * rip_interface.c (rip_enable_network_lookup): Interface enable + check by interface's address with /32 prefix. + + * ripd.c (rip_read): When RIP is configured with authentication + and no authentication in incoming packet, drop the packet. + + * rip_interface.c (rip_interface_reset): RIP_AUTH_SIMPLE_PASSWORD + is default mode of authentication. + (rip_interface_new): Likewise. + (no_ip_rip_authentication_mode): Likewise. + + * ripd.c (rip_read): Likewise. + +2000-09-10 David Lipovkov <davidl@nbase.co.il> + + * rip_snmp.c: Set ASN_INTEGER v->type where it is needed. + +2000-09-08 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ripd.c (rip_auth_simple_password): Simple password + authentication using key-chain. + (rip_write_rte): Likewise. + + * rip_interface.c (ip_rip_authentication_key_chain): Add check for + authentication string configuration. + +2000-09-08 Akihiro Mizutani <mizutani@dml.com> + + * ripd.c (rip_write_rte): Add check for ri->auth_str. + +2000-09-07 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ripd_api.h: New file is added. + +2000-08-22 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ripd.c (rip_rte_process): rip_route_process() is renamed to + rip_rte_process() to clarify meanings of the function. + rip_route_process() is newly added to process RIP route selection. + +2000-08-18 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ripd.c (rip_incoming_filter): Extract incoming filter code to + function from rip_route_process(). Add check for all interface + filter. + (rip_outgoing_filter): Extract incoming filter code to function + from rip_output_process(). Add check for all interface filter. + + * rip_zebra.c (rip_redistribute_clean): Reset redistribute status + when "no router rip" is performed. + + * rip_interface.c (rip_interface_clean): Reset interface's RIP + enable status. + +2000-08-17 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ripd.c (rip_route_process): When metric infinity is received the + route is removed from service immediately. + (rip_timeout): Likewise. + (rip_garbage_collect): Do not delete route in garbage collection. + (rip_output_process): Check metric_out exceed metric infinity. + + * zebra-0.88 is released. + +2000-08-15 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ripd.c (rip_distance_apply): Unlock node when there is matched + node. + +2000-08-13 Akihiro Mizutani <mizutani@dml.com> + + * rip_routemap.c (match_ip_nexthop): Add check for IP address + validness. + (no_set_metric): Add new ALIAS. + +2000-08-07 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ripd.h (struct rip ): Add distance. + +2000-08-05 Kunihiro Ishiguro <kunihiro@zebra.org> + + * rip_zebra.c (rip_zebra_ipv4_add): Use new Zebra api to register + routes. Pass RIP metric value to zebra. + +2000-08-02 Kunihiro Ishiguro <kunihiro@zebra.org> + + * rip_main.c (main): Make struct thread thread from global + variable to local variable in main. + +2000-08-06 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ripd.c (rip_packet_dump): Add MD5 authentication dump function. + (rip_auth_md5): RIP MD5 authentication packet receive works. + +2000-08-02 David Lipovkov <davidl@nbase.co.il> + + * rip_interface.c (rip_if_init): Install interface "pseudo" + commands. + (rip_interface_delete): Do not call if_delete() when interface is + pseudo interface. + +2000-07-31 Kunihiro Ishiguro <kunihiro@zebra.org> + + * rip_interface.c (ip_rip_authentication_mode): "ip rip + authentication mode (md5|text)" is added. + (ip_rip_authentication_key_chain): "ip rip authentication + key-chain KEY-CHAIN" is added. + (rip_interface_clean): Clean all interface configuration. + (rip_interface_reset): Reset all interface configuration. + (rip_clean_network): Clean rip_enable_network. + + * ripd.h (struct rip_interface): Add key_chain member. + + * ripd.c: Include md5-gnu.h. + +2000-07-30 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ripd.h (RIP_NO_AUTH): Change RIP_NO_AUTH value from 1 to 0. + + * ripd.c (rip_authentication): Use RIP_AUTH_SIMPLE_PASSWORD + instead of raw value 2. + (rip_write_rte): Likewise. + (rip_write_rte): Check ri->auth_type instead of ri->auth_str. + +2000-07-30 David Lipovkov <davidl@nbase.co.il> + + * rip_interface.c (rip_if_down): Do not delete ZEBRA_ROUTE_KERNEL + route. + +2000-07-27 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ripd.c (rip_update_process): Add "passive-interface" command. + + * ripd.h (struct rip_interface): Add passive member to struct + rip_interface. + +2000-07-24 Kunihiro Ishiguro <kunihiro@zebra.org> + + * rip_interface.c (rip_if_init): Multiple RIP routes for one + prefix change. The codes are enclosed by #ifdef NEW_RIP_TABLE. + +2000-07-24 Akihiro Mizutani <mizutani@dml.com> + + * rip_interface.c (rip_if_init): Use install_default() for + INTERFACE_NODE. + +2000-07-24 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ripd.c: First update timer will be invoked in two seconds. + +2000-07-09 Jochen Friedrich <jochen@scram.de> + + * rip_snmp.c: Local function definitions to static. Add INTEGER + ASN_INTEGER and TIMETICKS ASN_TIMETICKS definition. + (rip2PeerLookup): Peer with domain lookup implemented. + (rip2PeerTable): Temporary disable RIP2PEERLASTUPDATE value + support due to unknown SNMP agent startup time. + +2000-07-05 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ripd.h: Sweep obsolete definitions. + + * rip_interface.c (rip_split_horizon): Add "ip split-horizon" + command. + + * ripd.c (rip_output_process): Remove split_horizon argument. + (rip_update_process): Likewise. + + * ripd.h (struct rip_interface): Add split_horizon flag to struct + rip_interface. + +2000-07-04 Akihiro Mizutani <mizutani@dml.com> + + * ripd.c (rip_version): Change VERSION to <1-2>. + Add "no version" command. + +2000-07-03 Kunihiro Ishiguro <kunihiro@zebra.org> + + * rip_zebra.c (rip_redistribute_type_metric): "redistribute TYPE + metric <0-16>" command is added. + + * rip_routemap.c (route_set_metric): Set metric_set when metric is + modified. + + * ripd.h (struct rip_info): To check route-map set metric or not, + new member metric_set is added to struct rip_info. + + * ripd.c (rip_route_process): Move metric handling code from + rip_response_process() to rip_route_process(). + (rip_output_process): Set output offset-list metric. + +2000-07-02 Kunihiro Ishiguro <kunihiro@zebra.org> + + * rip_offset.c (rip_offset_list): New file for offset-list. + +2000-07-02 Akihiro Mizutani <mizutani@dml.com> + + * ripd.h (struct rip ): Add default_metric. + + * ripd.c (rip_default_metric): "default-metric <1-16>" command is + added. + (config_write_rip): Change configuration order. + + * rip_zebra.c: Fix help strings. + +2000-07-02 David Lipovkov <davidl@nbase.co.il> + + * rip_interface.c (rip_if_init): Add IF_DELETE_HOOK. + +2000-07-01 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ripd.c (rip_output_process): If specified route-map does not + exist, it treated as deny all. + +2000-06-30 Kunihiro Ishiguro <kunihiro@zebra.org> + + * rip_routemap.c (rip_route_map_init): Call rip_route_map_update + when route-map is deleted. + +2000-06-28 Kunihiro Ishiguro <kunihiro@zebra.org> + + * rip_routemap.c (set_metric): For consistency with bgpd's set + metric, value range is set to <0-4294967295>. + +2000-06-28 David Lipovkov <davidl@nbase.co.il> + + * rip_routemap.c (rip_route_map_update): Add check for rip is + enabled or not for avoid core dump. + + * rip_debug.c (debug_rip_packet_direct): Fix bug of setting + rip_debug_packet flag. + +2000-06-13 David Lipovkov <davidl@nbase.co.il> + + * rip_interface.c (rip_interface_delete): All work is done in + rip_if_down(). + +2000-06-06 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ripd.c (rip_redistribute_delete): Fix bug of missing + route_unlock_node() when redistribute route is not found. + +2000-06-05 Akihirof Mizutani <mizutani@dml.com> + + * rip_debug.c (rip_debug_init): Disable show debugging in + VIEW_NODE like other protocol daemon. + + * rip_routemap.c: Change command argument to more comprehensive. + + METRIC -> <0-16> + IFNAME -> WORD + IP_ADDR -> A.B.C.D + ACCSESS_LIST -> WORD + +2000-06-05 David Lipovkov <davidl@nbase.co.il> + + * rip_interface.c (rip_interface_delete): Delete all routes + include static and kernel through the interface , because even if + the interface is added again there is no guarantee that it will + get the same ifindex as before. + +2000-05-31 Akihirof Mizutani <mizutani@dml.com> + + * rip_debug.c: Fix rip debug help string. + +2000-04-27 Mirko Karanovic <mkaranov@torsel.alcatel.com> + + * rip_interface.c (rip_interface_down): Remove interface from + multicast group when interface goes down. + +2000-04-03 David Lipovkov <davidl@nbase.co.il> + + * rip_interface.c (rip_interface_down): Implemented rip functions + for interface up/down events: rip_interface_up() and + rip_interface_down() + +2000-03-16 David Lipovkov <davidl@nbase.co.il> + + * rip_zebra.c (rip_zclient_init): Added rip functions for + interface up/down events. + +2000-02-15 Hidetoshi Shimokawa <simokawa@sat.t.u-tokyo.ac.jp> + + * ripd.c (rip_write_rte): "set metic" in route-map has no effect + for RIPv1 in ripd. It worked fine for RIPv2. + +2000-01-17 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ripd.c (show_ip_protocols_rip): Fix bug of "show ip protocls" + mis-display RIP version. + + * ripd.h (struct rip_peer): Add timeout thread to rip_peer + structure. + +2000-01-16 Kunihiro Ishiguro <kunihiro@zebra.org> + + * rip_peer.c: Add new file for supporting RIP peer. + +1999-12-26 David Lipovkov <davidl@nbase.co.il> + + * ripd.c (rip_authentication): RIP authantication string is 16 + bytes long. + +1999-12-10 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ripd.c (rip_read): Add check for minimum packet length. + Authentication check is moved from rip_process_response() to + rip_read(). Patch from David Lipovkov <davidl@nbase.co.il> is + applied then add rte number check by Kunihiro Ishiguro + <kunihiro@zebra.org>. + +1999-12-07 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ripd.c (rip_response_process): In case of packet is RIPv2 and + network is non zero and netmask is zero, apply netmask rule as + same as RIPv1. + +1999-11-06 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ripd.c (rip_timers): Fix bug of timers basic argument format. + +1999-11-03 Kunihiro Ishiguro <kunihiro@zebra.org> + + * rip_snmp.c (rip2IfConfAddress): Forgot to include + RIP2IFCONFDOMAIN. + +1999-10-28 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ripd.h (struct rip_peer): New structure added. + +1999-10-26 Kunihiro Ishiguro <kunihiro@zebra.org> + + * rip_zebra.c (rip_zebra_ipv4_add): Increment + rip_global_route_changes when route change occur. + (rip_zebra_ipv4_delete): Likewise. + + * ripd.c (rip_request_process): Increment rip_global_queries when + reply to the query is sent. + +1999-10-25 Kunihiro Ishiguro <kunihiro@zebra.org> + + * rip_debug.c (rip_debug_reset): Reset function added. + + * ripd.c (rip_update_process): Logging bug is fixed. + +1999-10-10 Marc Boucher <marc@mbsi.ca> + + * ripd.c (config_write_rip): Add config_write_distribute() call. + +1999-09-29 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ripd.c (rip_distribute_update): Fix bug of access-list + prefix-list updates. + +1999-09-10 VOP <vop@unity.net> + + * rip_zebra.c: Add redistribute route-map feature. + +1999-09-10 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ripd.c (rip_response_process): Add check for given prefix is + given mask applied one. + +1999-09-03 VOP <vop@unity.net> + + * rip_interface.c (rip_interface_multicast_set): Bug fix about + setting multicast interface. + +1999-09-02 VOP <vop@unity.net> + + * rip_routemap.c: New file added. + +1999-09-02 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ripd.c (show_ip_protocols_rip): Show next update time. + (show_ip_protocols_rip): Show redistribute information. + +1999-08-25 Kunihiro Ishiguro <kunihiro@zebra.org> + + * RIPv2-MIB.txt: New file added. + + * rip_snmp.c: New file added. + +1999-08-24 Kunihiro Ishiguro <kunihiro@zebra.org> + + * rip_interface.c (ip_rip_authentication_string): RIPv2 + authentication command is added. + +1999-08-23 Kunihiro Ishiguro <kunihiro@zebra.org> + + * rip_interface.c (rip_interface_multicast_set): Process of + setting IP_MULTICAST_IF on specific interface. + + * ripd.c (rip_read): Add packet size check. + +1999-08-16 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ripd.c (rip_request_process): Fill in RIP_METRIC_INFINITY with + network byte order using htonl (). + (rip_response_process): Pass host byte order address to IN_CLASSC + and IN_CLASSB macro. + +1999-08-08 davidm@nbase.co.il (David Mozes) + + * rip_zebra.c (rip_zebra_read_ipv4): Fix split horizon problem. + +1999-07-03 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ripd.c (rip_timer_set): Function added. + +1999-07-01 Kunihiro Ishiguro <kunihiro@zebra.org> + + * rip_debug.c: New file added. + rip_debug.h: New file added. + +1999-07-01 Rick Payne <rickp@rossfell.co.uk> + + * rip_zebra.c (zebra_init): Install standard commands to + ZEBRA_NODE. + +1999-06-01 David Luyer <luyer@ucs.uwa.edu.au> + + * ripd.c (rip_process_route): Add support for RIP version 1. + +1999-05-29 Kunihiro Ishiguro <kunihiro@zebra.org> + + * rip_zebra.c: Change to use lib/zclient.[ch]. + +1999-05-20 Carlos Alberto Barcenilla <barce@frlp.utn.edu.ar> + + * ripd.c (rip_add_route): Change the existance route's metric check + to the condition specified by RFC2453. + +1999-05-17 Carlos Alberto Barcenilla <barce@frlp.utn.edu.ar> + + * ripd.c (rip_process_route): Add the if metric to the route metric. + + * ripd.c (rip_add_route): Deleted add if metric to the route. + +1999-05-16 Carlos Alberto Barcenilla <barce@frlp.utn.edu.ar> + + * rip_interface.c (if_valid_neighbor): New function. + + * ripd.c (rip_process_route): Added check whether the datagram + is from a valid neighbor. + +1999-05-15 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ripd.c (rip_process_route): Set interface pointer to rinfo. + +1999-05-15 Carlos Alberto Barcenilla <barce@frlp.utn.edu.ar> + + * ripd.c (rip_check_address): Unicast and not net 0 or 127 check + added. + +1999-05-14 Stephen R. van den Berg <srb@cuci.nl> + + * rip_main.c (signal_init): SIGTERM call sigint. + (sigint): Loggging more better message. + +1999-05-10 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ripd.c (rip_add_route): Fix previous route_unlock_node() chenge. + + * rip_main.c (main): Change default zlog output to ZLOG_STDOUT for + debugging. + +1999-05-09 Patrick Koppen <koppen@rhrk.uni-kl.de> + + * rip_interface.c (rip_request): Fix old semantics for fetching + connected address. + + * ripd.c (rip_add_route): Update timer when the route is updated. + +1999-05-09 Carlos Alberto Barcenilla <barce@frlp.utn.edu.ar> + + * rip_zebra.c (struct zebra): Add ridist_static, ridist_connect, + redist_rip, redist_ripng. + + * rip_zebra.c (zebra_create): Updated for current zebra method. + + * ripd.c (rip_add_route): Add missing route_unlock_node(). + +1999-05-03 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ripd.c (rip_add_route): Add metric check. Reported by Carlos + Alberto Barcenilla <barce@frlp.utn.edu.ar>. + +1999-02-18 Peter Galbavy <Peter.Galbavy@knowledge.com> + + * syslog support added + +1998-12-13 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ripd.c (rip_announce_func): Apply new lib functions. + +1998-12-09 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ripd.c (config_write_rip): Delete vector v argument. + * rip_zebra.c (config_write_zebra): Likewise. + * rip_interface.c (interface_config_write): Likewise. + +1998-09-07 Kunihiro Ishiguro <kunihiro@zebra.org> + + * rip_announce.c (rip_rib_close): When ripd terminates delete all + added route. + +1998-09-01 Kunihiro Ishiguro <kunihiro@zebra.org> + + * rip_interface.c: return read packet size. + +1998-05-18 Yamshita TAKAO <jargon@lares.dti.ne.jp> + + * ripd.h: Modify for compile on Solaris. + +1998-05-07 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ripd.c: DEFUN function return CMD_SUCCESS. + change xmalloc to XMALLOC macro. + +1998-05-03 Kunihiro Ishiguro <kunihiro@zebra.org> + + * rip_main.c: change CONFDIR to SYSCONFDIR. + +1998-05-01 Kunihiro Ishiguro <kunihiro@zebra.org> + + * .cvsignore: added. + +1998-02-04 Kunihiro Ishiguro <kunihiro@zebra.org> + + * rip_interface.c (config_write_interface): correct ADVERTISE spell. + + * rip_main.c (main): add usage() and make cleanup. + +1998-01-05 Kunihiro Ishiguro <kunihiro@zebra.org> + + * ripd.c (rip_version): add rip version command. + +1998-01-04 Kunihiro Ishiguro <kunihiro@zebra.org> + + * rip_interface.c (zebra_get_interface): added to get + interface's information. + + * ChangeLog: create. diff --git a/ripd/Makefile.am b/ripd/Makefile.am new file mode 100644 index 00000000..fd254851 --- /dev/null +++ b/ripd/Makefile.am @@ -0,0 +1,37 @@ +## Process this file with automake to produce Makefile.in. + +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib +DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" +INSTALL_SDATA=@INSTALL@ -m 600 + +noinst_LIBRARIES = librip.a +sbin_PROGRAMS = ripd + +librip_a_SOURCES = \ + ripd.c rip_zebra.c rip_interface.c rip_debug.c rip_snmp.c \ + rip_routemap.c rip_peer.c rip_offset.c + +noinst_HEADERS = \ + ripd.h rip_debug.h + +ripd_SOURCES = \ + rip_main.c $(librip_a_SOURCES) + +ripd_LDADD = ../lib/libzebra.a + +sysconf_DATA = ripd.conf.sample + +EXTRA_DIST = $(sysconf_DATA) RIPv2-MIB.txt + +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/ripd/Makefile.in b/ripd/Makefile.in new file mode 100644 index 00000000..fa355ef8 --- /dev/null +++ b/ripd/Makefile.in @@ -0,0 +1,489 @@ +# 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)/\" +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 + +noinst_LIBRARIES = librip.a +sbin_PROGRAMS = ripd + +librip_a_SOURCES = \ + ripd.c rip_zebra.c rip_interface.c rip_debug.c rip_snmp.c \ + rip_routemap.c rip_peer.c rip_offset.c + + +noinst_HEADERS = \ + ripd.h rip_debug.h + + +ripd_SOURCES = \ + rip_main.c $(librip_a_SOURCES) + + +ripd_LDADD = ../lib/libzebra.a + +sysconf_DATA = ripd.conf.sample + +EXTRA_DIST = $(sysconf_DATA) RIPv2-MIB.txt +subdir = ripd +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +LIBRARIES = $(noinst_LIBRARIES) + +librip_a_AR = $(AR) cru +librip_a_LIBADD = +am_librip_a_OBJECTS = ripd.$(OBJEXT) rip_zebra.$(OBJEXT) \ + rip_interface.$(OBJEXT) rip_debug.$(OBJEXT) rip_snmp.$(OBJEXT) \ + rip_routemap.$(OBJEXT) rip_peer.$(OBJEXT) rip_offset.$(OBJEXT) +librip_a_OBJECTS = $(am_librip_a_OBJECTS) +sbin_PROGRAMS = ripd$(EXEEXT) +PROGRAMS = $(sbin_PROGRAMS) + +am__objects_1 = ripd.$(OBJEXT) rip_zebra.$(OBJEXT) \ + rip_interface.$(OBJEXT) rip_debug.$(OBJEXT) rip_snmp.$(OBJEXT) \ + rip_routemap.$(OBJEXT) rip_peer.$(OBJEXT) rip_offset.$(OBJEXT) +am_ripd_OBJECTS = rip_main.$(OBJEXT) $(am__objects_1) +ripd_OBJECTS = $(am_ripd_OBJECTS) +ripd_DEPENDENCIES = ../lib/libzebra.a +ripd_LDFLAGS = + +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/rip_debug.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/rip_interface.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/rip_main.Po ./$(DEPDIR)/rip_offset.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/rip_peer.Po ./$(DEPDIR)/rip_routemap.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/rip_snmp.Po ./$(DEPDIR)/rip_zebra.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ripd.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 = $(librip_a_SOURCES) $(ripd_SOURCES) +DATA = $(sysconf_DATA) + +HEADERS = $(noinst_HEADERS) + +DIST_COMMON = $(noinst_HEADERS) ChangeLog Makefile.am Makefile.in +SOURCES = $(librip_a_SOURCES) $(ripd_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 ripd/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +librip.a: $(librip_a_OBJECTS) $(librip_a_DEPENDENCIES) + -rm -f librip.a + $(librip_a_AR) librip.a $(librip_a_OBJECTS) $(librip_a_LIBADD) + $(RANLIB) librip.a +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) +ripd$(EXEEXT): $(ripd_OBJECTS) $(ripd_DEPENDENCIES) + @rm -f ripd$(EXEEXT) + $(LINK) $(ripd_LDFLAGS) $(ripd_OBJECTS) $(ripd_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) core *.core + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rip_debug.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rip_interface.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rip_main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rip_offset.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rip_peer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rip_routemap.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rip_snmp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rip_zebra.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ripd.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 $(LIBRARIES) $(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-noinstLIBRARIES 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-noinstLIBRARIES 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 + + +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/ripd/RIPv2-MIB.txt b/ripd/RIPv2-MIB.txt new file mode 100644 index 00000000..6c92fb5f --- /dev/null +++ b/ripd/RIPv2-MIB.txt @@ -0,0 +1,530 @@ + RIPv2-MIB DEFINITIONS ::= BEGIN + + IMPORTS + MODULE-IDENTITY, OBJECT-TYPE, Counter32, + TimeTicks, IpAddress FROM SNMPv2-SMI + TEXTUAL-CONVENTION, RowStatus FROM SNMPv2-TC + MODULE-COMPLIANCE, OBJECT-GROUP FROM SNMPv2-CONF + mib-2 FROM RFC1213-MIB; + + -- This MIB module uses the extended OBJECT-TYPE macro as + -- defined in [9]. + + rip2 MODULE-IDENTITY + LAST-UPDATED "9407272253Z" -- Wed Jul 27 22:53:04 PDT 1994 + ORGANIZATION "IETF RIP-II Working Group" + CONTACT-INFO + " Fred Baker + Postal: Cisco Systems + 519 Lado Drive + Santa Barbara, California 93111 + Tel: +1 805 681 0115 + E-Mail: fbaker@cisco.com + + Postal: Gary Malkin + Xylogics, Inc. + 53 Third Avenue + Burlington, MA 01803 + + Phone: (617) 272-8140 + EMail: gmalkin@Xylogics.COM" + DESCRIPTION + "The MIB module to describe the RIP2 Version 2 Protocol" + ::= { mib-2 23 } + + -- RIP-2 Management Information Base + + -- the RouteTag type represents the contents of the + -- Route Domain field in the packet header or route entry. + -- The use of the Route Domain is deprecated. + + RouteTag ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "the RouteTag type represents the contents of the Route Domain + field in the packet header or route entry" + SYNTAX OCTET STRING (SIZE (2)) + +--4.1 Global Counters + +-- The RIP-2 Globals Group. +-- Implementation of this group is mandatory for systems +-- which implement RIP-2. + +-- These counters are intended to facilitate debugging quickly +-- changing routes or failing neighbors + +rip2Globals OBJECT IDENTIFIER ::= { rip2 1 } + + rip2GlobalRouteChanges OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of route changes made to the IP Route + Database by RIP. This does not include the refresh + of a route's age." + ::= { rip2Globals 1 } + + rip2GlobalQueries OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of responses sent to RIP queries + from other systems." + ::= { rip2Globals 2 } + +--4.2 RIP Interface Tables + +-- RIP Interfaces Groups +-- Implementation of these Groups is mandatory for systems +-- which implement RIP-2. + +-- The RIP Interface Status Table. + + rip2IfStatTable OBJECT-TYPE + SYNTAX SEQUENCE OF Rip2IfStatEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A list of subnets which require separate + status monitoring in RIP." + ::= { rip2 2 } + + rip2IfStatEntry OBJECT-TYPE + SYNTAX Rip2IfStatEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A Single Routing Domain in a single Subnet." + INDEX { rip2IfStatAddress } + ::= { rip2IfStatTable 1 } + + Rip2IfStatEntry ::= + SEQUENCE { + rip2IfStatAddress + IpAddress, + rip2IfStatRcvBadPackets + Counter32, + rip2IfStatRcvBadRoutes + Counter32, + rip2IfStatSentUpdates + Counter32, + rip2IfStatStatus + RowStatus + } + + rip2IfStatAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP Address of this system on the indicated + subnet. For unnumbered interfaces, the value 0.0.0.N, + where the least significant 24 bits (N) is the ifIndex + for the IP Interface in network byte order." + ::= { rip2IfStatEntry 1 } + + rip2IfStatRcvBadPackets OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of RIP response packets received by + the RIP process which were subsequently discarded + for any reason (e.g. a version 0 packet, or an + unknown command type)." + ::= { rip2IfStatEntry 2 } + + rip2IfStatRcvBadRoutes OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of routes, in valid RIP packets, + which were ignored for any reason (e.g. unknown + address family, or invalid metric)." + ::= { rip2IfStatEntry 3 } + + rip2IfStatSentUpdates OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of triggered RIP updates actually + sent on this interface. This explicitly does + NOT include full updates sent containing new + information." + ::= { rip2IfStatEntry 4 } + + rip2IfStatStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "Writing invalid has the effect of deleting + this interface." + ::= { rip2IfStatEntry 5 } + +-- The RIP Interface Configuration Table. + + rip2IfConfTable OBJECT-TYPE + SYNTAX SEQUENCE OF Rip2IfConfEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A list of subnets which require separate + configuration in RIP." + ::= { rip2 3 } + + rip2IfConfEntry OBJECT-TYPE + SYNTAX Rip2IfConfEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A Single Routing Domain in a single Subnet." + INDEX { rip2IfConfAddress } + ::= { rip2IfConfTable 1 } + + Rip2IfConfEntry ::= + SEQUENCE { + rip2IfConfAddress + IpAddress, + rip2IfConfDomain + RouteTag, + rip2IfConfAuthType + INTEGER, + rip2IfConfAuthKey + OCTET STRING (SIZE(0..16)), + rip2IfConfSend + INTEGER, + rip2IfConfReceive + INTEGER, + rip2IfConfDefaultMetric + INTEGER, + rip2IfConfStatus + RowStatus, + rip2IfConfSrcAddress + IpAddress + } + + rip2IfConfAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP Address of this system on the indicated + subnet. For unnumbered interfaces, the value 0.0.0.N, + where the least significant 24 bits (N) is the ifIndex + for the IP Interface in network byte order." + ::= { rip2IfConfEntry 1 } + + rip2IfConfDomain OBJECT-TYPE + SYNTAX RouteTag + MAX-ACCESS read-create + STATUS obsolete + DESCRIPTION + "Value inserted into the Routing Domain field + of all RIP packets sent on this interface." + DEFVAL { '0000'h } + ::= { rip2IfConfEntry 2 } + + rip2IfConfAuthType OBJECT-TYPE + SYNTAX INTEGER { + noAuthentication (1), + simplePassword (2), + md5 (3) + } + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The type of Authentication used on this + interface." + DEFVAL { noAuthentication } + ::= { rip2IfConfEntry 3 } + + rip2IfConfAuthKey OBJECT-TYPE + SYNTAX OCTET STRING (SIZE(0..16)) + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The value to be used as the Authentication Key + whenever the corresponding instance of + rip2IfConfAuthType has a value other than + noAuthentication. A modification of the corresponding + instance of rip2IfConfAuthType does not modify + the rip2IfConfAuthKey value. If a string shorter + than 16 octets is supplied, it will be left- + justified and padded to 16 octets, on the right, + with nulls (0x00). + + Reading this object always results in an OCTET + STRING of length zero; authentication may not + be bypassed by reading the MIB object." + DEFVAL { ''h } + ::= { rip2IfConfEntry 4 } + + rip2IfConfSend OBJECT-TYPE + SYNTAX INTEGER { + doNotSend (1), + ripVersion1 (2), + rip1Compatible (3), + ripVersion2 (4), + ripV1Demand (5), + ripV2Demand (6) + } + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "What the router sends on this interface. + ripVersion1 implies sending RIP updates compliant + with RFC 1058. rip1Compatible implies + broadcasting RIP-2 updates using RFC 1058 route + subsumption rules. ripVersion2 implies + multicasting RIP-2 updates. ripV1Demand indicates + the use of Demand RIP on a WAN interface under RIP + Version 1 rules. ripV2Demand indicates the use of + Demand RIP on a WAN interface under Version 2 rules." + DEFVAL { rip1Compatible } + ::= { rip2IfConfEntry 5 } + + rip2IfConfReceive OBJECT-TYPE + SYNTAX INTEGER { + rip1 (1), + rip2 (2), + rip1OrRip2 (3), + doNotRecieve (4) + } + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This indicates which version of RIP updates + are to be accepted. Note that rip2 and + rip1OrRip2 implies reception of multicast + packets." + DEFVAL { rip1OrRip2 } + ::= { rip2IfConfEntry 6 } + + rip2IfConfDefaultMetric OBJECT-TYPE + SYNTAX INTEGER ( 0..15 ) + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This variable indicates the metric that is to + be used for the default route entry in RIP updates + originated on this interface. A value of zero + indicates that no default route should be + originated; in this case, a default route via + another router may be propagated." + ::= { rip2IfConfEntry 7 } + + rip2IfConfStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "Writing invalid has the effect of deleting + this interface." + ::= { rip2IfConfEntry 8 } + + rip2IfConfSrcAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The IP Address this system will use as a source + address on this interface. If it is a numbered + interface, this MUST be the same value as + rip2IfConfAddress. On unnumbered interfaces, + it must be the value of rip2IfConfAddress for + some interface on the system." + ::= { rip2IfConfEntry 9 } + +--4.3 Peer Table + +-- Peer Table + +-- The RIP Peer Group +-- Implementation of this Group is Optional + +-- This group provides information about active peer +-- relationships intended to assist in debugging. An +-- active peer is a router from which a valid RIP +-- updated has been heard in the last 180 seconds. + + rip2PeerTable OBJECT-TYPE + SYNTAX SEQUENCE OF Rip2PeerEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A list of RIP Peers." + ::= { rip2 4 } + + rip2PeerEntry OBJECT-TYPE + SYNTAX Rip2PeerEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Information regarding a single routing peer." + INDEX { rip2PeerAddress, rip2PeerDomain } + ::= { rip2PeerTable 1 } + + Rip2PeerEntry ::= + SEQUENCE { + rip2PeerAddress + IpAddress, + rip2PeerDomain + RouteTag, + rip2PeerLastUpdate + TimeTicks, + rip2PeerVersion + INTEGER, + rip2PeerRcvBadPackets + Counter32, + rip2PeerRcvBadRoutes + Counter32 + } + + rip2PeerAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP Address that the peer is using as its source + address. Note that on an unnumbered link, this may + not be a member of any subnet on the system." + ::= { rip2PeerEntry 1 } + + rip2PeerDomain OBJECT-TYPE + SYNTAX RouteTag + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The value in the Routing Domain field in RIP + packets received from the peer. As domain suuport + is deprecated, this must be zero." + ::= { rip2PeerEntry 2 } + + rip2PeerLastUpdate OBJECT-TYPE + SYNTAX TimeTicks + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The value of sysUpTime when the most recent + RIP update was received from this system." + ::= { rip2PeerEntry 3 } + + rip2PeerVersion OBJECT-TYPE + SYNTAX INTEGER ( 0..255 ) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The RIP version number in the header of the + last RIP packet received." + ::= { rip2PeerEntry 4 } + + rip2PeerRcvBadPackets OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of RIP response packets from this + peer discarded as invalid." + ::= { rip2PeerEntry 5 } + + + rip2PeerRcvBadRoutes OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of routes from this peer that were + ignored because the entry format was invalid." + ::= { rip2PeerEntry 6 } + +-- conformance information + +rip2Conformance OBJECT IDENTIFIER ::= { rip2 5 } + +rip2Groups OBJECT IDENTIFIER ::= { rip2Conformance 1 } +rip2Compliances OBJECT IDENTIFIER ::= { rip2Conformance 2 } + +-- compliance statements +rip2Compliance MODULE-COMPLIANCE + STATUS current + DESCRIPTION + "The compliance statement " + MODULE -- this module + MANDATORY-GROUPS { + rip2GlobalGroup, + rip2IfStatGroup, + rip2IfConfGroup, + rip2PeerGroup + } + GROUP rip2GlobalGroup + DESCRIPTION + "This group defines global controls for RIP-II systems." + GROUP rip2IfStatGroup + DESCRIPTION + "This group defines interface statistics for RIP-II systems." + GROUP rip2IfConfGroup + DESCRIPTION + "This group defines interface configuration for RIP-II systems." + GROUP rip2PeerGroup + DESCRIPTION + "This group defines peer information for RIP-II systems." + ::= { rip2Compliances 1 } + +-- units of conformance + +rip2GlobalGroup OBJECT-GROUP + OBJECTS { + rip2GlobalRouteChanges, + rip2GlobalQueries + } + STATUS current + DESCRIPTION + "This group defines global controls for RIP-II systems." + ::= { rip2Groups 1 } +rip2IfStatGroup OBJECT-GROUP + OBJECTS { + rip2IfStatAddress, + rip2IfStatRcvBadPackets, + rip2IfStatRcvBadRoutes, + rip2IfStatSentUpdates, + rip2IfStatStatus + } + STATUS current + DESCRIPTION + "This group defines interface statistics for RIP-II systems." + ::= { rip2Groups 2 } +rip2IfConfGroup OBJECT-GROUP + OBJECTS { + rip2IfConfAddress, + rip2IfConfAuthType, + rip2IfConfAuthKey, + rip2IfConfSend, + rip2IfConfReceive, + rip2IfConfDefaultMetric, + rip2IfConfStatus, + rip2IfConfSrcAddress + } + STATUS current + DESCRIPTION + "This group defines interface configuration for RIP-II systems." + ::= { rip2Groups 3 } +rip2PeerGroup OBJECT-GROUP + OBJECTS { + rip2PeerAddress, + rip2PeerDomain, + rip2PeerLastUpdate, + rip2PeerVersion, + rip2PeerRcvBadPackets, + rip2PeerRcvBadRoutes + } + STATUS current + DESCRIPTION + "This group defines peer information for RIP-II systems." + ::= { rip2Groups 4 } +END diff --git a/ripd/rip_debug.c b/ripd/rip_debug.c new file mode 100644 index 00000000..4f09200a --- /dev/null +++ b/ripd/rip_debug.c @@ -0,0 +1,290 @@ +/* RIP debug routines + * Copyright (C) 1999 Kunihiro Ishiguro <kunihiro@zebra.org> + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> +#include "command.h" +#include "ripd/rip_debug.h" + +/* For debug statement. */ +unsigned long rip_debug_event = 0; +unsigned long rip_debug_packet = 0; +unsigned long rip_debug_zebra = 0; + +DEFUN (show_debugging_rip, + show_debugging_rip_cmd, + "show debugging rip", + SHOW_STR + DEBUG_STR + RIP_STR) +{ + vty_out (vty, "Zebra debugging status:%s", VTY_NEWLINE); + + if (IS_RIP_DEBUG_EVENT) + vty_out (vty, " RIP event debugging is on%s", VTY_NEWLINE); + + if (IS_RIP_DEBUG_PACKET) + { + if (IS_RIP_DEBUG_SEND && IS_RIP_DEBUG_RECV) + { + vty_out (vty, " RIP packet%s debugging is on%s", + IS_RIP_DEBUG_DETAIL ? " detail" : "", + VTY_NEWLINE); + } + else + { + if (IS_RIP_DEBUG_SEND) + vty_out (vty, " RIP packet send%s debugging is on%s", + IS_RIP_DEBUG_DETAIL ? " detail" : "", + VTY_NEWLINE); + else + vty_out (vty, " RIP packet receive%s debugging is on%s", + IS_RIP_DEBUG_DETAIL ? " detail" : "", + VTY_NEWLINE); + } + } + + if (IS_RIP_DEBUG_ZEBRA) + vty_out (vty, " RIP zebra debugging is on%s", VTY_NEWLINE); + + return CMD_SUCCESS; +} + +DEFUN (debug_rip_events, + debug_rip_events_cmd, + "debug rip events", + DEBUG_STR + RIP_STR + "RIP events\n") +{ + rip_debug_event = RIP_DEBUG_EVENT; + return CMD_WARNING; +} + +DEFUN (debug_rip_packet, + debug_rip_packet_cmd, + "debug rip packet", + DEBUG_STR + RIP_STR + "RIP packet\n") +{ + rip_debug_packet = RIP_DEBUG_PACKET; + rip_debug_packet |= RIP_DEBUG_SEND; + rip_debug_packet |= RIP_DEBUG_RECV; + return CMD_SUCCESS; +} + +DEFUN (debug_rip_packet_direct, + debug_rip_packet_direct_cmd, + "debug rip packet (recv|send)", + DEBUG_STR + RIP_STR + "RIP packet\n" + "RIP receive packet\n" + "RIP send packet\n") +{ + rip_debug_packet |= RIP_DEBUG_PACKET; + if (strncmp ("send", argv[0], strlen (argv[0])) == 0) + rip_debug_packet |= RIP_DEBUG_SEND; + if (strncmp ("recv", argv[0], strlen (argv[0])) == 0) + rip_debug_packet |= RIP_DEBUG_RECV; + rip_debug_packet &= ~RIP_DEBUG_DETAIL; + return CMD_SUCCESS; +} + +DEFUN (debug_rip_packet_detail, + debug_rip_packet_detail_cmd, + "debug rip packet (recv|send) detail", + DEBUG_STR + RIP_STR + "RIP packet\n" + "RIP receive packet\n" + "RIP send packet\n" + "Detailed information display\n") +{ + rip_debug_packet |= RIP_DEBUG_PACKET; + if (strncmp ("send", argv[0], strlen (argv[0])) == 0) + rip_debug_packet |= RIP_DEBUG_SEND; + if (strncmp ("recv", argv[0], strlen (argv[0])) == 0) + rip_debug_packet |= RIP_DEBUG_RECV; + rip_debug_packet |= RIP_DEBUG_DETAIL; + return CMD_SUCCESS; +} + +DEFUN (debug_rip_zebra, + debug_rip_zebra_cmd, + "debug rip zebra", + DEBUG_STR + RIP_STR + "RIP and ZEBRA communication\n") +{ + rip_debug_zebra = RIP_DEBUG_ZEBRA; + return CMD_WARNING; +} + +DEFUN (no_debug_rip_events, + no_debug_rip_events_cmd, + "no debug rip events", + NO_STR + DEBUG_STR + RIP_STR + "RIP events\n") +{ + rip_debug_event = 0; + return CMD_SUCCESS; +} + +DEFUN (no_debug_rip_packet, + no_debug_rip_packet_cmd, + "no debug rip packet", + NO_STR + DEBUG_STR + RIP_STR + "RIP packet\n") +{ + rip_debug_packet = 0; + return CMD_SUCCESS; +} + +DEFUN (no_debug_rip_packet_direct, + no_debug_rip_packet_direct_cmd, + "no debug rip packet (recv|send)", + NO_STR + DEBUG_STR + RIP_STR + "RIP packet\n" + "RIP option set for receive packet\n" + "RIP option set for send packet\n") +{ + if (strncmp ("send", argv[0], strlen (argv[0])) == 0) + { + if (IS_RIP_DEBUG_RECV) + rip_debug_packet &= ~RIP_DEBUG_SEND; + else + rip_debug_packet = 0; + } + else if (strncmp ("recv", argv[0], strlen (argv[0])) == 0) + { + if (IS_RIP_DEBUG_SEND) + rip_debug_packet &= ~RIP_DEBUG_RECV; + else + rip_debug_packet = 0; + } + return CMD_SUCCESS; +} + +DEFUN (no_debug_rip_zebra, + no_debug_rip_zebra_cmd, + "no debug rip zebra", + NO_STR + DEBUG_STR + RIP_STR + "RIP and ZEBRA communication\n") +{ + rip_debug_zebra = 0; + return CMD_WARNING; +} + +/* 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_RIP_DEBUG_EVENT) + { + vty_out (vty, "debug rip events%s", VTY_NEWLINE); + write++; + } + if (IS_RIP_DEBUG_PACKET) + { + if (IS_RIP_DEBUG_SEND && IS_RIP_DEBUG_RECV) + { + vty_out (vty, "debug rip packet%s%s", + IS_RIP_DEBUG_DETAIL ? " detail" : "", + VTY_NEWLINE); + write++; + } + else + { + if (IS_RIP_DEBUG_SEND) + vty_out (vty, "debug rip packet send%s%s", + IS_RIP_DEBUG_DETAIL ? " detail" : "", + VTY_NEWLINE); + else + vty_out (vty, "debug rip packet recv%s%s", + IS_RIP_DEBUG_DETAIL ? " detail" : "", + VTY_NEWLINE); + write++; + } + } + if (IS_RIP_DEBUG_ZEBRA) + { + vty_out (vty, "debug rip zebra%s", VTY_NEWLINE); + write++; + } + return write; +} + +void +rip_debug_reset () +{ + rip_debug_event = 0; + rip_debug_packet = 0; + rip_debug_zebra = 0; +} + +void +rip_debug_init () +{ + rip_debug_event = 0; + rip_debug_packet = 0; + rip_debug_zebra = 0; + + install_node (&debug_node, config_write_debug); + + install_element (ENABLE_NODE, &show_debugging_rip_cmd); + install_element (ENABLE_NODE, &debug_rip_events_cmd); + install_element (ENABLE_NODE, &debug_rip_packet_cmd); + install_element (ENABLE_NODE, &debug_rip_packet_direct_cmd); + install_element (ENABLE_NODE, &debug_rip_packet_detail_cmd); + install_element (ENABLE_NODE, &debug_rip_zebra_cmd); + install_element (ENABLE_NODE, &no_debug_rip_events_cmd); + install_element (ENABLE_NODE, &no_debug_rip_packet_cmd); + install_element (ENABLE_NODE, &no_debug_rip_packet_direct_cmd); + install_element (ENABLE_NODE, &no_debug_rip_zebra_cmd); + + install_element (CONFIG_NODE, &debug_rip_events_cmd); + install_element (CONFIG_NODE, &debug_rip_packet_cmd); + install_element (CONFIG_NODE, &debug_rip_packet_direct_cmd); + install_element (CONFIG_NODE, &debug_rip_packet_detail_cmd); + install_element (CONFIG_NODE, &debug_rip_zebra_cmd); + install_element (CONFIG_NODE, &no_debug_rip_events_cmd); + install_element (CONFIG_NODE, &no_debug_rip_packet_cmd); + install_element (CONFIG_NODE, &no_debug_rip_packet_direct_cmd); + install_element (CONFIG_NODE, &no_debug_rip_zebra_cmd); +} diff --git a/ripd/rip_debug.h b/ripd/rip_debug.h new file mode 100644 index 00000000..3b44d0cf --- /dev/null +++ b/ripd/rip_debug.h @@ -0,0 +1,54 @@ +/* RIP debug routines + * Copyright (C) 1999 Kunihiro Ishiguro <kunihiro@zebra.org> + * + * 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_RIP_DEBUG_H +#define _ZEBRA_RIP_DEBUG_H + +/* RIP debug event flags. */ +#define RIP_DEBUG_EVENT 0x01 + +/* RIP debug packet flags. */ +#define RIP_DEBUG_PACKET 0x01 +#define RIP_DEBUG_SEND 0x20 +#define RIP_DEBUG_RECV 0x40 +#define RIP_DEBUG_DETAIL 0x80 + +/* RIP debug zebra flags. */ +#define RIP_DEBUG_ZEBRA 0x01 + +/* Debug related macro. */ +#define IS_RIP_DEBUG_EVENT (rip_debug_event & RIP_DEBUG_EVENT) + +#define IS_RIP_DEBUG_PACKET (rip_debug_packet & RIP_DEBUG_PACKET) +#define IS_RIP_DEBUG_SEND (rip_debug_packet & RIP_DEBUG_SEND) +#define IS_RIP_DEBUG_RECV (rip_debug_packet & RIP_DEBUG_RECV) +#define IS_RIP_DEBUG_DETAIL (rip_debug_packet & RIP_DEBUG_DETAIL) + +#define IS_RIP_DEBUG_ZEBRA (rip_debug_zebra & RIP_DEBUG_ZEBRA) + +extern unsigned long rip_debug_event; +extern unsigned long rip_debug_packet; +extern unsigned long rip_debug_zebra; + +void rip_debug_init (); +void rip_debug_reset (); + +#endif /* _ZEBRA_RIP_DEBUG_H */ diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c new file mode 100644 index 00000000..06d4416b --- /dev/null +++ b/ripd/rip_interface.c @@ -0,0 +1,2001 @@ +/* Interface related function for RIP. + * Copyright (C) 1997, 98 Kunihiro Ishiguro <kunihiro@zebra.org> + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> + +#include "command.h" +#include "if.h" +#include "sockunion.h" +#include "prefix.h" +#include "memory.h" +#include "network.h" +#include "table.h" +#include "log.h" +#include "stream.h" +#include "thread.h" +#include "zclient.h" +#include "filter.h" +#include "sockopt.h" + +#include "zebra/connected.h" + +#include "ripd/ripd.h" +#include "ripd/rip_debug.h" + +void rip_enable_apply (struct interface *); +void rip_passive_interface_apply (struct interface *); +int rip_if_down(struct interface *ifp); + +struct message ri_version_msg[] = +{ + {RI_RIP_VERSION_1, "1"}, + {RI_RIP_VERSION_2, "2"}, + {RI_RIP_VERSION_1_AND_2, "1 2"}, + {0, NULL} +}; + +/* RIP enabled network vector. */ +vector rip_enable_interface; + +/* RIP enabled interface table. */ +struct route_table *rip_enable_network; + +/* Vector to store passive-interface name. */ +vector Vrip_passive_interface; + +/* Join to the RIP version 2 multicast group. */ +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.s_addr, + ifindex); + + if (ret < 0) + zlog (NULL, LOG_INFO, "can't setsockopt IP_ADD_MEMBERSHIP %s", + strerror (errno)); + + return ret; +} + +/* Leave from the RIP version 2 multicast group. */ +int +ipv4_multicast_leave (int sock, + struct in_addr group, + struct in_addr ifa, + unsigned int ifindex) +{ + int ret; + + ret = setsockopt_multicast_ipv4 (sock, + IP_DROP_MEMBERSHIP, + ifa, + group.s_addr, + ifindex); + + if (ret < 0) + zlog (NULL, LOG_INFO, "can't setsockopt IP_DROP_MEMBERSHIP"); + + return ret; +} + +/* Allocate new RIP's interface configuration. */ +struct rip_interface * +rip_interface_new () +{ + struct rip_interface *ri; + + ri = XMALLOC (MTYPE_RIP_INTERFACE, sizeof (struct rip_interface)); + memset (ri, 0, sizeof (struct rip_interface)); + + /* Default authentication type is simple password for Cisco + compatibility. */ + /* ri->auth_type = RIP_NO_AUTH; */ + ri->auth_type = RIP_AUTH_SIMPLE_PASSWORD; + + /* Set default split-horizon behavior. If the interface is Frame + Relay or SMDS is enabled, the default value for split-horizon is + off. But currently Zebra does detect Frame Relay or SMDS + interface. So all interface is set to split horizon. */ + ri->split_horizon_default = 1; + ri->split_horizon = ri->split_horizon_default; + + return ri; +} + +void +rip_interface_multicast_set (int sock, struct interface *ifp) +{ + int ret; + listnode node; + struct servent *sp; + struct sockaddr_in from; + + for (node = listhead (ifp->connected); node; nextnode (node)) + { + struct prefix_ipv4 *p; + struct connected *connected; + struct in_addr addr; + + connected = getdata (node); + p = (struct prefix_ipv4 *) connected->address; + + if (p->family == AF_INET) + { + addr = p->prefix; + + if (setsockopt_multicast_ipv4 (sock, IP_MULTICAST_IF, + addr, 0, ifp->ifindex) < 0) + { + zlog_warn ("Can't setsockopt IP_MULTICAST_IF to fd %d", sock); + return; + } + + /* Bind myself. */ + memset (&from, 0, sizeof (struct sockaddr_in)); + + /* Set RIP port. */ + sp = getservbyname ("router", "udp"); + if (sp) + from.sin_port = sp->s_port; + else + from.sin_port = htons (RIP_PORT_DEFAULT); + + /* Address shoud be any address. */ + from.sin_family = AF_INET; + from.sin_addr = addr; +#ifdef HAVE_SIN_LEN + from.sin_len = sizeof (struct sockaddr_in); +#endif /* HAVE_SIN_LEN */ + + ret = bind (sock, (struct sockaddr *) & from, + sizeof (struct sockaddr_in)); + if (ret < 0) + { + zlog_warn ("Can't bind socket: %s", strerror (errno)); + return; + } + + return; + + } + } +} + +/* Send RIP request packet to specified interface. */ +void +rip_request_interface_send (struct interface *ifp, u_char version) +{ + struct sockaddr_in to; + + /* RIPv2 support multicast. */ + if (version == RIPv2 && if_is_multicast (ifp)) + { + + if (IS_RIP_DEBUG_EVENT) + zlog_info ("multicast request on %s", ifp->name); + + rip_request_send (NULL, ifp, version); + return; + } + + /* RIPv1 and non multicast interface. */ + if (if_is_pointopoint (ifp) || if_is_broadcast (ifp)) + { + listnode cnode; + + if (IS_RIP_DEBUG_EVENT) + zlog_info ("broadcast request to %s", ifp->name); + + for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) + { + struct prefix_ipv4 *p; + struct connected *connected; + + connected = getdata (cnode); + p = (struct prefix_ipv4 *) connected->destination; + + if (p->family == AF_INET) + { + memset (&to, 0, sizeof (struct sockaddr_in)); + to.sin_port = htons (RIP_PORT_DEFAULT); + to.sin_addr = p->prefix; + +#if 0 + if (IS_RIP_DEBUG_EVENT) + zlog_info ("SEND request to %s", inet_ntoa (to.sin_addr)); +#endif /* 0 */ + + rip_request_send (&to, ifp, version); + } + } + } +} + +/* This will be executed when interface goes up. */ +void +rip_request_interface (struct interface *ifp) +{ + struct rip_interface *ri; + + /* In default ripd doesn't send RIP_REQUEST to the loopback interface. */ + if (if_is_loopback (ifp)) + return; + + /* If interface is down, don't send RIP packet. */ + if (! if_is_up (ifp)) + return; + + /* Fetch RIP interface information. */ + ri = ifp->info; + + + /* If there is no version configuration in the interface, + use rip's version setting. */ + if (ri->ri_send == RI_RIP_UNSPEC) + { + if (rip->version == RIPv1) + rip_request_interface_send (ifp, RIPv1); + else + rip_request_interface_send (ifp, RIPv2); + } + /* If interface has RIP version configuration use it. */ + else + { + if (ri->ri_send & RIPv1) + rip_request_interface_send (ifp, RIPv1); + if (ri->ri_send & RIPv2) + rip_request_interface_send (ifp, RIPv2); + } +} + +/* Send RIP request to the neighbor. */ +void +rip_request_neighbor (struct in_addr addr) +{ + struct sockaddr_in to; + + memset (&to, 0, sizeof (struct sockaddr_in)); + to.sin_port = htons (RIP_PORT_DEFAULT); + to.sin_addr = addr; + + rip_request_send (&to, NULL, rip->version); +} + +/* Request routes at all interfaces. */ +void +rip_request_neighbor_all () +{ + struct route_node *rp; + + if (! rip) + return; + + if (IS_RIP_DEBUG_EVENT) + zlog_info ("request to the all neighbor"); + + /* Send request to all neighbor. */ + for (rp = route_top (rip->neighbor); rp; rp = route_next (rp)) + if (rp->info) + rip_request_neighbor (rp->p.u.prefix4); +} + +/* Multicast packet receive socket. */ +int +rip_multicast_join (struct interface *ifp, int sock) +{ + listnode cnode; + + if (if_is_up (ifp) && if_is_multicast (ifp)) + { + if (IS_RIP_DEBUG_EVENT) + zlog_info ("multicast join at %s", ifp->name); + + for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) + { + struct prefix_ipv4 *p; + struct connected *connected; + struct in_addr group; + + connected = getdata (cnode); + p = (struct prefix_ipv4 *) connected->address; + + if (p->family != AF_INET) + continue; + + group.s_addr = htonl (INADDR_RIP_GROUP); + if (ipv4_multicast_join (sock, group, p->prefix, ifp->ifindex) < 0) + return -1; + else + return 0; + } + } + return 0; +} + +/* Leave from multicast group. */ +void +rip_multicast_leave (struct interface *ifp, int sock) +{ + listnode cnode; + + if (if_is_up (ifp) && if_is_multicast (ifp)) + { + if (IS_RIP_DEBUG_EVENT) + zlog_info ("multicast leave from %s", ifp->name); + + for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) + { + struct prefix_ipv4 *p; + struct connected *connected; + struct in_addr group; + + connected = getdata (cnode); + p = (struct prefix_ipv4 *) connected->address; + + if (p->family != AF_INET) + continue; + + group.s_addr = htonl (INADDR_RIP_GROUP); + if (ipv4_multicast_leave (sock, group, p->prefix, ifp->ifindex) == 0) + return; + } + } +} + +/* Is there and address on interface that I could use ? */ +int +rip_if_ipv4_address_check (struct interface *ifp) +{ + struct listnode *nn; + struct connected *connected; + int count = 0; + + for (nn = listhead (ifp->connected); nn; nextnode (nn)) + if ((connected = getdata (nn)) != NULL) + { + struct prefix *p; + + p = connected->address; + + if (p->family == AF_INET) + { + count++; + } + } + + return count; +} + + + + +/* Does this address belongs to me ? */ +int +if_check_address (struct in_addr addr) +{ + listnode node; + + for (node = listhead (iflist); node; nextnode (node)) + { + listnode cnode; + struct interface *ifp; + + ifp = getdata (node); + + for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) + { + struct connected *connected; + struct prefix_ipv4 *p; + + connected = getdata (cnode); + p = (struct prefix_ipv4 *) connected->address; + + if (p->family != AF_INET) + continue; + + if (IPV4_ADDR_CMP (&p->prefix, &addr) == 0) + return 1; + } + } + return 0; +} + +/* is this address from a valid neighbor? (RFC2453 - Sec. 3.9.2) */ +int +if_valid_neighbor (struct in_addr addr) +{ + listnode node; + struct connected *connected = NULL; + struct prefix_ipv4 *p; + + for (node = listhead (iflist); node; nextnode (node)) + { + listnode cnode; + struct interface *ifp; + + ifp = getdata (node); + + for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) + { + struct prefix *pxn = NULL; /* Prefix of the neighbor */ + struct prefix *pxc = NULL; /* Prefix of the connected network */ + + connected = getdata (cnode); + + if (if_is_pointopoint (ifp)) + { + p = (struct prefix_ipv4 *) connected->address; + + if (p && p->family == AF_INET) + { + if (IPV4_ADDR_SAME (&p->prefix, &addr)) + return 1; + + p = (struct prefix_ipv4 *) connected->destination; + if (p && IPV4_ADDR_SAME (&p->prefix, &addr)) + return 1; + } + } + else + { + p = (struct prefix_ipv4 *) connected->address; + + if (p->family != AF_INET) + continue; + + pxn = prefix_new(); + pxn->family = AF_INET; + pxn->prefixlen = 32; + pxn->u.prefix4 = addr; + + pxc = prefix_new(); + prefix_copy(pxc, (struct prefix *) p); + apply_mask(pxc); + + if (prefix_match (pxc, pxn)) + { + prefix_free (pxn); + prefix_free (pxc); + return 1; + } + prefix_free(pxc); + prefix_free(pxn); + } + } + } + return 0; +} + +/* Inteface link down message processing. */ +int +rip_interface_down (int command, struct zclient *zclient, zebra_size_t length) +{ + struct interface *ifp; + struct stream *s; + + s = zclient->ibuf; + + /* zebra_interface_state_read() updates interface structure in + iflist. */ + ifp = zebra_interface_state_read(s); + + if (ifp == NULL) + return 0; + + rip_if_down(ifp); + + if (IS_RIP_DEBUG_ZEBRA) + zlog_info ("interface %s index %d flags %ld metric %d mtu %d is down", + ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu); + + return 0; +} + +/* Inteface link up message processing */ +int +rip_interface_up (int command, struct zclient *zclient, zebra_size_t length) +{ + struct interface *ifp; + + /* zebra_interface_state_read () updates interface structure in + iflist. */ + ifp = zebra_interface_state_read (zclient->ibuf); + + if (ifp == NULL) + return 0; + + if (IS_RIP_DEBUG_ZEBRA) + zlog_info ("interface %s index %d flags %ld metric %d mtu %d is up", + ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu); + + /* Check if this interface is RIP enabled or not.*/ + rip_enable_apply (ifp); + + /* Check for a passive interface */ + rip_passive_interface_apply (ifp); + + /* Apply distribute list to the all interface. */ + rip_distribute_update_interface (ifp); + + return 0; +} + +/* Inteface addition message from zebra. */ +int +rip_interface_add (int command, struct zclient *zclient, zebra_size_t length) +{ + struct interface *ifp; + + ifp = zebra_interface_add_read (zclient->ibuf); + + if (IS_RIP_DEBUG_ZEBRA) + zlog_info ("interface add %s index %d flags %ld metric %d mtu %d", + ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu); + + /* Check if this interface is RIP enabled or not.*/ + rip_enable_apply (ifp); + + /* Apply distribute list to the all interface. */ + rip_distribute_update_interface (ifp); + + /* rip_request_neighbor_all (); */ + + return 0; +} + +int +rip_interface_delete (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct interface *ifp; + struct stream *s; + + + s = zclient->ibuf; + /* zebra_interface_state_read() updates interface structure in iflist */ + ifp = zebra_interface_state_read(s); + + if (ifp == NULL) + return 0; + + if (if_is_up (ifp)) { + rip_if_down(ifp); + } + + zlog_info("interface delete %s index %d flags %ld metric %d mtu %d", + ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu); + + /* To support pseudo interface do not free interface structure. */ + /* if_delete(ifp); */ + + return 0; +} + +void +rip_interface_clean () +{ + listnode node; + struct interface *ifp; + struct rip_interface *ri; + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + ri = ifp->info; + + ri->enable_network = 0; + ri->enable_interface = 0; + ri->running = 0; + + if (ri->t_wakeup) + { + thread_cancel (ri->t_wakeup); + ri->t_wakeup = NULL; + } + } +} + +void +rip_interface_reset () +{ + listnode node; + struct interface *ifp; + struct rip_interface *ri; + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + ri = ifp->info; + + ri->enable_network = 0; + ri->enable_interface = 0; + ri->running = 0; + + ri->ri_send = RI_RIP_UNSPEC; + ri->ri_receive = RI_RIP_UNSPEC; + + /* ri->auth_type = RIP_NO_AUTH; */ + ri->auth_type = RIP_AUTH_SIMPLE_PASSWORD; + + if (ri->auth_str) + { + free (ri->auth_str); + ri->auth_str = NULL; + } + if (ri->key_chain) + { + free (ri->key_chain); + ri->key_chain = NULL; + } + + ri->split_horizon = 0; + ri->split_horizon_default = 0; + + ri->list[RIP_FILTER_IN] = NULL; + ri->list[RIP_FILTER_OUT] = NULL; + + ri->prefix[RIP_FILTER_IN] = NULL; + ri->prefix[RIP_FILTER_OUT] = NULL; + + if (ri->t_wakeup) + { + thread_cancel (ri->t_wakeup); + ri->t_wakeup = NULL; + } + + ri->recv_badpackets = 0; + ri->recv_badroutes = 0; + ri->sent_updates = 0; + + ri->passive = 0; + } +} + +int +rip_if_down(struct interface *ifp) +{ + struct route_node *rp; + struct rip_info *rinfo; + struct rip_interface *ri = NULL; + if (rip) + { + for (rp = route_top (rip->table); rp; rp = route_next (rp)) + if ((rinfo = rp->info) != NULL) + { + /* Routes got through this interface. */ + if (rinfo->ifindex == ifp->ifindex && + rinfo->type == ZEBRA_ROUTE_RIP && + rinfo->sub_type == RIP_ROUTE_RTE) + { + rip_zebra_ipv4_delete ((struct prefix_ipv4 *) &rp->p, + &rinfo->nexthop, + rinfo->ifindex); + + rip_redistribute_delete (rinfo->type,rinfo->sub_type, + (struct prefix_ipv4 *)&rp->p, + rinfo->ifindex); + } + else + { + /* All redistributed routes but static and system */ + if ((rinfo->ifindex == ifp->ifindex) && + (rinfo->type != ZEBRA_ROUTE_STATIC) && + (rinfo->type != ZEBRA_ROUTE_SYSTEM)) + rip_redistribute_delete (rinfo->type,rinfo->sub_type, + (struct prefix_ipv4 *)&rp->p, + rinfo->ifindex); + } + } + } + + ri = ifp->info; + + if (ri->running) + { + if (IS_RIP_DEBUG_EVENT) + zlog_info ("turn off %s", ifp->name); + + /* Leave from multicast group. */ + rip_multicast_leave (ifp, rip->sock); + + ri->running = 0; + } + + return 0; +} + +/* Needed for stop RIP process. */ +void +rip_if_down_all () +{ + struct interface *ifp; + listnode node; + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + rip_if_down (ifp); + } +} + +int +rip_interface_address_add (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct connected *ifc; + struct prefix *p; + + ifc = zebra_interface_address_add_read (zclient->ibuf); + + if (ifc == NULL) + return 0; + + p = ifc->address; + + if (p->family == AF_INET) + { + if (IS_RIP_DEBUG_ZEBRA) + zlog_info ("connected address %s/%d is added", + inet_ntoa (p->u.prefix4), p->prefixlen); + + /* Check is this interface is RIP enabled or not.*/ + rip_enable_apply (ifc->ifp); + +#ifdef HAVE_SNMP + rip_ifaddr_add (ifc->ifp, ifc); +#endif /* HAVE_SNMP */ + } + + return 0; +} + +int +rip_interface_address_delete (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct connected *ifc; + struct prefix *p; + + ifc = zebra_interface_address_delete_read (zclient->ibuf); + + if (ifc) + { + p = ifc->address; + if (p->family == AF_INET) + { + if (IS_RIP_DEBUG_ZEBRA) + + zlog_info ("connected address %s/%d is deleted", + inet_ntoa (p->u.prefix4), p->prefixlen); + +#ifdef HAVE_SNMP + rip_ifaddr_delete (ifc->ifp, ifc); +#endif /* HAVE_SNMP */ + + /* Check if this interface is RIP enabled or not.*/ + rip_enable_apply (ifc->ifp); + } + + connected_free (ifc); + + } + + return 0; +} + +/* Check interface is enabled by network statement. */ +int +rip_enable_network_lookup (struct interface *ifp) +{ + struct listnode *nn; + struct connected *connected; + struct prefix_ipv4 address; + + for (nn = listhead (ifp->connected); nn; nextnode (nn)) + if ((connected = getdata (nn)) != NULL) + { + struct prefix *p; + struct route_node *node; + + p = connected->address; + + if (p->family == AF_INET) + { + address.family = AF_INET; + address.prefix = p->u.prefix4; + address.prefixlen = IPV4_MAX_BITLEN; + + node = route_node_match (rip_enable_network, + (struct prefix *)&address); + if (node) + { + route_unlock_node (node); + return 1; + } + } + } + return -1; +} + +/* Add RIP enable network. */ +int +rip_enable_network_add (struct prefix *p) +{ + struct route_node *node; + + node = route_node_get (rip_enable_network, p); + + if (node->info) + { + route_unlock_node (node); + return -1; + } + else + node->info = "enabled"; + + return 1; +} + +/* Delete RIP enable network. */ +int +rip_enable_network_delete (struct prefix *p) +{ + struct route_node *node; + + node = route_node_lookup (rip_enable_network, p); + if (node) + { + node->info = NULL; + + /* Unlock info lock. */ + route_unlock_node (node); + + /* Unlock lookup lock. */ + route_unlock_node (node); + + return 1; + } + return -1; +} + +/* Check interface is enabled by ifname statement. */ +int +rip_enable_if_lookup (char *ifname) +{ + int i; + char *str; + + for (i = 0; i < vector_max (rip_enable_interface); i++) + if ((str = vector_slot (rip_enable_interface, i)) != NULL) + if (strcmp (str, ifname) == 0) + return i; + return -1; +} + +/* Add interface to rip_enable_if. */ +int +rip_enable_if_add (char *ifname) +{ + int ret; + + ret = rip_enable_if_lookup (ifname); + if (ret >= 0) + return -1; + + vector_set (rip_enable_interface, strdup (ifname)); + + return 1; +} + +/* Delete interface from rip_enable_if. */ +int +rip_enable_if_delete (char *ifname) +{ + int index; + char *str; + + index = rip_enable_if_lookup (ifname); + if (index < 0) + return -1; + + str = vector_slot (rip_enable_interface, index); + free (str); + vector_unset (rip_enable_interface, index); + + return 1; +} + +/* Join to multicast group and send request to the interface. */ +int +rip_interface_wakeup (struct thread *t) +{ + struct interface *ifp; + struct rip_interface *ri; + + /* Get interface. */ + ifp = THREAD_ARG (t); + + ri = ifp->info; + ri->t_wakeup = NULL; + + /* Join to multicast group. */ + if (rip_multicast_join (ifp, rip->sock) < 0) + { + zlog_err ("multicast join failed, interface %s not running", ifp->name); + return 0; + } + + /* Set running flag. */ + ri->running = 1; + + /* Send RIP request to the interface. */ + rip_request_interface (ifp); + + return 0; +} + +int rip_redistribute_check (int); + +void +rip_connect_set (struct interface *ifp, int set) +{ + struct listnode *nn; + struct connected *connected; + struct prefix_ipv4 address; + + for (nn = listhead (ifp->connected); nn; nextnode (nn)) + if ((connected = getdata (nn)) != NULL) + { + struct prefix *p; + p = connected->address; + + if (p->family != AF_INET) + continue; + + address.family = AF_INET; + address.prefix = p->u.prefix4; + address.prefixlen = p->prefixlen; + apply_mask_ipv4 (&address); + + if (set) + rip_redistribute_add (ZEBRA_ROUTE_CONNECT, RIP_ROUTE_INTERFACE, + &address, connected->ifp->ifindex, NULL); + else + { + rip_redistribute_delete (ZEBRA_ROUTE_CONNECT, RIP_ROUTE_INTERFACE, + &address, connected->ifp->ifindex); + if (rip_redistribute_check (ZEBRA_ROUTE_CONNECT)) + rip_redistribute_add (ZEBRA_ROUTE_CONNECT, RIP_ROUTE_REDISTRIBUTE, + &address, connected->ifp->ifindex, NULL); + } + } +} + +/* Update interface status. */ +void +rip_enable_apply (struct interface *ifp) +{ + int ret; + struct rip_interface *ri = NULL; + + /* Check interface. */ + if (if_is_loopback (ifp)) + return; + + if (! if_is_up (ifp)) + return; + + ri = ifp->info; + + /* Check network configuration. */ + ret = rip_enable_network_lookup (ifp); + + /* If the interface is matched. */ + if (ret > 0) + ri->enable_network = 1; + else + ri->enable_network = 0; + + /* Check interface name configuration. */ + ret = rip_enable_if_lookup (ifp->name); + if (ret >= 0) + ri->enable_interface = 1; + else + ri->enable_interface = 0; + + /* any interface MUST have an IPv4 address */ + if ( ! rip_if_ipv4_address_check (ifp) ) + { + ri->enable_network = 0; + ri->enable_interface = 0; + } + + /* Update running status of the interface. */ + if (ri->enable_network || ri->enable_interface) + { + if (! ri->running) + { + if (IS_RIP_DEBUG_EVENT) + zlog_info ("turn on %s", ifp->name); + + /* Add interface wake up thread. */ + if (! ri->t_wakeup) + ri->t_wakeup = thread_add_timer (master, rip_interface_wakeup, + ifp, 1); + rip_connect_set (ifp, 1); + } + } + else + { + if (ri->running) + { + if (IS_RIP_DEBUG_EVENT) + zlog_info ("turn off %s", ifp->name); + + /* Might as well clean up the route table as well */ + rip_if_down(ifp); + + ri->running = 0; + rip_connect_set (ifp, 0); + } + } +} + +/* Apply network configuration to all interface. */ +void +rip_enable_apply_all () +{ + struct interface *ifp; + listnode node; + + /* Check each interface. */ + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + rip_enable_apply (ifp); + } +} + +int +rip_neighbor_lookup (struct sockaddr_in *from) +{ + struct prefix_ipv4 p; + struct route_node *node; + + memset (&p, 0, sizeof (struct prefix_ipv4)); + p.family = AF_INET; + p.prefix = from->sin_addr; + p.prefixlen = IPV4_MAX_BITLEN; + + node = route_node_lookup (rip->neighbor, (struct prefix *) &p); + if (node) + { + route_unlock_node (node); + return 1; + } + return 0; +} + +/* Add new RIP neighbor to the neighbor tree. */ +int +rip_neighbor_add (struct prefix_ipv4 *p) +{ + struct route_node *node; + + node = route_node_get (rip->neighbor, (struct prefix *) p); + + if (node->info) + return -1; + + node->info = rip->neighbor; + + return 0; +} + +/* Delete RIP neighbor from the neighbor tree. */ +int +rip_neighbor_delete (struct prefix_ipv4 *p) +{ + struct route_node *node; + + /* Lock for look up. */ + node = route_node_lookup (rip->neighbor, (struct prefix *) p); + if (! node) + return -1; + + node->info = NULL; + + /* Unlock lookup lock. */ + route_unlock_node (node); + + /* Unlock real neighbor information lock. */ + route_unlock_node (node); + + return 0; +} + +/* Clear all network and neighbor configuration. */ +void +rip_clean_network () +{ + int i; + char *str; + struct route_node *rn; + + /* rip_enable_network. */ + for (rn = route_top (rip_enable_network); rn; rn = route_next (rn)) + if (rn->info) + { + rn->info = NULL; + route_unlock_node (rn); + } + + /* rip_enable_interface. */ + for (i = 0; i < vector_max (rip_enable_interface); i++) + if ((str = vector_slot (rip_enable_interface, i)) != NULL) + { + free (str); + vector_slot (rip_enable_interface, i) = NULL; + } +} + +/* Utility function for looking up passive interface settings. */ +int +rip_passive_interface_lookup (char *ifname) +{ + int i; + char *str; + + for (i = 0; i < vector_max (Vrip_passive_interface); i++) + if ((str = vector_slot (Vrip_passive_interface, i)) != NULL) + if (strcmp (str, ifname) == 0) + return i; + return -1; +} + +void +rip_passive_interface_apply (struct interface *ifp) +{ + int ret; + struct rip_interface *ri; + + ri = ifp->info; + + ret = rip_passive_interface_lookup (ifp->name); + if (ret < 0) + ri->passive = 0; + else + ri->passive = 1; +} + +void +rip_passive_interface_apply_all () +{ + struct interface *ifp; + listnode node; + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + rip_passive_interface_apply (ifp); + } +} + +/* Passive interface. */ +int +rip_passive_interface_set (struct vty *vty, char *ifname) +{ + if (rip_passive_interface_lookup (ifname) >= 0) + return CMD_WARNING; + + vector_set (Vrip_passive_interface, strdup (ifname)); + + rip_passive_interface_apply_all (); + + return CMD_SUCCESS; +} + +int +rip_passive_interface_unset (struct vty *vty, char *ifname) +{ + int i; + char *str; + + i = rip_passive_interface_lookup (ifname); + if (i < 0) + return CMD_WARNING; + + str = vector_slot (Vrip_passive_interface, i); + free (str); + vector_unset (Vrip_passive_interface, i); + + rip_passive_interface_apply_all (); + + return CMD_SUCCESS; +} + +/* Free all configured RIP passive-interface settings. */ +void +rip_passive_interface_clean () +{ + int i; + char *str; + + for (i = 0; i < vector_max (Vrip_passive_interface); i++) + if ((str = vector_slot (Vrip_passive_interface, i)) != NULL) + { + free (str); + vector_slot (Vrip_passive_interface, i) = NULL; + } + rip_passive_interface_apply_all (); +} + +/* RIP enable network or interface configuration. */ +DEFUN (rip_network, + rip_network_cmd, + "network (A.B.C.D/M|WORD)", + "Enable routing on an IP network\n" + "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n" + "Interface name\n") +{ + int ret; + struct prefix_ipv4 p; + + ret = str2prefix_ipv4 (argv[0], &p); + + if (ret) + ret = rip_enable_network_add ((struct prefix *) &p); + else + ret = rip_enable_if_add (argv[0]); + + if (ret < 0) + { + vty_out (vty, "There is a same network configuration %s%s", argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + + rip_enable_apply_all (); + + return CMD_SUCCESS; +} + +/* RIP enable network or interface configuration. */ +DEFUN (no_rip_network, + no_rip_network_cmd, + "no network (A.B.C.D/M|WORD)", + NO_STR + "Enable routing on an IP network\n" + "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n" + "Interface name\n") +{ + int ret; + struct prefix_ipv4 p; + + ret = str2prefix_ipv4 (argv[0], &p); + + if (ret) + ret = rip_enable_network_delete ((struct prefix *) &p); + else + ret = rip_enable_if_delete (argv[0]); + + if (ret < 0) + { + vty_out (vty, "Can't find network configuration %s%s", argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + + rip_enable_apply_all (); + + return CMD_SUCCESS; +} + +/* RIP neighbor configuration set. */ +DEFUN (rip_neighbor, + rip_neighbor_cmd, + "neighbor A.B.C.D", + "Specify a neighbor router\n" + "Neighbor address\n") +{ + int ret; + struct prefix_ipv4 p; + + ret = str2prefix_ipv4 (argv[0], &p); + + if (ret <= 0) + { + vty_out (vty, "Please specify address by A.B.C.D%s", VTY_NEWLINE); + return CMD_WARNING; + } + + rip_neighbor_add (&p); + + return CMD_SUCCESS; +} + +/* RIP neighbor configuration unset. */ +DEFUN (no_rip_neighbor, + no_rip_neighbor_cmd, + "no neighbor A.B.C.D", + NO_STR + "Specify a neighbor router\n" + "Neighbor address\n") +{ + int ret; + struct prefix_ipv4 p; + + ret = str2prefix_ipv4 (argv[0], &p); + + if (ret <= 0) + { + vty_out (vty, "Please specify address by A.B.C.D%s", VTY_NEWLINE); + return CMD_WARNING; + } + + rip_neighbor_delete (&p); + + return CMD_SUCCESS; +} + +DEFUN (ip_rip_receive_version, + ip_rip_receive_version_cmd, + "ip rip receive version (1|2)", + IP_STR + "Routing Information Protocol\n" + "Advertisement reception\n" + "Version control\n" + "RIP version 1\n" + "RIP version 2\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *)vty->index; + ri = ifp->info; + + /* Version 1. */ + if (atoi (argv[0]) == 1) + { + ri->ri_receive = RI_RIP_VERSION_1; + return CMD_SUCCESS; + } + if (atoi (argv[0]) == 2) + { + ri->ri_receive = RI_RIP_VERSION_2; + return CMD_SUCCESS; + } + return CMD_WARNING; +} + +DEFUN (ip_rip_receive_version_1, + ip_rip_receive_version_1_cmd, + "ip rip receive version 1 2", + IP_STR + "Routing Information Protocol\n" + "Advertisement reception\n" + "Version control\n" + "RIP version 1\n" + "RIP version 2\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *)vty->index; + ri = ifp->info; + + /* Version 1 and 2. */ + ri->ri_receive = RI_RIP_VERSION_1_AND_2; + return CMD_SUCCESS; +} + +DEFUN (ip_rip_receive_version_2, + ip_rip_receive_version_2_cmd, + "ip rip receive version 2 1", + IP_STR + "Routing Information Protocol\n" + "Advertisement reception\n" + "Version control\n" + "RIP version 2\n" + "RIP version 1\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *)vty->index; + ri = ifp->info; + + /* Version 1 and 2. */ + ri->ri_receive = RI_RIP_VERSION_1_AND_2; + return CMD_SUCCESS; +} + +DEFUN (no_ip_rip_receive_version, + no_ip_rip_receive_version_cmd, + "no ip rip receive version", + NO_STR + IP_STR + "Routing Information Protocol\n" + "Advertisement reception\n" + "Version control\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *)vty->index; + ri = ifp->info; + + ri->ri_receive = RI_RIP_UNSPEC; + return CMD_SUCCESS; +} + +ALIAS (no_ip_rip_receive_version, + no_ip_rip_receive_version_num_cmd, + "no ip rip receive version (1|2)", + NO_STR + IP_STR + "Routing Information Protocol\n" + "Advertisement reception\n" + "Version control\n" + "Version 1\n" + "Version 2\n") + +DEFUN (ip_rip_send_version, + ip_rip_send_version_cmd, + "ip rip send version (1|2)", + IP_STR + "Routing Information Protocol\n" + "Advertisement transmission\n" + "Version control\n" + "RIP version 1\n" + "RIP version 2\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *)vty->index; + ri = ifp->info; + + /* Version 1. */ + if (atoi (argv[0]) == 1) + { + ri->ri_send = RI_RIP_VERSION_1; + return CMD_SUCCESS; + } + if (atoi (argv[0]) == 2) + { + ri->ri_send = RI_RIP_VERSION_2; + return CMD_SUCCESS; + } + return CMD_WARNING; +} + +DEFUN (ip_rip_send_version_1, + ip_rip_send_version_1_cmd, + "ip rip send version 1 2", + IP_STR + "Routing Information Protocol\n" + "Advertisement transmission\n" + "Version control\n" + "RIP version 1\n" + "RIP version 2\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *)vty->index; + ri = ifp->info; + + /* Version 1 and 2. */ + ri->ri_send = RI_RIP_VERSION_1_AND_2; + return CMD_SUCCESS; +} + +DEFUN (ip_rip_send_version_2, + ip_rip_send_version_2_cmd, + "ip rip send version 2 1", + IP_STR + "Routing Information Protocol\n" + "Advertisement transmission\n" + "Version control\n" + "RIP version 2\n" + "RIP version 1\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *)vty->index; + ri = ifp->info; + + /* Version 1 and 2. */ + ri->ri_send = RI_RIP_VERSION_1_AND_2; + return CMD_SUCCESS; +} + +DEFUN (no_ip_rip_send_version, + no_ip_rip_send_version_cmd, + "no ip rip send version", + NO_STR + IP_STR + "Routing Information Protocol\n" + "Advertisement transmission\n" + "Version control\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *)vty->index; + ri = ifp->info; + + ri->ri_send = RI_RIP_UNSPEC; + return CMD_SUCCESS; +} + +ALIAS (no_ip_rip_send_version, + no_ip_rip_send_version_num_cmd, + "no ip rip send version (1|2)", + NO_STR + IP_STR + "Routing Information Protocol\n" + "Advertisement transmission\n" + "Version control\n" + "Version 1\n" + "Version 2\n") + +DEFUN (ip_rip_authentication_mode, + ip_rip_authentication_mode_cmd, + "ip rip authentication mode (md5|text)", + IP_STR + "Routing Information Protocol\n" + "Authentication control\n" + "Authentication mode\n" + "Keyed message digest\n" + "Clear text authentication\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *)vty->index; + ri = ifp->info; + + if (strncmp ("md5", argv[0], strlen (argv[0])) == 0) + ri->auth_type = RIP_AUTH_MD5; + else if (strncmp ("text", argv[0], strlen (argv[0])) == 0) + ri->auth_type = RIP_AUTH_SIMPLE_PASSWORD; + else + { + vty_out (vty, "mode should be md5 or text%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +DEFUN (no_ip_rip_authentication_mode, + no_ip_rip_authentication_mode_cmd, + "no ip rip authentication mode", + NO_STR + IP_STR + "Routing Information Protocol\n" + "Authentication control\n" + "Authentication mode\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *)vty->index; + ri = ifp->info; + + /* ri->auth_type = RIP_NO_AUTH; */ + ri->auth_type = RIP_AUTH_SIMPLE_PASSWORD; + + return CMD_SUCCESS; +} + +ALIAS (no_ip_rip_authentication_mode, + no_ip_rip_authentication_mode_type_cmd, + "no ip rip authentication mode (md5|text)", + NO_STR + IP_STR + "Routing Information Protocol\n" + "Authentication control\n" + "Authentication mode\n" + "Keyed message digest\n" + "Clear text authentication\n") + +DEFUN (ip_rip_authentication_string, + ip_rip_authentication_string_cmd, + "ip rip authentication string LINE", + IP_STR + "Routing Information Protocol\n" + "Authentication control\n" + "Authentication string\n" + "Authentication string\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *)vty->index; + ri = ifp->info; + + if (strlen (argv[0]) > 16) + { + vty_out (vty, "%% RIPv2 authentication string must be shorter than 16%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + if (ri->key_chain) + { + vty_out (vty, "%% key-chain configuration exists%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (ri->auth_str) + free (ri->auth_str); + + ri->auth_str = strdup (argv[0]); + + return CMD_SUCCESS; +} + +DEFUN (no_ip_rip_authentication_string, + no_ip_rip_authentication_string_cmd, + "no ip rip authentication string", + NO_STR + IP_STR + "Routing Information Protocol\n" + "Authentication control\n" + "Authentication string\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *)vty->index; + ri = ifp->info; + + if (ri->auth_str) + free (ri->auth_str); + + ri->auth_str = NULL; + + return CMD_SUCCESS; +} + +ALIAS (no_ip_rip_authentication_string, + no_ip_rip_authentication_string2_cmd, + "no ip rip authentication string LINE", + NO_STR + IP_STR + "Routing Information Protocol\n" + "Authentication control\n" + "Authentication string\n" + "Authentication string\n") + +DEFUN (ip_rip_authentication_key_chain, + ip_rip_authentication_key_chain_cmd, + "ip rip authentication key-chain LINE", + IP_STR + "Routing Information Protocol\n" + "Authentication control\n" + "Authentication key-chain\n" + "name of key-chain\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *) vty->index; + ri = ifp->info; + + if (ri->auth_str) + { + vty_out (vty, "%% authentication string configuration exists%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + if (ri->key_chain) + free (ri->key_chain); + + ri->key_chain = strdup (argv[0]); + + return CMD_SUCCESS; +} + +DEFUN (no_ip_rip_authentication_key_chain, + no_ip_rip_authentication_key_chain_cmd, + "no ip rip authentication key-chain", + NO_STR + IP_STR + "Routing Information Protocol\n" + "Authentication control\n" + "Authentication key-chain\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *) vty->index; + ri = ifp->info; + + if (ri->key_chain) + free (ri->key_chain); + + ri->key_chain = NULL; + + return CMD_SUCCESS; +} + +ALIAS (no_ip_rip_authentication_key_chain, + no_ip_rip_authentication_key_chain2_cmd, + "no ip rip authentication key-chain LINE", + NO_STR + IP_STR + "Routing Information Protocol\n" + "Authentication control\n" + "Authentication key-chain\n" + "name of key-chain\n") + +DEFUN (rip_split_horizon, + rip_split_horizon_cmd, + "ip split-horizon", + IP_STR + "Perform split horizon\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = vty->index; + ri = ifp->info; + + ri->split_horizon = 1; + return CMD_SUCCESS; +} + +DEFUN (no_rip_split_horizon, + no_rip_split_horizon_cmd, + "no ip split-horizon", + NO_STR + IP_STR + "Perform split horizon\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = vty->index; + ri = ifp->info; + + ri->split_horizon = 0; + return CMD_SUCCESS; +} + +DEFUN (rip_passive_interface, + rip_passive_interface_cmd, + "passive-interface IFNAME", + "Suppress routing updates on an interface\n" + "Interface name\n") +{ + return rip_passive_interface_set (vty, argv[0]); +} + +DEFUN (no_rip_passive_interface, + no_rip_passive_interface_cmd, + "no passive-interface IFNAME", + NO_STR + "Suppress routing updates on an interface\n" + "Interface name\n") +{ + return rip_passive_interface_unset (vty, argv[0]); +} + +/* Write rip configuration of each interface. */ +int +rip_interface_config_write (struct vty *vty) +{ + listnode node; + struct interface *ifp; + + for (node = listhead (iflist); node; nextnode (node)) + { + struct rip_interface *ri; + + ifp = getdata (node); + ri = 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); + + /* Split horizon. */ + if (ri->split_horizon != ri->split_horizon_default) + { + if (ri->split_horizon) + vty_out (vty, " ip split-horizon%s", VTY_NEWLINE); + else + vty_out (vty, " no ip split-horizon%s", VTY_NEWLINE); + } + + /* RIP version setting. */ + if (ri->ri_send != RI_RIP_UNSPEC) + vty_out (vty, " ip rip send version %s%s", + lookup (ri_version_msg, ri->ri_send), + VTY_NEWLINE); + + if (ri->ri_receive != RI_RIP_UNSPEC) + vty_out (vty, " ip rip receive version %s%s", + lookup (ri_version_msg, ri->ri_receive), + VTY_NEWLINE); + + /* RIP authentication. */ +#if 0 + /* RIP_AUTH_SIMPLE_PASSWORD becomes default mode. */ + if (ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD) + vty_out (vty, " ip rip authentication mode text%s", VTY_NEWLINE); +#endif /* 0 */ + if (ri->auth_type == RIP_AUTH_MD5) + vty_out (vty, " ip rip authentication mode md5%s", VTY_NEWLINE); + + if (ri->auth_str) + vty_out (vty, " ip rip authentication string %s%s", + ri->auth_str, VTY_NEWLINE); + + if (ri->key_chain) + vty_out (vty, " ip rip authentication key-chain %s%s", + ri->key_chain, VTY_NEWLINE); + + vty_out (vty, "!%s", VTY_NEWLINE); + } + return 0; +} + +int +config_write_rip_network (struct vty *vty, int config_mode) +{ + int i; + char *ifname; + struct route_node *node; + + /* Network type RIP enable interface statement. */ + for (node = route_top (rip_enable_network); node; node = route_next (node)) + if (node->info) + vty_out (vty, "%s%s/%d%s", + config_mode ? " network " : " ", + inet_ntoa (node->p.u.prefix4), + node->p.prefixlen, + VTY_NEWLINE); + + /* Interface name RIP enable statement. */ + for (i = 0; i < vector_max (rip_enable_interface); i++) + if ((ifname = vector_slot (rip_enable_interface, i)) != NULL) + vty_out (vty, "%s%s%s", + config_mode ? " network " : " ", + ifname, + VTY_NEWLINE); + + /* RIP neighbors listing. */ + for (node = route_top (rip->neighbor); node; node = route_next (node)) + if (node->info) + vty_out (vty, "%s%s%s", + config_mode ? " neighbor " : " ", + inet_ntoa (node->p.u.prefix4), + VTY_NEWLINE); + + /* RIP passive interface listing. */ + if (config_mode) + for (i = 0; i < vector_max (Vrip_passive_interface); i++) + if ((ifname = vector_slot (Vrip_passive_interface, i)) != NULL) + vty_out (vty, " passive-interface %s%s", ifname, VTY_NEWLINE); + + return 0; +} + +struct cmd_node interface_node = +{ + INTERFACE_NODE, + "%s(config-if)# ", + 1, +}; + +/* Called when interface structure allocated. */ +int +rip_interface_new_hook (struct interface *ifp) +{ + ifp->info = rip_interface_new (); + return 0; +} + +/* Called when interface structure deleted. */ +int +rip_interface_delete_hook (struct interface *ifp) +{ + XFREE (MTYPE_RIP_INTERFACE, ifp->info); + return 0; +} + +/* Allocate and initialize interface vector. */ +void +rip_if_init () +{ + /* Default initial size of interface vector. */ + if_init(); + if_add_hook (IF_NEW_HOOK, rip_interface_new_hook); + if_add_hook (IF_DELETE_HOOK, rip_interface_delete_hook); + + /* RIP network init. */ + rip_enable_interface = vector_init (1); + rip_enable_network = route_table_init (); + + /* RIP passive interface. */ + Vrip_passive_interface = vector_init (1); + + /* Install interface node. */ + install_node (&interface_node, rip_interface_config_write); + + /* Install commands. */ + install_element (CONFIG_NODE, &interface_cmd); + install_default (INTERFACE_NODE); + install_element (INTERFACE_NODE, &interface_desc_cmd); + install_element (INTERFACE_NODE, &no_interface_desc_cmd); + install_element (RIP_NODE, &rip_network_cmd); + install_element (RIP_NODE, &no_rip_network_cmd); + install_element (RIP_NODE, &rip_neighbor_cmd); + install_element (RIP_NODE, &no_rip_neighbor_cmd); + + install_element (RIP_NODE, &rip_passive_interface_cmd); + install_element (RIP_NODE, &no_rip_passive_interface_cmd); + + install_element (INTERFACE_NODE, &ip_rip_send_version_cmd); + install_element (INTERFACE_NODE, &ip_rip_send_version_1_cmd); + install_element (INTERFACE_NODE, &ip_rip_send_version_2_cmd); + install_element (INTERFACE_NODE, &no_ip_rip_send_version_cmd); + install_element (INTERFACE_NODE, &no_ip_rip_send_version_num_cmd); + + install_element (INTERFACE_NODE, &ip_rip_receive_version_cmd); + install_element (INTERFACE_NODE, &ip_rip_receive_version_1_cmd); + install_element (INTERFACE_NODE, &ip_rip_receive_version_2_cmd); + install_element (INTERFACE_NODE, &no_ip_rip_receive_version_cmd); + install_element (INTERFACE_NODE, &no_ip_rip_receive_version_num_cmd); + + install_element (INTERFACE_NODE, &ip_rip_authentication_mode_cmd); + install_element (INTERFACE_NODE, &no_ip_rip_authentication_mode_cmd); + install_element (INTERFACE_NODE, &no_ip_rip_authentication_mode_type_cmd); + + install_element (INTERFACE_NODE, &ip_rip_authentication_key_chain_cmd); + install_element (INTERFACE_NODE, &no_ip_rip_authentication_key_chain_cmd); + install_element (INTERFACE_NODE, &no_ip_rip_authentication_key_chain2_cmd); + + install_element (INTERFACE_NODE, &ip_rip_authentication_string_cmd); + install_element (INTERFACE_NODE, &no_ip_rip_authentication_string_cmd); + install_element (INTERFACE_NODE, &no_ip_rip_authentication_string2_cmd); + + install_element (INTERFACE_NODE, &rip_split_horizon_cmd); + install_element (INTERFACE_NODE, &no_rip_split_horizon_cmd); +} diff --git a/ripd/rip_main.c b/ripd/rip_main.c new file mode 100644 index 00000000..1070fb45 --- /dev/null +++ b/ripd/rip_main.c @@ -0,0 +1,270 @@ +/* RIPd main routine. + * Copyright (C) 1997, 98 Kunihiro Ishiguro <kunihiro@zebra.org> + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> + +#include "version.h" +#include "getopt.h" +#include "thread.h" +#include "command.h" +#include "memory.h" +#include "prefix.h" +#include "filter.h" +#include "keychain.h" +#include "log.h" + +#include "ripd/ripd.h" + +/* ripd options. */ +static struct option longopts[] = +{ + { "daemon", no_argument, NULL, 'd'}, + { "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 } +}; + +/* Configuration file and directory. */ +char config_current[] = RIPD_DEFAULT_CONFIG; +char config_default[] = SYSCONFDIR RIPD_DEFAULT_CONFIG; +char *config_file = NULL; + +/* ripd program name */ + +/* Route retain mode flag. */ +int retain_mode = 0; + +/* RIP VTY bind address. */ +char *vty_addr = NULL; + +/* RIP VTY connection port. */ +int vty_port = RIP_VTY_PORT; + +/* Master of threads. */ +struct thread_master *master; + +/* Process ID saved for use by init system */ +char *pid_file = PATH_RIPD_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\ +Daemon which manages RIP version 1 and 2.\n\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\ +-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 ripd.\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); +} + +/* 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); +} + +/* SIGHUP handler. */ +void +sighup (int sig) +{ + zlog_info ("SIGHUP received"); + rip_clean (); + rip_reset (); + zlog_info ("ripd restarting!"); + + /* Reload config file. */ + vty_read_config (config_file, config_current, config_default); + + /* Create VTY's socket */ + vty_serv_sock (vty_addr, vty_port, RIP_VTYSH_PATH); + + /* Try to return to normal operation. */ +} + +/* SIGINT handler. */ +void +sigint (int sig) +{ + zlog (NULL, LOG_INFO, "Terminating on signal"); + + if (! retain_mode) + rip_clean (); + + exit (0); +} + +/* SIGUSR1 handler. */ +void +sigusr1 (int sig) +{ + zlog_rotate (NULL); +} + +/* 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 routine of ripd. */ +int +main (int argc, char **argv) +{ + char *p; + int daemon_mode = 0; + char *progname; + struct thread thread; + + /* Set umask before anything for security */ + umask (0027); + + /* Get program name. */ + progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); + + /* First of all we need logging init. */ + zlog_default = openzlog (progname, ZLOG_NOLOG, ZLOG_RIP, + LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); + + /* Command line option parse. */ + while (1) + { + int opt; + + opt = getopt_long (argc, argv, "df:hA:P:rv", longopts, 0); + + if (opt == EOF) + break; + + switch (opt) + { + case 0: + break; + case 'd': + daemon_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; + } + } + + /* Prepare master thread. */ + master = thread_master_create (); + + /* Library initialization. */ + signal_init (); + cmd_init (1); + vty_init (); + memory_init (); + keychain_init (); + + /* RIP related initialization. */ + rip_init (); + rip_if_init (); + rip_zclient_init (); + rip_peer_init (); + + /* Sort all installed commands. */ + sort_node (); + + /* Get configuration file. */ + vty_read_config (config_file, config_current, config_default); + + /* Change to the daemon program. */ + if (daemon_mode) + daemon (0, 0); + + /* Pid file create. */ + pid_output (pid_file); + + /* Create VTY's socket */ + vty_serv_sock (vty_addr, vty_port, RIP_VTYSH_PATH); + + /* Execute each thread. */ + while (thread_fetch (master, &thread)) + thread_call (&thread); + + /* Not reached. */ + exit (0); +} diff --git a/ripd/rip_offset.c b/ripd/rip_offset.c new file mode 100644 index 00000000..0d473482 --- /dev/null +++ b/ripd/rip_offset.c @@ -0,0 +1,414 @@ +/* RIP offset-list + * Copyright (C) 2000 Kunihiro Ishiguro <kunihiro@zebra.org> + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> + +#include "if.h" +#include "prefix.h" +#include "filter.h" +#include "command.h" +#include "linklist.h" +#include "memory.h" + +#define RIP_OFFSET_LIST_IN 0 +#define RIP_OFFSET_LIST_OUT 1 +#define RIP_OFFSET_LIST_MAX 2 + +struct rip_offset_list +{ + char *ifname; + + struct + { + char *alist_name; + /* struct access_list *alist; */ + int metric; + } direct[RIP_OFFSET_LIST_MAX]; +}; + +static struct list *rip_offset_list_master; + +int +strcmp_safe (char *s1, char *s2) +{ + if (s1 == NULL && s2 == NULL) + return 0; + if (s1 == NULL) + return -1; + if (s2 == NULL) + return 1; + return strcmp (s1, s2); +} + +struct rip_offset_list * +rip_offset_list_new () +{ + struct rip_offset_list *new; + + new = XMALLOC (MTYPE_RIP_OFFSET_LIST, sizeof (struct rip_offset_list)); + memset (new, 0, sizeof (struct rip_offset_list)); + return new; +} + +void +rip_offset_list_free (struct rip_offset_list *offset) +{ + XFREE (MTYPE_RIP_OFFSET_LIST, offset); +} + +struct rip_offset_list * +rip_offset_list_lookup (char *ifname) +{ + struct rip_offset_list *offset; + struct listnode *nn; + + LIST_LOOP (rip_offset_list_master, offset, nn) + { + if (strcmp_safe (offset->ifname, ifname) == 0) + return offset; + } + return NULL; +} + +struct rip_offset_list * +rip_offset_list_get (char *ifname) +{ + struct rip_offset_list *offset; + + offset = rip_offset_list_lookup (ifname); + if (offset) + return offset; + + offset = rip_offset_list_new (); + if (ifname) + offset->ifname = strdup (ifname); + listnode_add_sort (rip_offset_list_master, offset); + + return offset; +} + +int +rip_offset_list_set (struct vty *vty, char *alist, char *direct_str, + char *metric_str, char *ifname) +{ + int direct; + int metric; + struct rip_offset_list *offset; + + /* Check direction. */ + if (strncmp (direct_str, "i", 1) == 0) + direct = RIP_OFFSET_LIST_IN; + else if (strncmp (direct_str, "o", 1) == 0) + direct = RIP_OFFSET_LIST_OUT; + else + { + vty_out (vty, "Invalid direction: %s%s", direct_str, VTY_NEWLINE); + return CMD_WARNING; + } + + /* Check metric. */ + metric = atoi (metric_str); + if (metric < 0 || metric > 16) + { + vty_out (vty, "Invalid metric: %s%s", metric_str, VTY_NEWLINE); + return CMD_WARNING; + } + + /* Get offset-list structure with interface name. */ + offset = rip_offset_list_get (ifname); + + if (offset->direct[direct].alist_name) + free (offset->direct[direct].alist_name); + offset->direct[direct].alist_name = strdup (alist); + offset->direct[direct].metric = metric; + + return CMD_SUCCESS; +} + +int +rip_offset_list_unset (struct vty *vty, char *alist, char *direct_str, + char *metric_str, char *ifname) +{ + int direct; + int metric; + struct rip_offset_list *offset; + + /* Check direction. */ + if (strncmp (direct_str, "i", 1) == 0) + direct = RIP_OFFSET_LIST_IN; + else if (strncmp (direct_str, "o", 1) == 0) + direct = RIP_OFFSET_LIST_OUT; + else + { + vty_out (vty, "Invalid direction: %s%s", direct_str, VTY_NEWLINE); + return CMD_WARNING; + } + + /* Check metric. */ + metric = atoi (metric_str); + if (metric < 0 || metric > 16) + { + vty_out (vty, "Invalid metric: %s%s", metric_str, VTY_NEWLINE); + return CMD_WARNING; + } + + /* Get offset-list structure with interface name. */ + offset = rip_offset_list_lookup (ifname); + + if (offset) + { + if (offset->direct[direct].alist_name) + free (offset->direct[direct].alist_name); + offset->direct[direct].alist_name = NULL; + + if (offset->direct[RIP_OFFSET_LIST_IN].alist_name == NULL && + offset->direct[RIP_OFFSET_LIST_OUT].alist_name == NULL) + { + listnode_delete (rip_offset_list_master, offset); + if (offset->ifname) + free (offset->ifname); + rip_offset_list_free (offset); + } + } + else + { + vty_out (vty, "Can't find offset-list%s", VTY_NEWLINE); + return CMD_WARNING; + } + return CMD_SUCCESS; +} + +#define OFFSET_LIST_IN_NAME(O) ((O)->direct[RIP_OFFSET_LIST_IN].alist_name) +#define OFFSET_LIST_IN_METRIC(O) ((O)->direct[RIP_OFFSET_LIST_IN].metric) + +#define OFFSET_LIST_OUT_NAME(O) ((O)->direct[RIP_OFFSET_LIST_OUT].alist_name) +#define OFFSET_LIST_OUT_METRIC(O) ((O)->direct[RIP_OFFSET_LIST_OUT].metric) + +/* If metric is modifed return 1. */ +int +rip_offset_list_apply_in (struct prefix_ipv4 *p, struct interface *ifp, + u_int32_t *metric) +{ + struct rip_offset_list *offset; + struct access_list *alist; + + /* Look up offset-list with interface name. */ + offset = rip_offset_list_lookup (ifp->name); + if (offset && OFFSET_LIST_IN_NAME (offset)) + { + alist = access_list_lookup (AFI_IP, OFFSET_LIST_IN_NAME (offset)); + + if (alist + && access_list_apply (alist, (struct prefix *)p) == FILTER_PERMIT) + { + *metric += OFFSET_LIST_IN_METRIC (offset); + return 1; + } + return 0; + } + /* Look up offset-list without interface name. */ + offset = rip_offset_list_lookup (NULL); + if (offset && OFFSET_LIST_IN_NAME (offset)) + { + alist = access_list_lookup (AFI_IP, OFFSET_LIST_IN_NAME (offset)); + + if (alist + && access_list_apply (alist, (struct prefix *)p) == FILTER_PERMIT) + { + *metric += OFFSET_LIST_IN_METRIC (offset); + return 1; + } + return 0; + } + return 0; +} + +/* If metric is modifed return 1. */ +int +rip_offset_list_apply_out (struct prefix_ipv4 *p, struct interface *ifp, + u_int32_t *metric) +{ + struct rip_offset_list *offset; + struct access_list *alist; + + /* Look up offset-list with interface name. */ + offset = rip_offset_list_lookup (ifp->name); + if (offset && OFFSET_LIST_OUT_NAME (offset)) + { + alist = access_list_lookup (AFI_IP, OFFSET_LIST_OUT_NAME (offset)); + + if (alist + && access_list_apply (alist, (struct prefix *)p) == FILTER_PERMIT) + { + *metric += OFFSET_LIST_OUT_METRIC (offset); + return 1; + } + return 0; + } + + /* Look up offset-list without interface name. */ + offset = rip_offset_list_lookup (NULL); + if (offset && OFFSET_LIST_OUT_NAME (offset)) + { + alist = access_list_lookup (AFI_IP, OFFSET_LIST_OUT_NAME (offset)); + + if (alist + && access_list_apply (alist, (struct prefix *)p) == FILTER_PERMIT) + { + *metric += OFFSET_LIST_OUT_METRIC (offset); + return 1; + } + return 0; + } + return 0; +} + +DEFUN (rip_offset_list, + rip_offset_list_cmd, + "offset-list WORD (in|out) <0-16>", + "Modify RIP metric\n" + "Access-list name\n" + "For incoming updates\n" + "For outgoing updates\n" + "Metric value\n") +{ + return rip_offset_list_set (vty, argv[0], argv[1], argv[2], NULL); +} + +DEFUN (rip_offset_list_ifname, + rip_offset_list_ifname_cmd, + "offset-list WORD (in|out) <0-16> IFNAME", + "Modify RIP metric\n" + "Access-list name\n" + "For incoming updates\n" + "For outgoing updates\n" + "Metric value\n" + "Interface to match\n") +{ + return rip_offset_list_set (vty, argv[0], argv[1], argv[2], argv[3]); +} + +DEFUN (no_rip_offset_list, + no_rip_offset_list_cmd, + "no offset-list WORD (in|out) <0-16>", + NO_STR + "Modify RIP metric\n" + "Access-list name\n" + "For incoming updates\n" + "For outgoing updates\n" + "Metric value\n") +{ + return rip_offset_list_unset (vty, argv[0], argv[1], argv[2], NULL); +} + +DEFUN (no_rip_offset_list_ifname, + no_rip_offset_list_ifname_cmd, + "no offset-list WORD (in|out) <0-16> IFNAME", + NO_STR + "Modify RIP metric\n" + "Access-list name\n" + "For incoming updates\n" + "For outgoing updates\n" + "Metric value\n" + "Interface to match\n") +{ + return rip_offset_list_unset (vty, argv[0], argv[1], argv[2], argv[3]); +} + +int +offset_list_cmp (struct rip_offset_list *o1, struct rip_offset_list *o2) +{ + return strcmp_safe (o1->ifname, o2->ifname); +} + +void +offset_list_del (struct rip_offset_list *offset) +{ + if (OFFSET_LIST_IN_NAME (offset)) + free (OFFSET_LIST_IN_NAME (offset)); + if (OFFSET_LIST_OUT_NAME (offset)) + free (OFFSET_LIST_OUT_NAME (offset)); + if (offset->ifname) + free (offset->ifname); + rip_offset_list_free (offset); +} + +void +rip_offset_init () +{ + rip_offset_list_master = list_new (); + rip_offset_list_master->cmp = (int (*)(void *, void *)) offset_list_cmp; + rip_offset_list_master->del = (void (*)(void *)) offset_list_del; + + install_element (RIP_NODE, &rip_offset_list_cmd); + install_element (RIP_NODE, &rip_offset_list_ifname_cmd); + install_element (RIP_NODE, &no_rip_offset_list_cmd); + install_element (RIP_NODE, &no_rip_offset_list_ifname_cmd); +} + +void +rip_offset_clean () +{ + list_delete (rip_offset_list_master); + + rip_offset_list_master = list_new (); + rip_offset_list_master->cmp = (int (*)(void *, void *)) offset_list_cmp; + rip_offset_list_master->del = (void (*)(void *)) offset_list_del; +} + +int +config_write_rip_offset_list (struct vty *vty) +{ + struct listnode *nn; + struct rip_offset_list *offset; + + LIST_LOOP (rip_offset_list_master, offset, nn) + { + if (! offset->ifname) + { + if (offset->direct[RIP_OFFSET_LIST_IN].alist_name) + vty_out (vty, " offset-list %s in %d%s", + offset->direct[RIP_OFFSET_LIST_IN].alist_name, + offset->direct[RIP_OFFSET_LIST_IN].metric, + VTY_NEWLINE); + if (offset->direct[RIP_OFFSET_LIST_OUT].alist_name) + vty_out (vty, " offset-list %s out %d%s", + offset->direct[RIP_OFFSET_LIST_OUT].alist_name, + offset->direct[RIP_OFFSET_LIST_OUT].metric, + VTY_NEWLINE); + } + else + { + if (offset->direct[RIP_OFFSET_LIST_IN].alist_name) + vty_out (vty, " offset-list %s in %d %s%s", + offset->direct[RIP_OFFSET_LIST_IN].alist_name, + offset->direct[RIP_OFFSET_LIST_IN].metric, + offset->ifname, VTY_NEWLINE); + if (offset->direct[RIP_OFFSET_LIST_OUT].alist_name) + vty_out (vty, " offset-list %s out %d %s%s", + offset->direct[RIP_OFFSET_LIST_OUT].alist_name, + offset->direct[RIP_OFFSET_LIST_OUT].metric, + offset->ifname, VTY_NEWLINE); + } + } + + return 0; +} diff --git a/ripd/rip_peer.c b/ripd/rip_peer.c new file mode 100644 index 00000000..20c2da73 --- /dev/null +++ b/ripd/rip_peer.c @@ -0,0 +1,211 @@ +/* RIP peer support + * Copyright (C) 2000 Kunihiro Ishiguro <kunihiro@zebra.org> + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> + +#include "if.h" +#include "prefix.h" +#include "command.h" +#include "linklist.h" +#include "thread.h" +#include "memory.h" + +#include "ripd/ripd.h" + +/* Linked list of RIP peer. */ +struct list *peer_list; + +struct rip_peer * +rip_peer_new () +{ + struct rip_peer *new; + + new = XMALLOC (MTYPE_RIP_PEER, sizeof (struct rip_peer)); + memset (new, 0, sizeof (struct rip_peer)); + return new; +} + +void +rip_peer_free (struct rip_peer *peer) +{ + XFREE (MTYPE_RIP_PEER, peer); +} + +struct rip_peer * +rip_peer_lookup (struct in_addr *addr) +{ + struct rip_peer *peer; + struct listnode *nn; + + LIST_LOOP (peer_list, peer, nn) + { + if (IPV4_ADDR_SAME (&peer->addr, addr)) + return peer; + } + return NULL; +} + +struct rip_peer * +rip_peer_lookup_next (struct in_addr *addr) +{ + struct rip_peer *peer; + struct listnode *nn; + + LIST_LOOP (peer_list, peer, nn) + { + if (htonl (peer->addr.s_addr) > htonl (addr->s_addr)) + return peer; + } + return NULL; +} + +/* RIP peer is timeout. */ +int +rip_peer_timeout (struct thread *t) +{ + struct rip_peer *peer; + + peer = THREAD_ARG (t); + listnode_delete (peer_list, peer); + rip_peer_free (peer); + + return 0; +} + +/* Get RIP peer. At the same time update timeout thread. */ +struct rip_peer * +rip_peer_get (struct in_addr *addr) +{ + struct rip_peer *peer; + + peer = rip_peer_lookup (addr); + + if (peer) + { + if (peer->t_timeout) + thread_cancel (peer->t_timeout); + } + else + { + peer = rip_peer_new (); + peer->addr = *addr; + listnode_add_sort (peer_list, peer); + } + + /* Update timeout thread. */ + peer->t_timeout = thread_add_timer (master, rip_peer_timeout, peer, + RIP_PEER_TIMER_DEFAULT); + + /* Last update time set. */ + time (&peer->uptime); + + return peer; +} + +void +rip_peer_update (struct sockaddr_in *from, u_char version) +{ + struct rip_peer *peer; + peer = rip_peer_get (&from->sin_addr); + peer->version = version; +} + +void +rip_peer_bad_route (struct sockaddr_in *from) +{ + struct rip_peer *peer; + peer = rip_peer_get (&from->sin_addr); + peer->recv_badroutes++; +} + +void +rip_peer_bad_packet (struct sockaddr_in *from) +{ + struct rip_peer *peer; + peer = rip_peer_get (&from->sin_addr); + peer->recv_badpackets++; +} + +/* Display peer uptime. */ +char * +rip_peer_uptime (struct rip_peer *peer, char *buf, size_t len) +{ + time_t uptime; + struct tm *tm; + + /* If there is no connection has been done before print `never'. */ + if (peer->uptime == 0) + { + snprintf (buf, len, "never "); + return buf; + } + + /* Get current time. */ + uptime = time (NULL); + uptime -= peer->uptime; + tm = gmtime (&uptime); + + /* Making formatted timer strings. */ +#define ONE_DAY_SECOND 60*60*24 +#define ONE_WEEK_SECOND 60*60*24*7 + + if (uptime < ONE_DAY_SECOND) + snprintf (buf, len, "%02d:%02d:%02d", + tm->tm_hour, tm->tm_min, tm->tm_sec); + else if (uptime < ONE_WEEK_SECOND) + snprintf (buf, len, "%dd%02dh%02dm", + tm->tm_yday, tm->tm_hour, tm->tm_min); + else + snprintf (buf, len, "%02dw%dd%02dh", + tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour); + return buf; +} + +void +rip_peer_display (struct vty *vty) +{ + struct rip_peer *peer; + struct listnode *nn; +#define RIP_UPTIME_LEN 25 + char timebuf[RIP_UPTIME_LEN]; + + LIST_LOOP (peer_list, peer, nn) + { + vty_out (vty, " %-16s %9d %9d %9d %s%s", inet_ntoa (peer->addr), + peer->recv_badpackets, peer->recv_badroutes, + ZEBRA_RIP_DISTANCE_DEFAULT, + rip_peer_uptime (peer, timebuf, RIP_UPTIME_LEN), + VTY_NEWLINE); + } +} + +int +rip_peer_list_cmp (struct rip_peer *p1, struct rip_peer *p2) +{ + return htonl (p1->addr.s_addr) > htonl (p2->addr.s_addr); +} + +void +rip_peer_init () +{ + peer_list = list_new (); + peer_list->cmp = (int (*)(void *, void *)) rip_peer_list_cmp; +} diff --git a/ripd/rip_routemap.c b/ripd/rip_routemap.c new file mode 100644 index 00000000..791de412 --- /dev/null +++ b/ripd/rip_routemap.c @@ -0,0 +1,898 @@ +/* RIPv2 routemap. + * Copyright (C) 1999 Kunihiro Ishiguro <kunihiro@zebra.org> + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> + +#include "memory.h" +#include "prefix.h" +#include "routemap.h" +#include "command.h" +#include "filter.h" +#include "log.h" +#include "sockunion.h" /* for inet_aton () */ +#include "plist.h" + +#include "ripd/ripd.h" + +/* Add rip route map rule. */ +int +rip_route_match_add (struct vty *vty, struct route_map_index *index, + char *command, char *arg) +{ + int ret; + + ret = route_map_add_match (index, command, arg); + if (ret) + { + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + case RMAP_COMPILE_ERROR: + vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + } + } + return CMD_SUCCESS; +} + +/* Delete rip route map rule. */ +int +rip_route_match_delete (struct vty *vty, struct route_map_index *index, + char *command, char *arg) +{ + int ret; + + ret = route_map_delete_match (index, command, arg); + if (ret) + { + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + case RMAP_COMPILE_ERROR: + vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + } + } + return CMD_SUCCESS; +} + +/* Add rip route map rule. */ +int +rip_route_set_add (struct vty *vty, struct route_map_index *index, + char *command, char *arg) +{ + int ret; + + ret = route_map_add_set (index, command, arg); + if (ret) + { + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + case RMAP_COMPILE_ERROR: + vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + } + } + return CMD_SUCCESS; +} + +/* Delete rip route map rule. */ +int +rip_route_set_delete (struct vty *vty, struct route_map_index *index, + char *command, char *arg) +{ + int ret; + + ret = route_map_delete_set (index, command, arg); + if (ret) + { + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + case RMAP_COMPILE_ERROR: + vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + } + } + return CMD_SUCCESS; +} + +/* Hook function for updating route_map assignment. */ +void +rip_route_map_update () +{ + int i; + + if (rip) + { + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + { + if (rip->route_map[i].name) + rip->route_map[i].map = + route_map_lookup_by_name (rip->route_map[i].name); + } + } +} + +/* `match metric METRIC' */ +/* Match function return 1 if match is success else return zero. */ +route_map_result_t +route_match_metric (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + u_int32_t *metric; + struct rip_info *rinfo; + + if (type == RMAP_RIP) + { + metric = rule; + rinfo = object; + + if (rinfo->metric == *metric) + return RMAP_MATCH; + else + return RMAP_NOMATCH; + } + return RMAP_NOMATCH; +} + +/* Route map `match metric' match statement. `arg' is METRIC value */ +void * +route_match_metric_compile (char *arg) +{ + u_int32_t *metric; + + metric = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); + *metric = atoi (arg); + + if(*metric > 0) + return metric; + + XFREE (MTYPE_ROUTE_MAP_COMPILED, metric); + return NULL; +} + +/* Free route map's compiled `match metric' value. */ +void +route_match_metric_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for metric matching. */ +struct route_map_rule_cmd route_match_metric_cmd = +{ + "metric", + route_match_metric, + route_match_metric_compile, + route_match_metric_free +}; + +/* `match interface IFNAME' */ +/* Match function return 1 if match is success else return zero. */ +route_map_result_t +route_match_interface (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct rip_info *rinfo; + struct interface *ifp; + char *ifname; + + if (type == RMAP_RIP) + { + ifname = rule; + ifp = if_lookup_by_name(ifname); + + if (!ifp) + return RMAP_NOMATCH; + + rinfo = object; + + if (rinfo->ifindex_out == ifp->ifindex) + return RMAP_MATCH; + else + return RMAP_NOMATCH; + } + return RMAP_NOMATCH; +} + +/* Route map `match interface' match statement. `arg' is IFNAME value */ +/* XXX I don`t know if I need to check does interface exist? */ +void * +route_match_interface_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +/* Free route map's compiled `match interface' value. */ +void +route_match_interface_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for interface matching. */ +struct route_map_rule_cmd route_match_interface_cmd = +{ + "interface", + route_match_interface, + route_match_interface_compile, + route_match_interface_free +}; + +/* `match ip next-hop IP_ACCESS_LIST' */ + +/* Match function return 1 if match is success else return zero. */ +route_map_result_t +route_match_ip_next_hop (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct access_list *alist; + struct rip_info *rinfo; + struct prefix_ipv4 p; + + if (type == RMAP_RIP) + { + rinfo = object; + p.family = AF_INET; + p.prefix = rinfo->nexthop; + p.prefixlen = IPV4_MAX_BITLEN; + + alist = access_list_lookup (AFI_IP, (char *) rule); + if (alist == NULL) + return RMAP_NOMATCH; + + return (access_list_apply (alist, &p) == FILTER_DENY ? + RMAP_NOMATCH : RMAP_MATCH); + } + return RMAP_NOMATCH; +} + +/* Route map `ip next-hop' match statement. `arg' should be + access-list name. */ +void * +route_match_ip_next_hop_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +/* Free route map's compiled `. */ +void +route_match_ip_next_hop_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for ip next-hop matching. */ +struct route_map_rule_cmd route_match_ip_next_hop_cmd = +{ + "ip next-hop", + route_match_ip_next_hop, + route_match_ip_next_hop_compile, + route_match_ip_next_hop_free +}; + +/* `match ip next-hop prefix-list PREFIX_LIST' */ + +route_map_result_t +route_match_ip_next_hop_prefix_list (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct prefix_list *plist; + struct rip_info *rinfo; + struct prefix_ipv4 p; + + if (type == RMAP_RIP) + { + rinfo = object; + p.family = AF_INET; + p.prefix = rinfo->nexthop; + p.prefixlen = IPV4_MAX_BITLEN; + + plist = prefix_list_lookup (AFI_IP, (char *) rule); + if (plist == NULL) + return RMAP_NOMATCH; + + return (prefix_list_apply (plist, &p) == PREFIX_DENY ? + RMAP_NOMATCH : RMAP_MATCH); + } + return RMAP_NOMATCH; +} + +void * +route_match_ip_next_hop_prefix_list_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +void +route_match_ip_next_hop_prefix_list_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = +{ + "ip next-hop prefix-list", + route_match_ip_next_hop_prefix_list, + route_match_ip_next_hop_prefix_list_compile, + route_match_ip_next_hop_prefix_list_free +}; + +/* `match ip address IP_ACCESS_LIST' */ + +/* Match function should return 1 if match is success else return + zero. */ +route_map_result_t +route_match_ip_address (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct access_list *alist; + + if (type == RMAP_RIP) + { + alist = access_list_lookup (AFI_IP, (char *) rule); + if (alist == NULL) + return RMAP_NOMATCH; + + return (access_list_apply (alist, prefix) == FILTER_DENY ? + RMAP_NOMATCH : RMAP_MATCH); + } + return RMAP_NOMATCH; +} + +/* Route map `ip address' match statement. `arg' should be + access-list name. */ +void * +route_match_ip_address_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +/* Free route map's compiled `ip address' value. */ +void +route_match_ip_address_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for ip address matching. */ +struct route_map_rule_cmd route_match_ip_address_cmd = +{ + "ip address", + route_match_ip_address, + route_match_ip_address_compile, + route_match_ip_address_free +}; + +/* `match ip address prefix-list PREFIX_LIST' */ + +route_map_result_t +route_match_ip_address_prefix_list (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct prefix_list *plist; + + if (type == RMAP_RIP) + { + plist = prefix_list_lookup (AFI_IP, (char *) rule); + if (plist == NULL) + return RMAP_NOMATCH; + + return (prefix_list_apply (plist, prefix) == PREFIX_DENY ? + RMAP_NOMATCH : RMAP_MATCH); + } + return RMAP_NOMATCH; +} + +void * +route_match_ip_address_prefix_list_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +void +route_match_ip_address_prefix_list_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = +{ + "ip address prefix-list", + route_match_ip_address_prefix_list, + route_match_ip_address_prefix_list_compile, + route_match_ip_address_prefix_list_free +}; + +/* `set metric METRIC' */ + +/* Set metric to attribute. */ +route_map_result_t +route_set_metric (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + u_int32_t *metric; + struct rip_info *rinfo; + + if (type == RMAP_RIP) + { + /* Fetch routemap's rule information. */ + metric = rule; + rinfo = object; + + /* Set metric out value. */ + rinfo->metric_out = *metric; + rinfo->metric_set = 1; + } + return RMAP_OKAY; +} + +/* set metric compilation. */ +void * +route_set_metric_compile (char *arg) +{ + u_int32_t *metric; + + metric = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); + *metric = atoi (arg); + + return metric; + +#if 0 + /* To make it consistent to other daemon, metric check is commented + out.*/ + if (*metric >= 0 && *metric <= 16) + return metric; + + XFREE (MTYPE_ROUTE_MAP_COMPILED, metric); + return NULL; +#endif /* 0 */ +} + +/* Free route map's compiled `set metric' value. */ +void +route_set_metric_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Set metric rule structure. */ +struct route_map_rule_cmd route_set_metric_cmd = +{ + "metric", + route_set_metric, + route_set_metric_compile, + route_set_metric_free, +}; + +/* `set ip next-hop IP_ADDRESS' */ + +/* Set nexthop to object. ojbect must be pointer to struct attr. */ +route_map_result_t +route_set_ip_nexthop (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct in_addr *address; + struct rip_info *rinfo; + + if(type == RMAP_RIP) + { + /* Fetch routemap's rule information. */ + address = rule; + rinfo = object; + + /* Set next hop value. */ + rinfo->nexthop_out = *address; + } + + return RMAP_OKAY; +} + +/* Route map `ip nexthop' compile function. Given string is converted + to struct in_addr structure. */ +void * +route_set_ip_nexthop_compile (char *arg) +{ + int ret; + struct in_addr *address; + + address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in_addr)); + + ret = inet_aton (arg, address); + + if (ret == 0) + { + XFREE (MTYPE_ROUTE_MAP_COMPILED, address); + return NULL; + } + + return address; +} + +/* Free route map's compiled `ip nexthop' value. */ +void +route_set_ip_nexthop_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for ip nexthop set. */ +struct route_map_rule_cmd route_set_ip_nexthop_cmd = +{ + "ip next-hop", + route_set_ip_nexthop, + route_set_ip_nexthop_compile, + route_set_ip_nexthop_free +}; + +#define MATCH_STR "Match values from routing table\n" +#define SET_STR "Set values in destination routing protocol\n" + +DEFUN (match_metric, + match_metric_cmd, + "match metric <0-4294967295>", + MATCH_STR + "Match metric of route\n" + "Metric value\n") +{ + return rip_route_match_add (vty, vty->index, "metric", argv[0]); +} + +DEFUN (no_match_metric, + no_match_metric_cmd, + "no match metric", + NO_STR + MATCH_STR + "Match metric of route\n") +{ + if (argc == 0) + return rip_route_match_delete (vty, vty->index, "metric", NULL); + + return rip_route_match_delete (vty, vty->index, "metric", argv[0]); +} + +ALIAS (no_match_metric, + no_match_metric_val_cmd, + "no match metric <0-4294967295>", + NO_STR + MATCH_STR + "Match metric of route\n" + "Metric value\n") + +DEFUN (match_interface, + match_interface_cmd, + "match interface WORD", + MATCH_STR + "Match first hop interface of route\n" + "Interface name\n") +{ + return rip_route_match_add (vty, vty->index, "interface", argv[0]); +} + +DEFUN (no_match_interface, + no_match_interface_cmd, + "no match interface", + NO_STR + MATCH_STR + "Match first hop interface of route\n") +{ + if (argc == 0) + return rip_route_match_delete (vty, vty->index, "interface", NULL); + + return rip_route_match_delete (vty, vty->index, "interface", argv[0]); +} + +ALIAS (no_match_interface, + no_match_interface_val_cmd, + "no match interface WORD", + NO_STR + MATCH_STR + "Match first hop interface of route\n" + "Interface name\n") + +DEFUN (match_ip_next_hop, + match_ip_next_hop_cmd, + "match ip next-hop WORD", + MATCH_STR + IP_STR + "Match next-hop address of route\n" + "IP access-list name\n") +{ + return rip_route_match_add (vty, vty->index, "ip next-hop", argv[0]); +} + +DEFUN (no_match_ip_next_hop, + no_match_ip_next_hop_cmd, + "no match ip next-hop", + NO_STR + MATCH_STR + IP_STR + "Match next-hop address of route\n") +{ + if (argc == 0) + return rip_route_match_delete (vty, vty->index, "ip next-hop", NULL); + + return rip_route_match_delete (vty, vty->index, "ip next-hop", argv[0]); +} + +ALIAS (no_match_ip_next_hop, + no_match_ip_next_hop_val_cmd, + "no match ip next-hop WORD", + NO_STR + MATCH_STR + IP_STR + "Match next-hop address of route\n" + "IP access-list name\n") + +DEFUN (match_ip_next_hop_prefix_list, + match_ip_next_hop_prefix_list_cmd, + "match ip next-hop prefix-list WORD", + MATCH_STR + IP_STR + "Match next-hop address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n") +{ + return rip_route_match_add (vty, vty->index, "ip next-hop prefix-list", argv[0]); +} + +DEFUN (no_match_ip_next_hop_prefix_list, + no_match_ip_next_hop_prefix_list_cmd, + "no match ip next-hop prefix-list", + NO_STR + MATCH_STR + IP_STR + "Match next-hop address of route\n" + "Match entries of prefix-lists\n") +{ + if (argc == 0) + return rip_route_match_delete (vty, vty->index, "ip next-hop prefix-list", NULL); + + return rip_route_match_delete (vty, vty->index, "ip next-hop prefix-list", argv[0]); +} + +ALIAS (no_match_ip_next_hop_prefix_list, + no_match_ip_next_hop_prefix_list_val_cmd, + "no match ip next-hop prefix-list WORD", + NO_STR + MATCH_STR + IP_STR + "Match next-hop address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n") + +DEFUN (match_ip_address, + match_ip_address_cmd, + "match ip address WORD", + MATCH_STR + IP_STR + "Match address of route\n" + "IP access-list name\n") +{ + return rip_route_match_add (vty, vty->index, "ip address", argv[0]); +} + +DEFUN (no_match_ip_address, + no_match_ip_address_cmd, + "no match ip address", + NO_STR + MATCH_STR + IP_STR + "Match address of route\n") +{ + if (argc == 0) + return rip_route_match_delete (vty, vty->index, "ip address", NULL); + + return rip_route_match_delete (vty, vty->index, "ip address", argv[0]); +} + +ALIAS (no_match_ip_address, + no_match_ip_address_val_cmd, + "no match ip address WORD", + NO_STR + MATCH_STR + IP_STR + "Match address of route\n" + "IP access-list name\n") + +DEFUN (match_ip_address_prefix_list, + match_ip_address_prefix_list_cmd, + "match ip address prefix-list WORD", + MATCH_STR + IP_STR + "Match address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n") +{ + return rip_route_match_add (vty, vty->index, "ip address prefix-list", argv[0]); +} + +DEFUN (no_match_ip_address_prefix_list, + no_match_ip_address_prefix_list_cmd, + "no match ip address prefix-list", + NO_STR + MATCH_STR + IP_STR + "Match address of route\n" + "Match entries of prefix-lists\n") +{ + if (argc == 0) + return rip_route_match_delete (vty, vty->index, "ip address prefix-list", NULL); + + return rip_route_match_delete (vty, vty->index, "ip address prefix-list", argv[0]); +} + +ALIAS (no_match_ip_address_prefix_list, + no_match_ip_address_prefix_list_val_cmd, + "no match ip address prefix-list WORD", + NO_STR + MATCH_STR + IP_STR + "Match address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n") + +/* set functions */ + +DEFUN (set_metric, + set_metric_cmd, + "set metric <0-4294967295>", + SET_STR + "Metric value for destination routing protocol\n" + "Metric value\n") +{ + return rip_route_set_add (vty, vty->index, "metric", argv[0]); +} + +DEFUN (no_set_metric, + no_set_metric_cmd, + "no set metric", + NO_STR + SET_STR + "Metric value for destination routing protocol\n") +{ + if (argc == 0) + return rip_route_set_delete (vty, vty->index, "metric", NULL); + + return rip_route_set_delete (vty, vty->index, "metric", argv[0]); +} + +ALIAS (no_set_metric, + no_set_metric_val_cmd, + "no set metric <0-4294967295>", + NO_STR + SET_STR + "Metric value for destination routing protocol\n" + "Metric value\n") + +DEFUN (set_ip_nexthop, + set_ip_nexthop_cmd, + "set ip next-hop A.B.C.D", + SET_STR + IP_STR + "Next hop address\n" + "IP address of next hop\n") +{ + union sockunion su; + int ret; + + ret = str2sockunion (argv[0], &su); + if (ret < 0) + { + vty_out (vty, "%% Malformed next-hop address%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return rip_route_set_add (vty, vty->index, "ip next-hop", argv[0]); +} + +DEFUN (no_set_ip_nexthop, + no_set_ip_nexthop_cmd, + "no set ip next-hop", + NO_STR + SET_STR + IP_STR + "Next hop address\n") +{ + if (argc == 0) + return rip_route_set_delete (vty, vty->index, "ip next-hop", NULL); + + return rip_route_set_delete (vty, vty->index, "ip next-hop", argv[0]); +} + +ALIAS (no_set_ip_nexthop, + no_set_ip_nexthop_val_cmd, + "no set ip next-hop A.B.C.D", + NO_STR + SET_STR + IP_STR + "Next hop address\n" + "IP address of next hop\n") + +void +rip_route_map_reset () +{ + ; +} + +/* Route-map init */ +void +rip_route_map_init () +{ + route_map_init (); + route_map_init_vty (); + route_map_add_hook (rip_route_map_update); + route_map_delete_hook (rip_route_map_update); + + route_map_install_match (&route_match_metric_cmd); + route_map_install_match (&route_match_interface_cmd); + route_map_install_match (&route_match_ip_next_hop_cmd); + route_map_install_match (&route_match_ip_next_hop_prefix_list_cmd); + route_map_install_match (&route_match_ip_address_cmd); + route_map_install_match (&route_match_ip_address_prefix_list_cmd); + + route_map_install_set (&route_set_metric_cmd); + route_map_install_set (&route_set_ip_nexthop_cmd); + + install_element (RMAP_NODE, &match_metric_cmd); + install_element (RMAP_NODE, &no_match_metric_cmd); + install_element (RMAP_NODE, &no_match_metric_val_cmd); + install_element (RMAP_NODE, &match_interface_cmd); + install_element (RMAP_NODE, &no_match_interface_cmd); + install_element (RMAP_NODE, &no_match_interface_val_cmd); + install_element (RMAP_NODE, &match_ip_next_hop_cmd); + install_element (RMAP_NODE, &no_match_ip_next_hop_cmd); + install_element (RMAP_NODE, &no_match_ip_next_hop_val_cmd); + install_element (RMAP_NODE, &match_ip_next_hop_prefix_list_cmd); + install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd); + install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_val_cmd); + install_element (RMAP_NODE, &match_ip_address_cmd); + install_element (RMAP_NODE, &no_match_ip_address_cmd); + install_element (RMAP_NODE, &no_match_ip_address_val_cmd); + install_element (RMAP_NODE, &match_ip_address_prefix_list_cmd); + install_element (RMAP_NODE, &no_match_ip_address_prefix_list_cmd); + install_element (RMAP_NODE, &no_match_ip_address_prefix_list_val_cmd); + + install_element (RMAP_NODE, &set_metric_cmd); + install_element (RMAP_NODE, &no_set_metric_cmd); + install_element (RMAP_NODE, &no_set_metric_val_cmd); + install_element (RMAP_NODE, &set_ip_nexthop_cmd); + install_element (RMAP_NODE, &no_set_ip_nexthop_cmd); + install_element (RMAP_NODE, &no_set_ip_nexthop_val_cmd); +} diff --git a/ripd/rip_snmp.c b/ripd/rip_snmp.c new file mode 100644 index 00000000..dc2b6212 --- /dev/null +++ b/ripd/rip_snmp.c @@ -0,0 +1,577 @@ +/* RIP SNMP support + * Copyright (C) 1999 Kunihiro Ishiguro <kunihiro@zebra.org> + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> + +#ifdef HAVE_SNMP +#include <asn1.h> +#include <snmp.h> +#include <snmp_impl.h> + +#include "if.h" +#include "log.h" +#include "prefix.h" +#include "command.h" +#include "table.h" +#include "smux.h" + +#include "ripd/ripd.h" + +/* RIPv2-MIB. */ +#define RIPV2MIB 1,3,6,1,2,1,23 + +/* Zebra enterprise RIP MIB. This variable is used for register + RIPv2-MIB to SNMP agent under SMUX protocol. */ +#define RIPDOID 1,3,6,1,4,1,3317,1,2,3 + +/* RIPv2-MIB rip2Globals values. */ +#define RIP2GLOBALROUTECHANGES 1 +#define RIP2GLOBALQUERIES 2 + +/* RIPv2-MIB rip2IfStatEntry. */ +#define RIP2IFSTATENTRY 1 + +/* RIPv2-MIB rip2IfStatTable. */ +#define RIP2IFSTATADDRESS 1 +#define RIP2IFSTATRCVBADPACKETS 2 +#define RIP2IFSTATRCVBADROUTES 3 +#define RIP2IFSTATSENTUPDATES 4 +#define RIP2IFSTATSTATUS 5 + +/* RIPv2-MIB rip2IfConfTable. */ +#define RIP2IFCONFADDRESS 1 +#define RIP2IFCONFDOMAIN 2 +#define RIP2IFCONFAUTHTYPE 3 +#define RIP2IFCONFAUTHKEY 4 +#define RIP2IFCONFSEND 5 +#define RIP2IFCONFRECEIVE 6 +#define RIP2IFCONFDEFAULTMETRIC 7 +#define RIP2IFCONFSTATUS 8 +#define RIP2IFCONFSRCADDRESS 9 + +/* RIPv2-MIB rip2PeerTable. */ +#define RIP2PEERADDRESS 1 +#define RIP2PEERDOMAIN 2 +#define RIP2PEERLASTUPDATE 3 +#define RIP2PEERVERSION 4 +#define RIP2PEERRCVBADPACKETS 5 +#define RIP2PEERRCVBADROUTES 6 + +/* SNMP value hack. */ +#define COUNTER ASN_COUNTER +#define INTEGER ASN_INTEGER +#define TIMETICKS ASN_TIMETICKS +#define IPADDRESS ASN_IPADDRESS +#define STRING ASN_OCTET_STR + +/* Define SNMP local variables. */ +SNMP_LOCAL_VARIABLES + +/* RIP-MIB instances. */ +oid rip_oid [] = { RIPV2MIB }; +oid ripd_oid [] = { RIPDOID }; + +/* Interface cache table sorted by interface's address. */ +struct route_table *rip_ifaddr_table; + +/* Hook functions. */ +static u_char *rip2Globals (); +static u_char *rip2IfStatEntry (); +static u_char *rip2IfConfAddress (); +static u_char *rip2PeerTable (); + +struct variable rip_variables[] = +{ + /* RIP Global Counters. */ + {RIP2GLOBALROUTECHANGES, COUNTER, RONLY, rip2Globals, + 2, {1, 1}}, + {RIP2GLOBALQUERIES, COUNTER, RONLY, rip2Globals, + 2, {1, 2}}, + /* RIP Interface Tables. */ + {RIP2IFSTATADDRESS, IPADDRESS, RONLY, rip2IfStatEntry, + 3, {2, 1, 1}}, + {RIP2IFSTATRCVBADPACKETS, COUNTER, RONLY, rip2IfStatEntry, + 3, {2, 1, 2}}, + {RIP2IFSTATRCVBADROUTES, COUNTER, RONLY, rip2IfStatEntry, + 3, {2, 1, 3}}, + {RIP2IFSTATSENTUPDATES, COUNTER, RONLY, rip2IfStatEntry, + 3, {2, 1, 4}}, + {RIP2IFSTATSTATUS, COUNTER, RWRITE, rip2IfStatEntry, + 3, {2, 1, 5}}, + {RIP2IFCONFADDRESS, IPADDRESS, RONLY, rip2IfConfAddress, + /* RIP Interface Configuration Table. */ + 3, {3, 1, 1}}, + {RIP2IFCONFDOMAIN, STRING, RONLY, rip2IfConfAddress, + 3, {3, 1, 2}}, + {RIP2IFCONFAUTHTYPE, COUNTER, RONLY, rip2IfConfAddress, + 3, {3, 1, 3}}, + {RIP2IFCONFAUTHKEY, STRING, RONLY, rip2IfConfAddress, + 3, {3, 1, 4}}, + {RIP2IFCONFSEND, COUNTER, RONLY, rip2IfConfAddress, + 3, {3, 1, 5}}, + {RIP2IFCONFRECEIVE, COUNTER, RONLY, rip2IfConfAddress, + 3, {3, 1, 6}}, + {RIP2IFCONFDEFAULTMETRIC, COUNTER, RONLY, rip2IfConfAddress, + 3, {3, 1, 7}}, + {RIP2IFCONFSTATUS, COUNTER, RONLY, rip2IfConfAddress, + 3, {3, 1, 8}}, + {RIP2IFCONFSRCADDRESS, IPADDRESS, RONLY, rip2IfConfAddress, + 3, {3, 1, 9}}, + {RIP2PEERADDRESS, IPADDRESS, RONLY, rip2PeerTable, + /* RIP Peer Table. */ + 3, {4, 1, 1}}, + {RIP2PEERDOMAIN, INTEGER, RONLY, rip2PeerTable, + 3, {4, 1, 2}}, + {RIP2PEERLASTUPDATE, TIMETICKS, RONLY, rip2PeerTable, + 3, {4, 1, 3}}, + {RIP2PEERVERSION, INTEGER, RONLY, rip2PeerTable, + 3, {4, 1, 4}}, + {RIP2PEERRCVBADPACKETS, COUNTER, RONLY, rip2PeerTable, + 3, {4, 1, 5}}, + {RIP2PEERRCVBADROUTES, COUNTER, RONLY, rip2PeerTable, + 3, {4, 1, 6}} +}; + +static u_char * +rip2Globals (struct variable *v, oid name[], size_t *length, + int exact, size_t *var_len, WriteMethod **write_method) +{ + if (smux_header_generic(v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + + /* Retrun global counter. */ + switch (v->magic) + { + case RIP2GLOBALROUTECHANGES: + return SNMP_INTEGER (rip_global_route_changes); + break; + case RIP2GLOBALQUERIES: + return SNMP_INTEGER (rip_global_queries); + break; + default: + return NULL; + break; + } + return NULL; +} + +void +rip_ifaddr_add (struct interface *ifp, struct connected *ifc) +{ + struct prefix *p; + struct route_node *rn; + + p = ifc->address; + + if (p->family != AF_INET) + return; + + rn = route_node_get (rip_ifaddr_table, p); + rn->info = ifp; +} + +void +rip_ifaddr_delete (struct interface *ifp, struct connected *ifc) +{ + struct prefix *p; + struct route_node *rn; + struct interface *i; + + p = ifc->address; + + if (p->family != AF_INET) + return; + + rn = route_node_lookup (rip_ifaddr_table, p); + if (! rn) + return; + i = rn->info; + if (rn && !strncmp(i->name,ifp->name,INTERFACE_NAMSIZ)) + { + rn->info = NULL; + route_unlock_node (rn); + route_unlock_node (rn); + } +} + +struct interface * +rip_ifaddr_lookup_next (struct in_addr *addr) +{ + struct prefix_ipv4 p; + struct route_node *rn; + struct interface *ifp; + + p.family = AF_INET; + p.prefixlen = IPV4_MAX_BITLEN; + p.prefix = *addr; + + rn = route_node_get (rip_ifaddr_table, (struct prefix *) &p); + + for (rn = route_next (rn); rn; rn = route_next (rn)) + if (rn->info) + break; + + if (rn && rn->info) + { + ifp = rn->info; + *addr = rn->p.u.prefix4; + route_unlock_node (rn); + return ifp; + } + return NULL; +} + +static struct interface * +rip2IfLookup (struct variable *v, oid name[], size_t *length, + struct in_addr *addr, int exact) +{ + int len; + struct interface *ifp; + + if (exact) + { + /* Check the length. */ + if (*length - v->namelen != sizeof (struct in_addr)) + return NULL; + + oid2in_addr (name + v->namelen, sizeof (struct in_addr), addr); + + return if_lookup_exact_address (*addr); + } + else + { + len = *length - v->namelen; + if (len > 4) len = 4; + + oid2in_addr (name + v->namelen, len, addr); + + ifp = rip_ifaddr_lookup_next (addr); + + if (ifp == NULL) + return NULL; + + oid_copy_addr (name + v->namelen, addr, sizeof (struct in_addr)); + + *length = v->namelen + sizeof (struct in_addr); + + return ifp; + } + return NULL; +} + +static struct rip_peer * +rip2PeerLookup (struct variable *v, oid name[], size_t *length, + struct in_addr *addr, int exact) +{ + int len; + struct rip_peer *peer; + + if (exact) + { + /* Check the length. */ + if (*length - v->namelen != sizeof (struct in_addr) + 1) + return NULL; + + oid2in_addr (name + v->namelen, sizeof (struct in_addr), addr); + + peer = rip_peer_lookup (addr); + + if (peer->domain == name[v->namelen + sizeof (struct in_addr)]) + return peer; + + return NULL; + } + else + { + len = *length - v->namelen; + if (len > 4) len = 4; + + oid2in_addr (name + v->namelen, len, addr); + + len = *length - v->namelen; + peer = rip_peer_lookup (addr); + if (peer) + { + if ((len < sizeof (struct in_addr) + 1) || + (peer->domain > name[v->namelen + sizeof (struct in_addr)])) + { + oid_copy_addr (name + v->namelen, &peer->addr, + sizeof (struct in_addr)); + name[v->namelen + sizeof (struct in_addr)] = peer->domain; + *length = sizeof (struct in_addr) + v->namelen + 1; + return peer; + } + } + peer = rip_peer_lookup_next (addr); + + if (! peer) + return NULL; + + oid_copy_addr (name + v->namelen, &peer->addr, + sizeof (struct in_addr)); + name[v->namelen + sizeof (struct in_addr)] = peer->domain; + *length = sizeof (struct in_addr) + v->namelen + 1; + + return peer; + } + return NULL; +} + +static u_char * +rip2IfStatEntry (struct variable *v, oid name[], size_t *length, + int exact, size_t *var_len, WriteMethod **write_method) +{ + struct interface *ifp; + struct rip_interface *ri; + static struct in_addr addr; + static long valid = SNMP_VALID; + + memset (&addr, 0, sizeof (struct in_addr)); + + /* Lookup interface. */ + ifp = rip2IfLookup (v, name, length, &addr, exact); + if (! ifp) + return NULL; + + /* Fetch rip_interface information. */ + ri = ifp->info; + + switch (v->magic) + { + case RIP2IFSTATADDRESS: + return SNMP_IPADDRESS (addr); + break; + case RIP2IFSTATRCVBADPACKETS: + *var_len = sizeof (long); + return (u_char *) &ri->recv_badpackets; + + case RIP2IFSTATRCVBADROUTES: + *var_len = sizeof (long); + return (u_char *) &ri->recv_badroutes; + + case RIP2IFSTATSENTUPDATES: + *var_len = sizeof (long); + return (u_char *) &ri->sent_updates; + + case RIP2IFSTATSTATUS: + *var_len = sizeof (long); + v->type = ASN_INTEGER; + return (u_char *) &valid; + + default: + return NULL; + + } + return NULL; +} + +static long +rip2IfConfSend (struct rip_interface *ri) +{ +#define doNotSend 1 +#define ripVersion1 2 +#define rip1Compatible 3 +#define ripVersion2 4 +#define ripV1Demand 5 +#define ripV2Demand 6 + + if (! ri->running) + return doNotSend; + + if (ri->ri_send & RIPv2) + return ripVersion2; + else if (ri->ri_send & RIPv1) + return ripVersion1; + else if (rip) + { + if (rip->version == RIPv2) + return ripVersion2; + else if (rip->version == RIPv1) + return ripVersion1; + } + return doNotSend; +} + +static long +rip2IfConfReceive (struct rip_interface *ri) +{ +#define rip1 1 +#define rip2 2 +#define rip1OrRip2 3 +#define doNotReceive 4 + + if (! ri->running) + return doNotReceive; + + if (ri->ri_receive == RI_RIP_VERSION_1_AND_2) + return rip1OrRip2; + else if (ri->ri_receive & RIPv2) + return ripVersion2; + else if (ri->ri_receive & RIPv1) + return ripVersion1; + else + return doNotReceive; +} + +static u_char * +rip2IfConfAddress (struct variable *v, oid name[], size_t *length, + int exact, size_t *val_len, WriteMethod **write_method) +{ + static struct in_addr addr; + static long valid = SNMP_INVALID; + static long domain = 0; + static long config = 0; + static u_int auth = 0; + struct interface *ifp; + struct rip_interface *ri; + + memset (&addr, 0, sizeof (struct in_addr)); + + /* Lookup interface. */ + ifp = rip2IfLookup (v, name, length, &addr, exact); + if (! ifp) + return NULL; + + /* Fetch rip_interface information. */ + ri = ifp->info; + + switch (v->magic) + { + case RIP2IFCONFADDRESS: + *val_len = sizeof (struct in_addr); + return (u_char *) &addr; + + case RIP2IFCONFDOMAIN: + *val_len = 2; + return (u_char *) &domain; + + case RIP2IFCONFAUTHTYPE: + auth = ri->auth_type; + *val_len = sizeof (long); + v->type = ASN_INTEGER; + return (u_char *)&auth; + + case RIP2IFCONFAUTHKEY: + *val_len = 0; + return (u_char *) &domain; + case RIP2IFCONFSEND: + config = rip2IfConfSend (ri); + *val_len = sizeof (long); + v->type = ASN_INTEGER; + return (u_char *) &config; + case RIP2IFCONFRECEIVE: + config = rip2IfConfReceive (ri); + *val_len = sizeof (long); + v->type = ASN_INTEGER; + return (u_char *) &config; + + case RIP2IFCONFDEFAULTMETRIC: + *val_len = sizeof (long); + v->type = ASN_INTEGER; + return (u_char *) &ifp->metric; + case RIP2IFCONFSTATUS: + *val_len = sizeof (long); + v->type = ASN_INTEGER; + return (u_char *) &valid; + case RIP2IFCONFSRCADDRESS: + *val_len = sizeof (struct in_addr); + return (u_char *) &addr; + + default: + return NULL; + + } + return NULL; +} + +static u_char * +rip2PeerTable (struct variable *v, oid name[], size_t *length, + int exact, size_t *val_len, WriteMethod **write_method) +{ + static struct in_addr addr; + static int version; + /* static time_t uptime; */ + + struct rip_peer *peer; + + memset (&addr, 0, sizeof (struct in_addr)); + + /* Lookup interface. */ + peer = rip2PeerLookup (v, name, length, &addr, exact); + if (! peer) + return NULL; + + switch (v->magic) + { + case RIP2PEERADDRESS: + *val_len = sizeof (struct in_addr); + return (u_char *) &peer->addr; + + case RIP2PEERDOMAIN: + *val_len = sizeof (int); + return (u_char *) &peer->domain; + + case RIP2PEERLASTUPDATE: +#if 0 + /* We don't know the SNMP agent startup time. We have two choices here: + * - assume ripd startup time equals SNMP agent startup time + * - don't support this variable, at all + * Currently, we do the latter... + */ + *val_len = sizeof (time_t); + uptime = peer->uptime; /* now - snmp_agent_startup - peer->uptime */ + return (u_char *) &uptime; +#else + return (u_char *) NULL; +#endif + + case RIP2PEERVERSION: + *val_len = sizeof (int); + version = peer->version; + return (u_char *) &version; + + case RIP2PEERRCVBADPACKETS: + *val_len = sizeof (int); + return (u_char *) &peer->recv_badpackets; + + case RIP2PEERRCVBADROUTES: + *val_len = sizeof (int); + return (u_char *) &peer->recv_badroutes; + + default: + return NULL; + + } + return NULL; +} + +/* Register RIPv2-MIB. */ +void +rip_snmp_init () +{ + rip_ifaddr_table = route_table_init (); + + smux_init (ripd_oid, sizeof (ripd_oid) / sizeof (oid)); + REGISTER_MIB("mibII/rip", rip_variables, variable, rip_oid); + smux_start (); +} +#endif /* HAVE_SNMP */ diff --git a/ripd/rip_zebra.c b/ripd/rip_zebra.c new file mode 100644 index 00000000..b6caf3b0 --- /dev/null +++ b/ripd/rip_zebra.c @@ -0,0 +1,691 @@ +/* RIPd and zebra interface. + * Copyright (C) 1997, 1999 Kunihiro Ishiguro <kunihiro@zebra.org> + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> + +#include "command.h" +#include "prefix.h" +#include "stream.h" +#include "routemap.h" +#include "zclient.h" +#include "log.h" +#include "ripd/ripd.h" +#include "ripd/rip_debug.h" + +/* All information about zebra. */ +struct zclient *zclient = NULL; + +/* Callback prototypes for zebra client service. */ +int rip_interface_add (int, struct zclient *, zebra_size_t); +int rip_interface_delete (int, struct zclient *, zebra_size_t); +int rip_interface_address_add (int, struct zclient *, zebra_size_t); +int rip_interface_address_delete (int, struct zclient *, zebra_size_t); +int rip_interface_up (int, struct zclient *, zebra_size_t); +int rip_interface_down (int, struct zclient *, zebra_size_t); + +/* RIPd to zebra command interface. */ +void +rip_zebra_ipv4_add (struct prefix_ipv4 *p, struct in_addr *nexthop, + u_int32_t metric, u_char distance) +{ + struct zapi_ipv4 api; + + if (zclient->redist[ZEBRA_ROUTE_RIP]) + { + api.type = ZEBRA_ROUTE_RIP; + api.flags = 0; + api.message = 0; + SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); + api.nexthop_num = 1; + api.nexthop = &nexthop; + api.ifindex_num = 0; + SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); + api.metric = metric; + + if (distance && distance != ZEBRA_RIP_DISTANCE_DEFAULT) + { + SET_FLAG (api.message, ZAPI_MESSAGE_DISTANCE); + api.distance = distance; + } + + zapi_ipv4_add (zclient, p, &api); + + rip_global_route_changes++; + } +} + +void +rip_zebra_ipv4_delete (struct prefix_ipv4 *p, struct in_addr *nexthop, + u_int32_t metric) +{ + struct zapi_ipv4 api; + + if (zclient->redist[ZEBRA_ROUTE_RIP]) + { + api.type = ZEBRA_ROUTE_RIP; + api.flags = 0; + api.message = 0; + SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); + api.nexthop_num = 1; + api.nexthop = &nexthop; + api.ifindex_num = 0; + SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); + api.metric = metric; + + zapi_ipv4_delete (zclient, p, &api); + + rip_global_route_changes++; + } +} + +/* Zebra route add and delete treatment. */ +int +rip_zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length) +{ + struct stream *s; + struct zapi_ipv4 api; + unsigned long ifindex; + struct in_addr nexthop; + struct prefix_ipv4 p; + + s = zclient->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)) + { + api.nexthop_num = stream_getc (s); + nexthop.s_addr = stream_get_ipv4 (s); + } + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) + { + api.ifindex_num = stream_getc (s); + ifindex = stream_getl (s); + } + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) + api.distance = stream_getc (s); + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) + api.metric = stream_getl (s); + + /* Then fetch IPv4 prefixes. */ + if (command == ZEBRA_IPV4_ROUTE_ADD) + rip_redistribute_add (api.type, RIP_ROUTE_REDISTRIBUTE, &p, ifindex, &nexthop); + else + rip_redistribute_delete (api.type, RIP_ROUTE_REDISTRIBUTE, &p, ifindex); + + return 0; +} + +void +rip_zclient_reset () +{ + zclient_reset (zclient); +} + +/* RIP route-map set for redistribution */ +void +rip_routemap_set (int type, char *name) +{ + if (rip->route_map[type].name) + free(rip->route_map[type].name); + + rip->route_map[type].name = strdup (name); + rip->route_map[type].map = route_map_lookup_by_name (name); +} + +void +rip_redistribute_metric_set (int type, int metric) +{ + rip->route_map[type].metric_config = 1; + rip->route_map[type].metric = metric; +} + +int +rip_metric_unset (int type,int metric) +{ +#define DONT_CARE_METRIC_RIP 17 + if (metric != DONT_CARE_METRIC_RIP && + rip->route_map[type].metric != metric) + return 1; + rip->route_map[type].metric_config = 0; + rip->route_map[type].metric = 0; + return 0; +} + +/* RIP route-map unset for redistribution */ +int +rip_routemap_unset (int type,char *name) +{ + if (! rip->route_map[type].name || + (name != NULL && strcmp(rip->route_map[type].name,name))) + return 1; + + free (rip->route_map[type].name); + rip->route_map[type].name = NULL; + rip->route_map[type].map = NULL; + + return 0; +} + +/* Redistribution types */ +static struct { + int type; + int str_min_len; + char *str; +} redist_type[] = { + {ZEBRA_ROUTE_KERNEL, 1, "kernel"}, + {ZEBRA_ROUTE_CONNECT, 1, "connected"}, + {ZEBRA_ROUTE_STATIC, 1, "static"}, + {ZEBRA_ROUTE_OSPF, 1, "ospf"}, + {ZEBRA_ROUTE_BGP, 1, "bgp"}, + {0, 0, NULL} +}; + +DEFUN (router_zebra, + router_zebra_cmd, + "router zebra", + "Enable a routing process\n" + "Make connection to zebra daemon\n") +{ + vty->node = ZEBRA_NODE; + zclient->enable = 1; + zclient_start (zclient); + return CMD_SUCCESS; +} + +DEFUN (no_router_zebra, + no_router_zebra_cmd, + "no router zebra", + NO_STR + "Enable a routing process\n" + "Make connection to zebra daemon\n") +{ + zclient->enable = 0; + zclient_stop (zclient); + return CMD_SUCCESS; +} + +int +rip_redistribute_set (int type) +{ + if (zclient->redist[type]) + return CMD_SUCCESS; + + zclient->redist[type] = 1; + + if (zclient->sock > 0) + zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient->sock, type); + + return CMD_SUCCESS; +} + +int +rip_redistribute_unset (int type) +{ + if (! zclient->redist[type]) + return CMD_SUCCESS; + + zclient->redist[type] = 0; + + if (zclient->sock > 0) + zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient->sock, type); + + /* Remove the routes from RIP table. */ + rip_redistribute_withdraw (type); + + return CMD_SUCCESS; +} + +int +rip_redistribute_check (int type) +{ + return (zclient->redist[type]); +} + +void +rip_redistribute_clean () +{ + int i; + + for (i = 0; redist_type[i].str; i++) + { + if (zclient->redist[redist_type[i].type]) + { + if (zclient->sock > 0) + zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, + zclient->sock, redist_type[i].type); + + zclient->redist[redist_type[i].type] = 0; + + /* Remove the routes from RIP table. */ + rip_redistribute_withdraw (redist_type[i].type); + } + } +} + +DEFUN (rip_redistribute_rip, + rip_redistribute_rip_cmd, + "redistribute rip", + "Redistribute information from another routing protocol\n" + "Routing Information Protocol (RIP)\n") +{ + zclient->redist[ZEBRA_ROUTE_RIP] = 1; + return CMD_SUCCESS; +} + +DEFUN (no_rip_redistribute_rip, + no_rip_redistribute_rip_cmd, + "no redistribute rip", + NO_STR + "Redistribute information from another routing protocol\n" + "Routing Information Protocol (RIP)\n") +{ + zclient->redist[ZEBRA_ROUTE_RIP] = 0; + return CMD_SUCCESS; +} + +DEFUN (rip_redistribute_type, + rip_redistribute_type_cmd, + "redistribute (kernel|connected|static|ospf|bgp)", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Open Shortest Path First (OSPF)\n" + "Border Gateway Protocol (BGP)\n") +{ + int i; + + for(i = 0; redist_type[i].str; i++) + { + if (strncmp (redist_type[i].str, argv[0], + redist_type[i].str_min_len) == 0) + { + zclient_redistribute_set (zclient, redist_type[i].type); + return CMD_SUCCESS; + } + } + + vty_out(vty, "Invalid type %s%s", argv[0], + VTY_NEWLINE); + + return CMD_WARNING; +} + +DEFUN (no_rip_redistribute_type, + no_rip_redistribute_type_cmd, + "no redistribute (kernel|connected|static|ospf|bgp)", + NO_STR + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Open Shortest Path First (OSPF)\n" + "Border Gateway Protocol (BGP)\n") +{ + int i; + + for (i = 0; redist_type[i].str; i++) + { + if (strncmp(redist_type[i].str, argv[0], + redist_type[i].str_min_len) == 0) + { + rip_metric_unset (redist_type[i].type, DONT_CARE_METRIC_RIP); + rip_routemap_unset (redist_type[i].type,NULL); + rip_redistribute_unset (redist_type[i].type); + return CMD_SUCCESS; + } + } + + vty_out(vty, "Invalid type %s%s", argv[0], + VTY_NEWLINE); + + return CMD_WARNING; +} + +DEFUN (rip_redistribute_type_routemap, + rip_redistribute_type_routemap_cmd, + "redistribute (kernel|connected|static|ospf|bgp) route-map WORD", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Open Shortest Path First (OSPF)\n" + "Border Gateway Protocol (BGP)\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + int i; + + for (i = 0; redist_type[i].str; i++) { + if (strncmp(redist_type[i].str, argv[0], + redist_type[i].str_min_len) == 0) + { + rip_routemap_set (redist_type[i].type, argv[1]); + zclient_redistribute_set (zclient, redist_type[i].type); + return CMD_SUCCESS; + } + } + + vty_out(vty, "Invalid type %s%s", argv[0], + VTY_NEWLINE); + + return CMD_WARNING; +} + +DEFUN (no_rip_redistribute_type_routemap, + no_rip_redistribute_type_routemap_cmd, + "no redistribute (kernel|connected|static|ospf|bgp) route-map WORD", + NO_STR + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Open Shortest Path First (OSPF)\n" + "Border Gateway Protocol (BGP)\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + int i; + + for (i = 0; redist_type[i].str; i++) + { + if (strncmp(redist_type[i].str, argv[0], + redist_type[i].str_min_len) == 0) + { + if (rip_routemap_unset (redist_type[i].type,argv[1])) + return CMD_WARNING; + rip_redistribute_unset (redist_type[i].type); + return CMD_SUCCESS; + } + } + + vty_out(vty, "Invalid type %s%s", argv[0], + VTY_NEWLINE); + + return CMD_WARNING; +} + +DEFUN (rip_redistribute_type_metric, + rip_redistribute_type_metric_cmd, + "redistribute (kernel|connected|static|ospf|bgp) metric <0-16>", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Open Shortest Path First (OSPF)\n" + "Border Gateway Protocol (BGP)\n" + "Metric\n" + "Metric value\n") +{ + int i; + int metric; + + metric = atoi (argv[1]); + + for (i = 0; redist_type[i].str; i++) { + if (strncmp(redist_type[i].str, argv[0], + redist_type[i].str_min_len) == 0) + { + rip_redistribute_metric_set (redist_type[i].type, metric); + zclient_redistribute_set (zclient, redist_type[i].type); + return CMD_SUCCESS; + } + } + + vty_out(vty, "Invalid type %s%s", argv[0], + VTY_NEWLINE); + + return CMD_WARNING; +} + +DEFUN (no_rip_redistribute_type_metric, + no_rip_redistribute_type_metric_cmd, + "no redistribute (kernel|connected|static|ospf|bgp) metric <0-16>", + NO_STR + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Open Shortest Path First (OSPF)\n" + "Border Gateway Protocol (BGP)\n" + "Metric\n" + "Metric value\n") +{ + int i; + + for (i = 0; redist_type[i].str; i++) + { + if (strncmp(redist_type[i].str, argv[0], + redist_type[i].str_min_len) == 0) + { + if (rip_metric_unset (redist_type[i].type, atoi(argv[1]))) + return CMD_WARNING; + rip_redistribute_unset (redist_type[i].type); + return CMD_SUCCESS; + } + } + + vty_out(vty, "Invalid type %s%s", argv[0], + VTY_NEWLINE); + + return CMD_WARNING; +} + +DEFUN (no_rip_redistribute_type_metric_routemap, + no_rip_redistribute_type_metric_routemap_cmd, + "no redistribute (kernel|connected|static|ospf|bgp) metric <0-16> route-map WORD", + NO_STR + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Open Shortest Path First (OSPF)\n" + "Border Gateway Protocol (BGP)\n" + "Metric\n" + "Metric value\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + int i; + + for (i = 0; redist_type[i].str; i++) + { + if (strncmp(redist_type[i].str, argv[0], + redist_type[i].str_min_len) == 0) + { + if (rip_metric_unset (redist_type[i].type, atoi(argv[1]))) + return CMD_WARNING; + if (rip_routemap_unset (redist_type[i].type, argv[2])) + { + rip_redistribute_metric_set(redist_type[i].type, atoi(argv[1])); + return CMD_WARNING; + } + rip_redistribute_unset (redist_type[i].type); + return CMD_SUCCESS; + } + } + + vty_out(vty, "Invalid type %s%s", argv[0], + VTY_NEWLINE); + + return CMD_WARNING; +} + +/* Default information originate. */ + +DEFUN (rip_default_information_originate, + rip_default_information_originate_cmd, + "default-information originate", + "Control distribution of default route\n" + "Distribute a default route\n") +{ + struct prefix_ipv4 p; + + if (! rip->default_information) + { + memset (&p, 0, sizeof (struct prefix_ipv4)); + p.family = AF_INET; + + rip->default_information = 1; + + rip_redistribute_add (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0, NULL); + } + + return CMD_SUCCESS; +} + +DEFUN (no_rip_default_information_originate, + no_rip_default_information_originate_cmd, + "no default-information originate", + NO_STR + "Control distribution of default route\n" + "Distribute a default route\n") +{ + struct prefix_ipv4 p; + + if (rip->default_information) + { + memset (&p, 0, sizeof (struct prefix_ipv4)); + p.family = AF_INET; + + rip->default_information = 0; + + rip_redistribute_delete (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0); + } + + return CMD_SUCCESS; +} + +/* RIP configuration write function. */ +int +config_write_zebra (struct vty *vty) +{ + if (! zclient->enable) + { + vty_out (vty, "no router zebra%s", VTY_NEWLINE); + return 1; + } + else if (! zclient->redist[ZEBRA_ROUTE_RIP]) + { + vty_out (vty, "router zebra%s", VTY_NEWLINE); + vty_out (vty, " no redistribute rip%s", VTY_NEWLINE); + return 1; + } + return 0; +} + +int +config_write_rip_redistribute (struct vty *vty, int config_mode) +{ + int i; + char *str[] = { "system", "kernel", "connected", "static", "rip", + "ripng", "ospf", "ospf6", "bgp"}; + + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + if (i != zclient->redist_default && zclient->redist[i]) + { + if (config_mode) + { + if (rip->route_map[i].metric_config) + { + if (rip->route_map[i].name) + vty_out (vty, " redistribute %s metric %d route-map %s%s", + str[i], rip->route_map[i].metric, + rip->route_map[i].name, + VTY_NEWLINE); + else + vty_out (vty, " redistribute %s metric %d%s", + str[i], rip->route_map[i].metric, + VTY_NEWLINE); + } + else + { + if (rip->route_map[i].name) + vty_out (vty, " redistribute %s route-map %s%s", + str[i], rip->route_map[i].name, + VTY_NEWLINE); + else + vty_out (vty, " redistribute %s%s", str[i], + VTY_NEWLINE); + } + } + else + vty_out (vty, " %s", str[i]); + } + return 0; +} + +/* Zebra node structure. */ +struct cmd_node zebra_node = +{ + ZEBRA_NODE, + "%s(config-router)# ", +}; + +void +rip_zclient_init () +{ + /* Set default value to the zebra client structure. */ + zclient = zclient_new (); + zclient_init (zclient, ZEBRA_ROUTE_RIP); + zclient->interface_add = rip_interface_add; + zclient->interface_delete = rip_interface_delete; + zclient->interface_address_add = rip_interface_address_add; + zclient->interface_address_delete = rip_interface_address_delete; + zclient->ipv4_route_add = rip_zebra_read_ipv4; + zclient->ipv4_route_delete = rip_zebra_read_ipv4; + zclient->interface_up = rip_interface_up; + zclient->interface_down = rip_interface_down; + + /* Install zebra node. */ + install_node (&zebra_node, config_write_zebra); + + /* Install command elements to zebra node. */ + install_element (CONFIG_NODE, &router_zebra_cmd); + install_element (CONFIG_NODE, &no_router_zebra_cmd); + install_default (ZEBRA_NODE); + install_element (ZEBRA_NODE, &rip_redistribute_rip_cmd); + install_element (ZEBRA_NODE, &no_rip_redistribute_rip_cmd); + + /* Install command elements to rip node. */ + install_element (RIP_NODE, &rip_redistribute_type_cmd); + install_element (RIP_NODE, &rip_redistribute_type_routemap_cmd); + install_element (RIP_NODE, &rip_redistribute_type_metric_cmd); + install_element (RIP_NODE, &no_rip_redistribute_type_cmd); + install_element (RIP_NODE, &no_rip_redistribute_type_routemap_cmd); + install_element (RIP_NODE, &no_rip_redistribute_type_metric_cmd); + install_element (RIP_NODE, &no_rip_redistribute_type_metric_routemap_cmd); + install_element (RIP_NODE, &rip_default_information_originate_cmd); + install_element (RIP_NODE, &no_rip_default_information_originate_cmd); +} diff --git a/ripd/ripd.c b/ripd/ripd.c new file mode 100644 index 00000000..c017fe56 --- /dev/null +++ b/ripd/ripd.c @@ -0,0 +1,3536 @@ +/* RIP version 1 and 2. + * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro <kunihiro@zebra.org> + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> + +#include "if.h" +#include "command.h" +#include "prefix.h" +#include "table.h" +#include "thread.h" +#include "memory.h" +#include "log.h" +#include "stream.h" +#include "filter.h" +#include "sockunion.h" +#include "routemap.h" +#include "plist.h" +#include "distribute.h" +#include "md5-gnu.h" +#include "keychain.h" + +#include "ripd/ripd.h" +#include "ripd/rip_debug.h" + +/* RIP Structure. */ +struct rip *rip = NULL; + +/* RIP neighbor address table. */ +struct route_table *rip_neighbor_table; + +/* RIP route changes. */ +long rip_global_route_changes = 0; + +/* RIP queries. */ +long rip_global_queries = 0; + +/* Prototypes. */ +void rip_event (enum rip_event, int); + +void rip_output_process (struct interface *, struct sockaddr_in *, + int, u_char); + +/* RIP output routes type. */ +enum +{ + rip_all_route, + rip_changed_route +}; + +/* RIP command strings. */ +struct message rip_msg[] = +{ + {RIP_REQUEST, "REQUEST"}, + {RIP_RESPONSE, "RESPONSE"}, + {RIP_TRACEON, "TRACEON"}, + {RIP_TRACEOFF, "TRACEOFF"}, + {RIP_POLL, "POLL"}, + {RIP_POLL_ENTRY, "POLL ENTRY"}, + {0, NULL} +}; + +/* Each route type's strings and default preference. */ +struct +{ + int key; + char *str; + char *str_long; +} route_info[] = +{ + { ZEBRA_ROUTE_SYSTEM, "X", "system"}, + { ZEBRA_ROUTE_KERNEL, "K", "kernel"}, + { ZEBRA_ROUTE_CONNECT, "C", "connected"}, + { ZEBRA_ROUTE_STATIC, "S", "static"}, + { ZEBRA_ROUTE_RIP, "R", "rip"}, + { ZEBRA_ROUTE_RIPNG, "R", "ripng"}, + { ZEBRA_ROUTE_OSPF, "O", "ospf"}, + { ZEBRA_ROUTE_OSPF6, "O", "ospf6"}, + { ZEBRA_ROUTE_BGP, "B", "bgp"} +}; + +/* Utility function to set boradcast option to the socket. */ +int +sockopt_broadcast (int sock) +{ + int ret; + int on = 1; + + ret = setsockopt (sock, SOL_SOCKET, SO_BROADCAST, (char *) &on, sizeof on); + if (ret < 0) + { + zlog_warn ("can't set sockopt SO_BROADCAST to socket %d", sock); + return -1; + } + return 0; +} + +int +rip_route_rte (struct rip_info *rinfo) +{ + return (rinfo->type == ZEBRA_ROUTE_RIP && rinfo->sub_type == RIP_ROUTE_RTE); +} + +struct rip_info * +rip_info_new () +{ + struct rip_info *new; + + new = XMALLOC (MTYPE_RIP_INFO, sizeof (struct rip_info)); + memset (new, 0, sizeof (struct rip_info)); + return new; +} + +void +rip_info_free (struct rip_info *rinfo) +{ + XFREE (MTYPE_RIP_INFO, rinfo); +} + +/* RIP route garbage collect timer. */ +int +rip_garbage_collect (struct thread *t) +{ + struct rip_info *rinfo; + struct route_node *rp; + + rinfo = THREAD_ARG (t); + rinfo->t_garbage_collect = NULL; + + /* Off timeout timer. */ + RIP_TIMER_OFF (rinfo->t_timeout); + + /* Get route_node pointer. */ + rp = rinfo->rp; + + /* Unlock route_node. */ + rp->info = NULL; + route_unlock_node (rp); + + /* Free RIP routing information. */ + rip_info_free (rinfo); + + return 0; +} + +/* Timeout RIP routes. */ +int +rip_timeout (struct thread *t) +{ + struct rip_info *rinfo; + struct route_node *rn; + + rinfo = THREAD_ARG (t); + rinfo->t_timeout = NULL; + + rn = rinfo->rp; + + /* - The garbage-collection timer is set for 120 seconds. */ + RIP_TIMER_ON (rinfo->t_garbage_collect, rip_garbage_collect, + rip->garbage_time); + + rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rn->p, &rinfo->nexthop, + rinfo->metric); + /* - The metric for the route is set to 16 (infinity). This causes + the route to be removed from service. */ + rinfo->metric = RIP_METRIC_INFINITY; + rinfo->flags &= ~RIP_RTF_FIB; + + /* - The route change flag is to indicate that this entry has been + changed. */ + rinfo->flags |= RIP_RTF_CHANGED; + + /* - The output process is signalled to trigger a response. */ + rip_event (RIP_TRIGGERED_UPDATE, 0); + + return 0; +} + +void +rip_timeout_update (struct rip_info *rinfo) +{ + if (rinfo->metric != RIP_METRIC_INFINITY) + { + RIP_TIMER_OFF (rinfo->t_timeout); + RIP_TIMER_ON (rinfo->t_timeout, rip_timeout, rip->timeout_time); + } +} + +int +rip_incoming_filter (struct prefix_ipv4 *p, struct rip_interface *ri) +{ + struct distribute *dist; + struct access_list *alist; + struct prefix_list *plist; + + /* Input distribute-list filtering. */ + if (ri->list[RIP_FILTER_IN]) + { + if (access_list_apply (ri->list[RIP_FILTER_IN], + (struct prefix *) p) == FILTER_DENY) + { + if (IS_RIP_DEBUG_PACKET) + zlog_info ("%s/%d filtered by distribute in", + inet_ntoa (p->prefix), p->prefixlen); + return -1; + } + } + if (ri->prefix[RIP_FILTER_IN]) + { + if (prefix_list_apply (ri->prefix[RIP_FILTER_IN], + (struct prefix *) p) == PREFIX_DENY) + { + if (IS_RIP_DEBUG_PACKET) + zlog_info ("%s/%d filtered by prefix-list in", + inet_ntoa (p->prefix), p->prefixlen); + return -1; + } + } + + /* All interface filter check. */ + dist = distribute_lookup (NULL); + if (dist) + { + if (dist->list[DISTRIBUTE_IN]) + { + alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_IN]); + + if (alist) + { + if (access_list_apply (alist, + (struct prefix *) p) == FILTER_DENY) + { + if (IS_RIP_DEBUG_PACKET) + zlog_info ("%s/%d filtered by distribute in", + inet_ntoa (p->prefix), p->prefixlen); + return -1; + } + } + } + if (dist->prefix[DISTRIBUTE_IN]) + { + plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_IN]); + + if (plist) + { + if (prefix_list_apply (plist, + (struct prefix *) p) == PREFIX_DENY) + { + if (IS_RIP_DEBUG_PACKET) + zlog_info ("%s/%d filtered by prefix-list in", + inet_ntoa (p->prefix), p->prefixlen); + return -1; + } + } + } + } + return 0; +} + +int +rip_outgoing_filter (struct prefix_ipv4 *p, struct rip_interface *ri) +{ + struct distribute *dist; + struct access_list *alist; + struct prefix_list *plist; + + if (ri->list[RIP_FILTER_OUT]) + { + if (access_list_apply (ri->list[RIP_FILTER_OUT], + (struct prefix *) p) == FILTER_DENY) + { + if (IS_RIP_DEBUG_PACKET) + zlog_info ("%s/%d is filtered by distribute out", + inet_ntoa (p->prefix), p->prefixlen); + return -1; + } + } + if (ri->prefix[RIP_FILTER_OUT]) + { + if (prefix_list_apply (ri->prefix[RIP_FILTER_OUT], + (struct prefix *) p) == PREFIX_DENY) + { + if (IS_RIP_DEBUG_PACKET) + zlog_info ("%s/%d is filtered by prefix-list out", + inet_ntoa (p->prefix), p->prefixlen); + return -1; + } + } + + /* All interface filter check. */ + dist = distribute_lookup (NULL); + if (dist) + { + if (dist->list[DISTRIBUTE_OUT]) + { + alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_OUT]); + + if (alist) + { + if (access_list_apply (alist, + (struct prefix *) p) == FILTER_DENY) + { + if (IS_RIP_DEBUG_PACKET) + zlog_info ("%s/%d filtered by distribute out", + inet_ntoa (p->prefix), p->prefixlen); + return -1; + } + } + } + if (dist->prefix[DISTRIBUTE_OUT]) + { + plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_OUT]); + + if (plist) + { + if (prefix_list_apply (plist, + (struct prefix *) p) == PREFIX_DENY) + { + if (IS_RIP_DEBUG_PACKET) + zlog_info ("%s/%d filtered by prefix-list out", + inet_ntoa (p->prefix), p->prefixlen); + return -1; + } + } + } + } + return 0; +} + +/* Check nexthop address validity. */ +static int +rip_nexthop_check (struct in_addr *addr) +{ + listnode node; + listnode cnode; + struct interface *ifp; + struct connected *ifc; + struct prefix *p; + + /* If nexthop address matches local configured address then it is + invalid nexthop. */ + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + + for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) + { + ifc = getdata (cnode); + p = ifc->address; + + if (p->family == AF_INET + && IPV4_ADDR_SAME (&p->u.prefix4, addr)) + return -1; + } + } + return 0; +} + +/* RIP add route to routing table. */ +void +rip_rte_process (struct rte *rte, struct sockaddr_in *from, + struct interface *ifp) + +{ + int ret; + struct prefix_ipv4 p; + struct route_node *rp; + struct rip_info *rinfo; + struct rip_interface *ri; + struct in_addr *nexthop; + u_char oldmetric; + int same = 0; + + /* Make prefix structure. */ + memset (&p, 0, sizeof (struct prefix_ipv4)); + p.family = AF_INET; + p.prefix = rte->prefix; + p.prefixlen = ip_masklen (rte->mask); + + /* Make sure mask is applied. */ + apply_mask_ipv4 (&p); + + /* Apply input filters. */ + ri = ifp->info; + + ret = rip_incoming_filter (&p, ri); + if (ret < 0) + return; + + /* Once the entry has been validated, update the metric by + adding the cost of the network on wich the message + arrived. If the result is greater than infinity, use infinity + (RFC2453 Sec. 3.9.2) */ + /* Zebra ripd can handle offset-list in. */ + ret = rip_offset_list_apply_in (&p, ifp, &rte->metric); + + /* If offset-list does not modify the metric use interface's + metric. */ + if (! ret) + rte->metric += ifp->metric; + + if (rte->metric > RIP_METRIC_INFINITY) + rte->metric = RIP_METRIC_INFINITY; + + /* Set nexthop pointer. */ + if (rte->nexthop.s_addr == 0) + nexthop = &from->sin_addr; + else + nexthop = &rte->nexthop; + + /* Check nexthop address. */ + if (rip_nexthop_check (nexthop) < 0) + { + if (IS_RIP_DEBUG_PACKET) + zlog_info ("Nexthop address %s is invalid", inet_ntoa (*nexthop)); + return; + } + + /* Get index for the prefix. */ + rp = route_node_get (rip->table, (struct prefix *) &p); + + /* Check to see whether there is already RIP route on the table. */ + rinfo = rp->info; + + if (rinfo) + { + /* Redistributed route check. */ + if (rinfo->type != ZEBRA_ROUTE_RIP + && rinfo->metric != RIP_METRIC_INFINITY) + return; + + /* Local static route. */ + if (rinfo->type == ZEBRA_ROUTE_RIP + && rinfo->sub_type == RIP_ROUTE_STATIC + && rinfo->metric != RIP_METRIC_INFINITY) + return; + } + + if (! rinfo) + { + /* Now, check to see whether there is already an explicit route + for the destination prefix. If there is no such route, add + this route to the routing table, unless the metric is + infinity (there is no point in adding a route which + unusable). */ + if (rte->metric != RIP_METRIC_INFINITY) + { + rinfo = rip_info_new (); + + /* - Setting the destination prefix and length to those in + the RTE. */ + rinfo->rp = rp; + + /* - Setting the metric to the newly calculated metric (as + described above). */ + rinfo->metric = rte->metric; + rinfo->tag = ntohs (rte->tag); + + /* - Set the next hop address to be the address of the router + from which the datagram came or the next hop address + specified by a next hop RTE. */ + IPV4_ADDR_COPY (&rinfo->nexthop, nexthop); + IPV4_ADDR_COPY (&rinfo->from, &from->sin_addr); + rinfo->ifindex = ifp->ifindex; + + /* - Initialize the timeout for the route. If the + garbage-collection timer is running for this route, stop it + (see section 2.3 for a discussion of the timers). */ + rip_timeout_update (rinfo); + + /* - Set the route change flag. */ + rinfo->flags |= RIP_RTF_CHANGED; + + /* - Signal the output process to trigger an update (see section + 2.5). */ + rip_event (RIP_TRIGGERED_UPDATE, 0); + + /* Finally, route goes into the kernel. */ + rinfo->type = ZEBRA_ROUTE_RIP; + rinfo->sub_type = RIP_ROUTE_RTE; + + /* Set distance value. */ + rinfo->distance = rip_distance_apply (rinfo); + + rp->info = rinfo; + rip_zebra_ipv4_add (&p, &rinfo->nexthop, rinfo->metric, + rinfo->distance); + rinfo->flags |= RIP_RTF_FIB; + } + } + else + { + /* Route is there but we are not sure the route is RIP or not. */ + rinfo = rp->info; + + /* If there is an existing route, compare the next hop address + to the address of the router from which the datagram came. + If this datagram is from the same router as the existing + route, reinitialize the timeout. */ + same = IPV4_ADDR_SAME (&rinfo->from, &from->sin_addr); + + if (same) + rip_timeout_update (rinfo); + + /* Next, compare the metrics. If the datagram is from the same + router as the existing route, and the new metric is different + than the old one; or, if the new metric is lower than the old + one; do the following actions: */ + if ((same && rinfo->metric != rte->metric) || + rte->metric < rinfo->metric) + { + /* - Adopt the route from the datagram. That is, put the + new metric in, and adjust the next hop address (if + necessary). */ + oldmetric = rinfo->metric; + rinfo->metric = rte->metric; + rinfo->tag = ntohs (rte->tag); + IPV4_ADDR_COPY (&rinfo->from, &from->sin_addr); + rinfo->ifindex = ifp->ifindex; + rinfo->distance = rip_distance_apply (rinfo); + + /* Should a new route to this network be established + while the garbage-collection timer is running, the + new route will replace the one that is about to be + deleted. In this case the garbage-collection timer + must be cleared. */ + + if (oldmetric == RIP_METRIC_INFINITY && + rinfo->metric < RIP_METRIC_INFINITY) + { + rinfo->type = ZEBRA_ROUTE_RIP; + rinfo->sub_type = RIP_ROUTE_RTE; + + RIP_TIMER_OFF (rinfo->t_garbage_collect); + + if (! IPV4_ADDR_SAME (&rinfo->nexthop, nexthop)) + IPV4_ADDR_COPY (&rinfo->nexthop, nexthop); + + rip_zebra_ipv4_add (&p, nexthop, rinfo->metric, + rinfo->distance); + rinfo->flags |= RIP_RTF_FIB; + } + + /* Update nexthop and/or metric value. */ + if (oldmetric != RIP_METRIC_INFINITY) + { + rip_zebra_ipv4_delete (&p, &rinfo->nexthop, oldmetric); + rip_zebra_ipv4_add (&p, nexthop, rinfo->metric, + rinfo->distance); + rinfo->flags |= RIP_RTF_FIB; + + if (! IPV4_ADDR_SAME (&rinfo->nexthop, nexthop)) + IPV4_ADDR_COPY (&rinfo->nexthop, nexthop); + } + + /* - Set the route change flag and signal the output process + to trigger an update. */ + rinfo->flags |= RIP_RTF_CHANGED; + rip_event (RIP_TRIGGERED_UPDATE, 0); + + /* - If the new metric is infinity, start the deletion + process (described above); */ + if (rinfo->metric == RIP_METRIC_INFINITY) + { + /* If the new metric is infinity, the deletion process + begins for the route, which is no longer used for + routing packets. Note that the deletion process is + started only when the metric is first set to + infinity. If the metric was already infinity, then a + new deletion process is not started. */ + if (oldmetric != RIP_METRIC_INFINITY) + { + /* - The garbage-collection timer is set for 120 seconds. */ + RIP_TIMER_ON (rinfo->t_garbage_collect, + rip_garbage_collect, rip->garbage_time); + RIP_TIMER_OFF (rinfo->t_timeout); + + /* - The metric for the route is set to 16 + (infinity). This causes the route to be removed + from service.*/ + rip_zebra_ipv4_delete (&p, &rinfo->nexthop, oldmetric); + rinfo->flags &= ~RIP_RTF_FIB; + + /* - The route change flag is to indicate that this + entry has been changed. */ + /* - The output process is signalled to trigger a + response. */ + ; /* Above processes are already done previously. */ + } + } + else + { + /* otherwise, re-initialize the timeout. */ + rip_timeout_update (rinfo); + } + } + /* Unlock tempolary lock of the route. */ + route_unlock_node (rp); + } +} + +/* Dump RIP packet */ +void +rip_packet_dump (struct rip_packet *packet, int size, char *sndrcv) +{ + caddr_t lim; + struct rte *rte; + char *command_str; + char pbuf[BUFSIZ], nbuf[BUFSIZ]; + u_char netmask = 0; + u_char *p; + + /* Set command string. */ + if (packet->command > 0 && packet->command < RIP_COMMAND_MAX) + command_str = lookup (rip_msg, packet->command); + else + command_str = "unknown"; + + /* Dump packet header. */ + zlog_info ("%s %s version %d packet size %d", + sndrcv, command_str, packet->version, size); + + /* Dump each routing table entry. */ + rte = packet->rte; + + for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++) + { + if (packet->version == RIPv2) + { + netmask = ip_masklen (rte->mask); + + if (ntohs (rte->family) == 0xffff) + { + if (ntohs (rte->tag) == RIP_AUTH_SIMPLE_PASSWORD) + { + p = (u_char *)&rte->prefix; + + zlog_info (" family 0x%X type %d auth string: %s", + ntohs (rte->family), ntohs (rte->tag), p); + } + else if (ntohs (rte->tag) == RIP_AUTH_MD5) + { + struct rip_md5_info *md5; + + md5 = (struct rip_md5_info *) &packet->rte; + + zlog_info (" family 0x%X type %d (MD5 authentication)", + ntohs (md5->family), ntohs (md5->type)); + zlog_info (" RIP-2 packet len %d Key ID %d" + " Auth Data len %d", ntohs (md5->packet_len), + md5->keyid, md5->auth_len); + zlog_info (" Sequence Number %ld", (u_long)ntohl (md5->sequence)); + } + else if (ntohs (rte->tag) == RIP_AUTH_DATA) + { + p = (u_char *)&rte->prefix; + + zlog_info (" family 0x%X type %d (MD5 data)", + ntohs (rte->family), ntohs (rte->tag)); + zlog_info (" MD5: %02X%02X%02X%02X%02X%02X%02X%02X" + "%02X%02X%02X%02X%02X%02X%02X", + p[0],p[1],p[2],p[3],p[4],p[5],p[6],p[7], + p[9],p[10],p[11],p[12],p[13],p[14],p[15]); + } + else + { + zlog_info (" family 0x%X type %d (Unknown auth type)", + ntohs (rte->family), ntohs (rte->tag)); + } + } + else + zlog_info (" %s/%d -> %s family %d tag %d metric %ld", + inet_ntop (AF_INET, &rte->prefix, pbuf, BUFSIZ),netmask, + inet_ntop (AF_INET, &rte->nexthop, nbuf, BUFSIZ), + ntohs (rte->family), ntohs (rte->tag), + (u_long)ntohl (rte->metric)); + } + else + { + zlog_info (" %s family %d tag %d metric %ld", + inet_ntop (AF_INET, &rte->prefix, pbuf, BUFSIZ), + ntohs (rte->family), ntohs (rte->tag), + (u_long)ntohl (rte->metric)); + } + } +} + +/* Check if the destination address is valid (unicast; not net 0 + or 127) (RFC2453 Section 3.9.2 - Page 26). But we don't + check net 0 because we accept default route. */ +int +rip_destination_check (struct in_addr addr) +{ + u_int32_t destination; + + /* Convert to host byte order. */ + destination = ntohl (addr.s_addr); + + if (IPV4_NET127 (destination)) + return 0; + + /* Net 0 may match to the default route. */ + if (IPV4_NET0 (destination) && destination != 0) + return 0; + + /* Unicast address must belong to class A, B, C. */ + if (IN_CLASSA (destination)) + return 1; + if (IN_CLASSB (destination)) + return 1; + if (IN_CLASSC (destination)) + return 1; + + return 0; +} + +/* RIP version 2 authentication. */ +int +rip_auth_simple_password (struct rte *rte, struct sockaddr_in *from, + struct interface *ifp) +{ + struct rip_interface *ri; + char *auth_str; + + if (IS_RIP_DEBUG_EVENT) + zlog_info ("RIPv2 simple password authentication from %s", + inet_ntoa (from->sin_addr)); + + ri = ifp->info; + + if (ri->auth_type != RIP_AUTH_SIMPLE_PASSWORD + || ntohs (rte->tag) != RIP_AUTH_SIMPLE_PASSWORD) + return 0; + + /* Simple password authentication. */ + if (ri->auth_str) + { + auth_str = (char *) &rte->prefix; + + if (strncmp (auth_str, ri->auth_str, 16) == 0) + return 1; + } + if (ri->key_chain) + { + struct keychain *keychain; + struct key *key; + + keychain = keychain_lookup (ri->key_chain); + if (keychain == NULL) + return 0; + + key = key_match_for_accept (keychain, (char *) &rte->prefix); + if (key) + return 1; + } + return 0; +} + +/* RIP version 2 authentication with MD5. */ +int +rip_auth_md5 (struct rip_packet *packet, struct sockaddr_in *from, + struct interface *ifp) +{ + struct rip_interface *ri; + struct rip_md5_info *md5; + struct rip_md5_data *md5data; + struct keychain *keychain; + struct key *key; + struct md5_ctx ctx; + u_char pdigest[RIP_AUTH_MD5_SIZE]; + u_char digest[RIP_AUTH_MD5_SIZE]; + u_int16_t packet_len; + char *auth_str = NULL; + + if (IS_RIP_DEBUG_EVENT) + zlog_info ("RIPv2 MD5 authentication from %s", inet_ntoa (from->sin_addr)); + + ri = ifp->info; + md5 = (struct rip_md5_info *) &packet->rte; + + /* Check auth type. */ + if (ri->auth_type != RIP_AUTH_MD5 || ntohs (md5->type) != RIP_AUTH_MD5) + return 0; + + if (md5->auth_len != RIP_HEADER_SIZE + RIP_AUTH_MD5_SIZE) + return 0; + + if (ri->key_chain) + { + keychain = keychain_lookup (ri->key_chain); + if (keychain == NULL) + return 0; + + key = key_lookup_for_accept (keychain, md5->keyid); + if (key == NULL) + return 0; + + auth_str = key->string; + } + + if (ri->auth_str) + auth_str = ri->auth_str; + + if (! auth_str) + return 0; + + /* MD5 digest authentication. */ + packet_len = ntohs (md5->packet_len); + md5data = (struct rip_md5_data *)(((u_char *) packet) + packet_len); + + /* Save digest to pdigest. */ + memcpy (pdigest, md5data->digest, RIP_AUTH_MD5_SIZE); + + /* Overwrite digest by my secret. */ + memset (md5data->digest, 0, RIP_AUTH_MD5_SIZE); + strncpy (md5data->digest, auth_str, RIP_AUTH_MD5_SIZE); + + md5_init_ctx (&ctx); + md5_process_bytes (packet, packet_len + md5->auth_len, &ctx); + md5_finish_ctx (&ctx, digest); + + if (memcmp (pdigest, digest, RIP_AUTH_MD5_SIZE) == 0) + return packet_len; + else + return 0; +} + +void +rip_auth_md5_set (struct stream *s, struct interface *ifp) +{ + struct rip_interface *ri; + struct keychain *keychain = NULL; + struct key *key = NULL; + unsigned long len; + struct md5_ctx ctx; + unsigned char secret[RIP_AUTH_MD5_SIZE]; + unsigned char digest[RIP_AUTH_MD5_SIZE]; + char *auth_str = NULL; + + ri = ifp->info; + + /* Make it sure this interface is configured as MD5 + authentication. */ + if (ri->auth_type != RIP_AUTH_MD5) + return; + + /* Lookup key chain. */ + if (ri->key_chain) + { + keychain = keychain_lookup (ri->key_chain); + if (keychain == NULL) + return; + + /* Lookup key. */ + key = key_lookup_for_send (keychain); + if (key == NULL) + return; + + auth_str = key->string; + } + + if (ri->auth_str) + auth_str = ri->auth_str; + + if (! auth_str) + return; + + /* Get packet length. */ + len = s->putp; + + /* Check packet length. */ + if (len < (RIP_HEADER_SIZE + RIP_RTE_SIZE)) + { + zlog_err ("rip_auth_md5_set(): packet length %ld is less than minimum length.", len); + return; + } + + /* Move RTE. */ + memmove (s->data + RIP_HEADER_SIZE + RIP_RTE_SIZE, + s->data + RIP_HEADER_SIZE, + len - RIP_HEADER_SIZE); + + /* Set pointer to authentication header. */ + stream_set_putp (s, RIP_HEADER_SIZE); + len += RIP_RTE_SIZE; + + /* MD5 authentication. */ + stream_putw (s, 0xffff); + stream_putw (s, RIP_AUTH_MD5); + + /* RIP-2 Packet length. Actual value is filled in + rip_auth_md5_set(). */ + stream_putw (s, len); + + /* Key ID. */ + if (key) + stream_putc (s, key->index % 256); + else + stream_putc (s, 1); + + /* Auth Data Len. Set 16 for MD5 authentication + data. */ + stream_putc (s, RIP_AUTH_MD5_SIZE + RIP_HEADER_SIZE); + + /* Sequence Number (non-decreasing). */ + /* RFC2080: The value used in the sequence number is + arbitrary, but two suggestions are the time of the + message's creation or a simple message counter. */ + stream_putl (s, time (NULL)); + + /* Reserved field must be zero. */ + stream_putl (s, 0); + stream_putl (s, 0); + + /* Set pointer to authentication data. */ + stream_set_putp (s, len); + + /* Set authentication data. */ + stream_putw (s, 0xffff); + stream_putw (s, 0x01); + + /* Generate a digest for the RIP packet. */ + memset (secret, 0, RIP_AUTH_MD5_SIZE); + strncpy (secret, auth_str, RIP_AUTH_MD5_SIZE); + md5_init_ctx (&ctx); + md5_process_bytes (s->data, s->endp, &ctx); + md5_process_bytes (secret, RIP_AUTH_MD5_SIZE, &ctx); + md5_finish_ctx (&ctx, digest); + + /* Copy the digest to the packet. */ + stream_write (s, digest, RIP_AUTH_MD5_SIZE); +} + +/* RIP routing information. */ +void +rip_response_process (struct rip_packet *packet, int size, + struct sockaddr_in *from, struct interface *ifp) +{ + caddr_t lim; + struct rte *rte; + + /* The Response must be ignored if it is not from the RIP + port. (RFC2453 - Sec. 3.9.2)*/ + if (ntohs (from->sin_port) != RIP_PORT_DEFAULT) + { + zlog_info ("response doesn't come from RIP port: %d", + from->sin_port); + rip_peer_bad_packet (from); + return; + } + + /* The datagram's IPv4 source address should be checked to see + whether the datagram is from a valid neighbor; the source of the + datagram must be on a directly connected network */ + if (! if_valid_neighbor (from->sin_addr)) + { + zlog_info ("This datagram doesn't came from a valid neighbor: %s", + inet_ntoa (from->sin_addr)); + rip_peer_bad_packet (from); + return; + } + + /* It is also worth checking to see whether the response is from one + of the router's own addresses. */ + + ; /* Alredy done in rip_read () */ + + /* Update RIP peer. */ + rip_peer_update (from, packet->version); + + /* Set RTE pointer. */ + rte = packet->rte; + + for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++) + { + /* RIPv2 authentication check. */ + /* If the Address Family Identifier of the first (and only the + first) entry in the message is 0xFFFF, then the remainder of + the entry contains the authentication. */ + /* If the packet gets here it means authentication enabled */ + /* Check is done in rip_read(). So, just skipping it */ + if (packet->version == RIPv2 && + rte == packet->rte && + rte->family == 0xffff) + continue; + + if (ntohs (rte->family) != AF_INET) + { + /* Address family check. RIP only supports AF_INET. */ + zlog_info ("Unsupported family %d from %s.", + ntohs (rte->family), inet_ntoa (from->sin_addr)); + continue; + } + + /* - is the destination address valid (e.g., unicast; not net 0 + or 127) */ + if (! rip_destination_check (rte->prefix)) + { + zlog_info ("Network is net 0 or net 127 or it is not unicast network"); + rip_peer_bad_route (from); + continue; + } + + /* Convert metric value to host byte order. */ + rte->metric = ntohl (rte->metric); + + /* - is the metric valid (i.e., between 1 and 16, inclusive) */ + if (! (rte->metric >= 1 && rte->metric <= 16)) + { + zlog_info ("Route's metric is not in the 1-16 range."); + rip_peer_bad_route (from); + continue; + } + + /* RIPv1 does not have nexthop value. */ + if (packet->version == RIPv1 && rte->nexthop.s_addr != 0) + { + zlog_info ("RIPv1 packet with nexthop value %s", + inet_ntoa (rte->nexthop)); + rip_peer_bad_route (from); + continue; + } + + /* That is, if the provided information is ignored, a possibly + sub-optimal, but absolutely valid, route may be taken. If + the received Next Hop is not directly reachable, it should be + treated as 0.0.0.0. */ + if (packet->version == RIPv2 && rte->nexthop.s_addr != 0) + { + u_int32_t addrval; + + /* Multicast address check. */ + addrval = ntohl (rte->nexthop.s_addr); + if (IN_CLASSD (addrval)) + { + zlog_info ("Nexthop %s is multicast address, skip this rte", + inet_ntoa (rte->nexthop)); + continue; + } + + if (! if_lookup_address (rte->nexthop)) + { + struct route_node *rn; + struct rip_info *rinfo; + + rn = route_node_match_ipv4 (rip->table, &rte->nexthop); + + if (rn) + { + rinfo = rn->info; + + if (rinfo->type == ZEBRA_ROUTE_RIP + && rinfo->sub_type == RIP_ROUTE_RTE) + { + if (IS_RIP_DEBUG_EVENT) + zlog_info ("Next hop %s is on RIP network. Set nexthop to the packet's originator", inet_ntoa (rte->nexthop)); + rte->nexthop = rinfo->from; + } + else + { + if (IS_RIP_DEBUG_EVENT) + zlog_info ("Next hop %s is not directly reachable. Treat it as 0.0.0.0", inet_ntoa (rte->nexthop)); + rte->nexthop.s_addr = 0; + } + + route_unlock_node (rn); + } + else + { + if (IS_RIP_DEBUG_EVENT) + zlog_info ("Next hop %s is not directly reachable. Treat it as 0.0.0.0", inet_ntoa (rte->nexthop)); + rte->nexthop.s_addr = 0; + } + + } + } + + /* For RIPv1, there won't be a valid netmask. + + This is a best guess at the masks. If everyone was using old + Ciscos before the 'ip subnet zero' option, it would be almost + right too :-) + + Cisco summarize ripv1 advertisments to the classful boundary + (/16 for class B's) except when the RIP packet does to inside + the classful network in question. */ + + if ((packet->version == RIPv1 && rte->prefix.s_addr != 0) + || (packet->version == RIPv2 + && (rte->prefix.s_addr != 0 && rte->mask.s_addr == 0))) + { + u_int32_t destination; + + destination = ntohl (rte->prefix.s_addr); + + if (destination & 0xff) + { + masklen2ip (32, &rte->mask); + } + else if ((destination & 0xff00) || IN_CLASSC (destination)) + { + masklen2ip (24, &rte->mask); + } + else if ((destination & 0xff0000) || IN_CLASSB (destination)) + { + masklen2ip (16, &rte->mask); + } + else + { + masklen2ip (8, &rte->mask); + } + } + + /* In case of RIPv2, if prefix in RTE is not netmask applied one + ignore the entry. */ + if ((packet->version == RIPv2) + && (rte->mask.s_addr != 0) + && ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr)) + { + zlog_warn ("RIPv2 address %s is not mask /%d applied one", + inet_ntoa (rte->prefix), ip_masklen (rte->mask)); + rip_peer_bad_route (from); + continue; + } + + /* Default route's netmask is ignored. */ + if (packet->version == RIPv2 + && (rte->prefix.s_addr == 0) + && (rte->mask.s_addr != 0)) + { + if (IS_RIP_DEBUG_EVENT) + zlog_info ("Default route with non-zero netmask. Set zero to netmask"); + rte->mask.s_addr = 0; + } + + /* Routing table updates. */ + rip_rte_process (rte, from, ifp); + } +} + +/* RIP packet send to destination address. */ +int +rip_send_packet (caddr_t buf, int size, struct sockaddr_in *to, + struct interface *ifp) +{ + int ret; + struct sockaddr_in sin; + int sock; + + /* Make destination address. */ + memset (&sin, 0, sizeof (struct sockaddr_in)); + sin.sin_family = AF_INET; +#ifdef HAVE_SIN_LEN + sin.sin_len = sizeof (struct sockaddr_in); +#endif /* HAVE_SIN_LEN */ + + /* When destination is specified, use it's port and address. */ + if (to) + { + sock = rip->sock; + + sin.sin_port = to->sin_port; + sin.sin_addr = to->sin_addr; + } + else + { + sock = socket (AF_INET, SOCK_DGRAM, 0); + + sockopt_broadcast (sock); + sockopt_reuseaddr (sock); + sockopt_reuseport (sock); + + sin.sin_port = htons (RIP_PORT_DEFAULT); + sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP); + + /* Set multicast interface. */ + rip_interface_multicast_set (sock, ifp); + } + + ret = sendto (sock, buf, size, 0, (struct sockaddr *)&sin, + sizeof (struct sockaddr_in)); + + if (IS_RIP_DEBUG_EVENT) + zlog_info ("SEND to socket %d port %d addr %s", + sock, ntohs (sin.sin_port), inet_ntoa(sin.sin_addr)); + + if (ret < 0) + zlog_warn ("can't send packet : %s", strerror (errno)); + + if (! to) + close (sock); + + return ret; +} + +/* Add redistributed route to RIP table. */ +void +rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p, + unsigned int ifindex, struct in_addr *nexthop) +{ + int ret; + struct route_node *rp; + struct rip_info *rinfo; + + /* Redistribute route */ + ret = rip_destination_check (p->prefix); + if (! ret) + return; + + rp = route_node_get (rip->table, (struct prefix *) p); + + rinfo = rp->info; + + if (rinfo) + { + if (rinfo->type == ZEBRA_ROUTE_CONNECT + && rinfo->sub_type == RIP_ROUTE_INTERFACE + && rinfo->metric != RIP_METRIC_INFINITY) + { + route_unlock_node (rp); + return; + } + + /* Manually configured RIP route check. */ + if (rinfo->type == ZEBRA_ROUTE_RIP + && rinfo->sub_type == RIP_ROUTE_STATIC) + { + if (type != ZEBRA_ROUTE_RIP || sub_type != RIP_ROUTE_STATIC) + { + route_unlock_node (rp); + return; + } + } + + RIP_TIMER_OFF (rinfo->t_timeout); + RIP_TIMER_OFF (rinfo->t_garbage_collect); + + if (rip_route_rte (rinfo)) + rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p, &rinfo->nexthop, + rinfo->metric); + rp->info = NULL; + rip_info_free (rinfo); + + route_unlock_node (rp); + } + + rinfo = rip_info_new (); + + rinfo->type = type; + rinfo->sub_type = sub_type; + rinfo->ifindex = ifindex; + rinfo->metric = 1; + rinfo->rp = rp; + + if (nexthop) + rinfo->nexthop = *nexthop; + + rinfo->flags |= RIP_RTF_FIB; + rp->info = rinfo; + + rinfo->flags |= RIP_RTF_CHANGED; + + rip_event (RIP_TRIGGERED_UPDATE, 0); +} + +/* Delete redistributed route from RIP table. */ +void +rip_redistribute_delete (int type, int sub_type, struct prefix_ipv4 *p, + unsigned int ifindex) +{ + int ret; + struct route_node *rp; + struct rip_info *rinfo; + + ret = rip_destination_check (p->prefix); + if (! ret) + return; + + rp = route_node_lookup (rip->table, (struct prefix *) p); + if (rp) + { + rinfo = rp->info; + + if (rinfo != NULL + && rinfo->type == type + && rinfo->sub_type == sub_type + && rinfo->ifindex == ifindex) + { + /* Perform poisoned reverse. */ + rinfo->metric = RIP_METRIC_INFINITY; + RIP_TIMER_ON (rinfo->t_garbage_collect, + rip_garbage_collect, rip->garbage_time); + RIP_TIMER_OFF (rinfo->t_timeout); + rinfo->flags |= RIP_RTF_CHANGED; + + rip_event (RIP_TRIGGERED_UPDATE, 0); + } + } +} + +/* Response to request called from rip_read ().*/ +void +rip_request_process (struct rip_packet *packet, int size, + struct sockaddr_in *from, struct interface *ifp) +{ + caddr_t lim; + struct rte *rte; + struct prefix_ipv4 p; + struct route_node *rp; + struct rip_info *rinfo; + struct rip_interface *ri; + + ri = ifp->info; + + /* When passive interface is specified, suppress responses */ + if (ri->passive) + return; + + /* RIP peer update. */ + rip_peer_update (from, packet->version); + + lim = ((caddr_t) packet) + size; + rte = packet->rte; + + /* The Request is processed entry by entry. If there are no + entries, no response is given. */ + if (lim == (caddr_t) rte) + return; + + /* There is one special case. If there is exactly one entry in the + request, and it has an address family identifier of zero and a + metric of infinity (i.e., 16), then this is a request to send the + entire routing table. */ + if (lim == ((caddr_t) (rte + 1)) && + ntohs (rte->family) == 0 && + ntohl (rte->metric) == RIP_METRIC_INFINITY) + { + /* All route with split horizon */ + rip_output_process (ifp, from, rip_all_route, packet->version); + } + else + { + /* Examine the list of RTEs in the Request one by one. For each + entry, look up the destination in the router's routing + database and, if there is a route, put that route's metric in + the metric field of the RTE. If there is no explicit route + to the specified destination, put infinity in the metric + field. Once all the entries have been filled in, change the + command from Request to Response and send the datagram back + to the requestor. */ + p.family = AF_INET; + + for (; ((caddr_t) rte) < lim; rte++) + { + p.prefix = rte->prefix; + p.prefixlen = ip_masklen (rte->mask); + apply_mask_ipv4 (&p); + + rp = route_node_lookup (rip->table, (struct prefix *) &p); + if (rp) + { + rinfo = rp->info; + rte->metric = htonl (rinfo->metric); + route_unlock_node (rp); + } + else + rte->metric = htonl (RIP_METRIC_INFINITY); + } + packet->command = RIP_RESPONSE; + + rip_send_packet ((caddr_t) packet, size, from, ifp); + } + rip_global_queries++; +} + +#if RIP_RECVMSG +/* Set IPv6 packet info to the socket. */ +static int +setsockopt_pktinfo (int sock) +{ + int ret; + int val = 1; + + ret = setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &val, sizeof(val)); + if (ret < 0) + zlog_warn ("Can't setsockopt IP_PKTINFO : %s", strerror (errno)); + return ret; +} + +/* Read RIP packet by recvmsg function. */ +int +rip_recvmsg (int sock, u_char *buf, int size, struct sockaddr_in *from, + int *ifindex) +{ + int ret; + struct msghdr msg; + struct iovec iov; + struct cmsghdr *ptr; + char adata[1024]; + + msg.msg_name = (void *) from; + msg.msg_namelen = sizeof (struct sockaddr_in); + 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 = size; + + ret = recvmsg (sock, &msg, 0); + if (ret < 0) + return ret; + + for (ptr = CMSG_FIRSTHDR(&msg); ptr != NULL; ptr = CMSG_NXTHDR(&msg, ptr)) + if (ptr->cmsg_level == IPPROTO_IP && ptr->cmsg_type == IP_PKTINFO) + { + struct in_pktinfo *pktinfo; + int i; + + pktinfo = (struct in_pktinfo *) CMSG_DATA (ptr); + i = pktinfo->ipi_ifindex; + } + return ret; +} + +/* RIP packet read function. */ +int +rip_read_new (struct thread *t) +{ + int ret; + int sock; + char buf[RIP_PACKET_MAXSIZ]; + struct sockaddr_in from; + unsigned int ifindex; + + /* Fetch socket then register myself. */ + sock = THREAD_FD (t); + rip_event (RIP_READ, sock); + + /* Read RIP packet. */ + ret = rip_recvmsg (sock, buf, RIP_PACKET_MAXSIZ, &from, (int *)&ifindex); + if (ret < 0) + { + zlog_warn ("Can't read RIP packet: %s", strerror (errno)); + return ret; + } + + return ret; +} +#endif /* RIP_RECVMSG */ + +/* First entry point of RIP packet. */ +int +rip_read (struct thread *t) +{ + int sock; + int ret; + int rtenum; + union rip_buf rip_buf; + struct rip_packet *packet; + struct sockaddr_in from; + int fromlen, len; + struct interface *ifp; + struct rip_interface *ri; + + /* Fetch socket then register myself. */ + sock = THREAD_FD (t); + rip->t_read = NULL; + + /* Add myself to tne next event */ + rip_event (RIP_READ, sock); + + /* RIPd manages only IPv4. */ + memset (&from, 0, sizeof (struct sockaddr_in)); + fromlen = sizeof (struct sockaddr_in); + + len = recvfrom (sock, (char *)&rip_buf.buf, sizeof (rip_buf.buf), 0, + (struct sockaddr *) &from, &fromlen); + if (len < 0) + { + zlog_info ("recvfrom failed: %s", strerror (errno)); + return len; + } + + /* Check is this packet comming from myself? */ + if (if_check_address (from.sin_addr)) + { + if (IS_RIP_DEBUG_PACKET) + zlog_warn ("ignore packet comes from myself"); + return -1; + } + + /* Which interface is this packet comes from. */ + ifp = if_lookup_address (from.sin_addr); + + /* RIP packet received */ + if (IS_RIP_DEBUG_EVENT) + zlog_info ("RECV packet from %s port %d on %s", + inet_ntoa (from.sin_addr), ntohs (from.sin_port), + ifp ? ifp->name : "unknown"); + + /* If this packet come from unknown interface, ignore it. */ + if (ifp == NULL) + { + zlog_info ("packet comes from unknown interface"); + return -1; + } + + /* Packet length check. */ + if (len < RIP_PACKET_MINSIZ) + { + zlog_warn ("packet size %d is smaller than minimum size %d", + len, RIP_PACKET_MINSIZ); + rip_peer_bad_packet (&from); + return len; + } + if (len > RIP_PACKET_MAXSIZ) + { + zlog_warn ("packet size %d is larger than max size %d", + len, RIP_PACKET_MAXSIZ); + rip_peer_bad_packet (&from); + return len; + } + + /* Packet alignment check. */ + if ((len - RIP_PACKET_MINSIZ) % 20) + { + zlog_warn ("packet size %d is wrong for RIP packet alignment", len); + rip_peer_bad_packet (&from); + return len; + } + + /* Set RTE number. */ + rtenum = ((len - RIP_PACKET_MINSIZ) / 20); + + /* For easy to handle. */ + packet = &rip_buf.rip_packet; + + /* RIP version check. */ + if (packet->version == 0) + { + zlog_info ("version 0 with command %d received.", packet->command); + rip_peer_bad_packet (&from); + return -1; + } + + /* Dump RIP packet. */ + if (IS_RIP_DEBUG_RECV) + rip_packet_dump (packet, len, "RECV"); + + /* RIP version adjust. This code should rethink now. RFC1058 says + that "Version 1 implementations are to ignore this extra data and + process only the fields specified in this document.". So RIPv3 + packet should be treated as RIPv1 ignoring must be zero field. */ + if (packet->version > RIPv2) + packet->version = RIPv2; + + /* Is RIP running or is this RIP neighbor ?*/ + ri = ifp->info; + if (! ri->running && ! rip_neighbor_lookup (&from)) + { + if (IS_RIP_DEBUG_EVENT) + zlog_info ("RIP is not enabled on interface %s.", ifp->name); + rip_peer_bad_packet (&from); + return -1; + } + + /* RIP Version check. */ + if (packet->command == RIP_RESPONSE) + { + if (ri->ri_receive == RI_RIP_UNSPEC) + { + if (packet->version != rip->version) + { + if (IS_RIP_DEBUG_PACKET) + zlog_warn (" packet's v%d doesn't fit to my version %d", + packet->version, rip->version); + rip_peer_bad_packet (&from); + return -1; + } + } + else + { + if (packet->version == RIPv1) + if (! (ri->ri_receive & RIPv1)) + { + if (IS_RIP_DEBUG_PACKET) + zlog_warn (" packet's v%d doesn't fit to if version spec", + packet->version); + rip_peer_bad_packet (&from); + return -1; + } + if (packet->version == RIPv2) + if (! (ri->ri_receive & RIPv2)) + { + if (IS_RIP_DEBUG_PACKET) + zlog_warn (" packet's v%d doesn't fit to if version spec", + packet->version); + rip_peer_bad_packet (&from); + return -1; + } + } + } + + /* RFC2453 5.2 If the router is not configured to authenticate RIP-2 + messages, then RIP-1 and unauthenticated RIP-2 messages will be + accepted; authenticated RIP-2 messages shall be discarded. */ + + if ((ri->auth_type == RIP_NO_AUTH) + && rtenum + && (packet->version == RIPv2) && (packet->rte->family == 0xffff)) + { + if (IS_RIP_DEBUG_EVENT) + zlog_warn ("packet RIPv%d is dropped because authentication disabled", + packet->version); + rip_peer_bad_packet (&from); + return -1; + } + + /* If the router is configured to authenticate RIP-2 messages, then + RIP-1 messages and RIP-2 messages which pass authentication + testing shall be accepted; unauthenticated and failed + authentication RIP-2 messages shall be discarded. For maximum + security, RIP-1 messages should be ignored when authentication is + in use (see section 4.1); otherwise, the routing information from + authenticated messages will be propagated by RIP-1 routers in an + unauthenticated manner. */ + + if ((ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD + || ri->auth_type == RIP_AUTH_MD5) + && rtenum) + { + /* We follow maximum security. */ + if (packet->version == RIPv1 && packet->rte->family == 0xffff) + { + if (IS_RIP_DEBUG_PACKET) + zlog_warn ("packet RIPv%d is dropped because authentication enabled", packet->version); + rip_peer_bad_packet (&from); + return -1; + } + + /* Check RIPv2 authentication. */ + if (packet->version == RIPv2) + { + if (packet->rte->family == 0xffff) + { + if (ntohs (packet->rte->tag) == RIP_AUTH_SIMPLE_PASSWORD) + { + ret = rip_auth_simple_password (packet->rte, &from, ifp); + if (! ret) + { + if (IS_RIP_DEBUG_EVENT) + zlog_warn ("RIPv2 simple password authentication failed"); + rip_peer_bad_packet (&from); + return -1; + } + else + { + if (IS_RIP_DEBUG_EVENT) + zlog_info ("RIPv2 simple password authentication success"); + } + } + else if (ntohs (packet->rte->tag) == RIP_AUTH_MD5) + { + ret = rip_auth_md5 (packet, &from, ifp); + if (! ret) + { + if (IS_RIP_DEBUG_EVENT) + zlog_warn ("RIPv2 MD5 authentication failed"); + rip_peer_bad_packet (&from); + return -1; + } + else + { + if (IS_RIP_DEBUG_EVENT) + zlog_info ("RIPv2 MD5 authentication success"); + } + /* Reset RIP packet length to trim MD5 data. */ + len = ret; + } + else + { + if (IS_RIP_DEBUG_EVENT) + zlog_warn ("Unknown authentication type %d", + ntohs (packet->rte->tag)); + rip_peer_bad_packet (&from); + return -1; + } + } + else + { + /* There is no authentication in the packet. */ + if (ri->auth_str || ri->key_chain) + { + if (IS_RIP_DEBUG_EVENT) + zlog_warn ("RIPv2 authentication failed: no authentication in packet"); + rip_peer_bad_packet (&from); + return -1; + } + } + } + } + + /* Process each command. */ + switch (packet->command) + { + case RIP_RESPONSE: + rip_response_process (packet, len, &from, ifp); + break; + case RIP_REQUEST: + case RIP_POLL: + rip_request_process (packet, len, &from, ifp); + break; + case RIP_TRACEON: + case RIP_TRACEOFF: + zlog_info ("Obsolete command %s received, please sent it to routed", + lookup (rip_msg, packet->command)); + rip_peer_bad_packet (&from); + break; + case RIP_POLL_ENTRY: + zlog_info ("Obsolete command %s received", + lookup (rip_msg, packet->command)); + rip_peer_bad_packet (&from); + break; + default: + zlog_info ("Unknown RIP command %d received", packet->command); + rip_peer_bad_packet (&from); + break; + } + + return len; +} + +/* Make socket for RIP protocol. */ +int +rip_create_socket () +{ + int ret; + int sock; + struct sockaddr_in addr; + struct servent *sp; + + memset (&addr, 0, sizeof (struct sockaddr_in)); + + /* Set RIP port. */ + sp = getservbyname ("router", "udp"); + if (sp) + addr.sin_port = sp->s_port; + else + addr.sin_port = htons (RIP_PORT_DEFAULT); + + /* Address shoud be any address. */ + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + + /* Make datagram socket. */ + sock = socket (AF_INET, SOCK_DGRAM, 0); + if (sock < 0) + { + perror ("socket"); + exit (1); + } + + sockopt_broadcast (sock); + sockopt_reuseaddr (sock); + sockopt_reuseport (sock); +#ifdef RIP_RECVMSG + setsockopt_pktinfo (sock); +#endif /* RIP_RECVMSG */ + + ret = bind (sock, (struct sockaddr *) & addr, sizeof (addr)); + if (ret < 0) + { + perror ("bind"); + return ret; + } + + return sock; +} + +/* Write routing table entry to the stream and return next index of + the routing table entry in the stream. */ +int +rip_write_rte (int num, struct stream *s, struct prefix_ipv4 *p, + u_char version, struct rip_info *rinfo, struct interface *ifp) +{ + struct in_addr mask; + struct rip_interface *ri; + + /* RIP packet header. */ + if (num == 0) + { + stream_putc (s, RIP_RESPONSE); + stream_putc (s, version); + stream_putw (s, 0); + + /* In case of we need RIPv2 authentication. */ + if (version == RIPv2 && ifp) + { + ri = ifp->info; + + if (ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD) + { + if (ri->auth_str) + { + stream_putw (s, 0xffff); + stream_putw (s, RIP_AUTH_SIMPLE_PASSWORD); + + memset ((s->data + s->putp), 0, 16); + strncpy ((s->data + s->putp), ri->auth_str, 16); + stream_set_putp (s, s->putp + 16); + + num++; + } + if (ri->key_chain) + { + struct keychain *keychain; + struct key *key; + + keychain = keychain_lookup (ri->key_chain); + + if (keychain) + { + key = key_lookup_for_send (keychain); + + if (key) + { + stream_putw (s, 0xffff); + stream_putw (s, RIP_AUTH_SIMPLE_PASSWORD); + + memset ((s->data + s->putp), 0, 16); + strncpy ((s->data + s->putp), key->string, 16); + stream_set_putp (s, s->putp + 16); + + num++; + } + } + } + } + } + } + + /* Write routing table entry. */ + if (version == RIPv1) + { + stream_putw (s, AF_INET); + stream_putw (s, 0); + stream_put_ipv4 (s, p->prefix.s_addr); + stream_put_ipv4 (s, 0); + stream_put_ipv4 (s, 0); + stream_putl (s, rinfo->metric_out); + } + else + { + masklen2ip (p->prefixlen, &mask); + + stream_putw (s, AF_INET); + stream_putw (s, rinfo->tag); + stream_put_ipv4 (s, p->prefix.s_addr); + stream_put_ipv4 (s, mask.s_addr); + stream_put_ipv4 (s, rinfo->nexthop_out.s_addr); + stream_putl (s, rinfo->metric_out); + } + + return ++num; +} + +/* Send update to the ifp or spcified neighbor. */ +void +rip_output_process (struct interface *ifp, struct sockaddr_in *to, + int route_type, u_char version) +{ + int ret; + struct stream *s; + struct route_node *rp; + struct rip_info *rinfo; + struct rip_interface *ri; + struct prefix_ipv4 *p; + struct prefix_ipv4 classfull; + int num; + int rtemax; + + /* Logging output event. */ + if (IS_RIP_DEBUG_EVENT) + { + if (to) + zlog_info ("update routes to neighbor %s", inet_ntoa (to->sin_addr)); + else + zlog_info ("update routes on interface %s ifindex %d", + ifp->name, ifp->ifindex); + } + + /* Set output stream. */ + s = rip->obuf; + + /* Reset stream and RTE counter. */ + stream_reset (s); + num = 0; + rtemax = (RIP_PACKET_MAXSIZ - 4) / 20; + + /* Get RIP interface. */ + ri = ifp->info; + + /* If output interface is in simple password authentication mode, we + need space for authentication data. */ + if (ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD) + rtemax -= 1; + + /* If output interface is in MD5 authentication mode, we need space + for authentication header and data. */ + if (ri->auth_type == RIP_AUTH_MD5) + rtemax -= 2; + + /* If output interface is in simple password authentication mode + and string or keychain is specified we need space for auth. data */ + if (ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD) + { + if (ri->key_chain) + { + struct keychain *keychain; + + keychain = keychain_lookup (ri->key_chain); + if (keychain) + if (key_lookup_for_send (keychain)) + rtemax -=1; + } + else + if (ri->auth_str) + rtemax -=1; + } + + for (rp = route_top (rip->table); rp; rp = route_next (rp)) + if ((rinfo = rp->info) != NULL) + { + /* Some inheritance stuff: */ + /* Before we process with ipv4 prefix we should mask it */ + /* with Classful mask if we send RIPv1 packet.That's because */ + /* user could set non-classful mask or we could get it by RIPv2 */ + /* or other protocol. checked with Cisco's way of life :) */ + + if (version == RIPv1) + { + memcpy (&classfull, &rp->p, sizeof (struct prefix_ipv4)); + + if (IS_RIP_DEBUG_PACKET) + zlog_info("%s/%d before RIPv1 mask check ", + inet_ntoa (classfull.prefix), classfull.prefixlen); + + apply_classful_mask_ipv4 (&classfull); + p = &classfull; + + if (IS_RIP_DEBUG_PACKET) + zlog_info("%s/%d after RIPv1 mask check", + inet_ntoa (p->prefix), p->prefixlen); + } + else + p = (struct prefix_ipv4 *) &rp->p; + + /* Apply output filters. */ + ret = rip_outgoing_filter (p, ri); + if (ret < 0) + continue; + + /* Changed route only output. */ + if (route_type == rip_changed_route && + (! (rinfo->flags & RIP_RTF_CHANGED))) + continue; + + /* Split horizon. */ + /* if (split_horizon == rip_split_horizon) */ + if (ri->split_horizon) + { + /* We perform split horizon for RIP and connected route. */ + if ((rinfo->type == ZEBRA_ROUTE_RIP || + rinfo->type == ZEBRA_ROUTE_CONNECT) && + rinfo->ifindex == ifp->ifindex) + continue; + } + + /* Preparation for route-map. */ + rinfo->metric_set = 0; + rinfo->nexthop_out.s_addr = 0; + rinfo->metric_out = rinfo->metric; + rinfo->ifindex_out = ifp->ifindex; + + /* In order to avoid some local loops, if the RIP route has a + nexthop via this interface, keep the nexthop, otherwise set + it to 0. The nexthop should not be propagated beyond the + local broadcast/multicast area in order to avoid an IGP + multi-level recursive look-up. For RIP and connected + route, we don't set next hop value automatically. For + settting next hop to those routes, please use + route-map. */ + + if (rinfo->type != ZEBRA_ROUTE_RIP + && rinfo->type != ZEBRA_ROUTE_CONNECT + && rinfo->ifindex == ifp->ifindex) + rinfo->nexthop_out = rinfo->nexthop; + + /* Apply route map - continue, if deny */ + if (rip->route_map[rinfo->type].name + && rinfo->sub_type != RIP_ROUTE_INTERFACE) + { + ret = route_map_apply (rip->route_map[rinfo->type].map, + (struct prefix *)p, RMAP_RIP, rinfo); + + if (ret == RMAP_DENYMATCH) + { + if (IS_RIP_DEBUG_PACKET) + zlog_info ("%s/%d is filtered by route-map", + inet_ntoa (p->prefix), p->prefixlen); + continue; + } + } + + /* When route-map does not set metric. */ + if (! rinfo->metric_set) + { + /* If redistribute metric is set. */ + if (rip->route_map[rinfo->type].metric_config + && rinfo->metric != RIP_METRIC_INFINITY) + { + rinfo->metric_out = rip->route_map[rinfo->type].metric; + } + else + { + /* If the route is not connected or localy generated + one, use default-metric value*/ + if (rinfo->type != ZEBRA_ROUTE_RIP + && rinfo->type != ZEBRA_ROUTE_CONNECT + && rinfo->metric != RIP_METRIC_INFINITY) + rinfo->metric_out = rip->default_metric; + } + } + + /* Apply offset-list */ + if (rinfo->metric != RIP_METRIC_INFINITY) + rip_offset_list_apply_out (p, ifp, &rinfo->metric_out); + + if (rinfo->metric_out > RIP_METRIC_INFINITY) + rinfo->metric_out = RIP_METRIC_INFINITY; + + /* Write RTE to the stream. */ + num = rip_write_rte (num, s, p, version, rinfo, to ? NULL : ifp); + if (num == rtemax) + { + if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5) + rip_auth_md5_set (s, ifp); + + ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s), + to, ifp); + + if (ret >= 0 && IS_RIP_DEBUG_SEND) + rip_packet_dump ((struct rip_packet *)STREAM_DATA (s), + stream_get_endp(s), "SEND"); + num = 0; + stream_reset (s); + } + } + + /* Flush unwritten RTE. */ + if (num != 0) + { + if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5) + rip_auth_md5_set (s, ifp); + + ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s), to, ifp); + + if (ret >= 0 && IS_RIP_DEBUG_SEND) + rip_packet_dump ((struct rip_packet *)STREAM_DATA (s), + stream_get_endp (s), "SEND"); + num = 0; + stream_reset (s); + } + + /* Statistics updates. */ + ri->sent_updates++; +} + +/* Send RIP packet to the interface. */ +void +rip_update_interface (struct interface *ifp, u_char version, int route_type) +{ + struct prefix_ipv4 *p; + struct connected *connected; + listnode node; + struct sockaddr_in to; + + /* When RIP version is 2 and multicast enable interface. */ + if (version == RIPv2 && if_is_multicast (ifp)) + { + if (IS_RIP_DEBUG_EVENT) + zlog_info ("multicast announce on %s ", ifp->name); + + rip_output_process (ifp, NULL, route_type, version); + return; + } + + /* If we can't send multicast packet, send it with unicast. */ + if (if_is_broadcast (ifp) || if_is_pointopoint (ifp)) + { + for (node = listhead (ifp->connected); node; nextnode (node)) + { + connected = getdata (node); + + /* Fetch broadcast address or poin-to-point destination + address . */ + p = (struct prefix_ipv4 *) connected->destination; + + if (p->family == AF_INET) + { + /* Destination address and port setting. */ + memset (&to, 0, sizeof (struct sockaddr_in)); + to.sin_addr = p->prefix; + to.sin_port = htons (RIP_PORT_DEFAULT); + + if (IS_RIP_DEBUG_EVENT) + zlog_info ("%s announce to %s on %s", + if_is_pointopoint (ifp) ? "unicast" : "broadcast", + inet_ntoa (to.sin_addr), ifp->name); + + rip_output_process (ifp, &to, route_type, version); + } + } + } +} + +/* Update send to all interface and neighbor. */ +void +rip_update_process (int route_type) +{ + listnode node; + struct interface *ifp; + struct rip_interface *ri; + struct route_node *rp; + struct sockaddr_in to; + struct prefix_ipv4 *p; + + /* Send RIP update to each interface. */ + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + + if (if_is_loopback (ifp)) + continue; + + if (! if_is_up (ifp)) + continue; + + /* Fetch RIP interface information. */ + ri = ifp->info; + + /* When passive interface is specified, suppress announce to the + interface. */ + if (ri->passive) + continue; + + if (ri->running) + { + if (IS_RIP_DEBUG_EVENT) + { + if (ifp->name) + zlog_info ("SEND UPDATE to %s ifindex %d", + ifp->name, ifp->ifindex); + else + zlog_info ("SEND UPDATE to _unknown_ ifindex %d", + ifp->ifindex); + } + + /* If there is no version configuration in the interface, + use rip's version setting. */ + if (ri->ri_send == RI_RIP_UNSPEC) + { + if (rip->version == RIPv1) + rip_update_interface (ifp, RIPv1, route_type); + else + rip_update_interface (ifp, RIPv2, route_type); + } + /* If interface has RIP version configuration use it. */ + else + { + if (ri->ri_send & RIPv1) + rip_update_interface (ifp, RIPv1, route_type); + if (ri->ri_send & RIPv2) + rip_update_interface (ifp, RIPv2, route_type); + } + } + } + + /* RIP send updates to each neighbor. */ + for (rp = route_top (rip->neighbor); rp; rp = route_next (rp)) + if (rp->info != NULL) + { + p = (struct prefix_ipv4 *) &rp->p; + + ifp = if_lookup_address (p->prefix); + if (! ifp) + { + zlog_warn ("Neighbor %s doesn't exist direct connected network", + inet_ntoa (p->prefix)); + continue; + } + + /* Set destination address and port */ + memset (&to, 0, sizeof (struct sockaddr_in)); + to.sin_addr = p->prefix; + to.sin_port = htons (RIP_PORT_DEFAULT); + + /* RIP version is rip's configuration. */ + rip_output_process (ifp, &to, route_type, rip->version); + } +} + +/* RIP's periodical timer. */ +int +rip_update (struct thread *t) +{ + /* Clear timer pointer. */ + rip->t_update = NULL; + + if (IS_RIP_DEBUG_EVENT) + zlog_info ("update timer fire!"); + + /* Process update output. */ + rip_update_process (rip_all_route); + + /* Triggered updates may be suppressed if a regular update is due by + the time the triggered update would be sent. */ + if (rip->t_triggered_interval) + { + thread_cancel (rip->t_triggered_interval); + rip->t_triggered_interval = NULL; + } + rip->trigger = 0; + + /* Register myself. */ + rip_event (RIP_UPDATE_EVENT, 0); + + return 0; +} + +/* Walk down the RIP routing table then clear changed flag. */ +void +rip_clear_changed_flag () +{ + struct route_node *rp; + struct rip_info *rinfo; + + for (rp = route_top (rip->table); rp; rp = route_next (rp)) + if ((rinfo = rp->info) != NULL) + if (rinfo->flags & RIP_RTF_CHANGED) + rinfo->flags &= ~RIP_RTF_CHANGED; +} + +/* Triggered update interval timer. */ +int +rip_triggered_interval (struct thread *t) +{ + int rip_triggered_update (struct thread *); + + rip->t_triggered_interval = NULL; + + if (rip->trigger) + { + rip->trigger = 0; + rip_triggered_update (t); + } + return 0; +} + +/* Execute triggered update. */ +int +rip_triggered_update (struct thread *t) +{ + int interval; + + /* Clear thred pointer. */ + rip->t_triggered_update = NULL; + + /* Cancel interval timer. */ + if (rip->t_triggered_interval) + { + thread_cancel (rip->t_triggered_interval); + rip->t_triggered_interval = NULL; + } + rip->trigger = 0; + + /* Logging triggered update. */ + if (IS_RIP_DEBUG_EVENT) + zlog_info ("triggered update!"); + + /* Split Horizon processing is done when generating triggered + updates as well as normal updates (see section 2.6). */ + rip_update_process (rip_changed_route); + + /* Once all of the triggered updates have been generated, the route + change flags should be cleared. */ + rip_clear_changed_flag (); + + /* After a triggered update is sent, a timer should be set for a + random interval between 1 and 5 seconds. If other changes that + would trigger updates occur before the timer expires, a single + update is triggered when the timer expires. */ + interval = (random () % 5) + 1; + + rip->t_triggered_interval = + thread_add_timer (master, rip_triggered_interval, NULL, interval); + + return 0; +} + +/* Withdraw redistributed route. */ +void +rip_redistribute_withdraw (int type) +{ + struct route_node *rp; + struct rip_info *rinfo; + + if (!rip) + return; + + for (rp = route_top (rip->table); rp; rp = route_next (rp)) + if ((rinfo = rp->info) != NULL) + { + if (rinfo->type == type + && rinfo->sub_type != RIP_ROUTE_INTERFACE) + { + /* Perform poisoned reverse. */ + rinfo->metric = RIP_METRIC_INFINITY; + RIP_TIMER_ON (rinfo->t_garbage_collect, + rip_garbage_collect, rip->garbage_time); + RIP_TIMER_OFF (rinfo->t_timeout); + rinfo->flags |= RIP_RTF_CHANGED; + + rip_event (RIP_TRIGGERED_UPDATE, 0); + } + } +} + +/* Create new RIP instance and set it to global variable. */ +int +rip_create () +{ + rip = XMALLOC (MTYPE_RIP, sizeof (struct rip)); + memset (rip, 0, sizeof (struct rip)); + + /* Set initial value. */ + rip->version = RIPv2; + rip->update_time = RIP_UPDATE_TIMER_DEFAULT; + rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT; + rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT; + rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT; + + /* Initialize RIP routig table. */ + rip->table = route_table_init (); + rip->route = route_table_init (); + rip->neighbor = route_table_init (); + + /* Make output stream. */ + rip->obuf = stream_new (1500); + + /* Make socket. */ + rip->sock = rip_create_socket (); + if (rip->sock < 0) + return rip->sock; + + /* Create read and timer thread. */ + rip_event (RIP_READ, rip->sock); + rip_event (RIP_UPDATE_EVENT, 1); + + return 0; +} + +/* Sned RIP request to the destination. */ +int +rip_request_send (struct sockaddr_in *to, struct interface *ifp, + u_char version) +{ + struct rte *rte; + struct rip_packet rip_packet; + + memset (&rip_packet, 0, sizeof (rip_packet)); + + rip_packet.command = RIP_REQUEST; + rip_packet.version = version; + rte = rip_packet.rte; + rte->metric = htonl (RIP_METRIC_INFINITY); + + return rip_send_packet ((caddr_t) &rip_packet, sizeof (rip_packet), to, ifp); +} + +int +rip_update_jitter (unsigned long time) +{ + return ((rand () % (time + 1)) - (time / 2)); +} + +void +rip_event (enum rip_event event, int sock) +{ + int jitter = 0; + + switch (event) + { + case RIP_READ: + rip->t_read = thread_add_read (master, rip_read, NULL, sock); + break; + case RIP_UPDATE_EVENT: + if (rip->t_update) + { + thread_cancel (rip->t_update); + rip->t_update = NULL; + } + jitter = rip_update_jitter (rip->update_time); + rip->t_update = + thread_add_timer (master, rip_update, NULL, + sock ? 2 : rip->update_time + jitter); + break; + case RIP_TRIGGERED_UPDATE: + if (rip->t_triggered_interval) + rip->trigger = 1; + else if (! rip->t_triggered_update) + rip->t_triggered_update = + thread_add_event (master, rip_triggered_update, NULL, 0); + break; + default: + break; + } +} + +DEFUN (router_rip, + router_rip_cmd, + "router rip", + "Enable a routing process\n" + "Routing Information Protocol (RIP)\n") +{ + int ret; + + /* If rip is not enabled before. */ + if (! rip) + { + ret = rip_create (); + if (ret < 0) + { + zlog_info ("Can't create RIP"); + return CMD_WARNING; + } + } + vty->node = RIP_NODE; + vty->index = rip; + + return CMD_SUCCESS; +} + +DEFUN (no_router_rip, + no_router_rip_cmd, + "no router rip", + NO_STR + "Enable a routing process\n" + "Routing Information Protocol (RIP)\n") +{ + if (rip) + rip_clean (); + return CMD_SUCCESS; +} + +DEFUN (rip_version, + rip_version_cmd, + "version <1-2>", + "Set routing protocol version\n" + "version\n") +{ + int version; + + version = atoi (argv[0]); + if (version != RIPv1 && version != RIPv2) + { + vty_out (vty, "invalid rip version %d%s", version, + VTY_NEWLINE); + return CMD_WARNING; + } + rip->version = version; + + return CMD_SUCCESS; +} + +DEFUN (no_rip_version, + no_rip_version_cmd, + "no version", + NO_STR + "Set routing protocol version\n") +{ + /* Set RIP version to the default. */ + rip->version = RIPv2; + + return CMD_SUCCESS; +} + +ALIAS (no_rip_version, + no_rip_version_val_cmd, + "no version <1-2>", + NO_STR + "Set routing protocol version\n" + "version\n") + +DEFUN (rip_route, + rip_route_cmd, + "route A.B.C.D/M", + "RIP static route configuration\n" + "IP prefix <network>/<length>\n") +{ + int ret; + struct prefix_ipv4 p; + struct route_node *node; + + ret = str2prefix_ipv4 (argv[0], &p); + if (ret < 0) + { + vty_out (vty, "Malformed address%s", VTY_NEWLINE); + return CMD_WARNING; + } + apply_mask_ipv4 (&p); + + /* For router rip configuration. */ + node = route_node_get (rip->route, (struct prefix *) &p); + + if (node->info) + { + vty_out (vty, "There is already same static route.%s", VTY_NEWLINE); + route_unlock_node (node); + return CMD_WARNING; + } + + node->info = "static"; + + rip_redistribute_add (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0, NULL); + + return CMD_SUCCESS; +} + +DEFUN (no_rip_route, + no_rip_route_cmd, + "no route A.B.C.D/M", + NO_STR + "RIP static route configuration\n" + "IP prefix <network>/<length>\n") +{ + int ret; + struct prefix_ipv4 p; + struct route_node *node; + + ret = str2prefix_ipv4 (argv[0], &p); + if (ret < 0) + { + vty_out (vty, "Malformed address%s", VTY_NEWLINE); + return CMD_WARNING; + } + apply_mask_ipv4 (&p); + + /* For router rip configuration. */ + node = route_node_lookup (rip->route, (struct prefix *) &p); + if (! node) + { + vty_out (vty, "Can't find route %s.%s", argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + + rip_redistribute_delete (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0); + route_unlock_node (node); + + node->info = NULL; + route_unlock_node (node); + + return CMD_SUCCESS; +} + +void +rip_update_default_metric () +{ + struct route_node *np; + struct rip_info *rinfo; + + for (np = route_top (rip->table); np; np = route_next (np)) + if ((rinfo = np->info) != NULL) + if (rinfo->type != ZEBRA_ROUTE_RIP && rinfo->type != ZEBRA_ROUTE_CONNECT) + rinfo->metric = rip->default_metric; +} + +DEFUN (rip_default_metric, + rip_default_metric_cmd, + "default-metric <1-16>", + "Set a metric of redistribute routes\n" + "Default metric\n") +{ + if (rip) + { + rip->default_metric = atoi (argv[0]); + /* rip_update_default_metric (); */ + } + return CMD_SUCCESS; +} + +DEFUN (no_rip_default_metric, + no_rip_default_metric_cmd, + "no default-metric", + NO_STR + "Set a metric of redistribute routes\n" + "Default metric\n") +{ + if (rip) + { + rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT; + /* rip_update_default_metric (); */ + } + return CMD_SUCCESS; +} + +ALIAS (no_rip_default_metric, + no_rip_default_metric_val_cmd, + "no default-metric <1-16>", + NO_STR + "Set a metric of redistribute routes\n" + "Default metric\n") + +DEFUN (rip_timers, + rip_timers_cmd, + "timers basic <5-2147483647> <5-2147483647> <5-2147483647>", + "Adjust routing timers\n" + "Basic routing protocol update timers\n" + "Routing table update timer value in second. Default is 30.\n" + "Routing information timeout timer. Default is 180.\n" + "Garbage collection timer. Default is 120.\n") +{ + unsigned long update; + unsigned long timeout; + unsigned long garbage; + char *endptr = NULL; + unsigned long RIP_TIMER_MAX = 2147483647; + unsigned long RIP_TIMER_MIN = 5; + + update = strtoul (argv[0], &endptr, 10); + if (update > RIP_TIMER_MAX || update < RIP_TIMER_MIN || *endptr != '\0') + { + vty_out (vty, "update timer value error%s", VTY_NEWLINE); + return CMD_WARNING; + } + + timeout = strtoul (argv[1], &endptr, 10); + if (timeout > RIP_TIMER_MAX || timeout < RIP_TIMER_MIN || *endptr != '\0') + { + vty_out (vty, "timeout timer value error%s", VTY_NEWLINE); + return CMD_WARNING; + } + + garbage = strtoul (argv[2], &endptr, 10); + if (garbage > RIP_TIMER_MAX || garbage < RIP_TIMER_MIN || *endptr != '\0') + { + vty_out (vty, "garbage timer value error%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Set each timer value. */ + rip->update_time = update; + rip->timeout_time = timeout; + rip->garbage_time = garbage; + + /* Reset update timer thread. */ + rip_event (RIP_UPDATE_EVENT, 0); + + return CMD_SUCCESS; +} + +DEFUN (no_rip_timers, + no_rip_timers_cmd, + "no timers basic", + NO_STR + "Adjust routing timers\n" + "Basic routing protocol update timers\n") +{ + /* Set each timer value to the default. */ + rip->update_time = RIP_UPDATE_TIMER_DEFAULT; + rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT; + rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT; + + /* Reset update timer thread. */ + rip_event (RIP_UPDATE_EVENT, 0); + + return CMD_SUCCESS; +} + +struct route_table *rip_distance_table; + +struct rip_distance +{ + /* Distance value for the IP source prefix. */ + u_char distance; + + /* Name of the access-list to be matched. */ + char *access_list; +}; + +struct rip_distance * +rip_distance_new () +{ + struct rip_distance *new; + new = XMALLOC (MTYPE_RIP_DISTANCE, sizeof (struct rip_distance)); + memset (new, 0, sizeof (struct rip_distance)); + return new; +} + +void +rip_distance_free (struct rip_distance *rdistance) +{ + XFREE (MTYPE_RIP_DISTANCE, rdistance); +} + +int +rip_distance_set (struct vty *vty, char *distance_str, char *ip_str, + char *access_list_str) +{ + int ret; + struct prefix_ipv4 p; + u_char distance; + struct route_node *rn; + struct rip_distance *rdistance; + + ret = str2prefix_ipv4 (ip_str, &p); + if (ret == 0) + { + vty_out (vty, "Malformed prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + distance = atoi (distance_str); + + /* Get RIP distance node. */ + rn = route_node_get (rip_distance_table, (struct prefix *) &p); + if (rn->info) + { + rdistance = rn->info; + route_unlock_node (rn); + } + else + { + rdistance = rip_distance_new (); + rn->info = rdistance; + } + + /* Set distance value. */ + rdistance->distance = distance; + + /* Reset access-list configuration. */ + if (rdistance->access_list) + { + free (rdistance->access_list); + rdistance->access_list = NULL; + } + if (access_list_str) + rdistance->access_list = strdup (access_list_str); + + return CMD_SUCCESS; +} + +int +rip_distance_unset (struct vty *vty, char *distance_str, char *ip_str, + char *access_list_str) +{ + int ret; + struct prefix_ipv4 p; + u_char distance; + struct route_node *rn; + struct rip_distance *rdistance; + + ret = str2prefix_ipv4 (ip_str, &p); + if (ret == 0) + { + vty_out (vty, "Malformed prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + distance = atoi (distance_str); + + rn = route_node_lookup (rip_distance_table, (struct prefix *)&p); + if (! rn) + { + vty_out (vty, "Can't find specified prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + rdistance = rn->info; + + if (rdistance->access_list) + free (rdistance->access_list); + rip_distance_free (rdistance); + + rn->info = NULL; + route_unlock_node (rn); + route_unlock_node (rn); + + return CMD_SUCCESS; +} + +void +rip_distance_reset () +{ + struct route_node *rn; + struct rip_distance *rdistance; + + for (rn = route_top (rip_distance_table); rn; rn = route_next (rn)) + if ((rdistance = rn->info) != NULL) + { + if (rdistance->access_list) + free (rdistance->access_list); + rip_distance_free (rdistance); + rn->info = NULL; + route_unlock_node (rn); + } +} + +/* Apply RIP information to distance method. */ +u_char +rip_distance_apply (struct rip_info *rinfo) +{ + struct route_node *rn; + struct prefix_ipv4 p; + struct rip_distance *rdistance; + struct access_list *alist; + + if (! rip) + return 0; + + memset (&p, 0, sizeof (struct prefix_ipv4)); + p.family = AF_INET; + p.prefix = rinfo->from; + p.prefixlen = IPV4_MAX_BITLEN; + + /* Check source address. */ + rn = route_node_match (rip_distance_table, (struct prefix *) &p); + if (rn) + { + rdistance = rn->info; + route_unlock_node (rn); + + if (rdistance->access_list) + { + alist = access_list_lookup (AFI_IP, rdistance->access_list); + if (alist == NULL) + return 0; + if (access_list_apply (alist, &rinfo->rp->p) == FILTER_DENY) + return 0; + + return rdistance->distance; + } + else + return rdistance->distance; + } + + if (rip->distance) + return rip->distance; + + return 0; +} + +void +rip_distance_show (struct vty *vty) +{ + struct route_node *rn; + struct rip_distance *rdistance; + int header = 1; + char buf[BUFSIZ]; + + vty_out (vty, " Distance: (default is %d)%s", + rip->distance ? rip->distance :ZEBRA_RIP_DISTANCE_DEFAULT, + VTY_NEWLINE); + + for (rn = route_top (rip_distance_table); rn; rn = route_next (rn)) + if ((rdistance = rn->info) != NULL) + { + if (header) + { + vty_out (vty, " Address Distance List%s", + VTY_NEWLINE); + header = 0; + } + sprintf (buf, "%s/%d", inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen); + vty_out (vty, " %-20s %4d %s%s", + buf, rdistance->distance, + rdistance->access_list ? rdistance->access_list : "", + VTY_NEWLINE); + } +} + +DEFUN (rip_distance, + rip_distance_cmd, + "distance <1-255>", + "Administrative distance\n" + "Distance value\n") +{ + rip->distance = atoi (argv[0]); + return CMD_SUCCESS; +} + +DEFUN (no_rip_distance, + no_rip_distance_cmd, + "no distance <1-255>", + NO_STR + "Administrative distance\n" + "Distance value\n") +{ + rip->distance = 0; + return CMD_SUCCESS; +} + +DEFUN (rip_distance_source, + rip_distance_source_cmd, + "distance <1-255> A.B.C.D/M", + "Administrative distance\n" + "Distance value\n" + "IP source prefix\n") +{ + rip_distance_set (vty, argv[0], argv[1], NULL); + return CMD_SUCCESS; +} + +DEFUN (no_rip_distance_source, + no_rip_distance_source_cmd, + "no distance <1-255> A.B.C.D/M", + NO_STR + "Administrative distance\n" + "Distance value\n" + "IP source prefix\n") +{ + rip_distance_unset (vty, argv[0], argv[1], NULL); + return CMD_SUCCESS; +} + +DEFUN (rip_distance_source_access_list, + rip_distance_source_access_list_cmd, + "distance <1-255> A.B.C.D/M WORD", + "Administrative distance\n" + "Distance value\n" + "IP source prefix\n" + "Access list name\n") +{ + rip_distance_set (vty, argv[0], argv[1], argv[2]); + return CMD_SUCCESS; +} + +DEFUN (no_rip_distance_source_access_list, + no_rip_distance_source_access_list_cmd, + "no distance <1-255> A.B.C.D/M WORD", + NO_STR + "Administrative distance\n" + "Distance value\n" + "IP source prefix\n" + "Access list name\n") +{ + rip_distance_unset (vty, argv[0], argv[1], argv[2]); + return CMD_SUCCESS; +} + +/* Print out routes update time. */ +void +rip_vty_out_uptime (struct vty *vty, struct rip_info *rinfo) +{ + struct timeval timer_now; + time_t clock; + struct tm *tm; +#define TIME_BUF 25 + char timebuf [TIME_BUF]; + struct thread *thread; + + gettimeofday (&timer_now, NULL); + + if ((thread = rinfo->t_timeout) != NULL) + { + clock = thread->u.sands.tv_sec - timer_now.tv_sec; + tm = gmtime (&clock); + strftime (timebuf, TIME_BUF, "%M:%S", tm); + vty_out (vty, "%5s", timebuf); + } + else if ((thread = rinfo->t_garbage_collect) != NULL) + { + clock = thread->u.sands.tv_sec - timer_now.tv_sec; + tm = gmtime (&clock); + strftime (timebuf, TIME_BUF, "%M:%S", tm); + vty_out (vty, "%5s", timebuf); + } +} + +char * +rip_route_type_print (int sub_type) +{ + switch (sub_type) + { + case RIP_ROUTE_RTE: + return "n"; + case RIP_ROUTE_STATIC: + return "s"; + case RIP_ROUTE_DEFAULT: + return "d"; + case RIP_ROUTE_REDISTRIBUTE: + return "r"; + case RIP_ROUTE_INTERFACE: + return "i"; + default: + return "?"; + } +} + +DEFUN (show_ip_rip, + show_ip_rip_cmd, + "show ip rip", + SHOW_STR + IP_STR + "Show RIP routes\n") +{ + struct route_node *np; + struct rip_info *rinfo; + + if (! rip) + return CMD_SUCCESS; + + vty_out (vty, "Codes: R - RIP, C - connected, O - OSPF, B - BGP%s" + " (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s" + " (i) - interface%s%s" + " Network Next Hop Metric From Time%s", + VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + + for (np = route_top (rip->table); np; np = route_next (np)) + if ((rinfo = np->info) != NULL) + { + int len; + + len = vty_out (vty, "%s(%s) %s/%d", + /* np->lock, For debugging. */ + route_info[rinfo->type].str, + rip_route_type_print (rinfo->sub_type), + inet_ntoa (np->p.u.prefix4), np->p.prefixlen); + + len = 24 - len; + + if (len > 0) + vty_out (vty, "%*s", len, " "); + + if (rinfo->nexthop.s_addr) + vty_out (vty, "%-20s %2d ", inet_ntoa (rinfo->nexthop), + rinfo->metric); + else + vty_out (vty, "0.0.0.0 %2d ", rinfo->metric); + + /* Route which exist in kernel routing table. */ + if ((rinfo->type == ZEBRA_ROUTE_RIP) && + (rinfo->sub_type == RIP_ROUTE_RTE)) + { + vty_out (vty, "%-15s ", inet_ntoa (rinfo->from)); + rip_vty_out_uptime (vty, rinfo); + } + else if (rinfo->metric == RIP_METRIC_INFINITY) + { + vty_out (vty, "self "); + rip_vty_out_uptime (vty, rinfo); + } + else + vty_out (vty, "self"); + + vty_out (vty, "%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +/* Return next event time. */ +int +rip_next_thread_timer (struct thread *thread) +{ + struct timeval timer_now; + + gettimeofday (&timer_now, NULL); + + return thread->u.sands.tv_sec - timer_now.tv_sec; +} + +DEFUN (show_ip_protocols_rip, + show_ip_protocols_rip_cmd, + "show ip protocols", + SHOW_STR + IP_STR + "IP routing protocol process parameters and statistics\n") +{ + listnode node; + struct interface *ifp; + struct rip_interface *ri; + extern struct message ri_version_msg[]; + char *send_version; + char *receive_version; + + if (! rip) + return CMD_SUCCESS; + + vty_out (vty, "Routing Protocol is \"rip\"%s", VTY_NEWLINE); + vty_out (vty, " Sending updates every %ld seconds with +/-50%%,", + rip->update_time); + vty_out (vty, " next due in %d seconds%s", + rip_next_thread_timer (rip->t_update), + VTY_NEWLINE); + vty_out (vty, " Timeout after %ld seconds,", rip->timeout_time); + vty_out (vty, " garbage collect after %ld seconds%s", rip->garbage_time, + VTY_NEWLINE); + + /* Filtering status show. */ + config_show_distribute (vty); + + /* Default metric information. */ + vty_out (vty, " Default redistribution metric is %d%s", + rip->default_metric, VTY_NEWLINE); + + /* Redistribute information. */ + vty_out (vty, " Redistributing:"); + config_write_rip_redistribute (vty, 0); + vty_out (vty, "%s", VTY_NEWLINE); + + vty_out (vty, " Default version control: send version %d,", rip->version); + vty_out (vty, " receive version %d %s", rip->version, + VTY_NEWLINE); + + vty_out (vty, " Interface Send Recv Key-chain%s", VTY_NEWLINE); + + for (node = listhead (iflist); node; node = nextnode (node)) + { + ifp = getdata (node); + ri = ifp->info; + + if (ri->enable_network || ri->enable_interface) + { + if (ri->ri_send == RI_RIP_UNSPEC) + send_version = lookup (ri_version_msg, rip->version); + else + send_version = lookup (ri_version_msg, ri->ri_send); + + if (ri->ri_receive == RI_RIP_UNSPEC) + receive_version = lookup (ri_version_msg, rip->version); + else + receive_version = lookup (ri_version_msg, ri->ri_receive); + + vty_out (vty, " %-17s%-3s %-3s %s%s", ifp->name, + send_version, + receive_version, + ri->key_chain ? ri->key_chain : "", + VTY_NEWLINE); + } + } + + vty_out (vty, " Routing for Networks:%s", VTY_NEWLINE); + config_write_rip_network (vty, 0); + + vty_out (vty, " Routing Information Sources:%s", VTY_NEWLINE); + vty_out (vty, " Gateway BadPackets BadRoutes Distance Last Update%s", VTY_NEWLINE); + rip_peer_display (vty); + + rip_distance_show (vty); + + return CMD_SUCCESS; +} + +/* RIP configuration write function. */ +int +config_write_rip (struct vty *vty) +{ + int write = 0; + struct route_node *rn; + struct rip_distance *rdistance; + + if (rip) + { + /* Router RIP statement. */ + vty_out (vty, "router rip%s", VTY_NEWLINE); + write++; + + /* RIP version statement. Default is RIP version 2. */ + if (rip->version != RIPv2) + vty_out (vty, " version %d%s", rip->version, + VTY_NEWLINE); + + /* RIP timer configuration. */ + if (rip->update_time != RIP_UPDATE_TIMER_DEFAULT + || rip->timeout_time != RIP_TIMEOUT_TIMER_DEFAULT + || rip->garbage_time != RIP_GARBAGE_TIMER_DEFAULT) + vty_out (vty, " timers basic %lu %lu %lu%s", + rip->update_time, + rip->timeout_time, + rip->garbage_time, + VTY_NEWLINE); + + /* Default information configuration. */ + if (rip->default_information) + { + if (rip->default_information_route_map) + vty_out (vty, " default-information originate route-map %s%s", + rip->default_information_route_map, VTY_NEWLINE); + else + vty_out (vty, " default-information originate%s", + VTY_NEWLINE); + } + + /* Redistribute configuration. */ + config_write_rip_redistribute (vty, 1); + + /* RIP offset-list configuration. */ + config_write_rip_offset_list (vty); + + /* RIP enabled network and interface configuration. */ + config_write_rip_network (vty, 1); + + /* RIP default metric configuration */ + if (rip->default_metric != RIP_DEFAULT_METRIC_DEFAULT) + vty_out (vty, " default-metric %d%s", + rip->default_metric, VTY_NEWLINE); + + /* Distribute configuration. */ + write += config_write_distribute (vty); + + /* Distance configuration. */ + if (rip->distance) + vty_out (vty, " distance %d%s", rip->distance, VTY_NEWLINE); + + /* RIP source IP prefix distance configuration. */ + for (rn = route_top (rip_distance_table); rn; rn = route_next (rn)) + if ((rdistance = rn->info) != NULL) + vty_out (vty, " distance %d %s/%d %s%s", rdistance->distance, + inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, + rdistance->access_list ? rdistance->access_list : "", + VTY_NEWLINE); + + /* RIP static route configuration. */ + for (rn = route_top (rip->route); rn; rn = route_next (rn)) + if (rn->info) + vty_out (vty, " route %s/%d%s", + inet_ntoa (rn->p.u.prefix4), + rn->p.prefixlen, + VTY_NEWLINE); + + } + return write; +} + +/* RIP node structure. */ +struct cmd_node rip_node = +{ + RIP_NODE, + "%s(config-router)# ", + 1 +}; + +/* Distribute-list update functions. */ +void +rip_distribute_update (struct distribute *dist) +{ + struct interface *ifp; + struct rip_interface *ri; + struct access_list *alist; + struct prefix_list *plist; + + if (! dist->ifname) + return; + + ifp = if_lookup_by_name (dist->ifname); + if (ifp == NULL) + return; + + ri = ifp->info; + + if (dist->list[DISTRIBUTE_IN]) + { + alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_IN]); + if (alist) + ri->list[RIP_FILTER_IN] = alist; + else + ri->list[RIP_FILTER_IN] = NULL; + } + else + ri->list[RIP_FILTER_IN] = NULL; + + if (dist->list[DISTRIBUTE_OUT]) + { + alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_OUT]); + if (alist) + ri->list[RIP_FILTER_OUT] = alist; + else + ri->list[RIP_FILTER_OUT] = NULL; + } + else + ri->list[RIP_FILTER_OUT] = NULL; + + if (dist->prefix[DISTRIBUTE_IN]) + { + plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_IN]); + if (plist) + ri->prefix[RIP_FILTER_IN] = plist; + else + ri->prefix[RIP_FILTER_IN] = NULL; + } + else + ri->prefix[RIP_FILTER_IN] = NULL; + + if (dist->prefix[DISTRIBUTE_OUT]) + { + plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_OUT]); + if (plist) + ri->prefix[RIP_FILTER_OUT] = plist; + else + ri->prefix[RIP_FILTER_OUT] = NULL; + } + else + ri->prefix[RIP_FILTER_OUT] = NULL; +} + +void +rip_distribute_update_interface (struct interface *ifp) +{ + struct distribute *dist; + + dist = distribute_lookup (ifp->name); + if (dist) + rip_distribute_update (dist); +} + +/* Update all interface's distribute list. */ +void +rip_distribute_update_all () +{ + struct interface *ifp; + listnode node; + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + rip_distribute_update_interface (ifp); + } +} + +/* Delete all added rip route. */ +void +rip_clean () +{ + int i; + struct route_node *rp; + struct rip_info *rinfo; + + if (rip) + { + /* Clear RIP routes */ + for (rp = route_top (rip->table); rp; rp = route_next (rp)) + if ((rinfo = rp->info) != NULL) + { + if (rinfo->type == ZEBRA_ROUTE_RIP && + rinfo->sub_type == RIP_ROUTE_RTE) + rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p, + &rinfo->nexthop, rinfo->metric); + + RIP_TIMER_OFF (rinfo->t_timeout); + RIP_TIMER_OFF (rinfo->t_garbage_collect); + + rp->info = NULL; + route_unlock_node (rp); + + rip_info_free (rinfo); + } + + /* Cancel RIP related timers. */ + RIP_TIMER_OFF (rip->t_update); + RIP_TIMER_OFF (rip->t_triggered_update); + RIP_TIMER_OFF (rip->t_triggered_interval); + + /* Cancel read thread. */ + if (rip->t_read) + { + thread_cancel (rip->t_read); + rip->t_read = NULL; + } + + /* Close RIP socket. */ + if (rip->sock >= 0) + { + close (rip->sock); + rip->sock = -1; + } + + /* Static RIP route configuration. */ + for (rp = route_top (rip->route); rp; rp = route_next (rp)) + if (rp->info) + { + rp->info = NULL; + route_unlock_node (rp); + } + + /* RIP neighbor configuration. */ + for (rp = route_top (rip->neighbor); rp; rp = route_next (rp)) + if (rp->info) + { + rp->info = NULL; + route_unlock_node (rp); + } + + /* Redistribute related clear. */ + if (rip->default_information_route_map) + free (rip->default_information_route_map); + + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + if (rip->route_map[i].name) + free (rip->route_map[i].name); + + XFREE (MTYPE_ROUTE_TABLE, rip->table); + XFREE (MTYPE_ROUTE_TABLE, rip->route); + XFREE (MTYPE_ROUTE_TABLE, rip->neighbor); + + XFREE (MTYPE_RIP, rip); + rip = NULL; + } + + rip_clean_network (); + rip_passive_interface_clean (); + rip_offset_clean (); + rip_interface_clean (); + rip_distance_reset (); + rip_redistribute_clean (); +} + +/* Reset all values to the default settings. */ +void +rip_reset () +{ + /* Reset global counters. */ + rip_global_route_changes = 0; + rip_global_queries = 0; + + /* Call ripd related reset functions. */ + rip_debug_reset (); + rip_route_map_reset (); + + /* Call library reset functions. */ + vty_reset (); + access_list_reset (); + prefix_list_reset (); + + distribute_list_reset (); + + rip_interface_reset (); + rip_distance_reset (); + + rip_zclient_reset (); +} + +/* Allocate new rip structure and set default value. */ +void +rip_init () +{ + /* Randomize for triggered update random(). */ + srand (time (NULL)); + + /* Install top nodes. */ + install_node (&rip_node, config_write_rip); + + /* Install rip commands. */ + install_element (VIEW_NODE, &show_ip_rip_cmd); + install_element (VIEW_NODE, &show_ip_protocols_rip_cmd); + install_element (ENABLE_NODE, &show_ip_rip_cmd); + install_element (ENABLE_NODE, &show_ip_protocols_rip_cmd); + install_element (CONFIG_NODE, &router_rip_cmd); + install_element (CONFIG_NODE, &no_router_rip_cmd); + + install_default (RIP_NODE); + install_element (RIP_NODE, &rip_version_cmd); + install_element (RIP_NODE, &no_rip_version_cmd); + install_element (RIP_NODE, &no_rip_version_val_cmd); + install_element (RIP_NODE, &rip_default_metric_cmd); + install_element (RIP_NODE, &no_rip_default_metric_cmd); + install_element (RIP_NODE, &no_rip_default_metric_val_cmd); + install_element (RIP_NODE, &rip_timers_cmd); + install_element (RIP_NODE, &no_rip_timers_cmd); + install_element (RIP_NODE, &rip_route_cmd); + install_element (RIP_NODE, &no_rip_route_cmd); + install_element (RIP_NODE, &rip_distance_cmd); + install_element (RIP_NODE, &no_rip_distance_cmd); + install_element (RIP_NODE, &rip_distance_source_cmd); + install_element (RIP_NODE, &no_rip_distance_source_cmd); + install_element (RIP_NODE, &rip_distance_source_access_list_cmd); + install_element (RIP_NODE, &no_rip_distance_source_access_list_cmd); + + /* Debug related init. */ + rip_debug_init (); + + /* Filter related init. */ + rip_route_map_init (); + rip_offset_init (); + + /* SNMP init. */ +#ifdef HAVE_SNMP + rip_snmp_init (); +#endif /* HAVE_SNMP */ + + /* Access list install. */ + access_list_init (); + access_list_add_hook (rip_distribute_update_all); + access_list_delete_hook (rip_distribute_update_all); + + /* Prefix list initialize.*/ + prefix_list_init (); + prefix_list_add_hook (rip_distribute_update_all); + prefix_list_delete_hook (rip_distribute_update_all); + + /* Distribute list install. */ + distribute_list_init (RIP_NODE); + distribute_list_add_hook (rip_distribute_update); + distribute_list_delete_hook (rip_distribute_update); + + /* Distance control. */ + rip_distance_table = route_table_init (); +} diff --git a/ripd/ripd.conf.sample b/ripd/ripd.conf.sample new file mode 100644 index 00000000..2902ff9c --- /dev/null +++ b/ripd/ripd.conf.sample @@ -0,0 +1,24 @@ +! -*- rip -*- +! +! RIPd sample configuration file +! +! $Id: ripd.conf.sample,v 1.1 2002/12/13 20:15:30 paul Exp $ +! +hostname ripd +password zebra +! +! debug rip events +! debug rip packet +! +router rip +! network 11.0.0.0/8 +! network eth0 +! route 10.0.0.0/8 +! distribute-list private-only in eth0 +! +!access-list private-only permit 10.0.0.0/8 +!access-list private-only deny any +! +!log file ripd.log +! +log stdout diff --git a/ripd/ripd.h b/ripd/ripd.h new file mode 100644 index 00000000..2545db04 --- /dev/null +++ b/ripd/ripd.h @@ -0,0 +1,408 @@ +/* RIP related values and structures. + * Copyright (C) 1997, 1998, 1999 Kunihiro Ishiguro <kunihiro@zebra.org> + * + * 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_RIP_H +#define _ZEBRA_RIP_H + +/* RIP version number. */ +#define RIPv1 1 +#define RIPv2 2 + +/* RIP command list. */ +#define RIP_REQUEST 1 +#define RIP_RESPONSE 2 +#define RIP_TRACEON 3 /* Obsolete */ +#define RIP_TRACEOFF 4 /* Obsolete */ +#define RIP_POLL 5 +#define RIP_POLL_ENTRY 6 +#define RIP_COMMAND_MAX 7 + +/* RIP metric infinity value.*/ +#define RIP_METRIC_INFINITY 16 + +/* Normal RIP packet min and max size. */ +#define RIP_PACKET_MINSIZ 4 +#define RIP_PACKET_MAXSIZ 512 + +#define RIP_HEADER_SIZE 4 +#define RIP_RTE_SIZE 20 + +/* Max count of routing table entry in one rip packet. */ +#define RIP_MAX_RTE 25 + +/* RIP version 2 multicast address. */ +#ifndef INADDR_RIP_GROUP +#define INADDR_RIP_GROUP 0xe0000009 /* 224.0.0.9 */ +#endif + +/* RIP timers */ +#define RIP_UPDATE_TIMER_DEFAULT 30 +#define RIP_TIMEOUT_TIMER_DEFAULT 180 +#define RIP_GARBAGE_TIMER_DEFAULT 120 + +/* RIP peer timeout value. */ +#define RIP_PEER_TIMER_DEFAULT 180 + +/* RIP port number. */ +#define RIP_PORT_DEFAULT 520 +#define RIP_VTY_PORT 2602 +#define RIP_VTYSH_PATH "/tmp/.ripd" + +/* Default configuration file name. */ +#define RIPD_DEFAULT_CONFIG "ripd.conf" + +/* RIP route types. */ +#define RIP_ROUTE_RTE 0 +#define RIP_ROUTE_STATIC 1 +#define RIP_ROUTE_DEFAULT 2 +#define RIP_ROUTE_REDISTRIBUTE 3 +#define RIP_ROUTE_INTERFACE 4 + +/* RIP MD5 authentication. */ +#define RIP_AUTH_MD5_SIZE 16 + +/* RIP structure. */ +struct rip +{ + /* RIP socket. */ + int sock; + + /* Default version of rip instance. */ + u_char version; + + /* Output buffer of RIP. */ + struct stream *obuf; + + /* RIP routing information base. */ + struct route_table *table; + + /* RIP only static routing information. */ + struct route_table *route; + + /* RIP neighbor. */ + struct route_table *neighbor; + + /* RIP threads. */ + struct thread *t_read; + + /* Update and garbage timer. */ + struct thread *t_update; + + /* Triggered update hack. */ + int trigger; + struct thread *t_triggered_update; + struct thread *t_triggered_interval; + + /* RIP timer values. */ + unsigned long update_time; + unsigned long timeout_time; + unsigned long garbage_time; + + /* RIP default metric. */ + int default_metric; + + /* RIP default-information originate. */ + u_char default_information; + char *default_information_route_map; + + /* RIP default distance. */ + u_char distance; + struct route_table *distance_table; + + /* For redistribute route map. */ + struct + { + char *name; + struct route_map *map; + int metric_config; + u_int32_t metric; + } route_map[ZEBRA_ROUTE_MAX]; +}; + +/* RIP routing table entry which belong to rip_packet. */ +struct rte +{ + u_int16_t family; /* Address family of this route. */ + u_int16_t tag; /* Route Tag which included in RIP2 packet. */ + struct in_addr prefix; /* Prefix of rip route. */ + struct in_addr mask; /* Netmask of rip route. */ + struct in_addr nexthop; /* Next hop of rip route. */ + u_int32_t metric; /* Metric value of rip route. */ +}; + +/* RIP packet structure. */ +struct rip_packet +{ + unsigned char command; /* Command type of RIP packet. */ + unsigned char version; /* RIP version which coming from peer. */ + unsigned char pad1; /* Padding of RIP packet header. */ + unsigned char pad2; /* Same as above. */ + struct rte rte[1]; /* Address structure. */ +}; + +/* Buffer to read RIP packet. */ +union rip_buf +{ + struct rip_packet rip_packet; + char buf[RIP_PACKET_MAXSIZ]; +}; + +/* RIP route information. */ +struct rip_info +{ + /* This route's type. */ + int type; + + /* Sub type. */ + int sub_type; + + /* RIP nexthop. */ + struct in_addr nexthop; + struct in_addr from; + + /* Which interface does this route come from. */ + unsigned int ifindex; + + /* Metric of this route. */ + u_int32_t metric; + + /* Tag information of this route. */ + u_int16_t tag; + + /* Flags of RIP route. */ +#define RIP_RTF_FIB 1 +#define RIP_RTF_CHANGED 2 + u_char flags; + + /* Garbage collect timer. */ + struct thread *t_timeout; + struct thread *t_garbage_collect; + + /* Route-map futures - this variables can be changed. */ + struct in_addr nexthop_out; + u_char metric_set; + u_int32_t metric_out; + unsigned int ifindex_out; + + struct route_node *rp; + + u_char distance; + +#ifdef NEW_RIP_TABLE + struct rip_info *next; + struct rip_info *prev; +#endif /* NEW_RIP_TABLE */ +}; + +/* RIP specific interface configuration. */ +struct rip_interface +{ + /* RIP is enabled on this interface. */ + int enable_network; + int enable_interface; + + /* RIP is running on this interface. */ + int running; + + /* RIP version control. */ + int ri_send; + int ri_receive; + + /* RIPv2 authentication type. */ +#define RIP_NO_AUTH 0 +#define RIP_AUTH_DATA 1 +#define RIP_AUTH_SIMPLE_PASSWORD 2 +#define RIP_AUTH_MD5 3 + int auth_type; + + /* RIPv2 authentication string. */ + char *auth_str; + + /* RIPv2 authentication key chain. */ + char *key_chain; + + /* Split horizon flag. */ + int split_horizon; + int split_horizon_default; + + /* For filter type slot. */ +#define RIP_FILTER_IN 0 +#define RIP_FILTER_OUT 1 +#define RIP_FILTER_MAX 2 + + /* Access-list. */ + struct access_list *list[RIP_FILTER_MAX]; + + /* Prefix-list. */ + struct prefix_list *prefix[RIP_FILTER_MAX]; + + /* Wake up thread. */ + struct thread *t_wakeup; + + /* Interface statistics. */ + int recv_badpackets; + int recv_badroutes; + int sent_updates; + + /* Passive interface. */ + int passive; +}; + +/* RIP peer information. */ +struct rip_peer +{ + /* Peer address. */ + struct in_addr addr; + + /* Peer RIP tag value. */ + int domain; + + /* Last update time. */ + time_t uptime; + + /* Peer RIP version. */ + u_char version; + + /* Statistics. */ + int recv_badpackets; + int recv_badroutes; + + /* Timeout thread. */ + struct thread *t_timeout; +}; + +struct rip_md5_info +{ + u_int16_t family; + u_int16_t type; + u_int16_t packet_len; + u_char keyid; + u_char auth_len; + u_int32_t sequence; + u_int32_t reserv1; + u_int32_t reserv2; +}; + +struct rip_md5_data +{ + u_int16_t family; + u_int16_t type; + u_char digest[16]; +}; + +/* RIP accepet/announce methods. */ +#define RI_RIP_UNSPEC 0 +#define RI_RIP_VERSION_1 1 +#define RI_RIP_VERSION_2 2 +#define RI_RIP_VERSION_1_AND_2 3 + +/* Default value for "default-metric" command. */ +#define RIP_DEFAULT_METRIC_DEFAULT 1 + +/* RIP event. */ +enum rip_event +{ + RIP_READ, + RIP_UPDATE_EVENT, + RIP_TRIGGERED_UPDATE, +}; + +/* Macro for timer turn on. */ +#define RIP_TIMER_ON(T,F,V) \ + do { \ + if (!(T)) \ + (T) = thread_add_timer (master, (F), rinfo, (V)); \ + } while (0) + +/* Macro for timer turn off. */ +#define RIP_TIMER_OFF(X) \ + do { \ + if (X) \ + { \ + thread_cancel (X); \ + (X) = NULL; \ + } \ + } while (0) + +/* Prototypes. */ +void rip_init (); +void rip_reset (); +void rip_clean (); +void rip_clean_network (); +void rip_interface_clean (); +void rip_interface_reset (); +void rip_passive_interface_clean (); +void rip_if_init (); +void rip_if_down_all (); +void rip_route_map_init (); +void rip_route_map_reset (); +void rip_snmp_init (); +void rip_zclient_init (); +void rip_zclient_start (); +void rip_zclient_reset (); +void rip_offset_init (); +int if_check_address (struct in_addr addr); +int if_valid_neighbor (struct in_addr addr); + +int rip_request_send (struct sockaddr_in *, struct interface *, u_char); +int rip_neighbor_lookup (struct sockaddr_in *); +void rip_redistribute_add (int, int, struct prefix_ipv4 *, unsigned int, + struct in_addr *); +void rip_redistribute_delete (int, int, struct prefix_ipv4 *, unsigned int); +void rip_redistribute_withdraw (int); +void rip_zebra_ipv4_add (struct prefix_ipv4 *, struct in_addr *, u_int32_t, u_char); +void rip_zebra_ipv4_delete (struct prefix_ipv4 *, struct in_addr *, u_int32_t); +void rip_interface_multicast_set (int, struct interface *); +void rip_distribute_update_interface (struct interface *); + +int config_write_rip_network (struct vty *, int); +int config_write_rip_offset_list (struct vty *); +int config_write_rip_redistribute (struct vty *, int); + +void rip_peer_init (); +void rip_peer_update (struct sockaddr_in *, u_char); +void rip_peer_bad_route (struct sockaddr_in *); +void rip_peer_bad_packet (struct sockaddr_in *); +void rip_peer_display (struct vty *); +struct rip_peer *rip_peer_lookup (struct in_addr *); +struct rip_peer *rip_peer_lookup_next (struct in_addr *); + +int rip_offset_list_apply_in (struct prefix_ipv4 *, struct interface *, u_int32_t *); +int rip_offset_list_apply_out (struct prefix_ipv4 *, struct interface *, u_int32_t *); +void rip_offset_clean (); + +void rip_info_free (struct rip_info *); +u_char rip_distance_apply (struct rip_info *); +void rip_redistribute_clean (); +void rip_ifaddr_add (struct interface *, struct connected *); +void rip_ifaddr_delete (struct interface *, struct connected *); + +/* There is only one rip strucutre. */ +extern struct rip *rip; + +/* Master thread strucutre. */ +extern struct thread_master *master; + +/* RIP statistics for SNMP. */ +extern long rip_global_route_changes; +extern long rip_global_queries; + +#endif /* _ZEBRA_RIP_H */ |