OCUDU India extends OAI’s new ZMQ-capable nr-uesoftmodem into a multi-UE testbed: N OAI UEs against a single OCUDU gNB, joined by a Python IQ-superposition proxy, per-UE Linux network namespaces, wave admission into the 5G CN, and a live Rust/ratatui dashboard.

Multi-UE simulation architecture: OCUDU gNB, ZMQ proxy, N OAI UEs in per-UE Linux namespaces, traffic engine, and ue-sim dashboard

OAI ZMQ Support and OCUDU Integration

OAI’s recent release introduced ZMQ support in nr-uesoftmodem that pairs cleanly with OCUDU’s ZMQ-based radio interface. That gave us a single-UE simulator talking natively to the OCUDU gNB, a strong starting point for pre-silicon testing.

Expansion to Multi-UE Simulation

This OCUDU India new release extends that starting point into a multi-UE testbed. The harness spins up N OAI UE instances against a single OCUDU gNB, gives each UE its own isolated data path and identity, drives realistic traffic, and surfaces per-UE state in real time. The same OAI binary, the same OCUDU gNB, scaled out into a high-density simulated air interface.

Multi-UE Through a ZMQ IQ Superposition Proxy

ZMQ Proxy as the Central Multi-UE Interface

The central piece is a Python proxy that sits between the OCUDU gNB and N UE instances on the ZMQ path.

Downlink (gNB to UEs) is a fan-out. Every IQ frame from the gNB is copied to all N UE sockets. Each UE sees the full downlink as if it were the only one on the channel.

Uplink (UEs to gNB) is a superposition. The proxy sums the IQ frames received from all N UEs sample-by-sample, then forwards the combined waveform. This is what a real antenna would see: N transmitters adding in the air.

Realistic Shared Radio Behaviour

The gNB sees one radio. Each UE sees a private downlink and transmits into a shared uplink. PRACH contention, multi-user reception, MU-MIMO pairing: all of it falls out of the physics. The OAI UE and the OCUDU gNB run unmodified; the multi-UE behaviour is a property of the IQ-level proxy.

Proxy Poll Interval Optimization

One tuning detail worth flagging: the proxy poll interval. The ZMQ default of 100 ms held the downlink for up to 200 slots whenever no uplink frame was ready. Setting PROXY_POLL_MS=1 keeps the fan-out tight.

Per-UE Network Isolation

Per-UE lifecycle inside its own Linux network namespace: oaitun_ueN tunnel, policy routing, IMSI provisioning, traffic flow

Linux Network Namespace per UE

Each UE runs inside its own Linux network namespace (ue1, ue2, … ueN). Inside the namespace, OAI creates oaitun_ue1 exactly as in the single-UE case. A veth pair connects each namespace to the host for management traffic.

Policy Routing for User-Plane Traffic

Policy routing inside the namespace ensures that 5G user-plane traffic actually traverses oaitun_ue1 rather than escaping out the veth default route. This was a subtle detail that took some debugging when early pings from inside ue1 were never reaching the gNB.

IMSI Auto-Provisioning

IMSIs are auto-provisioned into the 5G CN’s MySQL subscriber database at startup. The harness reads the desired UE count, generates a contiguous IMSI block, inserts subscription records, and configures each UE process with its own IMSI, K, and OPc.

Wave Admission Into the Core

Controlled UE Registration

Registering N UEs simultaneously puts pressure on the AMF’s T3560 retransmission timer. The harness admits one UE every 20 seconds, so the AMF processes each NAS exchange comfortably and PDU session establishment completes cleanly.

CPU Pinning for L1 Determinism

Scheduling Contention at High UE Counts

The scaling boundary at high UE counts is scheduling contention, not CPU starvation. The gNB L1 thread needs to wake every 0.5 ms; with many UE threads competing for the same cores, the Linux scheduler can delay that wakeup past the slot deadline.

Core Partitioning and Cell Bandwidth Tuning

The fix is core partitioning via taskset: the gNB runs on a dedicated set of cores, while UEs and the proxy run on a separate set. Dropping to a 10 MHz cell (FFT 512) for high UE counts also halves per-UE PHY cost, which matters more than per-cell peak throughput at scale.

Realistic Per-UE Traffic

Traffic Generation from Inside Each UE Namespace

Empty UEs that registered and went idle don’t tell you much. The harness drives traffic from inside each netns: ICMP ping through oaitun_ueN, iperf3 DL + UL, and a sustained UDP downlink simulating video. All UEs ping simultaneously to load the cell, while a focus cycle rotates higher-rate traffic across UEs every few seconds.

Live Dashboard

Live ue-sim Rust/ratatui dashboard showing per-UE stage, RTT sparklines, and throughput

A Rust/ratatui terminal dashboard aggregates per-UE state in real time:

  • gNB liveness via TCP probe on port 4556, which is more reliable than pgrep since pgrep can match zombie processes.
  • Per-UE stage detection from log tail: SYNC, SIB1, RAR, RRC, REGISTERED, DATA.
  • Live DL/UL Mbps read from /proc/net/dev inside each UE’s netns, sampled every second.
  • RTT sparklines per UE, plus a multi-UE RTT overlay graph for spotting outliers.
  • Bitrate graph with a per-UE colour legend.
  • Add/remove UEs live without restarting the gNB.

Config Knobs Tuned for Multi-UE

OAI and OCUDU Multi-UE Parameter Tuning

A handful of OAI and OCUDU parameters were retuned for the multi-UE case: n310 and t310 to prevent Radio Link Failure on ZMQ jitter bursts, t311 to give UEs longer to re-establish after sync loss, request_pdu_session_timeout to accommodate NAS exchanges under CPU load, preamble_trans_max to let PRACH-contended UEs keep retrying, and PROXY_POLL_MS to keep the ZMQ proxy responsive.

What This Unlocks

A multi-UE simulator on commodity hardware brings a class of testing into reach that previously needed a lab full of commercial UEs or a fleet of USRPs:

  • Capacity stress. Scheduler behaviour under sustained load from up to a dozen active UEs, driven from a script.
  • Admission churn. Wave registration, controlled detach/reattach, registration storms.
  • Regression coverage. Multi-UE behaviour becomes part of the CI matrix.
  • Feature bring-up. New OCUDU scheduler features and policy tweaks validated against multiple UEs in minutes.

Key Advantages

  • N UEs from a single host, built on the latest OAI release with OCUDU ZMQ support.
  • ZMQ IQ superposition proxy that makes the multi-UE channel a property of the physics.
  • Per-UE Linux netns for real, isolated data paths.
  • Wave admission for clean bring-up through the AMF and 5G CN.
  • CPU pinning for deterministic L1 timing at high UE counts.
  • Live Rust/ratatui dashboard with per-UE stage, RTT, and throughput.
  • Auto-provisioning of IMSIs into the 5G CN’s subscriber database at startup.
  • Live add/remove of UEs without restarting the gNB.

Closing Thought

From Single-UE Simulation to Routine Multi-UE Validation

OAI giving us a UE simulator that speaks OCUDU’s ZMQ interface out of the box was the enabler. The harness around it (the IQ proxy, the netns wiring, the wave admission, the dashboard) turns that single-UE starting point into a scale testbed for the OCUDU RAN stack.

Production-Path Validation on Commodity Hardware

Multi-UE testing is now a routine part of OCUDU’s validation flow, running on commodity hardware, exercising the same L1, L2, and 5G CN code paths that production traffic hits.

Useful Links