Diff for /embedaddon/quagga/ripd/ripd.c between versions 1.1.1.2 and 1.1.1.3

version 1.1.1.2, 2013/07/21 23:54:40 version 1.1.1.3, 2016/11/02 10:09:10
Line 61  long rip_global_route_changes = 0; Line 61  long rip_global_route_changes = 0;
   
 /* RIP queries. */  /* RIP queries. */
 long rip_global_queries = 0;  long rip_global_queries = 0;
 /* Prototypes. */  /* Prototypes. */
 static void rip_event (enum rip_event, int);  static void rip_event (enum rip_event, int);
 static void rip_output_process (struct connected *, struct sockaddr_in *, int, u_char);  static void rip_output_process (struct connected *, struct sockaddr_in *, int, u_char);
 static int rip_triggered_update (struct thread *);  static int rip_triggered_update (struct thread *);
 static int rip_update_jitter (unsigned long);  static int rip_update_jitter (unsigned long);
 /* RIP output routes type. */  /* RIP output routes type. */
 enum  enum
 {  {
   rip_all_route,    rip_all_route,
   rip_changed_route    rip_changed_route
 };  };
 /* RIP command strings. */  /* RIP command strings. */
 static const struct message rip_msg[] =  static const struct message rip_msg[] =
 {  {
Line 86  static const struct message rip_msg[] = Line 86  static const struct message rip_msg[] =
   {RIP_POLL_ENTRY, "POLL ENTRY"},    {RIP_POLL_ENTRY, "POLL ENTRY"},
   {0, NULL},    {0, NULL},
 };  };
 /* Utility function to set boradcast option to the socket. */  /* Utility function to set boradcast option to the socket. */
 static int  static int
 sockopt_broadcast (int sock)  sockopt_broadcast (int sock)
Line 138  rip_garbage_collect (struct thread *t) Line 138  rip_garbage_collect (struct thread *t)
   rp = rinfo->rp;    rp = rinfo->rp;
   
   /* Unlock route_node. */    /* Unlock route_node. */
  rp->info = NULL;  listnode_delete (rp->info, rinfo);
  route_unlock_node (rp);  if (list_isempty ((struct list *)rp->info))
     {
       list_free (rp->info);
       rp->info = NULL;
       route_unlock_node (rp);
     }
   
   /* Free RIP routing information. */    /* Free RIP routing information. */
   rip_info_free (rinfo);    rip_info_free (rinfo);
Line 147  rip_garbage_collect (struct thread *t) Line 152  rip_garbage_collect (struct thread *t)
   return 0;    return 0;
 }  }
   
/* Timeout RIP routes. */static void rip_timeout_update (struct rip_info *rinfo);
static int
rip_timeout (struct thread *t)/* 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 *rinfo;  struct route_node *rp = rinfo_new->rp;
  struct route_node *rn;  struct rip_info *rinfo = NULL;
   struct list *list = NULL;
   
  rinfo = THREAD_ARG (t);  if (rp->info == NULL)
  rinfo->t_timeout = NULL;    rp->info = list_new ();
   list = (struct list *)rp->info;
   
  rn = rinfo->rp;  /* If ECMP is not allowed and some entry already exists in the list,
    * do nothing. */
   if (listcount (list) && !rip->ecmp)
     return NULL;
   
  /* - The garbage-collection timer is set for 120 seconds. */  rinfo = rip_info_new ();
  RIP_TIMER_ON (rinfo->t_garbage_collect, rip_garbage_collect,   memcpy (rinfo, rinfo_new, sizeof (struct rip_info));
                rip->garbage_time);  listnode_add (list, rinfo);
   
  rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rn->p, &rinfo->nexthop,  if (rip_route_rte (rinfo))
                         rinfo->metric);    {
  /* - The metric for the route is set to 16 (infinity).  This causes      rip_timeout_update (rinfo);
     the route to be removed from service. */      rip_zebra_ipv4_add (rp);
  rinfo->metric = RIP_METRIC_INFINITY;    }
  rinfo->flags &= ~RIP_RTF_FIB; 
   
  /* - The route change flag is to indicate that this entry has been  /* Set the route change flag on the first entry. */
     changed. */  rinfo = listgetdata (listhead (list));
  rinfo->flags |= RIP_RTF_CHANGED;  SET_FLAG (rinfo->flags, RIP_RTF_CHANGED);
   
  /* - The output process is signalled to trigger a response. */  /* Signal the output process to trigger an update (see section 2.5). */
   rip_event (RIP_TRIGGERED_UPDATE, 0);    rip_event (RIP_TRIGGERED_UPDATE, 0);
   
     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);
         }
   
     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);
       }
   
     /* 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);
   
     return rinfo;
   }
   
   /* Delete one route from the ECMP list.
    * RETURN:
    *  null - the entry is freed, and other entries exist in the list
    *  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);
       }
   
     /* 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);
   
     return rinfo;
   }
   
   /* Timeout RIP routes. */
   static int
   rip_timeout (struct thread *t)
   {
     rip_ecmp_delete ((struct rip_info *)THREAD_ARG (t));
   return 0;    return 0;
 }  }
   
