crates/gunnar-front/src/mesh_probe.rs
//! **The front proves the tunnel is the only path** (WireGuard-only, owner
//! 2026-10-04). The probe is SHARED with Holger's front since P4c (A28 M11):
//! Skidbladnir `nordisk_pairing::frontside::mesh_probe` (feature `mesh-probe`).
//!
//! The front sits on the same utility network as main and the twin, so it is
//! the one place a plain-IP connection between boxes can be tried for real.
//! Once the installer has fed both boxes, it dials each box's UTILITY address
//! on the control plane, the replication listener and the forge
//! ([`PLAIN_PORTS`]) — every one must be refused — and each box's control
//! plane on its OVERLAY address, which must answer. It says what it saw in
//! its log, one line per dial and one verdict line ([`PASS`] / [`FAIL`]),
//! which the installer reads through the log door; the kit's bench proof
//! holds an install to it.
use std::sync::Arc;
pub use nordisk_pairing::frontside::mesh_probe::{
boxes_of, Box3, Seen, Watch, AFTER_PASSED, DIAL, FAIL, PASS, REPEAT_FAILURE, UNTIL_PASSED,
};
/// The ports a plain-IP connection to a box is tried on: the control plane,
/// the replication listener, the forge.
pub const PLAIN_PORTS: [u16; 3] = [
nordisk_pairing::CONTROL_PORT,
nordisk_pairing::CONTROL_PORT + 1,
2222,
];
/// **Start the probe** as a jera job (P4b, lane mon-shared: it was a raw tokio loop; Holger's
/// front's probe is a jera job too): once main AND the twin are fed (`boxes_of(.., true)`), one
/// look every [`UNTIL_PASSED`] until it has passed, then every [`AFTER_PASSED`]; its lines said
/// only when they changed, a standing failure again after [`REPEAT_FAILURE`], each at its level.
/// Listed, a look that panics is said and a FAILED job and the next one runs, stopped at the
/// clean stop. The dials are blocking; a look runs on the runtime's blocking pool.
pub fn start(vm: Arc<crate::vm::FrontVm>) {
let say: gunnar_common::jobs::Say = Arc::new(|l: &str| tracing::error!("front: {l}"));
let watch = Watch::default();
let spawned = gunnar_common::jobs::start("front-mesh-probe", UNTIL_PASSED, say, move || {
if let Some(boxes) = vm.latest().as_ref().and_then(|r| boxes_of(r, true)) {
let (lines, _ok) =
watch.look(&boxes, &PLAIN_PORTS, nordisk_pairing::CONTROL_PORT, DIAL);
for (warn, l) in lines {
if warn {
tracing::warn!("front: {l}");
} else {
tracing::info!("front: {l}");
}
}
}
gunnar_common::jobs::Round::After(if watch.passed() {
AFTER_PASSED
} else {
UNTIL_PASSED
})
});
if let Err(e) = spawned {
tracing::error!("front: the mesh probe does not start ({e}): the tunnel is not probed");
}
}
#[cfg(test)]
mod tests {
use super::*;
/// Gunnar's plain ports: the control plane, the replication listener, the forge.
#[test]
fn the_plain_ports_are_the_control_plane_replication_and_the_forge() {
assert_eq!(
PLAIN_PORTS,
[
nordisk_pairing::CONTROL_PORT,
nordisk_pairing::CONTROL_PORT + 1,
2222
]
);
}
/// ★ Gunnar probes both boxes or none: a twin not fed yet holds the probe back.
#[test]
fn the_boxes_are_main_and_the_twin_once_both_are_fed() {
use nordisk_pairing::join::{Assigned, JoinReply, Peer};
use nordisk_pairing::Role;
use std::net::Ipv4Addr;
let peer = |name: &str, role: Role, last: u8, utility: bool| Peer {
name: name.into(),
role,
tunnel_pubkey: "K".into(),
overlay: Ipv4Addr::new(10, 44, 0, last),
endpoint: None,
utility: utility.then(|| Ipv4Addr::new(10, 13, 8, last)),
};
let reply = |peers: Vec<Peer>| JoinReply {
estate: "gunnar.mock.invalid".into(),
me: Assigned {
name: "vm1".into(),
overlay: nordisk_pairing::OVERLAY_FRONT,
},
cert_pem: None,
role: Some(Role::Front),
primary_overlay: None,
primary_utility: None,
peers,
feed: Default::default(),
};
assert_eq!(
boxes_of(&reply(vec![peer("vm2", Role::Primary, 2, true)]), true),
None,
"main alone"
);
assert_eq!(
boxes_of(
&reply(vec![
peer("vm2", Role::Primary, 2, true),
peer("vm3", Role::Twin, 3, false)
]),
true
),
None,
"a twin with no utility address"
);
assert_eq!(
boxes_of(
&reply(vec![
peer("vm2", Role::Primary, 2, true),
peer("vm3", Role::Twin, 3, true)
]),
true
)
.map(|b| b.len()),
Some(2)
);
}
}