Diff for /embedaddon/quagga/zebra/zebra_rib.c between versions 1.1.1.2 and 1.1.1.4

version 1.1.1.2, 2012/10/09 09:22:29 version 1.1.1.4, 2016/11/02 10:09:10
Line 34 Line 34
 #include "workqueue.h"  #include "workqueue.h"
 #include "prefix.h"  #include "prefix.h"
 #include "routemap.h"  #include "routemap.h"
   #include "vrf.h"
   
 #include "zebra/rib.h"  #include "zebra/rib.h"
 #include "zebra/rt.h"  #include "zebra/rt.h"
 #include "zebra/zserv.h"  #include "zebra/zserv.h"
 #include "zebra/redistribute.h"  #include "zebra/redistribute.h"
 #include "zebra/debug.h"  #include "zebra/debug.h"
   #include "zebra/zebra_fpm.h"
   
 /* Default rtm_table for all clients */  /* Default rtm_table for all clients */
 extern struct zebra_t zebrad;  extern struct zebra_t zebrad;
Line 70  static const struct Line 72  static const struct
   [ZEBRA_ROUTE_BABEL]   = {ZEBRA_ROUTE_BABEL,    95},    [ZEBRA_ROUTE_BABEL]   = {ZEBRA_ROUTE_BABEL,    95},
   /* no entry/default: 150 */    /* no entry/default: 150 */
 };  };
   
 /* Vector for routing table.  */  
 static vector vrf_vector;  
   
/* Allocate new VRF.  *//* RPF lookup behaviour */
static struct vrf *static enum multicast_mode ipv4_multicast_mode = MCAST_NO_CONFIG;
vrf_alloc (const char *name) 
{ 
  struct vrf *vrf; 
   
  vrf = XCALLOC (MTYPE_VRF, sizeof (struct vrf));static void __attribute__((format (printf, 4, 5)))
_rnode_zlog(const char *_func, struct route_node *rn, int priority,
  /* Put name.  */            const char *msgfmt, ...)
  if (name) 
    vrf->name = XSTRDUP (MTYPE_VRF_NAME, name); 
 
  /* Allocate routing table and static table.  */ 
  vrf->table[AFI_IP][SAFI_UNICAST] = route_table_init (); 
  vrf->table[AFI_IP6][SAFI_UNICAST] = route_table_init (); 
  vrf->stable[AFI_IP][SAFI_UNICAST] = route_table_init (); 
  vrf->stable[AFI_IP6][SAFI_UNICAST] = route_table_init (); 
  vrf->table[AFI_IP][SAFI_MULTICAST] = route_table_init (); 
  vrf->table[AFI_IP6][SAFI_MULTICAST] = route_table_init (); 
  vrf->stable[AFI_IP][SAFI_MULTICAST] = route_table_init (); 
  vrf->stable[AFI_IP6][SAFI_MULTICAST] = route_table_init (); 
 
 
  return vrf; 
} 
 
/* Lookup VRF by identifier.  */ 
struct vrf * 
vrf_lookup (u_int32_t id) 
 {  {
  return vector_lookup (vrf_vector, id);  char prefix[PREFIX_STRLEN], buf[256];
}  char msgbuf[512];
   va_list ap;
   
/* Initialize VRF.  */  va_start(ap, msgfmt);
static void  vsnprintf(msgbuf, sizeof(msgbuf), msgfmt, ap);
vrf_init (void)  va_end(ap);
{ 
  struct vrf *default_table; 
   
  /* Allocate VRF vector.  */  if (rn)
  vrf_vector = vector_init (1);    {
       rib_table_info_t *info = rn->table->info;
   
  /* Allocate default main table.  */      snprintf(buf, sizeof(buf), "%s%s vrf %u",
  default_table = vrf_alloc ("Default-IP-Routing-Table");               prefix2str(&rn->p, prefix, sizeof(prefix)),
                info->safi == SAFI_MULTICAST ? " (MRIB)" : "",
                info->zvrf->vrf_id);
     }
   else
     {
       snprintf(buf, sizeof(buf), "{(route_node *) NULL}");
     }
   
  /* Default table index must be 0.  */  zlog (NULL, priority, "%s: %s: %s", _func, buf, msgbuf);
  vector_set_index (vrf_vector, 0, default_table); 
 }  }
   
/* Lookup route table.  */#define rnode_debug(node, ...) \
struct route_table *        _rnode_zlog(__func__, node, LOG_DEBUG, __VA_ARGS__)
vrf_table (afi_t afi, safi_t safi, u_int32_t id)#define rnode_info(node, ...) \
{        _rnode_zlog(__func__, node, LOG_INFO, __VA_ARGS__)
  struct vrf *vrf; 
   
  vrf = vrf_lookup (id);/*
  if (! vrf) * nexthop_type_to_str
    return NULL; */
const char *
  return vrf->table[afi][safi];nexthop_type_to_str (enum nexthop_types_t nh_type)
} 
 
/* Lookup static route table.  */ 
struct route_table * 
vrf_static_table (afi_t afi, safi_t safi, u_int32_t id) 
 {  {
  struct vrf *vrf;  static const char *desc[] = {
     "none",
     "Directly connected",
     "Interface route",
     "IPv4 nexthop",
     "IPv4 nexthop with ifindex",
     "IPv4 nexthop with ifname",
     "IPv6 nexthop",
     "IPv6 nexthop with ifindex",
     "IPv6 nexthop with ifname",
     "Null0 nexthop",
   };
   
  vrf = vrf_lookup (id);  if (nh_type >= ZEBRA_NUM_OF (desc))
  if (! vrf)    return "<Invalid nh type>";
    return NULL; 
   
  return vrf->stable[afi][safi];  return desc[nh_type];
 }  }
/* Add nexthop to the end of the list.  *//* Add nexthop to the end of a nexthop list.  */
 static void  static void
nexthop_add (struct rib *rib, struct nexthop *nexthop)_nexthop_add (struct nexthop **target, struct nexthop *nexthop)
 {  {
   struct nexthop *last;    struct nexthop *last;
   
  for (last = rib->nexthop; last && last->next; last = last->next)  for (last = *target; last && last->next; last = last->next)
     ;      ;
   if (last)    if (last)
     last->next = nexthop;      last->next = nexthop;
   else    else
    rib->nexthop = nexthop;    *target = nexthop;
   nexthop->prev = last;    nexthop->prev = last;
   }
   
   /* Add nexthop to the end of a rib node's nexthop list */
   static void
   nexthop_add (struct rib *rib, struct nexthop *nexthop)
   {
     _nexthop_add(&rib->nexthop, nexthop);
   rib->nexthop_num++;    rib->nexthop_num++;
 }  }
   
Line 179  nexthop_delete (struct rib *rib, struct nexthop *nexth Line 171  nexthop_delete (struct rib *rib, struct nexthop *nexth
   rib->nexthop_num--;    rib->nexthop_num--;
 }  }
   
   static void nexthops_free(struct nexthop *nexthop);
   
 /* Free nexthop. */  /* Free nexthop. */
 static void  static void
 nexthop_free (struct nexthop *nexthop)  nexthop_free (struct nexthop *nexthop)
 {  {
   if (nexthop->ifname)    if (nexthop->ifname)
     XFREE (0, nexthop->ifname);      XFREE (0, nexthop->ifname);
     if (nexthop->resolved)
       nexthops_free(nexthop->resolved);
   XFREE (MTYPE_NEXTHOP, nexthop);    XFREE (MTYPE_NEXTHOP, nexthop);
 }  }
   
   /* Frees a list of nexthops */
   static void
   nexthops_free (struct nexthop *nexthop)
   {
     struct nexthop *nh, *next;
   
     for (nh = nexthop; nh; nh = next)
       {
         next = nh->next;
         nexthop_free (nh);
       }
   }
   
 struct nexthop *  struct nexthop *
nexthop_ifindex_add (struct rib *rib, unsigned int ifindex)nexthop_ifindex_add (struct rib *rib, ifindex_t ifindex)
 {  {
   struct nexthop *nexthop;    struct nexthop *nexthop;
   
Line 234  nexthop_ipv4_add (struct rib *rib, struct in_addr *ipv Line 243  nexthop_ipv4_add (struct rib *rib, struct in_addr *ipv
   
 struct nexthop *  struct nexthop *
 nexthop_ipv4_ifindex_add (struct rib *rib, struct in_addr *ipv4,   nexthop_ipv4_ifindex_add (struct rib *rib, struct in_addr *ipv4, 
                          struct in_addr *src, unsigned int ifindex)                          struct in_addr *src, ifindex_t ifindex)
 {  {
   struct nexthop *nexthop;    struct nexthop *nexthop;
   
Line 250  nexthop_ipv4_ifindex_add (struct rib *rib, struct in_a Line 259  nexthop_ipv4_ifindex_add (struct rib *rib, struct in_a
   return nexthop;    return nexthop;
 }  }
   
 #ifdef HAVE_IPV6  
 struct nexthop *  struct nexthop *
 nexthop_ipv6_add (struct rib *rib, struct in6_addr *ipv6)  nexthop_ipv6_add (struct rib *rib, struct in6_addr *ipv6)
 {  {
Line 283  nexthop_ipv6_ifname_add (struct rib *rib, struct in6_a Line 291  nexthop_ipv6_ifname_add (struct rib *rib, struct in6_a
   
 static struct nexthop *  static struct nexthop *
 nexthop_ipv6_ifindex_add (struct rib *rib, struct in6_addr *ipv6,  nexthop_ipv6_ifindex_add (struct rib *rib, struct in6_addr *ipv6,
                          unsigned int ifindex)                          ifindex_t ifindex)
 {  {
   struct nexthop *nexthop;    struct nexthop *nexthop;
   
Line 296  nexthop_ipv6_ifindex_add (struct rib *rib, struct in6_ Line 304  nexthop_ipv6_ifindex_add (struct rib *rib, struct in6_
   
   return nexthop;    return nexthop;
 }  }
 #endif /* HAVE_IPV6 */  
   
 struct nexthop *  struct nexthop *
 nexthop_blackhole_add (struct rib *rib)  nexthop_blackhole_add (struct rib *rib)
Line 312  nexthop_blackhole_add (struct rib *rib) Line 319  nexthop_blackhole_add (struct rib *rib)
   return nexthop;    return nexthop;
 }  }
   
   /* This method checks whether a recursive nexthop has at
    * least one resolved nexthop in the fib.
    */
   int
   nexthop_has_fib_child(struct nexthop *nexthop)
   {
     struct nexthop *nh;
   
     if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
       return 0;
   
     for (nh = nexthop->resolved; nh; nh = nh->next)
       if (CHECK_FLAG (nh->flags, NEXTHOP_FLAG_FIB))
         return 1;
   
     return 0;
   }
   
 /* If force flag is not set, do not modify falgs at all for uninstall  /* If force flag is not set, do not modify falgs at all for uninstall
    the route from FIB. */     the route from FIB. */
 static int  static int
Line 322  nexthop_active_ipv4 (struct rib *rib, struct nexthop * Line 347  nexthop_active_ipv4 (struct rib *rib, struct nexthop *
   struct route_table *table;    struct route_table *table;
   struct route_node *rn;    struct route_node *rn;
   struct rib *match;    struct rib *match;
     int resolved;
   struct nexthop *newhop;    struct nexthop *newhop;
     struct nexthop *resolved_hop;
   
   if (nexthop->type == NEXTHOP_TYPE_IPV4)    if (nexthop->type == NEXTHOP_TYPE_IPV4)
     nexthop->ifindex = 0;      nexthop->ifindex = 0;
   
   if (set)    if (set)
    UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);    {
       UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
       nexthops_free(nexthop->resolved);
       nexthop->resolved = NULL;
       rib->nexthop_mtu = 0;
     }
   
   /* Make lookup prefix. */    /* Make lookup prefix. */
   memset (&p, 0, sizeof (struct prefix_ipv4));    memset (&p, 0, sizeof (struct prefix_ipv4));
Line 337  nexthop_active_ipv4 (struct rib *rib, struct nexthop * Line 369  nexthop_active_ipv4 (struct rib *rib, struct nexthop *
   p.prefix = nexthop->gate.ipv4;    p.prefix = nexthop->gate.ipv4;
   
   /* Lookup table.  */    /* Lookup table.  */
  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);  table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, rib->vrf_id);
   if (! table)    if (! table)
     return 0;      return 0;
   
Line 351  nexthop_active_ipv4 (struct rib *rib, struct nexthop * Line 383  nexthop_active_ipv4 (struct rib *rib, struct nexthop *
         return 0;          return 0;
   
       /* Pick up selected route. */        /* Pick up selected route. */
      for (match = rn->info; match; match = match->next)      RNODE_FOREACH_RIB (rn, match)
         {          {
           if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED))            if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED))
             continue;              continue;
          if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))          if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB))
             break;              break;
         }          }
   
Line 372  nexthop_active_ipv4 (struct rib *rib, struct nexthop * Line 404  nexthop_active_ipv4 (struct rib *rib, struct nexthop *
         }          }
       else        else
         {          {
             /* If the longest prefix match for the nexthop yields
              * a blackhole, mark it as inactive. */
             if (CHECK_FLAG (match->flags, ZEBRA_FLAG_BLACKHOLE)
                 || CHECK_FLAG (match->flags, ZEBRA_FLAG_REJECT))
               return 0;
   
           if (match->type == ZEBRA_ROUTE_CONNECT)            if (match->type == ZEBRA_ROUTE_CONNECT)
             {              {
               /* Directly point connected route. */                /* Directly point connected route. */
Line 383  nexthop_active_ipv4 (struct rib *rib, struct nexthop * Line 421  nexthop_active_ipv4 (struct rib *rib, struct nexthop *
             }              }
           else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL))            else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL))
             {              {
                 resolved = 0;
               for (newhop = match->nexthop; newhop; newhop = newhop->next)                for (newhop = match->nexthop; newhop; newhop = newhop->next)
                 if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)                  if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)
                     && ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE))                      && ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE))
Line 390  nexthop_active_ipv4 (struct rib *rib, struct nexthop * Line 429  nexthop_active_ipv4 (struct rib *rib, struct nexthop *
                     if (set)                      if (set)
                       {                        {
                         SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);                          SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
                        nexthop->rtype = newhop->type;
                        if (newhop->type == NEXTHOP_TYPE_IPV4 ||                        resolved_hop = XCALLOC(MTYPE_NEXTHOP, sizeof (struct nexthop));
                            newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX)                        SET_FLAG (resolved_hop->flags, NEXTHOP_FLAG_ACTIVE);
                          nexthop->rgate.ipv4 = newhop->gate.ipv4;                        /* If the resolving route specifies a gateway, use it */
                         if (newhop->type == NEXTHOP_TYPE_IPV4
                             || newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX
                             || newhop->type == NEXTHOP_TYPE_IPV4_IFNAME)
                           {
                             resolved_hop->type = newhop->type;
                             resolved_hop->gate.ipv4 = newhop->gate.ipv4;
                             resolved_hop->ifindex = newhop->ifindex;
                           }
 
                         /* If the resolving route is an interface route, it
                          * means the gateway we are looking up is connected
                          * to that interface. Therefore, the resolved route
                          * should have the original gateway as nexthop as it
                          * is directly connected. */
                         if (newhop->type == NEXTHOP_TYPE_IFINDEX                          if (newhop->type == NEXTHOP_TYPE_IFINDEX
                            || newhop->type == NEXTHOP_TYPE_IFNAME                            || newhop->type == NEXTHOP_TYPE_IFNAME)
                            || newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX)                          {
                          nexthop->rifindex = newhop->ifindex;                            resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
                             resolved_hop->gate.ipv4 = nexthop->gate.ipv4;
                             resolved_hop->ifindex = newhop->ifindex;
                           }
 
                         _nexthop_add(&nexthop->resolved, resolved_hop);
                       }                        }
                    return 1;                    resolved = 1;
                   }                    }
              return 0;              if (resolved && set)
                 rib->nexthop_mtu = match->mtu;
               return resolved;
             }              }
           else            else
             {              {
Line 412  nexthop_active_ipv4 (struct rib *rib, struct nexthop * Line 472  nexthop_active_ipv4 (struct rib *rib, struct nexthop *
   return 0;    return 0;
 }  }
   
 #ifdef HAVE_IPV6  
 /* If force flag is not set, do not modify falgs at all for uninstall  /* If force flag is not set, do not modify falgs at all for uninstall
    the route from FIB. */     the route from FIB. */
 static int  static int
Line 423  nexthop_active_ipv6 (struct rib *rib, struct nexthop * Line 482  nexthop_active_ipv6 (struct rib *rib, struct nexthop *
   struct route_table *table;    struct route_table *table;
   struct route_node *rn;    struct route_node *rn;
   struct rib *match;    struct rib *match;
     int resolved;
   struct nexthop *newhop;    struct nexthop *newhop;
     struct nexthop *resolved_hop;
   
   if (nexthop->type == NEXTHOP_TYPE_IPV6)    if (nexthop->type == NEXTHOP_TYPE_IPV6)
     nexthop->ifindex = 0;      nexthop->ifindex = 0;
   
   if (set)    if (set)
    UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);    {
       UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
       nexthops_free(nexthop->resolved);
       nexthop->resolved = NULL;
     }
   
   /* Make lookup prefix. */    /* Make lookup prefix. */
   memset (&p, 0, sizeof (struct prefix_ipv6));    memset (&p, 0, sizeof (struct prefix_ipv6));
Line 438  nexthop_active_ipv6 (struct rib *rib, struct nexthop * Line 503  nexthop_active_ipv6 (struct rib *rib, struct nexthop *
   p.prefix = nexthop->gate.ipv6;    p.prefix = nexthop->gate.ipv6;
   
   /* Lookup table.  */    /* Lookup table.  */
  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);  table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, rib->vrf_id);
   if (! table)    if (! table)
     return 0;      return 0;
   
Line 452  nexthop_active_ipv6 (struct rib *rib, struct nexthop * Line 517  nexthop_active_ipv6 (struct rib *rib, struct nexthop *
         return 0;          return 0;
   
       /* Pick up selected route. */        /* Pick up selected route. */
      for (match = rn->info; match; match = match->next)      RNODE_FOREACH_RIB (rn, match)
         {          {
           if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED))            if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED))
             continue;              continue;
          if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))          if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB))
             break;              break;
         }          }
   
