Skip to content

HiCAIN System Topology

1. Overview

The Cnuas Virtual AI HPC Infrastructure is a layered, 100% software-emulated data center stack. Five components cooperate at three planes:

Plane Component Role
Host userspace daemons hicain-vswitchd (HiSwitch) RoCE/IB fabric switch
higpu-link-switchd (HiLink) GPU-to-GPU interconnect (NVSwitch-equivalent)
QEMU device models hicain_vnic Virtual RoCE-IB NIC PCIe device
higpu Virtual GPU PCIe device
Guest Kernel modules + libhicain-rdmav34.so provider + libhicart.so runtime Verbs and runtime exposed to applications

Two independent fabrics carry distinct kinds of traffic:

  • The HiSwitch fabric carries every Ethernet frame including RoCEv2 (UDP/4791) RDMA traffic. This is the data network and is what ibv_rc_pingpong / perftest / NCCL's IB transport flow over.
  • The HiLink fabric is independent. It carries only HiGPU ↔ HiGPU peer traffic, the equivalent of NVIDIA NVLink. A VM with a HiGPU but no HiNIC can still do GPU-to-GPU; a VM with HiNIC but no HiGPU never touches HiLink.

A real VM typically has both (-device hicain-vnic ... -device higpu ...) and therefore wires into both daemons via separate UNIX-domain sockets.

2. Physical Rack Reference (OCP Open Rack v3)

HiCAIN's physical-equivalent model is the Open Compute Project Open Rack v3 (ORv3), the 2023+ revision used by every major hyperscaler for AI/HPC builds (Meta, Microsoft Azure Maia, Google's TPU pods, NVIDIA HGX/B200 reference designs). ORv3 is not just a deeper EIA-310 rack; it's a different rack with different mechanical, electrical, and serviceability properties:

ORv3 property Value Why it matters for HiCAIN
Rack-unit height (OU) 48 mm (vs 44.5 mm for 19″ U) All our rack diagrams are sized in OU
Equipment bay width 21″ (537 mm), 20 % wider than 19″ Gives room for 8x GPU sleds + dual-NIC headers
Power 48 V DC busbars at the rear, fed by a power shelf Hot-pluggable PSUs; no per-server AC inlets
Servicing Front-only; cables and connectors on the cold aisle Switch + GPU + compute all share the cold-aisle service model
Modular zones power / equipment / cable Maps 1:1 to our TOR-row / blade-rows / cable-bay layout

Why ORv3 and not ORv2? ORv2 (2014) targeted general-purpose cloud workloads; ORv3 (2023) is the rack the AI buildout was designed around, wider 21″ bays, denser busbars, and explicit support for top-of-rack accelerator-optimised switches like the ones HiSwitch + HiLink emulate. An ORv2-style 19″ rack would not fit the dual-fabric (RoCE TOR + GPU peer switch) header we ship one rack-unit apart in every HiCAIN rack.

2.1 Component-to-ORv3 Slot Mapping

ORv3 slot (top-down) HiCAIN component OU height Function
1OU hicain-vswitchd (HiSwitch TOR) 1 RoCEv2 + InfiniBand fabric, 10 ports, DCB
1OU higpu-link-switchd (HiLink spine) 1 GPU peer fabric, 8 ports, NVSwitch-equivalent
1OU Management host 1 Bare-metal Ubuntu; runs the two daemons + real GPU
8x 2OU VM "blades" (QEMU guests) 16 Each carries HiNIC + HiGPU + the full guest stack
4OU Cable management 4 UDS files in /var/run/hicain/ and /var/run/hilink/
2OU Power shelf (1+1 redundant PSUs) 2 48 V DC to rear busbar
Total 24 OU Half-height ORv3 rack; ORv3 racks ship in 41 OU and 44 OU heights

In the emulator the "U-height" is purely visual, components are processes and .qcow2 images, not metal, but the mapping makes it easy to point at a real ORv3 photo and explain what each HiCAIN process would be if it were physical.

2.2 Single Rack (front view)

