diff --git a/CMakeLists.txt b/CMakeLists.txt index d2c594aad5..de4ae15ab8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 ####################################### diff --git a/executables/nr-cuup.c b/executables/nr-cuup.c index 558e450d33..40ae604716 100644 --- a/executables/nr-cuup.c +++ b/executables/nr-cuup.c @@ -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 TO TERMINATE\n"); itti_wait_tasks_end(NULL); diff --git a/executables/nr-softmodem.c b/executables/nr-softmodem.c index aa8dd6025e..ad24e55755 100644 --- a/executables/nr-softmodem.c +++ b/executables/nr-softmodem.c @@ -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; diff --git a/openair2/E2AP/CMakeLists.txt b/openair2/E2AP/CMakeLists.txt index c5603849a3..c7f79ae06f 100644 --- a/openair2/E2AP/CMakeLists.txt +++ b/openair2/E2AP/CMakeLists.txt @@ -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) diff --git a/openair2/E2AP/RAN_FUNCTION/CMakeLists.txt b/openair2/E2AP/RAN_FUNCTION/CMakeLists.txt index da550029e0..7c8cb59cfd 100644 --- a/openair2/E2AP/RAN_FUNCTION/CMakeLists.txt +++ b/openair2/E2AP/RAN_FUNCTION/CMakeLists.txt @@ -1,17 +1,40 @@ -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) diff --git a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/CMakeLists.txt b/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/CMakeLists.txt deleted file mode 100644 index f2560ff838..0000000000 --- a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ -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} ) diff --git a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_gtp.c b/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_gtp.c index ac02a85c05..c1d2a0f0b7 100644 --- a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_gtp.c +++ b/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_gtp.c @@ -23,17 +23,17 @@ #include -#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/LAYER2/nr_pdcp/nr_pdcp_oai_api.h" + + +#if defined (NGRAN_GNB_CUCP) #include "openair2/RRC/NR/rrc_gNB_UE_context.h" +#endif - -static -const int mod_id = 0; - -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); } - - 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; - } - } - } else { - LOG_W(NR_RRC,"rrc_gNB_get_ue_context return NULL\n"); - // if (gtp->msg.ngut != NULL) free(gtp->msg.ngut); - } - i++; + 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"); + + 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; + } + } + } + + 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) diff --git a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_gtp.h b/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_gtp.h index b69fb7e462..74a6277a5e 100644 --- a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_gtp.h +++ b/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_gtp.h @@ -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*); diff --git a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_mac.c b/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_mac.c index 099c1bad1c..f6a152627c 100644 --- a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_mac.c +++ b/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_mac.c @@ -20,14 +20,13 @@ */ #include "ran_func_mac.h" -#include "openair2/E2AP/flexric/test/rnd/fill_rnd_data_mac.h" #include 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) diff --git a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_mac.h b/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_mac.h index c32d84433d..6839b03485 100644 --- a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_mac.h +++ b/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_mac.h @@ -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*); diff --git a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_pdcp.c b/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_pdcp.c index a340c6f499..6c8c1268a7 100644 --- a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_pdcp.c +++ b/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_pdcp.c @@ -19,164 +19,125 @@ * contact@openairinterface.org */ -#include "ran_func_pdcp.h" - #include #include #include -#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 -static -const int mod_id = 0; +#if defined (NGRAN_GNB_CUCP) +#include "openair2/RRC/NR/rrc_gNB_UE_context.h" +#endif -static - uint32_t num_act_rb(NR_UEs_t* UE_info) +#if defined (NGRAN_GNB_CUUP) +#include "openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h" +#endif + +#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(); + + size_t num_ues = 0; + uint64_t ue_id_list[MAX_MOBILES_PER_GNB]; + size_t total_num_rb = 0; + + #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"); + + 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; + + 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++; - pdcp->msg.tstamp = time_now_us(); + AssertFatal(num_ues < MAX_MOBILES_PER_GNB, "cannot have more UEs than global UE number maximum\n"); + } - 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 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 { - - //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); - - 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 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; } - - diff --git a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_pdcp.h b/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_pdcp.h index 951cd7373d..a1b4f2d3a3 100644 --- a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_pdcp.h +++ b/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_pdcp.h @@ -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); diff --git a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_rlc.c b/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_rlc.c index bc9bac5916..d78c103fbf 100644 --- a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_rlc.c +++ b/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_rlc.c @@ -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) diff --git a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_rlc.h b/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_rlc.h index b2f518e7f6..9edf6f0818 100644 --- a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_rlc.h +++ b/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_rlc.h @@ -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); diff --git a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_slice.c b/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_slice.c index b0f81136b0..11ce8b513b 100644 --- a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_slice.c +++ b/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_slice.c @@ -24,13 +24,15 @@ #include #include -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) diff --git a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_slice.h b/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_slice.h index d01f7f2cf2..3d9203a676 100644 --- a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_slice.h +++ b/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_slice.h @@ -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); diff --git a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_tc.c b/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_tc.c index 6d420fa183..e6fc3f851b 100644 --- a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_tc.c +++ b/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_tc.c @@ -23,13 +23,15 @@ #include "../../flexric/test/rnd/fill_rnd_data_tc.h" #include -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) diff --git a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_tc.h b/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_tc.h index 19d655301b..86f5dd1a5a 100644 --- a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_tc.h +++ b/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_tc.h @@ -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); diff --git a/openair2/E2AP/RAN_FUNCTION/O-RAN/CMakeLists.txt b/openair2/E2AP/RAN_FUNCTION/O-RAN/CMakeLists.txt deleted file mode 100644 index 3a1c042785..0000000000 --- a/openair2/E2AP/RAN_FUNCTION/O-RAN/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -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}) diff --git a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.c b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.c index 562cc715d8..357a82b277 100644 --- a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.c +++ b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.c @@ -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/RRC/NR/rrc_gNB_UE_context.h" -#include "openair3/NGAP/ngap_gNB_ue_context.h" -#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" +#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_pdcp/nr_pdcp_oai_api.h" +#include "openair2/E1AP/e1ap_common.h" +#endif + #include "openair2/F1AP/f1ap_ids.h" #include #include +/* 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,6 +64,231 @@ static bool nssai_matches(nssai_t a_nssai, uint8_t b_sst, const uint32_t *b_sd) } } +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) +{ + gnb_cu_up_e2sm_t gnb_cu_up = {0}; + + // 6.2.3.20 + // Mandatory + gnb_cu_up.gnb_cu_cp_ue_e1ap = cucp_ue_id; + + // 6.2.3.25 + // RAN UE ID + // Optional + gnb_cu_up.ran_ue_id = NULL; + + return gnb_cu_up; +} + +typedef struct { + 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_pdcp_t; + + __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); + + // 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); + } + } + + return matches->num_ues; +} + +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; + const int rb_id = 1; // at the moment, only 1 DRB is supported + + // Get PDCP stats for specific DRB + const bool rc = nr_pdcp_get_statistics(rrc_ue_id, srb_flag, rb_id, &pdcp); + assert(rc == true && "Cannot get PDCP stats\n"); + + return pdcp; +} + +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; imeas_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; ipdcp_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}; + + // 6.2.3.16 + // Mandatory + // AMF UE NGAP ID + gnb.amf_ue_ngap_id = ue_context_p->ue_context.rrc_ue_id; + + // Mandatory + //GUAMI 6.2.3.17 + gnb.guami.plmn_id = (e2sm_plmn_t) { + .mcc = ue_context_p->ue_context.ue_guami.mcc, + .mnc = ue_context_p->ue_context.ue_guami.mnc, + .mnc_digit_len = ue_context_p->ue_context.ue_guami.mnc_len + }; + + gnb.guami.amf_region_id = ue_context_p->ue_context.ue_guami.amf_region_id; + gnb.guami.amf_set_id = ue_context_p->ue_context.ue_guami.amf_set_id; + gnb.guami.amf_ptr = ue_context_p->ue_context.ue_guami.amf_pointer; + + // gNB-CU UE F1AP ID List + // C-ifCUDUseparated + 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++) { + 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) +{ + gnb_du_e2sm_t gnb_du = {0}; + + // 6.2.3.21 + // gNB CU UE F1AP + // Mandatory + gnb_du.gnb_cu_ue_f1ap = rrc_ue_id->secondary_ue; + + // 6.2.3.25 + // RAN UE ID + // Optional + gnb_du.ran_ue_id = NULL; + + 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, @@ -73,11 +313,245 @@ static size_t filter_ues_by_s_nssai_in_du_or_monolithic(test_cond_e const condit } 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; +} + +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); + + meas_record_lst_t meas_record = {0}; + + // Get RLC stats per DRB + 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 + meas_record.value = REAL_MEAS_VALUE; + + // Calculate DL Thp + 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 + meas_record.value = REAL_MEAS_VALUE; + + // Calculate UL Thp + 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 + 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 + meas_record.value = INTEGER_MEAS_VALUE; + + // Get the number of DL PRBs + 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 + meas_record.value = INTEGER_MEAS_VALUE; + + // Get the number of UL PRBs + 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 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}; + + // 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; imeas_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_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"); + + 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; +} + +static kpm_ind_msg_format_3_t fill_kpm_ind_msg_frm_3_in_du(const matched_ues_mac_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; iue_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; + msg_frm_3.meas_report_per_ue[i].ue_meas_report_lst.gnb_du = fill_gnb_du_data(&rrc_ue_id); + + // Fill UE related info + msg_frm_3.meas_report_per_ue[i].ind_msg_format_1 = fill_kpm_ind_msg_frm_1_in_du(matched_ues->ue_list[i], i, act_def_fr_1); + } + + + return msg_frm_3; +} + +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; imeas_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'; + + 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"); + + 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; +} + +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); + + + 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; iue_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_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 + +#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; @@ -104,388 +578,10 @@ static size_t filter_ues_by_s_nssai_in_cu(test_cond_e const condition, uint8_t s } 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; -} - -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; - const int rb_id = 1; // at the moment, only 1 DRB is supported - - // Get PDCP stats for specific DRB - const bool rc = nr_pdcp_get_statistics(rrc_ue_id, srb_flag, rb_id, &pdcp); - assert(rc == true && "Cannot get PDCP stats\n"); - - return pdcp; -} - -static -gnb_e2sm_t fill_gnb_data(rrc_gNB_ue_context_t * ue_context_p) -{ - gnb_e2sm_t gnb = {0}; - - // 6.2.3.16 - // Mandatory - // AMF UE NGAP ID - gnb.amf_ue_ngap_id = ue_context_p->ue_context.rrc_ue_id; - - // Mandatory - //GUAMI 6.2.3.17 - gnb.guami.plmn_id = (e2sm_plmn_t) { - .mcc = ue_context_p->ue_context.ue_guami.mcc, - .mnc = ue_context_p->ue_context.ue_guami.mnc, - .mnc_digit_len = ue_context_p->ue_context.ue_guami.mnc_len - }; - - gnb.guami.amf_region_id = ue_context_p->ue_context.ue_guami.amf_region_id; - gnb.guami.amf_set_id = ue_context_p->ue_context.ue_guami.amf_set_id; - gnb.guami.amf_ptr = ue_context_p->ue_context.ue_guami.amf_pointer; - - // gNB-CU UE F1AP ID List - // C-ifCUDUseparated - 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++) - { - 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) -{ - gnb_du_e2sm_t gnb_du = {0}; - - // 6.2.3.21 - // gNB CU UE F1AP - // Mandatory - gnb_du.gnb_cu_ue_f1ap = rrc_ue_id->secondary_ue; - - - // 6.2.3.25 - // RAN UE ID - // Optional - gnb_du.ran_ue_id = NULL; - - return gnb_du; -} - -// 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}; - - -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); - - meas_record_lst_t meas_record = {0}; - - // Get RLC stats per DRB - 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 - { - 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; - /* 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 - { - 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; - /* 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 - { - 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 - { - 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; - /* 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 - { - 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; - /* 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 - { - 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) -{ - 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; imeas_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_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); - - return msg_frm_1; -} - -static kpm_ind_msg_format_3_t fill_kpm_ind_msg_frm_3_in_du(const matched_ues_mac_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; iue_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; - msg_frm_3.meas_report_per_ue[i].ue_meas_report_lst.gnb_du = fill_gnb_du_data(&rrc_ue_id); - - // Fill UE related info - msg_frm_3.meas_report_per_ue[i].ind_msg_format_1 = fill_kpm_ind_msg_frm_1_in_du(matched_ues->ue_list[i], i, act_def_fr_1); - } - - - 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) -{ - 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; imeas_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"); - 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); - - 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) { @@ -500,8 +596,7 @@ 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; irrc_ue_id_list[i]); msg_frm_3.meas_report_per_ue[i].ue_meas_report_lst.type = GNB_UE_ID_E2SM; @@ -514,108 +609,16 @@ static kpm_ind_msg_format_3_t fill_kpm_ind_msg_frm_3_in_cu(const matched_ues_rrc 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; imeas_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'; - - 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); - - - return msg_frm_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); - - - 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; iue_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_monolithic(matched_ues->ue_list[i], i, rrc_ue_context_list->ue_context.rrc_ue_id, act_def_fr_1); - } - - return msg_frm_3; -} - -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; } - diff --git a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.h b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.h index 9ef9207819..4883f9fe49 100644 --- a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.h +++ b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.h @@ -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*); diff --git a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc.c b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc.c index e05bb3fd7b..7c22fe5726 100644 --- a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc.c +++ b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc.c @@ -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 #include -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) diff --git a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc.h b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc.h index c7f252971c..ed877fea02 100644 --- a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc.h +++ b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc.h @@ -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); diff --git a/openair2/E2AP/RAN_FUNCTION/init_ran_func.c b/openair2/E2AP/RAN_FUNCTION/init_ran_func.c index abf503c62c..5e9f214795 100644 --- a/openair2/E2AP/RAN_FUNCTION/init_ran_func.c +++ b/openair2/E2AP/RAN_FUNCTION/init_ran_func.c @@ -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; } - diff --git a/openair2/E2AP/RAN_FUNCTION/read_setup_ran.c b/openair2/E2AP/RAN_FUNCTION/read_setup_ran.c index 9967a23902..2bc481d527 100644 --- a/openair2/E2AP/RAN_FUNCTION/read_setup_ran.c +++ b/openair2/E2AP/RAN_FUNCTION/read_setup_ran.c @@ -25,18 +25,66 @@ #include #include -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 } - - - diff --git a/openair2/E2AP/RAN_FUNCTION/read_setup_ran.h b/openair2/E2AP/RAN_FUNCTION/read_setup_ran.h index 2b4c83f2e1..42162f625c 100644 --- a/openair2/E2AP/RAN_FUNCTION/read_setup_ran.h +++ b/openair2/E2AP/RAN_FUNCTION/read_setup_ran.h @@ -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 diff --git a/openair2/E2AP/README.md b/openair2/E2AP/README.md index c496605f2f..20d5dcd0ac 100644 --- a/openair2/E2AP/README.md +++ b/openair2/E2AP/README.md @@ -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 --rfsim --sa -E -sudo ./nr-softmodem -O --rfsim --sa -E +sudo ./nr-softmodem -O --sa +``` + +* if CU-CP/CU-UP/DU split is used, start the gNB as follows +```bash +sudo ./nr-softmodem -O --rfsim --sa -E +sudo ./nr-softmodem -O --sa +sudo ./nr-cuup -O --sa ``` * start the nrUE @@ -152,17 +178,17 @@ cd flexric ./build/examples/xApp/c/monitor/xapp_kpm_moni ``` -* start the GTP xApp +* start the (MAC + RLC + PDCP + GTP) xApp ```bash cd flexric -./build/examples/xApp/c/monitor/xapp_gtp_moni -``` - -* start the (MAC + RLC + PDCP) 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 diff --git a/openair2/E2AP/e2_agent_arg.c b/openair2/E2AP/e2_agent_arg.c new file mode 100644 index 0000000000..ea0eee3f1a --- /dev/null +++ b/openair2/E2AP/e2_agent_arg.c @@ -0,0 +1,50 @@ +/* + * 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; +} diff --git a/openair2/E2AP/e2_agent_arg.h b/openair2/E2AP/e2_agent_arg.h index 30f1ce4750..48ec8b3a24 100644 --- a/openair2/E2AP/e2_agent_arg.h +++ b/openair2/E2AP/e2_agent_arg.h @@ -23,6 +23,8 @@ #define E2_AGENT_ARGS_H #include +#include +#include // 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 diff --git a/openair2/E2AP/e2_agent_paramdef.h b/openair2/E2AP/e2_agent_paramdef.h new file mode 100644 index 0000000000..8d68c8898a --- /dev/null +++ b/openair2/E2AP/e2_agent_paramdef.h @@ -0,0 +1,42 @@ +/* + * 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 diff --git a/openair2/E2AP/flexric b/openair2/E2AP/flexric index 93961d2480..70dd779f53 160000 --- a/openair2/E2AP/flexric +++ b/openair2/E2AP/flexric @@ -1 +1 @@ -Subproject commit 93961d2480b2c7a5721e03435cb34cf9446d1ad1 +Subproject commit 70dd779f5339f4dac3ac176a24b49c45046a59fa diff --git a/openair2/ENB_APP/enb_config.c b/openair2/ENB_APP/enb_config.c index a360369c94..0debcc3264 100644 --- a/openair2/ENB_APP/enb_config.c +++ b/openair2/ENB_APP/enb_config.c @@ -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 - - diff --git a/openair2/ENB_APP/enb_paramdef.h b/openair2/ENB_APP/enb_paramdef.h index 626705317b..ed3be8c024 100644 --- a/openair2/ENB_APP/enb_paramdef.h +++ b/openair2/ENB_APP/enb_paramdef.h @@ -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" diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index bc12793140..52deedc10e 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -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 diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c index efa08e7358..c86bb686c4 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c @@ -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; +} diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h index b172abc1c8..97a48b0e6a 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h @@ -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 */