summaryrefslogtreecommitdiff
path: root/bgpd/bgp_table.c
diff options
context:
space:
mode:
Diffstat (limited to 'bgpd/bgp_table.c')
-rw-r--r--bgpd/bgp_table.c44
1 files changed, 39 insertions, 5 deletions
diff --git a/bgpd/bgp_table.c b/bgpd/bgp_table.c
index 66332567..5b8c6a49 100644
--- a/bgpd/bgp_table.c
+++ b/bgpd/bgp_table.c
@@ -38,6 +38,7 @@ bgp_table_init (afi_t afi, safi_t safi)
rt = XCALLOC (MTYPE_BGP_TABLE, sizeof (struct bgp_table));
+ bgp_table_lock(rt);
rt->type = BGP_TABLE_MAIN;
rt->afi = afi;
rt->safi = safi;
@@ -46,10 +47,29 @@ bgp_table_init (afi_t afi, safi_t safi)
}
void
+bgp_table_lock (struct bgp_table *rt)
+{
+ rt->lock++;
+}
+
+void
+bgp_table_unlock (struct bgp_table *rt)
+{
+ assert (rt->lock > 0);
+ rt->lock--;
+
+ if (rt->lock == 0)
+ bgp_table_free (rt);
+}
+
+void
bgp_table_finish (struct bgp_table **rt)
{
- bgp_table_free (*rt);
- *rt = NULL;
+ if (*rt != NULL)
+ {
+ bgp_table_unlock(*rt);
+ *rt = NULL;
+ }
}
static struct bgp_node *
@@ -91,6 +111,9 @@ bgp_table_free (struct bgp_table *rt)
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)
@@ -108,22 +131,31 @@ bgp_table_free (struct bgp_table *rt)
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;
-
- bgp_node_free (tmp_node);
}
else
{
- bgp_node_free (tmp_node);
break;
}
}
+ assert (rt->count == 0);
+
+ if (rt->owner)
+ {
+ peer_unlock (rt->owner);
+ rt->owner = NULL;
+ }
+
XFREE (MTYPE_BGP_TABLE, rt);
return;
}
@@ -217,6 +249,7 @@ bgp_lock_node (struct bgp_node *node)
void
bgp_unlock_node (struct bgp_node *node)
{
+ assert (node->lock > 0);
node->lock--;
if (node->lock == 0)
@@ -344,6 +377,7 @@ bgp_node_get (struct bgp_table *const table, struct prefix *p)
if (new->p.prefixlen != p->prefixlen)
{
match = new;
+ bgp_lock_node (match);
new = bgp_node_set (table, p);
set_link (match, new);
table->count++;