Line 365  rip_rte_process (struct rte *rte, struct sockaddr_in * Line 489  rip_rte_process (struct rte *rte, struct sockaddr_in *
   int ret;    int ret;
   struct prefix_ipv4 p;    struct prefix_ipv4 p;
   struct route_node *rp;    struct route_node *rp;
  struct rip_info *rinfo, rinfotmp;  struct rip_info *rinfo = NULL, newinfo;
   struct rip_interface *ri;    struct rip_interface *ri;
   struct in_addr *nexthop;    struct in_addr *nexthop;
   u_char oldmetric;  
   int same = 0;    int same = 0;
   int route_reuse = 0;  
   unsigned char old_dist, new_dist;    unsigned char old_dist, new_dist;
     struct list *list = NULL;
     struct listnode *node = NULL;
   
   /* Make prefix structure. */    /* Make prefix structure. */
   memset (&p, 0, sizeof (struct prefix_ipv4));    memset (&p, 0, sizeof (struct prefix_ipv4));
Line 389  rip_rte_process (struct rte *rte, struct sockaddr_in * Line 513  rip_rte_process (struct rte *rte, struct sockaddr_in *
   if (ret < 0)    if (ret < 0)
     return;      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. */    /* Modify entry according to the interface routemap. */
   if (ri->routemap[RIP_FILTER_IN])    if (ri->routemap[RIP_FILTER_IN])
     {      {
       int ret;        int ret;
       struct rip_info newinfo;  
   
       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 */  
   
       /* The object should be of the type of rip_info */        /* The object should be of the type of rip_info */
       ret = route_map_apply (ri->routemap[RIP_FILTER_IN],        ret = route_map_apply (ri->routemap[RIP_FILTER_IN],
                              (struct prefix *) &p, RMAP_RIP, &newinfo);                               (struct prefix *) &p, RMAP_RIP, &newinfo);
Line 433  rip_rte_process (struct rte *rte, struct sockaddr_in * Line 556  rip_rte_process (struct rte *rte, struct sockaddr_in *
   /* If offset-list does not modify the metric use interface's    /* If offset-list does not modify the metric use interface's
      metric. */       metric. */
   if (!ret)    if (!ret)
    rte->metric += ifp->metric;    rte->metric += ifp->metric ? ifp->metric : 1;
   
   if (rte->metric > RIP_METRIC_INFINITY)    if (rte->metric > RIP_METRIC_INFINITY)
     rte->metric = RIP_METRIC_INFINITY;      rte->metric = RIP_METRIC_INFINITY;
Line 455  rip_rte_process (struct rte *rte, struct sockaddr_in * Line 578  rip_rte_process (struct rte *rte, struct sockaddr_in *
   /* Get index for the prefix. */    /* Get index for the prefix. */
   rp = route_node_get (rip->table, (struct prefix *) &p);    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. */    /* Check to see whether there is already RIP route on the table. */
  rinfo = rp->info;  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)    if (rinfo)
     {      {
       /* Local static route. */        /* Local static route. */
Line 474  rip_rte_process (struct rte *rte, struct sockaddr_in * Line 651  rip_rte_process (struct rte *rte, struct sockaddr_in *
       if (rinfo->type != ZEBRA_ROUTE_RIP        if (rinfo->type != ZEBRA_ROUTE_RIP
           && rinfo->metric != RIP_METRIC_INFINITY)            && rinfo->metric != RIP_METRIC_INFINITY)
         {          {
           /* Fill in a minimaly temporary rip_info structure, for a future  
              rip_distance_apply() use) */  
           memset (&rinfotmp, 0, sizeof (rinfotmp));  
           IPV4_ADDR_COPY (&rinfotmp.from, &from->sin_addr);  
           rinfotmp.rp = rinfo->rp;  
           new_dist = rip_distance_apply (&rinfotmp);  
           new_dist = new_dist ? new_dist : ZEBRA_RIP_DISTANCE_DEFAULT;  
           old_dist = rinfo->distance;            old_dist = rinfo->distance;
          /* Only connected routes may have a valid NULL distance */          /* Only routes directly connected to an interface (nexthop == 0)
          if (rinfo->type != ZEBRA_ROUTE_CONNECT)           * may have a valid NULL distance */
           if (rinfo->nexthop.s_addr != 0)
             old_dist = old_dist ? old_dist : ZEBRA_RIP_DISTANCE_DEFAULT;              old_dist = old_dist ? old_dist : ZEBRA_RIP_DISTANCE_DEFAULT;
           /* If imported route does not have STRICT precedence,             /* If imported route does not have STRICT precedence, 
              mark it as a ghost */               mark it as a ghost */
          if (new_dist > old_dist           if (new_dist <= old_dist && rte->metric != RIP_METRIC_INFINITY)
              || rte->metric == RIP_METRIC_INFINITY)            rip_ecmp_replace (&newinfo);
            {
              route_unlock_node (rp);          route_unlock_node (rp);
              return;          return;
            } 
          else 
            { 
              RIP_TIMER_OFF (rinfo->t_timeout); 
              RIP_TIMER_OFF (rinfo->t_garbage_collect); 
                                                                                 
              rp->info = NULL; 
              if (rip_route_rte (rinfo)) 
                rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p,  
                                        &rinfo->nexthop, rinfo->metric); 
              rip_info_free (rinfo); 
              rinfo = NULL; 
              route_reuse = 1; 
            } 
         }          }
     }      }
   
   if (!rinfo)    if (!rinfo)
     {      {
         if (rp->info)
           route_unlock_node (rp);
   
       /* Now, check to see whether there is already an explicit route        /* Now, check to see whether there is already an explicit route
          for the destination prefix.  If there is no such route, add           for the destination prefix.  If there is no such route, add
          this route to the routing table, unless the metric is           this route to the routing table, unless the metric is
          infinity (there is no point in adding a route which           infinity (there is no point in adding a route which
          unusable). */           unusable). */
       if (rte->metric != RIP_METRIC_INFINITY)        if (rte->metric != RIP_METRIC_INFINITY)
        {        rip_ecmp_add (&newinfo);
          rinfo = rip_info_new (); 
 
          /* - Setting the destination prefix and length to those in 
             the RTE. */ 
          rinfo->rp = rp; 
 
          /* - Setting the metric to the newly calculated metric (as 
             described above). */ 
          rinfo->metric = rte->metric; 
          rinfo->tag = ntohs (rte->tag); 
 
          /* - Set the next hop address to be the address of the router 
             from which the datagram came or the next hop address 
             specified by a next hop RTE. */ 
          IPV4_ADDR_COPY (&rinfo->nexthop, nexthop); 
          IPV4_ADDR_COPY (&rinfo->from, &from->sin_addr); 
          rinfo->ifindex = ifp->ifindex; 
 
          /* - Initialize the timeout for the route.  If the 
             garbage-collection timer is running for this route, stop it 
             (see section 2.3 for a discussion of the timers). */ 
          rip_timeout_update (rinfo); 
 
          /* - Set the route change flag. */ 
          rinfo->flags |= RIP_RTF_CHANGED; 
 
          /* - Signal the output process to trigger an update (see section 
             2.5). */ 
          rip_event (RIP_TRIGGERED_UPDATE, 0); 
 
          /* Finally, route goes into the kernel. */ 
          rinfo->type = ZEBRA_ROUTE_RIP; 
          rinfo->sub_type = RIP_ROUTE_RTE; 
 
          /* Set distance value. */ 
          rinfo->distance = rip_distance_apply (rinfo); 
 
          rp->info = rinfo; 
          rip_zebra_ipv4_add (&p, &rinfo->nexthop, rinfo->metric, 
                              rinfo->distance); 
          rinfo->flags |= RIP_RTF_FIB; 
        } 
 
      /* Unlock temporary lock, i.e. same behaviour */ 
      if (route_reuse) 
        route_unlock_node (rp); 
     }      }
   else    else
     {      {
       /* Route is there but we are not sure the route is RIP or not. */        /* Route is there but we are not sure the route is RIP or not. */
       rinfo = rp->info;  
   
       /* If there is an existing route, compare the next hop address        /* If there is an existing route, compare the next hop address
          to the address of the router from which the datagram came.           to the address of the router from which the datagram came.
Line 577  rip_rte_process (struct rte *rte, struct sockaddr_in * Line 690  rip_rte_process (struct rte *rte, struct sockaddr_in *
       same = (IPV4_ADDR_SAME (&rinfo->from, &from->sin_addr)        same = (IPV4_ADDR_SAME (&rinfo->from, &from->sin_addr)
               && (rinfo->ifindex == ifp->ifindex));                && (rinfo->ifindex == ifp->ifindex));
   
      if (same)      old_dist = rinfo->distance ? \
        rip_timeout_update (rinfo);                 rinfo->distance : ZEBRA_RIP_DISTANCE_DEFAULT;
   
   
       /* Fill in a minimaly temporary rip_info structure, for a future  
          rip_distance_apply() use) */  
       memset (&rinfotmp, 0, sizeof (rinfotmp));  
       IPV4_ADDR_COPY (&rinfotmp.from, &from->sin_addr);  
       rinfotmp.rp = rinfo->rp;  
   
   
       /* Next, compare the metrics.  If the datagram is from the same        /* Next, compare the metrics.  If the datagram is from the same
          router as the existing route, and the new metric is different           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           than the old one; or, if the new metric is lower than the old
Line 598  rip_rte_process (struct rte *rte, struct sockaddr_in * Line 703  rip_rte_process (struct rte *rte, struct sockaddr_in *
           || (rte->metric < rinfo->metric)            || (rte->metric < rinfo->metric)
           || ((same)            || ((same)
               && (rinfo->metric == rte->metric)                && (rinfo->metric == rte->metric)
              && ntohs (rte->tag) != rinfo->tag)              && (newinfo.tag != rinfo->tag))
          || (rinfo->distance > rip_distance_apply (&rinfotmp))          || (old_dist > new_dist)
          || ((rinfo->distance != rip_distance_apply (rinfo)) && same))          || ((old_dist != new_dist) && same))
         {          {
          /* - Adopt the route from the datagram.  That is, put the          if (listcount (list) == 1)
             new metric in, and adjust the next hop address (if 
             necessary). */ 
          oldmetric = rinfo->metric; 
          rinfo->metric = rte->metric; 
          rinfo->tag = ntohs (rte->tag); 
          IPV4_ADDR_COPY (&rinfo->from, &from->sin_addr); 
          rinfo->ifindex = ifp->ifindex; 
          rinfo->distance = rip_distance_apply (rinfo); 
 
          /* Should a new route to this network be established 
             while the garbage-collection timer is running, the 
             new route will replace the one that is about to be 
             deleted.  In this case the garbage-collection timer 
             must be cleared. */ 
 
          if (oldmetric == RIP_METRIC_INFINITY && 
              rinfo->metric < RIP_METRIC_INFINITY) 
             {              {
              rinfo->type = ZEBRA_ROUTE_RIP;              if (newinfo.metric != RIP_METRIC_INFINITY)
              rinfo->sub_type = RIP_ROUTE_RTE;                rip_ecmp_replace (&newinfo);
              else
              RIP_TIMER_OFF (rinfo->t_garbage_collect);                rip_ecmp_delete (rinfo);
 
              if (!IPV4_ADDR_SAME (&rinfo->nexthop, nexthop)) 
                IPV4_ADDR_COPY (&rinfo->nexthop, nexthop); 
 
              rip_zebra_ipv4_add (&p, nexthop, rinfo->metric, 
                                  rinfo->distance); 
              rinfo->flags |= RIP_RTF_FIB; 
             }              }
          else
          /* Update nexthop and/or metric value.  */ 
          if (oldmetric != RIP_METRIC_INFINITY) 
             {              {
              rip_zebra_ipv4_delete (&p, &rinfo->nexthop, oldmetric);              if (newinfo.metric < rinfo->metric)
              rip_zebra_ipv4_add (&p, nexthop, rinfo->metric,                rip_ecmp_replace (&newinfo);
                                  rinfo->distance);              else if (newinfo.metric > rinfo->metric)
              rinfo->flags |= RIP_RTF_FIB;                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;
   
              if (!IPV4_ADDR_SAME (&rinfo->nexthop, nexthop))                  assert (newinfo.metric != RIP_METRIC_INFINITY);
                IPV4_ADDR_COPY (&rinfo->nexthop, nexthop); 
            } 
   
           /* - Set the route change flag and signal the output process  
              to trigger an update. */  
           rinfo->flags |= RIP_RTF_CHANGED;  
           rip_event (RIP_TRIGGERED_UPDATE, 0);  
   
           /* - If the new metric is infinity, start the deletion  
              process (described above); */  
           if (rinfo->metric == RIP_METRIC_INFINITY)  
             {  
               /* If the new metric is infinity, the deletion process  
                  begins for the route, which is no longer used for  
                  routing packets.  Note that the deletion process is  
                  started only when the metric is first set to  
                  infinity.  If the metric was already infinity, then a  
                  new deletion process is not started. */  
               if (oldmetric != RIP_METRIC_INFINITY)  
                 {  
                   /* - The garbage-collection timer is set for 120 seconds. */  
                   RIP_TIMER_ON (rinfo->t_garbage_collect,  
                                 rip_garbage_collect, rip->garbage_time);  
                   RIP_TIMER_OFF (rinfo->t_timeout);                    RIP_TIMER_OFF (rinfo->t_timeout);
                     RIP_TIMER_OFF (rinfo->t_garbage_collect);
                     memcpy (rinfo, &newinfo, sizeof (struct rip_info));
                     rip_timeout_update (rinfo);
   
                  /* - The metric for the route is set to 16                  if (update)
                     (infinity).  This causes the route to be removed                    rip_zebra_ipv4_add (rp);
                     from service. */ 
                  rip_zebra_ipv4_delete (&p, &rinfo->nexthop, oldmetric); 
                  rinfo->flags &= ~RIP_RTF_FIB; 
   
                  /* - The route change flag is to indicate that this                  /* - Set the route change flag on the first entry. */
                     entry has been changed. */                  rinfo = listgetdata (listhead (list));
                  /* - The output process is signalled to trigger a                  SET_FLAG (rinfo->flags, RIP_RTF_CHANGED);
                     response. */                  rip_event (RIP_TRIGGERED_UPDATE, 0);
                  ;             /* Above processes are already done previously. */ 
                 }                  }
             }              }
           else  
             {  
               /* otherwise, re-initialize the timeout. */  
               rip_timeout_update (rinfo);  
             }  
         }          }
         else /* same & no change */
           rip_timeout_update (rinfo);
   
       /* Unlock tempolary lock of the route. */        /* Unlock tempolary lock of the route. */
       route_unlock_node (rp);        route_unlock_node (rp);
     }      }
Line 1107  rip_response_process (struct rip_packet *packet, int s Line 1168  rip_response_process (struct rip_packet *packet, int s
   struct prefix_ipv4 ifaddr;    struct prefix_ipv4 ifaddr;
   struct prefix_ipv4 ifaddrclass;    struct prefix_ipv4 ifaddrclass;
   int subnetted;    int subnetted;
      
   memset(&ifaddr, 0, sizeof(ifaddr));
   /* We don't know yet. */    /* We don't know yet. */
   subnetted = -1;    subnetted = -1;
   
Line 1515  rip_send_packet (u_char * buf, int size, struct sockad Line 1577  rip_send_packet (u_char * buf, int size, struct sockad
 /* Add redistributed route to RIP table. */  /* Add redistributed route to RIP table. */
 void  void
 rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p,   rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p, 
                      unsigned int ifindex, struct in_addr *nexthop,                      ifindex_t ifindex, struct in_addr *nexthop,
                       unsigned int metric, unsigned char distance)                        unsigned int metric, unsigned char distance)
 {  {
   int ret;    int ret;
  struct route_node *rp;  struct route_node *rp = NULL;
  struct rip_info *rinfo;  struct rip_info *rinfo = NULL, newinfo;
   struct list *list = NULL;
   
   /* Redistribute route  */    /* Redistribute route  */
   ret = rip_destination_check (p->prefix);    ret = rip_destination_check (p->prefix);
Line 1529  rip_redistribute_add (int type, int sub_type, struct p Line 1592  rip_redistribute_add (int type, int sub_type, struct p
   
   rp = route_node_get (rip->table, (struct prefix *) p);    rp = route_node_get (rip->table, (struct prefix *) p);
   
  rinfo = rp->info;  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;
   newinfo.rp = rp;
   if (nexthop)
     newinfo.nexthop = *nexthop;
   
  if (rinfo)  if ((list = rp->info) != NULL && listcount (list) != 0)
     {      {
         rinfo = listgetdata (listhead (list));
   
       if (rinfo->type == ZEBRA_ROUTE_CONNECT         if (rinfo->type == ZEBRA_ROUTE_CONNECT 
           && rinfo->sub_type == RIP_ROUTE_INTERFACE            && rinfo->sub_type == RIP_ROUTE_INTERFACE
           && rinfo->metric != RIP_METRIC_INFINITY)            && rinfo->metric != RIP_METRIC_INFINITY)
Line 1554  rip_redistribute_add (int type, int sub_type, struct p Line 1628  rip_redistribute_add (int type, int sub_type, struct p
             }              }
         }          }
   
      RIP_TIMER_OFF (rinfo->t_timeout);      rinfo = rip_ecmp_replace (&newinfo);
      RIP_TIMER_OFF (rinfo->t_garbage_collect);      route_unlock_node (rp);
 
      if (rip_route_rte (rinfo)) 
        rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p, &rinfo->nexthop, 
                               rinfo->metric); 
      rp->info = NULL; 
      rip_info_free (rinfo); 
       
      route_unlock_node (rp);       
     }      }
     else
       rinfo = rip_ecmp_add (&newinfo);
   
   rinfo = rip_info_new ();  
       
   rinfo->type = type;  
   rinfo->sub_type = sub_type;  
   rinfo->ifindex = ifindex;  
   rinfo->metric = 1;  
   rinfo->external_metric = metric;  
   rinfo->distance = distance;  
   rinfo->rp = rp;  
   
   if (nexthop)  
     rinfo->nexthop = *nexthop;  
   
   rinfo->flags |= RIP_RTF_FIB;  
   rp->info = rinfo;  
   
   rinfo->flags |= RIP_RTF_CHANGED;  
   
   if (IS_RIP_DEBUG_EVENT) {    if (IS_RIP_DEBUG_EVENT) {
     if (!nexthop)      if (!nexthop)
       zlog_debug ("Redistribute new prefix %s/%d on the interface %s",        zlog_debug ("Redistribute new prefix %s/%d on the interface %s",
Line 1595  rip_redistribute_add (int type, int sub_type, struct p Line 1645  rip_redistribute_add (int type, int sub_type, struct p
                  ifindex2ifname(ifindex));                   ifindex2ifname(ifindex));
   }    }
   
   
   rip_event (RIP_TRIGGERED_UPDATE, 0);    rip_event (RIP_TRIGGERED_UPDATE, 0);
 }  }
   
 /* Delete redistributed route from RIP table. */  /* Delete redistributed route from RIP table. */
 void  void
 rip_redistribute_delete (int type, int sub_type, struct prefix_ipv4 *p,   rip_redistribute_delete (int type, int sub_type, struct prefix_ipv4 *p, 
                           unsigned int ifindex)                         ifindex_t ifindex)
 {  {
   int ret;    int ret;
   struct route_node *rp;    struct route_node *rp;
Line 1615  rip_redistribute_delete (int type, int sub_type, struc Line 1664  rip_redistribute_delete (int type, int sub_type, struc
   rp = route_node_lookup (rip->table, (struct prefix *) p);    rp = route_node_lookup (rip->table, (struct prefix *) p);
   if (rp)    if (rp)
     {      {
      rinfo = rp->info;      struct list *list = rp->info;
   
      if (rinfo != NULL      if (list != NULL && listcount (list) != 0)
          && rinfo->type == type         {
          && rinfo->sub_type == sub_type           rinfo = listgetdata (listhead (list));
          && rinfo->ifindex == ifindex)          if (rinfo != NULL
        {              && rinfo->type == type
          /* Perform poisoned reverse. */              && rinfo->sub_type == sub_type
          rinfo->metric = RIP_METRIC_INFINITY;              && rinfo->ifindex == ifindex)
          RIP_TIMER_ON (rinfo->t_garbage_collect,             {
                        rip_garbage_collect, rip->garbage_time);              /* Perform poisoned reverse. */
          RIP_TIMER_OFF (rinfo->t_timeout);              rinfo->metric = RIP_METRIC_INFINITY;
          rinfo->flags |= RIP_RTF_CHANGED;              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)              if (IS_RIP_DEBUG_EVENT)
            zlog_debug ("Poisone %s/%d on the interface %s with an infinity metric [delete]",                zlog_debug ("Poisone %s/%d on the interface %s with an "
                       inet_ntoa(p->prefix), p->prefixlen,                            "infinity metric [delete]",
                       ifindex2ifname(ifindex));                            inet_ntoa(p->prefix), p->prefixlen,
                             ifindex2ifname(ifindex));
   
          rip_event (RIP_TRIGGERED_UPDATE, 0);              rip_event (RIP_TRIGGERED_UPDATE, 0);
        }            }
         }
       route_unlock_node (rp);
     }      }
 }  }
   
Line 1683  rip_request_process (struct rip_packet *packet, int si Line 1738  rip_request_process (struct rip_packet *packet, int si
       ntohs (rte->family) == 0 &&        ntohs (rte->family) == 0 &&
       ntohl (rte->metric) == RIP_METRIC_INFINITY)        ntohl (rte->metric) == RIP_METRIC_INFINITY)
     {         {   
       struct prefix_ipv4 saddr;  
   
       /* saddr will be used for determining which routes to split-horizon.  
          Since the source address we'll pick will be on the same subnet as the  
          destination, for the purpose of split-horizoning, we'll  
          pretend that "from" is our source address.  */  
       saddr.family = AF_INET;  
       saddr.prefixlen = IPV4_MAX_BITLEN;  
       saddr.prefix = from->sin_addr;  
   
       /* All route with split horizon */        /* All route with split horizon */
       rip_output_process (ifc, from, rip_all_route, packet->version);        rip_output_process (ifc, from, rip_all_route, packet->version);
     }      }
Line 1717  rip_request_process (struct rip_packet *packet, int si Line 1762  rip_request_process (struct rip_packet *packet, int si
           rp = route_node_lookup (rip->table, (struct prefix *) &p);            rp = route_node_lookup (rip->table, (struct prefix *) &p);
           if (rp)            if (rp)
             {              {
              rinfo = rp->info;              rinfo = listgetdata (listhead ((struct list *)rp->info));
               rte->metric = htonl (rinfo->metric);                rte->metric = htonl (rinfo->metric);
               route_unlock_node (rp);                route_unlock_node (rp);
             }              }
Line 1748  setsockopt_pktinfo (int sock) Line 1793  setsockopt_pktinfo (int sock)
 /* Read RIP packet by recvmsg function. */  /* Read RIP packet by recvmsg function. */
 int  int
 rip_recvmsg (int sock, u_char *buf, int size, struct sockaddr_in *from,  rip_recvmsg (int sock, u_char *buf, int size, struct sockaddr_in *from,
             int *ifindex)             ifindex_t *ifindex)
 {  {
   int ret;    int ret;
   struct msghdr msg;    struct msghdr msg;
Line 1789  rip_read_new (struct thread *t) Line 1834  rip_read_new (struct thread *t)
   int sock;    int sock;
   char buf[RIP_PACKET_MAXSIZ];    char buf[RIP_PACKET_MAXSIZ];
   struct sockaddr_in from;    struct sockaddr_in from;
  unsigned int ifindex;  ifindex_t ifindex;
       
   /* Fetch socket then register myself. */    /* Fetch socket then register myself. */
   sock = THREAD_FD (t);    sock = THREAD_FD (t);
Line 2152  rip_output_process (struct connected *ifc, struct sock Line 2197  rip_output_process (struct connected *ifc, struct sock
   int num = 0;    int num = 0;
   int rtemax;    int rtemax;
   int subnetted = 0;    int subnetted = 0;
     struct list *list = NULL;
     struct listnode *listnode = NULL;
   
   /* Logging output event. */    /* Logging output event. */
   if (IS_RIP_DEBUG_EVENT)    if (IS_RIP_DEBUG_EVENT)
Line 2168  rip_output_process (struct connected *ifc, struct sock Line 2215  rip_output_process (struct connected *ifc, struct sock
   
   /* Reset stream and RTE counter. */    /* Reset stream and RTE counter. */
   stream_reset (s);    stream_reset (s);
  rtemax = (RIP_PACKET_MAXSIZ - 4) / 20;  rtemax = RIP_MAX_RTE;
   
   /* Get RIP interface. */    /* Get RIP interface. */
   ri = ifc->ifp->info;    ri = ifc->ifp->info;
Line 2209  rip_output_process (struct connected *ifc, struct sock Line 2256  rip_output_process (struct connected *ifc, struct sock
     }      }
   
   for (rp = route_top (rip->table); rp; rp = route_next (rp))    for (rp = route_top (rip->table); rp; rp = route_next (rp))
    if ((rinfo = rp->info) != NULL)    if ((list = rp->info) != NULL && listcount (list) != 0)
       {        {
           rinfo = listgetdata (listhead (list));
         /* For RIPv1, if we are subnetted, output subnets in our network    */          /* For RIPv1, if we are subnetted, output subnets in our network    */
         /* that have the same mask as the output "interface". For other     */          /* that have the same mask as the output "interface". For other     */
         /* networks, only the classfull version is output.                  */          /* networks, only the classfull version is output.                  */
Line 2269  rip_output_process (struct connected *ifc, struct sock Line 2317  rip_output_process (struct connected *ifc, struct sock
              * (in order to handle the case when multiple subnets are               * (in order to handle the case when multiple subnets are
              * configured on the same interface).               * configured on the same interface).
              */               */
            if (rinfo->type == ZEBRA_ROUTE_RIP  &&            int suppress = 0;
                 rinfo->ifindex == ifc->ifp->ifindex)             struct rip_info *tmp_rinfo = NULL;
              continue;
            if (rinfo->type == ZEBRA_ROUTE_CONNECT &&            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))                   prefix_match((struct prefix *)p, ifc->address))
                 suppress = 1;
   
               if (suppress)
               continue;                continue;
           }            }
   
Line 2367  rip_output_process (struct connected *ifc, struct sock Line 2426  rip_output_process (struct connected *ifc, struct sock
              * (in order to handle the case when multiple subnets are               * (in order to handle the case when multiple subnets are
              * configured on the same interface).               * configured on the same interface).
              */               */
          if (rinfo->type == ZEBRA_ROUTE_RIP  &&          struct rip_info *tmp_rinfo = NULL;
               rinfo->ifindex == ifc->ifp->ifindex)
               rinfo->metric_out = RIP_METRIC_INFINITY;          for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo))
          if (rinfo->type == ZEBRA_ROUTE_CONNECT &&            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))                prefix_match((struct prefix *)p, ifc->address))
               rinfo->metric_out = RIP_METRIC_INFINITY;            rinfo->metric_out = RIP_METRIC_INFINITY;
         }          }
                   
         /* Prepare preamble, auth headers, if needs be */          /* Prepare preamble, auth headers, if needs be */
Line 2512  rip_update_process (int route_type) Line 2574  rip_update_process (int route_type)
   
           if (IS_RIP_DEBUG_EVENT)             if (IS_RIP_DEBUG_EVENT) 
             zlog_debug("SEND UPDATE to %s ifindex %d",              zlog_debug("SEND UPDATE to %s ifindex %d",
                       (ifp->name ? ifp->name : "_unknown_"), ifp->ifindex);                       ifp->name, ifp->ifindex);
   
           /* send update on each connected network */            /* send update on each connected network */
           for (ALL_LIST_ELEMENTS (ifp->connected, ifnode, ifnnode, connected))            for (ALL_LIST_ELEMENTS (ifp->connected, ifnode, ifnnode, connected))
Line 2592  static void Line 2654  static void
 rip_clear_changed_flag (void)  rip_clear_changed_flag (void)
 {  {
   struct route_node *rp;    struct route_node *rp;
  struct rip_info *rinfo;  struct rip_info *rinfo = NULL;
   struct list *list = NULL;
   struct listnode *listnode = NULL;
   
   for (rp = route_top (rip->table); rp; rp = route_next (rp))    for (rp = route_top (rip->table); rp; rp = route_next (rp))
    if ((rinfo = rp->info) != NULL)    if ((list = rp->info) != NULL)
      if (rinfo->flags & RIP_RTF_CHANGED)      for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
        rinfo->flags &= ~RIP_RTF_CHANGED;        {
           UNSET_FLAG (rinfo->flags, RIP_RTF_CHANGED);
           /* This flag can be set only on the first entry. */
           break;
         }
 }  }
   
 /* Triggered update interval timer. */  /* Triggered update interval timer. */
Line 2662  void Line 2730  void
 rip_redistribute_withdraw (int type)  rip_redistribute_withdraw (int type)
 {  {
   struct route_node *rp;    struct route_node *rp;
  struct rip_info *rinfo;  struct rip_info *rinfo = NULL;
   struct list *list = NULL;
   
   if (!rip)    if (!rip)
     return;      return;
   
   for (rp = route_top (rip->table); rp; rp = route_next (rp))    for (rp = route_top (rip->table); rp; rp = route_next (rp))
    if ((rinfo = rp->info) != NULL)    if ((list = rp->info) != NULL)
       {        {
           rinfo = listgetdata (listhead (list));
         if (rinfo->type == type          if (rinfo->type == type
             && rinfo->sub_type != RIP_ROUTE_INTERFACE)              && rinfo->sub_type != RIP_ROUTE_INTERFACE)
           {            {
Line 2773  rip_request_send (struct sockaddr_in *to, struct inter Line 2843  rip_request_send (struct sockaddr_in *to, struct inter
     }      }
   return sizeof (rip_packet);    return sizeof (rip_packet);
 }  }
 static int  static int
 rip_update_jitter (unsigned long time)  rip_update_jitter (unsigned long time)
 {  {
Line 2790  rip_update_jitter (unsigned long time) Line 2860  rip_update_jitter (unsigned long time)
   if (jitter_input < JITTER_BOUND)    if (jitter_input < JITTER_BOUND)
     jitter_input = JITTER_BOUND;      jitter_input = JITTER_BOUND;
       
  jitter = (((rand () % ((jitter_input * 2) + 1)) - jitter_input));    jitter = (((random () % ((jitter_input * 2) + 1)) - jitter_input));  
   
   return jitter/JITTER_BOUND;    return jitter/JITTER_BOUND;
 }  }
Line 2827  rip_event (enum rip_event event, int sock) Line 2897  rip_event (enum rip_event event, int sock)
       break;        break;
     }      }
 }  }
 DEFUN (router_rip,  DEFUN (router_rip,
        router_rip_cmd,         router_rip_cmd,
        "router rip",         "router rip",
Line 2982  static void Line 3052  static void
 rip_update_default_metric (void)  rip_update_default_metric (void)
 {  {
   struct route_node *np;    struct route_node *np;
  struct rip_info *rinfo;  struct rip_info *rinfo = NULL;
   struct list *list = NULL;
   struct listnode *listnode = NULL;
   
   for (np = route_top (rip->table); np; np = route_next (np))    for (np = route_top (rip->table); np; np = route_next (np))
    if ((rinfo = np->info) != NULL)    if ((list = np->info) != NULL)
      if (rinfo->type != ZEBRA_ROUTE_RIP && rinfo->type != ZEBRA_ROUTE_CONNECT)      for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
        rinfo->metric = rip->default_metric;        if (rinfo->type != ZEBRA_ROUTE_RIP && rinfo->type != ZEBRA_ROUTE_CONNECT)
           rinfo->metric = rip->default_metric;
 }  }
 #endif  #endif
   
Line 3103  ALIAS (no_rip_timers, Line 3176  ALIAS (no_rip_timers,
        "Routing information timeout timer. Default is 180.\n"         "Routing information timeout timer. Default is 180.\n"
        "Garbage collection timer. Default is 120.\n")         "Garbage collection timer. Default is 120.\n")
   
 struct route_table *rip_distance_table;  struct route_table *rip_distance_table;
   
 struct rip_distance  struct rip_distance
Line 3180  rip_distance_unset (struct vty *vty, const char *dista Line 3253  rip_distance_unset (struct vty *vty, const char *dista
 {  {
   int ret;    int ret;
   struct prefix_ipv4 p;    struct prefix_ipv4 p;
   u_char distance;  
   struct route_node *rn;    struct route_node *rn;
   struct rip_distance *rdistance;    struct rip_distance *rdistance;
   
Line 3191  rip_distance_unset (struct vty *vty, const char *dista Line 3263  rip_distance_unset (struct vty *vty, const char *dista
       return CMD_WARNING;        return CMD_WARNING;
     }      }
   
   distance = atoi (distance_str);  
   
   rn = route_node_lookup (rip_distance_table, (struct prefix *)&p);    rn = route_node_lookup (rip_distance_table, (struct prefix *)&p);
   if (! rn)    if (! rn)
     {      {
Line 3371  DEFUN (no_rip_distance_source_access_list, Line 3441  DEFUN (no_rip_distance_source_access_list,
   rip_distance_unset (vty, argv[0], argv[1], argv[2]);    rip_distance_unset (vty, argv[0], argv[1], argv[2]);
   return CMD_SUCCESS;    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);
       }
 }
 
 DEFUN (rip_allow_ecmp,
        rip_allow_ecmp_cmd,
        "allow-ecmp",
        "Allow Equal Cost MultiPath\n")
 {
   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;
 }
 
 DEFUN (no_rip_allow_ecmp,
        no_rip_allow_ecmp_cmd,
        "no 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;
     }
 
   rip->ecmp = 0;
   zlog_info ("ECMP is disabled.");
   rip_ecmp_disable ();
   return CMD_SUCCESS;
 }
 
 /* Print out routes update time. */  /* Print out routes update time. */
 static void  static void
 rip_vty_out_uptime (struct vty *vty, struct rip_info *rinfo)  rip_vty_out_uptime (struct vty *vty, struct rip_info *rinfo)
Line 3426  DEFUN (show_ip_rip, Line 3570  DEFUN (show_ip_rip,
        "Show RIP routes\n")         "Show RIP routes\n")
 {  {
   struct route_node *np;    struct route_node *np;
  struct rip_info *rinfo;  struct rip_info *rinfo = NULL;
   struct list *list = NULL;
   struct listnode *listnode = NULL;
   
   if (! rip)    if (! rip)
     return CMD_SUCCESS;      return CMD_SUCCESS;
Line 3439  DEFUN (show_ip_rip, Line 3585  DEFUN (show_ip_rip,
            VTY_NEWLINE, VTY_NEWLINE,  VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);             VTY_NEWLINE, VTY_NEWLINE,  VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
       
   for (np = route_top (rip->table); np; np = route_next (np))    for (np = route_top (rip->table); np; np = route_next (np))
    if ((rinfo = np->info) != NULL)    if ((list = np->info) != NULL)
       for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
       {        {
         int len;          int len;
   
Line 3676  config_write_rip (struct vty *vty) Line 3823  config_write_rip (struct vty *vty)
                    rdistance->access_list ? rdistance->access_list : "",                     rdistance->access_list ? rdistance->access_list : "",
                    VTY_NEWLINE);                     VTY_NEWLINE);
   
         /* ECMP configuration. */
         if (rip->ecmp)
           vty_out (vty, " allow-ecmp%s", VTY_NEWLINE);
   
       /* RIP static route configuration. */        /* RIP static route configuration. */
       for (rn = route_top (rip->route); rn; rn = route_next (rn))        for (rn = route_top (rip->route); rn; rn = route_next (rn))
         if (rn->info)          if (rn->info)
Line 3695  static struct cmd_node rip_node = Line 3846  static struct cmd_node rip_node =
   "%s(config-router)# ",    "%s(config-router)# ",
   1    1
 };  };
 /* Distribute-list update functions. */  /* Distribute-list update functions. */
 static void  static void
 rip_distribute_update (struct distribute *dist)  rip_distribute_update (struct distribute *dist)
Line 3786  rip_distribute_update_all_wrapper(struct access_list * Line 3937  rip_distribute_update_all_wrapper(struct access_list *
 {  {
         rip_distribute_update_all(NULL);          rip_distribute_update_all(NULL);
 }  }
 /* Delete all added rip route. */  /* Delete all added rip route. */
 void  void
 rip_clean (void)  rip_clean (void)
 {  {
   int i;    int i;
   struct route_node *rp;    struct route_node *rp;
  struct rip_info *rinfo;  struct rip_info *rinfo = NULL;
   struct list *list = NULL;
   struct listnode *listnode = NULL;
   
   if (rip)    if (rip)
     {      {
       /* Clear RIP routes */        /* Clear RIP routes */
       for (rp = route_top (rip->table); rp; rp = route_next (rp))        for (rp = route_top (rip->table); rp; rp = route_next (rp))
        if ((rinfo = rp->info) != NULL)        if ((list = rp->info) != NULL)
          {          {
            if (rinfo->type == ZEBRA_ROUTE_RIP &&            rinfo = listgetdata (listhead (list));
                rinfo->sub_type == RIP_ROUTE_RTE)            if (rip_route_rte (rinfo))
              rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p,              rip_zebra_ipv4_delete (rp);
                                     &rinfo->nexthop, rinfo->metric); 
         
            RIP_TIMER_OFF (rinfo->t_timeout); 
            RIP_TIMER_OFF (rinfo->t_garbage_collect); 
   
            rp->info = NULL;            for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
            route_unlock_node (rp);              {
                 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);
           }
   
             rip_info_free (rinfo);  
           }  
   
       /* Cancel RIP related timers. */        /* Cancel RIP related timers. */
       RIP_TIMER_OFF (rip->t_update);        RIP_TIMER_OFF (rip->t_update);
       RIP_TIMER_OFF (rip->t_triggered_update);        RIP_TIMER_OFF (rip->t_triggered_update);
Line 3979  void Line 4133  void
 rip_init (void)  rip_init (void)
 {  {
   /* Randomize for triggered update random(). */    /* Randomize for triggered update random(). */
  srand (time (NULL));  srandom (time (NULL));
   
   /* Install top nodes. */    /* Install top nodes. */
   install_node (&rip_node, config_write_rip);    install_node (&rip_node, config_write_rip);
Line 4010  rip_init (void) Line 4164  rip_init (void)
   install_element (RIP_NODE, &no_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, &rip_distance_source_access_list_cmd);
   install_element (RIP_NODE, &no_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. */    /* Debug related init. */
   rip_debug_init ();    rip_debug_init ();

Removed from v.1.1.1.2  
changed lines
  Added in v.1.1.1.3


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>