version 1.1.1.2, 2012/10/09 09:22:29
|
version 1.1.1.3, 2013/07/21 23:54:41
|
Line 40
|
Line 40
|
#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 74 static const struct
|
Line 75 static const struct
|
/* Vector for routing table. */ |
/* Vector for routing table. */ |
static vector vrf_vector; |
static vector vrf_vector; |
|
|
|
/* |
|
* vrf_table_create |
|
*/ |
|
static void |
|
vrf_table_create (struct vrf *vrf, afi_t afi, safi_t safi) |
|
{ |
|
rib_table_info_t *info; |
|
struct route_table *table; |
|
|
|
assert (!vrf->table[afi][safi]); |
|
|
|
table = route_table_init (); |
|
vrf->table[afi][safi] = table; |
|
|
|
info = XCALLOC (MTYPE_RIB_TABLE_INFO, sizeof (*info)); |
|
info->vrf = vrf; |
|
info->afi = afi; |
|
info->safi = safi; |
|
table->info = info; |
|
} |
|
|
/* Allocate new VRF. */ |
/* Allocate new VRF. */ |
static struct vrf * |
static struct vrf * |
vrf_alloc (const char *name) |
vrf_alloc (const char *name) |
Line 87 vrf_alloc (const char *name)
|
Line 109 vrf_alloc (const char *name)
|
vrf->name = XSTRDUP (MTYPE_VRF_NAME, name); |
vrf->name = XSTRDUP (MTYPE_VRF_NAME, name); |
|
|
/* Allocate routing table and static table. */ |
/* Allocate routing table and static table. */ |
vrf->table[AFI_IP][SAFI_UNICAST] = route_table_init (); | vrf_table_create (vrf, AFI_IP, SAFI_UNICAST); |
vrf->table[AFI_IP6][SAFI_UNICAST] = route_table_init (); | vrf_table_create (vrf, AFI_IP6, SAFI_UNICAST); |
vrf->stable[AFI_IP][SAFI_UNICAST] = route_table_init (); |
vrf->stable[AFI_IP][SAFI_UNICAST] = route_table_init (); |
vrf->stable[AFI_IP6][SAFI_UNICAST] = route_table_init (); |
vrf->stable[AFI_IP6][SAFI_UNICAST] = route_table_init (); |
vrf->table[AFI_IP][SAFI_MULTICAST] = route_table_init (); | vrf_table_create (vrf, AFI_IP, SAFI_MULTICAST); |
vrf->table[AFI_IP6][SAFI_MULTICAST] = route_table_init (); | vrf_table_create (vrf, AFI_IP6, SAFI_MULTICAST); |
vrf->stable[AFI_IP][SAFI_MULTICAST] = route_table_init (); |
vrf->stable[AFI_IP][SAFI_MULTICAST] = route_table_init (); |
vrf->stable[AFI_IP6][SAFI_MULTICAST] = route_table_init (); |
vrf->stable[AFI_IP6][SAFI_MULTICAST] = route_table_init (); |
|
|
Line 133 vrf_table (afi_t afi, safi_t safi, u_int32_t id)
|
Line 155 vrf_table (afi_t afi, safi_t safi, u_int32_t id)
|
if (! vrf) |
if (! vrf) |
return NULL; |
return NULL; |
|
|
|
if( afi >= AFI_MAX || safi >= SAFI_MAX ) |
|
return NULL; |
|
|
return vrf->table[afi][safi]; |
return vrf->table[afi][safi]; |
} |
} |
|
|
Line 146 vrf_static_table (afi_t afi, safi_t safi, u_int32_t id
|
Line 171 vrf_static_table (afi_t afi, safi_t safi, u_int32_t id
|
if (! vrf) |
if (! vrf) |
return NULL; |
return NULL; |
|
|
|
if( afi >= AFI_MAX || safi >= SAFI_MAX ) |
|
return NULL; |
|
|
return vrf->stable[afi][safi]; |
return vrf->stable[afi][safi]; |
} |
} |
|
|
|
/* |
|
* nexthop_type_to_str |
|
*/ |
|
const char * |
|
nexthop_type_to_str (enum nexthop_types_t nh_type) |
|
{ |
|
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", |
|
}; |
|
|
|
if (nh_type >= ZEBRA_NUM_OF (desc)) |
|
return "<Invalid nh type>"; |
|
|
|
return desc[nh_type]; |
|
} |
|
|
/* Add nexthop to the end of the list. */ |
/* Add nexthop to the end of the list. */ |
static void |
static void |
nexthop_add (struct rib *rib, struct nexthop *nexthop) |
nexthop_add (struct rib *rib, struct nexthop *nexthop) |
Line 351 nexthop_active_ipv4 (struct rib *rib, struct nexthop *
|
Line 404 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; |
Line 452 nexthop_active_ipv6 (struct rib *rib, struct nexthop *
|
Line 505 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; |
Line 543 rib_match_ipv4 (struct in_addr addr)
|
Line 596 rib_match_ipv4 (struct in_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; |
Line 601 rib_lookup_ipv4 (struct prefix_ipv4 *p)
|
Line 654 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; |
Line 658 rib_lookup_ipv4_route (struct prefix_ipv4 *p, union so
|
Line 711 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; |
Line 678 rib_lookup_ipv4_route (struct prefix_ipv4 *p, union so
|
Line 731 rib_lookup_ipv4_route (struct prefix_ipv4 *p, union so
|
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 */ |
/* We are happy with either direct or recursive hexthop */ |
if (nexthop->gate.ipv4.s_addr == qgate->sin.sin_addr.s_addr || | if (nexthop->gate.ipv4.s_addr == sockunion2ip (qgate) || |
nexthop->rgate.ipv4.s_addr == qgate->sin.sin_addr.s_addr) | nexthop->rgate.ipv4.s_addr == sockunion2ip (qgate)) |
return ZEBRA_RIB_FOUND_EXACT; |
return ZEBRA_RIB_FOUND_EXACT; |
else |
else |
{ |
{ |
Line 688 rib_lookup_ipv4_route (struct prefix_ipv4 *p, union so
|
Line 741 rib_lookup_ipv4_route (struct prefix_ipv4 *p, union so
|
char gate_buf[INET_ADDRSTRLEN], rgate_buf[INET_ADDRSTRLEN], qgate_buf[INET_ADDRSTRLEN]; |
char gate_buf[INET_ADDRSTRLEN], rgate_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, &nexthop->rgate.ipv4.s_addr, rgate_buf, INET_ADDRSTRLEN); |
inet_ntop (AF_INET, &qgate->sin.sin_addr.s_addr, qgate_buf, INET_ADDRSTRLEN); | inet_ntop (AF_INET, &sockunion2ip (qgate), qgate_buf, INET_ADDRSTRLEN); |
zlog_debug ("%s: qgate == %s, gate == %s, rgate == %s", __func__, qgate_buf, gate_buf, rgate_buf); |
zlog_debug ("%s: qgate == %s, gate == %s, rgate == %s", __func__, qgate_buf, gate_buf, rgate_buf); |
} |
} |
return ZEBRA_RIB_FOUND_NOGATE; |
return ZEBRA_RIB_FOUND_NOGATE; |
Line 725 rib_match_ipv6 (struct in6_addr *addr)
|
Line 778 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; |
Line 915 rib_install_kernel (struct route_node *rn, struct rib
|
Line 968 rib_install_kernel (struct route_node *rn, struct rib
|
int ret = 0; |
int ret = 0; |
struct nexthop *nexthop; |
struct nexthop *nexthop; |
|
|
|
/* |
|
* Make sure we update the FPM any time we send new information to |
|
* the kernel. |
|
*/ |
|
zfpm_trigger_update (rn, "installing in kernel"); |
switch (PREFIX_FAMILY (&rn->p)) |
switch (PREFIX_FAMILY (&rn->p)) |
{ |
{ |
case AF_INET: |
case AF_INET: |
Line 942 rib_uninstall_kernel (struct route_node *rn, struct ri
|
Line 1000 rib_uninstall_kernel (struct route_node *rn, struct ri
|
int ret = 0; |
int ret = 0; |
struct nexthop *nexthop; |
struct nexthop *nexthop; |
|
|
|
/* |
|
* Make sure we update the FPM any time we send new information to |
|
* the kernel. |
|
*/ |
|
zfpm_trigger_update (rn, "uninstalling from kernel"); |
|
|
switch (PREFIX_FAMILY (&rn->p)) |
switch (PREFIX_FAMILY (&rn->p)) |
{ |
{ |
case AF_INET: |
case AF_INET: |
Line 966 rib_uninstall (struct route_node *rn, struct rib *rib)
|
Line 1030 rib_uninstall (struct route_node *rn, struct rib *rib)
|
{ |
{ |
if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) |
if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) |
{ |
{ |
|
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_uninstall_kernel (rn, rib); |
Line 975 rib_uninstall (struct route_node *rn, struct rib *rib)
|
Line 1041 rib_uninstall (struct route_node *rn, struct rib *rib)
|
|
|
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; |
|
char buf[INET6_ADDRSTRLEN]; |
|
|
|
dest = rib_dest_from_rnode (rn); |
|
if (!dest) |
|
return 0; |
|
|
|
if (!rib_can_delete_dest (dest)) |
|
return 0; |
|
|
|
if (IS_ZEBRA_DEBUG_RIB) |
|
{ |
|
inet_ntop (rn->p.family, &rn->p.u.prefix, buf, sizeof (buf)); |
|
zlog_debug ("%s: %s/%d: removing dest from table", __func__, |
|
buf, rn->p.prefixlen); |
|
} |
|
|
|
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; |
|
} |
|
|
/* 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) |
Line 993 rib_process (struct route_node *rn)
|
Line 1122 rib_process (struct route_node *rn)
|
if (IS_ZEBRA_DEBUG_RIB || IS_ZEBRA_DEBUG_RIB_Q) |
if (IS_ZEBRA_DEBUG_RIB || IS_ZEBRA_DEBUG_RIB_Q) |
inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); |
inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); |
|
|
for (rib = rn->info; rib; rib = next) | RNODE_FOREACH_RIB_SAFE (rn, rib, next) |
{ |
{ |
/* 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)) |
{ |
{ |
Line 1017 rib_process (struct route_node *rn)
|
Line 1141 rib_process (struct route_node *rn)
|
if (IS_ZEBRA_DEBUG_RIB) |
if (IS_ZEBRA_DEBUG_RIB) |
zlog_debug ("%s: %s/%d: rn %p, removing rib %p", __func__, |
zlog_debug ("%s: %s/%d: rn %p, removing rib %p", __func__, |
buf, rn->p.prefixlen, rn, rib); |
buf, rn->p.prefixlen, rn, rib); |
rib_unlink (rn, rib); | rib_unlink (rn, rib); |
} |
} |
else |
else |
del = rib; |
del = rib; |
Line 1074 rib_process (struct route_node *rn)
|
Line 1198 rib_process (struct route_node *rn)
|
/* metric tie-breaks equal distance */ |
/* metric tie-breaks equal distance */ |
if (rib->metric <= select->metric) |
if (rib->metric <= select->metric) |
select = rib; |
select = rib; |
} /* for (rib = rn->info; rib; rib = next) */ | } /* RNODE_FOREACH_RIB_SAFE */ |
|
|
/* 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 |
* select --- the winner RIB entry, if any was found, otherwise NULL |
Line 1091 rib_process (struct route_node *rn)
|
Line 1215 rib_process (struct route_node *rn)
|
__func__, buf, rn->p.prefixlen, select, fib); |
__func__, buf, rn->p.prefixlen, select, fib); |
if (CHECK_FLAG (select->flags, ZEBRA_FLAG_CHANGED)) |
if (CHECK_FLAG (select->flags, ZEBRA_FLAG_CHANGED)) |
{ |
{ |
|
zfpm_trigger_update (rn, "updating existing route"); |
|
|
redistribute_delete (&rn->p, select); |
redistribute_delete (&rn->p, select); |
if (! RIB_SYSTEM_ROUTE (select)) |
if (! RIB_SYSTEM_ROUTE (select)) |
rib_uninstall_kernel (rn, select); |
rib_uninstall_kernel (rn, select); |
Line 1132 rib_process (struct route_node *rn)
|
Line 1258 rib_process (struct route_node *rn)
|
if (IS_ZEBRA_DEBUG_RIB) |
if (IS_ZEBRA_DEBUG_RIB) |
zlog_debug ("%s: %s/%d: Removing existing route, fib %p", __func__, |
zlog_debug ("%s: %s/%d: Removing existing route, fib %p", __func__, |
buf, rn->p.prefixlen, fib); |
buf, rn->p.prefixlen, fib); |
|
|
|
zfpm_trigger_update (rn, "removing existing route"); |
|
|
redistribute_delete (&rn->p, fib); |
redistribute_delete (&rn->p, fib); |
if (! RIB_SYSTEM_ROUTE (fib)) |
if (! RIB_SYSTEM_ROUTE (fib)) |
rib_uninstall_kernel (rn, fib); |
rib_uninstall_kernel (rn, fib); |
Line 1150 rib_process (struct route_node *rn)
|
Line 1279 rib_process (struct route_node *rn)
|
if (IS_ZEBRA_DEBUG_RIB) |
if (IS_ZEBRA_DEBUG_RIB) |
zlog_debug ("%s: %s/%d: Adding route, select %p", __func__, buf, |
zlog_debug ("%s: %s/%d: Adding route, select %p", __func__, buf, |
rn->p.prefixlen, select); |
rn->p.prefixlen, select); |
|
|
|
zfpm_trigger_update (rn, "new route selected"); |
|
|
/* Set real nexthop. */ |
/* Set real nexthop. */ |
nexthop_active_update (rn, select, 1); |
nexthop_active_update (rn, select, 1); |
|
|
Line 1171 rib_process (struct route_node *rn)
|
Line 1303 rib_process (struct route_node *rn)
|
end: |
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); |
zlog_debug ("%s: %s/%d: rn %p dequeued", __func__, buf, rn->p.prefixlen, rn); |
|
|
|
/* |
|
* Check if the dest can be deleted now. |
|
*/ |
|
rib_gc_dest (rn); |
} |
} |
|
|
/* Take a list of route_node structs and return 1, if there was a record |
/* Take a list of route_node structs and return 1, if there was a record |
Line 1189 process_subq (struct list * subq, u_char qindex)
|
Line 1326 process_subq (struct list * subq, u_char qindex)
|
rnode = listgetdata (lnode); |
rnode = listgetdata (lnode); |
rib_process (rnode); |
rib_process (rnode); |
|
|
if (rnode->info) /* The first RIB record is holding the flags bitmask. */ | if (rnode->info) |
UNSET_FLAG (((struct rib *)rnode->info)->rn_status, RIB_ROUTE_QUEUED(qindex)); | UNSET_FLAG (rib_dest_from_rnode (rnode)->flags, RIB_ROUTE_QUEUED (qindex)); |
| |
#if 0 |
#if 0 |
else |
else |
{ |
{ |
Line 1223 meta_queue_process (struct work_queue *dummy, void *da
|
Line 1361 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 1251 rib_meta_queue_add (struct meta_queue *mq, struct rout
|
Line 1391 rib_meta_queue_add (struct meta_queue *mq, struct rout
|
if (IS_ZEBRA_DEBUG_RIB_Q) |
if (IS_ZEBRA_DEBUG_RIB_Q) |
inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); |
inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); |
|
|
for (rib = rn->info; rib; rib = rib->next) | RNODE_FOREACH_RIB (rn, rib) |
{ |
{ |
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", |
zlog_debug ("%s: %s/%d: rn %p is already queued in sub-queue %u", |
Line 1264 rib_meta_queue_add (struct meta_queue *mq, struct rout
|
Line 1405 rib_meta_queue_add (struct meta_queue *mq, struct rout
|
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++; |
Line 1286 rib_queue_add (struct zebra_t *zebra, struct route_nod
|
Line 1427 rib_queue_add (struct zebra_t *zebra, struct route_nod
|
inet_ntop (AF_INET, &rn->p.u.prefix, buf, INET_ADDRSTRLEN); |
inet_ntop (AF_INET, &rn->p.u.prefix, buf, INET_ADDRSTRLEN); |
|
|
/* Pointless to queue a route_node with no RIB entries to add or remove */ |
/* Pointless to queue a route_node with no RIB entries to add or remove */ |
if (!rn->info) | if (!rnode_to_ribs (rn)) |
{ |
{ |
zlog_debug ("%s: called for route_node (%p, %d) with no ribs", |
zlog_debug ("%s: called for route_node (%p, %d) with no ribs", |
__func__, rn, rn->lock); |
__func__, rn, rn->lock); |
Line 1395 rib_queue_init (struct zebra_t *zebra)
|
Line 1536 rib_queue_init (struct zebra_t *zebra)
|
* |-> set RIB_ENTRY_REMOVE | |
* |-> set RIB_ENTRY_REMOVE | |
* rib_delnode (RIB freed) |
* rib_delnode (RIB freed) |
* |
* |
* | * The 'info' pointer of a route_node points to a rib_dest_t |
* Queueing state for a route_node is kept in the head RIB entry, this | * ('dest'). Queueing state for a route_node is kept on the dest. The |
* state must be preserved as and when the head RIB entry of a | * dest is created on-demand by rib_link() and is kept around at least |
* route_node is changed by rib_unlink / rib_link. A small complication, | * as long as there are ribs hanging off it (@see rib_gc_dest()). |
* but saves having to allocate a dedicated object for this. | |
* |
* |
* Refcounting (aka "locking" throughout the GNU Zebra and Quagga code): |
* Refcounting (aka "locking" throughout the GNU Zebra and Quagga code): |
* |
* |
* - route_nodes: refcounted by: |
* - route_nodes: refcounted by: |
* - RIBs attached to route_node: | * - dest attached to route_node: |
* - managed by: rib_link/unlink | * - managed by: rib_link/rib_gc_dest |
* - route_node processing queue |
* - route_node processing queue |
* - managed by: rib_addqueue, rib_process. |
* - managed by: rib_addqueue, rib_process. |
* |
* |
Line 1416 static void
|
Line 1556 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; |
|
rib_dest_t *dest; |
char buf[INET6_ADDRSTRLEN]; |
char buf[INET6_ADDRSTRLEN]; |
| |
assert (rib && rn); |
assert (rib && rn); |
|
|
route_lock_node (rn); /* rn route table reference */ |
|
|
|
if (IS_ZEBRA_DEBUG_RIB) |
if (IS_ZEBRA_DEBUG_RIB) |
{ |
{ |
inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); |
inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); |
Line 1429 rib_link (struct route_node *rn, struct rib *rib)
|
Line 1568 rib_link (struct route_node *rn, struct rib *rib)
|
buf, rn->p.prefixlen, rn, rib); |
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__, | { |
buf, rn->p.prefixlen); | zlog_debug ("%s: %s/%d: adding dest to table", __func__, |
| 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 1465 rib_addnode (struct route_node *rn, struct rib *rib)
|
Line 1614 rib_addnode (struct route_node *rn, struct rib *rib)
|
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; |
struct nexthop *nexthop, *next; |
char buf[INET6_ADDRSTRLEN]; |
char buf[INET6_ADDRSTRLEN]; |
|
rib_dest_t *dest; |
|
|
assert (rn && rib); |
assert (rn && rib); |
|
|
Line 1480 rib_unlink (struct route_node *rn, struct rib *rib)
|
Line 1639 rib_unlink (struct route_node *rn, struct rib *rib)
|
__func__, buf, rn->p.prefixlen, rn, rib); |
__func__, buf, rn->p.prefixlen, rn, rib); |
} |
} |
|
|
|
dest = rib_dest_from_rnode (rn); |
|
|
if (rib->next) |
if (rib->next) |
rib->next->prev = rib->prev; |
rib->next->prev = rib->prev; |
|
|
Line 1487 rib_unlink (struct route_node *rn, struct rib *rib)
|
Line 1648 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 */ |
Line 1506 rib_unlink (struct route_node *rn, struct rib *rib)
|
Line 1659 rib_unlink (struct route_node *rn, struct rib *rib)
|
} |
} |
XFREE (MTYPE_RIB, rib); |
XFREE (MTYPE_RIB, rib); |
|
|
route_unlock_node (rn); /* rn route table reference */ |
|
} |
} |
|
|
static void |
static void |
Line 1546 rib_add_ipv4 (int type, int flags, struct prefix_ipv4
|
Line 1698 rib_add_ipv4 (int type, int flags, struct prefix_ipv4
|
/* Set default distance by route type. */ |
/* Set default distance by route type. */ |
if (distance == 0) |
if (distance == 0) |
{ |
{ |
if ((unsigned)type >= sizeof(route_info) / sizeof(route_info[0])) | if ((unsigned)type >= array_size(route_info)) |
distance = 150; |
distance = 150; |
else |
else |
distance = route_info[type].distance; |
distance = route_info[type].distance; |
Line 1561 rib_add_ipv4 (int type, int flags, struct prefix_ipv4
|
Line 1713 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 1717 void rib_lookup_and_dump (struct prefix_ipv4 * p)
|
Line 1869 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 |
( |
( |
Line 1764 void rib_lookup_and_pushup (struct prefix_ipv4 * p)
|
Line 1916 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->flags, ZEBRA_FLAG_SELECTED) && |
! RIB_SYSTEM_ROUTE (rib)) |
! RIB_SYSTEM_ROUTE (rib)) |
Line 1816 rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct
|
Line 1968 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 1907 rib_delete_ipv4 (int type, int flags, struct prefix_ip
|
Line 2059 rib_delete_ipv4 (int type, int flags, struct prefix_ip
|
} |
} |
|
|
/* 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; |
Line 2000 static_install_ipv4 (struct prefix *p, struct static_i
|
Line 2152 static_install_ipv4 (struct prefix *p, struct static_i
|
|
|
/* 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 2036 static_install_ipv4 (struct prefix *p, struct static_i
|
Line 2188 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->table = zebrad.rtm_table_default; |
rib->nexthop_num = 0; |
rib->nexthop_num = 0; |
|
|
switch (si->type) |
switch (si->type) |
Line 2095 static_uninstall_ipv4 (struct prefix *p, struct static
|
Line 2248 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 2354 rib_add_ipv6 (int type, int flags, struct prefix_ipv6
|
Line 2507 rib_add_ipv6 (int type, int flags, struct prefix_ipv6
|
|
|
/* 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 2457 rib_delete_ipv6 (int type, int flags, struct prefix_ip
|
Line 2610 rib_delete_ipv6 (int type, int flags, struct prefix_ip
|
} |
} |
|
|
/* 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; |
Line 2550 static_install_ipv6 (struct prefix *p, struct static_i
|
Line 2703 static_install_ipv6 (struct prefix *p, struct static_i
|
|
|
/* 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 2647 static_uninstall_ipv6 (struct prefix *p, struct static
|
Line 2800 static_uninstall_ipv6 (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 2843 rib_update (void)
|
Line 2996 rib_update (void)
|
table = vrf_table (AFI_IP, SAFI_UNICAST, 0); |
table = vrf_table (AFI_IP, SAFI_UNICAST, 0); |
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 = vrf_table (AFI_IP6, SAFI_UNICAST, 0); |
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); |
} |
} |
|
|
Line 2864 rib_weed_table (struct route_table *table)
|
Line 3017 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 2896 rib_sweep_table (struct route_table *table)
|
Line 3047 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; |
|
|
Line 2932 rib_score_proto_table (u_char proto, struct route_tabl
|
Line 3081 rib_score_proto_table (u_char proto, struct route_tabl
|
|
|
if (table) |
if (table) |
for (rn = route_top (table); rn; rn = route_next (rn)) |
for (rn = route_top (table); rn; rn = route_next (rn)) |
for (rib = rn->info; rib; rib = next) | RNODE_FOREACH_RIB_SAFE (rn, rib, next) |
{ |
{ |
next = rib->next; |
|
if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) |
if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) |
continue; |
continue; |
if (rib->type == proto) |
if (rib->type == proto) |
Line 2964 rib_close_table (struct route_table *table)
|
Line 3112 rib_close_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 = rib->next) | RNODE_FOREACH_RIB (rn, rib) |
{ |
{ |
if (! RIB_SYSTEM_ROUTE (rib) | if (!CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) |
&& CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) | continue; |
rib_uninstall_kernel (rn, rib); | |
| zfpm_trigger_update (rn, NULL); |
| |
| if (! RIB_SYSTEM_ROUTE (rib)) |
| rib_uninstall_kernel (rn, rib); |
} |
} |
} |
} |
|
|
Line 2987 rib_init (void)
|
Line 3139 rib_init (void)
|
rib_queue_init (&zebrad); |
rib_queue_init (&zebrad); |
/* VRF initialization. */ |
/* VRF initialization. */ |
vrf_init (); |
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 (uint32_t id, uint32_t *next_id_p) |
|
{ |
|
while (++id < vector_active (vrf_vector)) |
|
{ |
|
if (vrf_lookup (id)) |
|
{ |
|
*next_id_p = 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 = 0; |
|
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 = 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; |
} |
} |