O-RAN NearRT-RIC and xApp


This application note shows how to use the E2 interface exposed by the srsRAN Project gNodeB and showcases its interoperability with third-party RIC frameworks. For this purpose, we use O-RAN Alliance compliant NearRT-RICs and xApps provided in ORAN SC RIC and FlexRIC projects.

Our E2 interface implementation is based on the following O-RAN technical specifications:

  • O-RAN.WG3.E2AP-R003-v03.00

  • O-RAN.WG3.E2SM-R003-v03.00

  • O-RAN.WG3.E2SM-KPM-R003-v03.00

  • O-RAN.WG3.E2SM-RC-R003-v03.00

Setup Overview

The following diagram presents the setup architecture used in this application note:


Hardware and Software Overview

For this application note, the following hardware and software are used:


While our ultimate goal is to fully support the E2 interface, it is still under development and its current version is limited in features and operation. Specifically, the current E2 interface implementation supports only E2SM_KPM and E2SM_RC service models with the following limitations:

  • E2SM_RC service model:

    • Only Control Service Style 2 is supported

  • E2SM_KPM service model:

    • All Report Service Styles (1 - 5) are supported

    • Monitoring period limited to 1s

    • The following 3 ‘dummy’ DU metrics are exposed (they will be removed in future releases):

      • CQI

      • RSRP

      • RSRQ

    • The following 6 ORAN defined metrics are expose:

      • DRB.UEThpDl - DL throughput

      • DRB.UEThpUl - UL throughput

      • DRB.RlcPacketDropRateDl - UL packet success rate

      • DRB.PacketSuccessRateUlgNBUu - RLC DL packet drop rate

      • DRB.RlcSduTransmittedVolumeDL - RLC DL transmitted SDU volume

      • DRB.RlcSduTransmittedVolumeUL - RLC UL transmitted SDU volume


For the purpose of presenting the usage of E2 interface exposed by srsRAN Project gNodeB, we use the NearRT-RIC and an example KPM monitoring xApps from the ORAN SC RIC and FlexRIC frameworks.


Depending on which RIC you are using, you should select the appropriate instructions from the tabs below. The tabs are grouped throughout the tutorial, so you only need to select the appropriate instructions in this section.

O-RAN Software Community (SC) Near-Real-time RIC is a reference platform that aligns with the architecture and specifications created in the O-RAN Alliance working groups.

The ORAN SC RIC platform is an advanced software framework with a functionality that includes platform health monitoring, alarms, etc. Since it relies on Kubernetes and Helm for deployment, reliability, and scalability, its vanilla installation is quite complex, involves many steps, and requires a high level of knowledge and expertise in those frameworks.

In this application note, we use a minimal version of the O-RAN SC near-RT RIC (i-release), that can be easily deployed as a multi-container application using a single Docker command, eliminating the necessity for Kubernetes or Helm. Specifically, we will deploy ORAN SC RIC using Docker and configuration files provided in this repository.

The ORAN SC RIC deployment is performed as follows:

git clone https://github.com/srsran/oran-sc-ric
cd ./oran-sc-ric
docker compose up


For this example we are using Open5GS as the 5G Core.

Open5GS is a C-language Open Source implementation for 5G Core and EPC. The following links will provide you with the information needed to download and set-up Open5GS so that it is ready to use with srsRAN:

For the purpose of this application note, we will use a dockerized Open5GS version provided in srsRAN Project at srsgnb/docker.


On Ubuntu, ZeroMQ development libraries can be installed with:

sudo apt-get install libzmq3-dev

Alternatively, ZeroMQ can also be built from source.

First, one needs to install libzmq:

git clone https://github.com/zeromq/libzmq.git
cd libzmq
sudo make install
sudo ldconfig

Second, install czmq:

git clone https://github.com/zeromq/czmq.git
cd czmq
sudo make install
sudo ldconfig

Finally, you need to compile srsRAN Project and srsRAN 4G (assuming you have already installed all the required dependencies).


If you have already built and installed srsRAN 4G and srsRAN Project prior to installing ZMQ and other dependencies you will have to re-build both to ensure the ZMQ drivers have been recognized correctly.

srsRAN Project

For srsRAN Project, the following commands can be used to download and build from source:

git clone https://github.com/srsran/srsRAN_Project.git
cd srsRAN_Project
mkdir build
cd build
make -j`nproc`

ZeroMQ is disabled by default, this is enabled when running cmake by including -DENABLE_EXPORT=ON -DENABLE_ZEROMQ=ON.

Pay extra attention to the cmake console output. Make sure you read the following line:

-- Checking for module 'ZeroMQ'
--   No package 'ZeroMQ' found
-- Found libZEROMQ: /usr/local/include, /usr/local/lib/libzmq.so


If you have not already done so, install the latest version of srsRAN 4G and all of its dependencies. This is outlined in the installation guide.

Please check our srsRAN 4G ZeroMQ Application Note for information on installing ZMQ and using it with srsRAN 4G/ srsUE.


Here, we use ZMQ-based setup, and hence the configuration files are based on those introduced in srsRAN gNB with srsUE application note.

The following config files were modified to use ZMQ-based RF driver and enable E2 interface in the srsRAN Project gNodeB:

Details of the modifications made are outlined in the following sections. The description of the remaining config parameters is available in srsRAN gNB with srsUE application note.

It is recommended you use these files to avoid errors while changing configs manually. Any configuration files not included here do not require modification from the default settings.


Here, we describe the gNB configuration parameters related to the E2 agent.

Enable E2 agents in all DUs and enable E2SM_KPM service module:

  enable_du_e2: true                # Enable DU E2 agent (one for each DU instance)
  e2sm_kpm_enabled: true            # Enable KPM service module
  addr:                   # RIC IP address
  port: 36421                       # RIC port

Enable E2AP packet captures and set the name of the output pcap file:

  e2ap_enable: true                 # Set to true to enable E2AP PCAPs.
  e2ap_filename: /tmp/gnb_e2ap.pcap # Path where the E2AP PCAP is stored.

Enable Enable RLC metrics reporting that will feed E2SM_KPM service model with measurements data:

  rlc_json_enable: 1                # Enable RLC metrics reporting
  rlc_report_period: 1000           # Set reporting period to 1s

Running the Network

The following order should be used when running the network:

  1. Open5GS

  2. NearRT-RIC

  3. gNB

  4. UE

  5. Start IP traffic (e.g., ping)

  6. xApp

Open5GS Core

srsRAN Project provides a dockerized version of the Open5GS. It is a convenient and quick way to start the core network. You can run it as follows:

cd ./srsRAN_Project/docker
docker compose up 5gc

Note that we have already configured Open5GS to operate correctly with srsRAN Project gNB. Moreover, the UE database is populated with the credentials used by our srsUE.


To start the ORAN SC RIC platform as a multi-container application, run the following command from the oran-sc-ric directory:

cd ./oran-sc-ric
docker compose up

Docker should download and build (when running for the first time) seven containers. When all containers are successfully deployed, the following message should be displayed on the NearRT-RIC console output:

ric_submgr          | RMR is ready now ...


We run gNB directly from the build folder (the config file is also located there) with the following command:

# when running with ORAN SC RIC
sudo ./gnb -c gnb_zmq.yaml e2 --addr="" --bind_addr=""

# when running with FlexRIC
sudo ./gnb -c gnb_zmq.yaml e2 --addr="" --bind_addr=""

The gNB console output should be similar to:

--== srsRAN gNB (commit 0b2702cca) ==--

Connecting to AMF on
Available radio types: zmq.
Connecting to NearRT-RIC on
Cell pci=1, bw=10 MHz, dl_arfcn=368500 (n3), dl_freq=1842.5 MHz, dl_ssb_arfcn=368410, ul_freq=1747.5 MHz

==== gNodeB started ===
Type <t> to view trace

The Connecting to AMF on message indicates that gNB initiated a connection to the core. While, the Connecting to NearRT-RIC on message indicates that gNB initiated a connection to the NearRT-RIC.

If the connection attempt is successful, the following (or similar) will be displayed on the NearRT-RIC console:

ric_rtmgr_sim       | 2024/04/02 11:07:39 POST /ric/v1/handles/associate-ran-to-e2t  body: [{"E2TAddress":"","ranNamelist":["gnb_001_001_00019b"]}] elapsed: 10.77µs


First, the correct network namespace must be created for the UE:

sudo ip netns add ue1

Next, we start srsUE. This is also done directly from within the build folder, with the config file in the same location:

sudo ./srsue ue_zmq.conf

If srsUE connects successfully to the network, the following (or similar) should be displayed on the console:

Built in Release mode using commit fa56836b1 on branch master.

