rt_exporter_init(struct rt_exporter *e, struct settle_config *scf)
{
rtex_trace(e, D_STATES, "Exporter init");
+ ASSERT_DIE(e->journal.domain);
e->journal.cleanup_done = rt_exporter_cleanup_done;
lfjour_init(&e->journal, scf);
ASSERT_DIE(e->feed_net);
rtex_trace(e, D_STATES, "Exporter shutdown");
/* Last lock check before dropping the domain reference */
- if (e->journal.domain)
- ASSERT_DIE(DG_IS_LOCKED(e->journal.domain));
-
- e->journal.domain = NULL;
+ ASSERT_DIE(DG_IS_LOCKED(e->journal.domain));
/* We have to tell every receiver to stop */
bool done = 1;
/* Wait for feeders to finish */
synchronize_rcu();
- /* The rest is done via the cleanup routine */
- lfjour_do_cleanup_now(&e->journal);
-
if (done)
{
+ /* Inhibit locking in cleanup */
+ e->journal.domain = NULL;
+
+ /* The rest is done via the cleanup routine */
+ lfjour_do_cleanup_now(&e->journal);
+
+ /* Invalidate the cleanup event */
+ e->journal.cleanup_event.hook = NULL;
ev_postpone(&e->journal.cleanup_event);
+
+ /* No announcement timer either */
settle_cancel(&e->journal.announce_timer);
+
+ /* Done! */
CALL(stopped, e);
}
else
void
rt_schedule_prune(struct rtable_private *tab)
{
+ /* The table is empty if there are no imports */
+ if (EMPTY_LIST(tab->imports))
+ return;
+
/* state change 0->1, 2->3 */
tab->prune_state |= 1;
if (!tab->reconf_end)
{
rtable *t = tab_;
RT_LOCK(t, tab);
+ ASSERT_DIE(birdloop_inside(tab->loop));
+
+ /* Check that the table is indeed pruned */
+ tab->prune_state = 0;
+ ASSERT_DIE(EMPTY_LIST(tab->imports));
+ u32 bs = atomic_load_explicit(&tab->routes_block_size, memory_order_relaxed);
+ net *routes = atomic_load_explicit(&tab->routes, memory_order_relaxed);
+ for (u32 i = 0; i < bs; i++)
+ ASSERT_DIE(atomic_load_explicit(&routes[i].routes, memory_order_relaxed) == NULL);
if (tab->export_digest)
{
bpp->exporter = (struct rt_exporter) {
.journal = {
.loop = c->c.proto->loop,
+ .domain = dom.rtable,
.item_size = sizeof(struct rt_export_item),
.item_done = bgp_out_item_done,
},