version 1.1.1.1, 2012/02/21 17:26:11
|
version 1.1.1.3, 2016/11/02 10:09:10
|
Line 24 Software Foundation, Inc., 59 Temple Place - Suite 330
|
Line 24 Software Foundation, Inc., 59 Temple Place - Suite 330
|
#include "memory.h" |
#include "memory.h" |
#include "sockunion.h" |
#include "sockunion.h" |
#include "vty.h" |
#include "vty.h" |
|
#include "filter.h" |
|
|
#include "bgpd/bgpd.h" |
#include "bgpd/bgpd.h" |
#include "bgpd/bgp_table.h" |
#include "bgpd/bgp_table.h" |
|
|
static void bgp_node_delete (struct bgp_node *); |
|
static void bgp_table_free (struct bgp_table *); |
|
|
|
struct bgp_table * |
|
bgp_table_init (afi_t afi, safi_t safi) |
|
{ |
|
struct bgp_table *rt; |
|
|
|
rt = XCALLOC (MTYPE_BGP_TABLE, sizeof (struct bgp_table)); |
|
|
|
bgp_table_lock(rt); |
|
rt->type = BGP_TABLE_MAIN; |
|
rt->afi = afi; |
|
rt->safi = safi; |
|
|
|
return rt; |
|
} |
|
|
|
void |
void |
bgp_table_lock (struct bgp_table *rt) |
bgp_table_lock (struct bgp_table *rt) |
{ |
{ |
Line 58 bgp_table_unlock (struct bgp_table *rt)
|
Line 41 bgp_table_unlock (struct bgp_table *rt)
|
assert (rt->lock > 0); |
assert (rt->lock > 0); |
rt->lock--; |
rt->lock--; |
|
|
if (rt->lock == 0) | if (rt->lock != 0) |
bgp_table_free (rt); | |
} | |
| |
void | |
bgp_table_finish (struct bgp_table **rt) | |
{ | |
if (*rt != NULL) | |
{ |
{ |
bgp_table_unlock(*rt); | return; |
*rt = NULL; | |
} |
} |
} |
|
|
|
static struct bgp_node * | route_table_finish (rt->route_table); |
bgp_node_create (void) | rt->route_table = NULL; |
{ | |
return XCALLOC (MTYPE_BGP_NODE, sizeof (struct bgp_node)); | |
} | |
|
|
/* Allocate new route node with prefix set. */ |
|
static struct bgp_node * |
|
bgp_node_set (struct bgp_table *table, struct prefix *prefix) |
|
{ |
|
struct bgp_node *node; |
|
|
|
node = bgp_node_create (); |
|
|
|
prefix_copy (&node->p, prefix); |
|
node->table = table; |
|
|
|
return node; |
|
} |
|
|
|
/* Free route node. */ |
|
static void |
|
bgp_node_free (struct bgp_node *node) |
|
{ |
|
XFREE (MTYPE_BGP_NODE, node); |
|
} |
|
|
|
/* Free route table. */ |
|
static void |
|
bgp_table_free (struct bgp_table *rt) |
|
{ |
|
struct bgp_node *tmp_node; |
|
struct bgp_node *node; |
|
|
|
if (rt == NULL) |
|
return; |
|
|
|
node = rt->top; |
|
|
|
/* Bulk deletion of nodes remaining in this table. This function is not |
|
called until workers have completed their dependency on this table. |
|
A final bgp_unlock_node() will not be called for these nodes. */ |
|
while (node) |
|
{ |
|
if (node->l_left) |
|
{ |
|
node = node->l_left; |
|
continue; |
|
} |
|
|
|
if (node->l_right) |
|
{ |
|
node = node->l_right; |
|
continue; |
|
} |
|
|
|
tmp_node = node; |
|
node = node->parent; |
|
|
|
tmp_node->table->count--; |
|
tmp_node->lock = 0; /* to cause assert if unlocked after this */ |
|
bgp_node_free (tmp_node); |
|
|
|
if (node != NULL) |
|
{ |
|
if (node->l_left == tmp_node) |
|
node->l_left = NULL; |
|
else |
|
node->l_right = NULL; |
|
} |
|
else |
|
{ |
|
break; |
|
} |
|
} |
|
|
|
assert (rt->count == 0); |
|
|
|
if (rt->owner) |
if (rt->owner) |
{ |
{ |
peer_unlock (rt->owner); |
peer_unlock (rt->owner); |
Line 157 bgp_table_free (struct bgp_table *rt)
|
Line 56 bgp_table_free (struct bgp_table *rt)
|
} |
} |
|
|
XFREE (MTYPE_BGP_TABLE, rt); |
XFREE (MTYPE_BGP_TABLE, rt); |
return; |
|
} |
} |
|
|
/* Utility mask array. */ |
|
static u_char maskbit[] = |
|
{ |
|
0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff |
|
}; |
|
|
|
/* Common prefix route genaration. */ |
|
static void |
|
route_common (struct prefix *n, struct prefix *p, struct prefix *new) |
|
{ |
|
int i; |
|
u_char diff; |
|
u_char mask; |
|
|
|
u_char *np = (u_char *)&n->u.prefix; |
|
u_char *pp = (u_char *)&p->u.prefix; |
|
u_char *newp = (u_char *)&new->u.prefix; |
|
|
|
for (i = 0; i < p->prefixlen / 8; i++) |
|
{ |
|
if (np[i] == pp[i]) |
|
newp[i] = np[i]; |
|
else |
|
break; |
|
} |
|
|
|
new->prefixlen = i * 8; |
|
|
|
if (new->prefixlen != p->prefixlen) |
|
{ |
|
diff = np[i] ^ pp[i]; |
|
mask = 0x80; |
|
while (new->prefixlen < p->prefixlen && !(mask & diff)) |
|
{ |
|
mask >>= 1; |
|
new->prefixlen++; |
|
} |
|
newp[i] = np[i] & maskbit[new->prefixlen % 8]; |
|
} |
|
} |
|
|
|
static void |
|
set_link (struct bgp_node *node, struct bgp_node *new) |
|
{ |
|
unsigned int bit = prefix_bit (&new->p.u.prefix, node->p.prefixlen); |
|
|
|
node->link[bit] = new; |
|
new->parent = node; |
|
} |
|
|
|
/* Lock node. */ |
|
struct bgp_node * |
|
bgp_lock_node (struct bgp_node *node) |
|
{ |
|
node->lock++; |
|
return node; |
|
} |
|
|
|
/* Unlock node. */ |
|
void |
void |
bgp_unlock_node (struct bgp_node *node) | bgp_table_finish (struct bgp_table **rt) |
{ |
{ |
assert (node->lock > 0); | if (*rt != NULL) |
node->lock--; | |
| |
if (node->lock == 0) | |
bgp_node_delete (node); | |
} | |
| |
/* Find matched prefix. */ | |
struct bgp_node * | |
bgp_node_match (const struct bgp_table *table, struct prefix *p) | |
{ | |
struct bgp_node *node; | |
struct bgp_node *matched; | |
| |
matched = NULL; | |
node = table->top; | |
| |
/* Walk down tree. If there is matched route then store it to | |
matched. */ | |
while (node && node->p.prefixlen <= p->prefixlen && | |
prefix_match (&node->p, p)) | |
{ |
{ |
if (node->info) | bgp_table_unlock(*rt); |
matched = node; | *rt = NULL; |
node = node->link[prefix_bit(&p->u.prefix, node->p.prefixlen)]; | |
} |
} |
|
|
/* If matched route found, return it. */ |
|
if (matched) |
|
return bgp_lock_node (matched); |
|
|
|
return NULL; |
|
} |
} |
|
|
struct bgp_node * | /* |
bgp_node_match_ipv4 (const struct bgp_table *table, struct in_addr *addr) | * bgp_node_create |
| */ |
| static struct route_node * |
| bgp_node_create (route_table_delegate_t *delegate, struct route_table *table) |
{ |
{ |
struct prefix_ipv4 p; |
|
|
|
memset (&p, 0, sizeof (struct prefix_ipv4)); |
|
p.family = AF_INET; |
|
p.prefixlen = IPV4_MAX_PREFIXLEN; |
|
p.prefix = *addr; |
|
|
|
return bgp_node_match (table, (struct prefix *) &p); |
|
} |
|
|
|
#ifdef HAVE_IPV6 |
|
struct bgp_node * |
|
bgp_node_match_ipv6 (const struct bgp_table *table, struct in6_addr *addr) |
|
{ |
|
struct prefix_ipv6 p; |
|
|
|
memset (&p, 0, sizeof (struct prefix_ipv6)); |
|
p.family = AF_INET6; |
|
p.prefixlen = IPV6_MAX_PREFIXLEN; |
|
p.prefix = *addr; |
|
|
|
return bgp_node_match (table, (struct prefix *) &p); |
|
} |
|
#endif /* HAVE_IPV6 */ |
|
|
|
/* Lookup same prefix node. Return NULL when we can't find route. */ |
|
struct bgp_node * |
|
bgp_node_lookup (const struct bgp_table *table, struct prefix *p) |
|
{ |
|
struct bgp_node *node; |
struct bgp_node *node; |
| node = XCALLOC (MTYPE_BGP_NODE, sizeof (struct bgp_node)); |
node = table->top; | return bgp_node_to_rnode (node); |
| |
while (node && node->p.prefixlen <= p->prefixlen && | |
prefix_match (&node->p, p)) | |
{ | |
if (node->p.prefixlen == p->prefixlen && node->info) | |
return bgp_lock_node (node); | |
| |
node = node->link[prefix_bit(&p->u.prefix, node->p.prefixlen)]; | |
} | |
| |
return NULL; | |
} |
} |
|
|
/* Add node to routing table. */ | /* |
struct bgp_node * | * bgp_node_destroy |
bgp_node_get (struct bgp_table *const table, struct prefix *p) | */ |
{ | |
struct bgp_node *new; | |
struct bgp_node *node; | |
struct bgp_node *match; | |
| |
match = NULL; | |
node = table->top; | |
while (node && node->p.prefixlen <= p->prefixlen && | |
prefix_match (&node->p, p)) | |
{ | |
if (node->p.prefixlen == p->prefixlen) | |
{ | |
bgp_lock_node (node); | |
return node; | |
} | |
match = node; | |
node = node->link[prefix_bit(&p->u.prefix, node->p.prefixlen)]; | |
} | |
| |
if (node == NULL) | |
{ | |
new = bgp_node_set (table, p); | |
if (match) | |
set_link (match, new); | |
else | |
table->top = new; | |
} | |
else | |
{ | |
new = bgp_node_create (); | |
route_common (&node->p, p, &new->p); | |
new->p.family = p->family; | |
new->table = table; | |
set_link (new, node); | |
| |
if (match) | |
set_link (match, new); | |
else | |
table->top = new; | |
| |
if (new->p.prefixlen != p->prefixlen) | |
{ | |
match = new; | |
new = bgp_node_set (table, p); | |
set_link (match, new); | |
table->count++; | |
} | |
} | |
table->count++; | |
bgp_lock_node (new); | |
| |
return new; | |
} | |
| |
/* Delete node from the routing table. */ | |
static void |
static void |
bgp_node_delete (struct bgp_node *node) | bgp_node_destroy (route_table_delegate_t *delegate, |
| struct route_table *table, struct route_node *node) |
{ |
{ |
struct bgp_node *child; | struct bgp_node *bgp_node; |
struct bgp_node *parent; | bgp_node = bgp_node_from_rnode (node); |
| XFREE (MTYPE_BGP_NODE, bgp_node); |
assert (node->lock == 0); | |
assert (node->info == NULL); | |
| |
if (node->l_left && node->l_right) | |
return; | |
| |
if (node->l_left) | |
child = node->l_left; | |
else | |
child = node->l_right; | |
| |
parent = node->parent; | |
| |
if (child) | |
child->parent = parent; | |
| |
if (parent) | |
{ | |
if (parent->l_left == node) | |
parent->l_left = child; | |
else | |
parent->l_right = child; | |
} | |
else | |
node->table->top = child; | |
| |
node->table->count--; | |
| |
bgp_node_free (node); | |
| |
/* If parent node is stub then delete it also. */ | |
if (parent && parent->lock == 0) | |
bgp_node_delete (parent); | |
} |
} |
|
|
/* Get fist node and lock it. This function is useful when one want | /* |
to lookup all the node exist in the routing table. */ | * Function vector to customize the behavior of the route table |
struct bgp_node * | * library for BGP route tables. |
bgp_table_top (const struct bgp_table *const table) | */ |
{ | route_table_delegate_t bgp_table_delegate = { |
/* If there is no node in the routing table return NULL. */ | .create_node = bgp_node_create, |
if (table->top == NULL) | .destroy_node = bgp_node_destroy |
return NULL; | }; |
|
|
/* Lock the top node and return it. */ | /* |
bgp_lock_node (table->top); | * bgp_table_init |
return table->top; | */ |
} | struct bgp_table * |
| bgp_table_init (afi_t afi, safi_t safi) |
/* Unlock current node and lock next node then return it. */ | |
struct bgp_node * | |
bgp_route_next (struct bgp_node *node) | |
{ |
{ |
struct bgp_node *next; | struct bgp_table *rt; |
struct bgp_node *start; | |
|
|
/* Node may be deleted from bgp_unlock_node so we have to preserve | rt = XCALLOC (MTYPE_BGP_TABLE, sizeof (struct bgp_table)); |
next node's pointer. */ | |
|
|
if (node->l_left) | rt->route_table = route_table_init_with_delegate (&bgp_table_delegate); |
{ | |
next = node->l_left; | |
bgp_lock_node (next); | |
bgp_unlock_node (node); | |
return next; | |
} | |
if (node->l_right) | |
{ | |
next = node->l_right; | |
bgp_lock_node (next); | |
bgp_unlock_node (node); | |
return next; | |
} | |
|
|
start = node; | /* |
while (node->parent) | * Set up back pointer to bgp_table. |
{ | */ |
if (node->parent->l_left == node && node->parent->l_right) | rt->route_table->info = rt; |
{ | |
next = node->parent->l_right; | |
bgp_lock_node (next); | |
bgp_unlock_node (start); | |
return next; | |
} | |
node = node->parent; | |
} | |
bgp_unlock_node (start); | |
return NULL; | |
} | |
|
|
/* Unlock current node and lock next node until limit. */ | bgp_table_lock (rt); |
struct bgp_node * | rt->type = BGP_TABLE_MAIN; |
bgp_route_next_until (struct bgp_node *node, struct bgp_node *limit) | rt->afi = afi; |
{ | rt->safi = safi; |
struct bgp_node *next; | |
struct bgp_node *start; | |
|
|
/* Node may be deleted from bgp_unlock_node so we have to preserve | return rt; |
next node's pointer. */ | |
| |
if (node->l_left) | |
{ | |
next = node->l_left; | |
bgp_lock_node (next); | |
bgp_unlock_node (node); | |
return next; | |
} | |
if (node->l_right) | |
{ | |
next = node->l_right; | |
bgp_lock_node (next); | |
bgp_unlock_node (node); | |
return next; | |
} | |
| |
start = node; | |
while (node->parent && node != limit) | |
{ | |
if (node->parent->l_left == node && node->parent->l_right) | |
{ | |
next = node->parent->l_right; | |
bgp_lock_node (next); | |
bgp_unlock_node (start); | |
return next; | |
} | |
node = node->parent; | |
} | |
bgp_unlock_node (start); | |
return NULL; | |
} | |
| |
unsigned long | |
bgp_table_count (const struct bgp_table *table) | |
{ | |
return table->count; | |
} |
} |