Guide for deploying an xApp with xDevSM and examples of the effective usage of the xDevSM framework.
This guide provides an overview of deploying an xApp based on the xDevSM framework and offers examples of how to use it effectively. For detailed information about the framework’s structure, refer to this paper.
Before you begin, ensure you have the following prerequisites installed and configured:
These tools are necessary for building and creating Helm charts for your xApp.
A complete guide on how to set-up a single-node k8s cluster to host the Near-RT RIC can be found here.
Download helm binary
# The version we download is the one indicated by ORAN SC in their RIC installation guides
wget https://get.helm.sh/helm-v3.11.2-linux-amd64.tar.gz
tar xvzpf helm-v3.11.2-linux-amd64.tar.gz
Install helm
sudo cp linux-amd64/helm /usr/local/bin/
Try it
helm version
The official guide is available here.
Note: The official guide contains an error:
./install -f ../RECIPE_EXAMPLE/example_recipe_oran_i_release.yamlit should be./install -f ../RECIPE_EXAMPLE/example_recipe_oran_j_release.yamlinstead.
Clone the repository:
git clone https://github.com/o-ran-sc/ric-plt-ric-dep.git
cd ric-plt-ric-dep
git checkout j-release
Install chartmuseum and common charts:
# be sure to be in the 'bin' folder
cd bin
# This script will create a docker container running chartmuseum and will create a repo with common charts used to build the ric
sudo ./install_common_templates_to_helm.sh
Deploy the near-RT RIC using the install script:
./install -f ../RECIPE_EXAMPLE/example_recipe_oran_j_release.yaml
Check if the Near-RT RIC is running:
kubectl get pods -n ricplt
If you’re running Kubernetes on bare metal or virtualized hardware (not using Minikube), be sure to expose the e2term service.
kubectl -n ricplt expose deployment deployment-ricplt-e2term-alpha --protocol=SCTP --port=36422 --target-port=36422 --external-ip=<local-ip-nrric> --name=sctp-service
The dms_cli tool facilitates xApp onboarding and deployment. It uses the xApp descriptor and an additional schema file to generate xApp Helm charts.
git clone https://github.com/o-ran-sc/ric-plt-appmgr.git
# Switch to the branch corresponding to the Near-RT RIC
git checkout j-release
# go inside xapp onboarder
cd ric-plt-appmgr/xapp_orchestrater/dev/xapp_onboarder
# installing python 3.9 (needed for this repo)
sudo add-apt-repository ppa:deadsnakes/ppa
sudo apt update
# installing python and python venv
sudo apt install python3.9-dev python3.9-venv
# create virtual environment
python3.9 -m venv .venv
# activate the virtual environment
. .venv/bin/activate
# install requirements
pip install -r requirements.txt
pip install .
⚠️ WARNING: if you get this error: bash error: invalid command ‘bdist_wheel’ just run pip install wheel
⚠️ WARNING: if you get an error with fire package just run pip install –upgrade pip setuptools wheel importlib_metadata
❗ Note: Be sure to use the virtual environment .venv just created (. .venv/bin/activate) to call the dms_cli command
⚠️ WARNING: if you get this error ModuleNotFoundError: No module named ‘pkg_resources’ run pip install “setuptools<70”
By default xDevSM supports KPM V3.00 and RC V1.03
Clone the examples repository and initialize xDevSM as a submodule:
git clone https://github.com/wineslab/xDevSM-xapps-examples.git
cd xDevSM-xapps-examples
git submodule init
git submodule update
xDevSM relies on the decorator design pattern. So, we need to attach new behaviors to objects by placing these objects inside special wrapper objects that contain the behaviors. General object where we need to attach new behaviors in xDevSM is xDevSMRMRXapp.
The directory structure for each xApp follows this convention:
<xapp_name>/
│── <xapp_name>.py
│── setup_imports.py
│── requirements.txt
├── config/
│ ├── config-file.json
│ └── schema.json
docker/
└── Dockerfile.<xapp_name>
Creating a generic xDevSM RMR xApp:
xapp_gen = xDevSMRMRXapp("0.0.0.0", route_file=args.route_file)
# Adding kpm APIs to the xapp
kpm_xapp = XappKpmFrame(xapp_gen,
xapp_gen.logger,
xapp_gen.server,
xapp_gen.get_xapp_name(),
xapp_gen.rmr_port,
xapp_gen.http_port,xapp_gen.get_pltnamespace(),
xapp_gen.get_app_namespace())
# Registering the outermost rmr handler
xapp_gen.register_handler(kpm_xapp.handle)
# Getting RAN Functions decoded
ran_function_description = kpm_xapp.get_ran_function_description(json_ran_info=gnb_info)
# Subscribe to an E2 Node
kpm_xapp.subscribe(gnb=gnb, ev_trigger=ev_trigger_tuple, func_def=func_def_dict, ran_period_ms=1000, sst=args.sst, sd=args.sd)
Take a look at this xApp to see how you can use multiple service models functionalities.
Once created you need to build and deploy your xApp.
Docker file: xDevSM-xapps-examples/docker/Dockerfile.kpm_basic_xapp.dev.
For automatic running:
# No parameters used
CMD ["python", "kpm_xapp.py"]
# Influx
CMD python3 kpm_xapp.py --influx_end_point http://<ip>:port -o <org> -t <token> -b <bucket>
# You may use other parameters like gnb_target, ssd, and sd
Important note:
ENV PLT_NAMESPACE="ricplt-j"change this in the dockerfile based on your deployment
For manual running:
ENTRYPOINT ["sleep", "infinity"]
Then build the image as outlined here.
Note: A full table of the supported service model can be found here
In this repository, you can find an example of a complete KPM xApp. This xApp can store KPM data in CSV files, InfluxDB and Redis. It subscribes to a single E2 node, which can be specified as an input parameter or defaults to the first available node to reply.
Clone the repository as previously mentioned.
Note: The following steps are general, so you can also apply them to build the image of your custom xApp.
Build the Image of the xApp:
Note: names and tag should match with those specified in the config files
docker build --tag kpm-basic-xapp:0.3.0-dev --file docker/Dockerfile.kpm_basic_xapp.dev .
Important Note: Make sure the image name and tag match those specified in
config/config-file.json. Also update theAPP_NAMESPACEfield in the config file to match your deployment’s namespace (e.g.,ricxapp-j).
Push the image to a registry (e.g., Docker Hub):
docker tag kpm-basic-xapp:0.3.0-dev <your_username>/kpm-basic-xapp:0.3.0-dev # use the versioning you want
docker push <your_username>/kpm-basic-xapp:0.3.0-dev # use the versioning you want
Change the xApp config file (xapps-repo → kpm_basic_xapp → config):
// config-file.json
//...
"name": "kpm-basic-xapp",
"version": "0.3.0-dev",
"APP_NAMESPACE": "ricxapp-j",
"containers": [
{
"name": "kpm-basic-xapp",
"image": {
"registry": "docker.io",
"name": "angeloferaudo/kpm-basic-xapp",
"tag": "0.3.0-dev"
}
}
],
Important Note: change the
APP_NAMESPACEwith the one used in your deployment.
To begin, ensure you have an instance of ChartMuseum running. You can do this either locally or through a Docker container:
docker run --rm -u 0 -it -d -p 8090:8080 \
-e DEBUG=1 -e STORAGE=local -e STORAGE_LOCAL_ROOTDIR=/charts \
-v $(pwd)/charts:/charts chartmuseum/chartmuseum:latest
export CHART_REPO_URL=http://0.0.0.0:8090
Once ChartMuseum is running, you can onboard the xApp:
dms_cli onboard \
--config-file-path <kpm-basic-xapp-path>/config/config-file.json \
--shcema_file_path <kpm-basic-xapp-path>/config/schema.json
To download the Helm chart for your xApp, use:
dms_cli download_helm_chart kpm-basic-xapp 0.3.0.dev # change name and version accordingly
Note: You can also do this using
dms_cli install. Please refer to this tutorial.
Once the Helm chart is downloaded, install it into the xApp namespace:
helm install kpm-basic-xapp kpm-basic-xapp-0.3.0.dev.tgz -n ricxapp-j
The official tutorial on connecting SRS RAN to the OSC Near-RT RIC can be found here.
Update the gNB configuration file as follows:
e2:
enable_du_e2: true # Enable DU E2 agent (one for each DU instance)
e2sm_kpm_enabled: true # Enable KPM service module
addr: <near-rt-ric-address> # RIC IP address
#bind_addr: 127.0.0.100 # A local IP that the E2 agent binds to for traffic from the RIC. ONLY required if running the RIC on a separate machine.
port: 36422 # RIC port
When running the gNB, bind it to the local address:
sudo ./gnb -c customConfigs/gnb_zmq.yaml e2 --addr=<near-rt-ric-address> --bind_addr=<local-address>
To connect OAI RAN to the Near-RT RIC, you need to build the gNB with the E2 agent enabled.
The official documentation is available here.
After cloning the repository initialize the submodules:
git clone https://gitlab.eurecom.fr/oai/openairinterface5g.git
cd openairinterface5g
# this downloads the flexric repository within the openairinterface5g project
# directory openair2/E2AP/flexric
git submodule init
git submodule update
Note: to build the Service Models use
gcc-12
Build and install the Service Models:
cd openair2/E2AP/flexric
mkdir build
cd build
cmake .. -DKPM_VERSION=KPM_V3_00
make -j ${nproc}
sudo make install
Take note of the directory where the service models are installed.
Build gnb with the build-e2 option enabled:
# THIS IS JUST AN EXAMPLE, USE THE OPTION YOU NEED ONLY + --build-e2
./build_oai --build-e2 --ninja --gNB --nrUE --ninja --cmake-opt -DKPM_VERSION=KPM_V3_00
Enable the E2 connection by updating the gNB configuration file:
e2_agent = {
near_ric_ip_addr = "127.0.0.1"; // near-RT RIC address
sm_dir = "/usr/local/lib/flexric/" // service model directory --> CHANGE THIS ACCORDINGLY
}
Note: by default the OAI E2 Agent uses a different port to connect to the near-RT RIC. This is hard-coded. You may have two solutions: 1. expose the e2term service on a different port (on the RIC); 2. change the e2 agent code and rebuild.
Run the gNB:
# Adjust options for your deployment (real/simulated)
sudo ./nr-softmodem -O <configuration_file> --gNBs.[0].min_rxtxtime 6 --rfsim --rfsimulator.serveraddr server
A. Feraudo, S. Maxenti, A. Lacava, P. Bellavista, M. Polese, and T. Melodia, "xDevSM: Streamlining xApp Development With a Flexible Framework for O-RAN E2 Service Models," in Proceedings of ACM WiNTECH, Washington, D.C., USA, November 2024. [pdf]
Feraudo, A., Maxenti, S., Lacava, A., Bonati, L., Bellavista, P., Polese, M., & Melodia, T., "xDevSM: An Open-Source Framework for Portable, AI-Ready xApps Across Heterogeneous O-RAN Deployments," arXiv:2602.03821 [cs.NI], pp. 1–12, January 2026. [pdf]