NVIDIA Aerial L1 + xFAPI + OCUDU L2
This guide covers pairing OCUDU DU-High (L2) with NVIDIA Aerial (L1/PHY) across the FAPI L2-L1 boundary, using xFAPI as the translator-bridge in its AERIAL_OCUDU mode.
Before you start: this guide assumes NVIDIA Aerial L1 is already installed and running. See Installing NVIDIA Aerial L1 for the Aerial build and bring-up.
This guide covers pairing OCUDU DU-High (L2) with NVIDIA Aerial (L1/PHY) across the FAPI L2-L1 boundary, using xFAPI as the translator-bridge in its AERIAL_OCUDU mode.
Aerial exposes SCF FAPI over nvIPC shared memory; xFAPI translates SCF FAPI to the OCUDU FAPI dialect and bridges it onto xSM shared memory for OCUDU. In this topology Aerial L1, xFAPI, and OCUDU DU-High are co-located on a single host.
For the OCUDU-to-OCUDU split (odu_low instead of Aerial) and the OAI-L1 variant, see the References.
Highlights
- OCUDU DU-High (L2) runs behind NVIDIA Aerial as the PHY, unchanged, with only the L1 endpoint and xFAPI's mode differing from the other splits.
- nvIPC to xSM translation in xFAPI (AERIAL_OCUDU mode): nvIPC secondary on the Aerial side, xSM slave on the OCUDU side.
- Single-host topology: Aerial L1 + xFAPI + OCUDU DU-High on one server, all shared-memory (no nFAPI sockets).
- Aerial-tuned cell config (
configs/aerial_l1_xfapi_ocudu_l2.yaml) with band/PUCCH/PRACH/TDD values matched to Aerial's decoders, so a UE attaches end-to-end.
1. System Under Test
This deployment was validated on a Tyrone Spark system, built on the NVIDIA GB10 Grace-Blackwell platform.
| Item | Detail |
|---|---|
| Platform | Tyrone Spark (NVIDIA GB10 Grace-Blackwell) |
| CPU | aarch64, isolated cores for the L1 and xSM RX/TX threads |
| GPU | NVIDIA GB10 (Aerial cuPHY) |
| NIC | NVIDIA ConnectX-7 (fronthaul to the O-RU) |
| Fronthaul | O-RU (e.g. LiteON RU) |
| Sync | PTP grandmaster / GNSS for fronthaul timing (ptp4l / phc2sys) |
| OS | Ubuntu 22.04 |
| Hugepages | Required for the DPDK-backed xSM memzone |
2. Architecture Overview
Aerial owns the PHY and RU; OCUDU owns MAC and above. The FAPI message set is the contract between them; nvIPC is the shared-memory transport Aerial exposes it on.
NVIDIA Aerial L1 xFAPI (AERIAL_OCUDU) OCUDU DU-High (L2)
cuPHY / SCF FAPI <--nvIPC--> nvIPC <-> xSM <--xSM--> odu_high / MAC / RLC / F1
- Aerial side: xFAPI is the nvIPC secondary (the role Aerial's testMAC plays); Aerial cuphycontroller is the nvIPC primary that creates the SHM pools.
- OCUDU side: xFAPI is DPDK primary and xSM slave on pair 1; OCUDU DU-High attaches as DPDK secondary and xSM master on pair 1.
3. Clone the repositories
Pick a common workspace, e.g. ~/tossi-ran:
mkdir -p ~/tossi-ran && cd ~/tossi-ran
# xFAPI bridge
git clone https://github.com/coranlabs/xFAPI
# OCUDU RAN (dev branch)
git clone https://github.com/TOSSI-Foundation/OCUDU-RAN
cd OCUDU-RAN && git checkout dev && cd ..
4. Build & Run xFAPI (AERIAL_OCUDU)
The xFAPI side (prerequisites, syncing the nFAPI sources, packing and building the nvIPC library from the Aerial container, and building xFAPI in aerial_ocudu mode) is documented in full in the xFAPI repository. The detailed steps below mirror that document:
docs/build_and_run_aerial_ocudu.md
Prerequisites
sudo apt update
sudo apt install -y build-essential cmake pkg-config \
libyaml-dev zlib1g-dev libhugetlbfs-dev
DPDK is required (the OCUDU-L2 side uses it). Set DPDK_PATH in setup_env.sh (repo root) and source it before building:
source setup_env.sh
This exports DPDK_PATH and PKG_CONFIG_PATH.
Sync the OAI nFAPI sources
Mirror the OAI nFAPI sources into src/ipc/nfapi:
./sync_nfapi.sh /path/to/openairinterface
# or: OAI_DIR=/path/to/openairinterface ./sync_nfapi.sh
-n for a dry run, -v for verbose, -h/--help for usage.
Get the nvIPC sources into the tree
The nvIPC source is packed from a running Aerial container.
Bring up the Aerial container (drops you into its terminal, tty mode):
/home/user/aerial-cuda-accelerated-ran/cuPHY-CP/container/run_aerial.sh
Inside the container, generate the nvipc tarball:
cd cuPHY-CP/gt_common_libs
./pack_nvipc.sh
It prints the output path, e.g.:
/opt/nvidia/cuBB/cuPHY-CP/gt_common_libs/nvipc_src.2026.07.13.tar.gz
Back on the host, copy it into xFAPI:
docker cp "aerial-l1:/opt/nvidia/cuBB/cuPHY-CP/gt_common_libs/nvipc_src.2026.07.13.tar.gz" /home/user/xFAPI
Unpack it into src/ipc/nvipc (use the actual filename from the step above):
rm -rf src/ipc/nvipc
mkdir -p src/ipc/nvipc
tar -xzf nvipc_src.2026.07.13.tar.gz \
-C src/ipc/nvipc \
--strip-components=1
Build the nvIPC library:
cd src/ipc/nvipc
cmake .
make -j$(nproc)
On success nvIPC/libnvipc.so is produced:
ls nvIPC/libnvipc.so
Hugepages (one-time, per boot)
echo 1024 | sudo tee /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
sudo mkdir -p /mnt/huge
sudo mount -t hugetlbfs nodev /mnt/huge
Build
From the repo root:
./build_xfapi.sh --mode=aerial_ocudu
Produces bin/xfapi_main. --clean to wipe build/ and bin/; -v for verbose; --help for all options.
5. Build OCUDU
cd ~/tossi-ran/OCUDU-RAN
mkdir -p build && cd build
cmake \
-DDU_SPLIT_TYPE=SPLIT_7_2 \
-DENABLE_DPDK=ON \
-DENABLE_UHD=OFF \
-DASSERT_LEVEL=MINIMAL \
-DMARCH=armv8-a \
../
make -j$nproc
This is the build for an arm-based deployment (the Tyrone Spark GB10 is aarch64): the split-7.2 DU with DPDK on, UHD off, minimal asserts, and -DMARCH=armv8-a. It produces the CU and DU-High (L2) binaries under build/apps/.
Verify the xSM library is resolved into the DU binary:
ldd build/apps/du/odu_high | grep xsm # libxsm.so resolved
6. Configure
6.1 OCUDU L2 config
Use the Aerial split config: configs/aerial_l1_xfapi_ocudu_l2.yaml.
Key fapi_split_l2 knobs (single-host bridge defaults):
fapi_split_l2:
rx_cpu: 14 # SCHED_FIFO RX thread affinity (-1 = no pinning)
rx_priority: 85 # [1, 99]
xsm_device_name: xsm_bridge
xsm_pair_index: 1 # OCUDU attaches as master on pair 1
xsm_file_prefix: gnb0 # must match xFAPI's DPDK file-prefix
dpdk_proc_type: secondary # xFAPI owns the primary
6.2 Aerial-tuned cell config
The cell_cfg values in aerial_l1_xfapi_ocudu_l2.yaml are set so OCUDU's MAC stays on Aerial L1's tested decode paths:
| Setting | Value |
|---|---|
| band / bw / scs | n78 / 100 MHz / 30 kHz |
| pci | 51 |
| nof_antennas_dl / ul | 4 / 4 |
| pucch.f2_max_nof_rbs | 4 |
| prach.prach_config_index | 159 |
| tdd (dl/ul) | 6 DL slots, 10 DL symbols, 3 UL slots |
| pusch.p0_nominal_with_grant | -96 |
Review these against your Aerial cell configuration before running.
6.3 xFAPI config
conf/aerial_ocudu_config.yaml in the xFAPI tree: nvipc.prefix must match Aerial cuphycontroller's shm_config.prefix, and the DPDK file-prefix must match xsm_file_prefix above (gnb0).
7. Run
Start the components in this order, each in its own terminal. Aerial brings up the PHY and the nvIPC primary; xFAPI must own its DPDK/xSM resources before the DU attaches; the CU must be listening before the DU sends F1 Setup.
7.1 NVIDIA Aerial L1
Bring up the Aerial cuphycontroller (nvIPC primary). Follow the Aerial documentation for your deployment; it creates the nvIPC SHM pools that xFAPI's secondary attaches to.
7.2 xFAPI bridge
cd ~/tossi-ran/xFAPI
./run_xfapi.sh
Set MAIN_CONFIG_FILE at the top of run_xfapi.sh to conf/aerial_ocudu_config.yaml (or run bin/xfapi_main --cfgfile conf/aerial_ocudu_config.yaml directly). This attaches to Aerial over nvIPC and creates the xSM memzone (DPDK primary, file-prefix gnb0).
7.3 OCUDU CU
cd ~/tossi-ran/OCUDU-RAN
./build/apps/cu/<cu_bin> -c configs/cu.yml
7.4 OCUDU DU-High (L2)
cd ~/tossi-ran/OCUDU-RAN
./build/apps/du/odu_high -c configs/aerial_l1_xfapi_ocudu_l2.yaml
Once all four are up, Aerial L1 and OCUDU L2 are connected through xFAPI: SCF FAPI over nvIPC on the Aerial side, translated to the OCUDU FAPI dialect over xSM on the L2 side.
7.5 Startup verification
| Process | Expect |
|---|---|
| Aerial | cuphycontroller running; nvIPC SHM pools created; SLOT.indication ticking. |
| xFAPI | nvIPC secondary attached to primary; xSM memzone created; P5/P7 translation active. |
| OCUDU CU | F1AP listener up; waiting for DU F1 Setup. |
| OCUDU DU | CONFIG.request emitted; cell up; F1AP/RRC to CU established; UE attach completes. |
8. Deployment Checklist
- IOMMU on, hugepages reserved, DPDK NIC bound to
vfio-pci. - O-RU fronthaul up; PTP/GNSS locked.
- Aerial cuphycontroller running;
nvipc.prefixin xFAPI matches Aerial'sshm_config.prefix. - xFAPI built in
aerial_ocudumode;libnvipc.sobuilt; nFAPI sources synced. - OCUDU built with the split-7.2 aarch64 CMake configure (DPDK on,
-DMARCH=armv8-a);libxsm.soresolved intoodu. aerial_l1_xfapi_ocudu_l2.yaml:xsm_file_prefix = gnb0,xsm_pair_index = 1,dpdk_proc_type = secondary.- RX thread
rx_cpu/rx_priorityon an isolated SCHED_FIFO core. - Startup order: Aerial -> xFAPI -> CU -> DU.
- Verify CONFIG exchange, cell up, F1AP to CU, UE attach.
9. References
- xFAPI - https://github.com/coranlabs/xFAPI
- xFAPI AERIAL_OCUDU build & run - https://github.com/coranlabs/xFAPI/blob/main/docs/build_and_run_aerial_ocudu.md
- OCUDU-RAN - https://github.com/TOSSI-Foundation/OCUDU-RAN
- OCUDU-to-OCUDU bridge - https://tossi.org/docs/ran-integration/fapi-split/xfapi-bridge/
- OAI L1 + xFAPI + OCUDU L2 - https://tossi.org/docs/ran-integration/fapi-split/oai-xfapi-ocudu/
- NVIDIA Aerial - https://developer.nvidia.com/aerial
- DPDK - https://www.dpdk.org/
- SCF 222.10 (5G FAPI: PHY API); 3GPP TS 38.211/212/213/214