Skip to content

Support Multipath TCP on Linux - #1759

Open
xroche wants to merge 4 commits into
masterfrom
mptcp-ready
Open

xroche wants to merge 4 commits into
masterfrom
mptcp-ready

Conversation

@xroche

@xroche xroche commented Sep 23, 2026

Copy link
Copy Markdown
Owner

--mptcp routes every outgoing connection through one socket factory, which asks the kernel for Multipath TCP and falls back to plain TCP. It is on by default only where two net.mptcp sysctls say the kernel can escape a blackholed SYN by itself.

xroche and others added 3 commits September 23, 2026 13:23
… be used

Outgoing connections went through five separate socket() calls, each hard-coding
protocol 0. One factory, hts_socket_client(), now owns that choice and takes
IPPROTO_MPTCP where the run asked for it. Two FTP data sockets pick up
socket_set_nosigpipe() on the way, which they never had.

--mptcp turns it on, --mptcp=0 off. Unset means on where the kernel exposes
net.mptcp.blackhole_timeout and net.mptcp.syn_retrans_before_tcp_fallback:
without those a middlebox that drops the SYN carrying the MPTCP option costs the
whole connect timeout on every host behind it, so the user has to ask.

Reporting goes through MPTCP_INFO, which is refused on a socket the kernel fell
back to plain TCP. SO_PROTOCOL cannot answer that question: it reads
IPPROTO_MPTCP either way, measured on both a negotiated and a fallen-back
loopback connection.

The accounting first counted an HTTPS connection twice, because a finished TLS
handshake sends the slot back through the connect path. One single-file crawl
reported four connections where it had made one.

macOS has MPTCP behind connectx() on an AF_MULTIPATH socket, which is a
different connect call rather than a different protocol argument, so it is not
wired here.

Signed-off-by: Xavier Roche <xroche@gmail.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>
…t could see

The default read only whether two sysctls exist. blackhole_timeout is a number,
and zero means the kernel's blackhole detection is off, so the file being there
never answered the question. Read both values instead.

The capability macro had two sources: configure's AC_CHECK_DECLS and a
defined(IPPROTO_MPTCP) test in the installed htsnet.h. configure now owns it and
puts HTS_INET_MPTCP in config.h, which keeps it out of htsfeatures.h, where only
switches that move an installed struct belong. --enable-mptcp joins the other
optional features, so --disable-auto-features reaches it, and it gates on
host_os first the way --enable-backtrace does, or an explicit ask would fail the
build on GNU/Hurd. Tests 397 and debian/rules want every feature named.

Two mutants survived every test. Accounting once per mirror rather than once per
connection read the same, because each crawl leg only required a non-zero count.
Nothing exercised the unset option at all. Both now have a leg, and the crawls
that count run with keep-alive off so more than one connection is on the line.

The self-test skipped by returning 0, which reads as a pass, and it asserted
MPTCP was negotiated on a build whose headers cannot report that. It returns 77
like its siblings, and gates on the new mptcpinfo feature.

Dropped: an AF_INET6 retry, a probed flag, and two NULL checks no caller can
reach. The counters cover the HTTP backend only, which the field docs now say.

Signed-off-by: Xavier Roche <xroche@gmail.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>
The last leg crawls over HTTPS, so "build (no openssl, --disable-https)" red on
it. Its neighbours skip such a leg on HTTPS_SUPPORT, and that loses one leg
rather than the whole test, so the other five still run there.

Caught by CI and not locally, because the default build has OpenSSL. Rechecked
against a --disable-https build, where the test passes, and against
--disable-auto-features, where HTS_INET_MPTCP is 0, the test skips, and 397 and
398 both pass.

Signed-off-by: Xavier Roche <xroche@gmail.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>
@xroche xroche changed the title Every connection opens a plain TCP socket, so Multipath TCP can never be used Support Multipath TCP on Linux Sep 23, 2026
A front end polls hts_get_stats(), so a counter that only reaches the log is a
counter no GUI can show. stat_transport_failures is the shape to copy: live on
opt, published into hts_stat_struct at both the mirror-end and the on-demand
site. The two Multipath TCP counts now go the same way.

Both fields are appended at the tail of hts_stat_struct, so the soname holds.
The direction that breaks is a front end built against the new header running
against an older engine, which is the usual rebuild-after-merge.

-#test=mptcpstats covers it, and runs everywhere because none of it needs a
kernel with Multipath TCP: the counters reach the stats, copy_htsopt carries the
option but never the counts, and an unset option leaves a set one alone.

Signed-off-by: Xavier Roche <xroche@gmail.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant