mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-11-09 12:48:43 +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:
parent
c262c728eb
commit
32bb548c11
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user