Line 473  nexthop_active_ipv6 (struct rib *rib, struct nexthop * Line 538  nexthop_active_ipv6 (struct rib *rib, struct nexthop *
         }          }
       else        else
         {          {
             /* If the longest prefix match for the nexthop yields
              * a blackhole, mark it as inactive. */
             if (CHECK_FLAG (match->flags, ZEBRA_FLAG_BLACKHOLE)
                 || CHECK_FLAG (match->flags, ZEBRA_FLAG_REJECT))
               return 0;
   
           if (match->type == ZEBRA_ROUTE_CONNECT)            if (match->type == ZEBRA_ROUTE_CONNECT)
             {              {
               /* Directly point connected route. */                /* Directly point connected route. */
Line 485  nexthop_active_ipv6 (struct rib *rib, struct nexthop * Line 556  nexthop_active_ipv6 (struct rib *rib, struct nexthop *
             }              }
           else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL))            else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL))
             {              {
                 resolved = 0;
               for (newhop = match->nexthop; newhop; newhop = newhop->next)                for (newhop = match->nexthop; newhop; newhop = newhop->next)
                 if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)                  if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)
                     && ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE))                      && ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE))
Line 492  nexthop_active_ipv6 (struct rib *rib, struct nexthop * Line 564  nexthop_active_ipv6 (struct rib *rib, struct nexthop *
                     if (set)                      if (set)
                       {                        {
                         SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);                          SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
                        nexthop->rtype = newhop->type;
                         resolved_hop = XCALLOC(MTYPE_NEXTHOP, sizeof (struct nexthop));
                         SET_FLAG (resolved_hop->flags, NEXTHOP_FLAG_ACTIVE);
                         /* See nexthop_active_ipv4 for a description how the
                          * resolved nexthop is constructed. */
                         if (newhop->type == NEXTHOP_TYPE_IPV6                          if (newhop->type == NEXTHOP_TYPE_IPV6
                             || newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX                              || newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX
                             || newhop->type == NEXTHOP_TYPE_IPV6_IFNAME)                              || newhop->type == NEXTHOP_TYPE_IPV6_IFNAME)
                          nexthop->rgate.ipv6 = newhop->gate.ipv6;                          {
                             resolved_hop->type = newhop->type;
                             resolved_hop->gate.ipv6 = newhop->gate.ipv6;
 
                             if (newhop->ifindex)
                               {
                                 resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
                                 resolved_hop->ifindex = newhop->ifindex;
                               }
                           }
 
                         if (newhop->type == NEXTHOP_TYPE_IFINDEX                          if (newhop->type == NEXTHOP_TYPE_IFINDEX
                            || newhop->type == NEXTHOP_TYPE_IFNAME                            || newhop->type == NEXTHOP_TYPE_IFNAME)
                            || newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX                          {
                            || newhop->type == NEXTHOP_TYPE_IPV6_IFNAME)                                resolved_hop->flags |= NEXTHOP_FLAG_ONLINK;
                          nexthop->rifindex = newhop->ifindex;                                resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
                                 resolved_hop->gate.ipv6 = nexthop->gate.ipv6;
                                 resolved_hop->ifindex = newhop->ifindex;
                           }
 
                         _nexthop_add(&nexthop->resolved, resolved_hop);
                       }                        }
                    return 1;                    resolved = 1;
                   }                    }
              return 0;              return resolved;
             }              }
           else            else
             {              {
Line 515  nexthop_active_ipv6 (struct rib *rib, struct nexthop * Line 606  nexthop_active_ipv6 (struct rib *rib, struct nexthop *
     }      }
   return 0;    return 0;
 }  }
 #endif /* HAVE_IPV6 */  
   
 struct rib *  struct rib *
rib_match_ipv4 (struct in_addr addr)rib_match_ipv4_safi (struct in_addr addr, safi_t safi, int skip_bgp,
                      struct route_node **rn_out, vrf_id_t vrf_id)
 {  {
   struct prefix_ipv4 p;  
   struct route_table *table;    struct route_table *table;
   struct route_node *rn;    struct route_node *rn;
   struct rib *match;    struct rib *match;
  struct nexthop *newhop;  struct nexthop *newhop, *tnewhop;
   int recursing;
   
   /* Lookup table.  */    /* Lookup table.  */
  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);  table = zebra_vrf_table (AFI_IP, safi, vrf_id);
   if (! table)    if (! table)
     return 0;      return 0;
   
  memset (&p, 0, sizeof (struct prefix_ipv4));  rn = route_node_match_ipv4 (table, &addr);
  p.family = AF_INET; 
  p.prefixlen = IPV4_MAX_PREFIXLEN; 
  p.prefix = addr; 
   
   rn = route_node_match (table, (struct prefix *) &p);  
   
   while (rn)    while (rn)
     {      {
       route_unlock_node (rn);        route_unlock_node (rn);
      
       /* Pick up selected route. */        /* Pick up selected route. */
      for (match = rn->info; match; match = match->next)      RNODE_FOREACH_RIB (rn, match)
         {          {
           if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED))            if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED))
             continue;              continue;
          if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))          if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB))
             break;              break;
         }          }
   
       /* If there is no selected route or matched route is EGP, go up        /* If there is no selected route or matched route is EGP, go up
          tree. */           tree. */
      if (! match       if (!match || (skip_bgp && (match->type == ZEBRA_ROUTE_BGP)))
          || match->type == ZEBRA_ROUTE_BGP) 
         {          {
           do {            do {
             rn = rn->parent;              rn = rn->parent;
Line 564  rib_match_ipv4 (struct in_addr addr) Line 649  rib_match_ipv4 (struct in_addr addr)
         }          }
       else        else
         {          {
          if (match->type == ZEBRA_ROUTE_CONNECT)          if (match->type != ZEBRA_ROUTE_CONNECT)
            /* Directly point connected route. */ 
            return match; 
          else 
             {              {
              for (newhop = match->nexthop; newhop; newhop = newhop->next)              int found = 0;
               for (ALL_NEXTHOPS_RO(match->nexthop, newhop, tnewhop, recursing))
                 if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB))                  if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB))
                  return match;                  {
              return NULL;                    found = 1;
                     break;
                   }
               if (!found)
                 return NULL;
             }              }
   
             if (rn_out)
               *rn_out = rn;
             return match;
         }          }
     }      }
   return NULL;    return NULL;
 }  }
   
 struct rib *  struct rib *
rib_lookup_ipv4 (struct prefix_ipv4 *p)rib_match_ipv4_multicast (struct in_addr addr, struct route_node **rn_out,
     vrf_id_t vrf_id)
 {  {
     struct rib *rib = NULL, *mrib = NULL, *urib = NULL;
     struct route_node *m_rn = NULL, *u_rn = NULL;
     int skip_bgp = 0; /* bool */
   
     switch (ipv4_multicast_mode)
       {
       case MCAST_MRIB_ONLY:
         return rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, rn_out,
                                     vrf_id);
       case MCAST_URIB_ONLY:
         return rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, rn_out,
                                     vrf_id);
       case MCAST_NO_CONFIG:
       case MCAST_MIX_MRIB_FIRST:
         rib = mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, &m_rn,
                                           vrf_id);
         if (!mrib)
           rib = urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, &u_rn,
                                             vrf_id);
         break;
       case MCAST_MIX_DISTANCE:
         mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, &m_rn,
                                     vrf_id);
         urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, &u_rn,
                                     vrf_id);
         if (mrib && urib)
           rib = urib->distance < mrib->distance ? urib : mrib;
         else if (mrib)
           rib = mrib;
         else if (urib)
           rib = urib;
         break;
       case MCAST_MIX_PFXLEN:
         mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, &m_rn,
                                     vrf_id);
         urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, &u_rn,
                                     vrf_id);
         if (mrib && urib)
           rib = u_rn->p.prefixlen > m_rn->p.prefixlen ? urib : mrib;
         else if (mrib)
           rib = mrib;
         else if (urib)
           rib = urib;
         break;
     }
   
     if (rn_out)
       *rn_out = (rib == mrib) ? m_rn : u_rn;
   
     if (IS_ZEBRA_DEBUG_RIB)
       {
         char buf[BUFSIZ];
         inet_ntop (AF_INET, &addr, buf, BUFSIZ);
   
         zlog_debug("%s: %s vrf %u: found %s, using %s",
                    __func__, buf, vrf_id,
                    mrib ? (urib ? "MRIB+URIB" : "MRIB") :
                            urib ? "URIB" : "nothing",
                    rib == urib ? "URIB" : rib == mrib ? "MRIB" : "none");
       }
     return rib;
   }
   
   void
   multicast_mode_ipv4_set (enum multicast_mode mode)
   {
     if (IS_ZEBRA_DEBUG_RIB)
       zlog_debug("%s: multicast lookup mode set (%d)", __func__, mode);
     ipv4_multicast_mode = mode;
   }
   
   enum multicast_mode
   multicast_mode_ipv4_get (void)
   {
     return ipv4_multicast_mode;
   }
   
   struct rib *
   rib_lookup_ipv4 (struct prefix_ipv4 *p, vrf_id_t vrf_id)
   {
   struct route_table *table;    struct route_table *table;
   struct route_node *rn;    struct route_node *rn;
   struct rib *match;    struct rib *match;
  struct nexthop *nexthop;  struct nexthop *nexthop, *tnexthop;
   int recursing;
   
   /* Lookup table.  */    /* Lookup table.  */
  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);  table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id);
   if (! table)    if (! table)
     return 0;      return 0;
   
Line 601  rib_lookup_ipv4 (struct prefix_ipv4 *p) Line 774  rib_lookup_ipv4 (struct prefix_ipv4 *p)
   /* Unlock node. */    /* Unlock node. */
   route_unlock_node (rn);    route_unlock_node (rn);
   
  for (match = rn->info; match; match = match->next)  RNODE_FOREACH_RIB (rn, match)
     {      {
       if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED))        if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED))
         continue;          continue;
      if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))      if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB))
         break;          break;
     }      }
   
Line 615  rib_lookup_ipv4 (struct prefix_ipv4 *p) Line 788  rib_lookup_ipv4 (struct prefix_ipv4 *p)
   if (match->type == ZEBRA_ROUTE_CONNECT)    if (match->type == ZEBRA_ROUTE_CONNECT)
     return match;      return match;
       
  for (nexthop = match->nexthop; nexthop; nexthop = nexthop->next)  for (ALL_NEXTHOPS_RO(match->nexthop, nexthop, tnexthop, recursing))
     if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))      if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
       return match;        return match;
   
Line 635  rib_lookup_ipv4 (struct prefix_ipv4 *p) Line 808  rib_lookup_ipv4 (struct prefix_ipv4 *p)
  * 3: no matches found   * 3: no matches found
  */   */
 int  int
rib_lookup_ipv4_route (struct prefix_ipv4 *p, union sockunion * qgate)rib_lookup_ipv4_route (struct prefix_ipv4 *p, union sockunion * qgate,
     vrf_id_t vrf_id)
 {  {
   struct route_table *table;    struct route_table *table;
   struct route_node *rn;    struct route_node *rn;
   struct rib *match;    struct rib *match;
  struct nexthop *nexthop;  struct nexthop *nexthop, *tnexthop;
   int recursing;
   int nexthops_active;
   
   /* Lookup table.  */    /* Lookup table.  */
  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);  table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id);
   if (! table)    if (! table)
     return ZEBRA_RIB_LOOKUP_ERROR;      return ZEBRA_RIB_LOOKUP_ERROR;
   
Line 658  rib_lookup_ipv4_route (struct prefix_ipv4 *p, union so Line 834  rib_lookup_ipv4_route (struct prefix_ipv4 *p, union so
   route_unlock_node (rn);    route_unlock_node (rn);
   
   /* Find out if a "selected" RR for the discovered RIB entry exists ever. */    /* Find out if a "selected" RR for the discovered RIB entry exists ever. */
  for (match = rn->info; match; match = match->next)  RNODE_FOREACH_RIB (rn, match)
     {      {
       if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED))        if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED))
         continue;          continue;
      if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))      if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB))
         break;          break;
     }      }
   
Line 674  rib_lookup_ipv4_route (struct prefix_ipv4 *p, union so Line 850  rib_lookup_ipv4_route (struct prefix_ipv4 *p, union so
     return ZEBRA_RIB_FOUND_CONNECTED;      return ZEBRA_RIB_FOUND_CONNECTED;
       
   /* Ok, we have a cood candidate, let's check it's nexthop list... */    /* Ok, we have a cood candidate, let's check it's nexthop list... */
  for (nexthop = match->nexthop; nexthop; nexthop = nexthop->next)  nexthops_active = 0;
   for (ALL_NEXTHOPS_RO(match->nexthop, nexthop, tnexthop, recursing))
     if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))      if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
     {  
       /* We are happy with either direct or recursive hexthop */  
       if (nexthop->gate.ipv4.s_addr == qgate->sin.sin_addr.s_addr ||  
           nexthop->rgate.ipv4.s_addr == qgate->sin.sin_addr.s_addr)  
         return ZEBRA_RIB_FOUND_EXACT;  
       else  
       {        {
           nexthops_active = 1;
           if (nexthop->gate.ipv4.s_addr == sockunion2ip (qgate))
             return ZEBRA_RIB_FOUND_EXACT;
         if (IS_ZEBRA_DEBUG_RIB)          if (IS_ZEBRA_DEBUG_RIB)
        {          {
          char gate_buf[INET_ADDRSTRLEN], rgate_buf[INET_ADDRSTRLEN], qgate_buf[INET_ADDRSTRLEN];            char gate_buf[INET_ADDRSTRLEN], qgate_buf[INET_ADDRSTRLEN];
          inet_ntop (AF_INET, &nexthop->gate.ipv4.s_addr, gate_buf, INET_ADDRSTRLEN);            inet_ntop (AF_INET, &nexthop->gate.ipv4.s_addr, gate_buf, INET_ADDRSTRLEN);
          inet_ntop (AF_INET, &nexthop->rgate.ipv4.s_addr, rgate_buf, INET_ADDRSTRLEN);            inet_ntop (AF_INET, &sockunion2ip(qgate), qgate_buf, INET_ADDRSTRLEN);
          inet_ntop (AF_INET, &qgate->sin.sin_addr.s_addr, qgate_buf, INET_ADDRSTRLEN);            zlog_debug ("%s: qgate == %s, %s == %s", __func__,
          zlog_debug ("%s: qgate == %s, gate == %s, rgate == %s", __func__, qgate_buf, gate_buf, rgate_buf);                        qgate_buf, recursing ? "rgate" : "gate", gate_buf);
        }          }
        return ZEBRA_RIB_FOUND_NOGATE; 
       }        }
     }  
   
     if (nexthops_active)
       return ZEBRA_RIB_FOUND_NOGATE;
   
   return ZEBRA_RIB_NOTFOUND;    return ZEBRA_RIB_NOTFOUND;
 }  }
   
 #ifdef HAVE_IPV6  
 struct rib *  struct rib *
rib_match_ipv6 (struct in6_addr *addr)rib_match_ipv6 (struct in6_addr *addr, vrf_id_t vrf_id)
 {  {
   struct prefix_ipv6 p;    struct prefix_ipv6 p;
   struct route_table *table;    struct route_table *table;
   struct route_node *rn;    struct route_node *rn;
   struct rib *match;    struct rib *match;
  struct nexthop *newhop;  struct nexthop *newhop, *tnewhop;
   int recursing;
   
   /* Lookup table.  */    /* Lookup table.  */
  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);  table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id);
   if (! table)    if (! table)
     return 0;      return 0;
   
Line 725  rib_match_ipv6 (struct in6_addr *addr) Line 900  rib_match_ipv6 (struct in6_addr *addr)
       route_unlock_node (rn);        route_unlock_node (rn);
               
       /* Pick up selected route. */        /* Pick up selected route. */
      for (match = rn->info; match; match = match->next)      RNODE_FOREACH_RIB (rn, match)
         {          {
           if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED))            if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED))
             continue;              continue;
          if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))          if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB))
             break;              break;
         }          }
   
Line 751  rib_match_ipv6 (struct in6_addr *addr) Line 926  rib_match_ipv6 (struct in6_addr *addr)
             return match;              return match;
           else            else
             {              {
              for (newhop = match->nexthop; newhop; newhop = newhop->next)              for (ALL_NEXTHOPS_RO(match->nexthop, newhop, tnewhop, recursing))
                 if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB))                  if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB))
                   return match;                    return match;
               return NULL;                return NULL;
Line 760  rib_match_ipv6 (struct in6_addr *addr) Line 935  rib_match_ipv6 (struct in6_addr *addr)
     }      }
   return NULL;    return NULL;
 }  }
 #endif /* HAVE_IPV6 */  
   
 #define RIB_SYSTEM_ROUTE(R) \  #define RIB_SYSTEM_ROUTE(R) \
         ((R)->type == ZEBRA_ROUTE_KERNEL || (R)->type == ZEBRA_ROUTE_CONNECT)          ((R)->type == ZEBRA_ROUTE_KERNEL || (R)->type == ZEBRA_ROUTE_CONNECT)
Line 779  static unsigned Line 953  static unsigned
 nexthop_active_check (struct route_node *rn, struct rib *rib,  nexthop_active_check (struct route_node *rn, struct rib *rib,
                       struct nexthop *nexthop, int set)                        struct nexthop *nexthop, int set)
 {  {
     rib_table_info_t *info = rn->table->info;
   struct interface *ifp;    struct interface *ifp;
   route_map_result_t ret = RMAP_MATCH;    route_map_result_t ret = RMAP_MATCH;
   extern char *proto_rm[AFI_MAX][ZEBRA_ROUTE_MAX+1];    extern char *proto_rm[AFI_MAX][ZEBRA_ROUTE_MAX+1];
Line 789  nexthop_active_check (struct route_node *rn, struct ri Line 964  nexthop_active_check (struct route_node *rn, struct ri
   switch (nexthop->type)    switch (nexthop->type)
     {      {
     case NEXTHOP_TYPE_IFINDEX:      case NEXTHOP_TYPE_IFINDEX:
      ifp = if_lookup_by_index (nexthop->ifindex);      ifp = if_lookup_by_index_vrf (nexthop->ifindex, rib->vrf_id);
       if (ifp && if_is_operative(ifp))        if (ifp && if_is_operative(ifp))
         SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);          SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
       else        else
Line 798  nexthop_active_check (struct route_node *rn, struct ri Line 973  nexthop_active_check (struct route_node *rn, struct ri
     case NEXTHOP_TYPE_IPV6_IFNAME:      case NEXTHOP_TYPE_IPV6_IFNAME:
       family = AFI_IP6;        family = AFI_IP6;
     case NEXTHOP_TYPE_IFNAME:      case NEXTHOP_TYPE_IFNAME:
      ifp = if_lookup_by_name (nexthop->ifname);      ifp = if_lookup_by_name_vrf (nexthop->ifname, rib->vrf_id);
       if (ifp && if_is_operative(ifp))        if (ifp && if_is_operative(ifp))
         {          {
           if (set)            if (set)
Line 820  nexthop_active_check (struct route_node *rn, struct ri Line 995  nexthop_active_check (struct route_node *rn, struct ri
       else        else
         UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);          UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
       break;        break;
 #ifdef HAVE_IPV6  
     case NEXTHOP_TYPE_IPV6:      case NEXTHOP_TYPE_IPV6:
       family = AFI_IP6;        family = AFI_IP6;
       if (nexthop_active_ipv6 (rib, nexthop, set, rn))        if (nexthop_active_ipv6 (rib, nexthop, set, rn))
Line 832  nexthop_active_check (struct route_node *rn, struct ri Line 1006  nexthop_active_check (struct route_node *rn, struct ri
       family = AFI_IP6;        family = AFI_IP6;
       if (IN6_IS_ADDR_LINKLOCAL (&nexthop->gate.ipv6))        if (IN6_IS_ADDR_LINKLOCAL (&nexthop->gate.ipv6))
         {          {
          ifp = if_lookup_by_index (nexthop->ifindex);          ifp = if_lookup_by_index_vrf (nexthop->ifindex, rib->vrf_id);
           if (ifp && if_is_operative(ifp))            if (ifp && if_is_operative(ifp))
             SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);              SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
           else            else
Line 846  nexthop_active_check (struct route_node *rn, struct ri Line 1020  nexthop_active_check (struct route_node *rn, struct ri
             UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);              UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
         }          }
       break;        break;
 #endif /* HAVE_IPV6 */  
     case NEXTHOP_TYPE_BLACKHOLE:      case NEXTHOP_TYPE_BLACKHOLE:
       SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);        SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
       break;        break;
Line 856  nexthop_active_check (struct route_node *rn, struct ri Line 1029  nexthop_active_check (struct route_node *rn, struct ri
   if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))    if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
     return 0;      return 0;
   
     /* XXX: What exactly do those checks do? Do we support
      * e.g. IPv4 routes with IPv6 nexthops or vice versa? */
   if (RIB_SYSTEM_ROUTE(rib) ||    if (RIB_SYSTEM_ROUTE(rib) ||
       (family == AFI_IP && rn->p.family != AF_INET) ||        (family == AFI_IP && rn->p.family != AF_INET) ||
       (family == AFI_IP6 && rn->p.family != AF_INET6))        (family == AFI_IP6 && rn->p.family != AF_INET6))
     return CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);      return CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
   
     /* The original code didn't determine the family correctly
      * e.g. for NEXTHOP_TYPE_IFINDEX. Retrieve the correct afi
      * from the rib_table_info in those cases.
      * Possibly it may be better to use only the rib_table_info
      * in every case.
      */
     if (!family)
       family = info->afi;
   
   rmap = 0;    rmap = 0;
   if (rib->type >= 0 && rib->type < ZEBRA_ROUTE_MAX &&    if (rib->type >= 0 && rib->type < ZEBRA_ROUTE_MAX &&
                 proto_rm[family][rib->type])                  proto_rm[family][rib->type])
Line 868  nexthop_active_check (struct route_node *rn, struct ri Line 1052  nexthop_active_check (struct route_node *rn, struct ri
   if (!rmap && proto_rm[family][ZEBRA_ROUTE_MAX])    if (!rmap && proto_rm[family][ZEBRA_ROUTE_MAX])
     rmap = route_map_lookup_by_name (proto_rm[family][ZEBRA_ROUTE_MAX]);      rmap = route_map_lookup_by_name (proto_rm[family][ZEBRA_ROUTE_MAX]);
   if (rmap) {    if (rmap) {
      ret = route_map_apply(rmap, &rn->p, RMAP_ZEBRA, nexthop);      struct nexthop_vrfid nh_vrf = {nexthop, rib->vrf_id};
       ret = route_map_apply(rmap, &rn->p, RMAP_ZEBRA, &nh_vrf);
   }    }
   
   if (ret == RMAP_DENYMATCH)    if (ret == RMAP_DENYMATCH)
Line 879  nexthop_active_check (struct route_node *rn, struct ri Line 1064  nexthop_active_check (struct route_node *rn, struct ri
 /* Iterate over all nexthops of the given RIB entry and refresh their  /* Iterate over all nexthops of the given RIB entry and refresh their
  * ACTIVE flag. rib->nexthop_active_num is updated accordingly. If any   * ACTIVE flag. rib->nexthop_active_num is updated accordingly. If any
  * nexthop is found to toggle the ACTIVE flag, the whole rib structure   * nexthop is found to toggle the ACTIVE flag, the whole rib structure
 * is flagged with ZEBRA_FLAG_CHANGED. The 4th 'set' argument is * is flagged with RIB_ENTRY_CHANGED. The 4th 'set' argument is
  * transparently passed to nexthop_active_check().   * transparently passed to nexthop_active_check().
  *   *
  * Return value is the new number of active nexthops.   * Return value is the new number of active nexthops.
Line 889  static int Line 1074  static int
 nexthop_active_update (struct route_node *rn, struct rib *rib, int set)  nexthop_active_update (struct route_node *rn, struct rib *rib, int set)
 {  {
   struct nexthop *nexthop;    struct nexthop *nexthop;
  unsigned int prev_active, prev_index, new_active;  unsigned int prev_active, new_active;
  ifindex_t prev_index;
   
   rib->nexthop_active_num = 0;    rib->nexthop_active_num = 0;
  UNSET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED);  UNSET_FLAG (rib->status, RIB_ENTRY_CHANGED);
   
   for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)    for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
   {    {
Line 902  nexthop_active_update (struct route_node *rn, struct r Line 1088  nexthop_active_update (struct route_node *rn, struct r
       rib->nexthop_active_num++;        rib->nexthop_active_num++;
     if (prev_active != new_active ||      if (prev_active != new_active ||
         prev_index != nexthop->ifindex)          prev_index != nexthop->ifindex)
      SET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED);      SET_FLAG (rib->status, RIB_ENTRY_CHANGED);
   }    }
   return rib->nexthop_active_num;    return rib->nexthop_active_num;
 }  }
   
   
   
static void
rib_install_kernel (struct route_node *rn, struct rib *rib)static int
 rib_update_kernel (struct route_node *rn, struct rib *old, struct rib *new)
 {  {
   int ret = 0;    int ret = 0;
  struct nexthop *nexthop;  struct nexthop *nexthop, *tnexthop;
   rib_table_info_t *info = rn->table->info;
   int recursing;
   
  switch (PREFIX_FAMILY (&rn->p))  if (info->safi != SAFI_UNICAST)
     {      {
    case AF_INET:      if (new)
      ret = kernel_add_ipv4 (&rn->p, rib);        for (ALL_NEXTHOPS_RO(new->nexthop, nexthop, tnexthop, recursing))
      break;          SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
#ifdef HAVE_IPV6      if (old)
    case AF_INET6:        for (ALL_NEXTHOPS_RO(old->nexthop, nexthop, tnexthop, recursing))
      ret = kernel_add_ipv6 (&rn->p, rib);          UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
      break;      return 0;
#endif /* HAVE_IPV6 */ 
     }      }
   
  /* This condition is never met, if we are using rt_socket.c */  /*
  if (ret < 0)   * Make sure we update the FPM any time we send new information to
    {   * the kernel.
      for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)   */
        UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);  zfpm_trigger_update (rn, "updating in kernel");
    } 
} 
   
/* Uninstall the route from kernel. */  ret = kernel_route_rib (&rn->p, old, new);
static int 
rib_uninstall_kernel (struct route_node *rn, struct rib *rib) 
{ 
  int ret = 0; 
  struct nexthop *nexthop; 
   
  switch (PREFIX_FAMILY (&rn->p))  /* This condition is never met, if we are using rt_socket.c */
    {  if (ret < 0 && new)
    case AF_INET:      for (ALL_NEXTHOPS_RO(new->nexthop, nexthop, tnexthop, recursing))
      ret = kernel_delete_ipv4 (&rn->p, rib);        UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
      break; 
#ifdef HAVE_IPV6 
    case AF_INET6: 
      ret = kernel_delete_ipv6 (&rn->p, rib); 
      break; 
#endif /* HAVE_IPV6 */ 
    } 
   
  for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)  if (old)
    UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);    for (ALL_NEXTHOPS_RO(old->nexthop, nexthop, tnexthop, recursing))
       UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
   
   return ret;    return ret;
 }  }
Line 964  rib_uninstall_kernel (struct route_node *rn, struct ri Line 1138  rib_uninstall_kernel (struct route_node *rn, struct ri
 static void  static void
 rib_uninstall (struct route_node *rn, struct rib *rib)  rib_uninstall (struct route_node *rn, struct rib *rib)
 {  {
  if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))  rib_table_info_t *info = rn->table->info;
 
   if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB))
     {      {
         if (info->safi == SAFI_UNICAST)
           zfpm_trigger_update (rn, "rib_uninstall");
   
       redistribute_delete (&rn->p, rib);        redistribute_delete (&rn->p, rib);
       if (! RIB_SYSTEM_ROUTE (rib))        if (! RIB_SYSTEM_ROUTE (rib))
        rib_uninstall_kernel (rn, rib);        rib_update_kernel (rn, rib, NULL);
       UNSET_FLAG (rib->flags, ZEBRA_FLAG_SELECTED);        UNSET_FLAG (rib->flags, ZEBRA_FLAG_SELECTED);
     }      }
 }  }
   
 static void rib_unlink (struct route_node *, struct rib *);  static void rib_unlink (struct route_node *, struct rib *);
   
   /*
    * rib_can_delete_dest
    *
    * Returns TRUE if the given dest can be deleted from the table.
    */
   static int
   rib_can_delete_dest (rib_dest_t *dest)
   {
     if (dest->routes)
       {
         return 0;
       }
   
     /*
      * Don't delete the dest if we have to update the FPM about this
      * prefix.
      */
     if (CHECK_FLAG (dest->flags, RIB_DEST_UPDATE_FPM) ||
         CHECK_FLAG (dest->flags, RIB_DEST_SENT_TO_FPM))
       return 0;
   
     return 1;
   }
   
   /*
    * rib_gc_dest
    *
    * Garbage collect the rib dest corresponding to the given route node
    * if appropriate.
    *
    * Returns TRUE if the dest was deleted, FALSE otherwise.
    */
   int
   rib_gc_dest (struct route_node *rn)
   {
     rib_dest_t *dest;
   
     dest = rib_dest_from_rnode (rn);
     if (!dest)
       return 0;
   
     if (!rib_can_delete_dest (dest))
       return 0;
   
     if (IS_ZEBRA_DEBUG_RIB)
       rnode_debug (rn, "removing dest from table");
   
     dest->rnode = NULL;
     XFREE (MTYPE_RIB_DEST, dest);
     rn->info = NULL;
   
     /*
      * Release the one reference that we keep on the route node.
      */
     route_unlock_node (rn);
     return 1;
   }
   
   /* Check if 'alternate' RIB entry is better than 'current'. */
   static struct rib *
   rib_choose_best (struct rib *current, struct rib *alternate)
   {
     if (current == NULL)
       return alternate;
   
     /* filter route selection in following order:
      * - connected beats other types
      * - lower distance beats higher
      * - lower metric beats higher for equal distance
      * - last, hence oldest, route wins tie break.
      */
   
     /* Connected routes. Pick the last connected
      * route of the set of lowest metric connected routes.
      */
     if (alternate->type == ZEBRA_ROUTE_CONNECT)
       {
         if (current->type != ZEBRA_ROUTE_CONNECT
             || alternate->metric <= current->metric)
           return alternate;
   
         return current;
       }
   
     if (current->type == ZEBRA_ROUTE_CONNECT)
       return current;
   
     /* higher distance loses */
     if (alternate->distance < current->distance)
       return alternate;
     if (current->distance < alternate->distance)
       return current;
   
     /* metric tie-breaks equal distance */
     if (alternate->metric <= current->metric)
       return alternate;
   
     return current;
   }
   
 /* Core function for processing routing information base. */  /* Core function for processing routing information base. */
 static void  static void
 rib_process (struct route_node *rn)  rib_process (struct route_node *rn)
 {  {
   struct rib *rib;    struct rib *rib;
   struct rib *next;    struct rib *next;
  struct rib *fib = NULL;  struct rib *old_selected = NULL;
  struct rib *select = NULL;  struct rib *new_selected = NULL;
  struct rib *del = NULL;  struct rib *old_fib = NULL;
   struct rib *new_fib = NULL;
   int installed = 0;    int installed = 0;
  struct nexthop *nexthop = NULL;  struct nexthop *nexthop = NULL, *tnexthop;
  char buf[INET6_ADDRSTRLEN];  int recursing;
    rib_table_info_t *info;
 
   assert (rn);    assert (rn);
     
   if (IS_ZEBRA_DEBUG_RIB || IS_ZEBRA_DEBUG_RIB_Q)  
     inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN);  
   
  for (rib = rn->info; rib; rib = next)  info = rn->table->info;
 
   RNODE_FOREACH_RIB (rn, rib)
     {      {
       /* The next pointer is saved, because current pointer  
        * may be passed to rib_unlink() in the middle of iteration.  
        */  
       next = rib->next;  
         
       /* Currently installed rib. */        /* Currently installed rib. */
       if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))        if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
         {          {
          assert (fib == NULL);          assert (old_selected == NULL);
          fib = rib;          old_selected = rib;
         }          }
            if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB))
      /* Unlock removed routes, so they'll be freed, bar the FIB entry, 
       * which we need to do do further work with below. 
       */ 
      if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) 
         {          {
          if (rib != fib)          assert (old_fib == NULL);
            {          old_fib = rib;
              if (IS_ZEBRA_DEBUG_RIB) 
                zlog_debug ("%s: %s/%d: rn %p, removing rib %p", __func__, 
                  buf, rn->p.prefixlen, rn, rib); 
                rib_unlink (rn, rib); 
            } 
          else 
            del = rib; 
           
          continue; 
         }          }
   
         /* Skip deleted entries from selection */
         if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
           continue;
               
       /* Skip unreachable nexthop. */        /* Skip unreachable nexthop. */
       if (! nexthop_active_update (rn, rib, 0))        if (! nexthop_active_update (rn, rib, 0))
Line 1033  rib_process (struct route_node *rn) Line 1299  rib_process (struct route_node *rn)
       if (rib->distance == DISTANCE_INFINITY)        if (rib->distance == DISTANCE_INFINITY)
         continue;          continue;
   
      /* Newly selected rib, the common case. */      if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_FIB_OVERRIDE))
      if (!select)        new_fib = rib_choose_best(new_fib, rib);
        {      else
          select = rib;        new_selected = rib_choose_best(new_selected, rib);
          continue;    } /* RNODE_FOREACH_RIB_SAFE */
        } 
       
      /* filter route selection in following order: 
       * - connected beats other types 
       * - lower distance beats higher 
       * - lower metric beats higher for equal distance 
       * - last, hence oldest, route wins tie break. 
       */ 
       
      /* Connected routes. Pick the last connected 
       * route of the set of lowest metric connected routes. 
       */ 
      if (rib->type == ZEBRA_ROUTE_CONNECT) 
        { 
          if (select->type != ZEBRA_ROUTE_CONNECT 
              || rib->metric <= select->metric) 
            select = rib; 
          continue; 
        } 
      else if (select->type == ZEBRA_ROUTE_CONNECT) 
        continue; 
       
      /* higher distance loses */ 
      if (rib->distance > select->distance) 
        continue; 
       
      /* lower wins */ 
      if (rib->distance < select->distance) 
        { 
          select = rib; 
          continue; 
        } 
       
      /* metric tie-breaks equal distance */ 
      if (rib->metric <= select->metric) 
        select = rib; 
    } /* for (rib = rn->info; rib; rib = next) */ 
   
     /* If no FIB override route, use the selected route also for FIB */
     if (new_fib == NULL)
       new_fib = new_selected;
   
   /* After the cycle is finished, the following pointers will be set:    /* After the cycle is finished, the following pointers will be set:
   * select --- the winner RIB entry, if any was found, otherwise NULL   * old_selected --- RIB entry currently having SELECTED
   * fib    --- the SELECTED RIB entry, if any, otherwise NULL   * new_selected --- RIB entry that is newly SELECTED
   * del    --- equal to fib, if fib is queued for deletion, NULL otherwise   * old_fib      --- RIB entry currently in kernel FIB
   * rib    --- NULL   * new_fib      --- RIB entry that is newly to be in kernel FIB
    *
    * new_selected will get SELECTED flag, and is going to be redistributed
    * the zclients. new_fib (which can be new_selected) will be installed in kernel.
    */     */
   
  /* Same RIB entry is selected. Update FIB and finish. */  /* Set real nexthops. */
  if (select && select == fib)  if (new_fib)
     nexthop_active_update (rn, new_fib, 1);
   if (new_selected && new_selected != new_fib)
      nexthop_active_update (rn, new_selected, 1);
 
   /* Update kernel if FIB entry has changed */
   if (old_fib != new_fib
       || (new_fib && CHECK_FLAG (new_fib->status, RIB_ENTRY_CHANGED)))
     {      {
      if (IS_ZEBRA_DEBUG_RIB)        if (old_fib && old_fib != new_fib)
        zlog_debug ("%s: %s/%d: Updating existing route, select %p, fib %p",          {
                     __func__, buf, rn->p.prefixlen, select, fib);            if (! RIB_SYSTEM_ROUTE (old_fib) && (! new_fib || RIB_SYSTEM_ROUTE (new_fib)))
      if (CHECK_FLAG (select->flags, ZEBRA_FLAG_CHANGED))              rib_update_kernel (rn, old_fib, NULL);
        {            UNSET_FLAG (old_fib->status, RIB_ENTRY_SELECTED_FIB);
          redistribute_delete (&rn->p, select);          }
          if (! RIB_SYSTEM_ROUTE (select)) 
            rib_uninstall_kernel (rn, select); 
   
          /* Set real nexthop. */        if (new_fib)
          nexthop_active_update (rn, select, 1);          {
              /* Install new or replace existing FIB entry */
          if (! RIB_SYSTEM_ROUTE (select))            SET_FLAG (new_fib->status, RIB_ENTRY_SELECTED_FIB);
            rib_install_kernel (rn, select);            if (! RIB_SYSTEM_ROUTE (new_fib))
          redistribute_add (&rn->p, select);              rib_update_kernel (rn, old_fib, new_fib);
        }          }
      else if (! RIB_SYSTEM_ROUTE (select)) 
        { 
          /* Housekeeping code to deal with  
             race conditions in kernel with linux 
             netlink reporting interface up before IPv4 or IPv6 protocol 
             is ready to add routes. 
             This makes sure the routes are IN the kernel. 
           */ 
   
          for (nexthop = select->nexthop; nexthop; nexthop = nexthop->next)        if (info->safi == SAFI_UNICAST)
            if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))          zfpm_trigger_update (rn, "updating existing route");
            { 
              installed = 1; 
              break; 
            } 
          if (! installed)  
            rib_install_kernel (rn, select); 
        } 
      goto end; 
     }      }
  else if (old_fib == new_fib && new_fib && ! RIB_SYSTEM_ROUTE (new_fib))
  /* At this point we either haven't found the best RIB entry or it is 
   * different from what we currently intend to flag with SELECTED. In both 
   * cases, if a RIB block is present in FIB, it should be withdrawn. 
   */ 
  if (fib) 
     {      {
      if (IS_ZEBRA_DEBUG_RIB)      /* Housekeeping code to deal with race conditions in kernel with
        zlog_debug ("%s: %s/%d: Removing existing route, fib %p", __func__,       * linux netlink reporting interface up before IPv4 or IPv6 protocol
          buf, rn->p.prefixlen, fib);       * is ready to add routes. This makes sure routes are IN the kernel.
      redistribute_delete (&rn->p, fib);       */
      if (! RIB_SYSTEM_ROUTE (fib))      for (ALL_NEXTHOPS_RO(new_fib->nexthop, nexthop, tnexthop, recursing))
        rib_uninstall_kernel (rn, fib);        if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
      UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED);          {
            installed = 1;
      /* Set real nexthop. */            break;
      nexthop_active_update (rn, fib, 1);          }
       if (! installed)
         rib_update_kernel (rn, NULL, new_fib);
     }      }
   
  /* Regardless of some RIB entry being SELECTED or not before, now we can  /* Redistribute SELECTED entry */
   * tell, that if a new winner exists, FIB is still not updated with this  if (old_selected != new_selected
   * data, but ready to be.      || (new_selected && CHECK_FLAG (new_selected->status, RIB_ENTRY_CHANGED)))
   */ 
  if (select) 
     {      {
      if (IS_ZEBRA_DEBUG_RIB)      if (old_selected)
        zlog_debug ("%s: %s/%d: Adding route, select %p", __func__, buf,        {
          rn->p.prefixlen, select);          if (! new_selected)
      /* Set real nexthop. */            redistribute_delete (&rn->p, old_selected);
      nexthop_active_update (rn, select, 1);          if (old_selected != new_selected)
             UNSET_FLAG (old_selected->flags, ZEBRA_FLAG_SELECTED);
         }
   
      if (! RIB_SYSTEM_ROUTE (select))      if (new_selected)
        rib_install_kernel (rn, select);        {
      SET_FLAG (select->flags, ZEBRA_FLAG_SELECTED);          /* Install new or replace existing redistributed entry */
      redistribute_add (&rn->p, select);          SET_FLAG (new_selected->flags, ZEBRA_FLAG_SELECTED);
    }          redistribute_add (&rn->p, new_selected);
         }
      }
   
  /* FIB route was removed, should be deleted */  /* Remove all RIB entries queued for removal */
  if (del)  RNODE_FOREACH_RIB_SAFE (rn, rib, next)
     {      {
      if (IS_ZEBRA_DEBUG_RIB)      if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
        zlog_debug ("%s: %s/%d: Deleting fib %p, rn %p", __func__, buf,        {
          rn->p.prefixlen, del, rn);          if (IS_ZEBRA_DEBUG_RIB)
      rib_unlink (rn, del);            rnode_debug (rn, "rn %p, removing rib %p",
                         (void *)rn, (void *)rib);
           rib_unlink (rn, rib);
         }
     }      }
   
 end:  
   if (IS_ZEBRA_DEBUG_RIB_Q)    if (IS_ZEBRA_DEBUG_RIB_Q)
    zlog_debug ("%s: %s/%d: rn %p dequeued", __func__, buf, rn->p.prefixlen, rn);    rnode_debug (rn, "rn %p dequeued", (void *)rn);
 
   /*
    * Check if the dest can be deleted now.
    */
   rib_gc_dest (rn);
 }  }
   
 /* Take a list of route_node structs and return 1, if there was a record  /* Take a list of route_node structs and return 1, if there was a record
Line 1189  process_subq (struct list * subq, u_char qindex) Line 1420  process_subq (struct list * subq, u_char qindex)
   rnode = listgetdata (lnode);    rnode = listgetdata (lnode);
   rib_process (rnode);    rib_process (rnode);
   
  if (rnode->info) /* The first RIB record is holding the flags bitmask. */  if (rnode->info)
    UNSET_FLAG (((struct rib *)rnode->info)->rn_status, RIB_ROUTE_QUEUED(qindex));    UNSET_FLAG (rib_dest_from_rnode (rnode)->flags, RIB_ROUTE_QUEUED (qindex));
 
 #if 0  #if 0
   else    else
     {      {
Line 1223  meta_queue_process (struct work_queue *dummy, void *da Line 1455  meta_queue_process (struct work_queue *dummy, void *da
   return mq->size ? WQ_REQUEUE : WQ_SUCCESS;    return mq->size ? WQ_REQUEUE : WQ_SUCCESS;
 }  }
   
/* Map from rib types to queue type (priority) in meta queue *//*
  * Map from rib types to queue type (priority) in meta queue
  */
 static const u_char meta_queue_map[ZEBRA_ROUTE_MAX] = {  static const u_char meta_queue_map[ZEBRA_ROUTE_MAX] = {
   [ZEBRA_ROUTE_SYSTEM]  = 4,    [ZEBRA_ROUTE_SYSTEM]  = 4,
   [ZEBRA_ROUTE_KERNEL]  = 0,    [ZEBRA_ROUTE_KERNEL]  = 0,
Line 1246  static void Line 1480  static void
 rib_meta_queue_add (struct meta_queue *mq, struct route_node *rn)  rib_meta_queue_add (struct meta_queue *mq, struct route_node *rn)
 {  {
   struct rib *rib;    struct rib *rib;
   char buf[INET6_ADDRSTRLEN];  
   
  if (IS_ZEBRA_DEBUG_RIB_Q)  RNODE_FOREACH_RIB (rn, rib)
    inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); 
 
  for (rib = rn->info; rib; rib = rib->next) 
     {      {
       u_char qindex = meta_queue_map[rib->type];        u_char qindex = meta_queue_map[rib->type];
   
       /* Invariant: at this point we always have rn->info set. */        /* Invariant: at this point we always have rn->info set. */
      if (CHECK_FLAG (((struct rib *)rn->info)->rn_status, RIB_ROUTE_QUEUED(qindex)))      if (CHECK_FLAG (rib_dest_from_rnode (rn)->flags,
                       RIB_ROUTE_QUEUED (qindex)))
         {          {
           if (IS_ZEBRA_DEBUG_RIB_Q)            if (IS_ZEBRA_DEBUG_RIB_Q)
            zlog_debug ("%s: %s/%d: rn %p is already queued in sub-queue %u",            rnode_debug (rn, "rn %p is already queued in sub-queue %u",
                        __func__, buf, rn->p.prefixlen, rn, qindex);                         (void *)rn, qindex);
           continue;            continue;
         }          }
   
      SET_FLAG (((struct rib *)rn->info)->rn_status, RIB_ROUTE_QUEUED(qindex));      SET_FLAG (rib_dest_from_rnode (rn)->flags, RIB_ROUTE_QUEUED (qindex));
       listnode_add (mq->subq[qindex], rn);        listnode_add (mq->subq[qindex], rn);
       route_lock_node (rn);        route_lock_node (rn);
       mq->size++;        mq->size++;
   
       if (IS_ZEBRA_DEBUG_RIB_Q)        if (IS_ZEBRA_DEBUG_RIB_Q)
        zlog_debug ("%s: %s/%d: queued rn %p into sub-queue %u",        rnode_debug (rn, "queued rn %p into sub-queue %u",
                    __func__, buf, rn->p.prefixlen, rn, qindex);                     (void *)rn, qindex);
     }      }
 }  }
   
Line 1279  rib_meta_queue_add (struct meta_queue *mq, struct rout Line 1510  rib_meta_queue_add (struct meta_queue *mq, struct rout
 static void  static void
 rib_queue_add (struct zebra_t *zebra, struct route_node *rn)  rib_queue_add (struct zebra_t *zebra, struct route_node *rn)
 {  {
   char buf[INET_ADDRSTRLEN];  
   assert (zebra && rn);    assert (zebra && rn);
     
   if (IS_ZEBRA_DEBUG_RIB_Q)  
     inet_ntop (AF_INET, &rn->p.u.prefix, buf, INET_ADDRSTRLEN);  
   
   /* Pointless to queue a route_node with no RIB entries to add or remove */    /* Pointless to queue a route_node with no RIB entries to add or remove */
  if (!rn->info)  if (!rnode_to_ribs (rn))
     {      {
       zlog_debug ("%s: called for route_node (%p, %d) with no ribs",        zlog_debug ("%s: called for route_node (%p, %d) with no ribs",
                  __func__, rn, rn->lock);                  __func__, (void *)rn, rn->lock);
       zlog_backtrace(LOG_DEBUG);        zlog_backtrace(LOG_DEBUG);
       return;        return;
     }      }
   
   if (IS_ZEBRA_DEBUG_RIB_Q)    if (IS_ZEBRA_DEBUG_RIB_Q)
    zlog_info ("%s: %s/%d: work queue added", __func__, buf, rn->p.prefixlen);    rnode_info (rn, "work queue added");
   
   assert (zebra);    assert (zebra);
   
Line 1319  rib_queue_add (struct zebra_t *zebra, struct route_nod Line 1546  rib_queue_add (struct zebra_t *zebra, struct route_nod
   rib_meta_queue_add (zebra->mq, rn);    rib_meta_queue_add (zebra->mq, rn);
   
   if (IS_ZEBRA_DEBUG_RIB_Q)    if (IS_ZEBRA_DEBUG_RIB_Q)
    zlog_debug ("%s: %s/%d: rn %p queued", __func__, buf, rn->p.prefixlen, rn);    rnode_debug (rn, "rn %p queued", (void *)rn);
   
   return;    return;
 }  }
Line 1379  rib_queue_init (struct zebra_t *zebra) Line 1606  rib_queue_init (struct zebra_t *zebra)
  * as a route_node will not be requeued, if already queued.   * as a route_node will not be requeued, if already queued.
  *   *
  * RIBs are submitted via rib_addnode or rib_delnode which set minimal   * RIBs are submitted via rib_addnode or rib_delnode which set minimal
 * state, or static_install_ipv{4,6} (when an existing RIB is updated) * state, or static_install_route (when an existing RIB is updated)
  * and then submit route_node to queue for best-path selection later.   * and then submit route_node to queue for best-path selection later.
  * Order of add/delete state changes are preserved for any given RIB.   * Order of add/delete state changes are preserved for any given RIB.
  *   *
Line 1395  rib_queue_init (struct zebra_t *zebra) Line 1622  rib_queue_init (struct zebra_t *zebra)
  * |-> set RIB_ENTRY_REMOVE                           |   * |-> set RIB_ENTRY_REMOVE                           |
  * rib_delnode                                  (RIB freed)   * rib_delnode                                  (RIB freed)
  *   *
 * * The 'info' pointer of a route_node points to a rib_dest_t
 * Queueing state for a route_node is kept in the head RIB entry, this * ('dest'). Queueing state for a route_node is kept on the dest. The
 * state must be preserved as and when the head RIB entry of a * dest is created on-demand by rib_link() and is kept around at least
 * route_node is changed by rib_unlink / rib_link. A small complication, * as long as there are ribs hanging off it (@see rib_gc_dest()).
 * but saves having to allocate a dedicated object for this. 
  *    * 
  * Refcounting (aka "locking" throughout the GNU Zebra and Quagga code):   * Refcounting (aka "locking" throughout the GNU Zebra and Quagga code):
  *   *
  * - route_nodes: refcounted by:   * - route_nodes: refcounted by:
 *   - RIBs attached to route_node: *   - dest attached to route_node:
 *     - managed by: rib_link/unlink *     - managed by: rib_link/rib_gc_dest
  *   - route_node processing queue   *   - route_node processing queue
  *     - managed by: rib_addqueue, rib_process.   *     - managed by: rib_addqueue, rib_process.
  *   *
Line 1416  static void Line 1642  static void
 rib_link (struct route_node *rn, struct rib *rib)  rib_link (struct route_node *rn, struct rib *rib)
 {  {
   struct rib *head;    struct rib *head;
  char buf[INET6_ADDRSTRLEN];  rib_dest_t *dest;
  
   assert (rib && rn);    assert (rib && rn);
       
   route_lock_node (rn); /* rn route table reference */  
   
   if (IS_ZEBRA_DEBUG_RIB)    if (IS_ZEBRA_DEBUG_RIB)
  {    rnode_debug (rn, "rn %p, rib %p", (void *)rn, (void *)rib);
    inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); 
    zlog_debug ("%s: %s/%d: rn %p, rib %p", __func__, 
      buf, rn->p.prefixlen, rn, rib); 
  } 
   
  head = rn->info;  dest = rib_dest_from_rnode (rn);
  if (head)  if (!dest)
     {      {
       if (IS_ZEBRA_DEBUG_RIB)        if (IS_ZEBRA_DEBUG_RIB)
        zlog_debug ("%s: %s/%d: new head, rn_status copied over", __func__,        rnode_debug (rn, "adding dest to table");
          buf, rn->p.prefixlen);
       dest = XCALLOC (MTYPE_RIB_DEST, sizeof (rib_dest_t));
       route_lock_node (rn); /* rn route table reference */
       rn->info = dest;
       dest->rnode = rn;
     }
 
   head = dest->routes;
   if (head)
     {
       head->prev = rib;        head->prev = rib;
       /* Transfer the rn status flags to the new head RIB */  
       rib->rn_status = head->rn_status;  
     }      }
   rib->next = head;    rib->next = head;
  rn->info = rib;  dest->routes = rib;
   rib_queue_add (&zebrad, rn);    rib_queue_add (&zebrad, rn);
 }  }
   
Line 1453  rib_addnode (struct route_node *rn, struct rib *rib) Line 1680  rib_addnode (struct route_node *rn, struct rib *rib)
   if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))    if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
     {      {
       if (IS_ZEBRA_DEBUG_RIB)        if (IS_ZEBRA_DEBUG_RIB)
      {        rnode_debug (rn, "rn %p, un-removed rib %p", (void *)rn, (void *)rib);
        char buf[INET6_ADDRSTRLEN];
        inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); 
        zlog_debug ("%s: %s/%d: rn %p, un-removed rib %p", 
                    __func__, buf, rn->p.prefixlen, rn, rib); 
      } 
       UNSET_FLAG (rib->status, RIB_ENTRY_REMOVED);        UNSET_FLAG (rib->status, RIB_ENTRY_REMOVED);
       return;        return;
     }      }
   rib_link (rn, rib);    rib_link (rn, rib);
 }  }
   
   /*
    * rib_unlink
    *
    * Detach a rib structure from a route_node.
    *
    * Note that a call to rib_unlink() should be followed by a call to
    * rib_gc_dest() at some point. This allows a rib_dest_t that is no
    * longer required to be deleted.
    */
 static void  static void
 rib_unlink (struct route_node *rn, struct rib *rib)  rib_unlink (struct route_node *rn, struct rib *rib)
 {  {
  struct nexthop *nexthop, *next;  rib_dest_t *dest;
  char buf[INET6_ADDRSTRLEN]; 
   
   assert (rn && rib);    assert (rn && rib);
   
   if (IS_ZEBRA_DEBUG_RIB)    if (IS_ZEBRA_DEBUG_RIB)
  {    rnode_debug (rn, "rn %p, rib %p", (void *)rn, (void *)rib);
    inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); 
    zlog_debug ("%s: %s/%d: rn %p, rib %p", 
                __func__, buf, rn->p.prefixlen, rn, rib); 
  } 
   
     dest = rib_dest_from_rnode (rn);
   
   if (rib->next)    if (rib->next)
     rib->next->prev = rib->prev;      rib->next->prev = rib->prev;
   
Line 1487  rib_unlink (struct route_node *rn, struct rib *rib) Line 1716  rib_unlink (struct route_node *rn, struct rib *rib)
     rib->prev->next = rib->next;      rib->prev->next = rib->next;
   else    else
     {      {
      rn->info = rib->next;      dest->routes = rib->next;
       
      if (rn->info) 
        { 
          if (IS_ZEBRA_DEBUG_RIB) 
            zlog_debug ("%s: %s/%d: rn %p, rib %p, new head copy", 
                        __func__, buf, rn->p.prefixlen, rn, rib); 
          rib->next->rn_status = rib->rn_status; 
        } 
     }      }
   
   /* free RIB and nexthops */    /* free RIB and nexthops */
  for (nexthop = rib->nexthop; nexthop; nexthop = next)  nexthops_free(rib->nexthop);
    { 
      next = nexthop->next; 
      nexthop_free (nexthop); 
    } 
   XFREE (MTYPE_RIB, rib);    XFREE (MTYPE_RIB, rib);
   
   route_unlock_node (rn); /* rn route table reference */  
 }  }
   
 static void  static void
 rib_delnode (struct route_node *rn, struct rib *rib)  rib_delnode (struct route_node *rn, struct rib *rib)
 {  {
   if (IS_ZEBRA_DEBUG_RIB)    if (IS_ZEBRA_DEBUG_RIB)
  {    rnode_debug (rn, "rn %p, rib %p, removing", (void *)rn, (void *)rib);
    char buf[INET6_ADDRSTRLEN]; 
    inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); 
    zlog_debug ("%s: %s/%d: rn %p, rib %p, removing", __func__, 
      buf, rn->p.prefixlen, rn, rib); 
  } 
   SET_FLAG (rib->status, RIB_ENTRY_REMOVED);    SET_FLAG (rib->status, RIB_ENTRY_REMOVED);
   rib_queue_add (&zebrad, rn);    rib_queue_add (&zebrad, rn);
 }  }