This is the basic deployment: one rack, two switches at the top (HiSwitch + HiLink), one management host, eight VM slots, power at the bottom.

HiCAIN single rack, front view

Green LED = active, grey LED = idle. Blue port stubs are the RoCE/IB fabric; pink port stubs are the HiLink GPU fabric. Every "cable" you see is a SOCK_SEQPACKET UNIX-domain socket on the host, the emulator preserves every interface and connector you'd find in a real ORv3 rack, just transported over UDS instead of copper/fibre.

2.3 Two Racks Aggregated

Scale-out: two ORv3 racks adjacent in a hot-aisle / cold-aisle row, peered via a single yellow inter-TOR cable. HiLink stays rack-local (NVSwitch domains do not span racks); cross-rack GPU traffic falls back to RoCEv2 through the two TORs, the same path NCCL would take in a real cluster.

HiCAIN two racks, front view

The wire-level mechanics of the inter-TOR link (FDB learning via gratuitous ARP, IB Subnet-Administration traffic, etc.) are covered in HiCAIN Virtual Switch Design §1.2.

2.4 Logical View (same topology, no chassis)

If you want to look past the rack and just see who talks to whom, this is the same two-rack layout as a labelled flowchart.

flowchart LR subgraph RACK_A["Rack A (ORv3, 24 OU)"] direction TB TOR_A["hicain-vswitchd A<br/>(HiSwitch TOR)"] LINK_A["higpu-link-switchd A<br/>(HiLink, rack-local)"] VMA0["vm-a0"] --- TOR_A VMA1["vm-a1"] --- TOR_A VMA2["vm-a2"] --- TOR_A VMA0 -. GPU peer .- LINK_A VMA1 -. GPU peer .- LINK_A VMA2 -. GPU peer .- LINK_A end subgraph RACK_B["Rack B (ORv3, 24 OU)"] direction TB TOR_B["hicain-vswitchd B<br/>(HiSwitch TOR)"] LINK_B["higpu-link-switchd B<br/>(HiLink, rack-local)"] VMB0["vm-b0"] --- TOR_B VMB1["vm-b1"] --- TOR_B VMB2["vm-b2"] --- TOR_B VMB0 -. GPU peer .- LINK_B VMB1 -. GPU peer .- LINK_B VMB2 -. GPU peer .- LINK_B end TOR_A ===|inter-TOR fabric link| TOR_B classDef tor fill:#dbeafe,stroke:#1e40af,color:#1e3a8a classDef link fill:#fce7f3,stroke:#9d174d,color:#831843 classDef vm fill:#fef3c7,stroke:#b45309,color:#78350f class TOR_A,TOR_B tor class LINK_A,LINK_B link class VMA0,VMA1,VMA2,VMB0,VMB1,VMB2 vm

Note the dotted lines: HiLink connections never leave the rack.

3. Host-Level Topology

This is the canonical two-VM development layout used by the tests/test_rocev2_e2e.py gate.

