Fixes bug in protocol flushing and rtable pruning.
When route was propagated to another rtable through a pipe and then the pipe was reconfigured softly in such a way that any subsequent route updates are filtered, then the source protocol shutdown didn't clean up the route in the second rtable which caused stale routes and potential crashes.
This commit is contained in:
parent
48b15ef10f
commit
9135c1f0ca
3 changed files with 36 additions and 21 deletions
|
@ -835,14 +835,18 @@ static void
|
||||||
proto_schedule_flush_loop(void)
|
proto_schedule_flush_loop(void)
|
||||||
{
|
{
|
||||||
struct proto *p;
|
struct proto *p;
|
||||||
|
struct announce_hook *h;
|
||||||
|
|
||||||
if (flush_loop_state)
|
if (flush_loop_state)
|
||||||
return;
|
return;
|
||||||
flush_loop_state = 1;
|
flush_loop_state = 1;
|
||||||
|
|
||||||
rt_schedule_prune_all();
|
|
||||||
WALK_LIST(p, flush_proto_list)
|
WALK_LIST(p, flush_proto_list)
|
||||||
|
{
|
||||||
p->flushing = 1;
|
p->flushing = 1;
|
||||||
|
for (h=p->ahooks; h; h=h->next)
|
||||||
|
h->table->prune_state = 1;
|
||||||
|
}
|
||||||
|
|
||||||
ev_schedule(proto_flush_event);
|
ev_schedule(proto_flush_event);
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,7 +141,7 @@ typedef struct rtable {
|
||||||
int gc_counter; /* Number of operations since last GC */
|
int gc_counter; /* Number of operations since last GC */
|
||||||
bird_clock_t gc_time; /* Time of last GC */
|
bird_clock_t gc_time; /* Time of last GC */
|
||||||
byte gc_scheduled; /* GC is scheduled */
|
byte gc_scheduled; /* GC is scheduled */
|
||||||
byte prune_state; /* Table prune state, 1 -> prune is running */
|
byte prune_state; /* Table prune state, 1 -> scheduled, 2-> running */
|
||||||
byte hcu_scheduled; /* Hostcache update is scheduled */
|
byte hcu_scheduled; /* Hostcache update is scheduled */
|
||||||
byte nhu_state; /* Next Hop Update state */
|
byte nhu_state; /* Next Hop Update state */
|
||||||
struct fib_iterator prune_fit; /* Rtable prune FIB iterator */
|
struct fib_iterator prune_fit; /* Rtable prune FIB iterator */
|
||||||
|
@ -265,7 +265,6 @@ void rt_dump(rtable *);
|
||||||
void rt_dump_all(void);
|
void rt_dump_all(void);
|
||||||
int rt_feed_baby(struct proto *p);
|
int rt_feed_baby(struct proto *p);
|
||||||
void rt_feed_baby_abort(struct proto *p);
|
void rt_feed_baby_abort(struct proto *p);
|
||||||
void rt_schedule_prune_all(void);
|
|
||||||
int rt_prune_loop(void);
|
int rt_prune_loop(void);
|
||||||
struct rtable_config *rt_new_table(struct symbol *s);
|
struct rtable_config *rt_new_table(struct symbol *s);
|
||||||
|
|
||||||
|
|
|
@ -1268,19 +1268,8 @@ rt_init(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Called from proto_schedule_flush_loop() only,
|
|
||||||
ensuring that all prune states are zero */
|
|
||||||
void
|
|
||||||
rt_schedule_prune_all(void)
|
|
||||||
{
|
|
||||||
rtable *t;
|
|
||||||
|
|
||||||
WALK_LIST(t, routing_tables)
|
|
||||||
t->prune_state = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
rt_prune_step(rtable *tab, int *max_feed)
|
rt_prune_step(rtable *tab, int step, int *max_feed)
|
||||||
{
|
{
|
||||||
struct fib_iterator *fit = &tab->prune_fit;
|
struct fib_iterator *fit = &tab->prune_fit;
|
||||||
|
|
||||||
|
@ -1306,8 +1295,8 @@ again:
|
||||||
|
|
||||||
rescan:
|
rescan:
|
||||||
for (e=n->routes; e; e=e->next)
|
for (e=n->routes; e; e=e->next)
|
||||||
if (e->sender->proto->core_state != FS_HAPPY &&
|
if (e->sender->proto->flushing ||
|
||||||
e->sender->proto->core_state != FS_FEEDING)
|
(step && e->attrs->proto->flushing))
|
||||||
{
|
{
|
||||||
if (*max_feed <= 0)
|
if (*max_feed <= 0)
|
||||||
{
|
{
|
||||||
|
@ -1315,6 +1304,10 @@ again:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (step)
|
||||||
|
log(L_WARN "Route %I/%d from %s still in %s after flush",
|
||||||
|
n->n.prefix, n->n.pxlen, e->attrs->proto->name, tab->name);
|
||||||
|
|
||||||
rte_discard(tab, e);
|
rte_discard(tab, e);
|
||||||
(*max_feed)--;
|
(*max_feed)--;
|
||||||
|
|
||||||
|
@ -1339,23 +1332,42 @@ again:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* rt_prune_loop - prune routing tables
|
* rt_prune_loop - prune routing tables
|
||||||
* @tab: routing table to be pruned
|
|
||||||
*
|
*
|
||||||
* The prune loop scans routing tables and removes routes belonging to
|
* The prune loop scans routing tables and removes routes belonging to
|
||||||
* inactive protocols and also stale network entries. Returns 1 when
|
* flushing protocols and also stale network entries. Returns 1 when
|
||||||
* all such routes are pruned. It is a part of the protocol flushing
|
* all such routes are pruned. It is a part of the protocol flushing
|
||||||
* loop.
|
* loop.
|
||||||
|
*
|
||||||
|
* The prune loop runs in two steps. In the first step it prunes just
|
||||||
|
* the routes with flushing senders (in explicitly marked tables) so
|
||||||
|
* the route removal is propagated as usual. In the second step, all
|
||||||
|
* remaining relevant routes are removed. Ideally, there shouldn't be
|
||||||
|
* any, but it happens when pipe filters are changed.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
rt_prune_loop(void)
|
rt_prune_loop(void)
|
||||||
{
|
{
|
||||||
rtable *t;
|
static int step = 0;
|
||||||
int max_feed = 512;
|
int max_feed = 512;
|
||||||
|
rtable *t;
|
||||||
|
|
||||||
|
again:
|
||||||
WALK_LIST(t, routing_tables)
|
WALK_LIST(t, routing_tables)
|
||||||
if (! rt_prune_step(t, &max_feed))
|
if (! rt_prune_step(t, step, &max_feed))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (step == 0)
|
||||||
|
{
|
||||||
|
/* Prepare for the second step */
|
||||||
|
WALK_LIST(t, routing_tables)
|
||||||
|
t->prune_state = 1;
|
||||||
|
|
||||||
|
step = 1;
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Done */
|
||||||
|
step = 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue