Skip to content

Fix SGLang disagg on ionic/RoCE fabrics (AINIC transport env)#2

Merged
mkuznet1 merged 2 commits into
mkuznet1:aicomnet_dev_publicfrom
i-kosarev:workload2-sglang-r1-ionic-fixes
Jul 7, 2026
Merged

Fix SGLang disagg on ionic/RoCE fabrics (AINIC transport env)#2
mkuznet1 merged 2 commits into
mkuznet1:aicomnet_dev_publicfrom
i-kosarev:workload2-sglang-r1-ionic-fixes

Conversation

@i-kosarev

Copy link
Copy Markdown

Summary

Minimal fix (analogous to #1) enabling the SGLang disaggregated-serving workload
to run on ionic-based RoCE clusters such as mia1.

$MOONCAKE_COOKBOOK_PATH/set_env_vars.sh assumes a Mellanox/mlx5 fabric. On
ionic clusters it corrupts the transport environment three ways:

  1. forces NCCL_IB_DISABLE=1 (kills RDMA entirely),
  2. hardcodes mlx5 IB device names (wrong devices → no IB),
  3. mangles NCCL_SOCKET_IFNAME via an ip route awk parse.

The fix saves the launcher-provided NCCL_SOCKET_IFNAME before sourcing, then
re-asserts the ionic-correct values afterward: NCCL_IB_DISABLE=0, IBDEVICES
from IB_DEVICES, and NCCL/GLOO socket ifnames. host_ip is also derived from
the actual transport interface instead of the first hostname -I address (which
on multi-homed nodes may be the wrong NIC).

Single file, single hunk: scripts/sglang_disagg/sglang_disagg_server.sh.

Validation

Validated on mia1 (SLURM job 11211):

  • DeepSeek-R1-0528, 1 prefill + 1 decode + proxy disagg, TP=8, Mooncake KV
  • RCCL 78e8ba0 overlay + AINIC (ionic RDMA) transport confirmed in NCCL logs
  • Both servers fired up, sglang_router bound on port 2322
  • Full benchmark sweep, 100% request success:
ISL/OSL con8 con16 con32 (total_token_throughput tok/s)
1024/1024 154.47 309.46 630.84
8192/1024 704.67 1361.27 2712.20

Notes / prerequisites

On gfx950 (MI355X) this workload also requires the kernel + runtime work from the
private stack #341 (gfx950 kernel overlay) and #342 (runtime kernel guards +
Mooncake P/D default). This PR is orthogonal — it is the fabric/transport fix
needed on ionic RoCE clusters regardless of GPU arch.

Test plan

  • SGLang R1 disagg comes up and serves on mia1 (ionic RoCE)
  • NCCL logs show IB/ionic transport (RDMA engaged, not disabled)
  • Full benchmark sweep completes with perf CSV captured

MOONCAKE_COOKBOOK's set_env_vars.sh assumes a Mellanox/mlx5 fabric and, on
ionic-based RoCE clusters (mia1), disables RDMA (NCCL_IB_DISABLE=1), hardcodes
mlx5 device names, and mangles NCCL_SOCKET_IFNAME. Save the launcher-provided
transport iface before sourcing, then re-assert NCCL_IB_DISABLE=0, IBDEVICES
from IB_DEVICES, and NCCL/GLOO socket ifnames afterward. Also derive host_ip
from the transport interface instead of the first hostname -I address.

Validated on mia1 (DeepSeek-R1-0528, 1P+1D disagg, TP=8, RCCL 78e8ba0 overlay +
AINIC ionic RDMA), SLURM job 11211: both servers fired up, router bound on 2322,
full benchmark sweep 100% request success.

Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
Comment on lines +52 to +62
# Derive host_ip from the actual transport interface rather than the first
# `hostname -I` address (which on multi-homed nodes may be the wrong NIC).
_XPORT_IFACE="${_SAVED_NCCL_SOCKET_IFNAME%%,*}"
host_ip=""
if [[ -n "$_XPORT_IFACE" ]]; then
host_ip=$(ip -4 -o addr show "$_XPORT_IFACE" 2>/dev/null | awk '{print $4}' | cut -d/ -f1 | head -n1)
fi
[[ -z "$host_ip" ]] && host_ip=$(ip route get 1.1.1.1 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i=="src"){print $(i+1); exit}}')
[[ -z "$host_ip" ]] && host_ip=$(hostname -I | awk '{print $1}')
host_name=$(hostname)
unset _SAVED_NCCL_SOCKET_IFNAME _XPORT_IFACE

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reuse the IP that's already resolved upstream instead of re-deriving it here.

