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

version 1.1.1.1, 2012/02/21 17:26:11 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 55  static const struct Line 57  static const struct
 {    {  
   int key;    int key;
   int distance;    int distance;
} route_info[] =} route_info[ZEBRA_ROUTE_MAX] =
 {  {
  {ZEBRA_ROUTE_SYSTEM,    0},  [ZEBRA_ROUTE_SYSTEM]  = {ZEBRA_ROUTE_SYSTEM,    0},
  {ZEBRA_ROUTE_KERNEL,    0},  [ZEBRA_ROUTE_KERNEL]  = {ZEBRA_ROUTE_KERNEL,    0},
  {ZEBRA_ROUTE_CONNECT,   0},  [ZEBRA_ROUTE_CONNECT] = {ZEBRA_ROUTE_CONNECT,   0},
  {ZEBRA_ROUTE_STATIC,    1},  [ZEBRA_ROUTE_STATIC]  = {ZEBRA_ROUTE_STATIC,    1},
  {ZEBRA_ROUTE_RIP,     120},  [ZEBRA_ROUTE_RIP]     = {ZEBRA_ROUTE_RIP,     120},
  {ZEBRA_ROUTE_RIPNG,   120},  [ZEBRA_ROUTE_RIPNG]   = {ZEBRA_ROUTE_RIPNG,   120},
  {ZEBRA_ROUTE_OSPF,    110},  [ZEBRA_ROUTE_OSPF]    = {ZEBRA_ROUTE_OSPF,    110},
  {ZEBRA_ROUTE_OSPF6,   110},  [ZEBRA_ROUTE_OSPF6]   = {ZEBRA_ROUTE_OSPF6,   110},
  {ZEBRA_ROUTE_ISIS,    115},  [ZEBRA_ROUTE_ISIS]    = {ZEBRA_ROUTE_ISIS,    115},
  {ZEBRA_ROUTE_BGP,      20  /* IBGP is 200. */}  [ZEBRA_ROUTE_BGP]     = {ZEBRA_ROUTE_BGP,      20  /* IBGP is 200. */},
   [ZEBRA_ROUTE_BABEL]   = {ZEBRA_ROUTE_BABEL,    95},
   /* 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 (); 
 
  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 172  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 225  nexthop_ipv4_add (struct rib *rib, struct in_addr *ipv Line 241  nexthop_ipv4_add (struct rib *rib, struct in_addr *ipv
   return nexthop;    return nexthop;
 }  }
   
static 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 243  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 276  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 289  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 305  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 315  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 330  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 344  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 365  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 376  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 383  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 405  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 416  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 431  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 445  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 466  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 478  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 485  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 508  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 557  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 594  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 608  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 628  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 651  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 667  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 718  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 744  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 753  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 772  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 782  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 791  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 813  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 825  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 839  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 849  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 861  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 872  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 882  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 895  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 957  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 1026  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 1182  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 1216  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 1229  static const u_char meta_queue_map[ZEBRA_ROUTE_MAX] =  Line 1470  static const u_char meta_queue_map[ZEBRA_ROUTE_MAX] = 
   [ZEBRA_ROUTE_ISIS]    = 2,    [ZEBRA_ROUTE_ISIS]    = 2,
   [ZEBRA_ROUTE_BGP]     = 3,    [ZEBRA_ROUTE_BGP]     = 3,
   [ZEBRA_ROUTE_HSLS]    = 4,    [ZEBRA_ROUTE_HSLS]    = 4,
     [ZEBRA_ROUTE_BABEL]   = 2,
 };  };
   
 /* Look into the RN and queue it into one or more priority queues,  /* Look into the RN and queue it into one or more priority queues,
Line 1238  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 1271  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)
 {  {
    assert (zebra && rn);
  if (IS_ZEBRA_DEBUG_RIB_Q)
   /* Pointless to queue a route_node with no RIB entries to add or remove */
   if (!rnode_to_ribs (rn))
     {      {
      char buf[INET6_ADDRSTRLEN];      zlog_debug ("%s: called for route_node (%p, %d) with no ribs",
                   __func__, (void *)rn, rn->lock);
       zlog_backtrace(LOG_DEBUG);
       return;
     }
   
      zlog_info ("%s: %s/%d: work queue added", __func__,  if (IS_ZEBRA_DEBUG_RIB_Q)
                 inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN),    rnode_info (rn, "work queue added");
                 rn->p.prefixlen);
   assert (zebra);
 
   if (zebra->ribq == NULL)
     {
       zlog_err ("%s: work_queue does not exist!", __func__);
       return;
     }      }
   
   /*    /*
Line 1293  rib_queue_add (struct zebra_t *zebra, struct route_nod Line 1544  rib_queue_add (struct zebra_t *zebra, struct route_nod
     work_queue_add (zebra->ribq, zebra->mq);      work_queue_add (zebra->ribq, zebra->mq);
   
   rib_meta_queue_add (zebra->mq, rn);    rib_meta_queue_add (zebra->mq, rn);
   
     if (IS_ZEBRA_DEBUG_RIB_Q)
       rnode_debug (rn, "rn %p queued", (void *)rn);
   
     return;
 }  }
   
 /* Create new meta queue.  /* Create new meta queue.
Line 1320  meta_queue_new (void) Line 1576  meta_queue_new (void)
 static void  static void
 rib_queue_init (struct zebra_t *zebra)  rib_queue_init (struct zebra_t *zebra)
 {  {
     assert (zebra);
     
   if (! (zebra->ribq = work_queue_new (zebra->master,     if (! (zebra->ribq = work_queue_new (zebra->master, 
                                        "route_node processing")))                                         "route_node processing")))
     {      {
Line 1335  rib_queue_init (struct zebra_t *zebra) Line 1593  rib_queue_init (struct zebra_t *zebra)
   zebra->ribq->spec.hold = rib_process_hold_time;    zebra->ribq->spec.hold = rib_process_hold_time;
       
   if (!(zebra->mq = meta_queue_new ()))    if (!(zebra->mq = meta_queue_new ()))
     {
     zlog_err ("%s: could not initialise meta queue!", __func__);      zlog_err ("%s: could not initialise meta queue!", __func__);
       return;
     }
     return;
 }  }
   
 /* RIB updates are processed via a queue of pointers to route_nodes.  /* RIB updates are processed via a queue of pointers to route_nodes.
Line 1344  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 1360  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 1381  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 1418  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 1452  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 1491  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)              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 1501  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_UNICAST, 0);  table = zebra_vrf_table (AFI_IP, safi, vrf_id);
   if (! table)    if (! table)
     return 0;      return 0;
   
Line 1511  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)
     {      {
      distance = route_info[type].distance;      if ((unsigned)type >= array_size(route_info))
         distance = 150;
       else
         distance = route_info[type].distance;
   
       /* iBGP distance is 200. */        /* iBGP distance is 200. */
       if (type == ZEBRA_ROUTE_BGP && CHECK_FLAG (flags, ZEBRA_FLAG_IBGP))        if (type == ZEBRA_ROUTE_BGP && CHECK_FLAG (flags, ZEBRA_FLAG_IBGP))
Line 1523  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 1552  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 1574  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 1594  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 1627  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 1657  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 1679  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 1706  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 1726  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 1747  void rib_lookup_and_pushup (struct prefix_ipv4 * p) Line 2003  void rib_lookup_and_pushup (struct prefix_ipv4 * p)
 }  }
   
 int  int
rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib)rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib, safi_t safi)
 {  {
   struct route_table *table;    struct route_table *table;
   struct route_node *rn;    struct route_node *rn;
Line 1755  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_UNICAST, 0);  table = zebra_vrf_table (AFI_IP, safi, rib->vrf_id);
   if (! table)    if (! table)
     return 0;      return 0;
   
   /* Make it sure prefixlen is applied to the prefix. */    /* Make it sure prefixlen is applied to the prefix. */
   apply_mask_ipv4 (p);    apply_mask_ipv4 (p);
   
Line 1777  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 1797  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 1807  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 1820  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)                 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_UNICAST, 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 1853  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)
         continue;          continue;
       if (rib->type == ZEBRA_ROUTE_CONNECT && (nexthop = rib->nexthop) &&        if (rib->type == ZEBRA_ROUTE_CONNECT && (nexthop = rib->nexthop) &&
          nexthop->type == NEXTHOP_TYPE_IFINDEX && nexthop->ifindex == ifindex)          nexthop->type == NEXTHOP_TYPE_IFINDEX)
         {          {
             if (nexthop->ifindex != ifindex)
               continue;
           if (rib->refcnt)            if (rib->refcnt)
             {              {
               rib->refcnt--;                rib->refcnt--;
Line 1892  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 1912  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 1943  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 1975  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 1995  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 2019  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 2045  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 2054  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 2071  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 2096  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 2129  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 2144  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 2168  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 2186  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 2222  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 2234  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 2247  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)              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 2290  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_UNICAST, 0);  table = zebra_vrf_table (AFI_IP6, safi, vrf_id);
   if (! table)    if (! table)
     return 0;      return 0;
   
Line 2304  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 2341  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 2363  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 2375  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)                 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_UNICAST, 0);  table = zebra_vrf_table (AFI_IP6, safi, vrf_id);
   if (! table)    if (! table)
     return 0;      return 0;
       
Line 2401  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)
         continue;          continue;
       if (rib->type == ZEBRA_ROUTE_CONNECT && (nexthop = rib->nexthop) &&        if (rib->type == ZEBRA_ROUTE_CONNECT && (nexthop = rib->nexthop) &&
          nexthop->type == NEXTHOP_TYPE_IFINDEX && nexthop->ifindex == ifindex)          nexthop->type == NEXTHOP_TYPE_IFINDEX)
         {          {
             if (nexthop->ifindex != ifindex)
               continue;
           if (rib->refcnt)            if (rib->refcnt)
             {              {
               rib->refcnt--;                rib->refcnt--;
Line 2440  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 2460  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 2491  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 2679  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 2731  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 2739  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 2759  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 2771  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 2784  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 2821  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 2838  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 2853  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'. */
 static unsigned long
 rib_score_proto_table (u_char proto, struct route_table *table)
 {
   struct route_node *rn;
   struct rib *rib;
   struct rib *next;
   unsigned long n = 0;
 
   if (table)
     for (rn = route_top (table); rn; rn = route_next (rn))
       RNODE_FOREACH_RIB_SAFE (rn, rib, next)
         {
           if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
             continue;
           if (rib->type == proto)
             {
               rib_delnode (rn, rib);
               n++;
             }
         }
 
   return n;
 }
 
 /* Remove specific by protocol routes. */
 unsigned long
 rib_score_proto (u_char proto)
 {
   vrf_iter_t iter;
   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 2899  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.1  
changed lines
  Added in v.1.1.1.4


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