Define the path MTU floor in the protocol layer, not the upper one

The floor arrived in the upper layer beside the arithmetic that
degenerates below it, which is where the maintenance line keeps it. That
branch has no sans-IO split, so nothing there objected; here it made the
path-MTU state machine the first thing in the protocol tree to name
something in the upper layer, in a tree whose module doc says it is
runtime-agnostic and whose async adapters live elsewhere.

Only a u16 crossed, so nothing runtime-dependent was at stake. What was
at stake is that the value is a protocol policy decision — how little a
remote party may claim before this node stops believing it — and the
state machine that owns that rule was reaching outward to fetch it. The
established rule is decisions to the core, observability and I/O to the
shell.

Move it to the MMP tuning constants, beside the state machine, and
re-export it from the upper layer so every applying site keeps its
existing path: the MSS clamp, the lookup response and the MtuExceeded
signal are all unchanged, and so is the published surface.

The doc comment keeps its cross-reference to the arithmetic it describes,
which is a documentation link rather than a dependency.
This commit is contained in:
Johnathan Corgan
2026-08-14 05:18:39 +00:00
parent aaadf69c20
commit 9f55cd53da
5 changed files with 40 additions and 21 deletions
+29
View File
@@ -53,3 +53,32 @@ pub const MAX_SESSION_REPORT_INTERVAL_MS: u64 = 10_000;
/// Session-layer cold-start report interval (before SRTT is available).
pub const SESSION_COLD_START_INTERVAL_MS: u64 = 1_000;
// --- Path MTU ---
/// Smallest remote-supplied transport path MTU this node will act on.
///
/// The `path_mtu` field is an unsigned per-hop transit annotation carried
/// outside `proof_bytes`, and the `MtuExceeded` and `PathBroken` signals
/// arrive unencrypted, so any forwarder on the path can lower it. Below this
/// value the quantities derived from it degenerate: at a transport MTU of 137
/// or less, [`mss_ceiling`] saturates to a TCP MSS of zero, at 138 it is a
/// single byte, and the derived MSS stays under a hundred all the way to 236.
/// At the floor itself the derived inner IPv6 MTU is 179 and the TCP MSS is
/// 119, clear of both the zero cliff and that band.
///
/// A candidate below the floor is ignored — treated as no information at all,
/// never applied and never stored — rather than clamped, because clamping
/// would fabricate an estimate the node has no basis for. Locally derived link
/// MTUs are not subject to the floor; it applies only to values a remote party
/// supplied. A local value is exact, so the SYN-time clamp honours it however
/// small and refuses only the zero cliff, which no provenance makes usable.
///
/// It lives here rather than beside the arithmetic that consumes it because it
/// is a protocol policy decision — how little a remote party may claim before
/// this node stops believing it — and the path-MTU state machine that owns
/// that rule is in this module. The upper layer re-exports it, so
/// `crate::upper::icmp::MIN_ACTIONABLE_PATH_MTU` continues to resolve.
///
/// [`mss_ceiling`]: crate::upper::icmp::mss_ceiling
pub const MIN_ACTIONABLE_PATH_MTU: u16 = 256;
+2 -2
View File
@@ -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_REPORT_INTERVAL_MS, MIN_SESSION_REPORT_INTERVAL_MS,
SESSION_COLD_START_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,
};
+2 -2
View File
@@ -137,9 +137,9 @@ impl PathMtuState {
/// Too Big instead of sending it. Returning `false` leaves whatever the
/// local seed established and correctly reports "no change".
///
/// [`MIN_ACTIONABLE_PATH_MTU`]: crate::upper::icmp::MIN_ACTIONABLE_PATH_MTU
/// [`MIN_ACTIONABLE_PATH_MTU`]: super::limits::MIN_ACTIONABLE_PATH_MTU
pub fn apply_notification(&mut self, reported_mtu: u16, now_ms: u64) -> bool {
if reported_mtu < crate::upper::icmp::MIN_ACTIONABLE_PATH_MTU {
if reported_mtu < super::limits::MIN_ACTIONABLE_PATH_MTU {
return false;
}
+1 -1
View File
@@ -1,8 +1,8 @@
//! Source-side `PathMtuState::apply_notification` tests: the actionable floor
//! on a remote-supplied value, and the increase-sequence counter.
use crate::proto::mmp::MIN_ACTIONABLE_PATH_MTU;
use crate::proto::mmp::path_mtu::PathMtuState;
use crate::upper::icmp::MIN_ACTIONABLE_PATH_MTU;
#[test]
fn apply_notification_ignores_a_decrease_below_the_actionable_floor() {
+6 -16
View File
@@ -105,22 +105,12 @@ pub const FIPS_IPV6_OVERHEAD: u16 = 77;
/// Smallest remote-supplied transport path MTU this node will act on.
///
/// The `path_mtu` field is an unsigned per-hop transit annotation carried
/// outside `proof_bytes`, and the `MtuExceeded` and `PathBroken` signals
/// arrive unencrypted, so any forwarder on the path can lower it. Below this
/// value the quantities derived from it degenerate: at a transport MTU of 137
/// or less, [`mss_ceiling`] saturates to a TCP MSS of zero, at 138 it is a
/// single byte, and the derived MSS stays under a hundred all the way to 236.
/// At the floor itself the derived inner IPv6 MTU is 179 and the TCP MSS is
/// 119, clear of both the zero cliff and that band.
///
/// A candidate below the floor is ignored — treated as no information at all,
/// never applied and never stored — rather than clamped, because clamping
/// would fabricate an estimate the node has no basis for. Locally derived link
/// MTUs are not subject to the floor; it applies only to values a remote party
/// supplied. A local value is exact, so the SYN-time clamp honours it however
/// small and refuses only the zero cliff, which no provenance makes usable.
pub const MIN_ACTIONABLE_PATH_MTU: u16 = 256;
/// Re-exported: the value is a protocol policy decision and is defined beside
/// the path-MTU state machine that owns it, in
/// [`crate::proto::mmp::MIN_ACTIONABLE_PATH_MTU`]. It is named from here
/// because every site that applies it — the MSS clamp, the lookup response and
/// the `MtuExceeded` signal — reaches it through this module.
pub use crate::proto::mmp::MIN_ACTIONABLE_PATH_MTU;
/// Calculate the effective IPv6 MTU for FIPS-encapsulated traffic.
///