Line 1526  rib_delnode (struct route_node *rn, struct rib *rib) Line 1737  rib_delnode (struct route_node *rn, struct rib *rib)
 int  int
 rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p,   rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, 
               struct in_addr *gate, struct in_addr *src,                struct in_addr *gate, struct in_addr *src,
              unsigned int ifindex, u_int32_t vrf_id,              ifindex_t ifindex, vrf_id_t vrf_id, int table_id,
              u_int32_t metric, u_char distance, safi_t safi)              u_int32_t metric, u_int32_t mtu, u_char distance, safi_t safi)
 {  {
   struct rib *rib;    struct rib *rib;
   struct rib *same = NULL;    struct rib *same = NULL;
Line 1536  rib_add_ipv4 (int type, int flags, struct prefix_ipv4  Line 1747  rib_add_ipv4 (int type, int flags, struct prefix_ipv4 
   struct nexthop *nexthop;    struct nexthop *nexthop;
   
   /* Lookup table.  */    /* Lookup table.  */
  table = vrf_table (AFI_IP, safi, 0);  table = zebra_vrf_table (AFI_IP, safi, vrf_id);
   if (! table)    if (! table)
     return 0;      return 0;
   
Line 1546  rib_add_ipv4 (int type, int flags, struct prefix_ipv4  Line 1757  rib_add_ipv4 (int type, int flags, struct prefix_ipv4 
   /* Set default distance by route type. */    /* Set default distance by route type. */
   if (distance == 0)    if (distance == 0)
     {      {
      if ((unsigned)type >= sizeof(route_info) / sizeof(route_info[0]))      if ((unsigned)type >= array_size(route_info))
         distance = 150;          distance = 150;
       else        else
         distance = route_info[type].distance;          distance = route_info[type].distance;
Line 1561  rib_add_ipv4 (int type, int flags, struct prefix_ipv4  Line 1772  rib_add_ipv4 (int type, int flags, struct prefix_ipv4 
   
   /* If same type of route are installed, treat it as a implicit    /* If same type of route are installed, treat it as a implicit
      withdraw. */       withdraw. */
  for (rib = rn->info; rib; rib = rib->next)  RNODE_FOREACH_RIB (rn, rib)
     {      {
       if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))        if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
         continue;          continue;
Line 1590  rib_add_ipv4 (int type, int flags, struct prefix_ipv4  Line 1801  rib_add_ipv4 (int type, int flags, struct prefix_ipv4 
   rib->distance = distance;    rib->distance = distance;
   rib->flags = flags;    rib->flags = flags;
   rib->metric = metric;    rib->metric = metric;
  rib->table = vrf_id;  rib->mtu = mtu;
   rib->vrf_id = vrf_id;
   rib->table = table_id;
   rib->nexthop_num = 0;    rib->nexthop_num = 0;
   rib->uptime = time (NULL);    rib->uptime = time (NULL);
   
Line 1612  rib_add_ipv4 (int type, int flags, struct prefix_ipv4  Line 1825  rib_add_ipv4 (int type, int flags, struct prefix_ipv4 
   
   /* Link new rib to node.*/    /* Link new rib to node.*/
   if (IS_ZEBRA_DEBUG_RIB)    if (IS_ZEBRA_DEBUG_RIB)
    zlog_debug ("%s: calling rib_addnode (%p, %p)", __func__, rn, rib);    zlog_debug ("%s: calling rib_addnode (%p, %p)",
                __func__, (void *)rn, (void *)rib);
   rib_addnode (rn, rib);    rib_addnode (rn, rib);
       
   /* Free implicit route.*/    /* Free implicit route.*/
   if (same)    if (same)
   {    {
     if (IS_ZEBRA_DEBUG_RIB)      if (IS_ZEBRA_DEBUG_RIB)
      zlog_debug ("%s: calling rib_delnode (%p, %p)", __func__, rn, rib);      zlog_debug ("%s: calling rib_delnode (%p, %p)",
                  __func__, (void *)rn, (void *)rib);
     rib_delnode (rn, same);      rib_delnode (rn, same);
   }    }
       
Line 1632  rib_add_ipv4 (int type, int flags, struct prefix_ipv4  Line 1847  rib_add_ipv4 (int type, int flags, struct prefix_ipv4 
  * question are passed as 1st and 2nd arguments.   * question are passed as 1st and 2nd arguments.
  */   */
   
void rib_dump (const char * func, const struct prefix_ipv4 * p, const struct rib * rib)void _rib_dump (const char * func,
                 union prefix46constptr pp, const struct rib * rib)
 {  {
  char straddr1[INET_ADDRSTRLEN], straddr2[INET_ADDRSTRLEN];  const struct prefix *p = pp.p;
  struct nexthop *nexthop;  char straddr[PREFIX_STRLEN];
   struct nexthop *nexthop, *tnexthop;
   int recursing;
   
  inet_ntop (AF_INET, &p->prefix, straddr1, INET_ADDRSTRLEN);  zlog_debug ("%s: dumping RIB entry %p for %s vrf %u", func, (void *)rib,
  zlog_debug ("%s: dumping RIB entry %p for %s/%d", func, rib, straddr1, p->prefixlen);              prefix2str(p, straddr, sizeof(straddr)), rib->vrf_id);
   zlog_debug    zlog_debug
   (    (
     "%s: refcnt == %lu, uptime == %lu, type == %u, table == %d",      "%s: refcnt == %lu, uptime == %lu, type == %u, table == %d",
Line 1665  void rib_dump (const char * func, const struct prefix_ Line 1883  void rib_dump (const char * func, const struct prefix_
     rib->nexthop_active_num,      rib->nexthop_active_num,
     rib->nexthop_fib_num      rib->nexthop_fib_num
   );    );
  for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
  {  for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
    inet_ntop (AF_INET, &nexthop->gate.ipv4.s_addr, straddr1, INET_ADDRSTRLEN);    {
    inet_ntop (AF_INET, &nexthop->rgate.ipv4.s_addr, straddr2, INET_ADDRSTRLEN);      inet_ntop (p->family, &nexthop->gate, straddr, INET6_ADDRSTRLEN);
    zlog_debug      zlog_debug
    (      (
      "%s: NH %s (%s) with flags %s%s%s",        "%s: %s %s with flags %s%s%s",
      func,        func,
      straddr1,        (recursing ? "  NH" : "NH"),
      straddr2,        straddr,
      (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE) ? "ACTIVE " : ""),        (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE) ? "ACTIVE " : ""),
      (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? "FIB " : ""),        (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? "FIB " : ""),
      (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE) ? "RECURSIVE" : "")        (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE) ? "RECURSIVE" : "")
    );      );
  }    }
   zlog_debug ("%s: dump complete", func);    zlog_debug ("%s: dump complete", func);
 }  }
   
Line 1695  void rib_lookup_and_dump (struct prefix_ipv4 * p) Line 1913  void rib_lookup_and_dump (struct prefix_ipv4 * p)
   char prefix_buf[INET_ADDRSTRLEN];    char prefix_buf[INET_ADDRSTRLEN];
   
   /* Lookup table.  */    /* Lookup table.  */
  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);  table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT);
   if (! table)    if (! table)
   {    {
    zlog_err ("%s: vrf_table() returned NULL", __func__);    zlog_err ("%s: zebra_vrf_table() returned NULL", __func__);
     return;      return;
   }    }
   
   inet_ntop (AF_INET, &p->prefix.s_addr, prefix_buf, INET_ADDRSTRLEN);  
   /* Scan the RIB table for exactly matching RIB entry. */    /* Scan the RIB table for exactly matching RIB entry. */
   rn = route_node_lookup (table, (struct prefix *) p);    rn = route_node_lookup (table, (struct prefix *) p);
   
   /* No route for this prefix. */    /* No route for this prefix. */
   if (! rn)    if (! rn)
   {    {
    zlog_debug ("%s: lookup failed for %s/%d", __func__, prefix_buf, p->prefixlen);    zlog_debug ("%s: lookup failed for %s", __func__,
                 prefix2str((struct prefix*) p, prefix_buf, sizeof(prefix_buf)));
     return;      return;
   }    }
   
Line 1717  void rib_lookup_and_dump (struct prefix_ipv4 * p) Line 1935  void rib_lookup_and_dump (struct prefix_ipv4 * p)
   route_unlock_node (rn);    route_unlock_node (rn);
   
   /* let's go */    /* let's go */
  for (rib = rn->info; rib; rib = rib->next)  RNODE_FOREACH_RIB (rn, rib)
   {    {
     zlog_debug      zlog_debug
     (      (
       "%s: rn %p, rib %p: %s, %s",        "%s: rn %p, rib %p: %s, %s",
       __func__,        __func__,
      rn,      (void *)rn,
      rib,      (void *)rib,
       (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED) ? "removed" : "NOT removed"),        (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED) ? "removed" : "NOT removed"),
       (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED) ? "selected" : "NOT selected")        (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED) ? "selected" : "NOT selected")
     );      );
    rib_dump (__func__, p, rib);    rib_dump (p, rib);
   }    }
 }  }
   
Line 1744  void rib_lookup_and_pushup (struct prefix_ipv4 * p) Line 1962  void rib_lookup_and_pushup (struct prefix_ipv4 * p)
   struct rib *rib;    struct rib *rib;
   unsigned changed = 0;    unsigned changed = 0;
   
  if (NULL == (table = vrf_table (AFI_IP, SAFI_UNICAST, 0)))  if (NULL == (table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT)))
   {    {
    zlog_err ("%s: vrf_table() returned NULL", __func__);    zlog_err ("%s: zebra_vrf_table() returned NULL", __func__);
     return;      return;
   }    }
   
Line 1764  void rib_lookup_and_pushup (struct prefix_ipv4 * p) Line 1982  void rib_lookup_and_pushup (struct prefix_ipv4 * p)
    * RIBQ record already on head. This is necessary for proper revalidation     * RIBQ record already on head. This is necessary for proper revalidation
    * of the rest of the RIB.     * of the rest of the RIB.
    */     */
  for (rib = rn->info; rib; rib = rib->next)  RNODE_FOREACH_RIB (rn, rib)
   {    {
    if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED) &&    if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB) &&
       ! RIB_SYSTEM_ROUTE (rib))        ! RIB_SYSTEM_ROUTE (rib))
     {      {
       changed = 1;        changed = 1;
       if (IS_ZEBRA_DEBUG_RIB)        if (IS_ZEBRA_DEBUG_RIB)
       {        {
        char buf[INET_ADDRSTRLEN];        char buf[PREFIX_STRLEN];
        inet_ntop (rn->p.family, &p->prefix, buf, INET_ADDRSTRLEN);        zlog_debug ("%s: freeing way for connected prefix %s", __func__,
        zlog_debug ("%s: freeing way for connected prefix %s/%d", __func__, buf, p->prefixlen);                    prefix2str(&rn->p, buf, sizeof(buf)));
        rib_dump (__func__, (struct prefix_ipv4 *)&rn->p, rib);        rib_dump (&rn->p, rib);
       }        }
       rib_uninstall (rn, rib);        rib_uninstall (rn, rib);
     }      }
Line 1793  rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct  Line 2011  rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct 
   struct nexthop *nexthop;    struct nexthop *nexthop;
       
   /* Lookup table.  */    /* Lookup table.  */
  table = vrf_table (AFI_IP, safi, 0);  table = zebra_vrf_table (AFI_IP, safi, rib->vrf_id);
   if (! table)    if (! table)
     return 0;      return 0;
   
Line 1816  rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct  Line 2034  rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct 
   
   /* If same type of route are installed, treat it as a implicit    /* If same type of route are installed, treat it as a implicit
      withdraw. */       withdraw. */
  for (same = rn->info; same; same = same->next)  RNODE_FOREACH_RIB (rn, same)
     {      {
       if (CHECK_FLAG (same->status, RIB_ENTRY_REMOVED))        if (CHECK_FLAG (same->status, RIB_ENTRY_REMOVED))
         continue;          continue;
Line 1836  rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct  Line 2054  rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct 
   if (IS_ZEBRA_DEBUG_RIB)    if (IS_ZEBRA_DEBUG_RIB)
   {    {
     zlog_debug ("%s: called rib_addnode (%p, %p) on new RIB entry",      zlog_debug ("%s: called rib_addnode (%p, %p) on new RIB entry",
      __func__, rn, rib);                __func__, (void *)rn, (void *)rib);
    rib_dump (__func__, p, rib);    rib_dump (p, rib);
   }    }
   
   /* Free implicit route.*/    /* Free implicit route.*/
Line 1846  rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct  Line 2064  rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct 
     if (IS_ZEBRA_DEBUG_RIB)      if (IS_ZEBRA_DEBUG_RIB)
     {      {
       zlog_debug ("%s: calling rib_delnode (%p, %p) on existing RIB entry",        zlog_debug ("%s: calling rib_delnode (%p, %p) on existing RIB entry",
        __func__, rn, same);                  __func__, (void *)rn, (void *)same);
      rib_dump (__func__, p, same);      rib_dump (p, same);
     }      }
     rib_delnode (rn, same);      rib_delnode (rn, same);
   }    }
Line 1859  rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct  Line 2077  rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct 
 /* XXX factor with rib_delete_ipv6 */  /* XXX factor with rib_delete_ipv6 */
 int  int
 rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p,  rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p,
                 struct in_addr *gate, unsigned int ifindex, u_int32_t vrf_id, safi_t safi)                 struct in_addr *gate, ifindex_t ifindex, 
                  vrf_id_t vrf_id, safi_t safi)
 {  {
   struct route_table *table;    struct route_table *table;
   struct route_node *rn;    struct route_node *rn;
   struct rib *rib;    struct rib *rib;
   struct rib *fib = NULL;    struct rib *fib = NULL;
   struct rib *same = NULL;    struct rib *same = NULL;
  struct nexthop *nexthop;  struct nexthop *nexthop, *tnexthop;
  char buf1[INET_ADDRSTRLEN];  int recursing;
   char buf1[PREFIX_STRLEN];
   char buf2[INET_ADDRSTRLEN];    char buf2[INET_ADDRSTRLEN];
   
   /* Lookup table.  */    /* Lookup table.  */
  table = vrf_table (AFI_IP, safi, 0);  table = zebra_vrf_table (AFI_IP, safi, vrf_id);
   if (! table)    if (! table)
     return 0;      return 0;
   
   /* Apply mask. */    /* Apply mask. */
   apply_mask_ipv4 (p);    apply_mask_ipv4 (p);
   
  if (IS_ZEBRA_DEBUG_KERNEL && gate)  if (IS_ZEBRA_DEBUG_KERNEL)
    zlog_debug ("rib_delete_ipv4(): route delete %s/%d via %s ifindex %d",    {
                       inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN),      if (gate)
                       p->prefixlen        zlog_debug ("rib_delete_ipv4(): route delete %s vrf %u via %s ifindex %d",
                       inet_ntoa (*gate),                     prefix2str (p, buf1, sizeof(buf1)), vrf_id,
                       ifindex);                    inet_ntoa (*gate),
                     ifindex);
       else
         zlog_debug ("rib_delete_ipv4(): route delete %s vrf %u ifindex %d",
                     prefix2str (p, buf1, sizeof(buf1)), vrf_id,
                     ifindex);
     }
   
   /* Lookup route node. */    /* Lookup route node. */
   rn = route_node_lookup (table, (struct prefix *) p);    rn = route_node_lookup (table, (struct prefix *) p);
Line 1892  rib_delete_ipv4 (int type, int flags, struct prefix_ip Line 2118  rib_delete_ipv4 (int type, int flags, struct prefix_ip
       if (IS_ZEBRA_DEBUG_KERNEL)        if (IS_ZEBRA_DEBUG_KERNEL)
         {          {
           if (gate)            if (gate)
            zlog_debug ("route %s/%d via %s ifindex %d doesn't exist in rib",            zlog_debug ("route %s vrf %u via %s ifindex %d doesn't exist in rib",
                       inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN),                       prefix2str (p, buf1, sizeof(buf1)), vrf_id,
                       p->prefixlen, 
                        inet_ntop (AF_INET, gate, buf2, INET_ADDRSTRLEN),                         inet_ntop (AF_INET, gate, buf2, INET_ADDRSTRLEN),
                        ifindex);                         ifindex);
           else            else
            zlog_debug ("route %s/%d ifindex %d doesn't exist in rib",            zlog_debug ("route %s vrf %u ifindex %d doesn't exist in rib",
                       inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN),                       prefix2str (p, buf1, sizeof(buf1)), vrf_id,
                       p->prefixlen, 
                        ifindex);                         ifindex);
         }          }
       return ZEBRA_ERR_RTNOEXIST;        return ZEBRA_ERR_RTNOEXIST;
     }      }
   
   /* Lookup same type route. */    /* Lookup same type route. */
  for (rib = rn->info; rib; rib = rib->next)  RNODE_FOREACH_RIB (rn, rib)
     {      {
       if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))        if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
         continue;          continue;
   
      if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))      if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB))
         fib = rib;          fib = rib;
   
       if (rib->type != type)        if (rib->type != type)
Line 1933  rib_delete_ipv4 (int type, int flags, struct prefix_ip Line 2157  rib_delete_ipv4 (int type, int flags, struct prefix_ip
           break;            break;
         }          }
       /* Make sure that the route found has the same gateway. */        /* Make sure that the route found has the same gateway. */
      else if (gate == NULL ||      else
               ((nexthop = rib->nexthop) && 
                (IPV4_ADDR_SAME (&nexthop->gate.ipv4, gate) || 
                 IPV4_ADDR_SAME (&nexthop->rgate.ipv4, gate))))  
         {          {
          same = rib;          if (gate == NULL)
          break;            {
        }              same = rib;
               break;
             }
           for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
             if (IPV4_ADDR_SAME (&nexthop->gate.ipv4, gate))
               {
                 same = rib;
                 break;
               }
           if (same)
             break;
         }
     }      }
   
   /* If same type of route can't be found and this message is from    /* If same type of route can't be found and this message is from
      kernel. */       kernel. */
   if (! same)    if (! same)
Line 1953  rib_delete_ipv4 (int type, int flags, struct prefix_ip Line 2184  rib_delete_ipv4 (int type, int flags, struct prefix_ip
           for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next)            for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next)
             UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);              UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
   
          UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED);          UNSET_FLAG (fib->status, RIB_ENTRY_SELECTED_FIB);
         }          }
       else        else
         {          {
           if (IS_ZEBRA_DEBUG_KERNEL)            if (IS_ZEBRA_DEBUG_KERNEL)
             {              {
               if (gate)                if (gate)
                zlog_debug ("route %s/%d via %s ifindex %d type %d doesn't exist in rib",                zlog_debug ("route %s vrf %u via %s ifindex %d type %d "
                           inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN),                           "doesn't exist in rib",
                           p->prefixlen,                           prefix2str (p, buf1, sizeof(buf1)), vrf_id,
                            inet_ntop (AF_INET, gate, buf2, INET_ADDRSTRLEN),                             inet_ntop (AF_INET, gate, buf2, INET_ADDRSTRLEN),
                            ifindex,                             ifindex,
                            type);                             type);
               else                else
                zlog_debug ("route %s/%d ifindex %d type %d doesn't exist in rib",                zlog_debug ("route %s vrf %u ifindex %d type %d doesn't exist in rib",
                           inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN),                           prefix2str (p, buf1, sizeof(buf1)), vrf_id,
                           p->prefixlen, 
                            ifindex,                             ifindex,
                            type);                             type);
             }              }
