bmp_remove_table(struct bmp_proto *p, struct bmp_table *bt)
{
rt_export_unsubscribe(all, &bt->out_req);
+ ev_postpone(&bt->event);
HASH_REMOVE(p->table_map, HASH_TABLE, bt);
*/
static struct bmp_stream *
-bmp_find_stream(struct bmp_proto *p, struct bmp_stream_info *bsi)
+bmp_get_stream(struct bmp_proto *p, struct bmp_stream_info *bsi)
{
while (true)
{
SKIP_BACK_DECLARE(struct bmp_table, bt, streams, bmp_table_stream_enlisted(bs));
bmp_table_stream_rem_node(&bt->streams, bs);
- if (EMPTY_TLIST(bmp_table_stream, &bt->streams))
+ if (EMPTY_TLIST(bmp_table_stream, &bt->streams) && !bt->out_req.cur)
+ /* If out_req.cur, then we are called from bmp_check_routes()
+ * and therefore the table will be removed in the tail position there. */
bmp_remove_table(p, bt);
mb_free(bs);
return HASH_FIND(p->peer_map, HASH_PEER, bpi->proto_id);
}
+static struct bmp_peer *
+bmp_get_peer(struct bmp_proto *p, const struct bmp_peer_info *bpi)
+{
+ while (true)
+ {
+ /* Is there a peer? */
+ struct bmp_peer *bp = bmp_find_peer(p, bpi);
+ if (bp)
+ return bp;
+
+ /* Maybe it emerged recently? */
+ struct lfjour_item *li = lfjour_get(&p->proto_state_reader);
+ if (!li)
+ return NULL;
+
+ bmp_process_proto_state_change(p, li);
+ lfjour_release(&p->proto_state_reader, li);
+
+ /* Try again. */
+ }
+}
+
static struct bmp_peer *
bmp_add_peer(struct bmp_proto *p, struct bmp_peer_info *bpi, ea_list **cached_channels)
{
struct bmp_peer_info bpi = {
.proto_id = c->proto->id,
};
- struct bmp_peer *bp = bmp_find_peer(p, &bpi);
+ struct bmp_peer *bp = bmp_get_peer(p, &bpi);
struct bmp_stream_info bsi = {
.channel_id = c->id,
ea_list *old_attrs = old ? ea_strip_to(old->attrs, BIT32_ALL(EALS_PREIMPORT)) : NULL;
bsi.mode = BMP_STREAM_PRE_POLICY;
- struct bmp_stream *bs = bmp_find_stream(p, &bsi);
+ struct bmp_stream *bs = bmp_get_stream(p, &bsi);
if (!bs)
return;
ea_list *old_attrs = old ? ea_normalize(old->attrs, 0) : NULL;
bsi.mode = BMP_STREAM_POST_POLICY;
- struct bmp_stream *bs = bmp_find_stream(p, &bsi);
+ struct bmp_stream *bs = bmp_get_stream(p, &bsi);
if (!bs)
return;
break;
}
}
+
+ /* Remove if deleted */
+ if (EMPTY_TLIST(bmp_table_stream, &bt->streams))
+ bmp_remove_table(p, bt);
}
static void
static void
bmp_process_proto_state_change(struct bmp_proto *p, struct lfjour_item *last_up)
{
- if (!last_up)
- return;
-
SKIP_BACK_DECLARE(struct proto_pending_update, ppu, li, last_up);
struct bmp_peer_info bpi = {
{
bmp_send_termination_msg(p, BMP_TERM_REASON_ADM);
bmp_down(p);
- bmp_close_socket(p);
}
+ bmp_close_socket(p);
p->sock_err = 0;
return PS_FLUSH;