0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-09-18 19:35:20 +00:00

Table: Fixed feed race condition

The problem happened like this:

1. Single route for the given net in table
2. A feed is started
3. The route is deleted (from another thread)
4. The feed finds an empty net, exports nothing, ignores journal (here is bug)
5. The route is added
6. The export transitions from FEEDING to READY
7. While processing the journal, the route deletion and addition combines into noop.

This way routes mysteriously disappeared in specific cases of link instability.

Problem fixed by explicitly marking the empty-net journal entries as processed in step 4.
This commit is contained in:
Maria Matejka 2023-09-24 11:47:24 +02:00
parent c262c728eb
commit 32bb548c11
3 changed files with 15 additions and 4 deletions

View File

@ -505,6 +505,7 @@ channel_start_export(struct channel *c)
.trace_routes = c->debug | c->proto->debug,
.dump_req = channel_dump_export_req,
.log_state_change = channel_export_log_state_change,
.mark_seen = channel_rpe_mark_seen,
};
bmap_init(&c->export_map, c->proto->pool, 16);

View File

@ -911,7 +911,7 @@ rt_notify_basic(struct channel *c, const net_addr *net, rte *new, const rte *old
do_rt_notify(c, net, new, old);
}
static void
void
channel_rpe_mark_seen(struct rt_export_request *req, struct rt_pending_export *rpe)
{
struct channel *c = SKIP_BACK(struct channel, out_req, req);
@ -4266,11 +4266,12 @@ typedef struct {
static int
rt_prepare_feed(struct rt_table_export_hook *c, net *n, rt_feed_block *b)
{
uint bs = c->h.req->feed_block_size ?: 16384;
struct rt_export_request *req = c->h.req;
uint bs = req->feed_block_size ?: 16384;
if (n->routes)
{
if (c->h.req->export_bulk)
if (req->export_bulk)
{
uint cnt = rte_feed_count(n);
if (b->cnt && (b->cnt + cnt > bs))
@ -4304,6 +4305,13 @@ rt_prepare_feed(struct rt_table_export_hook *c, net *n, rt_feed_block *b)
b->rpe[b->pos++] = (struct rt_pending_export) { .new = n->routes, .new_best = n->routes };
}
}
else
if (req->mark_seen)
RPE_WALK(n->first, rpe, NULL)
req->mark_seen(req, rpe);
else
RPE_WALK(n->first, rpe, NULL)
rpe_mark_seen(&c->h, rpe);
return 1;
}

View File

@ -321,6 +321,8 @@ struct rt_export_request {
struct rt_pending_export *rpe, struct rt_pending_export *last,
const rte **feed, uint count);
void (*mark_seen)(struct rt_export_request *req, struct rt_pending_export *rpe);
void (*dump_req)(struct rt_export_request *req);
void (*log_state_change)(struct rt_export_request *req, u8);
};
@ -471,7 +473,7 @@ void rt_feed_any(struct rt_export_request *req, const net_addr *net, struct rt_p
void rt_notify_accepted(struct rt_export_request *req, const net_addr *net, struct rt_pending_export *first, struct rt_pending_export *last, const rte **feed, uint count);
void rt_notify_merged(struct rt_export_request *req, const net_addr *net, struct rt_pending_export *first, struct rt_pending_export *last, const rte **feed, uint count);
void channel_rpe_mark_seen(struct rt_export_request *req, struct rt_pending_export *rpe);
/* Types of route announcement, also used as flags */
#define RA_UNDEF 0 /* Undefined RA type */