STUN actor: try to avoid ip address flapping #21

Merged
lx merged 4 commits from stun-keep-values into main 2024-01-16 15:05:01 +00:00
2 changed files with 28 additions and 9 deletions
Showing only changes of commit 6613ea347d - Show all commits

View file

@ -1,5 +1,4 @@
use std::collections::HashSet; use std::collections::HashSet;
use std::sync::Arc;
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use iptables; use iptables;

View file

@ -8,6 +8,11 @@ use serde::{Deserialize, Serialize};
use crate::config::{RuntimeConfigConsul, RuntimeConfigStun}; use crate::config::{RuntimeConfigConsul, RuntimeConfigStun};
use crate::consul; use crate::consul;
/// If autodiscovery returns None but an address was obtained less than
/// this number of seconds ago (here 15 minutes), we keep that address
/// in the Consul db instead of insterting a None.
const PERSIST_SOME_RESULT_DURATION_SECS: u64 = 900;
pub struct StunActor { pub struct StunActor {
consul: consul::Consul, consul: consul::Consul,
refresh_time: Duration, refresh_time: Duration,
@ -78,7 +83,7 @@ impl StunActor {
} }
impl StunAutodiscovery { impl StunAutodiscovery {
async fn do_iteration(&self, consul: &consul::Consul) -> Result<()> { async fn do_iteration(&mut self, consul: &consul::Consul) -> Result<()> {
let binding_ip = match self.is_ipv4 { let binding_ip = match self.is_ipv4 {
true => IpAddr::V4(Ipv4Addr::UNSPECIFIED), // 0.0.0.0 true => IpAddr::V4(Ipv4Addr::UNSPECIFIED), // 0.0.0.0
false => IpAddr::V6(Ipv6Addr::UNSPECIFIED), // [::] false => IpAddr::V6(Ipv6Addr::UNSPECIFIED), // [::]
@ -96,16 +101,31 @@ impl StunAutodiscovery {
None => None, None => None,
}; };
consul let now = timestamp();
.kv_put(
&self.consul_key, if discovered_addr.is_none() {
serde_json::to_vec(&AutodiscoverResult { if let Some(last_result) = &self.last_result {
timestamp: timestamp(), if last_result.address.is_some()
&& now - last_result.timestamp <= PERSIST_SOME_RESULT_DURATION_SECS
{
// Keep non-None result that was obtained before by not
// writing/taking into account None result.
return Ok(());
}
}
}
let current_result = AutodiscoverResult {
timestamp: now,
address: discovered_addr, address: discovered_addr,
})?, };
)
consul
.kv_put(&self.consul_key, serde_json::to_vec(&current_result)?)
.await?; .await?;
self.last_result = Some(current_result);
Ok(()) Ok(())
} }
} }