Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/gunnar

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)
        );
    }
}