Line 1984  rib_delete_ipv4 (int type, int flags, struct prefix_ip Line 2214  rib_delete_ipv4 (int type, int flags, struct prefix_ip
   route_unlock_node (rn);    route_unlock_node (rn);
   return 0;    return 0;
 }  }
 /* Install static route into rib. */  /* Install static route into rib. */
 static void  static void
static_install_ipv4 (struct prefix *p, struct static_ipv4 *si)static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_route *si)
 {  {
   struct rib *rib;    struct rib *rib;
   struct route_node *rn;    struct route_node *rn;
   struct route_table *table;    struct route_table *table;
   
   /* Lookup table.  */    /* Lookup table.  */
  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);  table = zebra_vrf_table (afi, safi, si->vrf_id);
   if (! table)    if (! table)
     return;      return;
   
   /* Lookup existing route */    /* Lookup existing route */
   rn = route_node_get (table, p);    rn = route_node_get (table, p);
  for (rib = rn->info; rib; rib = rib->next)  RNODE_FOREACH_RIB (rn, rib)
     {      {
        if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))         if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
          continue;           continue;
Line 2016  static_install_ipv4 (struct prefix *p, struct static_i Line 2246  static_install_ipv4 (struct prefix *p, struct static_i
       route_unlock_node (rn);        route_unlock_node (rn);
       switch (si->type)        switch (si->type)
         {          {
          case STATIC_IPV4_GATEWAY:        case STATIC_IPV4_GATEWAY:
            nexthop_ipv4_add (rib, &si->gate.ipv4, NULL);          nexthop_ipv4_add (rib, &si->addr.ipv4, NULL);
            break;          break;
          case STATIC_IPV4_IFNAME:        case STATIC_IPV4_IFNAME:
            nexthop_ifname_add (rib, si->gate.ifname);          nexthop_ifname_add (rib, si->ifname);
            break;          break;
          case STATIC_IPV4_BLACKHOLE:        case STATIC_IPV4_BLACKHOLE:
            nexthop_blackhole_add (rib);          nexthop_blackhole_add (rib);
            break;          break;
         case STATIC_IPV6_GATEWAY:
           nexthop_ipv6_add (rib, &si->addr.ipv6);
           break;
         case STATIC_IPV6_IFNAME:
           nexthop_ifname_add (rib, si->ifname);
           break;
         case STATIC_IPV6_GATEWAY_IFNAME:
           nexthop_ipv6_ifname_add (rib, &si->addr.ipv6, si->ifname);
           break;
         }          }
       rib_queue_add (&zebrad, rn);        rib_queue_add (&zebrad, rn);
     }      }
Line 2036  static_install_ipv4 (struct prefix *p, struct static_i Line 2275  static_install_ipv4 (struct prefix *p, struct static_i
       rib->type = ZEBRA_ROUTE_STATIC;        rib->type = ZEBRA_ROUTE_STATIC;
       rib->distance = si->distance;        rib->distance = si->distance;
       rib->metric = 0;        rib->metric = 0;
         rib->vrf_id = si->vrf_id;
         rib->table = zebrad.rtm_table_default;
       rib->nexthop_num = 0;        rib->nexthop_num = 0;
   
       switch (si->type)        switch (si->type)
         {          {
          case STATIC_IPV4_GATEWAY:        case STATIC_IPV4_GATEWAY:
            nexthop_ipv4_add (rib, &si->gate.ipv4, NULL);          nexthop_ipv4_add (rib, &si->addr.ipv4, NULL);
            break;          break;
          case STATIC_IPV4_IFNAME:        case STATIC_IPV4_IFNAME:
            nexthop_ifname_add (rib, si->gate.ifname);          nexthop_ifname_add (rib, si->ifname);
            break;          break;
          case STATIC_IPV4_BLACKHOLE:        case STATIC_IPV4_BLACKHOLE:
            nexthop_blackhole_add (rib);          nexthop_blackhole_add (rib);
            break;          break;
         case STATIC_IPV6_GATEWAY:
           nexthop_ipv6_add (rib, &si->addr.ipv6);
           break;
         case STATIC_IPV6_IFNAME:
           nexthop_ifname_add (rib, si->ifname);
           break;
         case STATIC_IPV6_GATEWAY_IFNAME:
           nexthop_ipv6_ifname_add (rib, &si->addr.ipv6, si->ifname);
           break;
         }          }
   
       /* Save the flags of this static routes (reject, blackhole) */        /* Save the flags of this static routes (reject, blackhole) */
Line 2060  static_install_ipv4 (struct prefix *p, struct static_i Line 2310  static_install_ipv4 (struct prefix *p, struct static_i
 }  }
   
 static int  static int
static_ipv4_nexthop_same (struct nexthop *nexthop, struct static_ipv4 *si)static_nexthop_same (struct nexthop *nexthop, struct static_route *si)
 {  {
   if (nexthop->type == NEXTHOP_TYPE_IPV4    if (nexthop->type == NEXTHOP_TYPE_IPV4
       && si->type == STATIC_IPV4_GATEWAY        && si->type == STATIC_IPV4_GATEWAY
      && IPV4_ADDR_SAME (&nexthop->gate.ipv4, &si->gate.ipv4))      && IPV4_ADDR_SAME (&nexthop->gate.ipv4, &si->addr.ipv4))
     return 1;      return 1;
   if (nexthop->type == NEXTHOP_TYPE_IFNAME    if (nexthop->type == NEXTHOP_TYPE_IFNAME
       && si->type == STATIC_IPV4_IFNAME        && si->type == STATIC_IPV4_IFNAME
      && strcmp (nexthop->ifname, si->gate.ifname) == 0)      && strcmp (nexthop->ifname, si->ifname) == 0)
     return 1;      return 1;
   if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE    if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE
       && si->type == STATIC_IPV4_BLACKHOLE)        && si->type == STATIC_IPV4_BLACKHOLE)
     return 1;      return 1;
     if (nexthop->type == NEXTHOP_TYPE_IPV6
         && si->type == STATIC_IPV6_GATEWAY
         && IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->addr.ipv6))
       return 1;
     if (nexthop->type == NEXTHOP_TYPE_IFNAME
         && si->type == STATIC_IPV6_IFNAME
         && strcmp (nexthop->ifname, si->ifname) == 0)
       return 1;
     if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
         && si->type == STATIC_IPV6_GATEWAY_IFNAME
         && IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->addr.ipv6)
         && strcmp (nexthop->ifname, si->ifname) == 0)
       return 1;
   return 0;    return 0;
 }  }
   
 /* Uninstall static route from RIB. */  /* Uninstall static route from RIB. */
 static void  static void
