diff options
Diffstat (limited to 'ripd/ripd.c')
| -rw-r--r-- | ripd/ripd.c | 6791 |
1 files changed, 3366 insertions, 3425 deletions
diff --git a/ripd/ripd.c b/ripd/ripd.c index 6919e7bf95..89d67aaf2a 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -17,7 +17,7 @@ * 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. + * 02111-1307, USA. */ #include <zebra.h> @@ -66,187 +66,171 @@ long rip_global_route_changes = 0; long rip_global_queries = 0; /* Prototypes. */ -static void rip_event (enum rip_event, int); -static void rip_output_process (struct connected *, struct sockaddr_in *, int, u_char); -static int rip_triggered_update (struct thread *); -static int rip_update_jitter (unsigned long); +static void rip_event(enum rip_event, int); +static void rip_output_process(struct connected *, struct sockaddr_in *, int, + u_char); +static int rip_triggered_update(struct thread *); +static int rip_update_jitter(unsigned long); /* RIP output routes type. */ -enum -{ - rip_all_route, - rip_changed_route -}; +enum { rip_all_route, rip_changed_route }; /* RIP command strings. */ -static const 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 } -}; +static const 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}}; /* Utility function to set boradcast option to the socket. */ -static int -sockopt_broadcast (int sock) +static int sockopt_broadcast(int sock) { - int ret; - int on = 1; + 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; + 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; } -static int -rip_route_rte (struct rip_info *rinfo) +static int rip_route_rte(struct rip_info *rinfo) { - return (rinfo->type == ZEBRA_ROUTE_RIP && rinfo->sub_type == RIP_ROUTE_RTE); + return (rinfo->type == ZEBRA_ROUTE_RIP + && rinfo->sub_type == RIP_ROUTE_RTE); } -static struct rip_info * -rip_info_new (void) +static struct rip_info *rip_info_new(void) { - return XCALLOC (MTYPE_RIP_INFO, sizeof (struct rip_info)); + return XCALLOC(MTYPE_RIP_INFO, sizeof(struct rip_info)); } -void -rip_info_free (struct rip_info *rinfo) +void rip_info_free(struct rip_info *rinfo) { - XFREE (MTYPE_RIP_INFO, rinfo); + XFREE(MTYPE_RIP_INFO, rinfo); } /* RIP route garbage collect timer. */ -static int -rip_garbage_collect (struct thread *t) +static int rip_garbage_collect(struct thread *t) { - struct rip_info *rinfo; - struct route_node *rp; + struct rip_info *rinfo; + struct route_node *rp; + + rinfo = THREAD_ARG(t); + rinfo->t_garbage_collect = NULL; - rinfo = THREAD_ARG (t); - rinfo->t_garbage_collect = NULL; + /* Off timeout timer. */ + RIP_TIMER_OFF(rinfo->t_timeout); - /* Off timeout timer. */ - RIP_TIMER_OFF (rinfo->t_timeout); - - /* Get route_node pointer. */ - rp = rinfo->rp; + /* Get route_node pointer. */ + rp = rinfo->rp; - /* Unlock route_node. */ - listnode_delete (rp->info, rinfo); - if (list_isempty ((struct list *)rp->info)) - { - list_free (rp->info); - rp->info = NULL; - route_unlock_node (rp); - } + /* Unlock route_node. */ + listnode_delete(rp->info, rinfo); + if (list_isempty((struct list *)rp->info)) { + list_free(rp->info); + rp->info = NULL; + route_unlock_node(rp); + } - /* Free RIP routing information. */ - rip_info_free (rinfo); + /* Free RIP routing information. */ + rip_info_free(rinfo); - return 0; + return 0; } -static void rip_timeout_update (struct rip_info *rinfo); +static void rip_timeout_update(struct rip_info *rinfo); /* Add new route to the ECMP list. * RETURN: the new entry added in the list, or NULL if it is not the first * entry and ECMP is not allowed. */ -struct rip_info * -rip_ecmp_add (struct rip_info *rinfo_new) +struct rip_info *rip_ecmp_add(struct rip_info *rinfo_new) { - struct route_node *rp = rinfo_new->rp; - struct rip_info *rinfo = NULL; - struct list *list = NULL; + struct route_node *rp = rinfo_new->rp; + struct rip_info *rinfo = NULL; + struct list *list = NULL; - if (rp->info == NULL) - rp->info = list_new (); - list = (struct list *)rp->info; + if (rp->info == NULL) + rp->info = list_new(); + list = (struct list *)rp->info; - /* If ECMP is not allowed and some entry already exists in the list, - * do nothing. */ - if (listcount (list) && !rip->ecmp) - return NULL; + /* If ECMP is not allowed and some entry already exists in the list, + * do nothing. */ + if (listcount(list) && !rip->ecmp) + return NULL; - rinfo = rip_info_new (); - memcpy (rinfo, rinfo_new, sizeof (struct rip_info)); - listnode_add (list, rinfo); + rinfo = rip_info_new(); + memcpy(rinfo, rinfo_new, sizeof(struct rip_info)); + listnode_add(list, rinfo); - if (rip_route_rte (rinfo)) - { - rip_timeout_update (rinfo); - rip_zebra_ipv4_add (rp); - } + if (rip_route_rte(rinfo)) { + rip_timeout_update(rinfo); + rip_zebra_ipv4_add(rp); + } - /* Set the route change flag on the first entry. */ - rinfo = listgetdata (listhead (list)); - SET_FLAG (rinfo->flags, RIP_RTF_CHANGED); + /* Set the route change flag on the first entry. */ + rinfo = listgetdata(listhead(list)); + SET_FLAG(rinfo->flags, RIP_RTF_CHANGED); - /* Signal the output process to trigger an update (see section 2.5). */ - rip_event (RIP_TRIGGERED_UPDATE, 0); + /* Signal the output process to trigger an update (see section 2.5). */ + rip_event(RIP_TRIGGERED_UPDATE, 0); - return rinfo; + return rinfo; } /* Replace the ECMP list with the new route. * RETURN: the new entry added in the list */ -struct rip_info * -rip_ecmp_replace (struct rip_info *rinfo_new) -{ - struct route_node *rp = rinfo_new->rp; - struct list *list = (struct list *)rp->info; - struct rip_info *rinfo = NULL, *tmp_rinfo = NULL; - struct listnode *node = NULL, *nextnode = NULL; - - if (list == NULL || listcount (list) == 0) - return rip_ecmp_add (rinfo_new); - - /* Get the first entry */ - rinfo = listgetdata (listhead (list)); - - /* Learnt route replaced by a local one. Delete it from zebra. */ - if (rip_route_rte (rinfo) && !rip_route_rte (rinfo_new)) - if (CHECK_FLAG (rinfo->flags, RIP_RTF_FIB)) - rip_zebra_ipv4_delete (rp); - - /* Re-use the first entry, and delete the others. */ - for (ALL_LIST_ELEMENTS (list, node, nextnode, tmp_rinfo)) - if (tmp_rinfo != rinfo) - { - RIP_TIMER_OFF (tmp_rinfo->t_timeout); - RIP_TIMER_OFF (tmp_rinfo->t_garbage_collect); - list_delete_node (list, node); - rip_info_free (tmp_rinfo); - } +struct rip_info *rip_ecmp_replace(struct rip_info *rinfo_new) +{ + struct route_node *rp = rinfo_new->rp; + struct list *list = (struct list *)rp->info; + struct rip_info *rinfo = NULL, *tmp_rinfo = NULL; + struct listnode *node = NULL, *nextnode = NULL; + + if (list == NULL || listcount(list) == 0) + return rip_ecmp_add(rinfo_new); + + /* Get the first entry */ + rinfo = listgetdata(listhead(list)); + + /* Learnt route replaced by a local one. Delete it from zebra. */ + if (rip_route_rte(rinfo) && !rip_route_rte(rinfo_new)) + if (CHECK_FLAG(rinfo->flags, RIP_RTF_FIB)) + rip_zebra_ipv4_delete(rp); + + /* Re-use the first entry, and delete the others. */ + for (ALL_LIST_ELEMENTS(list, node, nextnode, tmp_rinfo)) + if (tmp_rinfo != rinfo) { + RIP_TIMER_OFF(tmp_rinfo->t_timeout); + RIP_TIMER_OFF(tmp_rinfo->t_garbage_collect); + list_delete_node(list, node); + rip_info_free(tmp_rinfo); + } - RIP_TIMER_OFF (rinfo->t_timeout); - RIP_TIMER_OFF (rinfo->t_garbage_collect); - memcpy (rinfo, rinfo_new, sizeof (struct rip_info)); + RIP_TIMER_OFF(rinfo->t_timeout); + RIP_TIMER_OFF(rinfo->t_garbage_collect); + memcpy(rinfo, rinfo_new, sizeof(struct rip_info)); - if (rip_route_rte (rinfo)) - { - rip_timeout_update (rinfo); - /* The ADD message implies an update. */ - rip_zebra_ipv4_add (rp); - } + if (rip_route_rte(rinfo)) { + rip_timeout_update(rinfo); + /* The ADD message implies an update. */ + rip_zebra_ipv4_add(rp); + } - /* Set the route change flag. */ - SET_FLAG (rinfo->flags, RIP_RTF_CHANGED); + /* Set the route change flag. */ + SET_FLAG(rinfo->flags, RIP_RTF_CHANGED); - /* Signal the output process to trigger an update (see section 2.5). */ - rip_event (RIP_TRIGGERED_UPDATE, 0); + /* Signal the output process to trigger an update (see section 2.5). */ + rip_event(RIP_TRIGGERED_UPDATE, 0); - return rinfo; + return rinfo; } /* Delete one route from the ECMP list. @@ -255,692 +239,694 @@ rip_ecmp_replace (struct rip_info *rinfo_new) * the entry - the entry is the last one in the list; its metric is set * to INFINITY, and the garbage collector is started for it */ -struct rip_info * -rip_ecmp_delete (struct rip_info *rinfo) -{ - struct route_node *rp = rinfo->rp; - struct list *list = (struct list *)rp->info; - - RIP_TIMER_OFF (rinfo->t_timeout); - - if (listcount (list) > 1) - { - /* Some other ECMP entries still exist. Just delete this entry. */ - RIP_TIMER_OFF (rinfo->t_garbage_collect); - listnode_delete (list, rinfo); - if (rip_route_rte (rinfo) && CHECK_FLAG (rinfo->flags, RIP_RTF_FIB)) - /* The ADD message implies the update. */ - rip_zebra_ipv4_add (rp); - rip_info_free (rinfo); - rinfo = NULL; - } - else - { - assert (rinfo == listgetdata (listhead (list))); - - /* This is the only entry left in the list. We must keep it in - * the list for garbage collection time, with INFINITY metric. */ - - rinfo->metric = RIP_METRIC_INFINITY; - RIP_TIMER_ON (rinfo->t_garbage_collect, - rip_garbage_collect, rip->garbage_time); - - if (rip_route_rte (rinfo) && CHECK_FLAG (rinfo->flags, RIP_RTF_FIB)) - rip_zebra_ipv4_delete (rp); - } +struct rip_info *rip_ecmp_delete(struct rip_info *rinfo) +{ + struct route_node *rp = rinfo->rp; + struct list *list = (struct list *)rp->info; + + RIP_TIMER_OFF(rinfo->t_timeout); + + if (listcount(list) > 1) { + /* Some other ECMP entries still exist. Just delete this entry. + */ + RIP_TIMER_OFF(rinfo->t_garbage_collect); + listnode_delete(list, rinfo); + if (rip_route_rte(rinfo) + && CHECK_FLAG(rinfo->flags, RIP_RTF_FIB)) + /* The ADD message implies the update. */ + rip_zebra_ipv4_add(rp); + rip_info_free(rinfo); + rinfo = NULL; + } else { + assert(rinfo == listgetdata(listhead(list))); + + /* This is the only entry left in the list. We must keep it in + * the list for garbage collection time, with INFINITY metric. + */ + + rinfo->metric = RIP_METRIC_INFINITY; + RIP_TIMER_ON(rinfo->t_garbage_collect, rip_garbage_collect, + rip->garbage_time); + + if (rip_route_rte(rinfo) + && CHECK_FLAG(rinfo->flags, RIP_RTF_FIB)) + rip_zebra_ipv4_delete(rp); + } - /* Set the route change flag on the first entry. */ - rinfo = listgetdata (listhead (list)); - SET_FLAG (rinfo->flags, RIP_RTF_CHANGED); + /* Set the route change flag on the first entry. */ + rinfo = listgetdata(listhead(list)); + SET_FLAG(rinfo->flags, RIP_RTF_CHANGED); - /* Signal the output process to trigger an update (see section 2.5). */ - rip_event (RIP_TRIGGERED_UPDATE, 0); + /* Signal the output process to trigger an update (see section 2.5). */ + rip_event(RIP_TRIGGERED_UPDATE, 0); - return rinfo; + return rinfo; } /* Timeout RIP routes. */ -static int -rip_timeout (struct thread *t) +static int rip_timeout(struct thread *t) { - rip_ecmp_delete ((struct rip_info *)THREAD_ARG (t)); - return 0; + rip_ecmp_delete((struct rip_info *)THREAD_ARG(t)); + return 0; } -static 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); - } -} - -static int -rip_filter (int rip_distribute, struct prefix_ipv4 *p, struct rip_interface *ri) -{ - struct distribute *dist; - struct access_list *alist; - struct prefix_list *plist; - int distribute = rip_distribute == RIP_FILTER_OUT ? - DISTRIBUTE_V4_OUT : DISTRIBUTE_V4_IN; - const char *inout = rip_distribute == RIP_FILTER_OUT ? "out" : "in"; - - /* Input distribute-list filtering. */ - if (ri->list[rip_distribute]) - { - if (access_list_apply (ri->list[rip_distribute], - (struct prefix *) p) == FILTER_DENY) - { - if (IS_RIP_DEBUG_PACKET) - zlog_debug ("%s/%d filtered by distribute %s", - inet_ntoa (p->prefix), p->prefixlen, inout); - return -1; - } - } - if (ri->prefix[rip_distribute]) +static void rip_timeout_update(struct rip_info *rinfo) { - if (prefix_list_apply (ri->prefix[rip_distribute], - (struct prefix *) p) == PREFIX_DENY) - { - if (IS_RIP_DEBUG_PACKET) - zlog_debug ("%s/%d filtered by prefix-list %s", - inet_ntoa (p->prefix), p->prefixlen, inout); - return -1; - } - } - - /* All interface filter check. */ - dist = distribute_lookup (NULL); - if (dist) - { - if (dist->list[distribute]) - { - alist = access_list_lookup (AFI_IP, dist->list[distribute]); - - if (alist) - { - if (access_list_apply (alist, (struct prefix *) p) == FILTER_DENY) - { - if (IS_RIP_DEBUG_PACKET) - zlog_debug ("%s/%d filtered by distribute %s", - inet_ntoa (p->prefix), p->prefixlen, inout); - return -1; + if (rinfo->metric != RIP_METRIC_INFINITY) { + RIP_TIMER_OFF(rinfo->t_timeout); + RIP_TIMER_ON(rinfo->t_timeout, rip_timeout, rip->timeout_time); + } +} + +static int rip_filter(int rip_distribute, struct prefix_ipv4 *p, + struct rip_interface *ri) +{ + struct distribute *dist; + struct access_list *alist; + struct prefix_list *plist; + int distribute = rip_distribute == RIP_FILTER_OUT ? DISTRIBUTE_V4_OUT + : DISTRIBUTE_V4_IN; + const char *inout = rip_distribute == RIP_FILTER_OUT ? "out" : "in"; + + /* Input distribute-list filtering. */ + if (ri->list[rip_distribute]) { + if (access_list_apply(ri->list[rip_distribute], + (struct prefix *)p) + == FILTER_DENY) { + if (IS_RIP_DEBUG_PACKET) + zlog_debug("%s/%d filtered by distribute %s", + inet_ntoa(p->prefix), p->prefixlen, + inout); + return -1; } - } } - if (dist->prefix[distribute]) - { - plist = prefix_list_lookup (AFI_IP, dist->prefix[distribute]); - - if (plist) - { - if (prefix_list_apply (plist, - (struct prefix *) p) == PREFIX_DENY) - { - if (IS_RIP_DEBUG_PACKET) - zlog_debug ("%s/%d filtered by prefix-list %s", - inet_ntoa (p->prefix), p->prefixlen, inout); - return -1; + if (ri->prefix[rip_distribute]) { + if (prefix_list_apply(ri->prefix[rip_distribute], + (struct prefix *)p) + == PREFIX_DENY) { + if (IS_RIP_DEBUG_PACKET) + zlog_debug("%s/%d filtered by prefix-list %s", + inet_ntoa(p->prefix), p->prefixlen, + inout); + return -1; + } + } + + /* All interface filter check. */ + dist = distribute_lookup(NULL); + if (dist) { + if (dist->list[distribute]) { + alist = access_list_lookup(AFI_IP, + dist->list[distribute]); + + if (alist) { + if (access_list_apply(alist, (struct prefix *)p) + == FILTER_DENY) { + if (IS_RIP_DEBUG_PACKET) + zlog_debug( + "%s/%d filtered by distribute %s", + inet_ntoa(p->prefix), + p->prefixlen, inout); + return -1; + } + } + } + if (dist->prefix[distribute]) { + plist = prefix_list_lookup(AFI_IP, + dist->prefix[distribute]); + + if (plist) { + if (prefix_list_apply(plist, (struct prefix *)p) + == PREFIX_DENY) { + if (IS_RIP_DEBUG_PACKET) + zlog_debug( + "%s/%d filtered by prefix-list %s", + inet_ntoa(p->prefix), + p->prefixlen, inout); + return -1; + } + } } - } } - } - return 0; + return 0; } /* Check nexthop address validity. */ -static int -rip_nexthop_check (struct in_addr *addr) +static int rip_nexthop_check(struct in_addr *addr) { - struct listnode *node; - struct listnode *cnode; - struct interface *ifp; - struct connected *ifc; - struct prefix *p; + struct listnode *node; + struct listnode *cnode; + struct interface *ifp; + struct connected *ifc; + struct prefix *p; - /* If nexthop address matches local configured address then it is - invalid nexthop. */ + /* If nexthop address matches local configured address then it is + invalid nexthop. */ - for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp)) - { - for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, ifc)) - { - p = ifc->address; + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) { + for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, ifc)) { + p = ifc->address; - if (p->family == AF_INET - && IPV4_ADDR_SAME (&p->u.prefix4, addr)) - return -1; + if (p->family == AF_INET + && IPV4_ADDR_SAME(&p->u.prefix4, addr)) + return -1; + } } - } - return 0; + return 0; } /* RIP add route to routing table. */ -static 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 = NULL, newinfo; - struct rip_interface *ri; - struct in_addr *nexthop; - int same = 0; - unsigned char old_dist, new_dist; - struct list *list = NULL; - struct listnode *node = NULL; - - /* 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_filter (RIP_FILTER_IN, &p, ri); - if (ret < 0) - return; - - memset (&newinfo, 0, sizeof (newinfo)); - newinfo.type = ZEBRA_ROUTE_RIP; - newinfo.sub_type = RIP_ROUTE_RTE; - newinfo.nexthop = rte->nexthop; - newinfo.from = from->sin_addr; - newinfo.ifindex = ifp->ifindex; - newinfo.metric = rte->metric; - newinfo.metric_out = rte->metric; /* XXX */ - newinfo.tag = ntohs (rte->tag); /* XXX */ - - /* Modify entry according to the interface routemap. */ - if (ri->routemap[RIP_FILTER_IN]) - { - int ret; - - /* The object should be of the type of rip_info */ - ret = route_map_apply (ri->routemap[RIP_FILTER_IN], - (struct prefix *) &p, RMAP_RIP, &newinfo); - - if (ret == RMAP_DENYMATCH) - { - if (IS_RIP_DEBUG_PACKET) - zlog_debug ("RIP %s/%d is filtered by route-map in", - inet_ntoa (p.prefix), p.prefixlen); - return; - } - - /* Get back the object */ - rte->nexthop = newinfo.nexthop_out; - rte->tag = htons (newinfo.tag_out); /* XXX */ - rte->metric = newinfo.metric_out; /* XXX: the routemap uses the metric_out field */ - } - - /* 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 ? ifp->metric : 1; - - 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 if nexthop address is myself, then do nothing. */ - if (rip_nexthop_check (nexthop) < 0) - { - if (IS_RIP_DEBUG_PACKET) - zlog_debug ("Nexthop address %s is myself", inet_ntoa (*nexthop)); - return; - } - - /* Get index for the prefix. */ - rp = route_node_get (rip->table, (struct prefix *) &p); - - newinfo.rp = rp; - newinfo.nexthop = *nexthop; - newinfo.metric = rte->metric; - newinfo.tag = ntohs (rte->tag); - newinfo.distance = rip_distance_apply (&newinfo); - - new_dist = newinfo.distance ? newinfo.distance : ZEBRA_RIP_DISTANCE_DEFAULT; - - /* Check to see whether there is already RIP route on the table. */ - if ((list = rp->info) != NULL) - for (ALL_LIST_ELEMENTS_RO (list, node, rinfo)) - { - /* Need to compare with redistributed entry or local entry */ - if (!rip_route_rte (rinfo)) - break; - - if (IPV4_ADDR_SAME (&rinfo->from, &from->sin_addr) && - IPV4_ADDR_SAME (&rinfo->nexthop, nexthop)) - break; - - if (!listnextnode (node)) - { - /* Not found in the list */ - - if (rte->metric > rinfo->metric) - { - /* New route has a greater metric. Discard it. */ - route_unlock_node (rp); - return; - } - - if (rte->metric < rinfo->metric) - /* New route has a smaller metric. Replace the ECMP list - * with the new one in below. */ - break; - - /* Metrics are same. We compare the distances. */ - old_dist = rinfo->distance ? \ - rinfo->distance : ZEBRA_RIP_DISTANCE_DEFAULT; - - if (new_dist > old_dist) - { - /* New route has a greater distance. Discard it. */ - route_unlock_node (rp); - return; - } - - if (new_dist < old_dist) - /* New route has a smaller distance. Replace the ECMP list - * with the new one in below. */ - break; - - /* Metrics and distances are both same. Keep "rinfo" null and - * the new route is added in the ECMP list in below. */ - } - } - - if (rinfo) - { - /* Local static route. */ - if (rinfo->type == ZEBRA_ROUTE_RIP - && ((rinfo->sub_type == RIP_ROUTE_STATIC) || - (rinfo->sub_type == RIP_ROUTE_DEFAULT)) - && rinfo->metric != RIP_METRIC_INFINITY) - { - route_unlock_node (rp); - return; - } - - /* Redistributed route check. */ - if (rinfo->type != ZEBRA_ROUTE_RIP - && rinfo->metric != RIP_METRIC_INFINITY) - { - old_dist = rinfo->distance; - /* Only routes directly connected to an interface (nexthop == 0) - * may have a valid NULL distance */ - if (rinfo->nexthop.s_addr != 0) - old_dist = old_dist ? old_dist : ZEBRA_RIP_DISTANCE_DEFAULT; - /* If imported route does not have STRICT precedence, - mark it as a ghost */ - if (new_dist <= old_dist && rte->metric != RIP_METRIC_INFINITY) - rip_ecmp_replace (&newinfo); - - route_unlock_node (rp); - return; - } - } - - if (!rinfo) - { - if (rp->info) - route_unlock_node (rp); - - /* 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) - rip_ecmp_add (&newinfo); - } - else - { - /* Route is there but we are not sure the route is RIP or not. */ - - /* 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) - && (rinfo->ifindex == ifp->ifindex)); - - old_dist = rinfo->distance ? \ - rinfo->distance : ZEBRA_RIP_DISTANCE_DEFAULT; - - /* 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, or if the tag has been changed; or if there is a route - with a lower administrave distance; or an update of the - distance on the actual route; do the following actions: */ - if ((same && rinfo->metric != rte->metric) - || (rte->metric < rinfo->metric) - || ((same) - && (rinfo->metric == rte->metric) - && (newinfo.tag != rinfo->tag)) - || (old_dist > new_dist) - || ((old_dist != new_dist) && same)) - { - if (listcount (list) == 1) - { - if (newinfo.metric != RIP_METRIC_INFINITY) - rip_ecmp_replace (&newinfo); - else - rip_ecmp_delete (rinfo); - } - else - { - if (newinfo.metric < rinfo->metric) - rip_ecmp_replace (&newinfo); - else if (newinfo.metric > rinfo->metric) - rip_ecmp_delete (rinfo); - else if (new_dist < old_dist) - rip_ecmp_replace (&newinfo); - else if (new_dist > old_dist) - rip_ecmp_delete (rinfo); - else - { - int update = CHECK_FLAG (rinfo->flags, RIP_RTF_FIB) ? 1 : 0; - - assert (newinfo.metric != RIP_METRIC_INFINITY); - - RIP_TIMER_OFF (rinfo->t_timeout); - RIP_TIMER_OFF (rinfo->t_garbage_collect); - memcpy (rinfo, &newinfo, sizeof (struct rip_info)); - rip_timeout_update (rinfo); - - if (update) - rip_zebra_ipv4_add (rp); - - /* - Set the route change flag on the first entry. */ - rinfo = listgetdata (listhead (list)); - SET_FLAG (rinfo->flags, RIP_RTF_CHANGED); - rip_event (RIP_TRIGGERED_UPDATE, 0); - } - } - } - else /* same & no change */ - rip_timeout_update (rinfo); - - /* Unlock tempolary lock of the route. */ - route_unlock_node (rp); - } -} +static 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 = NULL, newinfo; + struct rip_interface *ri; + struct in_addr *nexthop; + int same = 0; + unsigned char old_dist, new_dist; + struct list *list = NULL; + struct listnode *node = NULL; + + /* 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; -/* Dump RIP packet */ -static void -rip_packet_dump (struct rip_packet *packet, int size, const char *sndrcv) -{ - caddr_t lim; - struct rte *rte; - const 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_msg (rip_msg, packet->command, NULL); - else - command_str = "unknown"; - - /* Dump packet header. */ - zlog_debug ("%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); + ret = rip_filter(RIP_FILTER_IN, &p, ri); + if (ret < 0) + return; + + memset(&newinfo, 0, sizeof(newinfo)); + newinfo.type = ZEBRA_ROUTE_RIP; + newinfo.sub_type = RIP_ROUTE_RTE; + newinfo.nexthop = rte->nexthop; + newinfo.from = from->sin_addr; + newinfo.ifindex = ifp->ifindex; + newinfo.metric = rte->metric; + newinfo.metric_out = rte->metric; /* XXX */ + newinfo.tag = ntohs(rte->tag); /* XXX */ + + /* Modify entry according to the interface routemap. */ + if (ri->routemap[RIP_FILTER_IN]) { + int ret; + + /* The object should be of the type of rip_info */ + ret = route_map_apply(ri->routemap[RIP_FILTER_IN], + (struct prefix *)&p, RMAP_RIP, &newinfo); + + if (ret == RMAP_DENYMATCH) { + if (IS_RIP_DEBUG_PACKET) + zlog_debug( + "RIP %s/%d is filtered by route-map in", + inet_ntoa(p.prefix), p.prefixlen); + return; + } + + /* Get back the object */ + rte->nexthop = newinfo.nexthop_out; + rte->tag = htons(newinfo.tag_out); /* XXX */ + rte->metric = + newinfo.metric_out; /* XXX: the routemap uses the + metric_out field */ + } - if (rte->family == htons (RIP_FAMILY_AUTH)) - { - if (rte->tag == htons (RIP_AUTH_SIMPLE_PASSWORD)) - { - p = (u_char *)&rte->prefix; + /* 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); - zlog_debug (" family 0x%X type %d auth string: %s", - ntohs (rte->family), ntohs (rte->tag), p); + /* If offset-list does not modify the metric use interface's + metric. */ + if (!ret) + rte->metric += ifp->metric ? ifp->metric : 1; + + 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 if nexthop address is myself, then do nothing. */ + if (rip_nexthop_check(nexthop) < 0) { + if (IS_RIP_DEBUG_PACKET) + zlog_debug("Nexthop address %s is myself", + inet_ntoa(*nexthop)); + return; + } + + /* Get index for the prefix. */ + rp = route_node_get(rip->table, (struct prefix *)&p); + + newinfo.rp = rp; + newinfo.nexthop = *nexthop; + newinfo.metric = rte->metric; + newinfo.tag = ntohs(rte->tag); + newinfo.distance = rip_distance_apply(&newinfo); + + new_dist = newinfo.distance ? newinfo.distance + : ZEBRA_RIP_DISTANCE_DEFAULT; + + /* Check to see whether there is already RIP route on the table. */ + if ((list = rp->info) != NULL) + for (ALL_LIST_ELEMENTS_RO(list, node, rinfo)) { + /* Need to compare with redistributed entry or local + * entry */ + if (!rip_route_rte(rinfo)) + break; + + if (IPV4_ADDR_SAME(&rinfo->from, &from->sin_addr) + && IPV4_ADDR_SAME(&rinfo->nexthop, nexthop)) + break; + + if (!listnextnode(node)) { + /* Not found in the list */ + + if (rte->metric > rinfo->metric) { + /* New route has a greater metric. + * Discard it. */ + route_unlock_node(rp); + return; + } + + if (rte->metric < rinfo->metric) + /* New route has a smaller metric. + * Replace the ECMP list + * with the new one in below. */ + break; + + /* Metrics are same. We compare the distances. + */ + old_dist = rinfo->distance + ? rinfo->distance + : ZEBRA_RIP_DISTANCE_DEFAULT; + + if (new_dist > old_dist) { + /* New route has a greater distance. + * Discard it. */ + route_unlock_node(rp); + return; + } + + if (new_dist < old_dist) + /* New route has a smaller distance. + * Replace the ECMP list + * with the new one in below. */ + break; + + /* Metrics and distances are both same. Keep + * "rinfo" null and + * the new route is added in the ECMP list in + * below. */ + } } - else if (rte->tag == htons (RIP_AUTH_MD5)) - { - struct rip_md5_info *md5; - - md5 = (struct rip_md5_info *) &packet->rte; - - zlog_debug (" family 0x%X type %d (MD5 authentication)", - ntohs (md5->family), ntohs (md5->type)); - zlog_debug (" RIP-2 packet len %d Key ID %d" - " Auth Data len %d", - ntohs (md5->packet_len), md5->keyid, - md5->auth_len); - zlog_debug (" Sequence Number %ld", - (u_long) ntohl (md5->sequence)); + + if (rinfo) { + /* Local static route. */ + if (rinfo->type == ZEBRA_ROUTE_RIP + && ((rinfo->sub_type == RIP_ROUTE_STATIC) + || (rinfo->sub_type == RIP_ROUTE_DEFAULT)) + && rinfo->metric != RIP_METRIC_INFINITY) { + route_unlock_node(rp); + return; } - else if (rte->tag == htons (RIP_AUTH_DATA)) - { - p = (u_char *)&rte->prefix; - - zlog_debug (" family 0x%X type %d (MD5 data)", - ntohs (rte->family), ntohs (rte->tag)); - zlog_debug (" MD5: %02X%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[8], p[9], p[10], p[11], p[12], p[13], - p[14], p[15]); + + /* Redistributed route check. */ + if (rinfo->type != ZEBRA_ROUTE_RIP + && rinfo->metric != RIP_METRIC_INFINITY) { + old_dist = rinfo->distance; + /* Only routes directly connected to an interface + * (nexthop == 0) + * may have a valid NULL distance */ + if (rinfo->nexthop.s_addr != 0) + old_dist = old_dist + ? old_dist + : ZEBRA_RIP_DISTANCE_DEFAULT; + /* If imported route does not have STRICT precedence, + mark it as a ghost */ + if (new_dist <= old_dist + && rte->metric != RIP_METRIC_INFINITY) + rip_ecmp_replace(&newinfo); + + route_unlock_node(rp); + return; } - else - { - zlog_debug (" family 0x%X type %d (Unknown auth type)", - ntohs (rte->family), ntohs (rte->tag)); + } + + if (!rinfo) { + if (rp->info) + route_unlock_node(rp); + + /* 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) + rip_ecmp_add(&newinfo); + } else { + /* Route is there but we are not sure the route is RIP or not. + */ + + /* 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) + && (rinfo->ifindex == ifp->ifindex)); + + old_dist = rinfo->distance ? rinfo->distance + : ZEBRA_RIP_DISTANCE_DEFAULT; + + /* 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, or if the tag has been changed; or if there is a route + with a lower administrave distance; or an update of the + distance on the actual route; do the following actions: */ + if ((same && rinfo->metric != rte->metric) + || (rte->metric < rinfo->metric) + || ((same) && (rinfo->metric == rte->metric) + && (newinfo.tag != rinfo->tag)) + || (old_dist > new_dist) + || ((old_dist != new_dist) && same)) { + if (listcount(list) == 1) { + if (newinfo.metric != RIP_METRIC_INFINITY) + rip_ecmp_replace(&newinfo); + else + rip_ecmp_delete(rinfo); + } else { + if (newinfo.metric < rinfo->metric) + rip_ecmp_replace(&newinfo); + else if (newinfo.metric > rinfo->metric) + rip_ecmp_delete(rinfo); + else if (new_dist < old_dist) + rip_ecmp_replace(&newinfo); + else if (new_dist > old_dist) + rip_ecmp_delete(rinfo); + else { + int update = CHECK_FLAG(rinfo->flags, + RIP_RTF_FIB) + ? 1 + : 0; + + assert(newinfo.metric + != RIP_METRIC_INFINITY); + + RIP_TIMER_OFF(rinfo->t_timeout); + RIP_TIMER_OFF(rinfo->t_garbage_collect); + memcpy(rinfo, &newinfo, + sizeof(struct rip_info)); + rip_timeout_update(rinfo); + + if (update) + rip_zebra_ipv4_add(rp); + + /* - Set the route change flag on the + * first entry. */ + rinfo = listgetdata(listhead(list)); + SET_FLAG(rinfo->flags, RIP_RTF_CHANGED); + rip_event(RIP_TRIGGERED_UPDATE, 0); + } + } + } else /* same & no change */ + rip_timeout_update(rinfo); + + /* Unlock tempolary lock of the route. */ + route_unlock_node(rp); + } +} + +/* Dump RIP packet */ +static void rip_packet_dump(struct rip_packet *packet, int size, + const char *sndrcv) +{ + caddr_t lim; + struct rte *rte; + const 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_msg(rip_msg, packet->command, NULL); + else + command_str = "unknown"; + + /* Dump packet header. */ + zlog_debug("%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 (rte->family == htons(RIP_FAMILY_AUTH)) { + if (rte->tag + == htons(RIP_AUTH_SIMPLE_PASSWORD)) { + p = (u_char *)&rte->prefix; + + zlog_debug( + " family 0x%X type %d auth string: %s", + ntohs(rte->family), + ntohs(rte->tag), p); + } else if (rte->tag == htons(RIP_AUTH_MD5)) { + struct rip_md5_info *md5; + + md5 = (struct rip_md5_info *)&packet + ->rte; + + zlog_debug( + " family 0x%X type %d (MD5 authentication)", + ntohs(md5->family), + ntohs(md5->type)); + zlog_debug( + " RIP-2 packet len %d Key ID %d" + " Auth Data len %d", + ntohs(md5->packet_len), + md5->keyid, md5->auth_len); + zlog_debug( + " Sequence Number %ld", + (u_long)ntohl(md5->sequence)); + } else if (rte->tag == htons(RIP_AUTH_DATA)) { + p = (u_char *)&rte->prefix; + + zlog_debug( + " family 0x%X type %d (MD5 data)", + ntohs(rte->family), + ntohs(rte->tag)); + zlog_debug( + " MD5: %02X%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[8], p[9], + p[10], p[11], p[12], p[13], + p[14], p[15]); + } else { + zlog_debug( + " family 0x%X type %d (Unknown auth type)", + ntohs(rte->family), + ntohs(rte->tag)); + } + } else + zlog_debug( + " %s/%d -> %s family %d tag %" ROUTE_TAG_PRI + " metric %ld", + inet_ntop(AF_INET, &rte->prefix, pbuf, + BUFSIZ), + netmask, + inet_ntop(AF_INET, &rte->nexthop, nbuf, + BUFSIZ), + ntohs(rte->family), + (route_tag_t)ntohs(rte->tag), + (u_long)ntohl(rte->metric)); + } else { + zlog_debug( + " %s family %d tag %" ROUTE_TAG_PRI + " metric %ld", + inet_ntop(AF_INET, &rte->prefix, pbuf, BUFSIZ), + ntohs(rte->family), + (route_tag_t)ntohs(rte->tag), + (u_long)ntohl(rte->metric)); } - } - else - zlog_debug (" %s/%d -> %s family %d tag %"ROUTE_TAG_PRI" metric %ld", - inet_ntop (AF_INET, &rte->prefix, pbuf, BUFSIZ), - netmask, inet_ntop (AF_INET, &rte->nexthop, nbuf, - BUFSIZ), ntohs (rte->family), - (route_tag_t)ntohs (rte->tag), - (u_long) ntohl (rte->metric)); - } - else - { - zlog_debug (" %s family %d tag %"ROUTE_TAG_PRI" metric %ld", - inet_ntop (AF_INET, &rte->prefix, pbuf, BUFSIZ), - ntohs (rte->family), (route_tag_t)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. */ -static int -rip_destination_check (struct in_addr addr) +static int rip_destination_check(struct in_addr addr) { - u_int32_t destination; + u_int32_t destination; - /* Convert to host byte order. */ - destination = ntohl (addr.s_addr); + /* Convert to host byte order. */ + destination = ntohl(addr.s_addr); - if (IPV4_NET127 (destination)) - return 0; + if (IPV4_NET127(destination)) + return 0; - /* Net 0 may match to the default route. */ - if (IPV4_NET0 (destination) && destination != 0) - 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; + /* 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; + return 0; } /* RIP version 2 authentication. */ -static int -rip_auth_simple_password (struct rte *rte, struct sockaddr_in *from, - struct interface *ifp) -{ - struct rip_interface *ri; - char *auth_str = (char *) &rte->prefix; - int i; - - /* reject passwords with zeros in the middle of the string */ - for (i = strlen (auth_str); i < 16; i++) - { - if (auth_str[i] != '\0') - return 0; - } - - if (IS_RIP_DEBUG_EVENT) - zlog_debug ("RIPv2 simple password authentication from %s", - inet_ntoa (from->sin_addr)); - - ri = ifp->info; - - if (ri->auth_type != RIP_AUTH_SIMPLE_PASSWORD - || rte->tag != htons(RIP_AUTH_SIMPLE_PASSWORD)) - return 0; - - /* Simple password authentication. */ - if (ri->auth_str) - { - 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; +static int rip_auth_simple_password(struct rte *rte, struct sockaddr_in *from, + struct interface *ifp) +{ + struct rip_interface *ri; + char *auth_str = (char *)&rte->prefix; + int i; + + /* reject passwords with zeros in the middle of the string */ + for (i = strlen(auth_str); i < 16; i++) { + if (auth_str[i] != '\0') + return 0; + } + + if (IS_RIP_DEBUG_EVENT) + zlog_debug("RIPv2 simple password authentication from %s", + inet_ntoa(from->sin_addr)); + + ri = ifp->info; - key = key_match_for_accept (keychain, auth_str); - if (key) - return 1; - } - return 0; + if (ri->auth_type != RIP_AUTH_SIMPLE_PASSWORD + || rte->tag != htons(RIP_AUTH_SIMPLE_PASSWORD)) + return 0; + + /* Simple password authentication. */ + if (ri->auth_str) { + 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, auth_str); + if (key) + return 1; + } + return 0; } /* RIP version 2 authentication with MD5. */ -static int -rip_auth_md5 (struct rip_packet *packet, struct sockaddr_in *from, - int length, struct interface *ifp) -{ - struct rip_interface *ri; - struct rip_md5_info *md5; - struct rip_md5_data *md5data; - struct keychain *keychain; - struct key *key; - MD5_CTX ctx; - u_char digest[RIP_AUTH_MD5_SIZE]; - u_int16_t packet_len; - char auth_str[RIP_AUTH_MD5_SIZE]; - - if (IS_RIP_DEBUG_EVENT) - zlog_debug ("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 || md5->type != htons(RIP_AUTH_MD5)) - return 0; - - /* If the authentication length is less than 16, then it must be wrong for - * any interpretation of rfc2082. Some implementations also interpret - * this as RIP_HEADER_SIZE+ RIP_AUTH_MD5_SIZE, aka RIP_AUTH_MD5_COMPAT_SIZE. - */ - if ( !((md5->auth_len == RIP_AUTH_MD5_SIZE) - || (md5->auth_len == RIP_AUTH_MD5_COMPAT_SIZE))) - { - if (IS_RIP_DEBUG_EVENT) - zlog_debug ("RIPv2 MD5 authentication, strange authentication " - "length field %d", md5->auth_len); - return 0; - } - - /* grab and verify check packet length */ - packet_len = ntohs (md5->packet_len); - - if (packet_len > (length - RIP_HEADER_SIZE - RIP_AUTH_MD5_SIZE)) - { - if (IS_RIP_DEBUG_EVENT) - zlog_debug ("RIPv2 MD5 authentication, packet length field %d " - "greater than received length %d!", - md5->packet_len, length); - return 0; - } - - /* retrieve authentication data */ - md5data = (struct rip_md5_data *) (((u_char *) packet) + packet_len); - - memset (auth_str, 0, RIP_AUTH_MD5_SIZE); - - if (ri->key_chain) - { - keychain = keychain_lookup (ri->key_chain); - if (keychain == NULL) - return 0; +static int rip_auth_md5(struct rip_packet *packet, struct sockaddr_in *from, + int length, struct interface *ifp) +{ + struct rip_interface *ri; + struct rip_md5_info *md5; + struct rip_md5_data *md5data; + struct keychain *keychain; + struct key *key; + MD5_CTX ctx; + u_char digest[RIP_AUTH_MD5_SIZE]; + u_int16_t packet_len; + char auth_str[RIP_AUTH_MD5_SIZE]; + + if (IS_RIP_DEBUG_EVENT) + zlog_debug("RIPv2 MD5 authentication from %s", + inet_ntoa(from->sin_addr)); - key = key_lookup_for_accept (keychain, md5->keyid); - if (key == NULL) - return 0; + ri = ifp->info; + md5 = (struct rip_md5_info *)&packet->rte; + + /* Check auth type. */ + if (ri->auth_type != RIP_AUTH_MD5 || md5->type != htons(RIP_AUTH_MD5)) + return 0; + + /* If the authentication length is less than 16, then it must be wrong + * for + * any interpretation of rfc2082. Some implementations also interpret + * this as RIP_HEADER_SIZE+ RIP_AUTH_MD5_SIZE, aka + * RIP_AUTH_MD5_COMPAT_SIZE. + */ + if (!((md5->auth_len == RIP_AUTH_MD5_SIZE) + || (md5->auth_len == RIP_AUTH_MD5_COMPAT_SIZE))) { + if (IS_RIP_DEBUG_EVENT) + zlog_debug( + "RIPv2 MD5 authentication, strange authentication " + "length field %d", + md5->auth_len); + return 0; + } - strncpy (auth_str, key->string, RIP_AUTH_MD5_SIZE); - } - else if (ri->auth_str) - strncpy (auth_str, ri->auth_str, RIP_AUTH_MD5_SIZE); - - if (auth_str[0] == 0) - return 0; - - /* MD5 digest authentication. */ - memset (&ctx, 0, sizeof(ctx)); - MD5Init(&ctx); - MD5Update(&ctx, packet, packet_len + RIP_HEADER_SIZE); - MD5Update(&ctx, auth_str, RIP_AUTH_MD5_SIZE); - MD5Final(digest, &ctx); - - if (memcmp (md5data->digest, digest, RIP_AUTH_MD5_SIZE) == 0) - return packet_len; - else - return 0; + /* grab and verify check packet length */ + packet_len = ntohs(md5->packet_len); + + if (packet_len > (length - RIP_HEADER_SIZE - RIP_AUTH_MD5_SIZE)) { + if (IS_RIP_DEBUG_EVENT) + zlog_debug( + "RIPv2 MD5 authentication, packet length field %d " + "greater than received length %d!", + md5->packet_len, length); + return 0; + } + + /* retrieve authentication data */ + md5data = (struct rip_md5_data *)(((u_char *)packet) + packet_len); + + memset(auth_str, 0, RIP_AUTH_MD5_SIZE); + + 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; + + strncpy(auth_str, key->string, RIP_AUTH_MD5_SIZE); + } else if (ri->auth_str) + strncpy(auth_str, ri->auth_str, RIP_AUTH_MD5_SIZE); + + if (auth_str[0] == 0) + return 0; + + /* MD5 digest authentication. */ + memset(&ctx, 0, sizeof(ctx)); + MD5Init(&ctx); + MD5Update(&ctx, packet, packet_len + RIP_HEADER_SIZE); + MD5Update(&ctx, auth_str, RIP_AUTH_MD5_SIZE); + MD5Final(digest, &ctx); + + if (memcmp(md5data->digest, digest, RIP_AUTH_MD5_SIZE) == 0) + return packet_len; + else + return 0; } /* Pick correct auth string for sends, prepare auth_str buffer for use. @@ -951,39 +937,37 @@ rip_auth_md5 (struct rip_packet *packet, struct sockaddr_in *from, * zero padded. * */ -static void -rip_auth_prepare_str_send (struct rip_interface *ri, struct key *key, - char *auth_str, int len) +static void rip_auth_prepare_str_send(struct rip_interface *ri, struct key *key, + char *auth_str, int len) { - assert (ri || key); + assert(ri || key); - memset (auth_str, 0, len); - if (key && key->string) - strncpy (auth_str, key->string, len); - else if (ri->auth_str) - strncpy (auth_str, ri->auth_str, len); + memset(auth_str, 0, len); + if (key && key->string) + strncpy(auth_str, key->string, len); + else if (ri->auth_str) + strncpy(auth_str, ri->auth_str, len); - return; + return; } /* Write RIPv2 simple password authentication information * - * auth_str is presumed to be 2 bytes and correctly prepared + * auth_str is presumed to be 2 bytes and correctly prepared * (left justified and zero padded). */ -static void -rip_auth_simple_write (struct stream *s, char *auth_str, int len) +static void rip_auth_simple_write(struct stream *s, char *auth_str, int len) { - assert (s && len == RIP_AUTH_SIMPLE_SIZE); - - stream_putw (s, RIP_FAMILY_AUTH); - stream_putw (s, RIP_AUTH_SIMPLE_PASSWORD); - stream_put (s, auth_str, RIP_AUTH_SIMPLE_SIZE); - - return; + assert(s && len == RIP_AUTH_SIMPLE_SIZE); + + stream_putw(s, RIP_FAMILY_AUTH); + stream_putw(s, RIP_AUTH_SIMPLE_PASSWORD); + stream_put(s, auth_str, RIP_AUTH_SIMPLE_SIZE); + + return; } -/* write RIPv2 MD5 "authentication header" +/* write RIPv2 MD5 "authentication header" * (uses the auth key data field) * * Digest offset field is set to 0. @@ -991,1814 +975,1816 @@ rip_auth_simple_write (struct stream *s, char *auth_str, int len) * returns: offset of the digest offset field, which must be set when * length to the auth-data MD5 digest is known. */ -static size_t -rip_auth_md5_ah_write (struct stream *s, struct rip_interface *ri, - struct key *key) -{ - size_t doff = 0; - - assert (s && ri && ri->auth_type == RIP_AUTH_MD5); - - /* MD5 authentication. */ - stream_putw (s, RIP_FAMILY_AUTH); - stream_putw (s, RIP_AUTH_MD5); - - /* MD5 AH digest offset field. - * - * Set to placeholder value here, to true value when RIP-2 Packet length - * is known. Actual value is set in .....(). - */ - doff = stream_get_endp(s); - stream_putw (s, 0); - - /* Key ID. */ - if (key) - stream_putc (s, key->index % 256); - else - stream_putc (s, 1); - - /* Auth Data Len. Set 16 for MD5 authentication data. Older ripds - * however expect RIP_HEADER_SIZE + RIP_AUTH_MD5_SIZE so we allow for this - * to be configurable. - */ - stream_putc (s, ri->md5_auth_len); - - /* 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); - - return doff; +static size_t rip_auth_md5_ah_write(struct stream *s, struct rip_interface *ri, + struct key *key) +{ + size_t doff = 0; + + assert(s && ri && ri->auth_type == RIP_AUTH_MD5); + + /* MD5 authentication. */ + stream_putw(s, RIP_FAMILY_AUTH); + stream_putw(s, RIP_AUTH_MD5); + + /* MD5 AH digest offset field. + * + * Set to placeholder value here, to true value when RIP-2 Packet length + * is known. Actual value is set in .....(). + */ + doff = stream_get_endp(s); + stream_putw(s, 0); + + /* Key ID. */ + if (key) + stream_putc(s, key->index % 256); + else + stream_putc(s, 1); + + /* Auth Data Len. Set 16 for MD5 authentication data. Older ripds + * however expect RIP_HEADER_SIZE + RIP_AUTH_MD5_SIZE so we allow for + * this + * to be configurable. + */ + stream_putc(s, ri->md5_auth_len); + + /* 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); + + return doff; } /* If authentication is in used, write the appropriate header * returns stream offset to which length must later be written * or 0 if this is not required */ -static size_t -rip_auth_header_write (struct stream *s, struct rip_interface *ri, - struct key *key, char *auth_str, int len) -{ - assert (ri->auth_type != RIP_NO_AUTH); - - switch (ri->auth_type) - { - case RIP_AUTH_SIMPLE_PASSWORD: - rip_auth_prepare_str_send (ri, key, auth_str, len); - rip_auth_simple_write (s, auth_str, len); - return 0; - case RIP_AUTH_MD5: - return rip_auth_md5_ah_write (s, ri, key); - } - assert (1); - return 0; +static size_t rip_auth_header_write(struct stream *s, struct rip_interface *ri, + struct key *key, char *auth_str, int len) +{ + assert(ri->auth_type != RIP_NO_AUTH); + + switch (ri->auth_type) { + case RIP_AUTH_SIMPLE_PASSWORD: + rip_auth_prepare_str_send(ri, key, auth_str, len); + rip_auth_simple_write(s, auth_str, len); + return 0; + case RIP_AUTH_MD5: + return rip_auth_md5_ah_write(s, ri, key); + } + assert(1); + return 0; } /* Write RIPv2 MD5 authentication data trailer */ -static void -rip_auth_md5_set (struct stream *s, struct rip_interface *ri, size_t doff, - char *auth_str, int authlen) -{ - unsigned long len; - MD5_CTX ctx; - unsigned char digest[RIP_AUTH_MD5_SIZE]; - - /* Make it sure this interface is configured as MD5 - authentication. */ - assert ((ri->auth_type == RIP_AUTH_MD5) && (authlen == RIP_AUTH_MD5_SIZE)); - assert (doff > 0); - - /* Get packet length. */ - len = stream_get_endp(s); - - /* 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; - } - - /* Set the digest offset length in the header */ - stream_putw_at (s, doff, len); - - /* Set authentication data. */ - stream_putw (s, RIP_FAMILY_AUTH); - stream_putw (s, RIP_AUTH_DATA); - - /* Generate a digest for the RIP packet. */ - memset(&ctx, 0, sizeof(ctx)); - MD5Init(&ctx); - MD5Update(&ctx, STREAM_DATA (s), stream_get_endp (s)); - MD5Update(&ctx, auth_str, RIP_AUTH_MD5_SIZE); - MD5Final(digest, &ctx); - - /* Copy the digest to the packet. */ - stream_write (s, digest, RIP_AUTH_MD5_SIZE); +static void rip_auth_md5_set(struct stream *s, struct rip_interface *ri, + size_t doff, char *auth_str, int authlen) +{ + unsigned long len; + MD5_CTX ctx; + unsigned char digest[RIP_AUTH_MD5_SIZE]; + + /* Make it sure this interface is configured as MD5 + authentication. */ + assert((ri->auth_type == RIP_AUTH_MD5) + && (authlen == RIP_AUTH_MD5_SIZE)); + assert(doff > 0); + + /* Get packet length. */ + len = stream_get_endp(s); + + /* 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; + } + + /* Set the digest offset length in the header */ + stream_putw_at(s, doff, len); + + /* Set authentication data. */ + stream_putw(s, RIP_FAMILY_AUTH); + stream_putw(s, RIP_AUTH_DATA); + + /* Generate a digest for the RIP packet. */ + memset(&ctx, 0, sizeof(ctx)); + MD5Init(&ctx); + MD5Update(&ctx, STREAM_DATA(s), stream_get_endp(s)); + MD5Update(&ctx, auth_str, RIP_AUTH_MD5_SIZE); + MD5Final(digest, &ctx); + + /* Copy the digest to the packet. */ + stream_write(s, digest, RIP_AUTH_MD5_SIZE); } /* RIP routing information. */ -static void -rip_response_process (struct rip_packet *packet, int size, - struct sockaddr_in *from, struct connected *ifc) -{ - caddr_t lim; - struct rte *rte; - struct prefix_ipv4 ifaddr; - struct prefix_ipv4 ifaddrclass; - int subnetted; - - memset(&ifaddr, 0, sizeof(ifaddr)); - /* We don't know yet. */ - subnetted = -1; - - /* The Response must be ignored if it is not from the RIP - port. (RFC2453 - Sec. 3.9.2)*/ - if (from->sin_port != htons(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 (RFC2453 - Sec. 3.9.2) */ - if (if_lookup_address((void *)&from->sin_addr, AF_INET, VRF_DEFAULT) == NULL) - { - 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 == htons(RIP_FAMILY_AUTH)) - continue; - - if (rte->family != htons(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; +static void rip_response_process(struct rip_packet *packet, int size, + struct sockaddr_in *from, + struct connected *ifc) +{ + caddr_t lim; + struct rte *rte; + struct prefix_ipv4 ifaddr; + struct prefix_ipv4 ifaddrclass; + int subnetted; + + memset(&ifaddr, 0, sizeof(ifaddr)); + /* We don't know yet. */ + subnetted = -1; + + /* The Response must be ignored if it is not from the RIP + port. (RFC2453 - Sec. 3.9.2)*/ + if (from->sin_port != htons(RIP_PORT_DEFAULT)) { + zlog_info("response doesn't come from RIP port: %d", + from->sin_port); + rip_peer_bad_packet(from); + return; } - /* 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; + /* 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 (RFC2453 - Sec. + 3.9.2) */ + if (if_lookup_address((void *)&from->sin_addr, AF_INET, VRF_DEFAULT) + == NULL) { + zlog_info( + "This datagram doesn't came from a valid neighbor: %s", + inet_ntoa(from->sin_addr)); + rip_peer_bad_packet(from); + return; } - /* 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 ((void *)&rte->nexthop, AF_INET, VRF_DEFAULT)) - { - 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_debug ("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_debug ("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); + /* 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 == htons(RIP_FAMILY_AUTH)) + continue; + + if (rte->family != htons(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; } - else - { - if (IS_RIP_DEBUG_EVENT) - zlog_debug ("Next hop %s is not directly reachable. Treat it as 0.0.0.0", inet_ntoa (rte->nexthop)); - rte->nexthop.s_addr = 0; + + /* - 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); - /* For RIPv1, there won't be a valid netmask. + /* - 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; + } - 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. */ + /* 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; + } - 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; - - if (subnetted == -1) - { - memcpy (&ifaddr, ifc->address, sizeof (struct prefix_ipv4)); - memcpy (&ifaddrclass, &ifaddr, sizeof (struct prefix_ipv4)); - apply_classful_mask_ipv4 (&ifaddrclass); - subnetted = 0; - if (ifaddr.prefixlen > ifaddrclass.prefixlen) - subnetted = 1; - } - - destination = ntohl (rte->prefix.s_addr); - - if (IN_CLASSA (destination)) - masklen2ip (8, &rte->mask); - else if (IN_CLASSB (destination)) - masklen2ip (16, &rte->mask); - else if (IN_CLASSC (destination)) - masklen2ip (24, &rte->mask); - - if (subnetted == 1) - masklen2ip (ifaddrclass.prefixlen, - (struct in_addr *) &destination); - if ((subnetted == 1) && ((rte->prefix.s_addr & destination) == - ifaddrclass.prefix.s_addr)) - { - masklen2ip (ifaddr.prefixlen, &rte->mask); - if ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr) - masklen2ip (32, &rte->mask); - if (IS_RIP_DEBUG_EVENT) - zlog_debug ("Subnetted route %s", inet_ntoa (rte->prefix)); - } - else - { - if ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr) - continue; - } - - if (IS_RIP_DEBUG_EVENT) - { - zlog_debug ("Resultant route %s", inet_ntoa (rte->prefix)); - zlog_debug ("Resultant mask %s", inet_ntoa (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; - } + /* 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((void *)&rte->nexthop, AF_INET, + VRF_DEFAULT)) { + 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_debug( + "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_debug( + "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_debug( + "Next hop %s is not directly reachable. Treat it as 0.0.0.0", + inet_ntoa( + rte->nexthop)); + rte->nexthop.s_addr = 0; + } + } + } - /* 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_debug ("Default route with non-zero netmask. Set zero to netmask"); - rte->mask.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; + + if (subnetted == -1) { + memcpy(&ifaddr, ifc->address, + sizeof(struct prefix_ipv4)); + memcpy(&ifaddrclass, &ifaddr, + sizeof(struct prefix_ipv4)); + apply_classful_mask_ipv4(&ifaddrclass); + subnetted = 0; + if (ifaddr.prefixlen > ifaddrclass.prefixlen) + subnetted = 1; + } + + destination = ntohl(rte->prefix.s_addr); + + if (IN_CLASSA(destination)) + masklen2ip(8, &rte->mask); + else if (IN_CLASSB(destination)) + masklen2ip(16, &rte->mask); + else if (IN_CLASSC(destination)) + masklen2ip(24, &rte->mask); + + if (subnetted == 1) + masklen2ip(ifaddrclass.prefixlen, + (struct in_addr *)&destination); + if ((subnetted == 1) + && ((rte->prefix.s_addr & destination) + == ifaddrclass.prefix.s_addr)) { + masklen2ip(ifaddr.prefixlen, &rte->mask); + if ((rte->prefix.s_addr & rte->mask.s_addr) + != rte->prefix.s_addr) + masklen2ip(32, &rte->mask); + if (IS_RIP_DEBUG_EVENT) + zlog_debug("Subnetted route %s", + inet_ntoa(rte->prefix)); + } else { + if ((rte->prefix.s_addr & rte->mask.s_addr) + != rte->prefix.s_addr) + continue; + } + + if (IS_RIP_DEBUG_EVENT) { + zlog_debug("Resultant route %s", + inet_ntoa(rte->prefix)); + zlog_debug("Resultant mask %s", + inet_ntoa(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_debug( + "Default route with non-zero netmask. Set zero to netmask"); + rte->mask.s_addr = 0; + } + + /* Routing table updates. */ + rip_rte_process(rte, from, ifc->ifp); } - - /* Routing table updates. */ - rip_rte_process (rte, from, ifc->ifp); - } } /* Make socket for RIP protocol. */ -static int -rip_create_socket (void) -{ - int ret; - int sock; - struct sockaddr_in addr; - - memset (&addr, 0, sizeof (struct sockaddr_in)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = INADDR_ANY; +static int rip_create_socket(void) +{ + int ret; + int sock; + struct sockaddr_in addr; + + memset(&addr, 0, sizeof(struct sockaddr_in)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - addr.sin_len = sizeof (struct sockaddr_in); + addr.sin_len = sizeof(struct sockaddr_in); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ - /* sending port must always be the RIP port */ - addr.sin_port = htons (RIP_PORT_DEFAULT); - - /* Make datagram socket. */ - sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (sock < 0) - { - zlog_err("Cannot create UDP socket: %s", safe_strerror(errno)); - exit (1); - } - - sockopt_broadcast (sock); - sockopt_reuseaddr (sock); - sockopt_reuseport (sock); - setsockopt_ipv4_multicast_loop (sock, 0); + /* sending port must always be the RIP port */ + addr.sin_port = htons(RIP_PORT_DEFAULT); + + /* Make datagram socket. */ + sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (sock < 0) { + zlog_err("Cannot create UDP socket: %s", safe_strerror(errno)); + exit(1); + } + + sockopt_broadcast(sock); + sockopt_reuseaddr(sock); + sockopt_reuseport(sock); + setsockopt_ipv4_multicast_loop(sock, 0); #ifdef RIP_RECVMSG - setsockopt_pktinfo (sock); + setsockopt_pktinfo(sock); #endif /* RIP_RECVMSG */ #ifdef IPTOS_PREC_INTERNETCONTROL - setsockopt_ipv4_tos (sock, IPTOS_PREC_INTERNETCONTROL); + setsockopt_ipv4_tos(sock, IPTOS_PREC_INTERNETCONTROL); #endif - if (ripd_privs.change (ZPRIVS_RAISE)) - zlog_err ("rip_create_socket: could not raise privs"); - setsockopt_so_recvbuf (sock, RIP_UDP_RCV_BUF); - if ( (ret = bind (sock, (struct sockaddr *) & addr, sizeof (addr))) < 0) - - { - int save_errno = errno; - if (ripd_privs.change (ZPRIVS_LOWER)) - zlog_err ("rip_create_socket: could not lower privs"); - - zlog_err("%s: Can't bind socket %d to %s port %d: %s", __func__, - sock, inet_ntoa(addr.sin_addr), - (int) ntohs(addr.sin_port), - safe_strerror(save_errno)); - - close (sock); - return ret; - } - - if (ripd_privs.change (ZPRIVS_LOWER)) - zlog_err ("rip_create_socket: could not lower privs"); - - return sock; + if (ripd_privs.change(ZPRIVS_RAISE)) + zlog_err("rip_create_socket: could not raise privs"); + setsockopt_so_recvbuf(sock, RIP_UDP_RCV_BUF); + if ((ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr))) < 0) + + { + int save_errno = errno; + if (ripd_privs.change(ZPRIVS_LOWER)) + zlog_err("rip_create_socket: could not lower privs"); + + zlog_err("%s: Can't bind socket %d to %s port %d: %s", __func__, + sock, inet_ntoa(addr.sin_addr), + (int)ntohs(addr.sin_port), safe_strerror(save_errno)); + + close(sock); + return ret; + } + + if (ripd_privs.change(ZPRIVS_LOWER)) + zlog_err("rip_create_socket: could not lower privs"); + + return sock; } /* RIP packet send to destination address, on interface denoted by * by connected argument. NULL to argument denotes destination should be * should be RIP multicast group */ -static int -rip_send_packet (u_char * buf, int size, struct sockaddr_in *to, - struct connected *ifc) -{ - int ret; - struct sockaddr_in sin; - - assert (ifc != NULL); - - if (IS_RIP_DEBUG_PACKET) - { +static int rip_send_packet(u_char *buf, int size, struct sockaddr_in *to, + struct connected *ifc) +{ + int ret; + struct sockaddr_in sin; + + assert(ifc != NULL); + + if (IS_RIP_DEBUG_PACKET) { #define ADDRESS_SIZE 20 - char dst[ADDRESS_SIZE]; - dst[ADDRESS_SIZE - 1] = '\0'; - - if (to) - { - strncpy (dst, inet_ntoa(to->sin_addr), ADDRESS_SIZE - 1); - } - else - { - sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP); - strncpy (dst, inet_ntoa(sin.sin_addr), ADDRESS_SIZE - 1); - } + char dst[ADDRESS_SIZE]; + dst[ADDRESS_SIZE - 1] = '\0'; + + if (to) { + strncpy(dst, inet_ntoa(to->sin_addr), ADDRESS_SIZE - 1); + } else { + sin.sin_addr.s_addr = htonl(INADDR_RIP_GROUP); + strncpy(dst, inet_ntoa(sin.sin_addr), ADDRESS_SIZE - 1); + } #undef ADDRESS_SIZE - zlog_debug("rip_send_packet %s > %s (%s)", - inet_ntoa(ifc->address->u.prefix4), - dst, ifc->ifp->name); - } - - if ( CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY) ) - { - /* - * ZEBRA_IFA_SECONDARY is set on linux when an interface is configured - * with multiple addresses on the same subnet: the first address - * on the subnet is configured "primary", and all subsequent addresses - * on that subnet are treated as "secondary" addresses. - * In order to avoid routing-table bloat on other rip listeners, - * we do not send out RIP packets with ZEBRA_IFA_SECONDARY source addrs. - * XXX Since Linux is the only system for which the ZEBRA_IFA_SECONDARY - * flag is set, we would end up sending a packet for a "secondary" - * source address on non-linux systems. - */ - if (IS_RIP_DEBUG_PACKET) - zlog_debug("duplicate dropped"); - return 0; - } - - /* Make destination address. */ - memset (&sin, 0, sizeof (struct sockaddr_in)); - sin.sin_family = AF_INET; + zlog_debug("rip_send_packet %s > %s (%s)", + inet_ntoa(ifc->address->u.prefix4), dst, + ifc->ifp->name); + } + + if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY)) { + /* + * ZEBRA_IFA_SECONDARY is set on linux when an interface is + * configured + * with multiple addresses on the same subnet: the first address + * on the subnet is configured "primary", and all subsequent + * addresses + * on that subnet are treated as "secondary" addresses. + * In order to avoid routing-table bloat on other rip listeners, + * we do not send out RIP packets with ZEBRA_IFA_SECONDARY + * source addrs. + * XXX Since Linux is the only system for which the + * ZEBRA_IFA_SECONDARY + * flag is set, we would end up sending a packet for a + * "secondary" + * source address on non-linux systems. + */ + if (IS_RIP_DEBUG_PACKET) + zlog_debug("duplicate dropped"); + return 0; + } + + /* Make destination address. */ + memset(&sin, 0, sizeof(struct sockaddr_in)); + sin.sin_family = AF_INET; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - sin.sin_len = sizeof (struct sockaddr_in); + sin.sin_len = sizeof(struct sockaddr_in); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ - /* When destination is specified, use it's port and address. */ - if (to) - { - sin.sin_port = to->sin_port; - sin.sin_addr = to->sin_addr; - } - else - { - sin.sin_port = htons (RIP_PORT_DEFAULT); - sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP); + /* When destination is specified, use it's port and address. */ + if (to) { + sin.sin_port = to->sin_port; + sin.sin_addr = to->sin_addr; + } else { + sin.sin_port = htons(RIP_PORT_DEFAULT); + sin.sin_addr.s_addr = htonl(INADDR_RIP_GROUP); - rip_interface_multicast_set (rip->sock, ifc); - } + rip_interface_multicast_set(rip->sock, ifc); + } - ret = sendto (rip->sock, buf, size, 0, (struct sockaddr *)&sin, - sizeof (struct sockaddr_in)); + ret = sendto(rip->sock, buf, size, 0, (struct sockaddr *)&sin, + sizeof(struct sockaddr_in)); - if (IS_RIP_DEBUG_EVENT) - zlog_debug ("SEND to %s.%d", inet_ntoa(sin.sin_addr), - ntohs (sin.sin_port)); + if (IS_RIP_DEBUG_EVENT) + zlog_debug("SEND to %s.%d", inet_ntoa(sin.sin_addr), + ntohs(sin.sin_port)); - if (ret < 0) - zlog_warn ("can't send packet : %s", safe_strerror (errno)); + if (ret < 0) + zlog_warn("can't send packet : %s", safe_strerror(errno)); - return ret; + return ret; } /* Add redistributed route to RIP table. */ -void -rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p, - ifindex_t ifindex, struct in_addr *nexthop, - unsigned int metric, unsigned char distance, - route_tag_t tag) -{ - int ret; - struct route_node *rp = NULL; - struct rip_info *rinfo = NULL, newinfo; - struct list *list = NULL; +void rip_redistribute_add(int type, int sub_type, struct prefix_ipv4 *p, + ifindex_t ifindex, struct in_addr *nexthop, + unsigned int metric, unsigned char distance, + route_tag_t tag) +{ + int ret; + struct route_node *rp = NULL; + struct rip_info *rinfo = NULL, newinfo; + struct list *list = NULL; + + /* Redistribute route */ + ret = rip_destination_check(p->prefix); + if (!ret) + return; + + rp = route_node_get(rip->table, (struct prefix *)p); + + memset(&newinfo, 0, sizeof(struct rip_info)); + newinfo.type = type; + newinfo.sub_type = sub_type; + newinfo.ifindex = ifindex; + newinfo.metric = 1; + newinfo.external_metric = metric; + newinfo.distance = distance; + if (tag <= UINT16_MAX) /* RIP only supports 16 bit tags */ + newinfo.tag = tag; + newinfo.rp = rp; + if (nexthop) + newinfo.nexthop = *nexthop; + + if ((list = rp->info) != NULL && listcount(list) != 0) { + rinfo = listgetdata(listhead(list)); + + if (rinfo->type == ZEBRA_ROUTE_CONNECT + && rinfo->sub_type == RIP_ROUTE_INTERFACE + && rinfo->metric != RIP_METRIC_INFINITY) { + route_unlock_node(rp); + return; + } - /* Redistribute route */ - ret = rip_destination_check (p->prefix); - if (! ret) - return; - - rp = route_node_get (rip->table, (struct prefix *) p); - - memset (&newinfo, 0, sizeof (struct rip_info)); - newinfo.type = type; - newinfo.sub_type = sub_type; - newinfo.ifindex = ifindex; - newinfo.metric = 1; - newinfo.external_metric = metric; - newinfo.distance = distance; - if (tag <= UINT16_MAX) /* RIP only supports 16 bit tags */ - newinfo.tag = tag; - newinfo.rp = rp; - if (nexthop) - newinfo.nexthop = *nexthop; - - if ((list = rp->info) != NULL && listcount (list) != 0) - { - rinfo = listgetdata (listhead (list)); - - 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) + || (rinfo->sub_type == RIP_ROUTE_DEFAULT))) { + if (type != ZEBRA_ROUTE_RIP + || ((sub_type != RIP_ROUTE_STATIC) + && (sub_type != RIP_ROUTE_DEFAULT))) { + route_unlock_node(rp); + return; + } + } + + rinfo = rip_ecmp_replace(&newinfo); + route_unlock_node(rp); + } else + rinfo = rip_ecmp_add(&newinfo); + + if (IS_RIP_DEBUG_EVENT) { + if (!nexthop) + zlog_debug( + "Redistribute new prefix %s/%d on the interface %s", + inet_ntoa(p->prefix), p->prefixlen, + ifindex2ifname(ifindex, VRF_DEFAULT)); + else + zlog_debug( + "Redistribute new prefix %s/%d with nexthop %s on the interface %s", + inet_ntoa(p->prefix), p->prefixlen, + inet_ntoa(rinfo->nexthop), + ifindex2ifname(ifindex, VRF_DEFAULT)); } - /* Manually configured RIP route check. */ - if (rinfo->type == ZEBRA_ROUTE_RIP - && ((rinfo->sub_type == RIP_ROUTE_STATIC) || - (rinfo->sub_type == RIP_ROUTE_DEFAULT)) ) - { - if (type != ZEBRA_ROUTE_RIP || ((sub_type != RIP_ROUTE_STATIC) && - (sub_type != RIP_ROUTE_DEFAULT))) - { - route_unlock_node (rp); - return; - } - } - - rinfo = rip_ecmp_replace (&newinfo); - route_unlock_node (rp); - } - else - rinfo = rip_ecmp_add (&newinfo); - - if (IS_RIP_DEBUG_EVENT) { - if (!nexthop) - zlog_debug ("Redistribute new prefix %s/%d on the interface %s", - inet_ntoa(p->prefix), p->prefixlen, - ifindex2ifname(ifindex, VRF_DEFAULT)); - else - zlog_debug ("Redistribute new prefix %s/%d with nexthop %s on the interface %s", - inet_ntoa(p->prefix), p->prefixlen, inet_ntoa(rinfo->nexthop), - ifindex2ifname(ifindex, VRF_DEFAULT)); - } - - rip_event (RIP_TRIGGERED_UPDATE, 0); + 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, - ifindex_t 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) - { - struct list *list = rp->info; - - if (list != NULL && listcount (list) != 0) - { - rinfo = listgetdata (listhead (list)); - 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; - - if (IS_RIP_DEBUG_EVENT) - zlog_debug ("Poisone %s/%d on the interface %s with an " - "infinity metric [delete]", - inet_ntoa(p->prefix), p->prefixlen, - ifindex2ifname(ifindex, VRF_DEFAULT)); - - rip_event (RIP_TRIGGERED_UPDATE, 0); - } - } - route_unlock_node (rp); - } +void rip_redistribute_delete(int type, int sub_type, struct prefix_ipv4 *p, + ifindex_t 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) { + struct list *list = rp->info; + + if (list != NULL && listcount(list) != 0) { + rinfo = listgetdata(listhead(list)); + 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; + + if (IS_RIP_DEBUG_EVENT) + zlog_debug( + "Poisone %s/%d on the interface %s with an " + "infinity metric [delete]", + inet_ntoa(p->prefix), + p->prefixlen, + ifindex2ifname(ifindex, + VRF_DEFAULT)); + + rip_event(RIP_TRIGGERED_UPDATE, 0); + } + } + route_unlock_node(rp); + } } /* Response to request called from rip_read ().*/ -static void -rip_request_process (struct rip_packet *packet, int size, - struct sockaddr_in *from, struct connected *ifc) -{ - caddr_t lim; - struct rte *rte; - struct prefix_ipv4 p; - struct route_node *rp; - struct rip_info *rinfo; - struct rip_interface *ri; - - /* Does not reponse to the requests on the loopback interfaces */ - if (if_is_loopback (ifc->ifp)) - return; - - /* Check RIP process is enabled on this interface. */ - ri = ifc->ifp->info; - if (! ri->running) - return; - - /* 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 (ifc, from, rip_all_route, packet->version); - } - else - { - if (ntohs (rte->family) != AF_INET) - return; +static void rip_request_process(struct rip_packet *packet, int size, + struct sockaddr_in *from, struct connected *ifc) +{ + caddr_t lim; + struct rte *rte; + struct prefix_ipv4 p; + struct route_node *rp; + struct rip_info *rinfo; + struct rip_interface *ri; + + /* Does not reponse to the requests on the loopback interfaces */ + if (if_is_loopback(ifc->ifp)) + return; + + /* Check RIP process is enabled on this interface. */ + ri = ifc->ifp->info; + if (!ri->running) + return; + + /* 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(ifc, from, rip_all_route, packet->version); + } else { + if (ntohs(rte->family) != AF_INET) + return; + + /* 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 = listgetdata( + listhead((struct list *)rp->info)); + rte->metric = htonl(rinfo->metric); + route_unlock_node(rp); + } else + rte->metric = htonl(RIP_METRIC_INFINITY); + } + packet->command = RIP_RESPONSE; - /* 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 = listgetdata (listhead ((struct list *)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 ((u_char *)packet, size, from, ifc); - } - rip_global_queries++; + rip_send_packet((u_char *)packet, size, from, ifc); + } + rip_global_queries++; } #if RIP_RECVMSG /* Set IPv6 packet info to the socket. */ -static int -setsockopt_pktinfo (int sock) +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", safe_strerror (errno)); - return ret; + 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", + safe_strerror(errno)); + return ret; } /* Read RIP packet by recvmsg function. */ -int -rip_recvmsg (int sock, u_char *buf, int size, struct sockaddr_in *from, - ifindex_t *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 = ZCMSG_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; +int rip_recvmsg(int sock, u_char *buf, int size, struct sockaddr_in *from, + ifindex_t *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; - pktinfo = (struct in_pktinfo *) CMSG_DATA (ptr); - i = pktinfo->ipi_ifindex; - } - return ret; + for (ptr = ZCMSG_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; - ifindex_t 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", safe_strerror (errno)); - return ret; - } - - return ret; +int rip_read_new(struct thread *t) +{ + int ret; + int sock; + char buf[RIP_PACKET_MAXSIZ]; + struct sockaddr_in from; + ifindex_t 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", safe_strerror(errno)); + return ret; + } + + return ret; } #endif /* RIP_RECVMSG */ /* First entry point of RIP packet. */ -static 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 len; - int vrecv; - socklen_t fromlen; - struct interface *ifp = NULL; - struct connected *ifc; - struct rip_interface *ri; - struct prefix p; - - /* 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", safe_strerror (errno)); - return len; - } - - /* Check is this packet comming from myself? */ - if (if_check_address (from.sin_addr)) - { - if (IS_RIP_DEBUG_PACKET) - zlog_debug ("ignore packet comes from myself"); - return -1; - } - - /* Which interface is this packet comes from. */ - ifc = if_lookup_address ((void *)&from.sin_addr, AF_INET, VRF_DEFAULT); - if (ifc) - ifp = ifc->ifp; - - /* RIP packet received */ - if (IS_RIP_DEBUG_EVENT) - zlog_debug ("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 ("rip_read: cannot find interface for packet from %s port %d", - inet_ntoa(from.sin_addr), ntohs (from.sin_port)); - return -1; - } - - p.family = AF_INET; - p.u.prefix4 = from.sin_addr; - p.prefixlen = IPV4_MAX_BITLEN; - - ifc = connected_lookup_prefix (ifp, &p); - - if (ifc == NULL) - { - zlog_info ("rip_read: cannot find connected address for packet from %s " - "port %d on interface %s", - inet_ntoa(from.sin_addr), ntohs (from.sin_port), ifp->name); - 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_debug ("RIP is not enabled on interface %s.", ifp->name); - rip_peer_bad_packet (&from); - return -1; - } - - /* RIP Version check. RFC2453, 4.6 and 5.1 */ - vrecv = ((ri->ri_receive == RI_RIP_UNSPEC) ? - rip->version_recv : ri->ri_receive); - if (vrecv == RI_RIP_VERSION_NONE || - ((packet->version == RIPv1) && !(vrecv & RIPv1)) || - ((packet->version == RIPv2) && !(vrecv & RIPv2))) - { - if (IS_RIP_DEBUG_PACKET) - zlog_debug (" 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 == htons(RIP_FAMILY_AUTH))) - { - if (IS_RIP_DEBUG_EVENT) - zlog_debug ("packet RIPv%d is dropped because authentication disabled", - packet->version); - rip_peer_bad_packet (&from); - return -1; - } - - /* RFC: - 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. - */ - /* We make an exception for RIPv1 REQUEST packets, to which we'll - * always reply regardless of authentication settings, because: - * - * - if there other authorised routers on-link, the REQUESTor can - * passively obtain the routing updates anyway - * - if there are no other authorised routers on-link, RIP can - * easily be disabled for the link to prevent giving out information - * on state of this routers RIP routing table.. - * - * I.e. if RIPv1 has any place anymore these days, it's as a very - * simple way to distribute routing information (e.g. to embedded - * hosts / appliances) and the ability to give out RIPv1 - * routing-information freely, while still requiring RIPv2 - * authentication for any RESPONSEs might be vaguely useful. - */ - if (ri->auth_type != RIP_NO_AUTH - && packet->version == RIPv1) - { - /* Discard RIPv1 messages other than REQUESTs */ - if (packet->command != RIP_REQUEST) - { - if (IS_RIP_DEBUG_PACKET) - zlog_debug ("RIPv1" " dropped because authentication enabled"); - rip_peer_bad_packet (&from); - return -1; - } - } - else if (ri->auth_type != RIP_NO_AUTH) - { - const char *auth_desc; - - if (rtenum == 0) - { - /* There definitely is no authentication in the packet. */ - if (IS_RIP_DEBUG_PACKET) - zlog_debug ("RIPv2 authentication failed: no auth RTE in packet"); - rip_peer_bad_packet (&from); - return -1; - } - - /* First RTE must be an Authentication Family RTE */ - if (packet->rte->family != htons(RIP_FAMILY_AUTH)) - { - if (IS_RIP_DEBUG_PACKET) - zlog_debug ("RIPv2" " dropped because authentication enabled"); - rip_peer_bad_packet (&from); - return -1; - } - - /* Check RIPv2 authentication. */ - switch (ntohs(packet->rte->tag)) - { - case RIP_AUTH_SIMPLE_PASSWORD: - auth_desc = "simple"; - ret = rip_auth_simple_password (packet->rte, &from, ifp); - break; - - case RIP_AUTH_MD5: - auth_desc = "MD5"; - ret = rip_auth_md5 (packet, &from, len, ifp); - /* Reset RIP packet length to trim MD5 data. */ - len = ret; - break; - - default: - ret = 0; - auth_desc = "unknown type"; - if (IS_RIP_DEBUG_PACKET) - zlog_debug ("RIPv2 Unknown authentication type %d", - ntohs (packet->rte->tag)); - } - - if (ret) - { - if (IS_RIP_DEBUG_PACKET) - zlog_debug ("RIPv2 %s authentication success", auth_desc); - } - else - { - if (IS_RIP_DEBUG_PACKET) - zlog_debug ("RIPv2 %s authentication failure", auth_desc); - rip_peer_bad_packet (&from); - return -1; - } - } - - /* Process each command. */ - switch (packet->command) - { - case RIP_RESPONSE: - rip_response_process (packet, len, &from, ifc); - break; - case RIP_REQUEST: - case RIP_POLL: - rip_request_process (packet, len, &from, ifc); - break; - case RIP_TRACEON: - case RIP_TRACEOFF: - zlog_info ("Obsolete command %s received, please sent it to routed", - lookup_msg (rip_msg, packet->command, NULL)); - rip_peer_bad_packet (&from); - break; - case RIP_POLL_ENTRY: - zlog_info ("Obsolete command %s received", - lookup_msg (rip_msg, packet->command, NULL)); - rip_peer_bad_packet (&from); - break; - default: - zlog_info ("Unknown RIP command %d received", packet->command); - rip_peer_bad_packet (&from); - break; - } - - return len; +static 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 len; + int vrecv; + socklen_t fromlen; + struct interface *ifp = NULL; + struct connected *ifc; + struct rip_interface *ri; + struct prefix p; + + /* 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", safe_strerror(errno)); + return len; + } + + /* Check is this packet comming from myself? */ + if (if_check_address(from.sin_addr)) { + if (IS_RIP_DEBUG_PACKET) + zlog_debug("ignore packet comes from myself"); + return -1; + } + + /* Which interface is this packet comes from. */ + ifc = if_lookup_address((void *)&from.sin_addr, AF_INET, VRF_DEFAULT); + if (ifc) + ifp = ifc->ifp; + + /* RIP packet received */ + if (IS_RIP_DEBUG_EVENT) + zlog_debug("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( + "rip_read: cannot find interface for packet from %s port %d", + inet_ntoa(from.sin_addr), ntohs(from.sin_port)); + return -1; + } + + p.family = AF_INET; + p.u.prefix4 = from.sin_addr; + p.prefixlen = IPV4_MAX_BITLEN; + + ifc = connected_lookup_prefix(ifp, &p); + + if (ifc == NULL) { + zlog_info( + "rip_read: cannot find connected address for packet from %s " + "port %d on interface %s", + inet_ntoa(from.sin_addr), ntohs(from.sin_port), + ifp->name); + 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_debug("RIP is not enabled on interface %s.", + ifp->name); + rip_peer_bad_packet(&from); + return -1; + } + + /* RIP Version check. RFC2453, 4.6 and 5.1 */ + vrecv = ((ri->ri_receive == RI_RIP_UNSPEC) ? rip->version_recv + : ri->ri_receive); + if (vrecv == RI_RIP_VERSION_NONE + || ((packet->version == RIPv1) && !(vrecv & RIPv1)) + || ((packet->version == RIPv2) && !(vrecv & RIPv2))) { + if (IS_RIP_DEBUG_PACKET) + zlog_debug( + " 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 == htons(RIP_FAMILY_AUTH))) { + if (IS_RIP_DEBUG_EVENT) + zlog_debug( + "packet RIPv%d is dropped because authentication disabled", + packet->version); + rip_peer_bad_packet(&from); + return -1; + } + + /* RFC: + 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. + */ + /* We make an exception for RIPv1 REQUEST packets, to which we'll + * always reply regardless of authentication settings, because: + * + * - if there other authorised routers on-link, the REQUESTor can + * passively obtain the routing updates anyway + * - if there are no other authorised routers on-link, RIP can + * easily be disabled for the link to prevent giving out information + * on state of this routers RIP routing table.. + * + * I.e. if RIPv1 has any place anymore these days, it's as a very + * simple way to distribute routing information (e.g. to embedded + * hosts / appliances) and the ability to give out RIPv1 + * routing-information freely, while still requiring RIPv2 + * authentication for any RESPONSEs might be vaguely useful. + */ + if (ri->auth_type != RIP_NO_AUTH && packet->version == RIPv1) { + /* Discard RIPv1 messages other than REQUESTs */ + if (packet->command != RIP_REQUEST) { + if (IS_RIP_DEBUG_PACKET) + zlog_debug( + "RIPv1" + " dropped because authentication enabled"); + rip_peer_bad_packet(&from); + return -1; + } + } else if (ri->auth_type != RIP_NO_AUTH) { + const char *auth_desc; + + if (rtenum == 0) { + /* There definitely is no authentication in the packet. + */ + if (IS_RIP_DEBUG_PACKET) + zlog_debug( + "RIPv2 authentication failed: no auth RTE in packet"); + rip_peer_bad_packet(&from); + return -1; + } + + /* First RTE must be an Authentication Family RTE */ + if (packet->rte->family != htons(RIP_FAMILY_AUTH)) { + if (IS_RIP_DEBUG_PACKET) + zlog_debug( + "RIPv2" + " dropped because authentication enabled"); + rip_peer_bad_packet(&from); + return -1; + } + + /* Check RIPv2 authentication. */ + switch (ntohs(packet->rte->tag)) { + case RIP_AUTH_SIMPLE_PASSWORD: + auth_desc = "simple"; + ret = rip_auth_simple_password(packet->rte, &from, ifp); + break; + + case RIP_AUTH_MD5: + auth_desc = "MD5"; + ret = rip_auth_md5(packet, &from, len, ifp); + /* Reset RIP packet length to trim MD5 data. */ + len = ret; + break; + + default: + ret = 0; + auth_desc = "unknown type"; + if (IS_RIP_DEBUG_PACKET) + zlog_debug( + "RIPv2 Unknown authentication type %d", + ntohs(packet->rte->tag)); + } + + if (ret) { + if (IS_RIP_DEBUG_PACKET) + zlog_debug("RIPv2 %s authentication success", + auth_desc); + } else { + if (IS_RIP_DEBUG_PACKET) + zlog_debug("RIPv2 %s authentication failure", + auth_desc); + rip_peer_bad_packet(&from); + return -1; + } + } + + /* Process each command. */ + switch (packet->command) { + case RIP_RESPONSE: + rip_response_process(packet, len, &from, ifc); + break; + case RIP_REQUEST: + case RIP_POLL: + rip_request_process(packet, len, &from, ifc); + break; + case RIP_TRACEON: + case RIP_TRACEOFF: + zlog_info( + "Obsolete command %s received, please sent it to routed", + lookup_msg(rip_msg, packet->command, NULL)); + rip_peer_bad_packet(&from); + break; + case RIP_POLL_ENTRY: + zlog_info("Obsolete command %s received", + lookup_msg(rip_msg, packet->command, NULL)); + rip_peer_bad_packet(&from); + break; + default: + zlog_info("Unknown RIP command %d received", packet->command); + rip_peer_bad_packet(&from); + break; + } + + return len; } /* Write routing table entry to the stream and return next index of the routing table entry in the stream. */ -static int -rip_write_rte (int num, struct stream *s, struct prefix_ipv4 *p, - u_char version, struct rip_info *rinfo) -{ - struct in_addr mask; - - /* 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_out); - 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; +static int rip_write_rte(int num, struct stream *s, struct prefix_ipv4 *p, + u_char version, struct rip_info *rinfo) +{ + struct in_addr mask; + + /* 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_out); + 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 connected *ifc, 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; - struct prefix_ipv4 ifaddrclass; - struct key *key = NULL; - /* this might need to made dynamic if RIP ever supported auth methods - with larger key string sizes */ - char auth_str[RIP_AUTH_SIMPLE_SIZE]; - size_t doff = 0; /* offset of digest offset field */ - int num = 0; - int rtemax; - int subnetted = 0; - struct list *list = NULL; - struct listnode *listnode = NULL; +void rip_output_process(struct connected *ifc, 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; + struct prefix_ipv4 ifaddrclass; + struct key *key = NULL; + /* this might need to made dynamic if RIP ever supported auth methods + with larger key string sizes */ + char auth_str[RIP_AUTH_SIMPLE_SIZE]; + size_t doff = 0; /* offset of digest offset field */ + int num = 0; + int rtemax; + int subnetted = 0; + struct list *list = NULL; + struct listnode *listnode = NULL; + + /* Logging output event. */ + if (IS_RIP_DEBUG_EVENT) { + if (to) + zlog_debug("update routes to neighbor %s", + inet_ntoa(to->sin_addr)); + else + zlog_debug("update routes on interface %s ifindex %d", + ifc->ifp->name, ifc->ifp->ifindex); + } - /* Logging output event. */ - if (IS_RIP_DEBUG_EVENT) - { - if (to) - zlog_debug ("update routes to neighbor %s", inet_ntoa (to->sin_addr)); - else - zlog_debug ("update routes on interface %s ifindex %d", - ifc->ifp->name, ifc->ifp->ifindex); - } - - /* Set output stream. */ - s = rip->obuf; - - /* Reset stream and RTE counter. */ - stream_reset (s); - rtemax = RIP_MAX_RTE; - - /* Get RIP interface. */ - ri = ifc->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_NO_AUTH) - { - if (ri->key_chain) - { - struct keychain *keychain; - - keychain = keychain_lookup (ri->key_chain); - if (keychain) - key = key_lookup_for_send (keychain); - } - /* to be passed to auth functions later */ - rip_auth_prepare_str_send (ri, key, auth_str, RIP_AUTH_SIMPLE_SIZE); - } - - if (version == RIPv1) - { - memcpy (&ifaddrclass, ifc->address, sizeof (struct prefix_ipv4)); - apply_classful_mask_ipv4 (&ifaddrclass); - subnetted = 0; - if (ifc->address->prefixlen > ifaddrclass.prefixlen) - subnetted = 1; - } - - for (rp = route_top (rip->table); rp; rp = route_next (rp)) - if ((list = rp->info) != NULL && listcount (list) != 0) - { - rinfo = listgetdata (listhead (list)); - /* For RIPv1, if we are subnetted, output subnets in our network */ - /* that have the same mask as the output "interface". For other */ - /* networks, only the classfull version is output. */ - - if (version == RIPv1) - { - p = (struct prefix_ipv4 *) &rp->p; - - if (IS_RIP_DEBUG_PACKET) - zlog_debug("RIPv1 mask check, %s/%d considered for output", - inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen); - - if (subnetted && - prefix_match ((struct prefix *) &ifaddrclass, &rp->p)) - { - if ((ifc->address->prefixlen != rp->p.prefixlen) && - (rp->p.prefixlen != 32)) - continue; - } - else - { - memcpy (&classfull, &rp->p, sizeof(struct prefix_ipv4)); - apply_classful_mask_ipv4(&classfull); - if (rp->p.u.prefix4.s_addr != 0 && - classfull.prefixlen != rp->p.prefixlen) - continue; - } - if (IS_RIP_DEBUG_PACKET) - zlog_debug("RIPv1 mask check, %s/%d made it through", - inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen); - } - else - p = (struct prefix_ipv4 *) &rp->p; - - /* Apply output filters. */ - ret = rip_filter (RIP_FILTER_OUT, 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 == RIP_SPLIT_HORIZON) - { - /* - * We perform split horizon for RIP and connected route. - * For rip routes, we want to suppress the route if we would - * end up sending the route back on the interface that we - * learned it from, with a higher metric. For connected routes, - * we suppress the route if the prefix is a subset of the - * source address that we are going to use for the packet - * (in order to handle the case when multiple subnets are - * configured on the same interface). - */ - int suppress = 0; - struct rip_info *tmp_rinfo = NULL; - - for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo)) - if (tmp_rinfo->type == ZEBRA_ROUTE_RIP && - tmp_rinfo->ifindex == ifc->ifp->ifindex) - { - suppress = 1; - break; - } - - if (!suppress && rinfo->type == ZEBRA_ROUTE_CONNECT && - prefix_match((struct prefix *)p, ifc->address)) - suppress = 1; - - if (suppress) - continue; - } - - /* Preparation for route-map. */ - rinfo->metric_set = 0; - rinfo->nexthop_out.s_addr = 0; - rinfo->metric_out = rinfo->metric; - rinfo->tag_out = rinfo->tag; - rinfo->ifindex_out = ifc->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. - * see (4.4) - */ - if (rinfo->ifindex == ifc->ifp->ifindex) - rinfo->nexthop_out = rinfo->nexthop; - - /* Interface route-map */ - if (ri->routemap[RIP_FILTER_OUT]) - { - ret = route_map_apply (ri->routemap[RIP_FILTER_OUT], - (struct prefix *) p, RMAP_RIP, - rinfo); - - if (ret == RMAP_DENYMATCH) - { - if (IS_RIP_DEBUG_PACKET) - zlog_debug ("RIP %s/%d is filtered by route-map out", - inet_ntoa (p->prefix), p->prefixlen); - continue; - } - } - - /* Apply redistribute 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_debug ("%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, ifc->ifp, &rinfo->metric_out); - - if (rinfo->metric_out > RIP_METRIC_INFINITY) - rinfo->metric_out = RIP_METRIC_INFINITY; - - /* Perform split-horizon with poisoned reverse - * for RIP and connected routes. - **/ - if (ri->split_horizon == RIP_SPLIT_HORIZON_POISONED_REVERSE) { - /* - * We perform split horizon for RIP and connected route. - * For rip routes, we want to suppress the route if we would - * end up sending the route back on the interface that we - * learned it from, with a higher metric. For connected routes, - * we suppress the route if the prefix is a subset of the - * source address that we are going to use for the packet - * (in order to handle the case when multiple subnets are - * configured on the same interface). - */ - struct rip_info *tmp_rinfo = NULL; - - for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo)) - if (tmp_rinfo->type == ZEBRA_ROUTE_RIP && - tmp_rinfo->ifindex == ifc->ifp->ifindex) - rinfo->metric_out = RIP_METRIC_INFINITY; - if (tmp_rinfo->type == ZEBRA_ROUTE_CONNECT && - prefix_match((struct prefix *)p, ifc->address)) - rinfo->metric_out = RIP_METRIC_INFINITY; - } - - /* Prepare preamble, auth headers, if needs be */ - if (num == 0) - { - stream_putc (s, RIP_RESPONSE); - stream_putc (s, version); - stream_putw (s, 0); - - /* auth header for !v1 && !no_auth */ - if ( (ri->auth_type != RIP_NO_AUTH) && (version != RIPv1) ) - doff = rip_auth_header_write (s, ri, key, auth_str, - RIP_AUTH_SIMPLE_SIZE); - } - - /* Write RTE to the stream. */ - num = rip_write_rte (num, s, p, version, rinfo); - if (num == rtemax) - { - if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5) - rip_auth_md5_set (s, ri, doff, auth_str, RIP_AUTH_SIMPLE_SIZE); - - ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s), - to, ifc); - - 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, ri, doff, auth_str, RIP_AUTH_SIMPLE_SIZE); - - ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s), to, ifc); - - if (ret >= 0 && IS_RIP_DEBUG_SEND) - rip_packet_dump ((struct rip_packet *)STREAM_DATA (s), - stream_get_endp (s), "SEND"); - stream_reset (s); - } - - /* Statistics updates. */ - ri->sent_updates++; + /* Set output stream. */ + s = rip->obuf; + + /* Reset stream and RTE counter. */ + stream_reset(s); + rtemax = RIP_MAX_RTE; + + /* Get RIP interface. */ + ri = ifc->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_NO_AUTH) { + if (ri->key_chain) { + struct keychain *keychain; + + keychain = keychain_lookup(ri->key_chain); + if (keychain) + key = key_lookup_for_send(keychain); + } + /* to be passed to auth functions later */ + rip_auth_prepare_str_send(ri, key, auth_str, + RIP_AUTH_SIMPLE_SIZE); + } + + if (version == RIPv1) { + memcpy(&ifaddrclass, ifc->address, sizeof(struct prefix_ipv4)); + apply_classful_mask_ipv4(&ifaddrclass); + subnetted = 0; + if (ifc->address->prefixlen > ifaddrclass.prefixlen) + subnetted = 1; + } + + for (rp = route_top(rip->table); rp; rp = route_next(rp)) + if ((list = rp->info) != NULL && listcount(list) != 0) { + rinfo = listgetdata(listhead(list)); + /* For RIPv1, if we are subnetted, output subnets in our + * network */ + /* that have the same mask as the output "interface". + * For other */ + /* networks, only the classfull version is output. */ + + if (version == RIPv1) { + p = (struct prefix_ipv4 *)&rp->p; + + if (IS_RIP_DEBUG_PACKET) + zlog_debug( + "RIPv1 mask check, %s/%d considered for output", + inet_ntoa(rp->p.u.prefix4), + rp->p.prefixlen); + + if (subnetted + && prefix_match( + (struct prefix *)&ifaddrclass, + &rp->p)) { + if ((ifc->address->prefixlen + != rp->p.prefixlen) + && (rp->p.prefixlen != 32)) + continue; + } else { + memcpy(&classfull, &rp->p, + sizeof(struct prefix_ipv4)); + apply_classful_mask_ipv4(&classfull); + if (rp->p.u.prefix4.s_addr != 0 + && classfull.prefixlen + != rp->p.prefixlen) + continue; + } + if (IS_RIP_DEBUG_PACKET) + zlog_debug( + "RIPv1 mask check, %s/%d made it through", + inet_ntoa(rp->p.u.prefix4), + rp->p.prefixlen); + } else + p = (struct prefix_ipv4 *)&rp->p; + + /* Apply output filters. */ + ret = rip_filter(RIP_FILTER_OUT, 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 == RIP_SPLIT_HORIZON) { + /* + * We perform split horizon for RIP and + * connected route. + * For rip routes, we want to suppress the route + * if we would + * end up sending the route back on the + * interface that we + * learned it from, with a higher metric. For + * connected routes, + * we suppress the route if the prefix is a + * subset of the + * source address that we are going to use for + * the packet + * (in order to handle the case when multiple + * subnets are + * configured on the same interface). + */ + int suppress = 0; + struct rip_info *tmp_rinfo = NULL; + + for (ALL_LIST_ELEMENTS_RO(list, listnode, + tmp_rinfo)) + if (tmp_rinfo->type == ZEBRA_ROUTE_RIP + && tmp_rinfo->ifindex + == ifc->ifp->ifindex) { + suppress = 1; + break; + } + + if (!suppress + && rinfo->type == ZEBRA_ROUTE_CONNECT + && prefix_match((struct prefix *)p, + ifc->address)) + suppress = 1; + + if (suppress) + continue; + } + + /* Preparation for route-map. */ + rinfo->metric_set = 0; + rinfo->nexthop_out.s_addr = 0; + rinfo->metric_out = rinfo->metric; + rinfo->tag_out = rinfo->tag; + rinfo->ifindex_out = ifc->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. + * see (4.4) + */ + if (rinfo->ifindex == ifc->ifp->ifindex) + rinfo->nexthop_out = rinfo->nexthop; + + /* Interface route-map */ + if (ri->routemap[RIP_FILTER_OUT]) { + ret = route_map_apply( + ri->routemap[RIP_FILTER_OUT], + (struct prefix *)p, RMAP_RIP, rinfo); + + if (ret == RMAP_DENYMATCH) { + if (IS_RIP_DEBUG_PACKET) + zlog_debug( + "RIP %s/%d is filtered by route-map out", + inet_ntoa(p->prefix), + p->prefixlen); + continue; + } + } + + /* Apply redistribute 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_debug( + "%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, ifc->ifp, + &rinfo->metric_out); + + if (rinfo->metric_out > RIP_METRIC_INFINITY) + rinfo->metric_out = RIP_METRIC_INFINITY; + + /* Perform split-horizon with poisoned reverse + * for RIP and connected routes. + **/ + if (ri->split_horizon + == RIP_SPLIT_HORIZON_POISONED_REVERSE) { + /* + * We perform split horizon for RIP and + * connected route. + * For rip routes, we want to suppress the route + * if we would + * end up sending the route back on the + * interface that we + * learned it from, with a higher metric. For + * connected routes, + * we suppress the route if the prefix is a + * subset of the + * source address that we are going to use for + * the packet + * (in order to handle the case when multiple + * subnets are + * configured on the same interface). + */ + struct rip_info *tmp_rinfo = NULL; + + for (ALL_LIST_ELEMENTS_RO(list, listnode, + tmp_rinfo)) + if (tmp_rinfo->type == ZEBRA_ROUTE_RIP + && tmp_rinfo->ifindex + == ifc->ifp->ifindex) + rinfo->metric_out = + RIP_METRIC_INFINITY; + if (tmp_rinfo->type == ZEBRA_ROUTE_CONNECT + && prefix_match((struct prefix *)p, + ifc->address)) + rinfo->metric_out = RIP_METRIC_INFINITY; + } + + /* Prepare preamble, auth headers, if needs be */ + if (num == 0) { + stream_putc(s, RIP_RESPONSE); + stream_putc(s, version); + stream_putw(s, 0); + + /* auth header for !v1 && !no_auth */ + if ((ri->auth_type != RIP_NO_AUTH) + && (version != RIPv1)) + doff = rip_auth_header_write( + s, ri, key, auth_str, + RIP_AUTH_SIMPLE_SIZE); + } + + /* Write RTE to the stream. */ + num = rip_write_rte(num, s, p, version, rinfo); + if (num == rtemax) { + if (version == RIPv2 + && ri->auth_type == RIP_AUTH_MD5) + rip_auth_md5_set(s, ri, doff, auth_str, + RIP_AUTH_SIMPLE_SIZE); + + ret = rip_send_packet(STREAM_DATA(s), + stream_get_endp(s), to, + ifc); + + 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, ri, doff, auth_str, + RIP_AUTH_SIMPLE_SIZE); + + ret = rip_send_packet(STREAM_DATA(s), stream_get_endp(s), to, + ifc); + + if (ret >= 0 && IS_RIP_DEBUG_SEND) + rip_packet_dump((struct rip_packet *)STREAM_DATA(s), + stream_get_endp(s), "SEND"); + stream_reset(s); + } + + /* Statistics updates. */ + ri->sent_updates++; } /* Send RIP packet to the interface. */ -static void -rip_update_interface (struct connected *ifc, u_char version, int route_type) -{ - struct interface *ifp = ifc->ifp; - struct rip_interface *ri = ifp->info; - struct sockaddr_in to; - - /* When RIP version is 2 and multicast enable interface. */ - if (version == RIPv2 && !ri->v2_broadcast && if_is_multicast (ifp)) - { - if (IS_RIP_DEBUG_EVENT) - zlog_debug ("multicast announce on %s ", ifp->name); - - rip_output_process (ifc, 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)) - { - if (ifc->address->family == AF_INET) - { - /* Destination address and port setting. */ - memset (&to, 0, sizeof (struct sockaddr_in)); - if (ifc->destination) - /* use specified broadcast or peer destination addr */ - to.sin_addr = ifc->destination->u.prefix4; - else if (ifc->address->prefixlen < IPV4_MAX_PREFIXLEN) - /* calculate the appropriate broadcast address */ - to.sin_addr.s_addr = - ipv4_broadcast_addr(ifc->address->u.prefix4.s_addr, - ifc->address->prefixlen); - else - /* do not know where to send the packet */ - return; - to.sin_port = htons (RIP_PORT_DEFAULT); - - if (IS_RIP_DEBUG_EVENT) - zlog_debug("%s announce to %s on %s", - CONNECTED_PEER(ifc) ? "unicast" : "broadcast", - inet_ntoa (to.sin_addr), ifp->name); - - rip_output_process (ifc, &to, route_type, version); - } - } +static void rip_update_interface(struct connected *ifc, u_char version, + int route_type) +{ + struct interface *ifp = ifc->ifp; + struct rip_interface *ri = ifp->info; + struct sockaddr_in to; + + /* When RIP version is 2 and multicast enable interface. */ + if (version == RIPv2 && !ri->v2_broadcast && if_is_multicast(ifp)) { + if (IS_RIP_DEBUG_EVENT) + zlog_debug("multicast announce on %s ", ifp->name); + + rip_output_process(ifc, 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)) { + if (ifc->address->family == AF_INET) { + /* Destination address and port setting. */ + memset(&to, 0, sizeof(struct sockaddr_in)); + if (ifc->destination) + /* use specified broadcast or peer destination + * addr */ + to.sin_addr = ifc->destination->u.prefix4; + else if (ifc->address->prefixlen < IPV4_MAX_PREFIXLEN) + /* calculate the appropriate broadcast address + */ + to.sin_addr.s_addr = ipv4_broadcast_addr( + ifc->address->u.prefix4.s_addr, + ifc->address->prefixlen); + else + /* do not know where to send the packet */ + return; + to.sin_port = htons(RIP_PORT_DEFAULT); + + if (IS_RIP_DEBUG_EVENT) + zlog_debug("%s announce to %s on %s", + CONNECTED_PEER(ifc) ? "unicast" + : "broadcast", + inet_ntoa(to.sin_addr), ifp->name); + + rip_output_process(ifc, &to, route_type, version); + } + } } /* Update send to all interface and neighbor. */ -static void -rip_update_process (int route_type) -{ - struct listnode *node; - struct listnode *ifnode, *ifnnode; - struct connected *connected; - struct interface *ifp; - struct rip_interface *ri; - struct route_node *rp; - struct sockaddr_in to; - struct prefix *p; - - /* Send RIP update to each interface. */ - for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp)) - { - if (if_is_loopback (ifp)) - continue; - - if (! if_is_operative (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 there is no version configuration in the interface, - * use rip's version setting. - */ - int vsend = ((ri->ri_send == RI_RIP_UNSPEC) ? - rip->version_send : ri->ri_send); - - if (IS_RIP_DEBUG_EVENT) - zlog_debug("SEND UPDATE to %s ifindex %d", - ifp->name, ifp->ifindex); - - /* send update on each connected network */ - for (ALL_LIST_ELEMENTS (ifp->connected, ifnode, ifnnode, connected)) - { - if (connected->address->family == AF_INET) - { - if (vsend & RIPv1) - rip_update_interface (connected, RIPv1, route_type); - if ((vsend & RIPv2) && if_is_multicast(ifp)) - rip_update_interface (connected, RIPv2, route_type); +static void rip_update_process(int route_type) +{ + struct listnode *node; + struct listnode *ifnode, *ifnnode; + struct connected *connected; + struct interface *ifp; + struct rip_interface *ri; + struct route_node *rp; + struct sockaddr_in to; + struct prefix *p; + + /* Send RIP update to each interface. */ + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) { + if (if_is_loopback(ifp)) + continue; + + if (!if_is_operative(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 there is no version configuration in the + * interface, + * use rip's version setting. + */ + int vsend = ((ri->ri_send == RI_RIP_UNSPEC) + ? rip->version_send + : ri->ri_send); + + if (IS_RIP_DEBUG_EVENT) + zlog_debug("SEND UPDATE to %s ifindex %d", + ifp->name, ifp->ifindex); + + /* send update on each connected network */ + for (ALL_LIST_ELEMENTS(ifp->connected, ifnode, ifnnode, + connected)) { + if (connected->address->family == AF_INET) { + if (vsend & RIPv1) + rip_update_interface( + connected, RIPv1, + route_type); + if ((vsend & RIPv2) + && if_is_multicast(ifp)) + rip_update_interface( + connected, 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 = &rp->p; + + connected = if_lookup_address(&p->u.prefix4, AF_INET, + VRF_DEFAULT); + if (!connected) { + zlog_warn( + "Neighbor %s doesnt have connected interface!", + inet_ntoa(p->u.prefix4)); + continue; + } + + /* Set destination address and port */ + memset(&to, 0, sizeof(struct sockaddr_in)); + to.sin_addr = p->u.prefix4; + to.sin_port = htons(RIP_PORT_DEFAULT); + + /* RIP version is rip's configuration. */ + rip_output_process(connected, &to, route_type, + rip->version_send); } - } - } - } - - /* RIP send updates to each neighbor. */ - for (rp = route_top (rip->neighbor); rp; rp = route_next (rp)) - if (rp->info != NULL) - { - p = &rp->p; - - connected = if_lookup_address (&p->u.prefix4, AF_INET, VRF_DEFAULT); - if (! connected) - { - zlog_warn ("Neighbor %s doesnt have connected interface!", - inet_ntoa (p->u.prefix4)); - continue; - } - - /* Set destination address and port */ - memset (&to, 0, sizeof (struct sockaddr_in)); - to.sin_addr = p->u.prefix4; - to.sin_port = htons (RIP_PORT_DEFAULT); - - /* RIP version is rip's configuration. */ - rip_output_process (connected, &to, route_type, rip->version_send); - } } /* RIP's periodical timer. */ -static int -rip_update (struct thread *t) +static int rip_update(struct thread *t) { - /* Clear timer pointer. */ - rip->t_update = NULL; + /* Clear timer pointer. */ + rip->t_update = NULL; - if (IS_RIP_DEBUG_EVENT) - zlog_debug ("update timer fire!"); + if (IS_RIP_DEBUG_EVENT) + zlog_debug("update timer fire!"); - /* Process update output. */ - rip_update_process (rip_all_route); + /* 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. */ - RIP_TIMER_OFF (rip->t_triggered_interval); - rip->trigger = 0; + /* Triggered updates may be suppressed if a regular update is due by + the time the triggered update would be sent. */ + RIP_TIMER_OFF(rip->t_triggered_interval); + rip->trigger = 0; - /* Register myself. */ - rip_event (RIP_UPDATE_EVENT, 0); + /* Register myself. */ + rip_event(RIP_UPDATE_EVENT, 0); - return 0; + return 0; } /* Walk down the RIP routing table then clear changed flag. */ -static void -rip_clear_changed_flag (void) +static void rip_clear_changed_flag(void) { - struct route_node *rp; - struct rip_info *rinfo = NULL; - struct list *list = NULL; - struct listnode *listnode = NULL; + struct route_node *rp; + struct rip_info *rinfo = NULL; + struct list *list = NULL; + struct listnode *listnode = NULL; - for (rp = route_top (rip->table); rp; rp = route_next (rp)) - if ((list = rp->info) != NULL) - for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo)) - { - UNSET_FLAG (rinfo->flags, RIP_RTF_CHANGED); - /* This flag can be set only on the first entry. */ - break; - } + for (rp = route_top(rip->table); rp; rp = route_next(rp)) + if ((list = rp->info) != NULL) + for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) { + UNSET_FLAG(rinfo->flags, RIP_RTF_CHANGED); + /* This flag can be set only on the first entry. + */ + break; + } } /* Triggered update interval timer. */ -static int -rip_triggered_interval (struct thread *t) +static int rip_triggered_interval(struct thread *t) { - int rip_triggered_update (struct thread *); + int rip_triggered_update(struct thread *); - rip->t_triggered_interval = NULL; + rip->t_triggered_interval = NULL; - if (rip->trigger) - { - rip->trigger = 0; - rip_triggered_update (t); - } - return 0; -} + if (rip->trigger) { + rip->trigger = 0; + rip_triggered_update(t); + } + return 0; +} /* Execute triggered update. */ -static int -rip_triggered_update (struct thread *t) +static int rip_triggered_update(struct thread *t) { - int interval; + int interval; - /* Clear thred pointer. */ - rip->t_triggered_update = NULL; + /* Clear thred pointer. */ + rip->t_triggered_update = NULL; - /* Cancel interval timer. */ - RIP_TIMER_OFF (rip->t_triggered_interval); - rip->trigger = 0; + /* Cancel interval timer. */ + RIP_TIMER_OFF(rip->t_triggered_interval); + rip->trigger = 0; - /* Logging triggered update. */ - if (IS_RIP_DEBUG_EVENT) - zlog_debug ("triggered update!"); + /* Logging triggered update. */ + if (IS_RIP_DEBUG_EVENT) + zlog_debug("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); + /* 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 (); + /* 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; + /* 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); + rip->t_triggered_interval = thread_add_timer( + master, rip_triggered_interval, NULL, interval); - return 0; + return 0; } /* Withdraw redistributed route. */ -void -rip_redistribute_withdraw (int type) -{ - struct route_node *rp; - struct rip_info *rinfo = NULL; - struct list *list = NULL; +void rip_redistribute_withdraw(int type) +{ + struct route_node *rp; + struct rip_info *rinfo = NULL; + struct list *list = NULL; + + if (!rip) + return; + + for (rp = route_top(rip->table); rp; rp = route_next(rp)) + if ((list = rp->info) != NULL) { + rinfo = listgetdata(listhead(list)); + 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; + + if (IS_RIP_DEBUG_EVENT) { + struct prefix_ipv4 *p = + (struct prefix_ipv4 *)&rp->p; + + zlog_debug( + "Poisone %s/%d on the interface %s with an infinity metric [withdraw]", + inet_ntoa(p->prefix), + p->prefixlen, + ifindex2ifname(rinfo->ifindex, + VRF_DEFAULT)); + } + + rip_event(RIP_TRIGGERED_UPDATE, 0); + } + } +} - if (!rip) - return; +/* Create new RIP instance and set it to global variable. */ +static int rip_create(void) +{ + rip = XCALLOC(MTYPE_RIP, sizeof(struct rip)); - for (rp = route_top (rip->table); rp; rp = route_next (rp)) - if ((list = rp->info) != NULL) - { - rinfo = listgetdata (listhead (list)); - 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; + /* Set initial value. */ + rip->version_send = RI_RIP_VERSION_2; + rip->version_recv = RI_RIP_VERSION_1_AND_2; + 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; - if (IS_RIP_DEBUG_EVENT) { - struct prefix_ipv4 *p = (struct prefix_ipv4 *) &rp->p; + /* Initialize RIP routig table. */ + rip->table = route_table_init(); + rip->route = route_table_init(); + rip->neighbor = route_table_init(); - zlog_debug ("Poisone %s/%d on the interface %s with an infinity metric [withdraw]", - inet_ntoa(p->prefix), p->prefixlen, - ifindex2ifname(rinfo->ifindex, VRF_DEFAULT)); - } + /* Make output stream. */ + rip->obuf = stream_new(1500); - rip_event (RIP_TRIGGERED_UPDATE, 0); - } - } -} + /* Make socket. */ + rip->sock = rip_create_socket(); + if (rip->sock < 0) + return rip->sock; -/* Create new RIP instance and set it to global variable. */ -static int -rip_create (void) -{ - rip = XCALLOC (MTYPE_RIP, sizeof (struct rip)); + /* Create read and timer thread. */ + rip_event(RIP_READ, rip->sock); + rip_event(RIP_UPDATE_EVENT, 1); - /* Set initial value. */ - rip->version_send = RI_RIP_VERSION_2; - rip->version_recv = RI_RIP_VERSION_1_AND_2; - 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; + QOBJ_REG(rip, rip); - /* Initialize RIP routig table. */ - rip->table = route_table_init (); - rip->route = route_table_init (); - rip->neighbor = route_table_init (); + return 0; +} - /* Make output stream. */ - rip->obuf = stream_new (1500); +/* Sned RIP request to the destination. */ +int rip_request_send(struct sockaddr_in *to, struct interface *ifp, + u_char version, struct connected *connected) +{ + struct rte *rte; + struct rip_packet rip_packet; + struct listnode *node, *nnode; + + 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); + + if (connected) { + /* + * connected is only sent for ripv1 case, or when + * interface does not support multicast. Caller loops + * over each connected address for this case. + */ + if (rip_send_packet((u_char *)&rip_packet, sizeof(rip_packet), + to, connected) + != sizeof(rip_packet)) + return -1; + else + return sizeof(rip_packet); + } - /* Make socket. */ - rip->sock = rip_create_socket (); - if (rip->sock < 0) - return rip->sock; + /* send request on each connected network */ + for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, connected)) { + struct prefix_ipv4 *p; - /* Create read and timer thread. */ - rip_event (RIP_READ, rip->sock); - rip_event (RIP_UPDATE_EVENT, 1); + p = (struct prefix_ipv4 *)connected->address; - QOBJ_REG (rip, rip); + if (p->family != AF_INET) + continue; - return 0; + if (rip_send_packet((u_char *)&rip_packet, sizeof(rip_packet), + to, connected) + != sizeof(rip_packet)) + return -1; + } + return sizeof(rip_packet); } -/* Sned RIP request to the destination. */ -int -rip_request_send (struct sockaddr_in *to, struct interface *ifp, - u_char version, struct connected *connected) -{ - struct rte *rte; - struct rip_packet rip_packet; - struct listnode *node, *nnode; - - 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); - - if (connected) - { - /* - * connected is only sent for ripv1 case, or when - * interface does not support multicast. Caller loops - * over each connected address for this case. - */ - if (rip_send_packet ((u_char *) &rip_packet, sizeof (rip_packet), - to, connected) != sizeof (rip_packet)) - return -1; - else - return sizeof (rip_packet); - } - - /* send request on each connected network */ - for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, connected)) - { - struct prefix_ipv4 *p; - - p = (struct prefix_ipv4 *) connected->address; - - if (p->family != AF_INET) - continue; - - if (rip_send_packet ((u_char *) &rip_packet, sizeof (rip_packet), - to, connected) != sizeof (rip_packet)) - return -1; - } - return sizeof (rip_packet); -} - -static int -rip_update_jitter (unsigned long time) +static int rip_update_jitter(unsigned long time) { #define JITTER_BOUND 4 - /* We want to get the jitter to +/- 1/JITTER_BOUND the interval. - Given that, we cannot let time be less than JITTER_BOUND seconds. - The RIPv2 RFC says jitter should be small compared to - update_time. We consider 1/JITTER_BOUND to be small. - */ - - int jitter_input = time; - int jitter; - - if (jitter_input < JITTER_BOUND) - jitter_input = JITTER_BOUND; - - jitter = (((random () % ((jitter_input * 2) + 1)) - jitter_input)); - - return jitter/JITTER_BOUND; -} - -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: - RIP_TIMER_OFF (rip->t_update); - 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; - } + /* We want to get the jitter to +/- 1/JITTER_BOUND the interval. + Given that, we cannot let time be less than JITTER_BOUND seconds. + The RIPv2 RFC says jitter should be small compared to + update_time. We consider 1/JITTER_BOUND to be small. + */ + + int jitter_input = time; + int jitter; + + if (jitter_input < JITTER_BOUND) + jitter_input = JITTER_BOUND; + + jitter = (((random() % ((jitter_input * 2) + 1)) - jitter_input)); + + return jitter / JITTER_BOUND; +} + +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: + RIP_TIMER_OFF(rip->t_update); + 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_NOSH (router_rip, @@ -2807,21 +2793,19 @@ DEFUN_NOSH (router_rip, "Enable a routing process\n" "Routing Information Protocol (RIP)\n") { - int ret; + 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; + /* If rip is not enabled before. */ + if (!rip) { + ret = rip_create(); + if (ret < 0) { + zlog_info("Can't create RIP"); + return CMD_WARNING; + } } - } - VTY_PUSH_CONTEXT(RIP_NODE, rip); + VTY_PUSH_CONTEXT(RIP_NODE, rip); - return CMD_SUCCESS; + return CMD_SUCCESS; } DEFUN (no_router_rip, @@ -2831,9 +2815,9 @@ DEFUN (no_router_rip, "Enable a routing process\n" "Routing Information Protocol (RIP)\n") { - if (rip) - rip_clean (); - return CMD_SUCCESS; + if (rip) + rip_clean(); + return CMD_SUCCESS; } DEFUN (rip_version, @@ -2842,20 +2826,18 @@ DEFUN (rip_version, "Set routing protocol version\n" "version\n") { - int idx_number = 1; - int version; + int idx_number = 1; + int version; - version = atoi (argv[idx_number]->arg); - if (version != RIPv1 && version != RIPv2) - { - vty_out (vty, "invalid rip version %d%s", version, - VTY_NEWLINE); - return CMD_WARNING; - } - rip->version_send = version; - rip->version_recv = version; + version = atoi(argv[idx_number]->arg); + if (version != RIPv1 && version != RIPv2) { + vty_out(vty, "invalid rip version %d%s", version, VTY_NEWLINE); + return CMD_WARNING; + } + rip->version_send = version; + rip->version_recv = version; - return CMD_SUCCESS; + return CMD_SUCCESS; } DEFUN (no_rip_version, @@ -2865,11 +2847,11 @@ DEFUN (no_rip_version, "Set routing protocol version\n" "Version\n") { - /* Set RIP version to the default. */ - rip->version_send = RI_RIP_VERSION_2; - rip->version_recv = RI_RIP_VERSION_1_AND_2; + /* Set RIP version to the default. */ + rip->version_send = RI_RIP_VERSION_2; + rip->version_recv = RI_RIP_VERSION_1_AND_2; - return CMD_SUCCESS; + return CMD_SUCCESS; } @@ -2879,34 +2861,34 @@ DEFUN (rip_route, "RIP static route configuration\n" "IP prefix <network>/<length>\n") { - int idx_ipv4_prefixlen = 1; - int ret; - struct prefix_ipv4 p; - struct route_node *node; + int idx_ipv4_prefixlen = 1; + int ret; + struct prefix_ipv4 p; + struct route_node *node; - ret = str2prefix_ipv4 (argv[idx_ipv4_prefixlen]->arg, &p); - if (ret < 0) - { - vty_out (vty, "Malformed address%s", VTY_NEWLINE); - return CMD_WARNING; - } - apply_mask_ipv4 (&p); + ret = str2prefix_ipv4(argv[idx_ipv4_prefixlen]->arg, &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); + /* 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; - } + if (node->info) { + vty_out(vty, "There is already same static route.%s", + VTY_NEWLINE); + route_unlock_node(node); + return CMD_WARNING; + } - node->info = (void *)1; + node->info = (void *)1; - rip_redistribute_add (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0, NULL, 0, 0, 0); + rip_redistribute_add(ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0, NULL, 0, + 0, 0); - return CMD_SUCCESS; + return CMD_SUCCESS; } DEFUN (no_rip_route, @@ -2916,35 +2898,33 @@ DEFUN (no_rip_route, "RIP static route configuration\n" "IP prefix <network>/<length>\n") { - int idx_ipv4_prefixlen = 2; - int ret; - struct prefix_ipv4 p; - struct route_node *node; + int idx_ipv4_prefixlen = 2; + int ret; + struct prefix_ipv4 p; + struct route_node *node; - ret = str2prefix_ipv4 (argv[idx_ipv4_prefixlen]->arg, &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[idx_ipv4_prefixlen]->arg, - VTY_NEWLINE); - return CMD_WARNING; - } + ret = str2prefix_ipv4(argv[idx_ipv4_prefixlen]->arg, &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[idx_ipv4_prefixlen]->arg, VTY_NEWLINE); + return CMD_WARNING; + } - rip_redistribute_delete (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0); - route_unlock_node (node); + rip_redistribute_delete(ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0); + route_unlock_node(node); - node->info = NULL; - route_unlock_node (node); + node->info = NULL; + route_unlock_node(node); - return CMD_SUCCESS; + return CMD_SUCCESS; } #if 0 @@ -2970,13 +2950,12 @@ DEFUN (rip_default_metric, "Set a metric of redistribute routes\n" "Default metric\n") { - int idx_number = 1; - if (rip) - { - rip->default_metric = atoi (argv[idx_number]->arg); - /* rip_update_default_metric (); */ - } - return CMD_SUCCESS; + int idx_number = 1; + if (rip) { + rip->default_metric = atoi(argv[idx_number]->arg); + /* rip_update_default_metric (); */ + } + return CMD_SUCCESS; } DEFUN (no_rip_default_metric, @@ -2986,12 +2965,11 @@ DEFUN (no_rip_default_metric, "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; + if (rip) { + rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT; + /* rip_update_default_metric (); */ + } + return CMD_SUCCESS; } @@ -3004,46 +2982,46 @@ DEFUN (rip_timers, "Routing information timeout timer. Default is 180.\n" "Garbage collection timer. Default is 120.\n") { - int idx_number = 2; - int idx_number_2 = 3; - int idx_number_3 = 4; - 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[idx_number]->arg, &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[idx_number_2]->arg, &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[idx_number_3]->arg, &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; + int idx_number = 2; + int idx_number_2 = 3; + int idx_number_3 = 4; + 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[idx_number]->arg, &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[idx_number_2]->arg, &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[idx_number_3]->arg, &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, @@ -3056,213 +3034,196 @@ DEFUN (no_rip_timers, "Routing information timeout timer. Default is 180.\n" "Garbage collection timer. Default is 120.\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; + /* 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); + /* Reset update timer thread. */ + rip_event(RIP_UPDATE_EVENT, 0); - return CMD_SUCCESS; + return CMD_SUCCESS; } - struct route_table *rip_distance_table; -struct rip_distance -{ - /* Distance value for the IP source prefix. */ - u_char distance; +struct rip_distance { + /* Distance value for the IP source prefix. */ + u_char distance; - /* Name of the access-list to be matched. */ - char *access_list; + /* Name of the access-list to be matched. */ + char *access_list; }; -static struct rip_distance * -rip_distance_new (void) +static struct rip_distance *rip_distance_new(void) { - return XCALLOC (MTYPE_RIP_DISTANCE, sizeof (struct rip_distance)); + return XCALLOC(MTYPE_RIP_DISTANCE, sizeof(struct rip_distance)); } -static void -rip_distance_free (struct rip_distance *rdistance) -{ - XFREE (MTYPE_RIP_DISTANCE, rdistance); -} - -static int -rip_distance_set (struct vty *vty, const char *distance_str, const char *ip_str, - const 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; -} - -static int -rip_distance_unset (struct vty *vty, const char *distance_str, - const char *ip_str, const char *access_list_str) -{ - int ret; - struct prefix_ipv4 p; - 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; - } - - 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; +static void rip_distance_free(struct rip_distance *rdistance) +{ + XFREE(MTYPE_RIP_DISTANCE, rdistance); } -static void -rip_distance_reset (void) +static int rip_distance_set(struct vty *vty, const char *distance_str, + const char *ip_str, const char *access_list_str) { - struct route_node *rn; - struct rip_distance *rdistance; + 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; +} + +static int rip_distance_unset(struct vty *vty, const char *distance_str, + const char *ip_str, const char *access_list_str) +{ + int ret; + struct prefix_ipv4 p; + 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; + } + + 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; - 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); + free(rdistance->access_list); + rip_distance_free(rdistance); + rn->info = NULL; - route_unlock_node (rn); - } + route_unlock_node(rn); + route_unlock_node(rn); + + return CMD_SUCCESS; } -/* 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; +static void rip_distance_reset(void) +{ + 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); + } +} - return rdistance->distance; +/* 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; } - else - return rdistance->distance; - } - if (rip->distance) - return rip->distance; + if (rip->distance) + return rip->distance; - return 0; + return 0; } -static 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); - } +static 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, @@ -3271,9 +3232,9 @@ DEFUN (rip_distance, "Administrative distance\n" "Distance value\n") { - int idx_number = 1; - rip->distance = atoi (argv[idx_number]->arg); - return CMD_SUCCESS; + int idx_number = 1; + rip->distance = atoi(argv[idx_number]->arg); + return CMD_SUCCESS; } DEFUN (no_rip_distance, @@ -3283,8 +3244,8 @@ DEFUN (no_rip_distance, "Administrative distance\n" "Distance value\n") { - rip->distance = 0; - return CMD_SUCCESS; + rip->distance = 0; + return CMD_SUCCESS; } DEFUN (rip_distance_source, @@ -3294,10 +3255,11 @@ DEFUN (rip_distance_source, "Distance value\n" "IP source prefix\n") { - int idx_number = 1; - int idx_ipv4_prefixlen = 2; - rip_distance_set (vty, argv[idx_number]->arg, argv[idx_ipv4_prefixlen]->arg, NULL); - return CMD_SUCCESS; + int idx_number = 1; + int idx_ipv4_prefixlen = 2; + rip_distance_set(vty, argv[idx_number]->arg, + argv[idx_ipv4_prefixlen]->arg, NULL); + return CMD_SUCCESS; } DEFUN (no_rip_distance_source, @@ -3308,10 +3270,11 @@ DEFUN (no_rip_distance_source, "Distance value\n" "IP source prefix\n") { - int idx_number = 2; - int idx_ipv4_prefixlen = 3; - rip_distance_unset (vty, argv[idx_number]->arg, argv[idx_ipv4_prefixlen]->arg, NULL); - return CMD_SUCCESS; + int idx_number = 2; + int idx_ipv4_prefixlen = 3; + rip_distance_unset(vty, argv[idx_number]->arg, + argv[idx_ipv4_prefixlen]->arg, NULL); + return CMD_SUCCESS; } DEFUN (rip_distance_source_access_list, @@ -3322,11 +3285,12 @@ DEFUN (rip_distance_source_access_list, "IP source prefix\n" "Access list name\n") { - int idx_number = 1; - int idx_ipv4_prefixlen = 2; - int idx_word = 3; - rip_distance_set (vty, argv[idx_number]->arg, argv[idx_ipv4_prefixlen]->arg, argv[idx_word]->arg); - return CMD_SUCCESS; + int idx_number = 1; + int idx_ipv4_prefixlen = 2; + int idx_word = 3; + rip_distance_set(vty, argv[idx_number]->arg, + argv[idx_ipv4_prefixlen]->arg, argv[idx_word]->arg); + return CMD_SUCCESS; } DEFUN (no_rip_distance_source_access_list, @@ -3338,51 +3302,50 @@ DEFUN (no_rip_distance_source_access_list, "IP source prefix\n" "Access list name\n") { - int idx_number = 2; - int idx_ipv4_prefixlen = 3; - int idx_word = 4; - rip_distance_unset (vty, argv[idx_number]->arg, argv[idx_ipv4_prefixlen]->arg, argv[idx_word]->arg); - return CMD_SUCCESS; + int idx_number = 2; + int idx_ipv4_prefixlen = 3; + int idx_word = 4; + rip_distance_unset(vty, argv[idx_number]->arg, + argv[idx_ipv4_prefixlen]->arg, argv[idx_word]->arg); + return CMD_SUCCESS; } /* Update ECMP routes to zebra when ECMP is disabled. */ -static void -rip_ecmp_disable (void) -{ - struct route_node *rp; - struct rip_info *rinfo, *tmp_rinfo; - struct list *list; - struct listnode *node, *nextnode; - - if (!rip) - return; - - for (rp = route_top (rip->table); rp; rp = route_next (rp)) - if ((list = rp->info) != NULL && listcount (list) > 1) - { - rinfo = listgetdata (listhead (list)); - if (!rip_route_rte (rinfo)) - continue; - - /* Drop all other entries, except the first one. */ - for (ALL_LIST_ELEMENTS (list, node, nextnode, tmp_rinfo)) - if (tmp_rinfo != rinfo) - { - RIP_TIMER_OFF (tmp_rinfo->t_timeout); - RIP_TIMER_OFF (tmp_rinfo->t_garbage_collect); - list_delete_node (list, node); - rip_info_free (tmp_rinfo); - } - - /* Update zebra. */ - rip_zebra_ipv4_add (rp); - - /* Set the route change flag. */ - SET_FLAG (rinfo->flags, RIP_RTF_CHANGED); - - /* Signal the output process to trigger an update. */ - rip_event (RIP_TRIGGERED_UPDATE, 0); - } +static void rip_ecmp_disable(void) +{ + struct route_node *rp; + struct rip_info *rinfo, *tmp_rinfo; + struct list *list; + struct listnode *node, *nextnode; + + if (!rip) + return; + + for (rp = route_top(rip->table); rp; rp = route_next(rp)) + if ((list = rp->info) != NULL && listcount(list) > 1) { + rinfo = listgetdata(listhead(list)); + if (!rip_route_rte(rinfo)) + continue; + + /* Drop all other entries, except the first one. */ + for (ALL_LIST_ELEMENTS(list, node, nextnode, tmp_rinfo)) + if (tmp_rinfo != rinfo) { + RIP_TIMER_OFF(tmp_rinfo->t_timeout); + RIP_TIMER_OFF( + tmp_rinfo->t_garbage_collect); + list_delete_node(list, node); + rip_info_free(tmp_rinfo); + } + + /* Update zebra. */ + rip_zebra_ipv4_add(rp); + + /* Set the route change flag. */ + SET_FLAG(rinfo->flags, RIP_RTF_CHANGED); + + /* Signal the output process to trigger an update. */ + rip_event(RIP_TRIGGERED_UPDATE, 0); + } } DEFUN (rip_allow_ecmp, @@ -3390,15 +3353,14 @@ DEFUN (rip_allow_ecmp, "allow-ecmp", "Allow Equal Cost MultiPath\n") { - if (rip->ecmp) - { - vty_out (vty, "ECMP is already enabled.%s", VTY_NEWLINE); - return CMD_WARNING; - } + if (rip->ecmp) { + vty_out(vty, "ECMP is already enabled.%s", VTY_NEWLINE); + return CMD_WARNING; + } - rip->ecmp = 1; - zlog_info ("ECMP is enabled."); - return CMD_SUCCESS; + rip->ecmp = 1; + zlog_info("ECMP is enabled."); + return CMD_SUCCESS; } DEFUN (no_rip_allow_ecmp, @@ -3407,62 +3369,55 @@ DEFUN (no_rip_allow_ecmp, NO_STR "Allow Equal Cost MultiPath\n") { - if (!rip->ecmp) - { - vty_out (vty, "ECMP is already disabled.%s", VTY_NEWLINE); - return CMD_WARNING; - } + if (!rip->ecmp) { + vty_out(vty, "ECMP is already disabled.%s", VTY_NEWLINE); + return CMD_WARNING; + } - rip->ecmp = 0; - zlog_info ("ECMP is disabled."); - rip_ecmp_disable (); - return CMD_SUCCESS; + rip->ecmp = 0; + zlog_info("ECMP is disabled."); + rip_ecmp_disable(); + return CMD_SUCCESS; } /* Print out routes update time. */ -static void -rip_vty_out_uptime (struct vty *vty, struct rip_info *rinfo) +static void rip_vty_out_uptime(struct vty *vty, struct rip_info *rinfo) { - time_t clock; - struct tm *tm; + time_t clock; + struct tm *tm; #define TIME_BUF 25 - char timebuf [TIME_BUF]; - struct thread *thread; - - if ((thread = rinfo->t_timeout) != NULL) - { - clock = thread_timer_remain_second (thread); - 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_timer_remain_second (thread); - tm = gmtime (&clock); - strftime (timebuf, TIME_BUF, "%M:%S", tm); - vty_out (vty, "%5s", timebuf); - } -} - -static const 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 "?"; - } + char timebuf[TIME_BUF]; + struct thread *thread; + + if ((thread = rinfo->t_timeout) != NULL) { + clock = thread_timer_remain_second(thread); + 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_timer_remain_second(thread); + tm = gmtime(&clock); + strftime(timebuf, TIME_BUF, "%M:%S", tm); + vty_out(vty, "%5s", timebuf); + } +} + +static const 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, @@ -3472,77 +3427,85 @@ DEFUN (show_ip_rip, IP_STR "Show RIP routes\n") { - struct route_node *np; - struct rip_info *rinfo = NULL; - struct list *list = NULL; - struct listnode *listnode = NULL; - - if (! rip) - return CMD_SUCCESS; - - vty_out (vty, "Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP%s" - "Sub-codes:%s" - " (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s" - " (i) - interface%s%s" - " Network Next Hop Metric From Tag Time%s", - VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); - - for (np = route_top (rip->table); np; np = route_next (np)) - if ((list = np->info) != NULL) - for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo)) - { - int len; - - len = vty_out (vty, "%c(%s) %s/%d", - /* np->lock, For debugging. */ - zebra_route_char(rinfo->type), - 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)); - vty_out (vty, "%3"ROUTE_TAG_PRI" ", (route_tag_t)rinfo->tag); - rip_vty_out_uptime (vty, rinfo); - } - else if (rinfo->metric == RIP_METRIC_INFINITY) - { - vty_out (vty, "self "); - vty_out (vty, "%3"ROUTE_TAG_PRI" ", (route_tag_t)rinfo->tag); - rip_vty_out_uptime (vty, rinfo); - } - else - { - if (rinfo->external_metric) - { - len = vty_out (vty, "self (%s:%d)", - zebra_route_string(rinfo->type), - rinfo->external_metric); - len = 16 - len; - if (len > 0) - vty_out (vty, "%*s", len, " "); - } - else - vty_out (vty, "self "); - vty_out (vty, "%3"ROUTE_TAG_PRI, (route_tag_t)rinfo->tag); - } - - vty_out (vty, "%s", VTY_NEWLINE); - } - return CMD_SUCCESS; + struct route_node *np; + struct rip_info *rinfo = NULL; + struct list *list = NULL; + struct listnode *listnode = NULL; + + if (!rip) + return CMD_SUCCESS; + + vty_out(vty, + "Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP%s" + "Sub-codes:%s" + " (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s" + " (i) - interface%s%s" + " Network Next Hop Metric From Tag Time%s", + VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, + VTY_NEWLINE); + + for (np = route_top(rip->table); np; np = route_next(np)) + if ((list = np->info) != NULL) + for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) { + int len; + + len = vty_out( + vty, "%c(%s) %s/%d", + /* np->lock, For debugging. */ + zebra_route_char(rinfo->type), + 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)); + vty_out(vty, "%3" ROUTE_TAG_PRI " ", + (route_tag_t)rinfo->tag); + rip_vty_out_uptime(vty, rinfo); + } else if (rinfo->metric + == RIP_METRIC_INFINITY) { + vty_out(vty, "self "); + vty_out(vty, "%3" ROUTE_TAG_PRI " ", + (route_tag_t)rinfo->tag); + rip_vty_out_uptime(vty, rinfo); + } else { + if (rinfo->external_metric) { + len = vty_out( + vty, "self (%s:%d)", + zebra_route_string( + rinfo->type), + rinfo->external_metric); + len = 16 - len; + if (len > 0) + vty_out(vty, "%*s", len, + " "); + } else + vty_out(vty, + "self "); + vty_out(vty, "%3" ROUTE_TAG_PRI, + (route_tag_t)rinfo->tag); + } + + vty_out(vty, "%s", VTY_NEWLINE); + } + return CMD_SUCCESS; } /* Vincent: formerly, it was show_ip_protocols_rip: "show ip protocols" */ @@ -3554,541 +3517,519 @@ DEFUN (show_ip_rip_status, "Show RIP routes\n" "IP routing protocol process parameters and statistics\n") { - struct listnode *node; - struct interface *ifp; - struct rip_interface *ri; - extern const struct message ri_version_msg[]; - const char *send_version; - const 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 %lu seconds%s", - thread_timer_remain_second(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 %s,", - lookup_msg(ri_version_msg,rip->version_send, NULL)); - if (rip->version_recv == RI_RIP_VERSION_1_AND_2) - vty_out (vty, " receive any version %s", VTY_NEWLINE); - else - vty_out (vty, " receive version %s %s", - lookup_msg(ri_version_msg,rip->version_recv, NULL), VTY_NEWLINE); - - vty_out (vty, " Interface Send Recv Key-chain%s", VTY_NEWLINE); - - for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp)) - { - ri = ifp->info; - - if (!ri->running) - continue; - - if (ri->enable_network || ri->enable_interface) - { - if (ri->ri_send == RI_RIP_UNSPEC) - send_version = lookup_msg(ri_version_msg, rip->version_send, NULL); - else - send_version = lookup_msg(ri_version_msg, ri->ri_send, NULL); - - if (ri->ri_receive == RI_RIP_UNSPEC) - receive_version = lookup_msg(ri_version_msg, rip->version_recv, NULL); - else - receive_version = lookup_msg(ri_version_msg, ri->ri_receive, NULL); - - 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); - - { - int found_passive = 0; - for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp)) - { - ri = ifp->info; + struct listnode *node; + struct interface *ifp; + struct rip_interface *ri; + extern const struct message ri_version_msg[]; + const char *send_version; + const 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 %lu seconds%s", + thread_timer_remain_second(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 %s,", + lookup_msg(ri_version_msg, rip->version_send, NULL)); + if (rip->version_recv == RI_RIP_VERSION_1_AND_2) + vty_out(vty, " receive any version %s", VTY_NEWLINE); + else + vty_out(vty, " receive version %s %s", + lookup_msg(ri_version_msg, rip->version_recv, NULL), + VTY_NEWLINE); + + vty_out(vty, " Interface Send Recv Key-chain%s", + VTY_NEWLINE); + + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) { + ri = ifp->info; + + if (!ri->running) + continue; + + if (ri->enable_network || ri->enable_interface) { + if (ri->ri_send == RI_RIP_UNSPEC) + send_version = + lookup_msg(ri_version_msg, + rip->version_send, NULL); + else + send_version = lookup_msg(ri_version_msg, + ri->ri_send, NULL); + + if (ri->ri_receive == RI_RIP_UNSPEC) + receive_version = + lookup_msg(ri_version_msg, + rip->version_recv, NULL); + else + receive_version = lookup_msg( + ri_version_msg, ri->ri_receive, NULL); + + vty_out(vty, " %-17s%-3s %-3s %s%s", ifp->name, + send_version, receive_version, + ri->key_chain ? ri->key_chain : "", + VTY_NEWLINE); + } + } - if ((ri->enable_network || ri->enable_interface) && ri->passive) - { - if (!found_passive) - { - vty_out (vty, " Passive Interface(s):%s", VTY_NEWLINE); - found_passive = 1; - } - vty_out (vty, " %s%s", ifp->name, 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); + { + int found_passive = 0; + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) { + ri = ifp->info; + + if ((ri->enable_network || ri->enable_interface) + && ri->passive) { + if (!found_passive) { + vty_out(vty, + " Passive Interface(s):%s", + VTY_NEWLINE); + found_passive = 1; + } + vty_out(vty, " %s%s", ifp->name, + VTY_NEWLINE); + } + } + } + + 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); + rip_distance_show(vty); - return CMD_SUCCESS; + return CMD_SUCCESS; } /* RIP configuration write function. */ -static 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_send != RI_RIP_VERSION_2 - || rip->version_recv != RI_RIP_VERSION_1_AND_2) - vty_out (vty, " version %d%s", rip->version_send, - 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); - - /* Interface routemap configuration */ - write += config_write_if_rmap (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); - - /* ECMP configuration. */ - if (rip->ecmp) - vty_out (vty, " allow-ecmp%s", 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; +static 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_send != RI_RIP_VERSION_2 + || rip->version_recv != RI_RIP_VERSION_1_AND_2) + vty_out(vty, " version %d%s", rip->version_send, + 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); + + /* Interface routemap configuration */ + write += config_write_if_rmap(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); + + /* ECMP configuration. */ + if (rip->ecmp) + vty_out(vty, " allow-ecmp%s", 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. */ -static struct cmd_node rip_node = -{ - RIP_NODE, - "%s(config-router)# ", - 1 -}; +static struct cmd_node rip_node = {RIP_NODE, "%s(config-router)# ", 1}; /* Distribute-list update functions. */ -static 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, VRF_DEFAULT); - if (ifp == NULL) - return; - - ri = ifp->info; - - if (dist->list[DISTRIBUTE_V4_IN]) - { - alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_V4_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_V4_OUT]) - { - alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_V4_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_V4_IN]) - { - plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_V4_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_V4_OUT]) - { - plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_V4_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); +static 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, VRF_DEFAULT); + if (ifp == NULL) + return; + + ri = ifp->info; + + if (dist->list[DISTRIBUTE_V4_IN]) { + alist = access_list_lookup(AFI_IP, + dist->list[DISTRIBUTE_V4_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_V4_OUT]) { + alist = access_list_lookup(AFI_IP, + dist->list[DISTRIBUTE_V4_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_V4_IN]) { + plist = prefix_list_lookup(AFI_IP, + dist->prefix[DISTRIBUTE_V4_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_V4_OUT]) { + plist = prefix_list_lookup(AFI_IP, + dist->prefix[DISTRIBUTE_V4_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. */ /* ARGSUSED */ -static void -rip_distribute_update_all (struct prefix_list *notused) +static void rip_distribute_update_all(struct prefix_list *notused) { - struct interface *ifp; - struct listnode *node, *nnode; + struct interface *ifp; + struct listnode *node, *nnode; - for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), node, nnode, ifp)) - rip_distribute_update_interface (ifp); + for (ALL_LIST_ELEMENTS(vrf_iflist(VRF_DEFAULT), node, nnode, ifp)) + rip_distribute_update_interface(ifp); } /* ARGSUSED */ -static void -rip_distribute_update_all_wrapper(struct access_list *notused) +static void rip_distribute_update_all_wrapper(struct access_list *notused) { - rip_distribute_update_all(NULL); + rip_distribute_update_all(NULL); } /* Delete all added rip route. */ -void -rip_clean (void) +void rip_clean(void) { - int i; - struct route_node *rp; - struct rip_info *rinfo = NULL; - struct list *list = NULL; - struct listnode *listnode = NULL; + int i; + struct route_node *rp; + struct rip_info *rinfo = NULL; + struct list *list = NULL; + struct listnode *listnode = NULL; + + if (rip) { + QOBJ_UNREG(rip); + + /* Clear RIP routes */ + for (rp = route_top(rip->table); rp; rp = route_next(rp)) + if ((list = rp->info) != NULL) { + rinfo = listgetdata(listhead(list)); + if (rip_route_rte(rinfo)) + rip_zebra_ipv4_delete(rp); + + for (ALL_LIST_ELEMENTS_RO(list, listnode, + rinfo)) { + RIP_TIMER_OFF(rinfo->t_timeout); + RIP_TIMER_OFF(rinfo->t_garbage_collect); + rip_info_free(rinfo); + } + list_delete(list); + rp->info = NULL; + route_unlock_node(rp); + } + + /* 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. */ + THREAD_READ_OFF(rip->t_read); + + /* Close RIP socket. */ + if (rip->sock >= 0) { + close(rip->sock); + rip->sock = -1; + } - if (rip) - { - QOBJ_UNREG (rip); - - /* Clear RIP routes */ - for (rp = route_top (rip->table); rp; rp = route_next (rp)) - if ((list = rp->info) != NULL) - { - rinfo = listgetdata (listhead (list)); - if (rip_route_rte (rinfo)) - rip_zebra_ipv4_delete (rp); - - for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo)) - { - RIP_TIMER_OFF (rinfo->t_timeout); - RIP_TIMER_OFF (rinfo->t_garbage_collect); - rip_info_free (rinfo); - } - list_delete (list); - rp->info = NULL; - route_unlock_node (rp); - } - - /* 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. */ - THREAD_READ_OFF (rip->t_read); - - /* 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_nondefault_clean (); - rip_offset_clean (); - rip_interfaces_clean (); - rip_distance_reset (); - rip_redistribute_clean (); + /* 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_nondefault_clean(); + rip_offset_clean(); + rip_interfaces_clean(); + rip_distance_reset(); + rip_redistribute_clean(); } /* Reset all values to the default settings. */ -void -rip_reset (void) +void rip_reset(void) { - /* Reset global counters. */ - rip_global_route_changes = 0; - rip_global_queries = 0; + /* 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 ripd related reset functions. */ + rip_debug_reset(); + rip_route_map_reset(); - /* Call library reset functions. */ - vty_reset (); - access_list_reset (); - prefix_list_reset (); + /* Call library reset functions. */ + vty_reset(); + access_list_reset(); + prefix_list_reset(); - distribute_list_reset (); + distribute_list_reset(); - rip_interfaces_reset (); - rip_distance_reset (); + rip_interfaces_reset(); + rip_distance_reset(); - rip_zclient_reset (); + rip_zclient_reset(); } -static void -rip_if_rmap_update (struct if_rmap *if_rmap) +static void rip_if_rmap_update(struct if_rmap *if_rmap) { - struct interface *ifp; - struct rip_interface *ri; - struct route_map *rmap; + struct interface *ifp; + struct rip_interface *ri; + struct route_map *rmap; - ifp = if_lookup_by_name (if_rmap->ifname, VRF_DEFAULT); - if (ifp == NULL) - return; + ifp = if_lookup_by_name(if_rmap->ifname, VRF_DEFAULT); + if (ifp == NULL) + return; - ri = ifp->info; + ri = ifp->info; - if (if_rmap->routemap[IF_RMAP_IN]) - { - rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_IN]); - if (rmap) - ri->routemap[IF_RMAP_IN] = rmap; - else - ri->routemap[IF_RMAP_IN] = NULL; - } - else - ri->routemap[RIP_FILTER_IN] = NULL; + if (if_rmap->routemap[IF_RMAP_IN]) { + rmap = route_map_lookup_by_name(if_rmap->routemap[IF_RMAP_IN]); + if (rmap) + ri->routemap[IF_RMAP_IN] = rmap; + else + ri->routemap[IF_RMAP_IN] = NULL; + } else + ri->routemap[RIP_FILTER_IN] = NULL; - if (if_rmap->routemap[IF_RMAP_OUT]) - { - rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_OUT]); - if (rmap) - ri->routemap[IF_RMAP_OUT] = rmap; - else - ri->routemap[IF_RMAP_OUT] = NULL; - } - else - ri->routemap[RIP_FILTER_OUT] = NULL; + if (if_rmap->routemap[IF_RMAP_OUT]) { + rmap = route_map_lookup_by_name(if_rmap->routemap[IF_RMAP_OUT]); + if (rmap) + ri->routemap[IF_RMAP_OUT] = rmap; + else + ri->routemap[IF_RMAP_OUT] = NULL; + } else + ri->routemap[RIP_FILTER_OUT] = NULL; } -void -rip_if_rmap_update_interface (struct interface *ifp) +void rip_if_rmap_update_interface(struct interface *ifp) { - struct if_rmap *if_rmap; + struct if_rmap *if_rmap; - if_rmap = if_rmap_lookup (ifp->name); - if (if_rmap) - rip_if_rmap_update (if_rmap); + if_rmap = if_rmap_lookup(ifp->name); + if (if_rmap) + rip_if_rmap_update(if_rmap); } -static void -rip_routemap_update_redistribute (void) +static void rip_routemap_update_redistribute(void) { - int i; + 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); + 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); + } } - } } /* ARGSUSED */ -static void -rip_routemap_update (const char *notused) +static void rip_routemap_update(const char *notused) { - struct interface *ifp; - struct listnode *node, *nnode; + struct interface *ifp; + struct listnode *node, *nnode; - for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), node, nnode, ifp)) - rip_if_rmap_update_interface (ifp); + for (ALL_LIST_ELEMENTS(vrf_iflist(VRF_DEFAULT), node, nnode, ifp)) + rip_if_rmap_update_interface(ifp); - rip_routemap_update_redistribute (); + rip_routemap_update_redistribute(); } /* Allocate new rip structure and set default value. */ -void -rip_init (void) -{ - /* 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_rip_status_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, &rip_default_metric_cmd); - install_element (RIP_NODE, &no_rip_default_metric_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); - install_element (RIP_NODE, &rip_allow_ecmp_cmd); - install_element (RIP_NODE, &no_rip_allow_ecmp_cmd); - - /* Debug related init. */ - rip_debug_init (); - - /* Access list install. */ - access_list_init (); - access_list_add_hook (rip_distribute_update_all_wrapper); - access_list_delete_hook (rip_distribute_update_all_wrapper); - - /* 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); - - /* Route-map */ - rip_route_map_init (); - rip_offset_init (); - - route_map_add_hook (rip_routemap_update); - route_map_delete_hook (rip_routemap_update); - - if_rmap_init (RIP_NODE); - if_rmap_hook_add (rip_if_rmap_update); - if_rmap_hook_delete (rip_if_rmap_update); - - /* Distance control. */ - rip_distance_table = route_table_init (); +void rip_init(void) +{ + /* 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_rip_status_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, &rip_default_metric_cmd); + install_element(RIP_NODE, &no_rip_default_metric_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); + install_element(RIP_NODE, &rip_allow_ecmp_cmd); + install_element(RIP_NODE, &no_rip_allow_ecmp_cmd); + + /* Debug related init. */ + rip_debug_init(); + + /* Access list install. */ + access_list_init(); + access_list_add_hook(rip_distribute_update_all_wrapper); + access_list_delete_hook(rip_distribute_update_all_wrapper); + + /* 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); + + /* Route-map */ + rip_route_map_init(); + rip_offset_init(); + + route_map_add_hook(rip_routemap_update); + route_map_delete_hook(rip_routemap_update); + + if_rmap_init(RIP_NODE); + if_rmap_hook_add(rip_if_rmap_update); + if_rmap_hook_delete(rip_if_rmap_update); + + /* Distance control. */ + rip_distance_table = route_table_init(); } |
