summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--nest/proto.c1
-rw-r--r--nest/protocol.h1
-rw-r--r--nest/rt-table.c36
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();
}