tcp: register tcp.rcv_wnd_max and tcp.snd_mss_max as runtime-tunable sysctls - #46
Conversation
815fd47 to
85b2aec
Compare
The send-side MSS always tracked the egress interface MTU, with no way
to emit smaller segments while still advertising a large receive MSS.
Overlay/tunnel deployments whose host->peer path MTU is below the local
interface MTU need exactly that asymmetry (and classical PMTUD cannot
discover the smaller hop when it sits past a relay that drops ICMP PTB).
Expose it as a registered sysctl, consistent with the existing
'tcp.base_mss' / 'tcp.mtu_probing' knobs:
* 'tcp.snd_mss_max' (per-interface, like 'tcp.base_mss') — default 0
(uncapped); a non-zero value clamps '_mss_ceiling()' last, bounding
the segments we EMIT without lowering the advertised receive MSS.
Floor 88 (Linux 'TCP_MIN_MSS'); 0 reserved for "off".
It rides the 'sysctls={...}' bag in 'stack.init()'; it does not warrant
an explicit kwarg yet.
Tests at tests/integration/protocols/tcp/test__tcp__sysctls.py pin
registration, the default, validator rejection (0-or->=88) and the
per-interface storage semantics; test__tcp__session__throughput_knobs.py
pins the session behaviour (the cap bounds '_mss_ceiling' while leaving
'rcv_mss' at the interface ceiling).
The originally proposed companion knob 'tcp.rcv_wnd_max' is dropped as
superseded: 3.0.8 shipped the same capability by the Linux-faithful
route — 'tcp.rmem' (min/default/max) plus SO_RCVBUF seeding
'WindowState.rcv_wnd_max', with receive-buffer Dynamic Right-Sizing
growing it and the WSCALE shift sized for 'tcp.rmem.max' at SYN.
Reference: Linux include/net/tcp.h TCP_MIN_MSS=88.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HzQ7Jyy9os1WhyPuFJezJU
ccie18643
left a comment
There was a problem hiding this comment.
Thanks for this, and apologies for the slow review.
Landing the tcp.snd_mss_max half. The motivating case is real and there is
no other way to express it today: _mss_ceiling() tracked the egress
interface MTU with no way to bound emitted segments independently of the
advertised receive MSS, and classical PMTUD cannot discover a smaller hop
sitting behind a relay that drops ICMP PTB.
Dropping the tcp.rcv_wnd_max half as superseded. 3.0.8 shipped the same
capability by the Linux-faithful route: tcp.rmem (min/default/max) plus
SO_RCVBUF seeding WindowState.rcv_wnd_max, receive-buffer Dynamic
Right-Sizing growing it, and the WSCALE shift sized from tcp.rmem.max at
SYN. Keeping the static 65535 seed would have regressed that.
Two mechanical fixes on rebase: the PR was opened against master, which is
still the 2.7.10 line, so I retargeted it to the active PyTCP_3_0_10 dev
branch; and pytcp.socket.tcp__socket moved to
pytcp.runtime.socket.tcp__socket in the directory restructure.
Your authorship is preserved on the commit. make lint clean, 13,862 tests
green (+7 from your new cases).
85b2aec to
1e7b9c9
Compare
…audit The knob landed with PR #46 (commit 1e7b9c9) and is applied inside '_mss_ceiling()', the helper this record already documents as the PLPMTUD cold-start seed. The adherence record is updated in lockstep so the operator-facing surface of that helper stays fully described: the cap clamps the emitted MSS last, independently of the advertised receive MSS, and is inert at its 0 default so no RFC 4821 behaviour changes. Reference: RFC 4821 §7.2 (per-protocol operator override). Reference: Linux include/net/tcp.h TCP_MIN_MSS=88. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HzQ7Jyy9os1WhyPuFJezJU
Two TCP policy values were effectively hard-coded, forcing applications that embed PyTCP to monkeypatch internals to tune throughput on fast or asymmetric paths:
The advertised receive-window ceiling was fixed at 65535 bytes (WindowState.rcv_wnd_max). A bulk inbound transfer is bound by window / RTT, so on a high bandwidth-delay-product path (fast link, tunnel) 64 KiB throttles the peer far below the link rate even though PyTCP already negotiates RFC 7323 window scaling.
The send-side MSS always tracked the egress interface MTU, with no way to emit smaller segments while still advertising a large receive MSS. Overlay/tunnel deployments whose host->peer path MTU is below the local interface MTU need exactly that asymmetry (and classical PMTUD cannot discover the smaller hop when it sits past a relay that drops ICMP PTB).
Expose both as registered sysctls, consistent with the existing 'tcp.base_mss' / 'tcp.mtu_probing' knobs:
'tcp.rcv_wnd_max' (flat; Linux net.ipv4.tcp_rmem parity) — default 65535, seeded into WindowState.rcv_wnd_max at session creation, so behaviour is unchanged until an operator raises it.
'tcp.snd_mss_max' (per-interface, like 'tcp.base_mss') — default 0 (uncapped); a non-zero value clamps _mss_ceiling() last, bounding the segments we EMIT without lowering the advertised receive MSS. Floor 88 (Linux TCP_MIN_MSS); 0 reserved for "off".
Both ride the 'sysctls={...}' bag in stack.init(); neither warrants an explicit kwarg yet.
Tests at tests/integration/protocols/tcp/test__tcp__sysctls.py pin registration, defaults, validator rejection (rcv_wnd_max != 0; snd_mss_max 0-or->=88) and the per-interface storage semantics; test__tcp__session__throughput_knobs.py pins the session behaviour (rcv_wnd_max seeds the window; snd_mss_max caps _mss_ceiling while leaving rcv_mss at the interface ceiling).
Reference: Linux net.ipv4.tcp_rmem (receive-window max).
Reference: Linux include/net/tcp.h TCP_MIN_MSS=88.