Commit 01c7dca6 authored by Jaroslava Fiedlerova's avatar Jaroslava Fiedlerova

Merge remote-tracking branch 'origin/update-e2-agent' into integration_2024_w03

parents ca2dfc0e dcf215e5
......@@ -300,8 +300,8 @@ set(E2AP_VERSION "E2AP_V2" CACHE STRING "E2AP version")
set_property(CACHE E2AP_VERSION PROPERTY STRINGS "E2AP_V1" "E2AP_V2" "E2AP_V3")
message(STATUS "Selected E2AP_VERSION: ${E2AP_VERSION}")
set(KPM_VERSION "KPM_V2" CACHE STRING "The KPM SM version to use")
set_property(CACHE KPM_VERSION PROPERTY STRINGS "KPM_V2" "KPM_V3")
set(KPM_VERSION "KPM_V2_03" CACHE STRING "The KPM SM version to use")
set_property(CACHE KPM_VERSION PROPERTY STRINGS "KPM_V2_03" "KPM_V3_00")
message(STATUS "Selected KPM Version: ${KPM_VERSION}")
......@@ -1433,7 +1433,7 @@ target_link_libraries(L2 PRIVATE x2ap s1ap lte_rrc m2ap)
target_link_libraries(L2 PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs)
if(E2_AGENT)
target_link_libraries(L2 PUBLIC e2_agent e2_ran_func)
target_link_libraries(L2 PUBLIC e2_agent e2_agent_arg e2_ran_func_du_cucp_cuup)
target_compile_definitions(L2 PRIVATE E2_AGENT)
target_compile_definitions(L2 PRIVATE ${E2AP_VERSION} ${KPM_VERSION})
endif()
......@@ -1460,7 +1460,7 @@ target_link_libraries(e1_if PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs asn1_f1ap
target_link_libraries(L2_NR PRIVATE f1ap x2ap s1ap ngap nr_rrc e1ap nr_rlc)
if(E2_AGENT)
target_link_libraries(L2_NR PUBLIC e2_agent e2_ran_func)
target_link_libraries(L2_NR PUBLIC e2_agent e2_agent_arg e2_ran_func_du_cucp_cuup)
target_compile_definitions(L2_NR PRIVATE ${E2AP_VERSION} ${KPM_VERSION})
target_compile_definitions(L2_NR PRIVATE E2_AGENT)
endif()
......@@ -2113,6 +2113,10 @@ target_link_libraries(nr-cuup PRIVATE
GTPV1U e1ap f1ap SIMU_ETH
z sctp dl pthread shlib_loader ${T_LIB})
target_link_libraries(nr-cuup PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs)
if(E2_AGENT)
target_link_libraries(nr-cuup PRIVATE e2_agent e2_agent_arg e2_ran_func_cuup)
target_compile_definitions(nr-cuup PRIVATE ${E2AP_VERSION} ${KPM_VERSION} E2_AGENT)
endif()
# nr-uesoftmodem is UE implementation
#######################################
......
......@@ -39,6 +39,42 @@ int asn1_xer_print;
int oai_exit = 0;
instance_t CUuniqInstance = 0;
#ifdef E2_AGENT
#include "openair2/E2AP/flexric/src/agent/e2_agent_api.h"
#include "openair2/E2AP/RAN_FUNCTION/init_ran_func.h"
static void initialize_agent(ngran_node_t node_type, e2_agent_args_t oai_args)
{
AssertFatal(oai_args.sm_dir != NULL , "Please, specify the directory where the SMs are located in the config file, i.e., add in config file the next line: e2_agent = {near_ric_ip_addr = \"127.0.0.1\"; sm_dir = \"/usr/local/lib/flexric/\");} ");
AssertFatal(oai_args.ip != NULL , "Please, specify the IP address of the nearRT-RIC in the config file, i.e., e2_agent = {near_ric_ip_addr = \"127.0.0.1\"; sm_dir = \"/usr/local/lib/flexric/\"");
printf("After RCconfig_NR_E2agent %s %s \n",oai_args.sm_dir, oai_args.ip );
fr_args_t args = { .ip = oai_args.ip }; // init_fr_args(0, NULL);
memcpy(args.libs_dir, oai_args.sm_dir, 128);
sleep(1);
// Only 1 instances is supported in one executable
// Advice: run multiple executables to have multiple instances
const e1ap_upcp_inst_t *e1inst = getCxtE1(CUuniqInstance);
const int nb_id = e1inst->gnb_id;
const int cu_up_id = e1inst->cuup.setupReq.gNB_cu_up_id;
const int mcc = e1inst->cuup.setupReq.plmn[0].id.mcc;
const int mnc = e1inst->cuup.setupReq.plmn[0].id.mnc;
const int mnc_digit_len = e1inst->cuup.setupReq.plmn[0].id.mnc_digit_length;
printf("[E2 NODE]: mcc = %d mnc = %d mnc_digit = %d nb_id = %d \n", mcc, mnc, mnc_digit_len, nb_id);
printf("[E2 NODE]: Args %s %s \n", args.ip, args.libs_dir);
sm_io_ag_ran_t io = init_ran_func_ag();
init_agent_api(mcc, mnc, mnc_digit_len, nb_id, cu_up_id, node_type, io, &args);
}
#endif // E2_AGENT
void exit_function(const char *file, const char *function, const int line, const char *s, const int assert)
{
if (assert) {
......@@ -135,6 +171,22 @@ int main(int argc, char **argv)
AssertFatal(msg != NULL, "Send init to task for E1AP UP failed\n");
itti_send_msg_to_task(TASK_CUUP_E1, 0, msg);
#ifdef E2_AGENT
//////////////////////////////////
//////////////////////////////////
//// Init the E2 Agent
// OAI Wrapper
e2_agent_args_t oai_args = RCconfig_NR_E2agent();
if (oai_args.enabled) {
const ngran_node_t node_type = get_node_type();
assert(node_type == ngran_gNB_CUUP);
initialize_agent(node_type, oai_args);
}
#endif // E2_AGENT
printf("TYPE <CTRL-C> TO TERMINATE\n");
itti_wait_tasks_end(NULL);
......
......@@ -600,7 +600,7 @@ static void initialize_agent(ngran_node_t node_type, e2_agent_args_t oai_args)
AssertFatal(mac != NULL, "MAC not initialized\n");
cu_du_id = mac->f1_config.gnb_id;
nb_id = mac->f1_config.setup_req->gNB_DU_id;
} else if (node_type == ngran_gNB_CU) {
} else if (node_type == ngran_gNB_CU || node_type == ngran_gNB_CUCP) {
// agent buggy: the CU has no second ID, it is the CU-UP ID
// however, that is not a problem her for us, so put the same ID twice
nb_id = rrc->node_id;
......
......@@ -128,3 +128,4 @@ add_subdirectory(flexric/src/sm)
add_subdirectory(flexric/src/util)
add_subdirectory(RAN_FUNCTION)
add_library(e2_agent_arg STATIC e2_agent_arg.c)
add_subdirectory(CUSTOMIZED)
add_subdirectory(O-RAN)
add_library(e2_ran_func_cuup STATIC
init_ran_func.c
read_setup_ran.c
../flexric/test/rnd/fill_rnd_data_e2_setup_req.c # this is not rnd data; it is used to fill E2 Node Component Configuration Addition List in E2 Setup Request message
CUSTOMIZED/ran_func_gtp.c # current implementation doesn't take split architecture into account, neither CU/DU nor CU-UP/CU-CP
CUSTOMIZED/ran_func_pdcp.c # current implementation doesn't take split architecture into account, neither CU/DU nor CU-UP/CU-CP
CUSTOMIZED/ran_func_tc.c # currently, not implemented; therefore, filling rnd data
../flexric/test/rnd/fill_rnd_data_tc.c
O-RAN/ran_func_kpm.c # this file should only contain PDCP-U/GTP; to be done in the future
../flexric/test/rnd/fill_rnd_data_kpm.c # this dependancy will be taken out once RAN Function Definition is implemented
O-RAN/ran_func_rc.c # this file should only contain PDCP-U/GTP; to be done in the future
../flexric/test/rnd/fill_rnd_data_rc.c # this dependancy will be taken out once RAN Function Definition is implemented
)
add_library(e2_ran_func STATIC
init_ran_func.c
read_setup_ran.c
../flexric/test/rnd/fill_rnd_data_e2_setup_req.c
)
target_link_libraries(e2_ran_func_cuup PUBLIC asn1_nr_rrc nr_rrc asn1_nr_rrc_hdrs e2_time_obj kpm_ric_info_common_obj 3gpp_derived_ie_obj)
target_compile_definitions(e2_ran_func_cuup PUBLIC ${E2AP_VERSION} ${KPM_VERSION} NGRAN_GNB_CUUP)
target_link_libraries(e2_ran_func
PUBLIC
e2_ran_func_cust
e2_ran_func_oran
)
# This dependency sucks! Create pointers and forward declarations!
target_compile_definitions(e2_ran_func PRIVATE ${E2AP_VERSION} ${KPM_VERSION})
add_library(e2_ran_func_du_cucp_cuup STATIC
init_ran_func.c
read_setup_ran.c
../flexric/test/rnd/fill_rnd_data_e2_setup_req.c # this is not rnd data; it is used to fill E2 Node Component Configuration Addition List in E2 Setup Request message
CUSTOMIZED/ran_func_gtp.c # current implementation doesn't take split architecture into account, neither CU/DU nor CU-UP/CU-CP
CUSTOMIZED/ran_func_pdcp.c # current implementation doesn't take split architecture into account, neither CU/DU nor CU-UP/CU-CP
O-RAN/ran_func_kpm.c # this file should only contain RRC/PDCP-C; to be done in the future
# when nr-softmodem is divided in separate executables
../flexric/test/rnd/fill_rnd_data_kpm.c # this dependancy will be taken out once RAN Function Definition is implemented
O-RAN/ran_func_rc.c # this file should only contain RRC/PDCP-C; to be done in the future
# when nr-softmodem is divided in separate executables
../flexric/test/rnd/fill_rnd_data_rc.c # this dependancy will be taken out once RAN Function Definition is implemented
CUSTOMIZED/ran_func_mac.c
CUSTOMIZED/ran_func_rlc.c
CUSTOMIZED/ran_func_slice.c
CUSTOMIZED/ran_func_tc.c
../flexric/test/rnd/fill_rnd_data_tc.c
../flexric/test/rnd/fill_rnd_data_slice.c
)
target_link_libraries(e2_ran_func_du_cucp_cuup PUBLIC asn1_nr_rrc nr_rrc asn1_nr_rrc_hdrs e2_time_obj kpm_ric_info_common_obj 3gpp_derived_ie_obj)
target_compile_definitions(e2_ran_func_du_cucp_cuup PUBLIC ${E2AP_VERSION} ${KPM_VERSION} NGRAN_GNB_DU NGRAN_GNB_CUCP NGRAN_GNB_CUUP)
add_library(e2_ran_func_cust STATIC
ran_func_gtp.c
ran_func_mac.c
ran_func_pdcp.c
ran_func_rlc.c
ran_func_slice.c
ran_func_tc.c
# For testing purposes
../../flexric/test/rnd/fill_rnd_data_gtp.c
../../flexric/test/rnd/fill_rnd_data_tc.c
../../flexric/test/rnd/fill_rnd_data_mac.c
../../flexric/test/rnd/fill_rnd_data_rlc.c
../../flexric/test/rnd/fill_rnd_data_pdcp.c
../../flexric/test/rnd/fill_rnd_data_slice.c
../../flexric/src/util/time_now_us.c
)
target_link_libraries(e2_ran_func_cust PUBLIC asn1_nr_rrc nr_rrc asn1_nr_rrc_hdrs)
# This dependency sucks! Create pointers and forward declarations!
target_compile_definitions(e2_ran_func_cust PRIVATE ${E2AP_VERSION} ${KPM_VERSION} )
......@@ -23,17 +23,17 @@
#include <assert.h>
#include "openair2/E2AP/flexric/test/rnd/fill_rnd_data_gtp.h"
#include "common/ran_context.h"
#include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h"
#include "openair2/E2AP/flexric/src/util/time_now_us.h"
#include "openair2/RRC/NR/rrc_gNB_UE_context.h"
#include "openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h"
static
const int mod_id = 0;
#if defined (NGRAN_GNB_CUCP)
#include "openair2/RRC/NR/rrc_gNB_UE_context.h"
#endif
void read_gtp_sm(void * data)
bool read_gtp_sm(void * data)
{
assert(data != NULL);
......@@ -42,44 +42,46 @@ void read_gtp_sm(void * data)
gtp->msg.tstamp = time_now_us();
NR_UEs_t *UE_info = &RC.nrmac[mod_id]->UE_info;
size_t num_ues = 0;
UE_iterator(UE_info->list, ue) {
if (ue)
num_ues += 1;
}
uint64_t ue_id_list[MAX_MOBILES_PER_GNB];
size_t num_ues = nr_pdcp_get_num_ues(ue_id_list, MAX_MOBILES_PER_GNB);
gtp->msg.len = num_ues;
if(gtp->msg.len > 0){
gtp->msg.ngut = calloc(gtp->msg.len, sizeof(gtp_ngu_t_stats_t) );
assert(gtp->msg.ngut != NULL);
}
else {
return false;
}
#if defined (NGRAN_GNB_CUCP) && defined (NGRAN_GNB_CUUP)
if (RC.nrrrc[0]->node_type == ngran_gNB_DU || RC.nrrrc[0]->node_type == ngran_gNB_CUCP) return false;
assert((RC.nrrrc[0]->node_type == ngran_gNB_CU || RC.nrrrc[0]->node_type == ngran_gNB) && "Expected node types: CU or gNB-mono");
size_t i = 0;
UE_iterator(UE_info->list, UE)
{
uint16_t const rnti = UE->rnti;
struct rrc_gNB_ue_context_s *ue_context_p = rrc_gNB_get_ue_context_by_rnti_any_du(RC.nrrrc[mod_id], rnti);
if (ue_context_p != NULL) {
gtp->msg.ngut[i].rnti = ue_context_p->ue_context.rnti;
int nb_pdu_session = ue_context_p->ue_context.nb_of_pdusessions;
if (nb_pdu_session > 0) {
int nb_pdu_idx = nb_pdu_session - 1;
gtp->msg.ngut[i].teidgnb = ue_context_p->ue_context.pduSession[nb_pdu_idx].param.gNB_teid_N3;
gtp->msg.ngut[i].teidupf = ue_context_p->ue_context.pduSession[nb_pdu_idx].param.UPF_teid_N3;
// TODO: one PDU session has multiple QoS Flow
int nb_qos_flow = ue_context_p->ue_context.pduSession[nb_pdu_idx].param.nb_qos;
if (nb_qos_flow > 0) {
gtp->msg.ngut[i].qfi = ue_context_p->ue_context.pduSession[nb_pdu_idx].param.qos[nb_qos_flow - 1].qfi;
}
for (size_t i = 0; i < num_ues; i++) {
rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(RC.nrrrc[0], ue_id_list[i]);
gtp->msg.ngut[i].rnti = ue_id_list[i];
int nb_pdu_session = ue_context_p->ue_context.nb_of_pdusessions;
if (nb_pdu_session > 0) {
int nb_pdu_idx = nb_pdu_session - 1;
gtp->msg.ngut[i].teidgnb = ue_context_p->ue_context.pduSession[nb_pdu_idx].param.gNB_teid_N3;
gtp->msg.ngut[i].teidupf = ue_context_p->ue_context.pduSession[nb_pdu_idx].param.UPF_teid_N3;
// TODO: one PDU session has multiple QoS Flow
int nb_qos_flow = ue_context_p->ue_context.pduSession[nb_pdu_idx].param.nb_qos;
if (nb_qos_flow > 0) {
gtp->msg.ngut[i].qfi = ue_context_p->ue_context.pduSession[nb_pdu_idx].param.qos[nb_qos_flow - 1].qfi;
}
} else {
LOG_W(NR_RRC,"rrc_gNB_get_ue_context return NULL\n");
// if (gtp->msg.ngut != NULL) free(gtp->msg.ngut);
}
i++;
}
return true;
#elif defined (NGRAN_GNB_CUUP)
// For the moment, CU-UP doesn't store PDU session information
printf("GTP SM not yet implemented in CU-UP\n");
return false;
#endif
}
void read_gtp_setup_sm(void* data)
......
......@@ -24,7 +24,7 @@
#include "openair2/E2AP/flexric/src/agent/../sm/sm_io.h"
void read_gtp_sm(void*);
bool read_gtp_sm(void*);
void read_gtp_setup_sm(void*);
......
......@@ -20,14 +20,13 @@
*/
#include "ran_func_mac.h"
#include "openair2/E2AP/flexric/test/rnd/fill_rnd_data_mac.h"
#include <assert.h>
static
const int mod_id = 0;
void read_mac_sm(void* data)
bool read_mac_sm(void* data)
{
assert(data != NULL);
......@@ -110,6 +109,8 @@ void read_mac_sm(void* data)
++i;
}
return num_ues > 0;
}
void read_mac_setup_sm(void* data)
......
......@@ -28,7 +28,7 @@
#include "openair2/E2AP/flexric/src/util/time_now_us.h"
void read_mac_sm(void*);
bool read_mac_sm(void*);
void read_mac_setup_sm(void*);
......
......@@ -19,164 +19,125 @@
* contact@openairinterface.org
*/
#include "ran_func_pdcp.h"
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include "openair2/E2AP/flexric/test/rnd/fill_rnd_data_pdcp.h"
#include "ran_func_pdcp.h"
#include "common/ran_context.h"
#include "openair2/RRC/NR/rrc_gNB_UE_context.h"
#include "openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h"
#include "openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h"
#include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h"
#include "openair2/E2AP/flexric/src/util/time_now_us.h"
#if defined (NGRAN_GNB_DU)
#include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h"
#include "openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h"
#endif
#if defined (NGRAN_GNB_CUCP)
#include "openair2/RRC/NR/rrc_gNB_UE_context.h"
#endif
static
const int mod_id = 0;
#if defined (NGRAN_GNB_CUUP)
#include "openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h"
#endif
static
uint32_t num_act_rb(NR_UEs_t* UE_info)
#if defined (NGRAN_GNB_CUUP)
void fill_pdcp_stats_for_all_rbs(pdcp_radio_bearer_stats_t* rb, const size_t num_ues, const uint64_t* ue_id_list)
{
assert(UE_info!= NULL);
size_t j = 0;
for (size_t i = 0; i < num_ues; i++) {
for (int rb_id = 1; rb_id < 6; ++rb_id) {
nr_pdcp_statistics_t rb_pdcp = {0};
uint32_t act_rb = 0;
UE_iterator(UE_info->list, UE) {
uint16_t const rnti = UE->rnti;
for(int rb_id = 1; rb_id < 6; ++rb_id ){
nr_rlc_statistics_t rlc = {0};
const int srb_flag = 0;
const bool rc = nr_rlc_get_statistics(rnti, srb_flag, rb_id, &rlc);
if(rc) ++act_rb;
const bool rc = nr_pdcp_get_statistics(ue_id_list[i], srb_flag, rb_id, &rb_pdcp);
if (!rc) continue;
pdcp_radio_bearer_stats_t *rd = &rb[j++];
rd->txpdu_pkts = rb_pdcp.txpdu_pkts; /* aggregated number of tx packets */
rd->txpdu_bytes = rb_pdcp.txpdu_bytes; /* aggregated bytes of tx packets */
rd->txpdu_sn = rb_pdcp.txpdu_sn; /* current sequence number of last tx packet (or TX_NEXT) */
rd->rxpdu_pkts = rb_pdcp.rxpdu_pkts; /* aggregated number of rx packets */
rd->rxpdu_bytes = rb_pdcp.rxpdu_bytes; /* aggregated bytes of rx packets */
rd->rxpdu_sn = rb_pdcp.rxpdu_sn; /* current sequence number of last rx packet (or RX_NEXT) */
rd->rxpdu_oo_pkts = rb_pdcp.rxpdu_oo_pkts; /* aggregated number of out-of-order rx pkts (or RX_REORD) */
rd->rxpdu_oo_bytes = rb_pdcp.rxpdu_oo_bytes; /* aggregated amount of out-of-order rx bytes */
rd->rxpdu_dd_pkts = rb_pdcp.rxpdu_dd_pkts; /* aggregated number of duplicated discarded packets (or dropped packets because of other reasons such as integrity failure) (or RX_DELIV) */
rd->rxpdu_dd_bytes = rb_pdcp.rxpdu_dd_bytes; /* aggregated amount of discarded packets' bytes */
rd->rxpdu_ro_count = rb_pdcp.rxpdu_ro_count; /* this state variable indicates the COUNT value following the COUNT value associated with the PDCP Data PDU which triggered t-Reordering. (RX_REORD) */
rd->txsdu_pkts = rb_pdcp.txsdu_pkts; /* number of SDUs delivered */
rd->txsdu_bytes = rb_pdcp.txsdu_bytes; /* number of bytes of SDUs delivered */
rd->rxsdu_pkts = rb_pdcp.rxsdu_pkts; /* number of SDUs received */
rd->rxsdu_bytes = rb_pdcp.rxsdu_bytes; /* number of bytes of SDUs received */
rd->rnti = ue_id_list[i];
rd->mode = rb_pdcp.mode; /* 0: PDCP AM, 1: PDCP UM, 2: PDCP TM */
rd->rbid = rb_id;
}
}
return act_rb;
}
#endif
void read_pdcp_sm(void* data)
bool read_pdcp_sm(void* data)
{
assert(data != NULL);
//assert(data->type == PDCP_STATS_V0);
pdcp_ind_data_t* pdcp = (pdcp_ind_data_t*)data;
//fill_pdcp_ind_data(pdcp);
// TODO: Need to improve, not good
if (NODE_IS_CU(RC.nrrrc[mod_id]->node_type)) {
uint32_t act_rb = 0;
struct rrc_gNB_ue_context_s *ue_context_p1 = NULL;
RB_FOREACH(ue_context_p1, rrc_nr_ue_tree_s, &RC.nrrrc[mod_id]->rrc_ue_head) {
uint16_t const rnti = ue_context_p1->ue_context.rnti;
for(int rb_id = 1; rb_id < 6; ++rb_id ){
nr_pdcp_statistics_t rb_pdcp = {0};
const int srb_flag = 0;
const bool rc = nr_pdcp_get_statistics(rnti, srb_flag, rb_id, &rb_pdcp);
if(rc) ++act_rb;
}
}
pdcp->msg.tstamp = time_now_us();
pdcp->msg.tstamp = time_now_us();
pdcp->msg.len = act_rb;
if (pdcp->msg.len > 0) {
pdcp->msg.rb = calloc(pdcp->msg.len, sizeof(pdcp_radio_bearer_stats_t));
assert(pdcp->msg.rb != NULL && "Memory exhausted!");
}
size_t num_ues = 0;
uint64_t ue_id_list[MAX_MOBILES_PER_GNB];
size_t total_num_rb = 0;
size_t i = 0;
struct rrc_gNB_ue_context_s *ue_context_p2 = NULL;
RB_FOREACH(ue_context_p2, rrc_nr_ue_tree_s, &RC.nrrrc[mod_id]->rrc_ue_head) {
// TODO: Need to handel multiple UEs
uint16_t const rnti = ue_context_p2->ue_context.rnti;
for (size_t rb_id = 1; rb_id < 6; ++rb_id) {
nr_pdcp_statistics_t rb_pdcp = {0};
const int srb_flag = 0;
const bool rc = nr_pdcp_get_statistics(rnti, srb_flag, rb_id, &rb_pdcp);
if (!rc) continue;
pdcp_radio_bearer_stats_t *rd = &pdcp->msg.rb[i];
rd->txpdu_pkts = rb_pdcp.txpdu_pkts; /* aggregated number of tx packets */
rd->txpdu_bytes = rb_pdcp.txpdu_bytes; /* aggregated bytes of tx packets */
rd->txpdu_sn = rb_pdcp.txpdu_sn; /* current sequence number of last tx packet (or TX_NEXT) */
rd->rxpdu_pkts = rb_pdcp.rxpdu_pkts; /* aggregated number of rx packets */
rd->rxpdu_bytes = rb_pdcp.rxpdu_bytes; /* aggregated bytes of rx packets */
rd->rxpdu_sn = rb_pdcp.rxpdu_sn; /* current sequence number of last rx packet (or RX_NEXT) */
rd->rxpdu_oo_pkts = rb_pdcp.rxpdu_oo_pkts; /* aggregated number of out-of-order rx pkts (or RX_REORD) */
rd->rxpdu_oo_bytes = rb_pdcp.rxpdu_oo_bytes; /* aggregated amount of out-of-order rx bytes */
rd->rxpdu_dd_pkts = rb_pdcp.rxpdu_dd_pkts; /* aggregated number of duplicated discarded packets (or dropped packets because of other reasons such as integrity failure) (or RX_DELIV) */
rd->rxpdu_dd_bytes = rb_pdcp.rxpdu_dd_bytes; /* aggregated amount of discarded packets' bytes */
rd->rxpdu_ro_count = rb_pdcp.rxpdu_ro_count; /* this state variable indicates the COUNT value following the COUNT value associated with the PDCP Data PDU which triggered t-Reordering. (RX_REORD) */
rd->txsdu_pkts = rb_pdcp.txsdu_pkts; /* number of SDUs delivered */
rd->txsdu_bytes = rb_pdcp.txsdu_bytes; /* number of bytes of SDUs delivered */
rd->rxsdu_pkts = rb_pdcp.rxsdu_pkts; /* number of SDUs received */
rd->rxsdu_bytes = rb_pdcp.rxsdu_bytes; /* number of bytes of SDUs received */
rd->rnti = rnti;
rd->mode = rb_pdcp.mode; /* 0: PDCP AM, 1: PDCP UM, 2: PDCP TM */
rd->rbid = rb_id;
++i;
}
}
} else {
#if defined (NGRAN_GNB_CUCP) && defined (NGRAN_GNB_CUUP)
if (RC.nrrrc[0]->node_type == ngran_gNB_DU || RC.nrrrc[0]->node_type == ngran_gNB_CUCP) return false;
assert((RC.nrrrc[0]->node_type == ngran_gNB_CU || RC.nrrrc[0]->node_type == ngran_gNB) && "Expected node types: CU or gNB-mono");
//assert(0!=0 && "Calling PDCP");
// for the moment and while we don't have a split base station, we use the
// MAC structures to obtain the RNTIs which we use to query the PDCP
NR_UEs_t *UE_info = &RC.nrmac[mod_id]->UE_info;
uint32_t const act_rb = num_act_rb(UE_info);
struct rrc_gNB_ue_context_s *ue_context_p = NULL;
RB_FOREACH(ue_context_p, rrc_nr_ue_tree_s, &RC.nrrrc[0]->rrc_ue_head) {
ue_id_list[num_ues] = ue_context_p->ue_context.rrc_ue_id;
pdcp->msg.tstamp = time_now_us();
pdcp->msg.len = act_rb;
if (pdcp->msg.len > 0) {
pdcp->msg.rb = calloc(pdcp->msg.len, sizeof(pdcp_radio_bearer_stats_t));
assert(pdcp->msg.rb != NULL && "Memory exhausted!");
for(int rb_id = 1; rb_id < 6; ++rb_id ){
nr_pdcp_statistics_t rb_pdcp = {0};
const int srb_flag = 0;
const bool rc = nr_pdcp_get_statistics(ue_id_list[num_ues], srb_flag, rb_id, &rb_pdcp);
if(rc) ++total_num_rb;
}
num_ues++;
AssertFatal(num_ues < MAX_MOBILES_PER_GNB, "cannot have more UEs than global UE number maximum\n");
}
size_t i = 0;
UE_iterator(UE_info->list, UE)
{
const int rnti = UE->rnti;
for (size_t rb_id = 1; rb_id < 6; ++rb_id) {
nr_pdcp_statistics_t rb_pdcp = {0};
const int srb_flag = 0;
const bool rc = nr_pdcp_get_statistics(rnti, srb_flag, rb_id, &rb_pdcp);
if (!rc) continue;
pdcp_radio_bearer_stats_t *rd = &pdcp->msg.rb[i];
rd->txpdu_pkts = rb_pdcp.txpdu_pkts; /* aggregated number of tx packets */
rd->txpdu_bytes = rb_pdcp.txpdu_bytes; /* aggregated bytes of tx packets */
rd->txpdu_sn = rb_pdcp.txpdu_sn; /* current sequence number of last tx packet (or TX_NEXT) */
rd->rxpdu_pkts = rb_pdcp.rxpdu_pkts; /* aggregated number of rx packets */
rd->rxpdu_bytes = rb_pdcp.rxpdu_bytes; /* aggregated bytes of rx packets */
rd->rxpdu_sn = rb_pdcp.rxpdu_sn; /* current sequence number of last rx packet (or RX_NEXT) */
rd->rxpdu_oo_pkts = rb_pdcp.rxpdu_oo_pkts; /* aggregated number of out-of-order rx pkts (or RX_REORD) */
rd->rxpdu_oo_bytes = rb_pdcp.rxpdu_oo_bytes; /* aggregated amount of out-of-order rx bytes */
rd->rxpdu_dd_pkts = rb_pdcp.rxpdu_dd_pkts; /* aggregated number of duplicated discarded packets (or dropped packets because of other reasons such as integrity failure) (or RX_DELIV) */
rd->rxpdu_dd_bytes = rb_pdcp.rxpdu_dd_bytes; /* aggregated amount of discarded packets' bytes */
rd->rxpdu_ro_count = rb_pdcp.rxpdu_ro_count; /* this state variable indicates the COUNT value following the COUNT value associated with the PDCP Data PDU which triggered t-Reordering. (RX_REORD) */
rd->txsdu_pkts = rb_pdcp.txsdu_pkts; /* number of SDUs delivered */
rd->txsdu_bytes = rb_pdcp.txsdu_bytes; /* number of bytes of SDUs delivered */
rd->rxsdu_pkts = rb_pdcp.rxsdu_pkts; /* number of SDUs received */
rd->rxsdu_bytes = rb_pdcp.rxsdu_bytes; /* number of bytes of SDUs received */
rd->rnti = rnti;
rd->mode = rb_pdcp.mode; /* 0: PDCP AM, 1: PDCP UM, 2: PDCP TM */
rd->rbid = rb_id;
++i;
}
#elif defined (NGRAN_GNB_CUUP)
num_ues = nr_pdcp_get_num_ues(ue_id_list, MAX_MOBILES_PER_GNB);
for (size_t i = 0; i < num_ues; i++) {
for(int rb_id = 1; rb_id < 6; ++rb_id ){
nr_pdcp_statistics_t rb_pdcp = {0};
const int srb_flag = 0;
const bool rc = nr_pdcp_get_statistics(ue_id_list[i], srb_flag, rb_id, &rb_pdcp);
if(rc) ++total_num_rb;
}
}
#endif
pdcp->msg.len = total_num_rb;
if (pdcp->msg.len > 0) {
pdcp->msg.rb = calloc(pdcp->msg.len, sizeof(pdcp_radio_bearer_stats_t));
assert(pdcp->msg.rb != NULL && "Memory exhausted!");
// Filling Radio Bearer Statistics
#if defined (NGRAN_GNB_CUUP)
fill_pdcp_stats_for_all_rbs(pdcp->msg.rb, num_ues, ue_id_list);
#endif
return true;
}
else {
return false;
}
}
void read_pdcp_setup_sm(void* data)
......@@ -195,5 +156,3 @@ sm_ag_if_ans_t write_ctrl_pdcp_sm(void const* data)
sm_ag_if_ans_t ans = {0};
return ans;
}
......@@ -24,7 +24,7 @@
#include "openair2/E2AP/flexric/src/agent/../sm/sm_io.h"
void read_pdcp_sm(void*);
bool read_pdcp_sm(void*);
void read_pdcp_setup_sm(void* data);
......
......@@ -28,7 +28,6 @@
#include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h"
#include "openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h"
#include "openair2/E2AP/flexric/src/util/time_now_us.h"
#include "openair2/E2AP/flexric/test/rnd/fill_rnd_data_rlc.h"
static
const int mod_id = 0;
......@@ -67,7 +66,7 @@ void active_avg_to_tx(NR_UEs_t* const UE_info)
}
}
void read_rlc_sm(void* data)
bool read_rlc_sm(void* data)
{
assert(data != NULL);
// assert(data->type == RLC_STATS_V0);
......@@ -161,6 +160,8 @@ void read_rlc_sm(void* data)
++i;
}
}
return act_rb > 0;
}
void read_rlc_setup_sm(void* data)
......
......@@ -24,7 +24,7 @@
#include "openair2/E2AP/flexric/src/agent/../sm/sm_io.h"
void read_rlc_sm(void*);
bool read_rlc_sm(void*);
void read_rlc_setup_sm(void* data);
......
......@@ -24,13 +24,15 @@
#include <assert.h>
#include <stdio.h>
void read_slice_sm(void* data)
bool read_slice_sm(void* data)
{
assert(data != NULL);
// assert(data->type == SLICE_STATS_V0);
slice_ind_data_t* slice = (slice_ind_data_t*)data;
fill_slice_ind_data(slice);
return true;
}
void read_slice_setup_sm(void* data)
......
......@@ -24,7 +24,7 @@
#include "openair2/E2AP/flexric/src/agent/../sm/sm_io.h"
void read_slice_sm(void*);
bool read_slice_sm(void*);
void read_slice_setup_sm(void* data);
......
......@@ -23,13 +23,15 @@
#include "../../flexric/test/rnd/fill_rnd_data_tc.h"
#include <assert.h>
void read_tc_sm(void* data)
bool read_tc_sm(void* data)
{
assert(data != NULL);
//assert(data->type == TC_STATS_V0);
tc_ind_data_t* tc = (tc_ind_data_t*)data;
fill_tc_ind_data(tc);
return true;
}
void read_tc_setup_sm(void* data)
......
......@@ -24,7 +24,7 @@
#include "openair2/E2AP/flexric/src/agent/../sm/sm_io.h"
void read_tc_sm(void*);
bool read_tc_sm(void*);
void read_tc_setup_sm(void* data);
......
add_library(e2_ran_func_oran STATIC
ran_func_kpm.c
ran_func_rc.c
# For testing purposes
../../flexric/test/rnd/fill_rnd_data_kpm.c
../../flexric/test/rnd/fill_rnd_data_rc.c
)
target_link_libraries(e2_ran_func_oran PUBLIC asn1_nr_rrc nr_rrc asn1_nr_rrc_hdrs)
target_compile_definitions(e2_ran_func_oran PRIVATE ${E2AP_VERSION} ${KPM_VERSION})
......@@ -20,24 +20,39 @@
*/
#include "ran_func_kpm.h"
#include "openair2/E2AP/flexric/test/rnd/fill_rnd_data_kpm.h"
#include "openair2/E2AP/flexric/test/rnd/fill_rnd_data_kpm.h" // this dependancy will be taken out once RAN Function Definition is implemented
#include "openair2/E2AP/flexric/src/util/time_now_us.h"
#include "common/utils/assertions.h"
#if defined (NGRAN_GNB_DU)
#include "openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h"
#include "openair2/LAYER2/nr_rlc/nr_rlc_entity.h"
#include "openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h"
#endif
#if defined (NGRAN_GNB_CUCP)
#include "openair2/RRC/NR/rrc_gNB_UE_context.h"
#include "openair3/NGAP/ngap_gNB_ue_context.h"
#endif
#if defined (NGRAN_GNB_CUUP)
#include "openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h"
#include "openair2/LAYER2/nr_rlc/nr_rlc_entity.h"
#include "openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h"
#include "openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h"
#include "openair2/E1AP/e1ap_common.h"
#endif
#include "openair2/F1AP/f1ap_ids.h"
#include <assert.h>
#include <stdio.h>
/* Please note that only one executable nr-softmodem exists for DU, CU, CU-CP and gNB-mono nodes;
the layer separation should be done better in the future */
typedef struct {
NR_UE_info_t* ue_list[MAX_MOBILES_PER_GNB];
size_t num_ues;
} matched_ues_mac_t;
#if defined (NGRAN_GNB_CUUP)
typedef struct uldlcounter {
uint32_t dl;
uint32_t ul;
} uldlcounter_t;
static bool nssai_matches(nssai_t a_nssai, uint8_t b_sst, const uint32_t *b_sd)
{
......@@ -49,86 +64,51 @@ static bool nssai_matches(nssai_t a_nssai, uint8_t b_sst, const uint32_t *b_sd)
}
}
static size_t filter_ues_by_s_nssai_in_du_or_monolithic(test_cond_e const condition,
uint8_t sst,
const uint32_t *sd,
matched_ues_mac_t* matches)
static uldlcounter_t last_pdcp_sdu_total_bytes[MAX_MOBILES_PER_GNB] = {0};
static gnb_cu_up_e2sm_t fill_gnb_cu_up_data(const ue_id_t cucp_ue_id)
{
DevAssert(matches != NULL);
AssertFatal(condition == EQUAL_TEST_COND, "Condition %d not yet implemented", condition);
gnb_cu_up_e2sm_t gnb_cu_up = {0};
// Take MAC info
size_t i = 0;
UE_iterator (RC.nrmac[0]->UE_info.list, ue) {
NR_UE_sched_ctrl_t *sched_ctrl = &ue->UE_sched_ctrl;
// UE matches if any of its DRBs matches
for (int l = 0; l < sched_ctrl->dl_lc_num; ++l) {
long lcid = sched_ctrl->dl_lc_ids[l];
if (nssai_matches(sched_ctrl->dl_lc_nssai[lcid], sst, sd)) {
matches->ue_list[i++] = ue;
break;
}
}
AssertFatal(i < MAX_MOBILES_PER_GNB, "cannot have more UEs than global UE number maximum\n");
}
// 6.2.3.20
// Mandatory
gnb_cu_up.gnb_cu_cp_ue_e1ap = cucp_ue_id;
matches->num_ues = i;
assert(matches->num_ues >= 1 && "The number of filtered UEs must be at least equal to 1");
return i;
}
// 6.2.3.25
// RAN UE ID
// Optional
gnb_cu_up.ran_ue_id = NULL;
return gnb_cu_up;
}
typedef struct {
uint32_t rrc_ue_id_list[MAX_MOBILES_PER_GNB]; // list of matched UEs on RRC level containing only rrc_ue_id (gNB CU UE ID)
ue_id_t pdcp_ue_id_list[MAX_MOBILES_PER_GNB]; // list of matched UEs on PDCP-U level
size_t num_ues;
} matched_ues_rrc_t;
} matched_ues_pdcp_t;
static size_t filter_ues_by_s_nssai_in_cu(test_cond_e const condition, uint8_t sst, const uint32_t *sd, matched_ues_rrc_t* matches)
__attribute__((unused))
static size_t filter_ues_by_s_nssai_in_cuup(test_cond_e const condition, uint8_t sst, const uint32_t *sd, matched_ues_pdcp_t* matches)
{
DevAssert(matches != NULL);
AssertFatal(condition == EQUAL_TEST_COND, "Condition %d not yet implemented\n", condition);
struct rrc_gNB_ue_context_s *ue_context_p1 = NULL;
size_t i = 0;
RB_FOREACH(ue_context_p1, rrc_nr_ue_tree_s, &RC.nrrrc[0]->rrc_ue_head) {
gNB_RRC_UE_t *ue = &ue_context_p1->ue_context;
for (int p = 0; p < ue->nb_of_pdusessions; ++p) {
pdusession_t *pdu = &ue->pduSession[0].param;
if (nssai_matches(pdu->nssai, sst, sd)) {
matches->rrc_ue_id_list[i++] = ue_context_p1->ue_context.rrc_ue_id;
break;
}
// Get NSSAI info from E1 context
const instance_t CUuniqInstance = 0;
const e1ap_upcp_inst_t *e1inst = getCxtE1(CUuniqInstance);
// currently the CU-UP does not store the slices, so we can only do this "coarse filtering"
for(int s = 0; s < e1inst->cuup.setupReq.plmn[0].supported_slices; s++) {
if (nssai_matches(e1inst->cuup.setupReq.plmn[0].slice[s], sst, sd)) {
matches->num_ues = nr_pdcp_get_num_ues(matches->pdcp_ue_id_list, MAX_MOBILES_PER_GNB);
}
AssertFatal(i < MAX_MOBILES_PER_GNB, "cannot have more UEs than global UE number maximum\n");
}
matches->num_ues = i;
assert(matches->num_ues >= 1 && "The number of filtered UEs must be at least equal to 1");
return i;
}
static
nr_rlc_statistics_t get_rlc_stats_per_drb(NR_UE_info_t const * UE)
{
assert(UE != NULL);
nr_rlc_statistics_t rlc = {0};
const int srb_flag = 0;
const int rb_id = 1; // at the moment, only 1 DRB is supported
// Get RLC stats for specific DRB
const bool rc = nr_rlc_get_statistics(UE->rnti, srb_flag, rb_id, &rlc);
assert(rc == true && "Cannot get RLC stats\n");
// Activate average sojourn time at the RLC buffer for specific DRB
nr_rlc_activate_avg_time_to_tx(UE->rnti, rb_id+3, 1);
return rlc;
return matches->num_ues;
}
static
nr_pdcp_statistics_t get_pdcp_stats_per_drb(const uint32_t rrc_ue_id)
static nr_pdcp_statistics_t get_pdcp_stats_per_drb(const uint32_t rrc_ue_id)
{
nr_pdcp_statistics_t pdcp = {0};
const int srb_flag = 0;
......@@ -141,8 +121,118 @@ nr_pdcp_statistics_t get_pdcp_stats_per_drb(const uint32_t rrc_ue_id)
return pdcp;
}
static
gnb_e2sm_t fill_gnb_data(rrc_gNB_ue_context_t * ue_context_p)
static meas_record_lst_t fill_ue_pdcp_data(const uint32_t rrc_ue_id, const size_t ue_idx, const char * meas_info_name_str)
{
meas_record_lst_t meas_record = {0};
// Get PDCP stats per DRB
nr_pdcp_statistics_t pdcp = get_pdcp_stats_per_drb(rrc_ue_id);
// Measurement Type as requested in Action Definition
if (strcmp(meas_info_name_str, "DRB.PdcpSduVolumeDL") == 0) { // 3GPP TS 28.522 - section 5.1.2.1.1.1
meas_record.value = INTEGER_MEAS_VALUE;
// Get DL data volume delivered to PDCP layer
meas_record.int_val = (pdcp.rxsdu_bytes - last_pdcp_sdu_total_bytes[ue_idx].dl)*8/1000; // [kb]
last_pdcp_sdu_total_bytes[ue_idx].dl = pdcp.rxsdu_bytes;
/* note: this measurement is calculated as per spec */
} else if (strcmp(meas_info_name_str, "DRB.PdcpSduVolumeUL") == 0) { // 3GPP TS 28.522 - section 5.1.2.1.2.1
meas_record.value = INTEGER_MEAS_VALUE;
// Get UL data volume delivered from PDCP layer
meas_record.int_val = (pdcp.txsdu_bytes - last_pdcp_sdu_total_bytes[ue_idx].ul)*8/1000; // [kb]
last_pdcp_sdu_total_bytes[ue_idx].ul = pdcp.txsdu_bytes;
/* note: this measurement is calculated as per spec */
} else {
assert(false && "Measurement Name not yet implemented");
}
return meas_record;
}
static kpm_ind_msg_format_1_t fill_kpm_ind_msg_frm_1_in_cu(const uint32_t rrc_ue_id, const size_t ue_idx, const kpm_act_def_format_1_t * act_def_fr_1)
{
kpm_ind_msg_format_1_t msg_frm_1 = {0};
// Measurement Data contains a set of Meas Records, each collected at each granularity period
msg_frm_1.meas_data_lst_len = 1; /* this value is equal to (kpm_ric_event_trigger_format_1.report_period_ms/act_def_fr_1->gran_period_ms)
please, check their values in xApp */
msg_frm_1.meas_data_lst = calloc(msg_frm_1.meas_data_lst_len, sizeof(*msg_frm_1.meas_data_lst));
assert(msg_frm_1.meas_data_lst != NULL && "Memory exhausted" );
for (size_t i = 0; i<msg_frm_1.meas_data_lst_len; i++) {
// Measurement Record
msg_frm_1.meas_data_lst[i].meas_record_len = act_def_fr_1->meas_info_lst_len; // record data list length corresponds to info list length from action definition
msg_frm_1.meas_data_lst[i].meas_record_lst = calloc(msg_frm_1.meas_data_lst[i].meas_record_len, sizeof(meas_record_lst_t));
assert(msg_frm_1.meas_data_lst[i].meas_record_lst != NULL && "Memory exhausted");
for (size_t j = 0; j < msg_frm_1.meas_data_lst[i].meas_record_len; j++) { // each meas record corresponds to one meas type
// Measurement Type as requested in Action Definition
switch (act_def_fr_1->meas_info_lst[j].meas_type.type) {
case NAME_MEAS_TYPE: {
char meas_info_name_str[act_def_fr_1->meas_info_lst[j].meas_type.name.len + 1];
memcpy(meas_info_name_str, act_def_fr_1->meas_info_lst[j].meas_type.name.buf, act_def_fr_1->meas_info_lst[j].meas_type.name.len);
meas_info_name_str[act_def_fr_1->meas_info_lst[j].meas_type.name.len] = '\0';
msg_frm_1.meas_data_lst[i].meas_record_lst[j] = fill_ue_pdcp_data(rrc_ue_id, ue_idx, meas_info_name_str);
break;
}
case ID_MEAS_TYPE:
assert(false && "ID Measurement Type not yet implemented");
default:
assert(false && "Measurement Type not recognized");
}
}
}
// Measurement Information - OPTIONAL
msg_frm_1.meas_info_lst_len = act_def_fr_1->meas_info_lst_len;
msg_frm_1.meas_info_lst = calloc(msg_frm_1.meas_info_lst_len, sizeof(meas_info_format_1_lst_t));
assert(msg_frm_1.meas_info_lst != NULL && "Memory exhausted");
for (size_t i = 0; i < msg_frm_1.meas_info_lst_len; i++) {
msg_frm_1.meas_info_lst[i] = cp_meas_info_format_1_lst(&act_def_fr_1->meas_info_lst[i]);
}
return msg_frm_1;
}
__attribute__((unused))
static kpm_ind_msg_format_3_t fill_kpm_ind_msg_frm_3_in_cuup(const matched_ues_pdcp_t* matched_ues,
const kpm_act_def_format_1_t* act_def_fr_1)
{
assert(act_def_fr_1 != NULL);
kpm_ind_msg_format_3_t msg_frm_3 = {0};
// Fill UE Measurement Reports
msg_frm_3.ue_meas_report_lst_len = matched_ues->num_ues;
msg_frm_3.meas_report_per_ue = calloc(msg_frm_3.ue_meas_report_lst_len, sizeof(meas_report_per_ue_t));
assert(msg_frm_3.meas_report_per_ue != NULL && "Memory exhausted");
for (size_t i = 0; i<msg_frm_3.ue_meas_report_lst_len; i++) {
// Fill UE ID data
msg_frm_3.meas_report_per_ue[i].ue_meas_report_lst.type = GNB_CU_UP_UE_ID_E2SM;
msg_frm_3.meas_report_per_ue[i].ue_meas_report_lst.gnb_cu_up = fill_gnb_cu_up_data(matched_ues->pdcp_ue_id_list[i]);
// Fill UE related info
msg_frm_3.meas_report_per_ue[i].ind_msg_format_1 =
fill_kpm_ind_msg_frm_1_in_cu(matched_ues->pdcp_ue_id_list[i], i, act_def_fr_1);
}
return msg_frm_3;
}
#endif
#if defined (NGRAN_GNB_DU)
static uldlcounter_t last_rlc_pdu_total_bytes[MAX_MOBILES_PER_GNB] = {0};
static uldlcounter_t last_total_prbs[MAX_MOBILES_PER_GNB] = {0};
static gnb_e2sm_t fill_gnb_data(rrc_gNB_ue_context_t * ue_context_p)
{
gnb_e2sm_t gnb = {0};
......@@ -165,24 +255,20 @@ gnb_e2sm_t fill_gnb_data(rrc_gNB_ue_context_t * ue_context_p)
// gNB-CU UE F1AP ID List
// C-ifCUDUseparated
if (NODE_IS_CU(RC.nrrrc[0]->node_type))
{
if (NODE_IS_CU(RC.nrrrc[0]->node_type)) {
gnb.gnb_cu_ue_f1ap_lst_len = 1;
gnb.gnb_cu_ue_f1ap_lst = calloc(gnb.gnb_cu_ue_f1ap_lst_len, sizeof(uint32_t));
assert(gnb.gnb_cu_ue_f1ap_lst != NULL);
for (size_t i = 0; i < gnb.gnb_cu_ue_f1ap_lst_len; i++)
{
for (size_t i = 0; i < gnb.gnb_cu_ue_f1ap_lst_len; i++) {
gnb.gnb_cu_ue_f1ap_lst[i] = ue_context_p->ue_context.rrc_ue_id;
}
}
return gnb;
}
static
gnb_du_e2sm_t fill_gnb_du_data(const f1_ue_data_t * rrc_ue_id)
static gnb_du_e2sm_t fill_gnb_du_data(const f1_ue_data_t * rrc_ue_id)
{
gnb_du_e2sm_t gnb_du = {0};
......@@ -191,7 +277,6 @@ gnb_du_e2sm_t fill_gnb_du_data(const f1_ue_data_t * rrc_ue_id)
// Mandatory
gnb_du.gnb_cu_ue_f1ap = rrc_ue_id->secondary_ue;
// 6.2.3.25
// RAN UE ID
// Optional
......@@ -199,19 +284,58 @@ gnb_du_e2sm_t fill_gnb_du_data(const f1_ue_data_t * rrc_ue_id)
return gnb_du;
}
typedef struct {
NR_UE_info_t* ue_list[MAX_MOBILES_PER_GNB];
size_t num_ues;
} matched_ues_mac_t;
static size_t filter_ues_by_s_nssai_in_du_or_monolithic(test_cond_e const condition,
uint8_t sst,
const uint32_t *sd,
matched_ues_mac_t* matches)
{
DevAssert(matches != NULL);
AssertFatal(condition == EQUAL_TEST_COND, "Condition %d not yet implemented", condition);
// Take MAC info
size_t i = 0;
UE_iterator (RC.nrmac[0]->UE_info.list, ue) {
NR_UE_sched_ctrl_t *sched_ctrl = &ue->UE_sched_ctrl;
// UE matches if any of its DRBs matches
for (int l = 0; l < sched_ctrl->dl_lc_num; ++l) {
long lcid = sched_ctrl->dl_lc_ids[l];
if (nssai_matches(sched_ctrl->dl_lc_nssai[lcid], sst, sd)) {
matches->ue_list[i++] = ue;
break;
}
}
AssertFatal(i < MAX_MOBILES_PER_GNB, "cannot have more UEs than global UE number maximum\n");
}
matches->num_ues = i;
return i;
}
static nr_rlc_statistics_t get_rlc_stats_per_drb(NR_UE_info_t const * UE)
{
assert(UE != NULL);
nr_rlc_statistics_t rlc = {0};
const int srb_flag = 0;
const int rb_id = 1; // at the moment, only 1 DRB is supported
// Bad bad bad. Create a proper exponential moving average filter or at least, only read statistics
// Avoid coupling among sublayers
static uint32_t last_dl_rlc_pdu_total_bytes[MAX_MOBILES_PER_GNB] = {0};
static uint32_t last_ul_rlc_pdu_total_bytes[MAX_MOBILES_PER_GNB] = {0};
static uint32_t last_dl_total_prbs[MAX_MOBILES_PER_GNB] = {0};
static uint32_t last_ul_total_prbs[MAX_MOBILES_PER_GNB] = {0};
static uint32_t last_dl_pdcp_sdu_total_bytes[MAX_MOBILES_PER_GNB] = {0};
static uint32_t last_ul_pdcp_sdu_total_bytes[MAX_MOBILES_PER_GNB] = {0};
// Get RLC stats for specific DRB
const bool rc = nr_rlc_get_statistics(UE->rnti, srb_flag, rb_id, &rlc);
assert(rc == true && "Cannot get RLC stats\n");
// Activate average sojourn time at the RLC buffer for specific DRB
nr_rlc_activate_avg_time_to_tx(UE->rnti, rb_id+3, 1);
return rlc;
}
static
meas_record_lst_t fill_ue_mac_rlc_data(const NR_UE_info_t* UE, const size_t ue_idx, const char * meas_info_name_str, const uint32_t gran_period_ms)
static meas_record_lst_t fill_ue_mac_rlc_data(const NR_UE_info_t* UE, const size_t ue_idx, const char * meas_info_name_str, const uint32_t gran_period_ms)
{
assert(UE != NULL);
......@@ -221,136 +345,52 @@ meas_record_lst_t fill_ue_mac_rlc_data(const NR_UE_info_t* UE, const size_t ue_i
nr_rlc_statistics_t rlc = get_rlc_stats_per_drb(UE);
// Measurement Type as requested in Action Definition
if (strcmp(meas_info_name_str, "DRB.UEThpDl") == 0) // 3GPP TS 28.522 - section 5.1.1.3.1
{
if (strcmp(meas_info_name_str, "DRB.UEThpDl") == 0) { // 3GPP TS 28.522 - section 5.1.1.3.1
meas_record.value = REAL_MEAS_VALUE;
// Calculate DL Thp
meas_record.real_val = (double)(rlc.txpdu_bytes - last_dl_rlc_pdu_total_bytes[ue_idx])*8/gran_period_ms; // [kbps]
last_dl_rlc_pdu_total_bytes[ue_idx] = rlc.txpdu_bytes;
meas_record.real_val = (double)(rlc.txpdu_bytes - last_rlc_pdu_total_bytes[ue_idx].dl)*8/gran_period_ms; // [kbps]
last_rlc_pdu_total_bytes[ue_idx].dl = rlc.txpdu_bytes;
/* note: per spec, average UE throughput in DL (taken into consideration values from all UEs, and averaged)
here calculated as: UE specific throughput in DL */
}
else if (strcmp(meas_info_name_str, "DRB.UEThpUl") == 0) // 3GPP TS 28.522 - section 5.1.1.3.3
{
} else if (strcmp(meas_info_name_str, "DRB.UEThpUl") == 0) { // 3GPP TS 28.522 - section 5.1.1.3.3
meas_record.value = REAL_MEAS_VALUE;
// Calculate UL Thp
meas_record.real_val = (double)(rlc.rxpdu_bytes - last_ul_rlc_pdu_total_bytes[ue_idx])*8/gran_period_ms; // [kbps]
last_ul_rlc_pdu_total_bytes[ue_idx] = rlc.rxpdu_bytes;
meas_record.real_val = (double)(rlc.rxpdu_bytes - last_rlc_pdu_total_bytes[ue_idx].ul)*8/gran_period_ms; // [kbps]
last_rlc_pdu_total_bytes[ue_idx].ul = rlc.rxpdu_bytes;
/* note: per spec, average UE throughput in UL (taken into consideration values from all UEs, and averaged)
here calculated as: UE specific throughput in UL */
}
else if (strcmp(meas_info_name_str, "DRB.RlcSduDelayDl") == 0) // 3GPP TS 28.522 - section 5.1.3.3.3
{
} else if (strcmp(meas_info_name_str, "DRB.RlcSduDelayDl") == 0) { // 3GPP TS 28.522 - section 5.1.3.3.3
meas_record.value = REAL_MEAS_VALUE;
// Get the value of sojourn time at the RLC buffer
meas_record.real_val = rlc.txsdu_avg_time_to_tx; // [μs]
/* note: by default this measurement is calculated for previous 100ms (openair2/LAYER2/nr_rlc/nr_rlc_entity.c:118, 173, 213); please, update according to your needs */
}
else if (strcmp(meas_info_name_str, "RRU.PrbTotDl") == 0) // 3GPP TS 28.522 - section 5.1.1.2.1
{
} else if (strcmp(meas_info_name_str, "RRU.PrbTotDl") == 0) { // 3GPP TS 28.522 - section 5.1.1.2.1
meas_record.value = INTEGER_MEAS_VALUE;
// Get the number of DL PRBs
meas_record.int_val = UE->mac_stats.dl.total_rbs - last_dl_total_prbs[ue_idx]; // [PRBs]
last_dl_total_prbs[ue_idx] = UE->mac_stats.dl.total_rbs;
meas_record.int_val = UE->mac_stats.dl.total_rbs - last_total_prbs[ue_idx].dl; // [PRBs]
last_total_prbs[ue_idx].dl = UE->mac_stats.dl.total_rbs;
/* note: per spec, DL PRB usage [%] = (total used PRBs for DL traffic / total available PRBs for DL traffic) * 100
here calculated as: aggregated DL PRBs (t) - aggregated DL PRBs (t-gran_period) */
}
else if (strcmp(meas_info_name_str, "RRU.PrbTotUl") == 0) // 3GPP TS 28.522 - section 5.1.1.2.2
{
} else if (strcmp(meas_info_name_str, "RRU.PrbTotUl") == 0) { // 3GPP TS 28.522 - section 5.1.1.2.2
meas_record.value = INTEGER_MEAS_VALUE;
// Get the number of UL PRBs
meas_record.int_val = UE->mac_stats.ul.total_rbs - last_ul_total_prbs[ue_idx]; // [PRBs]
last_ul_total_prbs[ue_idx] = UE->mac_stats.ul.total_rbs;
meas_record.int_val = UE->mac_stats.ul.total_rbs - last_total_prbs[ue_idx].ul; // [PRBs]
last_total_prbs[ue_idx].ul = UE->mac_stats.ul.total_rbs;
/* note: per spec, UL PRB usage [%] = (total used PRBs for UL traffic / total available PRBs for UL traffic) * 100
here calculated as: aggregated UL PRBs (t) - aggregated UL PRBs (t-gran_period) */
}
else
{
assert(false && "Measurement Name not yet implemented");
}
return meas_record;
}
static
meas_record_lst_t fill_ue_pdcp_data(const uint32_t rrc_ue_id, const size_t ue_idx, const char * meas_info_name_str)
{
meas_record_lst_t meas_record = {0};
// Get PDCP stats per DRB
nr_pdcp_statistics_t pdcp = get_pdcp_stats_per_drb(rrc_ue_id);
// Measurement Type as requested in Action Definition
if (strcmp(meas_info_name_str, "DRB.PdcpSduVolumeDL") == 0) // 3GPP TS 28.522 - section 5.1.2.1.1.1
{
meas_record.value = INTEGER_MEAS_VALUE;
// Get DL data volume delivered to PDCP layer
meas_record.int_val = (pdcp.rxsdu_bytes - last_dl_pdcp_sdu_total_bytes[ue_idx])*8/1000; // [kb]
last_dl_pdcp_sdu_total_bytes[ue_idx] = pdcp.rxsdu_bytes;
/* note: this measurement is calculated as per spec */
}
else if (strcmp(meas_info_name_str, "DRB.PdcpSduVolumeUL") == 0) // 3GPP TS 28.522 - section 5.1.2.1.2.1
{
meas_record.value = INTEGER_MEAS_VALUE;
// Get UL data volume delivered from PDCP layer
meas_record.int_val = (pdcp.txsdu_bytes - last_ul_pdcp_sdu_total_bytes[ue_idx])*8/1000; // [kb]
last_ul_pdcp_sdu_total_bytes[ue_idx] = pdcp.txsdu_bytes;
/* note: this measurement is calculated as per spec */
}
else
{
} else {
assert(false && "Measurement Name not yet implemented");
}
return meas_record;
}
static
meas_info_format_1_lst_t * fill_kpm_meas_info_frm_1(const size_t len, const kpm_act_def_format_1_t * act_def_fr_1)
{
meas_info_format_1_lst_t * meas_info_lst = calloc(len, sizeof(meas_info_format_1_lst_t));
assert(meas_info_lst != NULL && "Memory exhausted" );
// Get measInfo from action definition
for (size_t i = 0; i < len; i++)
{
// Measurement Type
meas_info_lst[i].meas_type.type = act_def_fr_1->meas_info_lst[i].meas_type.type;
// Measurement Name
if (act_def_fr_1->meas_info_lst[i].meas_type.type == NAME_MEAS_TYPE) {
meas_info_lst[i].meas_type.name.buf = calloc(act_def_fr_1->meas_info_lst[i].meas_type.name.len, sizeof(uint8_t));
memcpy(meas_info_lst[i].meas_type.name.buf, act_def_fr_1->meas_info_lst[i].meas_type.name.buf, act_def_fr_1->meas_info_lst[i].meas_type.name.len);
meas_info_lst[i].meas_type.name.len = act_def_fr_1->meas_info_lst[i].meas_type.name.len;
} else {
meas_info_lst[i].meas_type.id = act_def_fr_1->meas_info_lst[i].meas_type.id;
}
// Label Information
meas_info_lst[i].label_info_lst_len = 1;
meas_info_lst[i].label_info_lst = calloc(meas_info_lst[i].label_info_lst_len, sizeof(label_info_lst_t));
assert(meas_info_lst[i].label_info_lst != NULL && "Memory exhausted" );
for (size_t j = 0; j < meas_info_lst[i].label_info_lst_len; j++) {
meas_info_lst[i].label_info_lst[j].noLabel = malloc(sizeof(enum_value_e));
*meas_info_lst[i].label_info_lst[j].noLabel = TRUE_ENUM_VALUE;
}
}
return meas_info_lst;
}
static
kpm_ind_msg_format_1_t fill_kpm_ind_msg_frm_1_in_du(const NR_UE_info_t* UE, const size_t ue_idx, const kpm_act_def_format_1_t * act_def_fr_1)
static kpm_ind_msg_format_1_t fill_kpm_ind_msg_frm_1_in_du(const NR_UE_info_t* UE, const size_t ue_idx, const kpm_act_def_format_1_t * act_def_fr_1)
{
kpm_ind_msg_format_1_t msg_frm_1 = {0};
......@@ -361,21 +401,17 @@ kpm_ind_msg_format_1_t fill_kpm_ind_msg_frm_1_in_du(const NR_UE_info_t* UE, cons
msg_frm_1.meas_data_lst = calloc(msg_frm_1.meas_data_lst_len, sizeof(*msg_frm_1.meas_data_lst));
assert(msg_frm_1.meas_data_lst != NULL && "Memory exhausted" );
for (size_t i = 0; i<msg_frm_1.meas_data_lst_len; i++)
{
for (size_t i = 0; i<msg_frm_1.meas_data_lst_len; i++) {
// Measurement Record
msg_frm_1.meas_data_lst[i].meas_record_len = act_def_fr_1->meas_info_lst_len; // record data list length corresponds to info list length from action definition
msg_frm_1.meas_data_lst[i].meas_record_lst = calloc(msg_frm_1.meas_data_lst[i].meas_record_len, sizeof(meas_record_lst_t));
assert(msg_frm_1.meas_data_lst[i].meas_record_lst != NULL && "Memory exhausted");
for (size_t j = 0; j < msg_frm_1.meas_data_lst[i].meas_record_len; j++) // each meas record corresponds to one meas type
{
for (size_t j = 0; j < msg_frm_1.meas_data_lst[i].meas_record_len; j++) { // each meas record corresponds to one meas type
// Measurement Type as requested in Action Definition
switch (act_def_fr_1->meas_info_lst[j].meas_type.type)
{
case NAME_MEAS_TYPE:
{
switch (act_def_fr_1->meas_info_lst[j].meas_type.type) {
case NAME_MEAS_TYPE: {
char meas_info_name_str[act_def_fr_1->meas_info_lst[j].meas_type.name.len + 1];
memcpy(meas_info_name_str, act_def_fr_1->meas_info_lst[j].meas_type.name.buf, act_def_fr_1->meas_info_lst[j].meas_type.name.len);
meas_info_name_str[act_def_fr_1->meas_info_lst[j].meas_type.name.len] = '\0';
......@@ -383,22 +419,22 @@ kpm_ind_msg_format_1_t fill_kpm_ind_msg_frm_1_in_du(const NR_UE_info_t* UE, cons
msg_frm_1.meas_data_lst[i].meas_record_lst[j] = fill_ue_mac_rlc_data(UE, ue_idx, meas_info_name_str, act_def_fr_1->gran_period_ms);
break;
}
case ID_MEAS_TYPE:
assert(false && "ID Measurement Type not yet implemented");
break;
default:
assert(false && "Measurement Type not recognized");
break;
}
}
}
// Measurement Information - OPTIONAL
msg_frm_1.meas_info_lst_len = act_def_fr_1->meas_info_lst_len;
msg_frm_1.meas_info_lst = fill_kpm_meas_info_frm_1(msg_frm_1.meas_info_lst_len, act_def_fr_1);
msg_frm_1.meas_info_lst = calloc(msg_frm_1.meas_info_lst_len, sizeof(meas_info_format_1_lst_t));
assert(msg_frm_1.meas_info_lst != NULL && "Memory exhausted");
for (size_t i = 0; i < msg_frm_1.meas_info_lst_len; i++) {
msg_frm_1.meas_info_lst[i] = cp_meas_info_format_1_lst(&act_def_fr_1->meas_info_lst[i]);
}
return msg_frm_1;
}
......@@ -417,8 +453,7 @@ static kpm_ind_msg_format_3_t fill_kpm_ind_msg_frm_3_in_du(const matched_ues_mac
msg_frm_3.meas_report_per_ue = calloc(msg_frm_3.ue_meas_report_lst_len, sizeof(meas_report_per_ue_t));
assert(msg_frm_3.meas_report_per_ue != NULL && "Memory exhausted");
for (size_t i = 0; i<msg_frm_3.ue_meas_report_lst_len; i++)
{
for (size_t i = 0; i<msg_frm_3.ue_meas_report_lst_len; i++) {
// Fill UE ID data
f1_ue_data_t rrc_ue_id = du_get_f1_ue_data(matched_ues->ue_list[i]->rnti); // get gNB CU UE ID as rrc_ue_id
msg_frm_3.meas_report_per_ue[i].ue_meas_report_lst.type = GNB_DU_UE_ID_E2SM;
......@@ -432,8 +467,7 @@ static kpm_ind_msg_format_3_t fill_kpm_ind_msg_frm_3_in_du(const matched_ues_mac
return msg_frm_3;
}
static
kpm_ind_msg_format_1_t fill_kpm_ind_msg_frm_1_in_cu(const uint32_t rrc_ue_id, const size_t ue_idx, const kpm_act_def_format_1_t * act_def_fr_1)
static kpm_ind_msg_format_1_t fill_kpm_ind_msg_frm_1_in_monolithic(const NR_UE_info_t* UE, const size_t ue_idx, const uint32_t rrc_ue_id, const kpm_act_def_format_1_t * act_def_fr_1)
{
kpm_ind_msg_format_1_t msg_frm_1 = {0};
......@@ -444,50 +478,51 @@ kpm_ind_msg_format_1_t fill_kpm_ind_msg_frm_1_in_cu(const uint32_t rrc_ue_id, co
msg_frm_1.meas_data_lst = calloc(msg_frm_1.meas_data_lst_len, sizeof(*msg_frm_1.meas_data_lst));
assert(msg_frm_1.meas_data_lst != NULL && "Memory exhausted" );
for (size_t i = 0; i<msg_frm_1.meas_data_lst_len; i++)
{
for (size_t i = 0; i<msg_frm_1.meas_data_lst_len; i++) {
// Measurement Record
msg_frm_1.meas_data_lst[i].meas_record_len = act_def_fr_1->meas_info_lst_len; // record data list length corresponds to info list length from action definition
msg_frm_1.meas_data_lst[i].meas_record_lst = calloc(msg_frm_1.meas_data_lst[i].meas_record_len, sizeof(meas_record_lst_t));
assert(msg_frm_1.meas_data_lst[i].meas_record_lst != NULL && "Memory exhausted");
for (size_t j = 0; j < msg_frm_1.meas_data_lst[i].meas_record_len; j++) // each meas record corresponds to one meas type
{
for (size_t j = 0; j < msg_frm_1.meas_data_lst[i].meas_record_len; j++) { // each meas record corresponds to one meas type
// Measurement Type as requested in Action Definition
switch (act_def_fr_1->meas_info_lst[j].meas_type.type)
{
case NAME_MEAS_TYPE:
{
switch (act_def_fr_1->meas_info_lst[j].meas_type.type) {
case NAME_MEAS_TYPE: {
char meas_info_name_str[act_def_fr_1->meas_info_lst[j].meas_type.name.len + 1];
memcpy(meas_info_name_str, act_def_fr_1->meas_info_lst[j].meas_type.name.buf, act_def_fr_1->meas_info_lst[j].meas_type.name.len);
meas_info_name_str[act_def_fr_1->meas_info_lst[j].meas_type.name.len] = '\0';
msg_frm_1.meas_data_lst[i].meas_record_lst[j] = fill_ue_pdcp_data(rrc_ue_id, ue_idx, meas_info_name_str);
if (strcmp(meas_info_name_str, "DRB.PdcpSduVolumeDL") == 0 || strcmp(meas_info_name_str, "DRB.PdcpSduVolumeUL") == 0) {
msg_frm_1.meas_data_lst[i].meas_record_lst[j] = fill_ue_pdcp_data(rrc_ue_id, ue_idx, meas_info_name_str);
} else {
msg_frm_1.meas_data_lst[i].meas_record_lst[j] = fill_ue_mac_rlc_data(UE, ue_idx, meas_info_name_str, act_def_fr_1->gran_period_ms);
}
break;
}
case ID_MEAS_TYPE:
assert(false && "ID Measurement Type not yet implemented");
break;
default:
assert(false && "Measurement Type not recognized");
break;
}
}
}
// Measurement Information - OPTIONAL
msg_frm_1.meas_info_lst_len = act_def_fr_1->meas_info_lst_len;
msg_frm_1.meas_info_lst = fill_kpm_meas_info_frm_1(msg_frm_1.meas_info_lst_len, act_def_fr_1);
msg_frm_1.meas_info_lst = calloc(msg_frm_1.meas_info_lst_len, sizeof(meas_info_format_1_lst_t));
assert(msg_frm_1.meas_info_lst != NULL && "Memory exhausted");
for (size_t i = 0; i < msg_frm_1.meas_info_lst_len; i++) {
msg_frm_1.meas_info_lst[i] = cp_meas_info_format_1_lst(&act_def_fr_1->meas_info_lst[i]);
}
return msg_frm_1;
}
static kpm_ind_msg_format_3_t fill_kpm_ind_msg_frm_3_in_cu(const matched_ues_rrc_t* matched_ues,
const kpm_act_def_format_1_t* act_def_fr_1)
static kpm_ind_msg_format_3_t fill_kpm_ind_msg_frm_3_in_monolithic(const matched_ues_mac_t* matched_ues,
const kpm_act_def_format_1_t* act_def_fr_1)
{
assert(act_def_fr_1 != NULL);
......@@ -500,85 +535,55 @@ static kpm_ind_msg_format_3_t fill_kpm_ind_msg_frm_3_in_cu(const matched_ues_rrc
msg_frm_3.meas_report_per_ue = calloc(msg_frm_3.ue_meas_report_lst_len, sizeof(meas_report_per_ue_t));
assert(msg_frm_3.meas_report_per_ue != NULL && "Memory exhausted");
for (size_t i = 0; i<msg_frm_3.ue_meas_report_lst_len; i++)
{
for (size_t i = 0; i<msg_frm_3.ue_meas_report_lst_len; i++) {
// Fill UE ID data
rrc_gNB_ue_context_t* rrc_ue_context_list = rrc_gNB_get_ue_context(RC.nrrrc[0], matched_ues->rrc_ue_id_list[i]);
rrc_gNB_ue_context_t* rrc_ue_context_list = rrc_gNB_get_ue_context_by_rnti_any_du(RC.nrrrc[0], matched_ues->ue_list[i]->rnti);
msg_frm_3.meas_report_per_ue[i].ue_meas_report_lst.type = GNB_UE_ID_E2SM;
msg_frm_3.meas_report_per_ue[i].ue_meas_report_lst.gnb = fill_gnb_data(rrc_ue_context_list);
// Fill UE related info
msg_frm_3.meas_report_per_ue[i].ind_msg_format_1 =
fill_kpm_ind_msg_frm_1_in_cu(matched_ues->rrc_ue_id_list[i], i, act_def_fr_1);
fill_kpm_ind_msg_frm_1_in_monolithic(matched_ues->ue_list[i], i, rrc_ue_context_list->ue_context.rrc_ue_id, act_def_fr_1);
}
return msg_frm_3;
}
#endif
static
kpm_ind_msg_format_1_t fill_kpm_ind_msg_frm_1_in_monolithic(const NR_UE_info_t* UE, const size_t ue_idx, const uint32_t rrc_ue_id, const kpm_act_def_format_1_t * act_def_fr_1)
{
kpm_ind_msg_format_1_t msg_frm_1 = {0};
// Measurement Data contains a set of Meas Records, each collected at each granularity period
msg_frm_1.meas_data_lst_len = 1; /* this value is equal to (kpm_ric_event_trigger_format_1.report_period_ms/act_def_fr_1->gran_period_ms)
please, check their values in xApp */
msg_frm_1.meas_data_lst = calloc(msg_frm_1.meas_data_lst_len, sizeof(*msg_frm_1.meas_data_lst));
assert(msg_frm_1.meas_data_lst != NULL && "Memory exhausted" );
for (size_t i = 0; i<msg_frm_1.meas_data_lst_len; i++)
{
// Measurement Record
msg_frm_1.meas_data_lst[i].meas_record_len = act_def_fr_1->meas_info_lst_len; // record data list length corresponds to info list length from action definition
#if defined (NGRAN_GNB_CUCP)
typedef struct {
uint32_t rrc_ue_id_list[MAX_MOBILES_PER_GNB]; // list of matched UEs on RRC level containing only rrc_ue_id (gNB CU UE ID)
size_t num_ues;
msg_frm_1.meas_data_lst[i].meas_record_lst = calloc(msg_frm_1.meas_data_lst[i].meas_record_len, sizeof(meas_record_lst_t));
assert(msg_frm_1.meas_data_lst[i].meas_record_lst != NULL && "Memory exhausted");
} matched_ues_rrc_t;
for (size_t j = 0; j < msg_frm_1.meas_data_lst[i].meas_record_len; j++) // each meas record corresponds to one meas type
{
// Measurement Type as requested in Action Definition
switch (act_def_fr_1->meas_info_lst[j].meas_type.type)
{
case NAME_MEAS_TYPE:
{
char meas_info_name_str[act_def_fr_1->meas_info_lst[j].meas_type.name.len + 1];
memcpy(meas_info_name_str, act_def_fr_1->meas_info_lst[j].meas_type.name.buf, act_def_fr_1->meas_info_lst[j].meas_type.name.len);
meas_info_name_str[act_def_fr_1->meas_info_lst[j].meas_type.name.len] = '\0';
static size_t filter_ues_by_s_nssai_in_cu(test_cond_e const condition, uint8_t sst, const uint32_t *sd, matched_ues_rrc_t* matches)
{
DevAssert(matches != NULL);
AssertFatal(condition == EQUAL_TEST_COND, "Condition %d not yet implemented\n", condition);
if (strcmp(meas_info_name_str, "DRB.PdcpSduVolumeDL") == 0 || strcmp(meas_info_name_str, "DRB.PdcpSduVolumeUL") == 0)
{
msg_frm_1.meas_data_lst[i].meas_record_lst[j] = fill_ue_pdcp_data(rrc_ue_id, ue_idx, meas_info_name_str);
}
else
{
msg_frm_1.meas_data_lst[i].meas_record_lst[j] = fill_ue_mac_rlc_data(UE, ue_idx, meas_info_name_str, act_def_fr_1->gran_period_ms);
}
struct rrc_gNB_ue_context_s *ue_context_p1 = NULL;
size_t i = 0;
RB_FOREACH(ue_context_p1, rrc_nr_ue_tree_s, &RC.nrrrc[0]->rrc_ue_head) {
gNB_RRC_UE_t *ue = &ue_context_p1->ue_context;
for (int p = 0; p < ue->nb_of_pdusessions; ++p) {
pdusession_t *pdu = &ue->pduSession[0].param;
if (nssai_matches(pdu->nssai, sst, sd)) {
matches->rrc_ue_id_list[i++] = ue_context_p1->ue_context.rrc_ue_id;
break;
}
case ID_MEAS_TYPE:
assert(false && "ID Measurement Type not yet implemented");
break;
default:
assert(false && "Measurement Type not recognized");
break;
}
}
AssertFatal(i < MAX_MOBILES_PER_GNB, "cannot have more UEs than global UE number maximum\n");
}
// Measurement Information - OPTIONAL
msg_frm_1.meas_info_lst_len = act_def_fr_1->meas_info_lst_len;
msg_frm_1.meas_info_lst = fill_kpm_meas_info_frm_1(msg_frm_1.meas_info_lst_len, act_def_fr_1);
return msg_frm_1;
matches->num_ues = i;
return i;
}
static kpm_ind_msg_format_3_t fill_kpm_ind_msg_frm_3_in_monolithic(const matched_ues_mac_t* matched_ues,
const kpm_act_def_format_1_t* act_def_fr_1)
static kpm_ind_msg_format_3_t fill_kpm_ind_msg_frm_3_in_cu(const matched_ues_rrc_t* matched_ues,
const kpm_act_def_format_1_t* act_def_fr_1)
{
assert(act_def_fr_1 != NULL);
......@@ -591,31 +596,29 @@ static kpm_ind_msg_format_3_t fill_kpm_ind_msg_frm_3_in_monolithic(const matched
msg_frm_3.meas_report_per_ue = calloc(msg_frm_3.ue_meas_report_lst_len, sizeof(meas_report_per_ue_t));
assert(msg_frm_3.meas_report_per_ue != NULL && "Memory exhausted");
for (size_t i = 0; i<msg_frm_3.ue_meas_report_lst_len; i++)
{
for (size_t i = 0; i<msg_frm_3.ue_meas_report_lst_len; i++) {
// Fill UE ID data
rrc_gNB_ue_context_t* rrc_ue_context_list = rrc_gNB_get_ue_context_by_rnti_any_du(RC.nrrrc[0], matched_ues->ue_list[i]->rnti);
rrc_gNB_ue_context_t* rrc_ue_context_list = rrc_gNB_get_ue_context(RC.nrrrc[0], matched_ues->rrc_ue_id_list[i]);
msg_frm_3.meas_report_per_ue[i].ue_meas_report_lst.type = GNB_UE_ID_E2SM;
msg_frm_3.meas_report_per_ue[i].ue_meas_report_lst.gnb = fill_gnb_data(rrc_ue_context_list);
// Fill UE related info
msg_frm_3.meas_report_per_ue[i].ind_msg_format_1 =
fill_kpm_ind_msg_frm_1_in_monolithic(matched_ues->ue_list[i], i, rrc_ue_context_list->ue_context.rrc_ue_id, act_def_fr_1);
fill_kpm_ind_msg_frm_1_in_cu(matched_ues->rrc_ue_id_list[i], i, act_def_fr_1);
}
return msg_frm_3;
}
#endif
static
kpm_ric_ind_hdr_format_1_t kpm_ind_hdr_frm_1(void)
static kpm_ric_ind_hdr_format_1_t kpm_ind_hdr_frm_1(void)
{
kpm_ric_ind_hdr_format_1_t hdr_frm_1 = {0};
int64_t const t = time_now_us();
#if defined KPM_V2
#if defined KPM_V2_03
hdr_frm_1.collectStartTime = t/1000000; // seconds
#elif defined KPM_V3
#elif defined KPM_V3_00
hdr_frm_1.collectStartTime = t; // microseconds
#else
static_assert(0!=0, "Undefined KPM SM Version");
......@@ -624,44 +627,55 @@ kpm_ric_ind_hdr_format_1_t kpm_ind_hdr_frm_1(void)
hdr_frm_1.fileformat_version = NULL;
// Check E2 Node NG-RAN Type
if (NODE_IS_DU(RC.nrrrc[0]->node_type))
{
#if defined (NGRAN_GNB_DU)
if (RC.nrrrc[0]->node_type == ngran_gNB_DU) {
hdr_frm_1.sender_name = calloc(1, sizeof(byte_array_t));
hdr_frm_1.sender_name->buf = calloc(strlen("My OAI-DU") + 1, sizeof(char));
memcpy(hdr_frm_1.sender_name->buf, "My OAI-DU", strlen("My OAI-DU"));
hdr_frm_1.sender_name->len = strlen("My OAI-DU");
hdr_frm_1.sender_name->buf = calloc(strlen("OAI-DU") + 1, sizeof(char));
memcpy(hdr_frm_1.sender_name->buf, "OAI-DU", strlen("OAI-DU"));
hdr_frm_1.sender_name->len = strlen("OAI-DU");
hdr_frm_1.sender_type = calloc(1, sizeof(byte_array_t));
hdr_frm_1.sender_type->buf = calloc(strlen("DU") + 1, sizeof(char));
memcpy(hdr_frm_1.sender_type->buf, "DU", strlen("DU"));
hdr_frm_1.sender_type->len = strlen("DU");
}
else if (NODE_IS_CU(RC.nrrrc[0]->node_type))
{
} else if (RC.nrrrc[0]->node_type == ngran_gNB_CU) {
hdr_frm_1.sender_name = calloc(1, sizeof(byte_array_t));
hdr_frm_1.sender_name->buf = calloc(strlen("My OAI-CU") + 1, sizeof(char));
memcpy(hdr_frm_1.sender_name->buf, "My OAI-CU", strlen("My OAI-CU"));
hdr_frm_1.sender_name->len = strlen("My OAI-CU");
hdr_frm_1.sender_name->buf = calloc(strlen("OAI-CU") + 1, sizeof(char));
memcpy(hdr_frm_1.sender_name->buf, "OAI-CU", strlen("OAI-CU"));
hdr_frm_1.sender_name->len = strlen("OAI-CU");
hdr_frm_1.sender_type = calloc(1, sizeof(byte_array_t));
hdr_frm_1.sender_type->buf = calloc(strlen("CU") + 1, sizeof(char));
memcpy(hdr_frm_1.sender_type->buf, "CU", strlen("CU"));
hdr_frm_1.sender_type->len = strlen("CU");
}
else if (NODE_IS_MONOLITHIC(RC.nrrrc[0]->node_type))
{
} else if (RC.nrrrc[0]->node_type == ngran_gNB) {
hdr_frm_1.sender_name = calloc(1, sizeof(byte_array_t));
hdr_frm_1.sender_name->buf = calloc(strlen("My OAI-MONO") + 1, sizeof(char));
memcpy(hdr_frm_1.sender_name->buf, "My OAI-MONO", strlen("My OAI-MONO"));
hdr_frm_1.sender_name->len = strlen("My OAI-MONO");
hdr_frm_1.sender_name->buf = calloc(strlen("OAI-MONO") + 1, sizeof(char));
memcpy(hdr_frm_1.sender_name->buf, "OAI-MONO", strlen("OAI-MONO"));
hdr_frm_1.sender_name->len = strlen("OAI-MONO");
hdr_frm_1.sender_type = calloc(1, sizeof(byte_array_t));
hdr_frm_1.sender_type->buf = calloc(strlen("MONO") + 1, sizeof(char));
memcpy(hdr_frm_1.sender_type->buf, "MONO", strlen("MONO"));
hdr_frm_1.sender_type->len = strlen("MONO");
} else if (RC.nrrrc[0]->node_type == ngran_gNB_CUCP) {
return hdr_frm_1; // nothing to fill
} else {
assert(0!=0 && "Unknown node type");
}
#endif
#if defined (NGRAN_GNB_CUUP)
hdr_frm_1.sender_name = calloc(1, sizeof(byte_array_t));
hdr_frm_1.sender_name->buf = calloc(strlen("OAI-CU-UP") + 1, sizeof(char));
memcpy(hdr_frm_1.sender_name->buf, "OAI-CU-UP", strlen("OAI-CU-UP"));
hdr_frm_1.sender_name->len = strlen("OAI-CU-UP");
hdr_frm_1.sender_type = calloc(1, sizeof(byte_array_t));
hdr_frm_1.sender_type->buf = calloc(strlen("CU-UP") + 1, sizeof(char));
memcpy(hdr_frm_1.sender_type->buf, "CU-UP", strlen("CU-UP"));
hdr_frm_1.sender_type->len = strlen("CU-UP");
#endif
hdr_frm_1.vendor_name = calloc(1, sizeof(byte_array_t));
hdr_frm_1.vendor_name->buf = calloc(strlen("OAI") + 1, sizeof(char));
......@@ -690,31 +704,32 @@ static void capture_sst_sd(test_info_lst_t* test, uint8_t *sst, uint32_t **sd)
// we made a mistake in the past: NSSAI is supposed to be an OCTET_STRING,
// but earlier version of the RAN function and the xApp used integer, so
// handle this gracefully by accepting integer as well
switch (*test->test_cond_value) {
case INTEGER_TEST_COND_VALUE:
AssertFatal(*test->int_value <= 0xff, "illegal SST %ld\n", *test->int_value);
*sst = *test->int_value;
switch (test->test_cond_value->type) {
case INTEGER_TEST_COND_VALUE: {
AssertFatal(*test->test_cond_value->int_value <= 0xff, "illegal SST %ld\n", *test->test_cond_value->int_value);
*sst = *test->test_cond_value->int_value;
*sd = NULL;
break;
case OCTET_STRING_TEST_COND_VALUE:
if (test->octet_string_value->len == 1) {
*sst = test->octet_string_value->buf[0];
}
case OCTET_STRING_TEST_COND_VALUE: {
if (test->test_cond_value->octet_string_value->len == 1) {
*sst = test->test_cond_value->octet_string_value->buf[0];
*sd = NULL;
} else {
DevAssert(test->octet_string_value->len == 4);
uint8_t *buf = test->octet_string_value->buf;
DevAssert(test->test_cond_value->octet_string_value->len == 4);
uint8_t *buf = test->test_cond_value->octet_string_value->buf;
*sst = buf[0];
*sd = malloc(**sd);
**sd = buf[1] << 16 | buf[2] << 8 | buf[3];
}
break;
}
default:
AssertFatal(false, "test condition value %d impossible\n", *test->test_cond_value);
break;
AssertFatal(false, "test condition value %d impossible\n", test->test_cond_value->type);
}
}
void read_kpm_sm(void* data)
bool read_kpm_sm(void* data)
{
assert(data != NULL);
// assert(data->type == KPM_STATS_V3_0);
......@@ -767,9 +782,7 @@ void read_kpm_sm(void* data)
}
case CQI_TEST_COND_TYPE: {
// This is a bad idea. Done only to check FlexRIC xAPP
printf("CQI not implemented!. Randomly filling the data \n");
goto rnd_data_label;
assert(0 != 0 && "Not implemented");
break;
}
......@@ -786,28 +799,52 @@ void read_kpm_sm(void* data)
case S_NSSAI_TEST_COND_TYPE: {
assert(frm_4->matching_cond_lst[i].test_info_lst.S_NSSAI == TRUE_TEST_COND_TYPE && "Must be true");
assert(frm_4->matching_cond_lst[i].test_info_lst.test_cond != NULL && "Even though is optional..");
assert(frm_4->matching_cond_lst[i].test_info_lst.int_value != NULL && "Even though is optional..");
assert(frm_4->matching_cond_lst[i].test_info_lst.test_cond_value != NULL && "Even though is optional..");
test_cond_e const test_cond = *frm_4->matching_cond_lst[i].test_info_lst.test_cond;
uint8_t sst = 0;
uint32_t *sd = NULL;
capture_sst_sd(&frm_4->matching_cond_lst[i].test_info_lst, &sst, &sd);
// Check E2 Node NG-RAN Type
if (NODE_IS_DU(RC.nrrrc[0]->node_type)) {
/* Current implementation:
- we only have one executable nr-softmodem for 4 node types: DU, CU, gNB-mono, CU-CP
In the future, when nr-softmodem is separated, linking should be done as following:
DU: e2_ran_func_du
CU-CP : e2_ran_func_cucp
CU-UP: e2_ran_func_cuup (this is available at the moment, executable nr-cuup)
CU: e2_ran_func_cucp + e2_ran_func_cuup
gNB-mono: e2_ran_func_du + e2_ran_func_cucp + e2_ran_func_cuup */
#if defined (NGRAN_GNB_DU)
if (RC.nrrrc[0]->node_type == ngran_gNB_DU) {
matched_ues_mac_t matched_ues = {0};
matched_ues.num_ues = filter_ues_by_s_nssai_in_du_or_monolithic(test_cond, sst, sd, &matched_ues);
if (matched_ues.num_ues == 0) return false;
kpm->ind.msg.frm_3 = fill_kpm_ind_msg_frm_3_in_du(&matched_ues, &frm_4->action_def_format_1);
} else if (NODE_IS_CU(RC.nrrrc[0]->node_type)) {
} else if (RC.nrrrc[0]->node_type == ngran_gNB_CU) {
matched_ues_rrc_t matched_ues = {0};
matched_ues.num_ues = filter_ues_by_s_nssai_in_cu(test_cond, sst, sd, &matched_ues);
if (matched_ues.num_ues == 0) return false;
kpm->ind.msg.frm_3 = fill_kpm_ind_msg_frm_3_in_cu(&matched_ues, &frm_4->action_def_format_1);
} else if (NODE_IS_MONOLITHIC(RC.nrrrc[0]->node_type)) {
} else if (RC.nrrrc[0]->node_type == ngran_gNB) {
matched_ues_mac_t matched_ues = {0};
matched_ues.num_ues = filter_ues_by_s_nssai_in_du_or_monolithic(test_cond, sst, sd, &matched_ues);
if (matched_ues.num_ues == 0) return false;
kpm->ind.msg.frm_3 = fill_kpm_ind_msg_frm_3_in_monolithic(&matched_ues, &frm_4->action_def_format_1);
} else if (RC.nrrrc[0]->node_type == ngran_gNB_CUCP) {
return false; // at the moment, measurements regarding CU-CP node are not yet implemented
} else {
assert(false && "NG-RAN Type not implemented");
}
#elif defined (NGRAN_GNB_CUUP)
matched_ues_pdcp_t matched_ues = {0};
matched_ues.num_ues = filter_ues_by_s_nssai_in_cuup(test_cond, sst, sd, &matched_ues);
if (matched_ues.num_ues == 0) return false;
kpm->ind.msg.frm_3 = fill_kpm_ind_msg_frm_3_in_cuup(&matched_ues, &frm_4->action_def_format_1);
#endif
free(sd); // if NULL, nothing happens
break;
......@@ -822,13 +859,11 @@ void read_kpm_sm(void* data)
}
default: {
rnd_data_label:
kpm->ind.hdr = fill_rnd_kpm_ind_hdr();
kpm->ind.msg = fill_rnd_kpm_ind_msg();
break;
AssertFatal(kpm->act_def->type == FORMAT_4_ACTION_DEFINITION, "Action Definition Format %d not yet implemented", kpm->act_def->type);
}
}
return true;
}
void read_kpm_setup_sm(void* e2ap)
......@@ -847,4 +882,3 @@ sm_ag_if_ans_t write_ctrl_kpm_sm(void const* src)
sm_ag_if_ans_t ans = {0};
return ans;
}
......@@ -24,7 +24,7 @@
#include "openair2/E2AP/flexric/src/agent/../sm/sm_io.h"
void read_kpm_sm(void*);
bool read_kpm_sm(void*);
void read_kpm_setup_sm(void*);
......
......@@ -20,7 +20,7 @@
*/
#include "ran_func_rc.h"
#include "../../flexric/test/rnd/fill_rnd_data_rc.h"
#include "../../flexric/test/rnd/fill_rnd_data_rc.h" // this dependancy will be taken out once RAN Function Definition is implemented
#include "../../flexric/src/sm/rc_sm/ie/ir/lst_ran_param.h"
#include "../../flexric/src/sm/rc_sm/ie/ir/ran_param_list.h"
#include "../../flexric/src/agent/e2_agent_api.h"
......@@ -30,11 +30,15 @@
#include <pthread.h>
#include <unistd.h>
void read_rc_sm(void* data)
// Please note: current implementation doesn't take split architecture into account, neither CU/DU nor CU-UP/CU-CP
bool read_rc_sm(void* data)
{
assert(data != NULL);
// assert(data->type == RAN_CTRL_STATS_V1_03);
assert(0!=0 && "Not implemented");
return true;
}
void read_rc_setup_sm(void* data)
......
......@@ -24,7 +24,7 @@
#include "openair2/E2AP/flexric/src/agent/../sm/sm_io.h"
void read_rc_sm(void *);
bool read_rc_sm(void *);
void read_rc_setup_sm(void* data);
......
......@@ -22,24 +22,35 @@
#include "init_ran_func.h"
#include "read_setup_ran.h"
#include "../flexric/src/agent/e2_agent_api.h"
#if defined (NGRAN_GNB_DU)
#include "CUSTOMIZED/ran_func_mac.h"
#include "CUSTOMIZED/ran_func_rlc.h"
#include "CUSTOMIZED/ran_func_pdcp.h"
#include "CUSTOMIZED/ran_func_slice.h"
#endif
#if defined (NGRAN_GNB_CUUP)
#include "CUSTOMIZED/ran_func_tc.h"
#include "CUSTOMIZED/ran_func_gtp.h"
#include "CUSTOMIZED/ran_func_pdcp.h"
#endif
#include "O-RAN/ran_func_kpm.h"
#include "O-RAN/ran_func_rc.h"
static
void init_read_ind_tbl(read_ind_fp (*read_ind_tbl)[SM_AGENT_IF_READ_V0_END])
{
#if defined (NGRAN_GNB_DU)
(*read_ind_tbl)[MAC_STATS_V0] = read_mac_sm;
(*read_ind_tbl)[RLC_STATS_V0] = read_rlc_sm ;
(*read_ind_tbl)[PDCP_STATS_V0] = read_pdcp_sm ;
(*read_ind_tbl)[SLICE_STATS_V0] = read_slice_sm ;
#endif
#if defined (NGRAN_GNB_CUUP)
(*read_ind_tbl)[TC_STATS_V0] = read_tc_sm ;
(*read_ind_tbl)[GTP_STATS_V0] = read_gtp_sm ;
(*read_ind_tbl)[PDCP_STATS_V0] = read_pdcp_sm ;
#endif
(*read_ind_tbl)[KPM_STATS_V3_0] = read_kpm_sm ;
(*read_ind_tbl)[RAN_CTRL_STATS_V1_03] = read_rc_sm;
}
......@@ -47,12 +58,17 @@ void init_read_ind_tbl(read_ind_fp (*read_ind_tbl)[SM_AGENT_IF_READ_V0_END])
static
void init_read_setup_tbl(read_e2_setup_fp (*read_setup_tbl)[SM_AGENT_IF_E2_SETUP_ANS_V0_END])
{
#if defined (NGRAN_GNB_DU)
(*read_setup_tbl)[MAC_AGENT_IF_E2_SETUP_ANS_V0] = read_mac_setup_sm;
(*read_setup_tbl)[RLC_AGENT_IF_E2_SETUP_ANS_V0] = read_rlc_setup_sm ;
(*read_setup_tbl)[PDCP_AGENT_IF_E2_SETUP_ANS_V0] = read_pdcp_setup_sm ;
(*read_setup_tbl)[SLICE_AGENT_IF_E2_SETUP_ANS_V0] = read_slice_setup_sm ;
#endif
#if defined (NGRAN_GNB_CUUP)
(*read_setup_tbl)[TC_AGENT_IF_E2_SETUP_ANS_V0] = read_tc_setup_sm ;
(*read_setup_tbl)[GTP_AGENT_IF_E2_SETUP_ANS_V0] = read_gtp_setup_sm ;
(*read_setup_tbl)[PDCP_AGENT_IF_E2_SETUP_ANS_V0] = read_pdcp_setup_sm ;
#endif
(*read_setup_tbl)[KPM_V3_0_AGENT_IF_E2_SETUP_ANS_V0] = read_kpm_setup_sm ;
(*read_setup_tbl)[RAN_CTRL_V1_3_AGENT_IF_E2_SETUP_ANS_V0] = read_rc_setup_sm;
}
......@@ -60,24 +76,34 @@ void init_read_setup_tbl(read_e2_setup_fp (*read_setup_tbl)[SM_AGENT_IF_E2_SETUP
static
void init_write_ctrl( write_ctrl_fp (*write_ctrl_tbl)[SM_AGENT_IF_WRITE_CTRL_V0_END])
{
#if defined (NGRAN_GNB_DU)
(*write_ctrl_tbl)[MAC_CTRL_REQ_V0] = write_ctrl_mac_sm;
(*write_ctrl_tbl)[RLC_CTRL_REQ_V0] = write_ctrl_rlc_sm;
(*write_ctrl_tbl)[PDCP_CTRL_REQ_V0] = write_ctrl_pdcp_sm;
(*write_ctrl_tbl)[SLICE_CTRL_REQ_V0] = write_ctrl_slice_sm;
#endif
#if defined (NGRAN_GNB_CUUP)
(*write_ctrl_tbl)[TC_CTRL_REQ_V0] = write_ctrl_tc_sm;
(*write_ctrl_tbl)[GTP_CTRL_REQ_V0] = write_ctrl_gtp_sm;
(*write_ctrl_tbl)[PDCP_CTRL_REQ_V0] = write_ctrl_pdcp_sm;
#endif
(*write_ctrl_tbl)[RAN_CONTROL_CTRL_V1_03] = write_ctrl_rc_sm;
}
static
void init_write_subs(write_subs_fp (*write_subs_tbl)[SM_AGENT_IF_WRITE_SUBS_V0_END])
{
#if defined (NGRAN_GNB_DU)
(*write_subs_tbl)[MAC_SUBS_V0] = NULL;
(*write_subs_tbl)[RLC_SUBS_V0] = NULL;
(*write_subs_tbl)[PDCP_SUBS_V0] = NULL;
(*write_subs_tbl)[SLICE_SUBS_V0] = NULL;
#endif
#if defined (NGRAN_GNB_CUUP)
(*write_subs_tbl)[TC_SUBS_V0] = NULL;
(*write_subs_tbl)[GTP_SUBS_V0] = NULL;
(*write_subs_tbl)[PDCP_SUBS_V0] = NULL;
#endif
(*write_subs_tbl)[KPM_SUBS_V3_0] = NULL;
(*write_subs_tbl)[RAN_CTRL_SUBS_V1_03] = write_subs_rc_sm;
}
......@@ -96,4 +122,3 @@ sm_io_ag_ran_t init_ran_func_ag(void)
return io;
}
......@@ -25,18 +25,66 @@
#include <assert.h>
#include <stdlib.h>
void read_setup_ran(void* data)
void read_setup_ran(void* data, const ngran_node_t node_type)
{
assert(data != NULL);
#ifdef E2AP_V1
#elif defined(E2AP_V2) || defined(E2AP_V3)
*((e2ap_node_component_config_add_t*)data) = fill_e2ap_node_component_config_add();
arr_node_component_config_add_t* dst = (arr_node_component_config_add_t*)data;
if(node_type == ngran_gNB){
dst->len_cca = 1;
dst->cca = calloc(1, sizeof(e2ap_node_component_config_add_t));
assert(dst->cca != NULL);
// NGAP
dst->cca[0] = fill_ngap_e2ap_node_component_config_add();
} else if(node_type == ngran_gNB_CU){
dst->len_cca = 2;
dst->cca = calloc(2, sizeof(e2ap_node_component_config_add_t));
assert(dst->cca != NULL);
// NGAP
dst->cca[0] = fill_ngap_e2ap_node_component_config_add();
// F1AP
dst->cca[1] = fill_f1ap_e2ap_node_component_config_add();
} else if(node_type == ngran_gNB_DU){
dst->len_cca = 1;
dst->cca = calloc(1, sizeof(e2ap_node_component_config_add_t));
assert(dst->cca != NULL);
// F1AP
dst->cca[0] = fill_f1ap_e2ap_node_component_config_add();
} else if(node_type == ngran_gNB_CUCP){
dst->len_cca = 3;
dst->cca = calloc(3, sizeof(e2ap_node_component_config_add_t));
assert(dst->cca != NULL);
// NGAP
dst->cca[0] = fill_ngap_e2ap_node_component_config_add();
// F1AP
dst->cca[1] = fill_f1ap_e2ap_node_component_config_add();
// E1AP
dst->cca[2] = fill_e1ap_e2ap_node_component_config_add();
} else if(node_type == ngran_gNB_CUUP){
dst->len_cca = 3;
dst->cca = calloc(3, sizeof(e2ap_node_component_config_add_t));
assert(dst->cca != NULL);
// NGAP
dst->cca[0] = fill_ngap_e2ap_node_component_config_add();
// F1AP
dst->cca[1] = fill_f1ap_e2ap_node_component_config_add();
// E1AP
dst->cca[2] = fill_e1ap_e2ap_node_component_config_add();
} else if(node_type == ngran_eNB){
dst->len_cca = 1;
dst->cca = calloc(1, sizeof(e2ap_node_component_config_add_t));
assert(dst->cca != NULL);
// S1AP
dst->cca[0] = fill_s1ap_e2ap_node_component_config_add();
} else {
assert(0 != 0 && "Not implemented");
}
#else
static_assert(0!=0, "Unknown E2AP version");
#endif
}
......@@ -22,6 +22,8 @@
#ifndef READ_SETUP_RAN_E2_AGENT_H
#define READ_SETUP_RAN_E2_AGENT_H
void read_setup_ran(void* data);
#include "common/ngran_types.h"
void read_setup_ran(void* data, const ngran_node_t node_type);
#endif
......@@ -62,6 +62,15 @@ cd oai/
- By default, OAI will build the E2 Agent with E2AP v2 and KPM v2. If you want a different version, edit the variable E2AP\_VERSION and KPM\_VERSION at OAI's CMakeLists.txt file.
Currently available versions:
| |KPM v2.03|KPM v3.00|
|:-----------|:--------|:--------|
| E2AP v1.01 | Y | Y |
| E2AP v2.03 | Y | Y |
| E2AP v3.01 | Y | Y |
Please note that KPM SM v2.01 is supported only in FlexRIC, but not in OAI.
```bash
cd cmake_targets/
./build_oai -I -w SIMU --gNB --nrUE --build-e2 --ninja
......@@ -89,7 +98,7 @@ git submodule update
```bash
git clone https://gitlab.eurecom.fr/mosaic5g/flexric flexric
cd flexric/
git checkout 93961d2480b2c7a5721e03435cb34cf9446d1ad1
git checkout 70dd779f5339f4dac3ac176a24b49c45046a59fa
```
### 2.2.2 Build FlexRIC
......@@ -104,11 +113,21 @@ sudo make install
By default the service model libraries will be installed in the path `/usr/local/lib/flexric` while the configuration file in `/usr/local/etc/flexric`.
Available SMs in this version are:
* KPM v02.03 and KPM v03.00 (xapp_kpm_moni)
* RC v01.03 (xapp_kpm_rc)
* GTP (xapp_gtp_moni)
* MAC + RLC + PDCP (xapp_mac_rlc_pdcp_moni)
#### 2.2.3.1 Available Service Models
1. KPM v02.03 and KPM v03.00 (`xapp_kpm_moni`)
At the moment, the following measurements are supported in OAI RAN:
* "DRB.PdcpSduVolumeDL"
* "DRB.PdcpSduVolumeUL"
* "DRB.RlcSduDelayDl"
* "DRB.UEThpDl"
* "DRB.UEThpUl"
* "RRU.PrbTotDl"
* "RRU.PrbTotUl"
2. RC v01.03 (`xapp_kpm_rc`)
At the moment, OAI RAN supports the RAN control function "QoS flow mapping configuration", i.e. creating a new DRB.
3. MAC + RLC + PDCP + GTP (`xapp_gtp_mac_rlc_pdcp_moni`)
If you are interested in TC and SLICE SMs, please follow the instructions at https://gitlab.eurecom.fr/mosaic5g/flexric.
......@@ -122,16 +141,23 @@ e2_agent = {
}
```
* start the gNB
* start the gNB-mono
```bash
cd oai/cmake_targets/ran_build/build
sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf --rfsim --sa -E
```
* if CU-DU split is used, start the gNB as follows
* if CU/DU split is used, start the gNB as follows
```bash
sudo ./nr-softmodem -O <path_to_du_conf_file> --rfsim --sa -E
sudo ./nr-softmodem -O <path_to_cu_conf_file> --sa
```
* if CU-CP/CU-UP/DU split is used, start the gNB as follows
```bash
sudo ./nr-softmodem -O <path_to_du_conf_file> --rfsim --sa -E
sudo ./nr-softmodem -O <path_to_cu_conf_file> --rfsim --sa -E
sudo ./nr-softmodem -O <path_to_cu_cp_conf_file> --sa
sudo ./nr-cuup -O <path_to_cu_up_conf_file> --sa
```
* start the nrUE
......@@ -152,17 +178,17 @@ cd flexric
./build/examples/xApp/c/monitor/xapp_kpm_moni
```
* start the GTP xApp
```bash
cd flexric
./build/examples/xApp/c/monitor/xapp_gtp_moni
```
* start the (MAC + RLC + PDCP) xApp
* start the (MAC + RLC + PDCP + GTP) xApp
```bash
cd flexric
./build/examples/xApp/c/monitor/xapp_mac_rlc_pdcp_moni
./build/examples/xApp/c/monitor/xapp_gtp_mac_rlc_pdcp_moni
```
The latency that you observe in your monitor xApp is the latency from the E2 Agent to the nearRT-RIC and xApp.
Therefore, FlexRIC is well suited for use cases with ultra low-latency requirements.
Additionally, all the data received in the `xapp_gtp_mac_rlc_pdcp_moni` xApp is also written to /tmp/xapp_db in case that offline data processing is wanted (e.g., Machine Learning/Artificial Intelligence applications). You can browse the data using e.g., sqlitebrowser.
Please note:
* KPM SM database is not been updated, therefore commented in `flexric/src/xApp/db/sqlite3/sqlite3_wrapper.c:1152`
* RC SM database is not yet implemented.
# Optional - Multiple UEs
......
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "e2_agent_arg.h"
#include "e2_agent_paramdef.h"
#include "common/config/config_userapi.h"
e2_agent_args_t RCconfig_NR_E2agent(void)
{
paramdef_t e2agent_params[] = E2AGENT_PARAMS_DESC;
int ret = config_get(config_get_if(), e2agent_params, sizeofArray(e2agent_params), CONFIG_STRING_E2AGENT);
if (ret < 0) {
printf("configuration file does not contain a \"%s\" section, applying default parameters from FlexRIC\n", CONFIG_STRING_E2AGENT);
return (e2_agent_args_t) { 0 };
}
bool enabled = config_isparamset(e2agent_params, E2AGENT_CONFIG_SMDIR_IDX)
&& config_isparamset(e2agent_params, E2AGENT_CONFIG_IP_IDX);
e2_agent_args_t dst = {.enabled = enabled};
if (!enabled) {
printf("E2 agent is DISABLED (for activation, define .%s.{%s,%s} parameters)\n", CONFIG_STRING_E2AGENT, E2AGENT_CONFIG_IP, E2AGENT_CONFIG_SMDIR);
return dst;
}
if (e2agent_params[E2AGENT_CONFIG_SMDIR_IDX].strptr != NULL)
dst.sm_dir = *e2agent_params[E2AGENT_CONFIG_SMDIR_IDX].strptr;
if (e2agent_params[E2AGENT_CONFIG_IP_IDX].strptr != NULL)
dst.ip = *e2agent_params[E2AGENT_CONFIG_IP_IDX].strptr;
return dst;
}
......@@ -23,6 +23,8 @@
#define E2_AGENT_ARGS_H
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
// Wrapper for OAI
typedef struct{
......@@ -31,6 +33,8 @@ typedef struct{
const bool enabled;
} e2_agent_args_t;
e2_agent_args_t RCconfig_NR_E2agent(void);
#endif
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#ifndef E2_AGENT_PARAMDEF_H_
#define E2_AGENT_PARAMDEF_H_
/* E2 Agent configuration */
#define CONFIG_STRING_E2AGENT "e2_agent"
#define E2AGENT_CONFIG_IP "near_ric_ip_addr"
#define E2AGENT_CONFIG_SMDIR "sm_dir"
static const char* const e2agent_config_ip_default = "127.0.0.1";
static const char* const e2agent_config_smdir_default = ".";
#define E2AGENT_PARAMS_DESC { \
{E2AGENT_CONFIG_IP, "RIC IP address", 0, strptr:NULL, defstrval:(char*)e2agent_config_ip_default, TYPE_STRING, 0}, \
{E2AGENT_CONFIG_SMDIR, "Directory with SMs to load", 0, strptr:NULL, defstrval:(char*)e2agent_config_smdir_default, TYPE_STRING, 0}, \
}
#define E2AGENT_CONFIG_IP_IDX 0
#define E2AGENT_CONFIG_SMDIR_IDX 1
#endif
flexric @ 70dd779f
Subproject commit 93961d2480b2c7a5721e03435cb34cf9446d1ad1
Subproject commit 70dd779f5339f4dac3ac176a24b49c45046a59fa
......@@ -2931,35 +2931,3 @@ void read_config_and_init(void) {
RCconfig_RRC(enb_id, RC.rrc[enb_id]);
}
}
#ifdef E2_AGENT
e2_agent_args_t RCconfig_E2agent(void)
{
paramdef_t e2agent_params[] = E2AGENT_PARAMS_DESC;
int ret = config_get(config_get_if(), e2agent_params, sizeofArray(e2agent_params), CONFIG_STRING_E2AGENT);
if (ret < 0) {
LOG_W(GNB_APP, "configuration file does not contain a \"%s\" section, applying default parameters\n", CONFIG_STRING_E2AGENT);
return (e2_agent_args_t) {0};
}
bool enabled = config_isparamset(e2agent_params, E2AGENT_CONFIG_SMDIR_IDX)
&& config_isparamset(e2agent_params, E2AGENT_CONFIG_IP_IDX);
if (!enabled) {
LOG_W(GNB_APP, "E2 agent is DISABLED (for activation, define .%s.{%s,%s} parameters)\n", CONFIG_STRING_E2AGENT, E2AGENT_CONFIG_IP, E2AGENT_CONFIG_SMDIR);
return (e2_agent_args_t) {
.enabled = false,
};
}
return (e2_agent_args_t) {
.enabled = true,
.ip = *e2agent_params[E2AGENT_CONFIG_IP_IDX].strptr,
.sm_dir = *e2agent_params[E2AGENT_CONFIG_SMDIR_IDX].strptr,
};
}
#endif
......@@ -1321,32 +1321,7 @@ typedef struct srb1_params_s {
#define CONFIG_HLP_PARALLEL "PARALLEL_SINGLE_THREAD, PARALLEL_RU_L1_SPLIT, or PARALLEL_RU_L1_TRX_SPLIT(RU_L1_TRX_SPLIT by defult)\n"
/*-------------------------------------------------------------------------------------------------------------------------------------------------------------*/
#ifdef E2_AGENT
/* E2 Agent configuration */
#define CONFIG_STRING_E2AGENT "e2_agent"
#define E2AGENT_CONFIG_IP "near_ric_ip_addr"
//#define E2AGENT_CONFIG_PORT "port"
#define E2AGENT_CONFIG_SMDIR "sm_dir"
static const char* const e2agent_config_ip_default = "127.0.0.1";
static const char* const e2agent_config_smdir_default = ".";
#define E2AGENT_PARAMS_DESC { \
{E2AGENT_CONFIG_IP, "RIC IP address", 0, strptr:NULL, defstrval:(char*)e2agent_config_ip_default, TYPE_STRING, 0}, \
{E2AGENT_CONFIG_SMDIR, "Directory with SMs to load", 0, strptr:NULL, defstrval:(char*)e2agent_config_smdir_default, TYPE_STRING, 0}, \
}
/*
// {E2AGENT_CONFIG_PORT, "RIC port", 0, u16ptr:NULL, defuintval:e2agent_config_port_default, TYPE_UINT16, 0}, \
}
*/
#define E2AGENT_CONFIG_IP_IDX 0
#define E2AGENT_CONFIG_SMDIR_IDX 1
//#define E2AGENT_CONFIG_PORT_IDX 2
#endif // E2_AGENT
#include "enb_paramdef_emtc.h"
......
......@@ -2267,33 +2267,3 @@ ngran_node_t get_node_type(void)
return ngran_gNB;
}
}
#ifdef E2_AGENT
e2_agent_args_t RCconfig_NR_E2agent(void)
{
paramdef_t e2agent_params[] = E2AGENT_PARAMS_DESC;
int ret = config_get(config_get_if(), e2agent_params, sizeofArray(e2agent_params), CONFIG_STRING_E2AGENT);
if (ret < 0) {
LOG_W(GNB_APP, "configuration file does not contain a \"%s\" section, applying default parameters from FlexRIC\n", CONFIG_STRING_E2AGENT);
return (e2_agent_args_t) { 0 };
}
bool enabled = config_isparamset(e2agent_params, E2AGENT_CONFIG_SMDIR_IDX)
&& config_isparamset(e2agent_params, E2AGENT_CONFIG_IP_IDX);
e2_agent_args_t dst = {.enabled = enabled};
if (!enabled) {
LOG_W(GNB_APP, "E2 agent is DISABLED (for activation, define .%s.{%s,%s} parameters)\n", CONFIG_STRING_E2AGENT, E2AGENT_CONFIG_IP, E2AGENT_CONFIG_SMDIR);
return dst;
}
if (e2agent_params[E2AGENT_CONFIG_SMDIR_IDX].strptr != NULL)
dst.sm_dir = *e2agent_params[E2AGENT_CONFIG_SMDIR_IDX].strptr;
if (e2agent_params[E2AGENT_CONFIG_IP_IDX].strptr != NULL)
dst.ip = *e2agent_params[E2AGENT_CONFIG_IP_IDX].strptr;
return dst;
}
#endif // E2_AGENT
......@@ -1366,3 +1366,15 @@ bool nr_pdcp_get_statistics(ue_id_t ue_id, int srb_flag, int rb_id, nr_pdcp_stat
return ret;
}
int nr_pdcp_get_num_ues(ue_id_t *ue_list, int len)
{
nr_pdcp_manager_lock(nr_pdcp_ue_manager);
int num_ues = nr_pdcp_manager_get_ue_count(nr_pdcp_ue_manager);
nr_pdcp_ue_t **nr_pdcp_ue_list = nr_pdcp_manager_get_ue_list(nr_pdcp_ue_manager);
for (int i = 0; i < num_ues && i < len; i++)
ue_list[i] = nr_pdcp_ue_list[i]->ue_id;
nr_pdcp_manager_unlock(nr_pdcp_ue_manager);
return num_ues;
}
......@@ -124,6 +124,8 @@ void nr_pdcp_tick(int frame, int subframe);
nr_pdcp_ue_manager_t *nr_pdcp_sdap_get_ue_manager();
int nr_pdcp_get_num_ues(ue_id_t *ue_list, int len);
bool nr_pdcp_get_statistics(ue_id_t ue_id, int srb_flag, int rb_id, nr_pdcp_statistics_t *out);
#endif /* NR_PDCP_OAI_API_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment