Nest: Fix race condition during reconfiguration
If export filter is changed during reconfiguration and a route disappears between reconfiguration and refeed (e.g., if the route is a static route also removed during the reconfiguration), the route is not withdrawn. The patch fixes that by adding tx reconfiguration timestamp.
This commit is contained in:
parent
8e86ffce82
commit
a81e18da25
3 changed files with 20 additions and 15 deletions
|
@ -165,6 +165,7 @@ proto_add_channel(struct proto *p, struct channel_config *cf)
|
||||||
c->channel_state = CS_DOWN;
|
c->channel_state = CS_DOWN;
|
||||||
c->export_state = ES_DOWN;
|
c->export_state = ES_DOWN;
|
||||||
c->last_state_change = current_time();
|
c->last_state_change = current_time();
|
||||||
|
c->last_tx_filter_change = current_time();
|
||||||
c->reloadable = 1;
|
c->reloadable = 1;
|
||||||
|
|
||||||
CALL(c->channel->init, c, cf);
|
CALL(c->channel->init, c, cf);
|
||||||
|
@ -557,6 +558,9 @@ channel_reconfigure(struct channel *c, struct channel_config *cf)
|
||||||
|
|
||||||
channel_verify_limits(c);
|
channel_verify_limits(c);
|
||||||
|
|
||||||
|
if (export_changed)
|
||||||
|
c->last_tx_filter_change = current_time();
|
||||||
|
|
||||||
/* Execute channel-specific reconfigure hook */
|
/* Execute channel-specific reconfigure hook */
|
||||||
if (c->channel->reconfigure && !c->channel->reconfigure(c, cf))
|
if (c->channel->reconfigure && !c->channel->reconfigure(c, cf))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -536,6 +536,7 @@ struct channel {
|
||||||
u8 gr_wait; /* Route export to channel is postponed until graceful restart */
|
u8 gr_wait; /* Route export to channel is postponed until graceful restart */
|
||||||
|
|
||||||
btime last_state_change; /* Time of last state transition */
|
btime last_state_change; /* Time of last state transition */
|
||||||
|
btime last_tx_filter_change;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -549,29 +549,29 @@ rt_notify_basic(struct channel *c, net *net, rte *new0, rte *old0, int refeed)
|
||||||
c->stats.exp_withdraws_received++;
|
c->stats.exp_withdraws_received++;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is a tricky part - we don't know whether route 'old' was
|
* This is a tricky part - we don't know whether route 'old' was exported to
|
||||||
* exported to protocol 'p' or was filtered by the export filter.
|
* protocol 'p' or was filtered by the export filter. We try to run the export
|
||||||
* We try to run the export filter to know this to have a correct
|
* filter to know this to have a correct value in 'old' argument of rte_update
|
||||||
* value in 'old' argument of rte_update (and proper filter value)
|
* (and proper filter value).
|
||||||
*
|
*
|
||||||
* FIXME - this is broken because 'configure soft' may change
|
* This is broken because 'configure soft' may change filters but keep routes.
|
||||||
* filters but keep routes. Refeed is expected to be called after
|
* Refeed cycle is expected to be called after change of the filters and with
|
||||||
* change of the filters and with old == new, therefore we do not
|
* old == new, therefore we do not even try to run the filter on an old route.
|
||||||
* even try to run the filter on an old route, This may lead to
|
* This may lead to 'spurious withdraws' but ensure that there are no 'missing
|
||||||
* 'spurious withdraws' but ensure that there are no 'missing
|
|
||||||
* withdraws'.
|
* withdraws'.
|
||||||
*
|
*
|
||||||
* This is not completely safe as there is a window between
|
* This is not completely safe as there is a window between reconfiguration
|
||||||
* reconfiguration and the end of refeed - if a newly filtered
|
* and the end of refeed - if a newly filtered route disappears during this
|
||||||
* route disappears during this period, proper withdraw is not
|
* period, proper withdraw is not sent (because old would be also filtered)
|
||||||
* sent (because old would be also filtered) and the route is
|
* and the route is not refeeded (because it disappeared before that).
|
||||||
* not refeeded (because it disappeared before that).
|
* Therefore, we also do not try to run the filter on old routes that are
|
||||||
|
* older than the last filter change.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (new)
|
if (new)
|
||||||
new = export_filter(c, new, &new_free, 0);
|
new = export_filter(c, new, &new_free, 0);
|
||||||
|
|
||||||
if (old && !refeed)
|
if (old && !(refeed || (old->lastmod <= c->last_tx_filter_change)))
|
||||||
old = export_filter(c, old, &old_free, 1);
|
old = export_filter(c, old, &old_free, 1);
|
||||||
|
|
||||||
if (!new && !old)
|
if (!new && !old)
|
||||||
|
|
Loading…
Reference in a new issue