mirror of
https://github.com/kvcache-ai/Mooncake.git
synced 2026-11-05 01:17:55 +00:00
[GH-ISSUE #2724] [TE] Cross-node RDMA KV transfer SIGSEGVs on AMD under rdma+hip multi-protocol registration #714
Labels
No labels
ascend
auto-closed
bug
bug
CI/Build
Common
documentation
enhancement
feature request
good first issue
help wanted
high priority
MetaX
nightly-failure
pull-request
PyTorch Backend
question
RFC
Roadmap
stale
Store
Tests
Transfer Engine
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
kvcache-ai/Mooncake#714
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @Lzy17 on GitHub (Jul 2, 2026).
Original GitHub issue: https://github.com/kvcache-ai/Mooncake/issues/2724
Environment
01d1eb2a(#2682, "Support rdma+hip multi-protocol segments").fabrics: Broadcom
bnxt_re(flat L2) andionic(routed L3).nodes, GPU KV cache transferred cross-node over RDMA.
hipprotocol isregistered for intra-node GPU-IPC,
rdmafor cross-node — the normaldisaggregated-inference setup.
USE_HIP=ON,ENABLE_MULTI_PROTOCOL=ON.Symptom
Cross-node KV transfer of GPU memory crashes with SIGSEGV during the RDMA
submit path, whenever the same GPU buffer is registered under both
hipandrdma. Single-protocol rdma-only deployments are unaffected.Two related failure modes depending on which sub-bug fires first:
RdmaTransport::submitTransferTask→ SIGSEGV atslice->rdma.source_lkey = local_segment_desc->buffers[buffer_id].lkey[device_id];(
rdma_transport.cpp) — out-of-bounds read on an emptylkeyvector.the
hiptransport and fails withhipIpcOpenMemHandle failed(hip isintra-node GPU-IPC only).
The
assert(lkey.size() == context_list_.size())that would have caught (1) iscompiled out in Release builds, so it surfaces as a bare segfault.
Root cause
With multi-protocol registration, a single GPU address ends up with two
buffer descriptors at the same address range:
hiptwin — uses IPC handles /shm_name, carries nolkey/rkey(the
hipmetadata (de)serialization intentionally omits them);rdmatwin — the valid RDMA registration, with a populatedlkey.Single-protocol rdma-only deployments only ever have the second one, so every
lookup is correct. #2682 enabled the dual registration, which is the first time
the RDMA data path is handed two twins at one address — and it does not
disambiguate. This surfaces three independent latent issues:
selectDevice()/selectDeviceByLocalHca()are protocol-blind(
rdma_transport.cpp). They scan the segment's buffers by address rangeonly and return the first match. Because the
hiptwin aliases the sameaddress, they return the
hipbuffer, whoselkeyvector is empty → theOOB read above. (root cause of the crash)
selectTransport()hardcodeshippriority aboverdma(
multi_transport.cpp). For a comma-joined multi-protocol segment thepriority table has
hip(4) >rdma(2), so a cross-node request selectsthe intra-node-only
hiptransport →hipIpcOpenMemHandle failed.USE_HIP_DMABUFdefine never reachesrdma_context.cpp(
src/CMakeLists.txt). The define is appliedPRIVATEto thetransfer_enginetarget, but the dmabuf MR-registration code lives inrdma_context.cpp, compiled in the separaterdma_transportOBJECT library(linked via
$<TARGET_OBJECTS:transport>). The define therefore neverreaches that code, the dmabuf path is silently compiled out, and GPU MRs
fall back to plain
ibv_reg_mr→EINVALon device memory.Diagnosis detail
A dump of the local segment at the crash confirms the dual registration:
proto=hip,lkey.size=0proto=rdma,lkey.size=1— the valid RDMA twins of thesame GPU addresses.
selectDevicereturns buffer id 0 (hip, empty lkey) →.lkey[0]on an emptyvector → SIGSEGV.
Scope / who is affected
deployments are unaffected (they never have a competing hip twin), which is
why this went unnoticed after #2682 merged.
Fix
See the accompanying PR. Three minimal, gated changes:
selectDevice/selectDeviceByLocalHca, underENABLE_MULTI_PROTOCOL,skip any buffer whose protocol is set and is not
rdma(guarded with!protocol.empty()so legacy single-protocol descriptors are untouched).hiptransport priority to be de-prioritized viaMC_DISABLE_HIPfordeployments that need the cross-node RDMA path (default behavior unchanged).
USE_HIP_DMABUF(and thehsa-runtime64usage requirements) to therdma_transporttarget that actually compilesrdma_context.cpp.Validation
/generateSIGSEGVs during KV transfer./generatecorrect; concurrency sweep(1/8/32/64) 100% success, zero QP/transfer failures, zero SIGSEGV. Validated
on both
bnxt_reandionicfabrics.ENABLE_MULTI_PROTOCOL=OFF) runs the same workloadunaffected, confirming the bug is specific to multi-protocol dual
registration.
Note for routed-RoCE (L3) fabrics
On routed fabrics (e.g. ionic, NICs on point-to-point
/31subnets) thedeployment must also select a routable GID (RoCEv2 IPv4 GID, e.g.
MC_GID_INDEX=1); otherwise the QP falls back to a link-local GID and the RTRhandshake times out. This is deployment config, not part of the fix, but worth
documenting for AMD multi-node users.
@github-actions[bot] commented on GitHub (Jul 2, 2026):
Thanks for opening this issue, @Lzy17!
36555117A maintainer will triage this when possible. To help us respond faster, please include:
Useful links: Documentation · Contributing guide