static_uninstall_ipv4 (struct prefix *p, struct static_ipv4 *si)static_uninstall_route (afi_t afi, safi_t safi, struct prefix *p, struct static_route *si)
 {  {
   struct route_node *rn;    struct route_node *rn;
   struct rib *rib;    struct rib *rib;
Line 2086  static_uninstall_ipv4 (struct prefix *p, struct static Line 2349  static_uninstall_ipv4 (struct prefix *p, struct static
   struct route_table *table;    struct route_table *table;
   
   /* Lookup table.  */    /* Lookup table.  */
  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);  table = zebra_vrf_table (afi, safi, si->vrf_id);
   if (! table)    if (! table)
     return;      return;
       
Line 2095  static_uninstall_ipv4 (struct prefix *p, struct static Line 2358  static_uninstall_ipv4 (struct prefix *p, struct static
   if (! rn)    if (! rn)
     return;      return;
   
  for (rib = rn->info; rib; rib = rib->next)  RNODE_FOREACH_RIB (rn, rib)
     {      {
       if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))        if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
         continue;          continue;
Line 2112  static_uninstall_ipv4 (struct prefix *p, struct static Line 2375  static_uninstall_ipv4 (struct prefix *p, struct static
   
   /* Lookup nexthop. */    /* Lookup nexthop. */
   for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)    for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
    if (static_ipv4_nexthop_same (nexthop, si))    if (static_nexthop_same (nexthop, si))
       break;        break;
   
   /* Can't find nexthop. */    /* Can't find nexthop. */
Line 2137  static_uninstall_ipv4 (struct prefix *p, struct static Line 2400  static_uninstall_ipv4 (struct prefix *p, struct static
   route_unlock_node (rn);    route_unlock_node (rn);
 }  }
   
 /* Add static route into static route configuration. */  
 int  int
static_add_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname,static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate,
                 u_char flags, u_char distance, u_int32_t vrf_id)                      const char *ifname, u_char flags, u_char distance,
                       vrf_id_t vrf_id)
 {  {
   u_char type = 0;    u_char type = 0;
   struct route_node *rn;    struct route_node *rn;
  struct static_ipv4 *si;  struct static_route *si;
  struct static_ipv4 *pp;  struct static_route *pp;
  struct static_ipv4 *cp;  struct static_route *cp;
  struct static_ipv4 *update = NULL;  struct static_route *update = NULL;
  struct route_table *stable;  struct zebra_vrf *zvrf = vrf_info_get (vrf_id);
   struct route_table *stable = zvrf->stable[AFI_IP][safi];
   
   /* Lookup table.  */  
   stable = vrf_static_table (AFI_IP, SAFI_UNICAST, vrf_id);  
   if (! stable)    if (! stable)
     return -1;      return -1;
       
Line 2170  static_add_ipv4 (struct prefix *p, struct in_addr *gat Line 2432  static_add_ipv4 (struct prefix *p, struct in_addr *gat
   for (si = rn->info; si; si = si->next)    for (si = rn->info; si; si = si->next)
     {      {
       if (type == si->type        if (type == si->type
          && (! gate || IPV4_ADDR_SAME (gate, &si->gate.ipv4))          && (! gate || IPV4_ADDR_SAME (gate, &si->addr.ipv4))
          && (! ifname || strcmp (ifname, si->gate.ifname) == 0))          && (! ifname || strcmp (ifname, si->ifname) == 0))
         {          {
           if (distance == si->distance)            if (distance == si->distance)
             {              {
Line 2185  static_add_ipv4 (struct prefix *p, struct in_addr *gat Line 2447  static_add_ipv4 (struct prefix *p, struct in_addr *gat
   
   /* Distance changed.  */    /* Distance changed.  */
   if (update)    if (update)
    static_delete_ipv4 (p, gate, ifname, update->distance, vrf_id);    static_delete_ipv4_safi (safi, p, gate, ifname, update->distance, vrf_id);
   
   /* Make new static route structure. */    /* Make new static route structure. */
  si = XCALLOC (MTYPE_STATIC_IPV4, sizeof (struct static_ipv4));  si = XCALLOC (MTYPE_STATIC_ROUTE, sizeof (struct static_route));
   
   si->type = type;    si->type = type;
   si->distance = distance;    si->distance = distance;
   si->flags = flags;    si->flags = flags;
     si->vrf_id = vrf_id;
   
   if (gate)    if (gate)
    si->gate.ipv4 = *gate;    si->addr.ipv4 = *gate;
   if (ifname)    if (ifname)
    si->gate.ifname = XSTRDUP (0, ifname);    si->ifname = XSTRDUP (0, ifname);
   
   /* Add new static route information to the tree with sort by    /* Add new static route information to the tree with sort by
      distance value and gateway address. */       distance value and gateway address. */
Line 2209  static_add_ipv4 (struct prefix *p, struct in_addr *gat Line 2472  static_add_ipv4 (struct prefix *p, struct in_addr *gat
         continue;          continue;
       if (si->type == STATIC_IPV4_GATEWAY && cp->type == STATIC_IPV4_GATEWAY)        if (si->type == STATIC_IPV4_GATEWAY && cp->type == STATIC_IPV4_GATEWAY)
         {          {
          if (ntohl (si->gate.ipv4.s_addr) < ntohl (cp->gate.ipv4.s_addr))          if (ntohl (si->addr.ipv4.s_addr) < ntohl (cp->addr.ipv4.s_addr))
             break;              break;
          if (ntohl (si->gate.ipv4.s_addr) > ntohl (cp->gate.ipv4.s_addr))          if (ntohl (si->addr.ipv4.s_addr) > ntohl (cp->addr.ipv4.s_addr))
             continue;              continue;
         }          }
     }      }
Line 2227  static_add_ipv4 (struct prefix *p, struct in_addr *gat Line 2490  static_add_ipv4 (struct prefix *p, struct in_addr *gat
   si->next = cp;    si->next = cp;
   
   /* Install into rib. */    /* Install into rib. */
  static_install_ipv4 (p, si);  static_install_route (AFI_IP, safi, p, si);
   
   return 1;    return 1;
 }  }
   
 /* Delete static route from static route configuration. */  
 int  int
static_delete_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname,static_delete_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate,
                    u_char distance, u_int32_t vrf_id)                         const char *ifname, u_char distance, vrf_id_t vrf_id)
 {  {
   u_char type = 0;    u_char type = 0;
   struct route_node *rn;    struct route_node *rn;
  struct static_ipv4 *si;  struct static_route *si;
   struct route_table *stable;    struct route_table *stable;
   
   /* Lookup table.  */    /* Lookup table.  */
  stable = vrf_static_table (AFI_IP, SAFI_UNICAST, vrf_id);  stable = zebra_vrf_static_table (AFI_IP, safi, vrf_id);
   if (! stable)    if (! stable)
     return -1;      return -1;
   
Line 2263  static_delete_ipv4 (struct prefix *p, struct in_addr * Line 2525  static_delete_ipv4 (struct prefix *p, struct in_addr *
   /* Find same static route is the tree */    /* Find same static route is the tree */
   for (si = rn->info; si; si = si->next)    for (si = rn->info; si; si = si->next)
     if (type == si->type      if (type == si->type
        && (! gate || IPV4_ADDR_SAME (gate, &si->gate.ipv4))        && (! gate || IPV4_ADDR_SAME (gate, &si->addr.ipv4))
        && (! ifname || strcmp (ifname, si->gate.ifname) == 0))        && (! ifname || strcmp (ifname, si->ifname) == 0))
       break;        break;
   
   /* Can't find static route. */    /* Can't find static route. */
Line 2275  static_delete_ipv4 (struct prefix *p, struct in_addr * Line 2537  static_delete_ipv4 (struct prefix *p, struct in_addr *
     }      }
   
   /* Install into rib. */    /* Install into rib. */
  static_uninstall_ipv4 (p, si);  static_uninstall_route (AFI_IP, safi, p, si);
   
   /* Unlink static route from linked list. */    /* Unlink static route from linked list. */
   if (si->prev)    if (si->prev)
Line 2288  static_delete_ipv4 (struct prefix *p, struct in_addr * Line 2550  static_delete_ipv4 (struct prefix *p, struct in_addr *
       
   /* Free static route configuration. */    /* Free static route configuration. */
   if (ifname)    if (ifname)
    XFREE (0, si->gate.ifname);    XFREE (0, si->ifname);
  XFREE (MTYPE_STATIC_IPV4, si);  XFREE (MTYPE_STATIC_ROUTE, si);
   
   route_unlock_node (rn);    route_unlock_node (rn);
   
   return 1;    return 1;
 }  }
   
   
 #ifdef HAVE_IPV6  
 static int  
 rib_bogus_ipv6 (int type, struct prefix_ipv6 *p,  
                 struct in6_addr *gate, unsigned int ifindex, int table)  
 {  
   if (type == ZEBRA_ROUTE_CONNECT && IN6_IS_ADDR_UNSPECIFIED (&p->prefix)) {  
 #if defined (MUSICA) || defined (LINUX)  
     /* IN6_IS_ADDR_V4COMPAT(&p->prefix) */  
     if (p->prefixlen == 96)  
       return 0;  
 #endif /* MUSICA */  
     return 1;  
   }  
   if (type == ZEBRA_ROUTE_KERNEL && IN6_IS_ADDR_UNSPECIFIED (&p->prefix)  
       && p->prefixlen == 96 && gate && IN6_IS_ADDR_UNSPECIFIED (gate))  
     {  
       kernel_delete_ipv6_old (p, gate, ifindex, 0, table);  
       return 1;  
     }  
   return 0;  
 }  
   
 int  int
 rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p,  rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p,
              struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id,              struct in6_addr *gate, ifindex_t ifindex,
              u_int32_t metric, u_char distance, safi_t safi)              vrf_id_t vrf_id, int table_id,
               u_int32_t metric, u_int32_t mtu, u_char distance, safi_t safi)
 {  {
   struct rib *rib;    struct rib *rib;
   struct rib *same = NULL;    struct rib *same = NULL;
Line 2331  rib_add_ipv6 (int type, int flags, struct prefix_ipv6  Line 2571  rib_add_ipv6 (int type, int flags, struct prefix_ipv6 
   struct nexthop *nexthop;    struct nexthop *nexthop;
   
   /* Lookup table.  */    /* Lookup table.  */
  table = vrf_table (AFI_IP6, safi, 0);  table = zebra_vrf_table (AFI_IP6, safi, vrf_id);
   if (! table)    if (! table)
     return 0;      return 0;
   
Line 2345  rib_add_ipv6 (int type, int flags, struct prefix_ipv6  Line 2585  rib_add_ipv6 (int type, int flags, struct prefix_ipv6 
   if (type == ZEBRA_ROUTE_BGP && CHECK_FLAG (flags, ZEBRA_FLAG_IBGP))    if (type == ZEBRA_ROUTE_BGP && CHECK_FLAG (flags, ZEBRA_FLAG_IBGP))
     distance = 200;      distance = 200;
   
   /* Filter bogus route. */  
   if (rib_bogus_ipv6 (type, p, gate, ifindex, 0))  
     return 0;  
   
   /* Lookup route node.*/    /* Lookup route node.*/
   rn = route_node_get (table, (struct prefix *) p);    rn = route_node_get (table, (struct prefix *) p);
   
   /* If same type of route are installed, treat it as a implicit    /* If same type of route are installed, treat it as a implicit
      withdraw. */       withdraw. */
  for (rib = rn->info; rib; rib = rib->next)  RNODE_FOREACH_RIB (rn, rib)
     {      {
       if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))        if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
         continue;          continue;
Line 2382  rib_add_ipv6 (int type, int flags, struct prefix_ipv6  Line 2618  rib_add_ipv6 (int type, int flags, struct prefix_ipv6 
   rib->distance = distance;    rib->distance = distance;
   rib->flags = flags;    rib->flags = flags;
   rib->metric = metric;    rib->metric = metric;
  rib->table = vrf_id;  rib->mtu = mtu;
   rib->vrf_id = vrf_id;
   rib->table = table_id;
   rib->nexthop_num = 0;    rib->nexthop_num = 0;
   rib->uptime = time (NULL);    rib->uptime = time (NULL);
   
Line 2404  rib_add_ipv6 (int type, int flags, struct prefix_ipv6  Line 2642  rib_add_ipv6 (int type, int flags, struct prefix_ipv6 
   
   /* Link new rib to node.*/    /* Link new rib to node.*/
   rib_addnode (rn, rib);    rib_addnode (rn, rib);
     if (IS_ZEBRA_DEBUG_RIB)
     {
       zlog_debug ("%s: called rib_addnode (%p, %p) on new RIB entry",
         __func__, (void *)rn, (void *)rib);
       rib_dump (p, rib);
     }
   
   /* Free implicit route.*/    /* Free implicit route.*/
   if (same)    if (same)
     {
       if (IS_ZEBRA_DEBUG_RIB)
       {
         zlog_debug ("%s: calling rib_delnode (%p, %p) on existing RIB entry",
           __func__, (void *)rn, (void *)same);
         rib_dump (p, same);
       }
     rib_delnode (rn, same);      rib_delnode (rn, same);
     }
       
   route_unlock_node (rn);    route_unlock_node (rn);
   return 0;    return 0;
Line 2416  rib_add_ipv6 (int type, int flags, struct prefix_ipv6  Line 2668  rib_add_ipv6 (int type, int flags, struct prefix_ipv6 
 /* XXX factor with rib_delete_ipv6 */  /* XXX factor with rib_delete_ipv6 */
 int  int
 rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p,  rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p,
                 struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id, safi_t safi)                 struct in6_addr *gate, ifindex_t ifindex,
                  vrf_id_t vrf_id, safi_t safi)
 {  {
   struct route_table *table;    struct route_table *table;
   struct route_node *rn;    struct route_node *rn;
   struct rib *rib;    struct rib *rib;
   struct rib *fib = NULL;    struct rib *fib = NULL;
   struct rib *same = NULL;    struct rib *same = NULL;
  struct nexthop *nexthop;  struct nexthop *nexthop, *tnexthop;
  char buf1[INET6_ADDRSTRLEN];  int recursing;
   char buf1[PREFIX_STRLEN];
   char buf2[INET6_ADDRSTRLEN];    char buf2[INET6_ADDRSTRLEN];
   
   /* Apply mask. */    /* Apply mask. */
   apply_mask_ipv6 (p);    apply_mask_ipv6 (p);
   
   /* Lookup table.  */    /* Lookup table.  */
  table = vrf_table (AFI_IP6, safi, 0);  table = zebra_vrf_table (AFI_IP6, safi, vrf_id);
   if (! table)    if (! table)
     return 0;      return 0;
       
Line 2442  rib_delete_ipv6 (int type, int flags, struct prefix_ip Line 2696  rib_delete_ipv6 (int type, int flags, struct prefix_ip
       if (IS_ZEBRA_DEBUG_KERNEL)        if (IS_ZEBRA_DEBUG_KERNEL)
         {          {
           if (gate)            if (gate)
            zlog_debug ("route %s/%d via %s ifindex %d doesn't exist in rib",            zlog_debug ("route %s vrf %u via %s ifindex %d doesn't exist in rib",
                       inet_ntop (AF_INET6, &p->prefix, buf1, INET6_ADDRSTRLEN),                       prefix2str (p, buf1, sizeof(buf1)), vrf_id,
                       p->prefixlen, 
                        inet_ntop (AF_INET6, gate, buf2, INET6_ADDRSTRLEN),                         inet_ntop (AF_INET6, gate, buf2, INET6_ADDRSTRLEN),
                        ifindex);                         ifindex);
           else            else
            zlog_debug ("route %s/%d ifindex %d doesn't exist in rib",            zlog_debug ("route %s vrf %u ifindex %d doesn't exist in rib",
                       inet_ntop (AF_INET6, &p->prefix, buf1, INET6_ADDRSTRLEN),                       prefix2str (p, buf1, sizeof(buf1)), vrf_id,
                       p->prefixlen, 
                        ifindex);                         ifindex);
         }          }
       return ZEBRA_ERR_RTNOEXIST;        return ZEBRA_ERR_RTNOEXIST;
     }      }
   
   /* Lookup same type route. */    /* Lookup same type route. */
  for (rib = rn->info; rib; rib = rib->next)  RNODE_FOREACH_RIB (rn, rib)
     {      {
       if (CHECK_FLAG(rib->status, RIB_ENTRY_REMOVED))        if (CHECK_FLAG(rib->status, RIB_ENTRY_REMOVED))
         continue;          continue;
   
      if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))      if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB))
         fib = rib;          fib = rib;
   
       if (rib->type != type)        if (rib->type != type)
Line 2483  rib_delete_ipv6 (int type, int flags, struct prefix_ip Line 2735  rib_delete_ipv6 (int type, int flags, struct prefix_ip
           break;            break;
         }          }
       /* Make sure that the route found has the same gateway. */        /* Make sure that the route found has the same gateway. */
      else if (gate == NULL ||      else
               ((nexthop = rib->nexthop) &&        {
                (IPV6_ADDR_SAME (&nexthop->gate.ipv6, gate) ||          if (gate == NULL)
                 IPV6_ADDR_SAME (&nexthop->rgate.ipv6, gate))))            {
        {              same = rib;
          same = rib;              break;
          break;            }
        }          for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
             if (IPV6_ADDR_SAME (&nexthop->gate.ipv6, gate))
               {
                 same = rib;
                 break;
               }
           if (same)
             break;
         }
     }      }
   
   /* If same type of route can't be found and this message is from    /* If same type of route can't be found and this message is from
Line 2503  rib_delete_ipv6 (int type, int flags, struct prefix_ip Line 2763  rib_delete_ipv6 (int type, int flags, struct prefix_ip
           for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next)            for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next)
             UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);              UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
   
          UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED);          UNSET_FLAG (fib->status, RIB_ENTRY_SELECTED_FIB);
         }          }
       else        else
         {          {
           if (IS_ZEBRA_DEBUG_KERNEL)            if (IS_ZEBRA_DEBUG_KERNEL)
             {              {
               if (gate)                if (gate)
                zlog_debug ("route %s/%d via %s ifindex %d type %d doesn't exist in rib",                zlog_debug ("route %s vrf %u via %s ifindex %d type %d "
                           inet_ntop (AF_INET6, &p->prefix, buf1, INET6_ADDRSTRLEN),                           "doesn't exist in rib",
                           p->prefixlen,                           prefix2str (p, buf1, sizeof(buf1)), vrf_id,
                            inet_ntop (AF_INET6, gate, buf2, INET6_ADDRSTRLEN),                             inet_ntop (AF_INET6, gate, buf2, INET6_ADDRSTRLEN),
                            ifindex,                             ifindex,
                            type);                             type);
               else                else
                zlog_debug ("route %s/%d ifindex %d type %d doesn't exist in rib",                zlog_debug ("route %s vrf %u ifindex %d type %d doesn't exist in rib",
                           inet_ntop (AF_INET6, &p->prefix, buf1, INET6_ADDRSTRLEN),                           prefix2str (p, buf1, sizeof(buf1)), vrf_id,
                           p->prefixlen, 
                            ifindex,                             ifindex,
                            type);                             type);
             }              }
Line 2534  rib_delete_ipv6 (int type, int flags, struct prefix_ip Line 2793  rib_delete_ipv6 (int type, int flags, struct prefix_ip
   route_unlock_node (rn);    route_unlock_node (rn);
   return 0;    return 0;
 }  }
   
 /* Install static route into rib. */  
 static void  
 static_install_ipv6 (struct prefix *p, struct static_ipv6 *si)  
 {  
   struct rib *rib;  
   struct route_table *table;  
   struct route_node *rn;  
   
   /* Lookup table.  */  
   table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);  
   if (! table)  
     return;  
   
   /* Lookup existing route */  
   rn = route_node_get (table, p);  
   for (rib = rn->info; rib; rib = rib->next)  
     {  
       if (CHECK_FLAG(rib->status, RIB_ENTRY_REMOVED))  
         continue;  
   
       if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance)  
         break;  
     }  
   
   if (rib)  
     {  
       /* Same distance static route is there.  Update it with new  
          nexthop. */  
       route_unlock_node (rn);  
   
       switch (si->type)  
         {  
         case STATIC_IPV6_GATEWAY:  
           nexthop_ipv6_add (rib, &si->ipv6);  
           break;  
         case STATIC_IPV6_IFNAME:  
           nexthop_ifname_add (rib, si->ifname);  
           break;  
         case STATIC_IPV6_GATEWAY_IFNAME:  
           nexthop_ipv6_ifname_add (rib, &si->ipv6, si->ifname);  
           break;  
         }  
       rib_queue_add (&zebrad, rn);  
     }  
   else  
     {  
       /* This is new static route. */  
       rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));  
         
       rib->type = ZEBRA_ROUTE_STATIC;  
       rib->distance = si->distance;  
       rib->metric = 0;  
       rib->nexthop_num = 0;  
   
       switch (si->type)  
         {  
         case STATIC_IPV6_GATEWAY:  
           nexthop_ipv6_add (rib, &si->ipv6);  
           break;  
         case STATIC_IPV6_IFNAME:  
           nexthop_ifname_add (rib, si->ifname);  
           break;  
         case STATIC_IPV6_GATEWAY_IFNAME:  
           nexthop_ipv6_ifname_add (rib, &si->ipv6, si->ifname);  
           break;  
         }  
   
       /* Save the flags of this static routes (reject, blackhole) */  
       rib->flags = si->flags;  
   
       /* Link this rib to the tree. */  
       rib_addnode (rn, rib);  
     }  
 }  
   
 static int  
 static_ipv6_nexthop_same (struct nexthop *nexthop, struct static_ipv6 *si)  
 {  
   if (nexthop->type == NEXTHOP_TYPE_IPV6  
       && si->type == STATIC_IPV6_GATEWAY  
       && IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->ipv6))  
     return 1;  
   if (nexthop->type == NEXTHOP_TYPE_IFNAME  
       && si->type == STATIC_IPV6_IFNAME  
       && strcmp (nexthop->ifname, si->ifname) == 0)  
     return 1;  
   if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME  
       && si->type == STATIC_IPV6_GATEWAY_IFNAME  
       && IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->ipv6)  
       && strcmp (nexthop->ifname, si->ifname) == 0)  
     return 1;  
   return 0;  
 }  
   
 static void  
 static_uninstall_ipv6 (struct prefix *p, struct static_ipv6 *si)  
 {  
   struct route_table *table;  
   struct route_node *rn;  
   struct rib *rib;  
   struct nexthop *nexthop;  
   
   /* Lookup table.  */  
   table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);  
   if (! table)  
     return;  
   
   /* Lookup existing route with type and distance. */  
   rn = route_node_lookup (table, (struct prefix *) p);  
   if (! rn)  
     return;  
   
   for (rib = rn->info; rib; rib = rib->next)  
     {  
       if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))  
         continue;  
       
       if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance)  
         break;  
     }  
   
   if (! rib)  
     {  
       route_unlock_node (rn);  
       return;  
     }  
   
   /* Lookup nexthop. */  
   for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)  
     if (static_ipv6_nexthop_same (nexthop, si))  
       break;  
   
   /* Can't find nexthop. */  
   if (! nexthop)  
     {  
       route_unlock_node (rn);  
       return;  
     }  
     
   /* Check nexthop. */  
   if (rib->nexthop_num == 1)  
     {  
       rib_delnode (rn, rib);  
     }  
   else  
     {  
       if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))  
         rib_uninstall (rn, rib);  
       nexthop_delete (rib, nexthop);  
       nexthop_free (nexthop);  
       rib_queue_add (&zebrad, rn);  
     }  
   /* Unlock node. */  
   route_unlock_node (rn);  
 }  
   
 /* Add static route into static route configuration. */  /* Add static route into static route configuration. */
 int  int
 static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,  static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
                  const char *ifname, u_char flags, u_char distance,                   const char *ifname, u_char flags, u_char distance,
                 u_int32_t vrf_id)                 vrf_id_t vrf_id)
 {  {
   struct route_node *rn;    struct route_node *rn;
  struct static_ipv6 *si;  struct static_route *si;
  struct static_ipv6 *pp;  struct static_route *pp;
  struct static_ipv6 *cp;  struct static_route *cp;
  struct route_table *stable;  struct static_route *update = NULL;
   struct zebra_vrf *zvrf = vrf_info_get (vrf_id);
   struct route_table *stable = zvrf->stable[AFI_IP6][SAFI_UNICAST];
   
   /* Lookup table.  */  
   stable = vrf_static_table (AFI_IP6, SAFI_UNICAST, vrf_id);  
   if (! stable)    if (! stable)
     return -1;      return -1;
           
Line 2722  static_add_ipv6 (struct prefix *p, u_char type, struct Line 2826  static_add_ipv6 (struct prefix *p, u_char type, struct
   /* Do nothing if there is a same static route.  */    /* Do nothing if there is a same static route.  */
   for (si = rn->info; si; si = si->next)    for (si = rn->info; si; si = si->next)
     {      {
      if (distance == si->distance       if (type == si->type
          && type == si->type          && (! gate || IPV6_ADDR_SAME (gate, &si->addr.ipv6))
          && (! gate || IPV6_ADDR_SAME (gate, &si->ipv6)) 
           && (! ifname || strcmp (ifname, si->ifname) == 0))            && (! ifname || strcmp (ifname, si->ifname) == 0))
         {          {
          route_unlock_node (rn);          if (distance == si->distance)
          return 0;            {
               route_unlock_node (rn);
               return 0;
             }
           else
             update = si;
         }          }
     }      }
   
     if (update)
       static_delete_ipv6(p, type, gate, ifname, si->distance, vrf_id);
   
   /* Make new static route structure. */    /* Make new static route structure. */
  si = XCALLOC (MTYPE_STATIC_IPV6, sizeof (struct static_ipv6));  si = XCALLOC (MTYPE_STATIC_ROUTE, sizeof (struct static_route));
   
   si->type = type;    si->type = type;
   si->distance = distance;    si->distance = distance;
   si->flags = flags;    si->flags = flags;
     si->vrf_id = vrf_id;
   
   switch (type)    switch (type)
     {      {
     case STATIC_IPV6_GATEWAY:      case STATIC_IPV6_GATEWAY:
      si->ipv6 = *gate;      si->addr.ipv6 = *gate;
       break;        break;
     case STATIC_IPV6_IFNAME:      case STATIC_IPV6_IFNAME:
       si->ifname = XSTRDUP (0, ifname);        si->ifname = XSTRDUP (0, ifname);
       break;        break;
     case STATIC_IPV6_GATEWAY_IFNAME:      case STATIC_IPV6_GATEWAY_IFNAME:
      si->ipv6 = *gate;      si->addr.ipv6 = *gate;
       si->ifname = XSTRDUP (0, ifname);        si->ifname = XSTRDUP (0, ifname);
       break;        break;
     }      }
Line 2774  static_add_ipv6 (struct prefix *p, u_char type, struct Line 2886  static_add_ipv6 (struct prefix *p, u_char type, struct
   si->next = cp;    si->next = cp;
   
   /* Install into rib. */    /* Install into rib. */
  static_install_ipv6 (p, si);  static_install_route (AFI_IP6, SAFI_UNICAST, p, si);
   
   return 1;    return 1;
 }  }
Line 2782  static_add_ipv6 (struct prefix *p, u_char type, struct Line 2894  static_add_ipv6 (struct prefix *p, u_char type, struct
 /* Delete static route from static route configuration. */  /* Delete static route from static route configuration. */
 int  int
 static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,  static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
                    const char *ifname, u_char distance, u_int32_t vrf_id)                    const char *ifname, u_char distance, vrf_id_t vrf_id)
 {  {
   struct route_node *rn;    struct route_node *rn;
  struct static_ipv6 *si;  struct static_route *si;
   struct route_table *stable;    struct route_table *stable;
   
   /* Lookup table.  */    /* Lookup table.  */
  stable = vrf_static_table (AFI_IP6, SAFI_UNICAST, vrf_id);  stable = zebra_vrf_static_table (AFI_IP6, SAFI_UNICAST, vrf_id);
   if (! stable)    if (! stable)
     return -1;      return -1;
   
Line 2802  static_delete_ipv6 (struct prefix *p, u_char type, str Line 2914  static_delete_ipv6 (struct prefix *p, u_char type, str
   for (si = rn->info; si; si = si->next)    for (si = rn->info; si; si = si->next)
     if (distance == si->distance       if (distance == si->distance 
         && type == si->type          && type == si->type
        && (! gate || IPV6_ADDR_SAME (gate, &si->ipv6))        && (! gate || IPV6_ADDR_SAME (gate, &si->addr.ipv6))
         && (! ifname || strcmp (ifname, si->ifname) == 0))          && (! ifname || strcmp (ifname, si->ifname) == 0))
       break;        break;
   
Line 2814  static_delete_ipv6 (struct prefix *p, u_char type, str Line 2926  static_delete_ipv6 (struct prefix *p, u_char type, str
     }      }
   
   /* Install into rib. */    /* Install into rib. */
  static_uninstall_ipv6 (p, si);  static_uninstall_route (AFI_IP6, SAFI_UNICAST, p, si);
   
   /* Unlink static route from linked list. */    /* Unlink static route from linked list. */
   if (si->prev)    if (si->prev)
Line 2827  static_delete_ipv6 (struct prefix *p, u_char type, str Line 2939  static_delete_ipv6 (struct prefix *p, u_char type, str
   /* Free static route configuration. */    /* Free static route configuration. */
   if (ifname)    if (ifname)
     XFREE (0, si->ifname);      XFREE (0, si->ifname);
  XFREE (MTYPE_STATIC_IPV6, si);  XFREE (MTYPE_STATIC_ROUTE, si);
   
   return 1;    return 1;
 }  }
#endif /* HAVE_IPV6 */
 
 /* RIB update function. */  /* RIB update function. */
 void  void
rib_update (void)rib_update (vrf_id_t vrf_id)
 {  {
   struct route_node *rn;    struct route_node *rn;
   struct route_table *table;    struct route_table *table;
       
  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);  table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id);
   if (table)    if (table)
     for (rn = route_top (table); rn; rn = route_next (rn))      for (rn = route_top (table); rn; rn = route_next (rn))
      if (rn->info)      if (rnode_to_ribs (rn))
         rib_queue_add (&zebrad, rn);          rib_queue_add (&zebrad, rn);
   
  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);  table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id);
   if (table)    if (table)
     for (rn = route_top (table); rn; rn = route_next (rn))      for (rn = route_top (table); rn; rn = route_next (rn))
      if (rn->info)      if (rnode_to_ribs (rn))
         rib_queue_add (&zebrad, rn);          rib_queue_add (&zebrad, rn);
 }  }
   
 /* Remove all routes which comes from non main table.  */  /* Remove all routes which comes from non main table.  */
 static void  static void
 rib_weed_table (struct route_table *table)  rib_weed_table (struct route_table *table)
Line 2864  rib_weed_table (struct route_table *table) Line 2975  rib_weed_table (struct route_table *table)
   
   if (table)    if (table)
     for (rn = route_top (table); rn; rn = route_next (rn))      for (rn = route_top (table); rn; rn = route_next (rn))
      for (rib = rn->info; rib; rib = next)      RNODE_FOREACH_RIB_SAFE (rn, rib, next)
         {          {
           next = rib->next;  
   
           if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))            if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
             continue;              continue;
   
Line 2881  rib_weed_table (struct route_table *table) Line 2990  rib_weed_table (struct route_table *table)
 void  void
 rib_weed_tables (void)  rib_weed_tables (void)
 {  {
  rib_weed_table (vrf_table (AFI_IP, SAFI_UNICAST, 0));  vrf_iter_t iter;
  rib_weed_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0));  struct zebra_vrf *zvrf;
 
   for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter))
     if ((zvrf = vrf_iter2info (iter)) != NULL)
       {
         rib_weed_table (zvrf->table[AFI_IP][SAFI_UNICAST]);
         rib_weed_table (zvrf->table[AFI_IP6][SAFI_UNICAST]);
       }
 }  }
 #if 0
 /* Delete self installed routes after zebra is relaunched.  */  /* Delete self installed routes after zebra is relaunched.  */
 static void  static void
 rib_sweep_table (struct route_table *table)  rib_sweep_table (struct route_table *table)
Line 2896  rib_sweep_table (struct route_table *table) Line 3013  rib_sweep_table (struct route_table *table)
   
   if (table)    if (table)
     for (rn = route_top (table); rn; rn = route_next (rn))      for (rn = route_top (table); rn; rn = route_next (rn))
      for (rib = rn->info; rib; rib = next)      RNODE_FOREACH_RIB_SAFE (rn, rib, next)
         {          {
           next = rib->next;  
   
           if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))            if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
             continue;              continue;
   
           if (rib->type == ZEBRA_ROUTE_KERNEL &&             if (rib->type == ZEBRA_ROUTE_KERNEL && 
               CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELFROUTE))                CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELFROUTE))
             {              {
              ret = rib_uninstall_kernel (rn, rib);              ret = rib_update_kernel (rn, rib, NULL);
               if (! ret)                if (! ret)
                 rib_delnode (rn, rib);                  rib_delnode (rn, rib);
             }              }
         }          }
 }  }
   #endif
   
 /* Sweep all RIB tables.  */  /* Sweep all RIB tables.  */
 void  void
 rib_sweep_route (void)  rib_sweep_route (void)
 {  {
  rib_sweep_table (vrf_table (AFI_IP, SAFI_UNICAST, 0));  vrf_iter_t iter;
  rib_sweep_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0));  struct zebra_vrf *zvrf;
 
   for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter))
     if ((zvrf = vrf_iter2info (iter)) != NULL)
       {
         rib_weed_table (zvrf->table[AFI_IP][SAFI_UNICAST]);
         rib_weed_table (zvrf->table[AFI_IP6][SAFI_UNICAST]);
       }
 }  }
   
 /* Remove specific by protocol routes from 'table'. */  /* Remove specific by protocol routes from 'table'. */