run.sh already resolves this node's IP (same iface → hostname -I logic) and hands us the rank-ordered, post-rendezvous node list via IPADDRS, and NODE_RANK is known here. So this node's IP is simply IPADDRS[NODE_RANK] — no second ip addr / ip route / hostname -I pass is needed.

More important than the dedup: host_ip feeds --host and socket_barrier --local-ip, which must match what peers registered for this node in the router/barrier (both are built from IPADDRS). An independent re-derivation can resolve to a different NIC on a multi-homed node and desync the two — the server binds/advertises one address while the router looks for another. Sourcing it from IPADDRS[NODE_RANK] keeps them consistent by construction.

The RDMA/socket env re-assert above (NCCL_IB_DISABLE / IBDEVICES / *_SOCKET_IFNAME) is the actual ionic fix and stays as-is.

Suggested change
# Derive host_ip from the actual transport interface rather than the first
# `hostname -I` address (which on multi-homed nodes may be the wrong NIC).
_XPORT_IFACE="${_SAVED_NCCL_SOCKET_IFNAME%%,*}"
host_ip=""
if [[ -n "$_XPORT_IFACE" ]]; then
host_ip=$(ip -4 -o addr show "$_XPORT_IFACE" 2>/dev/null | awk '{print $4}' | cut -d/ -f1 | head -n1)
fi
[[ -z "$host_ip" ]] && host_ip=$(ip route get 1.1.1.1 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i=="src"){print $(i+1); exit}}')
[[ -z "$host_ip" ]] && host_ip=$(hostname -I | awk '{print $1}')
host_name=$(hostname)
unset _SAVED_NCCL_SOCKET_IFNAME _XPORT_IFACE
# This node's IP is already resolved by run.sh and handed to us (rank-ordered,
# post-rendezvous) via IPADDRS. Reuse IPADDRS[NODE_RANK] so the address we bind
# and advertise (--host, socket_barrier --local-ip) matches exactly what peers
# registered for us in the router/barrier; re-deriving it here can pick a
# different NIC on multi-homed nodes and desync the two.
IFS=',' read -ra IP_ARRAY <<< "$IPADDRS"
host_ip="${IP_ARRAY[NODE_RANK]:-$(hostname -I | awk '{print $1}')}"
host_name=$(hostname)
unset _SAVED_NCCL_SOCKET_IFNAME

Note: the Cluster Topology section further down re-parses IP_ARRAY from IPADDRS; with the read moved up that later read becomes redundant (harmless) and can be dropped in a follow-up.

Validated the equivalent change on an AINIC/ionic node.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To fully match the validated test commit, one more spot: after the suggestion above lands, the Cluster Topology section still parses the array again:

-IFS=',' read -ra IP_ARRAY <<< "$IPADDRS"
+# IP_ARRAY was already parsed from IPADDRS above (where host_ip is derived).

The suggestion above introduces an earlier IFS=',' read -ra IP_ARRAY <<< "$IPADDRS" next to host_ip, so this later read becomes redundant (harmless, but dead). The test commit replaces it with the one-line breadcrumb above.

I couldn't post this as a one-click suggestion: that line isn't part of this PR's diff (it's unchanged, and only turns redundant once the host_ip change is applied), so GitHub rejects a review comment anchored there.

Re-deriving the node IP via ip addr/hostname -I risks picking a different
NIC on multi-homed nodes, causing a mismatch between what peers registered
in the router/barrier (built from IPADDRS) and what --host /
socket_barrier --local-ip binds to.

Source host_ip from IPADDRS[NODE_RANK] instead — the rank-ordered,
post-rendezvous list that run.sh already resolved and passed in. Keep
a hostname -I fallback for environments where IPADDRS is unset.

Remove the now-redundant IFS/read of IP_ARRAY in the Cluster Topology
section; the array is already populated at host_ip derivation time.

Suggested-by: mkuznet1
Co-Authored-By: Claude Sonnet 4 <noreply@anthropic.com>
@mkuznet1
mkuznet1 merged commit 112b524 into mkuznet1:aicomnet_dev_public Jul 7, 2026
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.

2 participants