flowchart TB subgraph HOST["HOST &mdash; hicain1 (bare-metal, Ubuntu 24.04)"] direction TB subgraph DAEMONS["Userspace daemons"] direction LR HISWITCH["hicain-vswitchd<br/>(HiSwitch)<br/>10 SEQPACKET ports<br/>FDB + classifier + DCB<br/>/var/run/hicain/"] HILINK["higpu-link-switchd<br/>(HiLink)<br/>8 SEQPACKET ports<br/>NVSwitch-equivalent<br/>/var/run/hilink/"] end subgraph VMA["QEMU vm-a"] direction TB VMA_NIC["-device hicain-vnic<br/>(RoCE-IB NIC)"] VMA_GPU["-device higpu<br/>(GPU + HiLink endpoint)"] VMA_KMOD["Guest kernel:<br/>hicain_net.ko + hicain_ib.ko<br/>higpu.ko"] VMA_USR["Guest userspace:<br/>libhicain-rdmav34.so<br/>libhicart.so<br/>perftest / pingpong / apps"] VMA_NIC --- VMA_KMOD VMA_GPU --- VMA_KMOD VMA_KMOD --- VMA_USR end subgraph VMB["QEMU vm-b"] direction TB VMB_NIC["-device hicain-vnic"] VMB_GPU["-device higpu"] VMB_KMOD["Guest kernel:<br/>hicain_net.ko + hicain_ib.ko<br/>higpu.ko"] VMB_USR["Guest userspace:<br/>libhicain-rdmav34.so<br/>libhicart.so<br/>perftest / pingpong / apps"] VMB_NIC --- VMB_KMOD VMB_GPU --- VMB_KMOD VMB_KMOD --- VMB_USR end HISWITCH ===|UDS port_0| VMA_NIC HISWITCH ===|UDS port_1| VMB_NIC HILINK -.->|UDS port_0| VMA_GPU HILINK -.->|UDS port_1| VMB_GPU end classDef daemon fill:#dbeafe,stroke:#1e40af,color:#1e3a8a classDef vm fill:#fef3c7,stroke:#b45309,color:#78350f classDef nic fill:#dcfce7,stroke:#166534,color:#14532d classDef gpu fill:#fce7f3,stroke:#9d174d,color:#831843 class HISWITCH,HILINK daemon class VMA,VMB vm class VMA_NIC,VMB_NIC nic class VMA_GPU,VMB_GPU gpu

Legend. Solid lines (===) carry RoCE/IB traffic over the HiSwitch fabric. Dotted lines (-.->) carry GPU-to-GPU traffic over the HiLink fabric. Each connection is a SOCK_SEQPACKET UDS between the QEMU device backend and the corresponding switch daemon.

4. Per-VM Internal Topology

Inside a single VM, the kernel and userspace stack stratifies as follows. The arrows show call direction, not data direction (RDMA data motion is reflected by what each verb does, not by the ABI boundary).

flowchart TB subgraph VM["VM &mdash; vm-a (Ubuntu 24.04 guest)"] direction TB subgraph APP["Application layer"] direction LR APP_NCCL["NCCL (host only*)"] APP_PERF["perftest, pingpong"] APP_USER["user code:<br/>MPI / libfabric / etc."] end subgraph LIB["Userspace libraries"] direction LR LIB_VERBS["libibverbs.so.1<br/>(stock rdma-core v50)"] LIB_PROV["libhicain-rdmav34.so<br/>(our provider,<br/>dlopen()'d by libibverbs)"] LIB_CART["libhicart.so<br/>(HiGPU runtime,<br/>CUDA-like API)"] end subgraph KMOD["Guest kernel modules"] direction LR KMOD_NET["hicain_net.ko<br/>netdev driver"] KMOD_IB["hicain_ib.ko<br/>IB-core RDMA driver"] KMOD_GPU["higpu.ko<br/>GPU char driver<br/>/dev/higpu0"] end subgraph QEMU["QEMU device backends"] direction LR QEMU_NIC["hicain_vnic.c<br/>PCIe + MMIO + IRQ<br/>UDS to HiSwitch"] QEMU_GPU["higpu PCI device<br/>+ HiLink endpoint<br/>UDS to HiLink"] end APP_NCCL --> LIB_VERBS APP_PERF --> LIB_VERBS APP_USER --> LIB_VERBS APP_USER --> LIB_CART LIB_VERBS --> LIB_PROV LIB_PROV --> KMOD_IB LIB_VERBS --> KMOD_IB LIB_CART --> KMOD_GPU KMOD_IB --> KMOD_NET KMOD_NET --> QEMU_NIC KMOD_GPU --> QEMU_GPU end classDef app fill:#fee2e2,stroke:#b91c1c,color:#7f1d1d classDef lib fill:#e0e7ff,stroke:#3730a3,color:#1e1b4b classDef kmod fill:#fef3c7,stroke:#92400e,color:#78350f classDef qemu fill:#dcfce7,stroke:#166534,color:#14532d class APP_NCCL,APP_PERF,APP_USER app class LIB_VERBS,LIB_PROV,LIB_CART lib class KMOD_NET,KMOD_IB,KMOD_GPU kmod class QEMU_NIC,QEMU_GPU qemu

