Skip to content

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.

ItemDetail
PlatformTyrone Spark (NVIDIA GB10 Grace-Blackwell)
CPUaarch64, isolated cores for the L1 and xSM RX/TX threads
GPUNVIDIA GB10 (Aerial cuPHY)
NICNVIDIA ConnectX-7 (fronthaul to the O-RU)
FronthaulO-RU (e.g. LiteON RU)
SyncPTP grandmaster / GNSS for fronthaul timing (ptp4l / phc2sys)
OSUbuntu 22.04
HugepagesRequired for the DPDK-backed xSM memzone
Bring-up topology for the Aerial plus xFAPI plus OCUDU deployment on a single Tyrone Spark (NVIDIA GB10) host: the O-RU fronthaul, NVIDIA Aerial L1, the xFAPI bridge, and OCUDU CU and DU-High, with PTP/GNSS timing.
Single-host bring-up topology on a Tyrone Spark (NVIDIA GB10): O-RU fronthaul, Aerial L1, xFAPI, and OCUDU CU and DU-High, co-located. ref. coRAN LABS

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
Architecture of the NVIDIA Aerial L1 plus xFAPI plus OCUDU L2 split on a single host: NVIDIA Aerial cuPHY exposes SCF FAPI over nvIPC shared memory, xFAPI in AERIAL_OCUDU mode translates nvIPC to xSM, and OCUDU DU-High (odu_high, MAC, RLC, F1) attaches over xSM as the xSM master on pair 1.
The Aerial plus xFAPI plus OCUDU split: Aerial owns the PHY and RU, xFAPI translates SCF FAPI over nvIPC to the OCUDU FAPI dialect over xSM, and OCUDU DU-High owns MAC and above, all co-located on one host.
  • 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:

SettingValue
band / bw / scsn78 / 100 MHz / 30 kHz
pci51
nof_antennas_dl / ul4 / 4
pucch.f2_max_nof_rbs4
prach.prach_config_index159
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

ProcessExpect
Aerialcuphycontroller running; nvIPC SHM pools created; SLOT.indication ticking.
xFAPInvIPC secondary attached to primary; xSM memzone created; P5/P7 translation active.
OCUDU CUF1AP listener up; waiting for DU F1 Setup.
OCUDU DUCONFIG.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.prefix in xFAPI matches Aerial's shm_config.prefix.
  • xFAPI built in aerial_ocudu mode; libnvipc.so built; nFAPI sources synced.
  • OCUDU built with the split-7.2 aarch64 CMake configure (DPDK on, -DMARCH=armv8-a); libxsm.so resolved into odu.
  • aerial_l1_xfapi_ocudu_l2.yaml: xsm_file_prefix = gnb0, xsm_pair_index = 1, dpdk_proc_type = secondary.
  • RX thread rx_cpu / rx_priority on an isolated SCHED_FIFO core.
  • Startup order: Aerial -> xFAPI -> CU -> DU.
  • Verify CONFIG exchange, cell up, F1AP to CU, UE attach.

9. References