RPKI: ask a cache without data yet again soon

A validator that is still running its first validation answers a query
with No Data Available (error code 2). That ended the session, and the
next attempt came after the retry interval: 600 seconds when the cache
had not yet said otherwise, which it cannot have before it has data.
For those ten minutes after a validator started, nothing was validated.

No Data Available is now asked again after 30 seconds, or after
retry_seconds if that is shorter, and logged as information rather than
as a warning. Other failures wait as before, after trying the next
cache if there is one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Rayhaan JaufeerallyandClaude Opus 5.5 committed 2026-10-05 16:08:19 +02:00
1 parent 9362ba9e34
commit 52593bb2c2
2 files changed
+55 -8

No files matched your search

+50 -8
View File
@@ -54,6 +54,12 @@ const MAX_RECORDS: usize = 8_000_000;
/// How long to wait before trying the next cache after one has failed. /// How long to wait before trying the next cache after one has failed.
const NEXT_CACHE_DELAY: Duration = Duration::from_secs(1); const NEXT_CACHE_DELAY: Duration = Duration::from_secs(1);
/// How long to wait before asking a cache again that said it has no data
/// yet, rather than the retry interval: it is up and validating, which
/// takes minutes after it starts, and the retry interval is ten unless it
/// has said otherwise, which it has not had the chance to.
const NO_DATA_RETRY: Duration = Duration::from_secs(30);
/// How long a cache that is being left is given to take the reason. /// How long a cache that is being left is given to take the reason.
const ERROR_REPORT_TIMEOUT: Duration = Duration::from_secs(1); const ERROR_REPORT_TIMEOUT: Duration = Duration::from_secs(1);
@@ -419,23 +425,29 @@ impl Client {
self.protocol_version = version; self.protocol_version = version;
continue; continue;
} }
warn!(%cache, err = %ended, "RPKI cache session ended"); let no_data = matches!(
ended,
SessionError::Reported {
code: error_code::NO_DATA_AVAILABLE,
..
}
);
if no_data {
info!(%cache, "RPKI cache has no data yet; asking again soon");
} else {
warn!(%cache, err = %ended, "RPKI cache session ended");
}
self.status(|status| { self.status(|status| {
status.state = CacheState::Connecting; status.state = CacheState::Connecting;
status.last_error = Some(ended.to_string()); status.last_error = Some(ended.to_string());
}); });
// The next cache at once; when all have been tried, a rest.
attempt += 1; attempt += 1;
// The next cache, or this one when it is back, may speak a // The next cache, or this one when it is back, may speak a
// newer version. // newer version.
self.protocol_version = VERSION_2; self.protocol_version = VERSION_2;
let wait = if attempt.is_multiple_of(self.config.caches.len()) { let all_tried = attempt.is_multiple_of(self.config.caches.len());
self.retry() self.wait(rest(all_tried, no_data, self.retry())).await;
} else {
NEXT_CACHE_DELAY
};
self.wait(wait).await;
} }
} }
@@ -889,3 +901,33 @@ enum Answer {
/// With a request to ask for everything instead. /// With a request to ask for everything instead.
Reset, Reset,
} }
/// How long to rest after a session ended: the next cache at once; when
/// all have been tried, the retry interval, or less if the last one is
/// only still validating.
fn rest(all_tried: bool, no_data: bool, retry: Duration) -> Duration {
match (all_tried, no_data) {
(false, _) => NEXT_CACHE_DELAY,
(true, true) => NO_DATA_RETRY.min(retry),
(true, false) => retry,
}
}
#[cfg(test)]
mod tests {
use super::*;
/// A cache that is still validating after it started is asked again
/// in half a minute, not the ten the retry interval is by default.
#[test]
fn a_cache_without_data_yet_is_asked_again_soon() {
let ten_minutes = Duration::from_secs(600);
assert_eq!(rest(true, true, ten_minutes), NO_DATA_RETRY);
assert_eq!(rest(true, false, ten_minutes), ten_minutes);
// Never later than the retry interval says.
let short = Duration::from_secs(5);
assert_eq!(rest(true, true, short), short);
// Another cache first, whatever this one said.
assert_eq!(rest(false, true, ten_minutes), NEXT_CACHE_DELAY);
}
}
+5
View File
@@ -64,6 +64,11 @@ rpki {
When the data expires, Ferrix discards it, and no route is considered When the data expires, Ferrix discards it, and no route is considered
invalid until new data is received. invalid until new data is received.
A validator that has just started reports that it has no data available
until its first validation run is complete, which takes several minutes.
Ferrix then asks again after 30 seconds, or after `retry_seconds` if that
is shorter, rather than after the retry interval.
### Running a Validator ### Running a Validator
The following command starts Routinator with an RTR server on port 3323: The following command starts Routinator with an RTR server on port 3323: