Lab 5: Building a KPM+RC xApp for RAN Slicing
This experiment is to deploy a 5G Standalone (SA) network using OpenAirInterface (OAI) RF Simulator gNB and OAI minimal 5GC. We also deploy FlexRIC as the Near-RT RIC. Finally a KPM+RC xApp for RAN Slicing will be deployed on bare-metal connecting to the RIC.
apiVersion: athena.trirematics.io/v1
kind: Network
metadata:
name: bubbleran
namespace: trirematics
spec:
slices:
- plmn: "00101"
dnn: "internet"
network-mode: "IPv4"
service-type: eMBB
differentiator: 0x000000
ipv4-range: "12.1.1.0/24"
ipv6-range: "2001:db8:1::/64"
access:
- name: oai-gnb
stack: 5g-sa
model: oai-ran/monolithic-gnb
identity:
an-id: 50
radio:
device: rf-sim
cells:
- band: n78
arfcn: 641280
bandwidth: 40MHz
subcarrier-spacing: 30kHz
tdd-config:
period: 5ms
dl-slots: 7
dl-symbols: 6
ul-slots: 2
ul-symbols: 4
controller: flexric.bubbleran
core-networks:
- minimal.bubbleran
core:
- name: minimal
stack: 5g-sa
model: oai-cn/minimal
identity:
region: 0
cn-group: 4
cn-id: 5
dns:
ipv4:
default: 8.8.8.8
secondary: 8.8.4.4
edge:
- name: flexric
stack: 5g-sa
model: mosaic5g/flexric
---
apiVersion: athena.trirematics.io/v1
kind: Terminal
metadata:
name: ue1
namespace: trirematics
spec:
vendor: oai
stack: 5g-sa
model: terminal/nr-rfsim
preferred-access: oai-gnb.bubbleran
target-cores:
- minimal.bubbleran
identity:
imsi: "001010000000001"
pin: "1234"
opc: "0xc42449363bbad02b66d16bc975d77cc1"
key: "0xfec86ba6eb707ed08905757b1bb44b8f"
sqn: "0xff9bb4000001"
slice:
dnn: "internet"
network-mode: "IPv4"
service-type: eMBB
differentiator: 0x000000
radio:
bands:
- n78
readiness-check:
method: ping
target: google-ip
interface-name: oaitun_ue0
---
apiVersion: athena.trirematics.io/v1
kind: Terminal
metadata:
name: ue2
namespace: trirematics
spec:
vendor: oai
stack: 5g-sa
model: terminal/nr-rfsim
preferred-access: oai-gnb.bubbleran
target-cores:
- minimal.bubbleran
identity:
imsi: "001010000000002"
pin: "1234"
opc: "0xc42449363bbad02b66d16bc975d77cc1"
key: "0xfec86ba6eb707ed08905757b1bb44b8f"
sqn: "0xff9bb4000001"
slice:
dnn: "internet"
network-mode: "IPv4"
service-type: eMBB
differentiator: 0x000000
radio:
bands:
- n78
readiness-check:
method: ping
target: google-ip
interface-name: oaitun_ue0
Deployment
Use the command brc install network open-ran.yaml to deploy the network.
It should finish without errors and printout the three Kubernetes resource names that were created.
Check for the status of the deployment using the command brc observe.
Wait until all the Elements other than the UE are in the STATUS set to
1/1 Y state.
After deploying the network you should update the xApp configuration file with the IP of the deployed Near RT-RIC and the local source IP in the cluster subnet.
To do so you may deploy the update_conf.py script which automatically extract the IPs from the cluster and updated the specified configuration file:
cd /path/to/xapp-sdk/conf
python3 update_conf.py xapp.yaml
The script will prompt the user for selecting which Near RT-RIC the xApp should connect to (in case of multiple RICs and/or networks currently deployed). After selecting a RIC to connect an output as the follwing is obtained:
Select the RIC to configure:
1) flexric.flexric.handover (10.244.2.46)
Choice [1-1]: 1
No entries found for Database.
Skipping database IP update.
Config 'xapp.yaml' updated: ip_ric=10.244.2.46, ip_xapp=10.244.0.158
Once the configuration file has been updated accordingly, now the Hello world xApp can be run.
KPM+RC RAN Slicing xApp (C)
You can find the following xApp code at path/to/your/xapp_sdk/labs/
/*
Copyright (C) 2021-2025 BubbleRAN SAS
External application
Last Changed: 2025-05-02
Project: MX-XAPP
Full License: https://bubbleran.com/resources/files/BubbleRAN_Licence-Agreement-1.3.pdf)
*/
#include <assert.h>
#include <stdatomic.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include "xapp_sdk_api.h"
static global_e2_node_id_sdk_t* node= NULL;
static _Atomic int dedicated_prb = 10;
static int clamp(int min, int max, int v)
{
if(v < min)
return min;
if(v > max)
return max;
return v;
}
static void cb_fn(float ue_thp_kbs, uint32_t ric_req_id)
{
printf(" ue_thp_kbs %lf \n", ue_thp_kbs);
if(ue_thp_kbs > 29999.9 && ue_thp_kbs < 35000.1)
return;
int new_dedicated_prb = dedicated_prb;
if(ue_thp_kbs < 30000){
new_dedicated_prb += 2;
} else if(ue_thp_kbs > 35000){
new_dedicated_prb -= 2;
} else {
assert(0!=0 && "Impossible path!");
}
int const min = 10;
int const max = 100;
dedicated_prb = clamp(min, max, new_dedicated_prb);
char* const sst = "0";
char* const sd = "1";
// Step 3
// Call the function slice_xapp_sdk with the correct arguments
printf("Dedicated PRBs %d\n", dedicated_prb);
}
int main(int argc, char** argv)
{
// Step 1
// Init the xapp SDK
arr_node_data_t arr_mon = node_data_xapp_sdk(MONITOR_USE_CASE_e);
assert(arr_mon.sz > 0 && "At least one gNB needed for monitoring");
node = &arr_mon.n[0].node;
ue_id_e2sm_sdk_t const* ue = &arr_mon.n[0].ue_ho[0].ue;
// Step 2
// call ue_mntr_cb_xapp_sdk to monitor UE_THP_DL with periodicity of 1 second
// and the callback function cb_fn
sleep(60);
// printf("Stopping ric_req_id %u\n", stop.ric_req_id);
// Step 3
// Stop the callback
free_arr_node_data(&arr_mon);
return EXIT_SUCCESS;
}
If changes are made, in order to compile this xApp you should run:
cd /path/to/xapp_sdk/build
cmake ..
make -j
sudo make install
ldconfig
Then in order to run it:
./build/labs/lab5 conf/xapp.yaml
If run successfully the output should look as follows:
10:15:07.552586 [INFO]: e42_xapp.c:191 NearRT-RIC Server IP Address = 10.244.2.155, PORT = 36422
10:15:07.552634 [INFO]: emb_sm_ag.c:93 Loaded SM(s) 10, custom SMs true
10:15:07.552643 [INFO]: emb_sm_ric.c:93 Loaded SM(s) 10, custom SMs true
10:15:07.553128 [INFO]: msg_handler_xapp.c:533 E42 SETUP-REQUEST tx
10:15:07.553321 [INFO]: msg_handler_xapp.c:374 E42 SETUP-RESPONSE rx xApp ID 8
10:15:07.553326 [INFO]: msg_handler_xapp.c:390 Connected E2 Node(s) 1
10:15:07.553444 [INFO]: msg_handler_xapp.c:568 RIC_SUBSCRIPTION_REQUEST tx RAN_FUNC_ID 2 RIC_REQ_ID 1
10:15:07.553736 [INFO]: msg_handler_xapp.c:155 RIC_SUBSCRIPTION_RESPONSE rx RAN_FUNC_ID 2 RIC_REQ_ID 1
10:15:07.554830 [INFO]: msg_handler_xapp.c:581 RIC_SUBSCRIPTION_DELETE_REQUEST tx RAN_FUNC_ID 2 RIC_REQ_ID 1
10:15:07.554998 [INFO]: msg_handler_xapp.c:195 RIC_SUBSCRIPTION_DELETE_RESPONSE RAN_FUNC_ID 2 rx RIC_REQ_ID 1
10:15:07.555039 [INFO]: msg_handler_xapp.c:568 RIC_SUBSCRIPTION_REQUEST tx RAN_FUNC_ID 2 RIC_REQ_ID 2
10:15:07.555188 [INFO]: msg_handler_xapp.c:155 RIC_SUBSCRIPTION_RESPONSE rx RAN_FUNC_ID 2 RIC_REQ_ID 2
ue_thp_kbs 53996.945312
10:15:08.555652 [INFO]: msg_handler_xapp.c:613 E42_RIC_CONTROL_REQUEST RAN_FUNC_ID 3 RIC_REQ_ID 3 tx
10:15:08.556002 [INFO]: msg_handler_xapp.c:306 CONTROL ACK rx RIC_REQ_ID 3
dedicated_prb 28
ue_thp_kbs 72742.992188
10:15:09.555626 [INFO]: msg_handler_xapp.c:613 E42_RIC_CONTROL_REQUEST RAN_FUNC_ID 3 RIC_REQ_ID 4 tx
10:15:09.555992 [INFO]: msg_handler_xapp.c:306 CONTROL ACK rx RIC_REQ_ID 4
dedicated_prb 26
ue_thp_kbs 67693.304688
10:15:10.555622 [INFO]: msg_handler_xapp.c:613 E42_RIC_CONTROL_REQUEST RAN_FUNC_ID 3 RIC_REQ_ID 5 tx
10:15:10.556741 [INFO]: msg_handler_xapp.c:306 CONTROL ACK rx RIC_REQ_ID 5
dedicated_prb 24
ue_thp_kbs 63974.703125
10:15:11.555614 [INFO]: msg_handler_xapp.c:613 E42_RIC_CONTROL_REQUEST RAN_FUNC_ID 3 RIC_REQ_ID 6 tx
10:15:11.555922 [INFO]: msg_handler_xapp.c:306 CONTROL ACK rx RIC_REQ_ID 6
dedicated_prb 22
ue_thp_kbs 59206.207031
10:15:12.555629 [INFO]: msg_handler_xapp.c:613 E42_RIC_CONTROL_REQUEST RAN_FUNC_ID 3 RIC_REQ_ID 7 tx
10:15:12.556029 [INFO]: msg_handler_xapp.c:306 CONTROL ACK rx RIC_REQ_ID 7
dedicated_prb 20
ue_thp_kbs 54966.601562
10:15:13.555646 [INFO]: msg_handler_xapp.c:613 E42_RIC_CONTROL_REQUEST RAN_FUNC_ID 3 RIC_REQ_ID 8 tx
10:15:13.556090 [INFO]: msg_handler_xapp.c:306 CONTROL ACK rx RIC_REQ_ID 8
dedicated_prb 18
ue_thp_kbs 48162.304688
10:15:14.555603 [INFO]: msg_handler_xapp.c:613 E42_RIC_CONTROL_REQUEST RAN_FUNC_ID 3 RIC_REQ_ID 9 tx
10:15:14.555920 [INFO]: msg_handler_xapp.c:306 CONTROL ACK rx RIC_REQ_ID 9
dedicated_prb 16
ue_thp_kbs 41433.054688