Setup
The OCUDU repository is officially online, as SRS has transferred all development work to the new GitLab repository. In this article I am going to walk through deploying the Split Docker and the troubleshooting steps I went through to get the end-to-end connectivity from the UE to the Internet.
Pre requisites
- OCUDU
- Docker & Docker Compose
- USRP B210 with GPSDO or External Clock Source
- 5G Capable UE and Test SIM
- Motorola Moto G Power 5G (2023)
- IMSI: 001010000560128
- K: FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
- OPC: 9ED73ED8F0FD186430CA9D7ED728EA0F
- APN: apn (IPv4)
- Computer with Internet connectivity
- OS: Ubuntu 22.04.5 LTS x86_64
- Kernel: 6.8.0-100-generic
For this example, I am running everything on a single machine – gNB DU, gNB CU CP, gNB CU UP, and 5G Core

OCUDU Install
Clone the OCUDU repository, then move into the ~/ocudu directory
$ git clone https://gitlab.com/ocudu/ocudu.git$ cd ocudu
Docker
Inspect the ~/ocudu/docker directory and you will see the following files

docker-compose.yml defines the following
- RAN Network: docker_ran (10.53.1.0/24)
- 5GC IP Address: 10.53.1.2
docker-compose.split.yml defines the following
- F1-U Network: f1u_network (172.18.10.0/24)
- DU F1-U IP Address: 172.18.10.3
- CU UP F1-U IP Address: 172.18.10.2
- gNB DU IP Address: 10.53.1.6
- gNB CU CP IP Address: 10.53.1.4 (E1AP, F1AP, AMF Bind)
- AMF address: 10.53.1.2
- gNB CU UP IP Address: 10.53.1.5
- Config Files
- ${CUCP_CONFIG_PATH:-../configs/cu_cp.yml}
- ${CUUP_CONFIG_PATH:-../configs/cu_up.yml}
- ${DU_CONFIG_PATH:-../configs/du_rf_b200_tdd_n78_20mhz.yml}
Initial Build
If you want to run the Split configuration then you will use the following command from ~/ocudu
docker compose -f docker/docker-compose.yml -f docker/docker-compose.split.yml up

Out of the box, everything should start. The first time you run the docker compose up command will take awhile to build. At this point, the UE should be able to connect to the network….
- If UE IMSI, K, and OPC, and APN are not configured in Open5gs, the UE will be rejected or PDU Session will not be setup
- Access the webui @ localhost:9999 on the host
- See 5GC additional configurations below to have changes be persistent (will require removing the open5gs image, then have it rebuilt with the docker compose up command)
- CU UP NG-U interface does not seem to be configured properly and may require configuration changes
- See cu_up.yml additional configurations below
- The host requires routing configuration changes to allow incoming Downlink traffic to reach the ocudu network
- See Host Network Configuration below
Additional Configurations
There are a few configurations I change locally – though it may not be necessary for you
~/ocudu/configs/du_rf_b200_tdd_n78_20mhz.yml- all_level: debug
~/ocudu/configs/cu_cp.yml- all_level: debug
~/ocudu/configs/cu_up.yml- ngu > socket > bind_addr: 10.53.1.5
- all_level: debug
~/ocudu/docker/open5gs/add_users.py- opc=”63bfa50ee6523365ff14c1f45f88737d”, amf=”9001″, apn=”apn”, qci=”9″, ip_alloc=””):
~/ocudu/docker/open5gs/open5gs.env- SUBSCRIBER_DB=<IMSI>,<K>,opc,<OPC>,8000,9,10.45.1.2
- TZ=America/New_York
Changing the cu_up.yml to 10.53.1.5 has been the only way I have gotten the UE to have internet connectivity.
Host Network Configuration
When the docker containers are running, you will need to check the hosts network configurations with ifconfig
# docker_ran bridge interfacebr-0fea5da6616c: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 10.53.1.1 netmask 255.255.255.0 broadcast 10.53.1.255# What interface is connected to the internetenp36s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 192.168.2.226 netmask 255.255.255.0 broadcast 192.168.2.255
Now, from the host you will need to enter the following commands… Make sure to change <br-docker_ran> and <inet_interface> to your specific configuration
sudo ip route add 10.45.0.0/16 via 10.53.1.2 dev <br-docker_ran>
sudo iptables -t nat -A POSTROUTING -s 10.45.0.0/16 -o <inet_interface> -j MASQUERADE
for example, I would configure the following
sudo ip route add 10.45.0.0/16 via 10.53.1.2 dev br-0fea5da6616c sudo iptables -t nat -A POSTROUTING -s 10.45.0.0/16 -o enp36s0 -j MASQUERADE
Now when your UE is connected to the network, it should be able to reach the internet.


Troubleshooting
For awhile I could not figure out why my UE could connect to the ocudu network, but would not get an internet connection…
I ran tcpdump on the host machine, and I ran it in open5gs core container as well. Since the open5gs container has internet connectivity, I was able to install tcpdump and run it in the container. Use the docker exec -it <container> bash command to open an interactive bash shell in the container.
docker exec -it open5gs_5gc bash
apt install tcpdump
tcpdump -i any -w docker_5gc.pcap
So now I had two packet captures to see where the data flow was failing.
The capture below is from the host –
- 1726: F1-U transfers UL NR RAN container from DU to CU UP (172.18.10.3 to 172.18.10.2)
- 1732: GTP-U PDU Session Container goes from the gNB CU UP to the 5G Core (10.53.1.5 to 10.35.1.2)
- 1742: The host receives the UE data to DNS server (10.45.1.2 to 8.8.8.8)
- 1744: The host sends the data to the internet (192.168.2.226 to 8.8.8.8)
- 1763: The host receives the UL data from the DNS server (8.8.8.8 to 192.168.2.226)
- 1764: The host packages the data to be sent to the UE (8.8.8.8 to 10.45.1.2)
- The packet stops here… There is no subsequent flow to the UPF



