Bring up a complete 5G Standalone cell where the permissively-licensed OCUDU DU (built on
srsRAN Project) drives a commercial Foxconn RPQN-7801 O-RU over a real O-RAN 7.2 (split-7.2x)
fronthaul — eCPRI on VLAN 4, S-plane PTP (G.8275.1) — paired with a native Open5GS core, then
attach a commercial Quectel 5G modem over the air, register it, open a PDU session, reach the
internet, and measure DL/UL throughput.
This is the production O-RAN shape on the OCUDU (srsRAN) platform: instead of the DU driving its
own USRP, the radio lives in a standalone Foxconn RPQN-7801 O-RU connected by an Open Fronthaul
7.2x link. OCUDU's Open Fronthaul (ru_ofh) block speaks eCPRI directly to the RU using a raw-socket
backend (no DPDK) over a VLAN-4 tagged interface, with the S-plane synchronised by G.8275.1 PTP
against the fabric grandmaster.
The Foxconn RU runs in file mode (a local RRHconfig_xran.xml + an activation script), not M-Plane
NETCONF, so the RU is configured out-of-band and the DU simply streams C/U-plane to it. Once the RU is
radiating you attach an ordinary Quectel RM520N-GL COTS modem to the cell, and it registers → gets a
PDU session → reaches the internet exactly like on any commercial 5G network.
The tutorial is deliberately explicit about the three things that are different from the SDR path and
that will otherwise cost you an afternoon: the RU activation / re-latch sequence (and the one PTP
restart the RU needs after every reset), the real subscriber key (it is not the generic test key),
and the modem band lock (n78 at 3.75 GHz enumerates as band 77). PLMN is the testbed standard
00101, and the UE lands in the 192.168.100.0/22 pool with internet access.
For the radio-less software version see the OCUDU soft-only
tutorial; for the USRP over-the-air version
with cross-vendor UEs see the OCUDU cross-vendor
tutorial.
After completing this tutorial you will be able to:
rrh_log_print c_on counter (not the misleading "core1 is running" line).Authentication failure (MAC failure) as a wrong-key symptom.| Difficulty | Advanced |
| Estimated time | 75–120 min |
| Domain / sandbox | sb1 (fronthaul servers + Foxconn O-RU) |
| Topic group | Cellular (4G/5G/O-RAN) |
| Last verified | 2026-08-19 |
Background knowledge
ssh/ip/iperf3 on Linux.Account & access
Devices / nodes
| Resource | Role | Qty | Notes |
|---|---|---|---|
E810 fronthaul server (sb1) |
OCUDU OFH DU + Open5GS core | 1 | fronthaul NIC on VLAN 4 (e.g. srv1-lg1.sb1, iface DATA1a) |
| Foxconn RPQN-7801 O-RU | commercial O-RU (radio) | 1 | foxconn-oru1, M-Plane host 10.3.16.1:830, RU MAC 6c:ad:ad:00:0d:60 |
| Quectel RM520N-GL | commercial 5G UE | 1 | USB on a UE node; AT /dev/ttyUSB2/3, QMI wwan0/cdc-wdm0 |
Disk images
| Image | Load onto | Provides |
|---|---|---|
ocudu.ndz |
DU node | OCUDU gnb (/opt/ocudu), Open5GS (/opt/open5gs), UHD/qmicli, isolcpus baked for real-time OFH |
lte5gue.ndz |
UE node | qmicli (libqmi), modem helper scripts |
(ocudu.ndz / lte5gue.ndz are symlinks to the latest dated builds.)
Software components
| Component | Version | Source |
|---|---|---|
| OCUDU gNB (srsRAN Project) | commit 3118ae5 (26.04) |
/opt/ocudu/build/apps/gnb/gnb — no license needed, built with ru_ofh raw-socket |
| Open5GS 5GC | build-tree | /opt/open5gs, mongo db open5gs, launcher /root/open5gs/start.sh |
linuxptp (ptp4l/phc2sys) |
distro | S-plane G.8275.1 on the DU host + the RU |
| Foxconn RU firmware | eng_v3_1_15q |
file-mode activation init_rrh_config_enable_cuplane |
Spectrum / RF / special
dl_arfcn 650000 (3750 MHz),00101, slice SST 1 / SD 000001, DNN internet (IPv4), UE pool192.168.100.0/22, gateway 192.168.100.1, internet-NAT'd.Shared RF space. The
sb1fronthaul rig shares one physical RF space, so a Quectel modem on any
co-located node can camp on this cell. If a UE "sees no signal", the RU is not radiating — it is never
an antenna/EIRP problem.
The OCUDU DU + Open5GS core run on one E810 compute node; its fronthaul NIC carries the VLAN-4 eCPRI
link to the Foxconn O-RU, which radiates over the air to the Quectel modem:
DU / core node (sb1) Foxconn RPQN-7801 O-RU Quectel UE
┌────────────────────────┐ eCPRI ┌───────────────────────┐ n78 OTA ┌──────────────┐
│ OCUDU gnb (ru_ofh) │ VLAN 4 │ file-mode RRHconfig │ 3.75 GHz │ RM520N-GL │
│ Open5GS 5GC │═════════════►│ eAxC 0-3 DL/UL, 4-7 RA │────────────►│ wwan0 QMI │
│ ogstun 192.168.100.1 │ + PTP S-pl │ M-Plane 10.3.16.1:830 │ RSRP -68 │ 192.168.100.2│
│ AMF 127.0.0.5:38412 │◄────────────►│ TX 24 dBm, 4T4R │ │ │
└────────────────────────┘ G.8275.1 └───────────────────────┘ └──────────────┘
DATA1a (VLAN 4) PTP GM = fabric switch (G.8275.1)
OCUDU needs no license server and no DPDK — the ru_ofh block uses a raw AF_PACKET socket on the
named interface.
ssh <username>@console.<domain>.cosmos-lab.org
-r 0):omf load -i ocudu.ndz -t <du-node> -r 0 -o 1200
omf load -i lte5gue.ndz -t <ue-node> -r 0 -o 1200
omf tell -a on -t <du-node>,<ue-node>
sshd and wedges an un-isolated hostocudu.ndz image already carries isolcpus/nohz_full/rcu_nocbs in GRUB sized to theptp4l+phc2sys S-plane. Confirm on the DU node:ssh root@<du-node> 'cat /sys/devices/system/cpu/isolated; timedatectl | grep NTP; pgrep -a phc2sys'
4-11,28-35,12-19,36-43
NTP service: inactive
3688 phc2sys -s DATA1a -O 0 -m
phc2sys must settle to a small offset (s2, tens of ns), which puts CLOCK_REALTIME on fronthaulisolcpus is empty on your node.There is no Ansible description for the Foxconn OCUDU path yet — the RU activation and its crash-recovery
loop need a human in the loop — so this tutorial is a manual bring-up. Do the steps in order: core →
DU config → RU activate → gNB → verify radiating → attach UE.
ssh root@<du-node>
/root/open5gs/start.sh # NFs + ogstun 192.168.100.1/22 + NAT→internet
ip -4 addr show ogstun | grep inet
inet 192.168.100.1/22 scope global ogstun
The COSMOS test SIMs are not programmed with the generic srsRAN/OAI test key. Each card's real
Ki/OPc lives in the OAI CN5G seed SQL that the monolithic Duranta image uses; find your card there:
grep -rh "'<IMSI>','5G_AKA'" /opt/oai-cn5g/oai-cn5g-fed/docker-compose/database/*.sql
# row format: imsi,'5G_AKA',Ki,Ki,{sqn..},amf,'milenage',OPc,...
('001010000000032','5G_AKA','9E53736BC519AB701CCAA585BDD529EC','9E53736BC519AB701CCAA585BDD529EC',
'{"sqn":...}','9001','milenage','C71942C8FB0B6998B05ADB8FA3E4DF19',NULL,...,'001010000000032'),
Provision it into Open5GS with opc set and no op_type (a stray op_type breaks MILENAGE), plus
the slice and DNN:
mongosh open5gs --quiet --eval '
db.subscribers.updateOne({imsi:"001010000000032"},
{$set:{"security.k":"9E53736BC519AB701CCAA585BDD529EC",
"security.opc":"C71942C8FB0B6998B05ADB8FA3E4DF19",
"security.op":null,"security.amf":"9001",
"slice.0.sst":1,"slice.0.sd":"000001","slice.0.session.0.name":"internet"},
$unset:{"security.op_type":""}})'
Wrong-key symptom. If the AMF logs
Authentication failure(MAC failure)on a fresh attempt
(preceded byUnknown UE by SUCI), the network key ≠ the SIM's — try the OAI-seed value above.
A cached-GUTI re-registration can succeed with a wrong key; aCFUN=0/1on the modem forces the
real MILENAGE test.
The gNB config /root/ocudu/gnb-ocudu-ofh-foxconn.yml carries the cell + a ru_ofh block matched to the
RU's RRHconfig_xran.xml. The fields that must agree with the RU:
cell_cfg:
dl_arfcn: 650000 # n78, 3750 MHz
band: 78
channel_bandwidth_MHz: 100
common_scs: 30
plmn: "00101"
tac: 7
nof_antennas_dl: 4
nof_antennas_ul: 4
ru_ofh:
network_interface: DATA1a # raw socket, no DPDK
ru_mac_addr: 6c:ad:ad:00:0d:60 # == RU RRH_SRC_MAC
du_mac_addr: 00:11:22:33:44:66 # == RU RRH_DST_MAC
vlan_tag_cp: 4
vlan_tag_up: 4
ru_prach_port_id: [4, 5, 6, 7]
ru_dl_port_id: [0, 1, 2, 3]
ru_ul_port_id: [0, 1, 2, 3]
is_prach_cp_enabled: true
compr_method_ul: bfp
compr_method_dl: bfp
compr_bitwidth_ul: 9
compr_bitwidth_dl: 9
cu_cp:
amf: { addr: 127.0.0.5, bind_addr: 127.0.0.1,
supported_tracking_areas: [{ tac: 7,
plmn_list: [{ plmn: "00101", tai_slice_support_list: [{ sst: 1, sd: 1 }] }] }] }
expert_phy: { max_proc_delay: 15 } # OFH L2->L1 slack; default 5 floods "late DL_TTI"
The RU is reached over its M-Plane SSH (legacy KEX, root/root). If it is unpingable, power-reset it
first from the sb1 console:
# on console.sb1.cosmos-lab.org (as your COSMOS user)
omf tell -a reset -t foxconn-oru1
Then, on the RU (from the DU node via the M-Plane SSH), restart the RU's ptp4l — the one that starts
at boot never locks — and run the cuplane activation. The gNB must be down for this:
ssh -p 830 -o KexAlgorithms=+diffie-hellman-group14-sha1 \
-o HostKeyAlgorithms=+ssh-rsa root@10.3.16.1
# on the RU:
killall ptp4l 2>/dev/null; setsid /usr/utils/run_ptp4l.sh >/tmp/ptp.log 2>&1 &
grep -a state=3 /tmp/ptp.log | tail -1 # wait for lock
ptp4l[...]: state=3 rms 6 max 8 freq +60 delay 9 # SLAVE, rms a few ns
# still on the RU — enable C/U-plane (reads RRHconfig_xran.xml):
cd /home/root/test && (./init_rrh_config_enable_cuplane > /tmp/L.out 2>&1 &)
grep -aE 'valid|core1' /tmp/L.out | tail -3
Setting of LO1 and PRB is valid
Setting of Tx attenuation is valid
core1 is running 9
Crash watchdog. The RU's
/var/log/rrh_log_print/rrh_log_print.logfills tmpfs and crashes the
mgmt daemon roughly every 15 minutes. Keep it alive with an in-place truncate loop (a plainrm
does not free space on an open file):setsid sh -c 'while true; do :> /var/log/rrh_log_print/rrh_log_print.log; sleep 15; done' &
With the RU at "core1 is running 9" and PTP locked, start the gNB on the isolated cores (keep stdin open,
detach from ssh):
ssh root@<du-node>
cd /opt/ocudu/build
nohup setsid bash -c 'sleep 1800 | taskset -c 0-47 \
./apps/gnb/gnb -c /root/ocudu/gnb-ocudu-ofh-foxconn.yml > /tmp/g.log 2>&1' & disown
sleep 30; pgrep -x gnb >/dev/null && echo ALIVE; grep -a 'to AMF completed' /tmp/g.log
ALIVE
N2: Connection to AMF on 127.0.0.5:38412 completed
taskset -c 0-47 is required: isolcpus hides the isolated cores from srsRAN's affinity validator, so
the process must be launched with a mask that includes them.
c_on, not "core1 is running"The authoritative "is it transmitting" signal is the RU's rrh_log_print counter: c_on climbing with
err_tci/ecpri/port/sct all zero (the srsRAN Foxconn success signature):
# on the RU:
grep -a xRN /var/log/rrh_log_print/rrh_log_print.log | tail -2
xRN: total=734319 c_early=0 c_on=66948 c_late=0 err_tci=0 err_ecpri=0 err_port=0 err_sct=0 err_total=648520
xRN: total=750079 c_early=0 c_on=68372 c_late=0 err_tci=0 err_ecpri=0 err_port=0 err_sct=0 err_total=662457
On the UE node, hard-lock the Quectel to NR5G-SA and force the PLMN. Set band 77:78, not 78 —
3.75 GHz enumerates as band 77, so a bare 78 lock blocks the cell:
ssh root@<ue-node> 'systemctl stop ModemManager'
# via AT on /dev/ttyUSB2 (or ttyUSB3):
AT+CFUN=0
AT+QNWPREFCFG="mode_pref",NR5G
AT+QNWPREFCFG="nr5g_disable_mode",0
AT+QNWPREFCFG="nr5g_band",77:78
AT+CRSM=214,28539,0,0,12,"FFFFFFFFFFFFFFFFFFFFFFFF" # clear forbidden-PLMN list
AT+CFUN=1
AT+COPS=1,2,"00101",12
AT+QENG="servingcell"
+QENG: "servingcell","NOCONN","NR5G-SA","TDD",001,01,00066C000,1,7,647328,78,3,-68,-10,30,1,71
NR5G-SA, PLMN 001/01, RSRP -68, SINR 30. Confirm registration in the AMF log:
ssh root@<du-node> "grep -a 'Registration complete' /tmp/open5gs/amf.log | tail -1"
[gmm] INFO: [imsi-001010000000032] Registration complete
ssh root@<ue-node>
echo Y > /sys/class/net/wwan0/qmi/raw_ip; ip link set wwan0 up
qmicli -d /dev/cdc-wdm0 -p --wds-start-network="apn='internet',ip-type=4" --client-no-release-cid
qmicli -d /dev/cdc-wdm0 -p --wds-get-current-settings | grep -E 'IPv4 address|gateway'
IPv4 address: 192.168.100.2
IPv4 gateway address: 192.168.100.1
QMI CID-alloc timeout? Reload the driver:
rmmod qmi_wwan; modprobe qmi_wwan(with ModemManager
stopped), then retry--wds-start-network.
ip addr add 192.168.100.2/30 dev wwan0; ip link set wwan0 up mtu 1400
ping -c5 -I wwan0 192.168.100.1 # UPF gateway
ping -c5 -I wwan0 8.8.8.8 # internet via UPF NAT
5 packets transmitted, 5 received, 0% packet loss # rtt avg ~103 ms (gw)
5 packets transmitted, 5 received, 0% packet loss # rtt avg ~77 ms (8.8.8.8)
Throughput — run an iperf3 server on the UPF gateway and drive it from the UE:
ssh root@<du-node> 'iperf3 -s -B 192.168.100.1 &'
ssh root@<ue-node> 'iperf3 -c 192.168.100.1 -B 192.168.100.2 -t 8 -R; \
iperf3 -c 192.168.100.1 -B 192.168.100.2 -t 8'
[ 5] 0.00-8.00 sec 23.6 MBytes 24.8 Mbits/sec receiver # DOWNLINK
[ 5] 0.00-8.25 sec 15.8 MBytes 16.0 Mbits/sec receiver # UPLINK
You now have a COTS UE reaching the internet over a commercial O-RU driven by a license-free DU.
ssh root@<ue-node> 'pkill -x iperf3; qmicli -d /dev/cdc-wdm0 -p --wds-stop-network=disable; \
ip addr flush dev wwan0'
ssh root@<du-node> 'pkill -x gnb; pkill -x iperf3'
# stop the RU watchdog + return the RU to idle (optional):
omf tell -a offh -t <du-node>,<ue-node>
The Foxconn O-RU is a shared sb1 resource — leave it powered as you found it (its own reset is
omf tell -a reset -t foxconn-oru1).
| Symptom | Likely cause | Fix |
|---|---|---|
Modem stuck SEARCH, no SSB seen |
RU not radiating | Check c_on climbing (Step verify); if not, re-do Step 4 (PTP restart + init_rrh_config) then restart the gNB |
RU unpingable at 10.3.16.1 |
tmpfs full → mgmt daemon crash | omf tell -a reset -t foxconn-oru1, then re-latch; keep the truncate watchdog running |
RU PTP never reaches state=3 |
boot ptp4l doesn't lock |
killall ptp4l; setsid /usr/utils/run_ptp4l.sh and wait |
gNB: Invalid CPU core selected '8' |
isolcpus hides cores |
launch inside taskset -c 0-47 |
gNB floods late DL_TTI.request |
L2→L1 slack too tight | expert_phy: { max_proc_delay: 15 } |
OFH woke up late … skipped N symbols |
CLOCK_REALTIME on UTC, not TAI |
NTP off + phc2sys -s DATA1a -O 0 (offset should be s2, ~tens of ns) |
AMF Authentication failure(MAC failure) on a fresh attempt |
wrong network Ki/OPc | use the OAI-seed key (Step 2); do not set op_type |
Modem camps commercial LTE (LIMSRV,LTE) |
mode_pref drifted to AUTO |
re-assert mode_pref=NR5G and COPS=1,2,"00101",12 |
qmicli … CID allocation failed |
ModemManager holds the QMI device / stuck channel | systemctl stop ModemManager; rmmod qmi_wwan; modprobe qmi_wwan |
ping: Network is unreachable |
wwan0 has no IP yet |
wait for --wds-get-current-settings to return an address, then ip addr add |
Author(s): COSMOS team · Last verified: 2026-08-19 · Tested image/release: ocudu.ndz (OCUDU commit 3118ae5) + Foxconn RPQN-7801 (eng_v3_1_15q) · Tags: ocudu, srsran, oran, 7.2, foxconn, o-ru, quectel, open5gs