* NCCL runs only on the host today, not in VMs, the guests have no CUDA driver and no CUDA-capable PCI device. Pulling NCCL into the guest is tracked by the hinic-nccl L2/L3 backlog and requires either GPU passthrough into the VM or our patched kernel loaded on the bare-metal host.

4.1 ABI Boundaries

Boundary Direction Mechanism
App ↔ libibverbs function calls C ABI, stock rdma-core
libibverbs ↔ libhicain provider function-pointer table (verbs_context_ops) resolved at dlopen time when driver_id == RDMA_DRIVER_HICAIN
libibverbs ↔ kernel ioctl on /dev/infiniband/uverbsN uverbs cmd mask + UAPI structs
kernel verbs ↔ hicain_ib.ko function-pointer table (struct ib_device_ops) resolved at ib_register_device()
hicain_ib.kohicain_net.ko per-frame notifier chain + dev_queue_xmit RoCEv2 framing happens here
hicain_net.ko ↔ QEMU hicain_vnic MMIO BAR + IRQ doorbell virtio-like rings on a memory window
QEMU hicain_vnic ↔ HiSwitch SOCK_SEQPACKET UDS one connection per port
App ↔ libhicart.so function calls C ABI
libhicart.sohigpu.ko ioctl on /dev/higpu0 custom UAPI
higpu.ko ↔ QEMU higpu MMIO BAR + IRQ command/completion rings
QEMU higpu ↔ HiLink SOCK_SEQPACKET UDS one connection per port

5. Fabric Walks

5.1 RoCEv2 frame end-to-end (vm-a → vm-b)

This is what ibv_rc_pingpong and the e2e gate exercise.

sequenceDiagram autonumber participant App_A as App (vm-a) participant Prov_A as libhicain<br/>(vm-a) participant Kern_A as hicain_ib +<br/>hicain_net (vm-a) participant QEMU_A as QEMU vnic<br/>(host) participant HiSw as hicain-vswitchd participant QEMU_B as QEMU vnic<br/>(host) participant Kern_B as hicain_ib +<br/>hicain_net (vm-b) participant Prov_B as libhicain<br/>(vm-b) participant App_B as App (vm-b) App_A->>Prov_A: ibv_post_send(SEND) Prov_A->>Kern_A: write() doorbell Kern_A->>Kern_A: build [eth][ip4][udp][bth]<br/>[payload][icrc] Kern_A->>QEMU_A: dev_queue_xmit (skb) QEMU_A->>HiSw: SEQPACKET frame (port_0) HiSw->>HiSw: classify + FDB lookup + DCB HiSw->>QEMU_B: SEQPACKET frame (port_1) QEMU_B->>Kern_B: NAPI RX (skb) Kern_B->>Kern_B: validate ICRC,<br/>BTH/RETH/AETH parse,<br/>copy payload Kern_B->>Kern_B: build ACK frame Kern_B-->>QEMU_B: dev_queue_xmit (ACK) QEMU_B-->>HiSw: SEQPACKET (port_1) HiSw-->>QEMU_A: SEQPACKET (port_0) QEMU_A-->>Kern_A: NAPI RX (ACK) Kern_A-->>Prov_A: completion CQE Prov_A-->>App_A: ibv_poll_cq returns Kern_B-->>Prov_B: receive CQE Prov_B-->>App_B: ibv_poll_cq returns

Per-frame cost is dominated by two UDS hops and the kernel-side ICRC compute on TX + validation on RX. Multi-packet SEND/WRITE (>MTU) fragments into FIRST + N×MIDDLE + LAST sequences; ACKs coalesce by setting ackreq=1 only on LAST/ONLY.

For comparison: the HiLink fabric uses a much smaller wire header because it's an interconnect, not a fabric, and ignores Ethernet framing entirely.