At the 5G Core side, we can see that the UL data is received (correlated to packet # 1732 on the host) though it never receives DL data from the host.

So now we can assume that there is something broken between the host and the 5GC on the docker_ran network.

This issue is fixed with the HOST NETWORK CONFIGURATION section which sets the route for UE traffic on 10.45.0.0/16 to reach the docker_ran network (10.53.1.1/16) where the 5GC is located. See the EXAMPLE DATA FLOW section below, to see what a working configuration looks like.
UE Packet Capture
If you wanted to go a step further, you can run tcpdump on rooted android devices. I use scrcpy to mirror android devices on my laptop, but if you connect your UE to your laptop and use adb you should be able to run tcpdump.
Verify if tcpdump is installed on the device and what the path is to tcpdump
adb devices List of devices attachedZY22HCLS7Z devicedevonn:/ # which tcpdump/system/bin/tcpdump
then exit back to your host CLI and run tcpdump on the UE.
adb shell su -c "/system/bin/tcpdump -i any -s 0 -w /sdcard/capture.pcap" tcpdump: data link type LINUX_SLL2tcpdump: listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
When you are finished with the capture, pull the pcap to your computer.
adb pull /storage/emulated/0/capture.pcap /storage/emulated/0/capture.pcap: 1 file pulled, 0 skipped. 6.1 MB/s (24576 bytes in 0.004s)
Open5gs Connection Issues
If Open5gs is running on the host machine then you will see this error

Make sure all Open5gs services are stopped locally on the host, then you will need to run the docker compose down –remove-orphans command before re-running the docker compose up command again.
Example data flow

Docker Commands
The following docker commands are run on the host, and are helpful for observing configurations, logs, or interacting with the containers.
docker images
List current loaded images

docker rmi -f <image>
Forcefully removes loaded images
docker network ls
Lists configured docker networks

docket network inspect <network>
Displays details of container networks
docker network inspect docker_ran[ { "Name": "docker_ran", "Id": "0fea5da6616c930c5fc45e73698ba57f183e3a925bee62f3b1dbd919c66f1d12", "Created": "2026-02-20T10:44:42.206208235-05:00", "Scope": "local", "Driver": "bridge", "EnableIPv4": true, "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": null, "Config": [ { "Subnet": "10.53.1.0/24", "IPRange": "", "Gateway": "10.53.1.1" } ] }, "Internal": false, "Attachable": false, "Ingress": false, "ConfigFrom": { "Network": "" }, "ConfigOnly": false, "Options": {}, "Labels": { "com.docker.compose.config-hash": "0edf626a1c1e248ce1822695de1063c5aafee1350a92a54495ab8f992c516cb8", "com.docker.compose.network": "ran", "com.docker.compose.project": "docker", "com.docker.compose.version": "5.0.1" }, "Containers": { "1c7b1a4eaa1f024ec654c4902dbb32f41cfad55cef9bb29a9315f2ecf1d88a66": { "Name": "ocudu_du", "EndpointID": "2c3847e91df4e15c600144aaec7e8217f348e6a0e61ac590a31186b5b2426c88", "MacAddress": "86:6c:c1:24:b9:df", "IPv4Address": "10.53.1.6/24", "IPv6Address": "" }, "6f1416e11f85f86e86abc1e472374fec6b02ff7ff43924cf306d1b20cc016190": { "Name": "open5gs_5gc", "EndpointID": "6a9939324857b0a8eb44eb092f6968d9e0ce6da41dd73d8225873cd2a7983853", "MacAddress": "ea:75:5c:b4:70:7b", "IPv4Address": "10.53.1.2/24", "IPv6Address": "" }, "9fe29132053e86a277d9b49973db556a2b9d878f49d1cbbdac19f94323fac33d": { "Name": "ocudu_cu_up", "EndpointID": "5cd10cb92b6b7a45d6645479360fac3365533391b5d14a50e2599d0a7aa24bbf", "MacAddress": "aa:db:41:41:4f:5d", "IPv4Address": "10.53.1.5/24", "IPv6Address": "" }, "c01bb0defdea15114556761ee81761e1391d83dcf5091517799b04c73d008dcf": { "Name": "ocudu_cu_cp", "EndpointID": "4421d977a794c81163d0e346380a5368298264bc3f6e7e55c337b03215b24d5d", "MacAddress": "46:41:ca:39:c6:df", "IPv4Address": "10.53.1.4/24", "IPv6Address": "" } }, "Status": { "IPAM": { "Subnets": { "10.53.1.0/24": { "IPsInUse": 7, "DynamicIPsAvailable": 249 } } } } }]
docker container ls or docker contain ps
Both commands display the same or similar information about currently running containers

docker container stats
Displays real time container process information

docker exec -it <container> bash
Allows interaction with a container via the defined shell (bash, in this example). This is useful for viewing or copying logs, installing additional applications, viewing container network information, etc.

docker logs -f <container>
Displays the logs of the specified container, which are also displayed in the attached view after running the docker compose up command without the -d (detached) flag.
docker inspect <container>
Provides detailed information on the container
docker rm <container>
Removes a container
docker stop <container>
Stops a container from running
docker start <container>
Starts a container


Leave a Reply