Lab 10: Collect SRS I/Q samples via ORAN LLC SM
This experiment deploys a 5G Standalone (SA) network using OpenAirInterface (OAI) gNB and OAI minimal 5GC. Additionally, deploys FlexRIC as the Near-RT RIC. Finally O-RAN LLC SM xApp for extracting uplink Sounding Reference Signal (SRS) I/Q samples is deployed on bare-metal connecting to the RIC.
This lab is only meant to be performed using OAI RAN on Over-the-Air deployments (i.e. using USRP, LITEON RU or Benetel RU) The sample network template file is for a deployment with LITEON RU, for USRP and Benetel RU, refer to our Github blueprint repository.
open-ran-liteon.yaml
apiVersion: athena.trirematics.io/v1
kind: Network
metadata:
name: bubbleran
namespace: trirematics
spec:
slices:
- plmn: "00101"
dnn: internet
network-mode: IPv4
service-type: 1
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-ru #cu-du-ru
identity:
an-id: 30
tracking-area: 1
radio:
device: oran-7.2
antenna:
formation: 4x4
annotations:
extras.t9s.io/ru-vendor: 'liteon' # or 'benetel'
cells:
- band: n78
arfcn: 650016 # n78, 3.5GHz, 100MHz bandwidth
bandwidth: 100MHz
subcarrier-spacing: 30kHz
tdd-config:
period: 2500
dl-slots: 3
dl-symbols: 6
ul-slots: 1
ul-symbols: 4
core-networks:
- open5gs.bubbleran
controller: flexric.bubbleran
core:
- name: open5gs
stack: 5g-sa
model: open5gs/5gc
scheduling:
nodeName: jogo
profiles:
- debug
identity:
region: 128
cn-group: 4
cn-id: 5
edge:
- name: flexric
stack: 5g-sa
model: mosaic5g/flexric
dns:
ipv4:
default: 8.8.8.8
secondary: 8.8.4.4
Deployment​
Use the command brc install network open-ran-liteon.yaml to deploy the network.
It should finish without errors and print out 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.
Please refer to this guide for detailed steps to run pre-checks before deploying networks using O-RAN 7.2 FHI with LITEON RU.
After deploying the network, before running the xApp, you should update the xApp configuration file with the IP of the deployed Near-RT RIC, the local source IP in the cluster subnet and the deployed database.
To do so you may execute the update_conf.py script which automatically extract the IPs from the cluster and updates the specified configuration file:
cd /path/to/xapp_sdk/conf
python3 update_conf.py xapp.yaml
Once the network is deployed, traffic can be generated between the UEs and the network with the following commands:
brc test throughput ue1 dl gateway -- -t 600
brc test throughput ue2 dl gateway -- -t 600
With the brc test throughput tool the user can generate iperf traffic from the UPF (gateway) to the UE for downlink traffic (dl) or vice-versa for uplink (ul).
For more details you may check the BubbleRAN CLI reference.
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). If the configuration file also defines the database information, the script will prompt the user to specify which database in the deployed network to connect to.
After selecting a RIC and database to connect, an output as the following is obtained:
Select the RIC to configure:
1) flexric.flexric.bubbleran (10.244.1.75 - trirematics, pod)
Choice [1-1]: 1
Select the Database to configure:
1) vmsingle-vmks-victoria-metrics-k8s-stack (10.106.214.123 - monitoring, svc)
Choice [1-1]: 1
Port-forwarding enabled for vmsingle-vmks-victoria-metrics-k8s-stack on port 8428.
Enter the scenario name for VictoriaMetrics: lab10
Config 'xapp.yaml' updated: ip_ric=10.244.1.75, ip_xapp=10.244.0.235, db.ip=localhost
If VictoriaMetrics is the selected database, the user should build the targets with VICTORIAMETRICS_XAPP CMakeList as shown in the Build and Install section.
For VictoriaMetrics, the script will automatically port-forward database to http://localhost:8428. It will also prompt for the scenario name to be configured for the xapp (lab10 in the example). Please, refer to xApp Generated Metrics to know more about it.
Once the configuration file is updated, the LLC xApp can run.
O-RAN LLC xApp​
This xApp first sends an RC SM subscription to the E2 node to find the UEs connected to it, and selects the first UE that reports a ran_ue_id.
It then uses the LLC Service Model to subscribe to aperiodic SRS event triggers generated by that UE, and stays subscribed for 10 seconds.
In its callback, it unpacks each indication message and reads the raw 16-bit I/Q pairs of every receive antenna and SRS symbol.
Depending on the header of the symbol, the buffer holds only the received SRS, or the received SRS together with the noise and the estimated channel.
The values are written to text files.
Only the first UE with a ran_ue_id is monitored, and a warning is printed if more UEs are found. UEs without a ran_ue_id are skipped. If the RC response contains no eligible UE, the xApp exits after a 10-second timeout without subscribing to LLC.
To collect the SRS of another UE, modify cb_sm_rc() in xapp_oran_llc_moni_srs.c to select it by its ran_ue_id.
The callback in xapp_oran_llc_moni_srs.c that saves the received I/Q samples locally is defined as follows:
static void cb_sm_llc(sm_ag_if_rd_t const *rd, global_e2_node_id_t const *n)
{
assert(n != NULL);
assert(rd != NULL);
assert(rd->type == INDICATION_MSG_AGENT_IF_ANS_V0);
assert(rd->ind.type == LLC_STATS_V1_0);
llc_ind_data_t const* ind = &rd->ind.llc.ind;
assert(ind->msg.format == FORMAT_1_E2SM_LLC_IND_MSG && "Only Aperiodic event supported");
e2sm_llc_ind_msg_frmt_1_t const* frmt_1 = &ind->msg.frmt_1;
assert(frmt_1->ll_info_type == SRS_LL_INFO_TYPE_E && "srs samples expected");
// ue_id is set in cb_sm_rc only for a UE with a ran_ue_id
uint64_t const* ran_ue_id = get_ran_ue_id(&ue_id);
assert(ran_ue_id != NULL);
int64_t t0 = 0;
memcpy(&t0,frmt_1->slot_tstamp.slot_start_time, 8);
printf("receive ind msg from E2 node id %u, msg latency %lu us (ran_ue_id %lu)\n", n->nb_id.nb_id, time_now_us() - t0, *ran_ue_id);
for(size_t i = 0; i < frmt_1->srs.sz_srs_rx_antenna; i++) {
srs_rx_antenna_t* rx = &frmt_1->srs.rx[i];
for (size_t j = 0; j < rx->sz_srs_symbols; j++) {
srs_symbol_t* symbol = &rx->symbol[j];
uint8_t hdr = rx->symbol->hdr;
byte_array_t raw_iq = symbol->raw_iq;
// case1: raw_iq includes one type of I/Q sample: rx srs
if (hdr == 1) {
size_t sz = raw_iq.len / 4; // sizeof(c16_t) = 4
char filename_rx[256] = {0};
size_t rc = snprintf(filename_rx, sizeof(filename_rx),
"iq_srs_rx_ant%lu_symbol%lu_nbid%u_ueid%lu.txt", i, j, n->nb_id.nb_id, *ran_ue_id);
assert(rc < 256);
(void)rc;
write_iq_text(filename_rx, raw_iq.buf, sz, t0);
}
// case2: raw_iq includes three types of I/Q sample: rx srs, noise, estimated channel
else {
size_t sz = raw_iq.len / 3 / 4; // rx, noise, estimated // sizeof(c16_t) = 4
// Offsets in bytes
size_t rx_offset = 0;
size_t noise_offset = 4 * sz;
size_t est_offset = 4 * sz * 2;
char filename_rx[256], filename_noise[256], filename_estimated[256] = {0};
size_t rc = snprintf(filename_rx, sizeof(filename_rx),
"iq_srs_rx_ant%lu_symbol%lu_nbid%u_ueid%lu.txt", i, j, n->nb_id.nb_id, *ran_ue_id);
assert(rc < 256);
(void)rc;
write_iq_text(filename_rx, raw_iq.buf + rx_offset, sz, t0);
rc = snprintf(filename_noise, sizeof(filename_noise),
"iq_srs_noise_ant%lu_symbol%lu_nbid%u_ueid%lu.txt", i, j, n->nb_id.nb_id, *ran_ue_id);
assert(rc < 256);
write_iq_text(filename_noise, raw_iq.buf + noise_offset, sz, t0);
rc = snprintf(filename_estimated,
sizeof(filename_estimated),
"iq_srs_estimated_ant%lu_symbol%lu_nbid%u_ueid%lu.txt", i, j, n->nb_id.nb_id, *ran_ue_id);
assert(rc < 256);
(void)rc;
write_iq_text(filename_estimated, raw_iq.buf + est_offset, sz, t0);
}
}
}
}
The user can compile this xApp from the terminal:
cd /path/to/xapp_sdk/build
cmake ..
make -j8
sudo make install
sudo ldconfig
To run it:
cd /path/to/xapp_sdk
./build/src/dev/c/xapp_oran_llc_moni_srs conf/xapp.yaml
If ran successfully the output should be as follows:
$ ./build/src/dev/c/xapp_oran_llc_moni_srs conf/xapp.yaml
17:42:41.023848 [INFO]: e42_xapp_api.c:93
##########################################################################################
##########################################################################################
##########################################################################################
Copyright (C) 2021-2026 BubbleRAN SAS
Project: MX-RIC
Full License: https://bubbleran.com/resources/files/BubbleRAN_Licence-Agreement-1.3.pdf
##########################################################################################
##########################################################################################
##########################################################################################
17:42:41.023948 [INFO]: e42_xapp_api.c:97 Git SHA1 f04542cfbbb694c803cd76f13b45eb9689b16cff
17:42:41.023956 [INFO]: xapp_conf.c:196 Configuration file path conf/xapp.yaml
17:42:41.024013 [INFO]: xapp_conf.c:201 ---------------------------------------------------
17:42:41.024022 [INFO]: xapp_conf.c:202 Configuration file encoded in base64. To decode use $base64 --decode tmp.txt
17:42:41.024022 [INFO]: xapp_conf.c:203 ---------------------------------------------------
17:42:41.024023 [INFO]: xapp_conf.c:204
eGFwcDoKICAgIGlwX3JpYzogMTI3LjAuMC4xCiAgICBlNDJfcG9ydDogMzY0MjIKICAgICMgSVAgdG8gYmluZCBTQ1RQIGNsaWVudAogICAgIyBOZWVkcyB0byBiZSBpbiB0aGUgcmFuZ2Ugb2YKICAgICMgaXBfcmljLiBJdCBpcyB0aGUgaW50ZXJmYWNlCiAgICAjIGZyb20gaWZjb25maWcgY21kCiAgICBpcF94YXBwOiAxMjcuMC4wLjEKICAgIHNtX2RpcjogL3Vzci9sb2NhbC9saWIvZmxleHJpYy8KICAgIGxvZzogMgogICAgICAgICMgdHJhY2U6IDAKICAgICAgICAjIGRlYnVnOiAxCiAgICAgICAgIyBpbmZvOiAyCiAgICAgICAgIyB3YXJuOiAzCiAgICAgICAgIyBlcnJvcjogNAogICAgICAgICMgZmF0YWw6IDUKICAgICAgICAjIGUuZy4sIGxldmVsID0gMiAtPiBsZXZlbCA9IGluZm8KICAgICMgQ29tbWVudCB0aGUgZGF0YWJhc2Ugc2VjdGlvbgogICAgIyBpZiBubyBkYXRhYmFzZSBpcyBuZWVkZWQvdXNlZAogICAgI2RiOgogICAgICAgICNpcDogMTI3LjAuMC4xCiAgICAgICAgI3BvcnQ6IDg0MjgKICAgICAgICAjZmlsZW5hbWU6IHNjZW5hcmlvICAjVGhpcyByZWZlcnMgdG8gdGhlIHNjZW5hcmlvIG5hbWUgKHRhZykgaW4gdmljdG9yaWEgbWV0cmljcwogICAgICAgIAogICAgICAgICMjIG15c3FsIHBhcmFtZXRlcnMgKG5vdCB1c2VkIGZvciB2aWN0b3JpYSBtZXRyaWNzKQogICAgICAgICNkaXI6IC90bXAvCiAgICAgICAgI3VzcjogeGFwcAogICAgICAgICNwc3c6IEJ1YmJsZVJBTgogICAgICAgICNmaWxlbmFtZTogdGVzdGRiCiAgICAgICAgIyBDb21tYW5kcyBmb3Igc2V0dGluZyB1cCBteXNxbAogICAgICAgICMgJCBzdWRvIG15c3FsCiAgICAgICAgIyAkIG15c3FsPiBDUkVBVEUgVVNFUiAndXNlcm5hbWUnQCdsb2NhbGhvc3QnIElERU5USUZJRUQgQlkgJ3Bhc3N3b3JkJzsKICAgICAgICAjICQgbXlzcWw+IGdyYW50IGFsbCBwcml2aWxlZ2VzIG9uICouKiB0byAndXNlcm5hbWUnQCdsb2NhbGhvc3QnOwogICAgICAgICMgJCBteXNxbD4gZXhpdAoK
17:42:41.024024 [INFO]: xapp_conf.c:205 ---------------------------------------------------
17:42:41.024024 [INFO]: xapp_conf.c:206 ---------------------------------------------------
17:42:41.024025 [INFO]: xapp_conf.c:207 ---------------------------------------------------
17:42:41.024071 [INFO]: e42_xapp.c:161 NearRT-RIC Server IP Address = 10.244.1.202, PORT = 36422
17:42:41.024072 [INFO]: e42_xapp.c:162 xApp IP Address = 10.244.0.158
17:42:41.024118 [INFO]: endpoint_xapp.c:74 [xApp]: SCTP client bind to IP 10.244.0.158, Port 40457
17:42:41.024181 [INFO]: emb_sm_ag.c:95 Loaded SM(s) 11, custom SMs true
17:42:41.024229 [INFO]: emb_sm_ric.c:95 Loaded SM(s) 11, custom SMs true
17:42:41.024828 [INFO]: msg_handler_xapp.c:553 E42 SETUP-REQUEST tx
17:42:41.025388 [INFO]: msg_handler_xapp.c:394 E42 SETUP-RESPONSE rx xApp ID 7
17:42:41.025402 [INFO]: msg_handler_xapp.c:410 Connected E2 Node(s) 1
Send RC and LLC subscriptions to target_nb_id 1
17:42:42.026879 [INFO]: msg_handler_xapp.c:588 RIC_SUBSCRIPTION_REQUEST tx RAN_FUNC_ID 3 RIC_REQ_ID 1
17:42:42.028280 [INFO]: msg_handler_xapp.c:155 RIC_SUBSCRIPTION_RESPONSE rx RAN_FUNC_ID 3 RIC_REQ_ID 1
Waiting for a UE to connect to the monitored E2-Node...
Found UE(0) ran_ue_id 14294967296 in E2 Node (gNB) id 1
Monitor ran_ue_id 14294967296
17:42:42.028914 [INFO]: msg_handler_xapp.c:601 RIC_SUBSCRIPTION_DELETE_REQUEST tx RAN_FUNC_ID 3 RIC_REQ_ID 1
17:42:42.028990 [INFO]: msg_handler_xapp.c:196 RIC_SUBSCRIPTION_DELETE_RESPONSE rx RAN_FUNC_ID 3 rx RIC_REQ_ID 1
17:42:42.029025 [INFO]: msg_handler_xapp.c:588 RIC_SUBSCRIPTION_REQUEST tx RAN_FUNC_ID 5 RIC_REQ_ID 2
17:42:42.029523 [INFO]: msg_handler_xapp.c:155 RIC_SUBSCRIPTION_RESPONSE rx RAN_FUNC_ID 5 RIC_REQ_ID 2
receive ind msg from E2 node id 1, msg latency 728 us (ran_ue_id 14294967296)
receive ind msg from E2 node id 1, msg latency 559 us (ran_ue_id 14294967296)
...
...
...
17:42:52.029630 [INFO]: msg_handler_xapp.c:601 RIC_SUBSCRIPTION_DELETE_REQUEST tx RAN_FUNC_ID 5 RIC_REQ_ID 2
17:42:52.030187 [INFO]: msg_handler_xapp.c:196 RIC_SUBSCRIPTION_DELETE_RESPONSE rx RAN_FUNC_ID 5 rx RIC_REQ_ID 2
Test xApp run SUCCESSFULLY
The directory where the xApp runs will be populated with files that follow the pattern iq_srs_<type>_ant<antenna>_symbol<symbol>_nbid<nb_id>_ueid<ran_ue_id>.txt, where <type> is rx, noise or estimated.
Each line of a file holds one I/Q sample as <slot_start_time_us> <I> <Q>, and the files are overwritten by every new indication message, so they always contain the latest SRS.