sequenceDiagram autonumber participant GpuApp_A as GPU app (vm-a) participant Cart_A as libhicart (vm-a) participant Higpu_A as higpu.ko (vm-a) participant QEMU_A as QEMU higpu<br/>(host) participant HiLink as higpu-link-switchd participant QEMU_B as QEMU higpu<br/>(host) participant Higpu_B as higpu.ko (vm-b) participant Cart_B as libhicart (vm-b) participant GpuApp_B as GPU app (vm-b) GpuApp_A->>Cart_A: hicartMemcpyPeer(dst_gpu=1) Cart_A->>Higpu_A: ioctl (peer copy desc) Higpu_A->>QEMU_A: MMIO doorbell QEMU_A->>HiLink: 12B header + payload<br/>{magic, ver, type=DATA,<br/>src_gpu=0, dst_gpu=1, len} HiLink->>HiLink: FDB lookup by dst_gpu HiLink->>QEMU_B: framed payload QEMU_B->>Higpu_B: IRQ + DMA descriptor Higpu_B-->>Cart_B: completion event Cart_B-->>GpuApp_B: peer data visible<br/>in destination buffer

HiLink has no IBA framing, no ICRC, no PSN/ACK reliability, it mirrors the NVLink/NVSwitch programming model where the interconnect is assumed lossless and ordered.

6. Packaging and Deployment Topology

How the artifacts produced by hicain-tools pkg build map to where they install:

flowchart LR subgraph BUILD["Host build (hicain-tools)"] direction TB SRC_HINIC["src/hinic/<br/>(kernel + provider sources)"] SRC_HISW["src/hiswitch/<br/>(switch daemon)"] SRC_HILINK["src/hilink/<br/>(link switch daemon)"] SRC_HIGPU["src/higpu/<br/>(GPU kmod + runtime)"] SRC_NCCL["NVIDIA/nccl-tests<br/>(cloned to cache)"] end subgraph DEBS["Debian packages (out/)"] direction TB DEB_KMOD["hicain-hinic-modules<br/>hicain_net.ko + hicain_ib.ko"] DEB_PROV["hicain-libhicain-provider<br/>libhicain-rdmav34.so +<br/>/etc/libibverbs.d/hicain.driver"] DEB_HISW["hicain-vswitchd<br/>(host daemon)"] DEB_HILINK["hicain-hilink-cli<br/>+ higpu-link-switchd"] DEB_HIGPU["hicain-higpu-modules<br/>+ libhicart"] DEB_NCCL["hicain-nccl-tests<br/>(host-only L1 gate)"] end subgraph TARGETS["Install targets"] direction TB TGT_HOST["HOST (hicain1)<br/>- hicain-vswitchd<br/>- higpu-link-switchd<br/>- hicain-nccl-tests<br/>- hicain-libhicain-provider (optional)<br/>- hicain-hinic-modules (optional, for L2)"] TGT_VM["VM image (hicain-vm-*.qcow2)<br/>- hicain-hinic-modules<br/>- hicain-libhicain-provider<br/>- hicain-higpu-modules<br/>- libhicart"] end SRC_HINIC --> DEB_KMOD SRC_HINIC --> DEB_PROV SRC_HISW --> DEB_HISW SRC_HILINK --> DEB_HILINK SRC_HIGPU --> DEB_HIGPU SRC_NCCL --> DEB_NCCL DEB_HISW --> TGT_HOST DEB_HILINK --> TGT_HOST DEB_NCCL --> TGT_HOST DEB_KMOD --> TGT_VM DEB_PROV --> TGT_VM DEB_HIGPU --> TGT_VM

The split is deliberate:

  • The switch and link daemons are host-side processes; they never ship into the VM.
  • The kernel modules + provider + GPU runtime ship inside the VM image because they have to be loaded by the guest kernel.
  • hicain-nccl-tests is host-only because NCCL needs real CUDA.

7. Address-space Summary

Identifier Space Allocator Example
Ethernet MAC 48 bits static, encoded in QEMU args (52:54:00:42:00:NN) 52:54:00:42:00:01
IPv4 (data) private /24 static at boot 10.42.0.1, 10.42.0.2
IPv4 (mgmt SSH via SLIRP) localhost loopback qemu user-net localhost:2222, localhost:2223
IB GID 128 bits derived: ::ffff:<data IPv4> ::ffff:10.42.0.1
QPN 24 bits per-device counter 1..N
HiLink GPU ID 8 bits static, from -device higpu,gpu_id=N 0..7
HiSwitch port 4 bits static, 10-port fixed layout 0..9
HiLink port 3 bits static, 8-port fixed 0..7

