CFG_NETWORK_MTU=1500 was baked blindly into the rootless daemon uplink (DOCKERD_ROOTLESS_ROOTLESSKIT_MTU) and every app's container network. On links whose real path MTU is below 1500 (Qubes/NAT/VPN with PMTU discovery blocked), image manifests + tiny images pull fine but large image LAYERS stall and reset mid-blob with "httpReadSeeker: ... EOF" — apps silently fail to install. Probed here: path MTU ~1328, Docker at 1500 → black hole. - New scripts/network/network_mtu.sh: networkDetectMtu (don't-fragment ICMP ladder → largest standard MTU that gets through, 1500 when ICMP gives no signal) + networkEffectiveMtu (CFG_NETWORK_MTU: a number is verbatim, "auto" probes once and caches $docker_dir/.network_mtu) + networkRedetectMtu. - CFG_NETWORK_MTU default 1500 -> auto. Rootless setup now writes the resolved MTU into the override (and re-detects per install); the per-app NETWORK_MTU_TAG uses the resolved value too. Explicit numbers still win. Verified on this box: auto -> 1300; alpine (multi-MB) + the full ~100MB navidrome image now pull to completion where they previously EOF'd. Applied live (override 1300, config=auto, cache=1300, rootless docker restarted). Signed-off-by: librelad <librelad@digitalangels.vip> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
69 lines
2.7 KiB
Bash
69 lines
2.7 KiB
Bash
#!/bin/bash
|
|
#
|
|
# Network MTU resolution.
|
|
# ---------------------------------------------------------------------------
|
|
# CFG_NETWORK_MTU drives BOTH the rootless daemon's uplink MTU
|
|
# (DOCKERD_ROOTLESS_ROOTLESSKIT_MTU — how image PULLS egress) and every app's
|
|
# container-network MTU (the NETWORK_MTU_TAG baked into each compose). A blind
|
|
# 1500 breaks on links whose real path MTU is lower (Qubes/NAT/VPN with PMTU
|
|
# discovery blocked): small transfers (image manifests, tiny images) succeed but
|
|
# large image-layer downloads stall and reset with "EOF" mid-blob.
|
|
#
|
|
# CFG_NETWORK_MTU accepts:
|
|
# <number> — use exactly (explicit override).
|
|
# auto — probe the path MTU once, cache a safe value (default).
|
|
#
|
|
# The probe is a don't-fragment ICMP ladder. If ICMP is fully filtered (no probe
|
|
# gets through at all) we can't tell a clean link from a constrained one, so we
|
|
# assume the standard 1500 rather than needlessly shrinking every network — set
|
|
# an explicit number for that case.
|
|
|
|
networkMtuCacheFile() { echo "${docker_dir%/}/.network_mtu"; }
|
|
|
|
# Largest standard MTU whose don't-fragment probe reaches the internet.
|
|
# Echoes a number; 1500 when no signal (ping missing / all probes filtered).
|
|
networkDetectMtu() {
|
|
local host="${1:-1.1.1.1}" m best=""
|
|
command -v ping >/dev/null 2>&1 || { echo 1500; return 0; }
|
|
for m in 1500 1492 1400 1300 1280; do
|
|
# payload = mtu - 28 (IPv4 + ICMP headers)
|
|
if ping -M do -s $((m - 28)) -c1 -W2 "$host" >/dev/null 2>&1; then
|
|
best="$m"; break
|
|
fi
|
|
done
|
|
echo "${best:-1500}"
|
|
}
|
|
|
|
# The concrete MTU to bake into the daemon + composes. Resolves CFG_NETWORK_MTU:
|
|
# a number is used verbatim; "auto"/empty is probed once and cached so we don't
|
|
# re-ping on every app install.
|
|
networkEffectiveMtu() {
|
|
local want="${CFG_NETWORK_MTU:-auto}"
|
|
if [[ "$want" =~ ^[0-9]+$ ]]; then echo "$want"; return 0; fi
|
|
|
|
local cache cached
|
|
cache="$(networkMtuCacheFile)"
|
|
cached="$(cat "$cache" 2>/dev/null | tr -dc '0-9')"
|
|
if [[ -n "$cached" ]]; then echo "$cached"; return 0; fi
|
|
|
|
local detected; detected="$(networkDetectMtu)"
|
|
if declare -F runInstallWrite >/dev/null 2>&1; then
|
|
printf '%s\n' "$detected" | runInstallWrite "$cache" 2>/dev/null || true
|
|
else
|
|
printf '%s\n' "$detected" > "$cache" 2>/dev/null || true
|
|
fi
|
|
echo "$detected"
|
|
}
|
|
|
|
# Force a fresh probe (clears the cache), echoing the new value. The rootless
|
|
# setup calls this so each (re)install re-detects the current link.
|
|
networkRedetectMtu() {
|
|
local cache; cache="$(networkMtuCacheFile)"
|
|
if declare -F runInstallOp >/dev/null 2>&1; then
|
|
runInstallOp rm -f "$cache" 2>/dev/null || true
|
|
else
|
|
rm -f "$cache" 2>/dev/null || true
|
|
fi
|
|
networkEffectiveMtu
|
|
}
|