Opening 1 channels in RF device=zmq with args=tx_port=tcp://,rx_port=tcp://,base_srate=11.52e6
Supported RF device list: UHD zmq file
CHx base_srate=11.52e6
Current sample rate is 1.92 MHz with a base rate of 11.52 MHz (x6 decimation)
CH0 rx_port=tcp://
CH0 tx_port=tcp://
Current sample rate is 11.52 MHz with a base rate of 11.52 MHz (x1 decimation)
Current sample rate is 11.52 MHz with a base rate of 11.52 MHz (x1 decimation)
Waiting PHY to initialize ... done!
Attaching UE...
Random Access Transmission: prach_occasion=0, preamble_index=0, ra-rnti=0x39, tti=334
Random Access Complete.     c-rnti=0x4601, ta=0
RRC Connected
PDU Session Establishment successful. IP:
RRC NR reconfiguration successful.

It is clear that the connection has been made successfully once the UE has been assigned an IP, this is seen in PDU Session Establishment successful. IP: The NR connection is then confirmed with the RRC NR reconfiguration successful. message.

IP Traffic with ping

Ping is the simplest tool to test the end-to-end connectivity in the network, i.e., it tests whether the UE and core can communicate. Here, we use it to generate traffic from UE, hence the gNB can measure data transmission-related metrics (e.g., throughput).

To run ping from UE to the core, use:

sudo ip netns exec ue1 ping -i 0.1

Note that we set the ping interval to 0.1s to increase the traffic volume.

Example ping output:

PING ( 56(84) bytes of data.
64 bytes from icmp_seq=1 ttl=64 time=32.2 ms
64 bytes from icmp_seq=2 ttl=64 time=35.3 ms
64 bytes from icmp_seq=3 ttl=64 time=38.2 ms
64 bytes from icmp_seq=4 ttl=64 time=71.5 ms
64 bytes from icmp_seq=5 ttl=64 time=32.9 ms

You can also ping the from core to the UE. First add a route to the UE on the host machine (i.e. the one running the Open5GS docker container):

sudo ip ro add via

Check the host routing table:

route -n

It should contain the following entries (note that Iface names might be different):

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface         UG    100    0        0 eno1     UG    0      0        0 br-dfa5521eb807   U     0      0        0 br-dfa5521eb807

Next, add a default route for the UE as follows:

sudo ip netns exec ue1 ip route add default via dev tun_srsue

Check the routing table of ue1:

sudo ip netns exec ue1 route -n

The output should be as follows:

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface         UG    0      0        0 tun_srsue   U     0      0        0 tun_srsue

Now ping the UE:

ping -i 0.1

In addition, iperf tool can be used to generate traffic at higher data rates than ping. For example, to send UL traffic from UE, one needs to run the following command:

sudo ip netns exec ue1 iperf -c -u -b 10M -i 1 -t 60


To start the provided example kpm_mon_xapp.py, run the following command from the oran-sc-ric directory:

docker compose exec python_xapp_runner ./kpm_mon_xapp.py --metrics=DRB.UEThpDl,DRB.UEThpUl --kpm_report_style=5

The xApp allows subscribing with all E2SM-KPM Report Styles (i.e., 1-5) and to set the metric names. With the above parameters, the xApp should subscribe to DRB.UEThpUl and DRB.UEThpUl measurements, and display the content of received RIC_INDICATION messages. The xApp console output should be similar to:

RIC Indication Received from gnb_001_001_00019b for Subscription ID: 5, KPM Report Style: 5
E2SM_KPM RIC Indication Content:
-ColletStartTime:  2024-04-02 13:24:56
-Measurements Data:
--UE_id: 0
---granulPeriod: 1000
---Metric: DRB.UEThpDl, Value: [7]
---Metric: DRB.UEThpUl, Value: [7]

On start, the xApp sends a subscription request to the NearRT-RIC, therefore the following (or similar) should be displayed on the NearRT-RIC console:

ric_rtmgr_sim       | 2024/04/02 13:35:33 POST /ric/v1/handles/xapp-subscription-handle  body: {"address":"","port":4560,"subscription_id":1} elapsed: 13.263µs

On exit, the xApp sends a subscription delete request to the NearRT-RIC and the following (or similar) should be displayed on the NearRT-RIC console:

ric_rtmgr_sim       | 2024/04/02 13:35:40 DELETE /ric/v1/handles/xapp-subscription-handle  body: {"address":"","port":4560,"subscription_id":1} elapsed: 27.513µs

E2AP packet analyzer

Enable E2AP PCAP

You can enable E2AP PCAPs by following this guide.

Live capture

Wireshark can be used to collect E2AP packets exchanged between E2 agent (located in srsRAN gNB) and NearRT-RIC at runtime. This requires the following steps to be executed:

  1. Start sniffing on the loopback interface.

  2. Set filter to sctp.port == 36421.

  3. Right-click on any packet -> Decode As.. -> set Current to E2AP

  4. Now filter can be set to e2ap to show only E2AP messages.

Note that at least Wireshark version 4.0.7 is needed to correctly decode and display E2AP packets (i.e., earlier Wireshark versions do not support E2APv3 protocol and as a result will display information about the Malformed Packets).

The figure below shows an example trace of E2AP packets.




E2AP dissector is still under development in Wireshark. Therefore, some fields are not decoded correctly in Wireshark version 4.0.7. Currently, the best option is to compile Wireshark from the source code. The screenshots presented in this tutorial were obtained with Wireshark version 4.1.0 (v4.1.0rc0-3390-g4f4a54e6d3f9).

Core Network not running

If the dockerized version of Open5Gs fails to run it may be due to the ports set in docker-compose.yml are already in use on your PC. For example, you may see an error like the following:

ERROR: for bdfcb7644f79_open5gs_5gc  Cannot start service 5gc: driver failed programming external connectivity on endpoint open5gs_5gc (2919e37332feb0a3001c44985b7e3d310ae82b7adb0e2cb1d9c214ed29ff39fa): Error starting userland proxy: listen tcp4 bind: address already in use

ERROR: for 5gc  Cannot start service 5gc: driver failed programming external connectivity on endpoint open5gs_5gc (2919e37332feb0a3001c44985b7e3d310ae82b7adb0e2cb1d9c214ed29ff39fa): Error starting userland proxy: listen tcp4 bind: address already in use
ERROR: Encountered errors while bringing up the project

In this case, the docker-compose file can be modified so that a different host port is used as 3000 is already in use. To do this, line 40 of the docker-compose.yml file can be update to use 3001 as the host port:

      container_name: open5gs_5gc
        context: open5gs
        target: open5gs
          OS_VERSION: "22.04"
          OPEN5GS_VERSION: "v2.6.1"
        SUBSCRIBER_DB: ${SUBSCRIBER_DB:-001010123456780,00112233445566778899aabbccddeeff,opc,63bfa50ee6523365ff14c1f45f88737d,8000,9,}
        OPEN5GS_IP: ${OPEN5GS_IP:-}
        UE_IP_BASE: ${UE_IP_BASE:-10.45.0}
        DEBUG: ${DEBUG:-false}
      privileged: true
-       - "3000:3000/tcp"
+       - "3001:3000/tcp"
      # Uncomment port to use the 5gc from outside the docker network
        #- "38412:38412/sctp"
      command: 5gc -c open5gs-5gc.yml
        test: [ "CMD-SHELL", "nc -z 7777" ]
        interval: 3s
        timeout: 1s
        retries: 60
          ipv4_address: ${OPEN5GS_IP:-}

UE issues

If the UE cannot connect to the network, ensure that the correct cell_cfg parameters are set in the gNB.

If the UE is connecting, but there is no PDU session being established you should check the following:

  • The APN configuration is the same across both the UE and Core

  • You are using the latest version of srsUE

  • IP Forwarding for the core has been enabled, you can do this by following this guide.

  • IP Forwarding for the UE has been enabled, see the following section

UE IP Forwarding

To ensure that the UE traffic is sent correctly to the internet the correct IP forwarding must be enabled. IP Forwarding should be enabled on the host machine, i.e. the one running the Open5GS docker container. This can be done with the following command:

sudo sysctl -w net.ipv4.ip_forward=1
sudo iptables -t nat -A POSTROUTING -o <IFNAME> -j MASQUERADE

Where <IFNAME> is the name of the interface connected to the internet.

To check that this has been configured correctly run the following command:

sudo ip netns exec ue1 ping -i 1

If the UE can ping the Google DNS, then the internet can be successfully accessed.

2nd Open5GS instance (installed manually)

The routing entries on the host PC for IPs: and should use the same interface, e.g.:

route -n

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface         UG    100    0        0 eno1     UG    0      0        0 br-dfa5521eb807   U     0      0        0 br-dfa5521eb807

However, if a second instance of Open5GS (that was installed manually) is running on the host PC, the route to goes to ogstun interface. For this reason, a UE cannot access the Internet, as the host will send packets to the manually installed Open5GS version. To solve this routing issue, you can disable (or even remove) the manually installed Open5GS – please check sections 6 and/or 7 of the Open5GS tutorial. In addition, you might need to disable the ogstun interface with the following command:

sudo ifconfig ogstun down

RIC running on a different machine

If you are running your RIC on a different machine, you will need to correctly configure the E2 bind_addr parameter in the gNB config file. This is shown in the example config, with the line commented out. If you are running the RIC on a separate machine simply uncomment this option.