8. Code-to-Concept Cross-Reference

Concept Code home Key file
HiSwitch daemon src/hiswitch/switch/ src/main.c, src/eth_pipeline.c, src/ib_pipeline.c
HiSwitch CLI tools/src/hicain_tools/ pkg/, deploy/
HiLink daemon src/hilink/switch/ higpu-link-switchd source
HiLink CLI src/hilink/cli/ Python, Typer + Rich
HiNIC QEMU device qemu/hw/net/hicain_vnic.c full PCIe + MMIO + UDS bridge
HiNIC kernel module src/hinic/kernel/ hicain_net.c, hicain_ib.c, hicain_proto.h
HiNIC userspace provider src/hinic/rdma-core/hicain.c the real one, not userspace/libhicain.c
HiGPU QEMU device qemu/hw/misc/higpu/ PCIe + HiLink endpoint
HiGPU kernel module src/higpu/kernel/ higpu.c
HiGPU runtime src/higpu/userspace/libhicart/ libhicart.so
VM image build tools/src/hicain_tools/image/ image build Typer command
Packaging tools/src/hicain_tools/pkg/targets/ one module per .deb target
E2E gate tests/test_rocev2_e2e.py 15 cases: pingpong, perftest, SRQ, atomics, UD
NCCL L1 gate tests/test_nccl_link.py 7 cases: deb build, ldd, dlopen, init banner

9. Live Traffic Flow (animated)

The SVG below is animated SMIL, it loops continuously while the page is open and behaves like a silent embedded video. Two flows are shown concurrently against the same physical rack pair from §2:

  • Blue, A RoCEv2 SEND from vm-a0 to vm-b0 (cross-rack): the packet rises out of the VM, hits TOR A, crosses the inter-TOR cable, drops into TOR B, then lands in vm-b0.
  • Pink, A HiLink hicartMemcpyPeer from vm-a1's GPU to vm-a2's GPU (rack-local): up to HiLink A, back down to the peer VM. Never touches the TOR.
Animated Cnuas traffic flow

The diagram above is an embedded animated SVG. If you see a still image, your browser is rendering it through the fallback <img> tag which may suppress SMIL animation in some Chrome versions; open the SVG directly and the blue + pink packet dots will loop continuously.

If your browser has prefers-reduced-motion set the animation auto-disables (the SVG falls back to the static layout).

9.1 Recording a real screen-capture video

The animated SVG is good for documentation and is built-in to the docs. If you want an actual MP4/WebM (e.g. to embed in a slide deck or share standalone), capture the rendered SVG with ffmpeg:

# 1. Serve the docs locally so the SVG renders with its animations.
mkdocs serve --dev-addr 127.0.0.1:8765 &

# 2. Capture the SVG region for one full animation period (12 s = 2
#    RoCEv2 loops + 3 HiLink loops; pick a multiple of LCM(6,4)=12
#    so the loop closes cleanly).
ffmpeg -y -f x11grab -framerate 30 -video_size 900x540 \
       -i :0.0+0,0 -t 12 \
       -vf "scale=900:540,format=yuv420p" \
       hicain-vdc-flow.mp4

For headless capture (no X server), render frames with chromium --headless --screenshot, or use Puppeteer / Playwright to drive a real browser and pipe MediaRecorder output to disk.

For terminal demos (CLI walkthroughs of hicain-tools deploy, ibv_devinfo, pingpong sessions, etc.) prefer asciinema: it captures the terminal at typing-speed, plays back at any size, embeds as a <script> tag, and the recording itself is text so it diffs cleanly in git:

asciinema rec -t "hicain Cnuas end-to-end pingpong" \
              docs/assets/hicain-pingpong.cast
asciinema upload docs/assets/hicain-pingpong.cast   # optional