mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2025-01-03 07:31:54 +00:00
Kernel: feed only once during startup
There was an inefficiency in the initial scan state machine, causing routes to be fed several times instead of just once. Now the export startup is postponed until first krt_scan() finishes and we actually can do the pruning with full information.
This commit is contained in:
parent
5fd0fd77e2
commit
0fa80d7c79
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user