AXPath
AXPath is a transport layer built on multiple parallel TCP subflows. It splits a logical connection into segments up to chunkSize, labels them with a connection-level Data Sequence Number (DSN, byte offset), and stripes them across subflows TCP connections. The receiver reorders by DSN and reassembles them into a continuous byte stream.
- Reliability: cumulative ACK (
dataAck) + SACK blocks (range list) + retransmission (with cross-subflow reinjection). - Tolerance: a single subflow drop does not break the logical connection; unacked chunks sent on that subflow are re-queued and retransmitted on remaining subflows.
- Resume: when all subflows are gone, the session can be resumed if new subflows attach within
resumeTimeoutMs; otherwise it closes. - Security:
streamSettings.securitysupports"none"/"tls"/"reality". With TLS/REALITY enabled, each subflow performs its own handshake.pskis only for HELLO authentication and does not replace TLS/REALITY.
AXPath is not backward compatible: both ends must run the same AXPath generation (same Xray build/version), otherwise the handshake will fail.
Configurations must be symmetric on both ends.
AXPathObject
AXPathObject corresponds to the axpathSettings item in transport configuration.
{
"subflows": 4,
"chunkSize": 32768,
"ackMaskBits": 1024,
"maxInflightBytes": 33554432,
"maxQueuePerFlow": 32,
"joinTimeoutMs": 16000,
"resumeTimeoutMs": 10000,
"reconnect": true,
"psk": ""
}2
3
4
5
6
7
8
9
10
11
subflows: number
Number of parallel TCP subflows. Valid range: 1-16 (values > 16 are clamped to 16). Default: 4.
chunkSize: number
Maximum data segment size in bytes. AXPath will split the byte stream into segments up to this size. Default: 32768.
ackMaskBits: number
SACK capacity in bits. Must be a multiple of 8.
Each SACK block costs 128 bits (start + end as uint64), so one ACK can carry about ackMaskBits/128 blocks (capped at 64). Default: 1024 (up to 8 blocks).
maxInflightBytes: number
Max unacked (in-flight) bytes per direction for backpressure and memory bound. When the limit is reached, the sender will stop sending until ACKs advance; if ACKs are blocked, a common symptom is "stuck at ~maxInflightBytes". Default: 33554432 (32 MiB).
maxQueuePerFlow: number
Max queued frames per subflow writer (data + control). Default: 32.
joinTimeoutMs: number
Client-side: how long to wait for at least one subflow to become ready during Dial (ms). Default: 16000.
resumeTimeoutMs: number
How long to keep an empty session (no subflows) for resuming (ms). Default: 10000.
reconnect: true | false
Client-side: whether to reconnect missing subflows automatically. Default: true.
psk: string
Optional PSK for HELLO authentication. Empty means disabled.
Tuning Tips
maxInflightBytes: increase on lossy/reordering or high-BDP paths; this increases memory usage.ackMaskBits: increase if you see heavy reordering so the receiver can report more SACK blocks.chunkSize: lowering it reduces retransmission granularity but increases overhead/CPU.subflows: more subflows may increase throughput but also increases TCP contention/unfairness; start with 2-4.
Debugging
- Stalls: look for
axpath: send window full(often means in-flight reachedmaxInflightBytesandlast_data_ackstops moving). - Disconnects: look for
axpath: subflow errorandaxpath: session closing(reason + state snapshot). - For developer debugging, see
testing/scenarios/AXPATH_DEBUG.mdin the Xray-core repository (1GiB loopback + fault injection).