From: Maria Matejka Date: Sun, 24 Sep 2023 09:47:24 +0000 (+0200) Subject: Table: Fixed feed race condition X-Git-Tag: v3.0.0~410 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=32bb548c116b40f79d077c10356c037770ed1005;p=thirdparty%2Fbird.git 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. --- diff --git a/nest/proto.c b/nest/proto.c index 0304ef7f9..476764b8c 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -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); diff --git a/nest/rt-table.c b/nest/rt-table.c index 6cd445646..a367a4b59 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -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; } diff --git a/nest/rt.h b/nest/rt.h index e0a099e1a..796940168 100644 --- a/nest/rt.h +++ b/nest/rt.h @@ -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 */