diff --git a/nest/proto.c b/nest/proto.c index 678697d6..6fa74e9f 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -676,9 +676,11 @@ void channel_notify_basic(void *); void channel_notify_accepted(void *); void channel_notify_merged(void *); -static void +void channel_start_export(struct channel *c) { + ASSERT_DIE(birdloop_inside(c->proto->loop)); + if (rt_export_get_state(&c->out_req) != TES_DOWN) bug("%s.%s: Attempted to start channel's already started export", c->proto->name, c->name); diff --git a/nest/protocol.h b/nest/protocol.h index cf7ecb89..2bfa1628 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -747,6 +747,8 @@ int proto_configure_channel(struct proto *p, struct channel **c, struct channel_ void channel_set_state(struct channel *c, uint state); +void channel_start_export(struct channel *c); + void channel_add_obstacle(struct channel *c); void channel_del_obstacle(struct channel *c); diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index 34882b88..1658dd6f 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -342,6 +342,8 @@ krt_learn_async(struct krt_proto *p, rte *e, int new) /* Hook defined in nest/rt-table.c ... to be refactored away later */ rte *krt_export_net(struct channel *c, const net_addr *a, linpool *lp); +static void krt_rt_notify(struct proto *P, struct channel *ch, const net_addr *net, rte *new, const rte *old); + static int krt_same_dest(rte *k, rte *e) { @@ -361,6 +363,11 @@ krt_same_dest(rte *k, rte *e) void krt_got_route(struct krt_proto *p, rte *e, s8 src) { + /* If we happen to get an asynchronous route notification + * before initialization, we wait for the scan. */ + if (p->sync_state == KPS_INIT) + return; + rte *new = NULL; e->pflags = 0; @@ -391,10 +398,6 @@ krt_got_route(struct krt_proto *p, rte *e, s8 src) /* The rest is for KRT_SRC_BIRD (or KRT_SRC_UNKNOWN) */ - /* We wait for the initial feed to have correct installed state */ - if (!p->ready) - goto ignore; - /* Get the exported version */ new = krt_export_net(p->p.main_channel, e->net, krt_filter_lp); @@ -423,10 +426,6 @@ aseen: krt_trace_in(p, e, "already seen"); goto done; -ignore: - krt_trace_in(p, e, "ignored"); - goto done; - update: krt_trace_in(p, new, "updating"); krt_replace_rte(p, e->net, new, e); @@ -447,12 +446,21 @@ krt_init_scan(struct krt_proto *p) { switch (p->sync_state) { + case KPS_INIT: + /* Allow exports now */ + p->p.rt_notify = krt_rt_notify; + channel_start_export(p->p.main_channel); + rt_refresh_begin(&p->p.main_channel->in_req); + p->sync_state = KPS_FIRST_SCAN; + return 1; + case KPS_IDLE: rt_refresh_begin(&p->p.main_channel->in_req); bmap_reset(&p->seen_map, 1024); p->sync_state = KPS_SCANNING; return 1; + case KPS_FIRST_SCAN: case KPS_SCANNING: bug("Kernel scan double-init"); @@ -470,14 +478,17 @@ krt_prune(struct krt_proto *p) { switch (p->sync_state) { + case KPS_INIT: case KPS_IDLE: bug("Kernel scan prune without scan"); case KPS_SCANNING: + channel_request_full_refeed(p->p.main_channel); + /* fall through */ + case KPS_FIRST_SCAN: p->sync_state = KPS_PRUNING; KRT_TRACE(p, D_EVENTS, "Pruning table %s", p->p.main_channel->table->name); rt_refresh_end(&p->p.main_channel->in_req); - channel_request_full_refeed(p->p.main_channel); break; case KPS_PRUNING: @@ -549,7 +560,7 @@ krt_scan_all(timer *t UNUSED) krt_do_scan(NULL); WALK_LIST2(p, n, krt_proto_list, krt_node) - if (p->sync_state == KPS_SCANNING) + if ((p->sync_state == KPS_SCANNING) || (p->sync_state == KPS_FIRST_SCAN)) krt_prune(p); } @@ -644,6 +655,9 @@ krt_scan_timer_kick(struct krt_proto *p) static int krt_preexport(struct channel *C, rte *e) { + /* The export should not start before proper sync */ + ASSERT_DIE(SKIP_BACK(struct krt_proto, p, C->proto)->sync_state != KPS_INIT); + if (e->src->owner == &C->proto->sources) #ifdef CONFIG_SINGLE_ROUTE return 1; @@ -659,15 +673,6 @@ krt_preexport(struct channel *C, rte *e) return -1; } - /* Before first scan we don't touch the routes */ - if (!SKIP_BACK(struct krt_proto, p, C->proto)->ready) - { - if (C->debug & D_ROUTES) - log(L_TRACE "%s.%s not ready yet to accept route for %N", - C->proto->name, C->name, e->net); - return -1; - } - return 0; } @@ -685,18 +690,24 @@ krt_rt_notify(struct proto *P, struct channel *ch, const net_addr *net, switch (p->sync_state) { + case KPS_INIT: + bug("Routes in init state should have been rejected by preexport."); + case KPS_IDLE: case KPS_PRUNING: if (new && bmap_test(&p->seen_map, new->id)) + { if (ch->debug & D_ROUTES) { /* Already installed and seen in the kernel dump */ log(L_TRACE "%s.%s: %N already in kernel", P->name, ch->name, net); - return; } + return; + } /* fall through */ + case KPS_FIRST_SCAN: case KPS_SCANNING: /* Actually replace the route */ krt_replace_rte(p, net, new, old); @@ -732,7 +743,6 @@ krt_reload_routes(struct channel *C, struct rt_feeding_request *rfr) if (KRT_CF->learn) { - p->reload = 1; krt_scan_timer_kick(p); } @@ -749,15 +759,18 @@ krt_export_fed(struct channel *C) { struct krt_proto *p = (void *) C->proto; - p->ready = 1; - p->initialized = 1; - switch (p->sync_state) { + case KPS_INIT: + bug("KRT export started before scan"); + case KPS_IDLE: krt_scan_timer_kick(p); break; + case KPS_FIRST_SCAN: + bug("KRT export done before first scan"); + case KPS_SCANNING: break; @@ -831,7 +844,8 @@ krt_init(struct proto_config *CF) p->p.main_channel = proto_add_channel(&p->p, proto_cf_main_channel(CF)); p->p.preexport = krt_preexport; - p->p.rt_notify = krt_rt_notify; + /* Not setting rt_notify here to not start exports, must wait for the first scan + * and then we can start exports manually */ p->p.iface_sub.if_notify = krt_if_notify; p->p.reload_routes = krt_reload_routes; p->p.export_fed = krt_export_fed; @@ -887,7 +901,7 @@ krt_shutdown(struct proto *P) return PS_FLUSH; /* FIXME we should flush routes even when persist during reconfiguration */ - if (p->initialized && !KRT_CF->persist && (P->down_code != PDC_CMD_GR_DOWN)) + if ((p->sync_state != KPS_INIT) && !KRT_CF->persist && (P->down_code != PDC_CMD_GR_DOWN)) { struct rt_export_feeder req = (struct rt_export_feeder) { @@ -922,8 +936,7 @@ krt_shutdown(struct proto *P) static void krt_cleanup(struct krt_proto *p) { - p->ready = 0; - p->initialized = 0; + p->sync_state = KPS_INIT; krt_sys_shutdown(p); rem_node(&p->krt_node); diff --git a/sysdep/unix/krt.h b/sysdep/unix/krt.h index 394e7401..14be715f 100644 --- a/sysdep/unix/krt.h +++ b/sysdep/unix/krt.h @@ -59,10 +59,9 @@ struct krt_proto { struct bmap seen_map; /* Routes seen during last periodic scan */ node krt_node; /* Node in krt_proto_list */ byte af; /* Kernel address family (AF_*) */ - byte ready; /* Initial feed has been finished */ - byte initialized; /* First scan has been finished */ - byte reload; /* Next scan is doing reload */ PACKED enum krt_prune_state { + KPS_INIT, + KPS_FIRST_SCAN, KPS_IDLE, KPS_SCANNING, KPS_PRUNING,