mirror of
https://github.com/jmcorgan/fips.git
synced 2026-10-05 19:18:25 +00:00
Move path MTU state and mesh framing constants out of the upper layer
PathMtuEntry and PathMtuLookup describe per-destination path MTU state that only the node writes, releases and expires; the TUN threads merely read it. FIPS_OVERHEAD is the combined FMP and FSP framing cost and is also used by the native datagram API. MIN_REACTIVE_PATH_MTU is path MTU policy for the MtuExceeded carrier and belongs beside MIN_ACTIONABLE_PATH_MTU. Define the path MTU types in node/path_mtu.rs, FIPS_OVERHEAD in a new proto/framing.rs, and MIN_REACTIVE_PATH_MTU in proto/mmp/limits.rs. The upper tun and icmp modules re-export all of them, so every existing crate and public path keeps resolving and no consumer changes. Values, types and documentation are unchanged, and none of the moved items has a log site.
This commit is contained in:
@@ -19,6 +19,7 @@ mod lifecycle;
|
||||
pub(crate) mod metrics;
|
||||
pub(crate) mod netmon;
|
||||
pub use netmon::NetmonTrigger;
|
||||
pub(crate) mod path_mtu;
|
||||
mod peer_error_budget;
|
||||
mod peering;
|
||||
mod rate_limit;
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
//! Per-destination path MTU state shared with the TCP MSS clamp.
|
||||
//!
|
||||
//! Every writer, the release paths and the expiry pass live in the node;
|
||||
//! the TUN reader and writer threads only read the map.
|
||||
|
||||
use crate::FipsAddress;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
/// One `path_mtu_lookup` entry: the MTU the TCP MSS clamp reads, plus how
|
||||
/// the entry is released.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct PathMtuEntry {
|
||||
/// Path MTU in bytes.
|
||||
pub mtu: u16,
|
||||
/// Unix ms at which a discovery `LookupResponse` supplied this value, or
|
||||
/// `None` for an entry that some event releases instead of a timer.
|
||||
///
|
||||
/// The discovery carrier is the one with no release path: it writes an
|
||||
/// entry for a destination this node may never open a session with, and
|
||||
/// all three callers of `path_mtu_lookup_release` fire on session state.
|
||||
/// A link MTU this node derived from its own transport, and a value
|
||||
/// learned inside a session, are both released by an event that says the
|
||||
/// thing they describe is gone, so they carry no deadline.
|
||||
pub learned_ms: Option<u64>,
|
||||
}
|
||||
|
||||
impl PathMtuEntry {
|
||||
/// An entry released by an event rather than a timer: a locally derived
|
||||
/// link MTU, or a value learned inside a session.
|
||||
pub fn held(mtu: u16) -> Self {
|
||||
Self {
|
||||
mtu,
|
||||
learned_ms: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// A remote party's claim stored at `at_ms` for a destination with no
|
||||
/// other release path. Expires.
|
||||
pub fn learned(mtu: u16, at_ms: u64) -> Self {
|
||||
Self {
|
||||
mtu,
|
||||
learned_ms: Some(at_ms),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Read-only handle to the per-destination path MTU map. Populated by
|
||||
/// the discovery handler on `LookupResponse`; read by the TUN reader
|
||||
/// (outbound clamp) and writer (inbound clamp) at TCP MSS clamp time.
|
||||
/// Keyed by [`FipsAddress`] (16 bytes, the IPv6 form of a fips peer
|
||||
/// address).
|
||||
pub type PathMtuLookup = Arc<RwLock<HashMap<FipsAddress, PathMtuEntry>>>;
|
||||
@@ -0,0 +1,37 @@
|
||||
//! Encapsulation overhead spanning the FMP and FSP layers.
|
||||
//!
|
||||
//! The framing cost of a session datagram is the sum of FMP link framing and
|
||||
//! FSP session framing, so it belongs to neither layer's wire module alone.
|
||||
|
||||
/// FIPS base encapsulation overhead for DataPacket (excluding port payload).
|
||||
///
|
||||
/// This is the fixed overhead for a SessionDatagram carrying an FSP DataPacket,
|
||||
/// used by the send path's CP-flag guard to check whether piggybacked coords
|
||||
/// fit within the transport MTU. For IPv6 effective MTU calculations, use
|
||||
/// [`FIPS_IPV6_OVERHEAD`] which accounts for port multiplexing and header
|
||||
/// compression.
|
||||
///
|
||||
/// Breakdown (traced through the actual send path):
|
||||
///
|
||||
/// ```text
|
||||
/// FMP outer header (cleartext AAD) 16
|
||||
/// common prefix (4) + receiver_idx (4) + counter (8)
|
||||
/// FMP AEAD ciphertext:
|
||||
/// timestamp (4) + msg_type (1) 5 [FMP inner header]
|
||||
/// ttl (1) + path_mtu (2) + src (16) + dst (16) 35 [SessionDatagram body]
|
||||
/// FSP header (4 prefix + 8 counter) 12 [cleartext AAD]
|
||||
/// FSP AEAD ciphertext:
|
||||
/// timestamp (4) + msg_type (1) + flags (1) 6 [FSP inner header]
|
||||
/// <application data>
|
||||
/// Poly1305 tag 16 [FSP AEAD]
|
||||
/// FMP Poly1305 tag 16 [FMP AEAD]
|
||||
/// ────
|
||||
/// 106
|
||||
/// ```
|
||||
///
|
||||
/// Note: the FMP inner header msg_type byte IS the SessionDatagram msg_type
|
||||
/// byte (shared, not double-counted). The "35 bytes" is the SessionDatagram
|
||||
/// body after msg_type is consumed by the dispatch layer.
|
||||
///
|
||||
/// [`FIPS_IPV6_OVERHEAD`]: crate::upper::icmp::FIPS_IPV6_OVERHEAD
|
||||
pub const FIPS_OVERHEAD: u16 = 16 + 16 + 5 + 35 + 12 + 6 + 16; // 106 bytes
|
||||
@@ -82,3 +82,19 @@ pub const SESSION_COLD_START_INTERVAL_MS: u64 = 1_000;
|
||||
///
|
||||
/// [`mss_ceiling`]: crate::upper::icmp::mss_ceiling
|
||||
pub const MIN_ACTIONABLE_PATH_MTU: u16 = 256;
|
||||
|
||||
/// Smallest path MTU this node will act on when the claim arrives on the
|
||||
/// unauthenticated reactive carrier, `MtuExceeded`.
|
||||
///
|
||||
/// Held equal to [`MIN_ACTIONABLE_PATH_MTU`] so no hop legitimately configured
|
||||
/// with a small transport MTU loses reactive feedback. It is a separate
|
||||
/// constant because the two carriers differ in what they prove: the
|
||||
/// authenticated `PathMtuNotification` and the proof-carrying discovery
|
||||
/// response come from a party this node has verified, whereas this one comes
|
||||
/// from whoever could route a datagram here. What keeps a legal-but-forged
|
||||
/// claim from pinning a session is corroboration against what this node has
|
||||
/// actually sent, not this floor. Raising it (576 is the value the original
|
||||
/// path-MTU floor design proposed, and derives an inner IPv6 MTU of 499)
|
||||
/// bounds the outcome of an uncorroborated claim further, at the cost of
|
||||
/// ignoring an honest report from any hop configured between the two values.
|
||||
pub const MIN_REACTIVE_PATH_MTU: u16 = MIN_ACTIONABLE_PATH_MTU;
|
||||
|
||||
@@ -85,6 +85,6 @@ impl fmt::Display for MmpMode {
|
||||
pub use limits::{
|
||||
COLD_START_SAMPLES, DEFAULT_COLD_START_INTERVAL_MS, DEFAULT_LOG_INTERVAL_SECS,
|
||||
DEFAULT_OWD_WINDOW_SIZE, EWMA_LONG_ALPHA, EWMA_SHORT_ALPHA, MAX_REPORT_INTERVAL_MS,
|
||||
MAX_SESSION_REPORT_INTERVAL_MS, MIN_ACTIONABLE_PATH_MTU, MIN_REPORT_INTERVAL_MS,
|
||||
MIN_SESSION_REPORT_INTERVAL_MS, SESSION_COLD_START_INTERVAL_MS,
|
||||
MAX_SESSION_REPORT_INTERVAL_MS, MIN_ACTIONABLE_PATH_MTU, MIN_REACTIVE_PATH_MTU,
|
||||
MIN_REPORT_INTERVAL_MS, MIN_SESSION_REPORT_INTERVAL_MS, SESSION_COLD_START_INTERVAL_MS,
|
||||
};
|
||||
|
||||
@@ -10,6 +10,7 @@ pub(crate) mod bloom;
|
||||
pub(crate) mod codec;
|
||||
pub(crate) mod coord;
|
||||
pub(crate) mod fmp;
|
||||
pub(crate) mod framing;
|
||||
pub(crate) mod fsp;
|
||||
pub(crate) mod link;
|
||||
pub(crate) mod lookup;
|
||||
|
||||
+7
-40
@@ -61,34 +61,9 @@ const MAX_ORIGINAL_PACKET: usize = MIN_IPV6_MTU - IPV6_HEADER_LEN - ICMPV6_HEADE
|
||||
|
||||
/// FIPS base encapsulation overhead for DataPacket (excluding port payload).
|
||||
///
|
||||
/// This is the fixed overhead for a SessionDatagram carrying an FSP DataPacket,
|
||||
/// used by the send path's CP-flag guard to check whether piggybacked coords
|
||||
/// fit within the transport MTU. For IPv6 effective MTU calculations, use
|
||||
/// [`FIPS_IPV6_OVERHEAD`] which accounts for port multiplexing and header
|
||||
/// compression.
|
||||
///
|
||||
/// Breakdown (traced through the actual send path):
|
||||
///
|
||||
/// ```text
|
||||
/// FMP outer header (cleartext AAD) 16
|
||||
/// common prefix (4) + receiver_idx (4) + counter (8)
|
||||
/// FMP AEAD ciphertext:
|
||||
/// timestamp (4) + msg_type (1) 5 [FMP inner header]
|
||||
/// ttl (1) + path_mtu (2) + src (16) + dst (16) 35 [SessionDatagram body]
|
||||
/// FSP header (4 prefix + 8 counter) 12 [cleartext AAD]
|
||||
/// FSP AEAD ciphertext:
|
||||
/// timestamp (4) + msg_type (1) + flags (1) 6 [FSP inner header]
|
||||
/// <application data>
|
||||
/// Poly1305 tag 16 [FSP AEAD]
|
||||
/// FMP Poly1305 tag 16 [FMP AEAD]
|
||||
/// ────
|
||||
/// 106
|
||||
/// ```
|
||||
///
|
||||
/// Note: the FMP inner header msg_type byte IS the SessionDatagram msg_type
|
||||
/// byte (shared, not double-counted). The "35 bytes" is the SessionDatagram
|
||||
/// body after msg_type is consumed by the dispatch layer.
|
||||
pub const FIPS_OVERHEAD: u16 = 16 + 16 + 5 + 35 + 12 + 6 + 16; // 106 bytes
|
||||
/// Re-exported: the value is FMP plus FSP framing and is defined with the
|
||||
/// protocol layers, in [`crate::proto::framing::FIPS_OVERHEAD`].
|
||||
pub use crate::proto::framing::FIPS_OVERHEAD;
|
||||
|
||||
/// FIPS encapsulation overhead for compressed IPv6 shim traffic (port 256).
|
||||
///
|
||||
@@ -115,18 +90,10 @@ pub use crate::proto::mmp::MIN_ACTIONABLE_PATH_MTU;
|
||||
/// Smallest path MTU this node will act on when the claim arrives on the
|
||||
/// unauthenticated reactive carrier, `MtuExceeded`.
|
||||
///
|
||||
/// Held equal to [`MIN_ACTIONABLE_PATH_MTU`] so no hop legitimately configured
|
||||
/// with a small transport MTU loses reactive feedback. It is a separate
|
||||
/// constant because the two carriers differ in what they prove: the
|
||||
/// authenticated `PathMtuNotification` and the proof-carrying discovery
|
||||
/// response come from a party this node has verified, whereas this one comes
|
||||
/// from whoever could route a datagram here. What keeps a legal-but-forged
|
||||
/// claim from pinning a session is corroboration against what this node has
|
||||
/// actually sent, not this floor. Raising it (576 is the value the original
|
||||
/// path-MTU floor design proposed, and derives an inner IPv6 MTU of 499)
|
||||
/// bounds the outcome of an uncorroborated claim further, at the cost of
|
||||
/// ignoring an honest report from any hop configured between the two values.
|
||||
pub const MIN_REACTIVE_PATH_MTU: u16 = MIN_ACTIONABLE_PATH_MTU;
|
||||
/// Re-exported: a protocol policy decision defined beside
|
||||
/// [`crate::proto::mmp::MIN_ACTIONABLE_PATH_MTU`], in
|
||||
/// [`crate::proto::mmp::MIN_REACTIVE_PATH_MTU`].
|
||||
pub use crate::proto::mmp::MIN_REACTIVE_PATH_MTU;
|
||||
|
||||
/// Calculate the effective IPv6 MTU for FIPS-encapsulated traffic.
|
||||
///
|
||||
|
||||
+6
-46
@@ -14,7 +14,6 @@
|
||||
use crate::FipsAddress;
|
||||
#[cfg(unix)]
|
||||
use crate::{FipsAddress, TunConfig};
|
||||
use std::collections::HashMap;
|
||||
#[cfg(unix)]
|
||||
use std::fs::File;
|
||||
#[cfg(unix)]
|
||||
@@ -25,7 +24,7 @@ use std::io::Write;
|
||||
use std::net::Ipv6Addr;
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::io::{AsRawFd, FromRawFd};
|
||||
use std::sync::{Arc, RwLock, mpsc};
|
||||
use std::sync::{Arc, mpsc};
|
||||
use thiserror::Error;
|
||||
#[cfg(unix)]
|
||||
use tracing::error;
|
||||
@@ -35,50 +34,9 @@ use tracing::{error, warn};
|
||||
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "freebsd"))]
|
||||
use tun::Layer;
|
||||
|
||||
/// One `path_mtu_lookup` entry: the MTU the TCP MSS clamp reads, plus how
|
||||
/// the entry is released.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct PathMtuEntry {
|
||||
/// Path MTU in bytes.
|
||||
pub mtu: u16,
|
||||
/// Unix ms at which a discovery `LookupResponse` supplied this value, or
|
||||
/// `None` for an entry that some event releases instead of a timer.
|
||||
///
|
||||
/// The discovery carrier is the one with no release path: it writes an
|
||||
/// entry for a destination this node may never open a session with, and
|
||||
/// all three callers of `path_mtu_lookup_release` fire on session state.
|
||||
/// A link MTU this node derived from its own transport, and a value
|
||||
/// learned inside a session, are both released by an event that says the
|
||||
/// thing they describe is gone, so they carry no deadline.
|
||||
pub learned_ms: Option<u64>,
|
||||
}
|
||||
|
||||
impl PathMtuEntry {
|
||||
/// An entry released by an event rather than a timer: a locally derived
|
||||
/// link MTU, or a value learned inside a session.
|
||||
pub fn held(mtu: u16) -> Self {
|
||||
Self {
|
||||
mtu,
|
||||
learned_ms: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// A remote party's claim stored at `at_ms` for a destination with no
|
||||
/// other release path. Expires.
|
||||
pub fn learned(mtu: u16, at_ms: u64) -> Self {
|
||||
Self {
|
||||
mtu,
|
||||
learned_ms: Some(at_ms),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Read-only handle to the per-destination path MTU map. Populated by
|
||||
/// the discovery handler on `LookupResponse`; read by the TUN reader
|
||||
/// (outbound clamp) and writer (inbound clamp) at TCP MSS clamp time.
|
||||
/// Keyed by [`FipsAddress`] (16 bytes, the IPv6 form of a fips peer
|
||||
/// address).
|
||||
pub type PathMtuLookup = Arc<RwLock<HashMap<FipsAddress, PathMtuEntry>>>;
|
||||
// The path MTU map is node state; re-exported so `crate::upper::tun` paths
|
||||
// keep resolving.
|
||||
pub use crate::node::path_mtu::{PathMtuEntry, PathMtuLookup};
|
||||
|
||||
/// The node-global TCP MSS ceiling, shared live with the TUN reader and
|
||||
/// writer threads.
|
||||
@@ -1653,6 +1611,8 @@ mod platform {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::RwLock;
|
||||
|
||||
#[test]
|
||||
fn test_tun_state_display() {
|
||||
|
||||
Reference in New Issue
Block a user