Line 2932  rib_score_proto_table (u_char proto, struct route_tabl Line 3055  rib_score_proto_table (u_char proto, struct route_tabl
   
   if (table)    if (table)
     for (rn = route_top (table); rn; rn = route_next (rn))      for (rn = route_top (table); rn; rn = route_next (rn))
      for (rib = rn->info; rib; rib = next)      RNODE_FOREACH_RIB_SAFE (rn, rib, next)
         {          {
           next = rib->next;  
           if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))            if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
             continue;              continue;
           if (rib->type == proto)            if (rib->type == proto)
Line 2951  rib_score_proto_table (u_char proto, struct route_tabl Line 3073  rib_score_proto_table (u_char proto, struct route_tabl
 unsigned long  unsigned long
 rib_score_proto (u_char proto)  rib_score_proto (u_char proto)
 {  {
  return  rib_score_proto_table (proto, vrf_table (AFI_IP,  SAFI_UNICAST, 0))  vrf_iter_t iter;
         +rib_score_proto_table (proto, vrf_table (AFI_IP6, SAFI_UNICAST, 0));  struct zebra_vrf *zvrf;
   unsigned long cnt = 0;
 
   for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter))
     if ((zvrf = vrf_iter2info (iter)) != NULL)
       cnt += rib_score_proto_table (proto, zvrf->table[AFI_IP][SAFI_UNICAST])
             +rib_score_proto_table (proto, zvrf->table[AFI_IP6][SAFI_UNICAST]);
 
   return cnt;
 }  }
   
 /* Close RIB and clean up kernel routes. */  /* Close RIB and clean up kernel routes. */
static voidvoid
 rib_close_table (struct route_table *table)  rib_close_table (struct route_table *table)
 {  {
   struct route_node *rn;    struct route_node *rn;
     rib_table_info_t *info = table->info;
   struct rib *rib;    struct rib *rib;
   
   if (table)    if (table)
     for (rn = route_top (table); rn; rn = route_next (rn))      for (rn = route_top (table); rn; rn = route_next (rn))
      for (rib = rn->info; rib; rib = rib->next)      RNODE_FOREACH_RIB (rn, rib)
         {          {
          if (! RIB_SYSTEM_ROUTE (rib)          if (!CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB))
              && CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))            continue;
            rib_uninstall_kernel (rn, rib);
           if (info->safi == SAFI_UNICAST)
             zfpm_trigger_update (rn, NULL);
 
           if (! RIB_SYSTEM_ROUTE (rib))
             rib_update_kernel (rn, rib, NULL);
         }          }
 }  }
   
Line 2976  rib_close_table (struct route_table *table) Line 3112  rib_close_table (struct route_table *table)
 void  void
 rib_close (void)  rib_close (void)
 {  {
  rib_close_table (vrf_table (AFI_IP, SAFI_UNICAST, 0));  vrf_iter_t iter;
  rib_close_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0));  struct zebra_vrf *zvrf;
 
   for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter))
     if ((zvrf = vrf_iter2info (iter)) != NULL)
       {
         rib_close_table (zvrf->table[AFI_IP][SAFI_UNICAST]);
         rib_close_table (zvrf->table[AFI_IP6][SAFI_UNICAST]);
       }
 }  }
 /* Routing information base initialize. */  /* Routing information base initialize. */
 void  void
 rib_init (void)  rib_init (void)
 {  {
   rib_queue_init (&zebrad);    rib_queue_init (&zebrad);
   /* VRF initialization.  */  
   vrf_init ();  
 }  }
   
   /*
    * vrf_id_get_next
    *
    * Get the first vrf id that is greater than the given vrf id if any.
    *
    * Returns TRUE if a vrf id was found, FALSE otherwise.
    */
   static inline int
   vrf_id_get_next (vrf_id_t vrf_id, vrf_id_t *next_id_p)
   {
     vrf_iter_t iter = vrf_iterator (vrf_id);
     struct zebra_vrf *zvrf = vrf_iter2info (iter);
   
     /* The same one ? Then find out the next. */
     if (zvrf && (zvrf->vrf_id == vrf_id))
       zvrf = vrf_iter2info (vrf_next (iter));
   
     if (zvrf)
       {
         *next_id_p = zvrf->vrf_id;
         return 1;
       }
   
     return 0;
   }
   
   /*
    * rib_tables_iter_next
    *
    * Returns the next table in the iteration.
    */
   struct route_table *
   rib_tables_iter_next (rib_tables_iter_t *iter)
   {
     struct route_table *table;
   
     /*
      * Array that helps us go over all AFI/SAFI combinations via one
      * index.
      */
     static struct {
       afi_t afi;
       safi_t safi;
     } afi_safis[] = {
       { AFI_IP, SAFI_UNICAST },
       { AFI_IP, SAFI_MULTICAST },
       { AFI_IP6, SAFI_UNICAST },
       { AFI_IP6, SAFI_MULTICAST },
     };
   
     table = NULL;
   
     switch (iter->state)
       {
   
       case RIB_TABLES_ITER_S_INIT:
         iter->vrf_id = VRF_DEFAULT;
         iter->afi_safi_ix = -1;
   
         /* Fall through */
   
       case RIB_TABLES_ITER_S_ITERATING:
         iter->afi_safi_ix++;
         while (1)
           {
   
             while (iter->afi_safi_ix < (int) ZEBRA_NUM_OF (afi_safis))
               {
                 table = zebra_vrf_table (afi_safis[iter->afi_safi_ix].afi,
                                    afi_safis[iter->afi_safi_ix].safi,
                                    iter->vrf_id);
                 if (table)
                   break;
   
                 iter->afi_safi_ix++;
               }
   
             /*
              * Found another table in this vrf.
              */
             if (table)
               break;
   
             /*
              * Done with all tables in the current vrf, go to the next
              * one.
              */
             if (!vrf_id_get_next (iter->vrf_id, &iter->vrf_id))
               break;
   
             iter->afi_safi_ix = 0;
           }
   
         break;
   
       case RIB_TABLES_ITER_S_DONE:
         return NULL;
       }
   
     if (table)
       iter->state = RIB_TABLES_ITER_S_ITERATING;
     else
       iter->state = RIB_TABLES_ITER_S_DONE;
   
     return table;
   }
   
   /*
    * Create a routing table for the specific AFI/SAFI in the given VRF.
    */
   static void
   zebra_vrf_table_create (struct zebra_vrf *zvrf, afi_t afi, safi_t safi)
   {
     rib_table_info_t *info;
     struct route_table *table;
   
     assert (!zvrf->table[afi][safi]);
   
     table = route_table_init ();
     zvrf->table[afi][safi] = table;
   
     info = XCALLOC (MTYPE_RIB_TABLE_INFO, sizeof (*info));
     info->zvrf = zvrf;
     info->afi = afi;
     info->safi = safi;
     table->info = info;
   }
   
   /* Allocate new zebra VRF. */
   struct zebra_vrf *
   zebra_vrf_alloc (vrf_id_t vrf_id)
   {
     struct zebra_vrf *zvrf;
   #ifdef HAVE_NETLINK
     char nl_name[64];
   #endif
   
     zvrf = XCALLOC (MTYPE_ZEBRA_VRF, sizeof (struct zebra_vrf));
   
     /* Allocate routing table and static table.  */
     zebra_vrf_table_create (zvrf, AFI_IP, SAFI_UNICAST);
     zebra_vrf_table_create (zvrf, AFI_IP6, SAFI_UNICAST);
     zvrf->stable[AFI_IP][SAFI_UNICAST] = route_table_init ();
     zvrf->stable[AFI_IP6][SAFI_UNICAST] = route_table_init ();
     zebra_vrf_table_create (zvrf, AFI_IP, SAFI_MULTICAST);
     zebra_vrf_table_create (zvrf, AFI_IP6, SAFI_MULTICAST);
     zvrf->stable[AFI_IP][SAFI_MULTICAST] = route_table_init ();
     zvrf->stable[AFI_IP6][SAFI_MULTICAST] = route_table_init ();
   
     /* Set VRF ID */
     zvrf->vrf_id = vrf_id;
   
   #ifdef HAVE_NETLINK
     /* Initialize netlink sockets */
     snprintf (nl_name, 64, "netlink-listen (vrf %u)", vrf_id);
     zvrf->netlink.sock = -1;
     zvrf->netlink.name = XSTRDUP (MTYPE_NETLINK_NAME, nl_name);
   
     snprintf (nl_name, 64, "netlink-cmd (vrf %u)", vrf_id);
     zvrf->netlink_cmd.sock = -1;
     zvrf->netlink_cmd.name = XSTRDUP (MTYPE_NETLINK_NAME, nl_name);
   #endif
   
     return zvrf;
   }
   
   /* Lookup the routing table in an enabled VRF. */
   struct route_table *
   zebra_vrf_table (afi_t afi, safi_t safi, vrf_id_t vrf_id)
   {
     struct zebra_vrf *zvrf = vrf_info_lookup (vrf_id);
   
     if (!zvrf)
       return NULL;
   
     if (afi >= AFI_MAX || safi >= SAFI_MAX)
       return NULL;
   
     return zvrf->table[afi][safi];
   }
   
   /* Lookup the static routing table in a VRF. */
   struct route_table *
   zebra_vrf_static_table (afi_t afi, safi_t safi, vrf_id_t vrf_id)
   {
     struct zebra_vrf *zvrf = vrf_info_lookup (vrf_id);
   
     if (!zvrf)
       return NULL;
   
     if (afi >= AFI_MAX || safi >= SAFI_MAX)
       return NULL;
   
     return zvrf->stable[afi][safi];
   }
   

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


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