diff options
-rw-r--r-- | nest/proto.c | 1 | ||||
-rw-r--r-- | nest/protocol.h | 1 | ||||
-rw-r--r-- | nest/rt-table.c | 36 |
3 files changed, 26 insertions, 12 deletions
diff --git a/nest/proto.c b/nest/proto.c index c531d869..bdac4bf6 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -585,6 +585,7 @@ proto_schedule_feed(struct proto *p, int initial) { DBG("%s: Scheduling meal\n", p->name); p->core_state = FS_FEEDING; + p->refeeding = !initial; proto_relink(p); p->attn->hook = initial ? proto_feed_initial : proto_feed_more; ev_schedule(p->attn); diff --git a/nest/protocol.h b/nest/protocol.h index 66e6c43d..e1adc525 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -134,6 +134,7 @@ struct proto { unsigned core_state; /* Core state machine (see below) */ unsigned core_goal; /* State we want to reach (see below) */ unsigned reconfiguring; /* We're shutting down due to reconfiguration */ + unsigned refeeding; /* We are refeeding (valid only if core_state == FS_FEEDING) */ u32 hash_key; /* Random key used for hashing of neighbors */ bird_clock_t last_state_change; /* Time of last state transition */ char *last_state_name_announced; /* Last state name we've announced to the user */ diff --git a/nest/rt-table.c b/nest/rt-table.c index a8d0fee5..8efc0a61 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -158,7 +158,7 @@ rte_trace_out(unsigned int flag, struct proto *p, rte *e, char *msg) } static inline void -do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old, ea_list *tmpa, int class) +do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old, ea_list *tmpa, int class, int refeed) { struct proto *p = a->proto; rte *new0 = new; @@ -199,15 +199,27 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old, else p->stats.exp_withdraws_received++; - /* This is a tricky part - we don't know whether route 'old' was - exported to protocol 'p' or was filtered by the export filter. - We try tu run the export filter to know this to have a correct - value in 'old' argument of rt_update (and proper filter value) - - FIXME - this is broken because 'configure soft' may change - filters but keep routes */ - - if (old) + /* + * This is a tricky part - we don't know whether route 'old' was + * exported to protocol 'p' or was filtered by the export filter. + * We try tu run the export filter to know this to have a correct + * value in 'old' argument of rt_update (and proper filter value) + * + * FIXME - this is broken because 'configure soft' may change + * filters but keep routes. Refeed is expected to be called after + * change of the filters and with old == new, therefore we do not + * even try to run the filter on an old route, This may lead to + * 'spurious withdraws' but ensure that there are no 'missing + * withdraws'. + * + * This is not completely safe as there is a window between + * reconfiguration and the end of refeed - if a newly filtered + * route disappears during this period, proper withdraw is not + * sent (because old would be also filtered) and the route is + * not refeeded (because it disappeared before that). + */ + + if (old && !refeed) { if (p->out_filter == FILTER_REJECT) old = NULL; @@ -313,7 +325,7 @@ rte_announce(rtable *tab, int type, net *net, rte *new, rte *old, ea_list *tmpa) { ASSERT(a->proto->core_state == FS_HAPPY || a->proto->core_state == FS_FEEDING); if (a->proto->accept_ra_types == type) - do_rte_announce(a, type, net, new, old, tmpa, class); + do_rte_announce(a, type, net, new, old, tmpa, class, 0); } } @@ -973,7 +985,7 @@ do_feed_baby(struct proto *p, int type, struct announce_hook *h, net *n, rte *e) rte_update_lock(); tmpa = q->make_tmp_attrs ? q->make_tmp_attrs(e, rte_update_pool) : NULL; - do_rte_announce(h, type, n, e, NULL, tmpa, ipa_classify(n->n.prefix)); + do_rte_announce(h, type, n, e, p->refeeding ? e : NULL, tmpa, ipa_classify(n->n.prefix), p->refeeding); rte_update_unlock(); } |