diff --git a/examples/xApp/c/monitor/xapp_kpm_moni.c b/examples/xApp/c/monitor/xapp_kpm_moni.c index 8b20b4a9a3dacd3c856de41063b9d4b1ffeef69f..5fa00cc2a32aba9b67901e0a239f8823955b8bb1 100644 --- a/examples/xApp/c/monitor/xapp_kpm_moni.c +++ b/examples/xApp/c/monitor/xapp_kpm_moni.c @@ -23,6 +23,7 @@ #include "../../../../src/util/alg_ds/alg/defer.h" #include "../../../../src/util/time_now_us.h" #include "../../../../src/util/alg_ds/ds/lock_guard/lock_guard.h" +#include "../../../../src/util/e.h" #include <stdlib.h> #include <stdio.h> @@ -31,10 +32,142 @@ #include <signal.h> #include <pthread.h> +static +uint64_t const period_ms = 1000; static pthread_mutex_t mtx; +static +void log_gnb_ue_id(ue_id_e2sm_t ue_id) +{ + if (ue_id.gnb.gnb_cu_ue_f1ap_lst != NULL) { + for (size_t i = 0; i < ue_id.gnb.gnb_cu_ue_f1ap_lst_len; i++) { + printf("UE ID type = gNB-CU, gnb_cu_ue_f1ap = %u\n", ue_id.gnb.gnb_cu_ue_f1ap_lst[i]); + } + } else { + printf("UE ID type = gNB, amf_ue_ngap_id = %lu\n", ue_id.gnb.amf_ue_ngap_id); + } + if (ue_id.gnb.ran_ue_id != NULL) { + printf("ran_ue_id = %lx\n", *ue_id.gnb.ran_ue_id); // RAN UE NGAP ID + } +} + +static +void log_du_ue_id(ue_id_e2sm_t ue_id) +{ + printf("UE ID type = gNB-DU, gnb_cu_ue_f1ap = %u\n", ue_id.gnb_du.gnb_cu_ue_f1ap); + if (ue_id.gnb_du.ran_ue_id != NULL) { + printf("ran_ue_id = %lx\n", *ue_id.gnb_du.ran_ue_id); // RAN UE NGAP ID + } +} + +static +void log_cuup_ue_id(ue_id_e2sm_t ue_id) +{ + printf("UE ID type = gNB-CU-UP, gnb_cu_cp_ue_e1ap = %u\n", ue_id.gnb_cu_up.gnb_cu_cp_ue_e1ap); + if (ue_id.gnb_cu_up.ran_ue_id != NULL) { + printf("ran_ue_id = %lx\n", *ue_id.gnb_cu_up.ran_ue_id); // RAN UE NGAP ID + } +} + +typedef void (*log_ue_id)(ue_id_e2sm_t ue_id); + +static +log_ue_id log_ue_id_e2sm[END_UE_ID_E2SM] = { + log_gnb_ue_id, // common for gNB-mono, CU and CU-CP + log_du_ue_id, + log_cuup_ue_id, + NULL, + NULL, + NULL, + NULL, +}; + +static +void log_int_value(byte_array_t name, meas_record_lst_t meas_record) +{ + if (cmp_str_ba("RRU.PrbTotDl", name) == 0) { + printf("RRU.PrbTotDl = %d [PRBs]\n", meas_record.int_val); + } else if (cmp_str_ba("RRU.PrbTotUl", name) == 0) { + printf("RRU.PrbTotUl = %d [PRBs]\n", meas_record.int_val); + } else if (cmp_str_ba("DRB.PdcpSduVolumeDL", name) == 0) { + printf("DRB.PdcpSduVolumeDL = %d [kb]\n", meas_record.int_val); + } else if (cmp_str_ba("DRB.PdcpSduVolumeUL", name) == 0) { + printf("DRB.PdcpSduVolumeUL = %d [kb]\n", meas_record.int_val); + } else { + printf("Measurement Name not yet supported\n"); + } +} + +static +void log_real_value(byte_array_t name, meas_record_lst_t meas_record) +{ + if (cmp_str_ba("DRB.RlcSduDelayDl", name) == 0) { + printf("DRB.RlcSduDelayDl = %.2f [μs]\n", meas_record.real_val); + } else if (cmp_str_ba("DRB.UEThpDl", name) == 0) { + printf("DRB.UEThpDl = %.2f [kbps]\n", meas_record.real_val); + } else if (cmp_str_ba("DRB.UEThpUl", name) == 0) { + printf("DRB.UEThpUl = %.2f [kbps]\n", meas_record.real_val); + } else { + printf("Measurement Name not yet supported\n"); + } +} + +typedef void (*log_meas_value)(byte_array_t name, meas_record_lst_t meas_record); + +static +log_meas_value get_meas_value[END_MEAS_VALUE] = { + log_int_value, + log_real_value, + NULL, +}; + +static +void match_meas_name_type(meas_type_t meas_type, meas_record_lst_t meas_record) +{ + // Get the value of the Measurement + get_meas_value[meas_record.value](meas_type.name, meas_record); +} + +static +void match_id_meas_type(meas_type_t meas_type, meas_record_lst_t meas_record) +{ + (void)meas_type; + (void)meas_record; + assert(false && "ID Measurement Type not yet supported"); +} + +typedef void (*check_meas_type)(meas_type_t meas_type, meas_record_lst_t meas_record); + +static +check_meas_type match_meas_type[END_MEAS_TYPE] = { + match_meas_name_type, + match_id_meas_type, +}; + +static +void log_kpm_measurements(kpm_ind_msg_format_1_t const* msg_frm_1) +{ + assert(msg_frm_1->meas_info_lst_len > 0 && "Cannot correctly print measurements"); + + // UE Measurements per granularity period + for (size_t j = 0; j < msg_frm_1->meas_data_lst_len; j++) { + meas_data_lst_t const data_item = msg_frm_1->meas_data_lst[j]; + + for (size_t z = 0; z < data_item.meas_record_len; z++) { + meas_type_t const meas_type = msg_frm_1->meas_info_lst[z].meas_type; + meas_record_lst_t const record_item = data_item.meas_record_lst[z]; + + match_meas_type[meas_type.type](meas_type, record_item); + + if (data_item.incomplete_flag && *data_item.incomplete_flag == TRUE_ENUM_VALUE) + printf("Measurement Record not reliable"); + } + } + +} + static void sm_cb_kpm(sm_ag_if_rd_t const* rd) { @@ -46,277 +179,201 @@ void sm_cb_kpm(sm_ag_if_rd_t const* rd) kpm_ind_data_t const* ind = &rd->ind.kpm.ind; kpm_ric_ind_hdr_format_1_t const* hdr_frm_1 = &ind->hdr.kpm_ric_ind_hdr_format_1; kpm_ind_msg_format_3_t const* msg_frm_3 = &ind->msg.frm_3; - int64_t const now = time_now_us(); static int counter = 1; { lock_guard(&mtx); - printf("\n%7d KPM ind_msg latency = %ld [μs]\n", counter, now - hdr_frm_1->collectStartTime); // xApp <-> E2 Node + printf("\n%7d KPM ind_msg latency = %ld [μs]\n", counter, now - hdr_frm_1->collectStartTime); // xApp <-> E2 Node // Reported list of measurements per UE - for (size_t i = 0; i < msg_frm_3->ue_meas_report_lst_len; i++) - { - switch (msg_frm_3->meas_report_per_ue[i].ue_meas_report_lst.type) - { - case GNB_UE_ID_E2SM: - if (msg_frm_3->meas_report_per_ue[i].ue_meas_report_lst.gnb.gnb_cu_ue_f1ap_lst != NULL) - { - for (size_t j = 0; j < msg_frm_3->meas_report_per_ue[i].ue_meas_report_lst.gnb.gnb_cu_ue_f1ap_lst_len; j++) - { - printf("UE ID type = gNB-CU, gnb_cu_ue_f1ap = %u\n", msg_frm_3->meas_report_per_ue[i].ue_meas_report_lst.gnb.gnb_cu_ue_f1ap_lst[j]); - } - } - else - { - printf("UE ID type = gNB, amf_ue_ngap_id = %lu\n", msg_frm_3->meas_report_per_ue[i].ue_meas_report_lst.gnb.amf_ue_ngap_id); - } - break; - - case GNB_DU_UE_ID_E2SM: - printf("UE ID type = gNB-DU, gnb_cu_ue_f1ap = %u\n", msg_frm_3->meas_report_per_ue[i].ue_meas_report_lst.gnb_du.gnb_cu_ue_f1ap); - break; - - case GNB_CU_UP_UE_ID_E2SM: - printf("UE ID type = gNB-CU-UP, gnb_cu_cp_ue_e1ap = %u\n", msg_frm_3->meas_report_per_ue[i].ue_meas_report_lst.gnb_cu_up.gnb_cu_cp_ue_e1ap); - break; + for (size_t i = 0; i < msg_frm_3->ue_meas_report_lst_len; i++) { + // log UE ID + ue_id_e2sm_t const ue_id_e2sm = msg_frm_3->meas_report_per_ue[i].ue_meas_report_lst; + ue_id_e2sm_e const type = ue_id_e2sm.type; + log_ue_id_e2sm[type](ue_id_e2sm); + + // log measurements + log_kpm_measurements(&msg_frm_3->meas_report_per_ue[i].ind_msg_format_1); - default: - assert(false && "UE ID type not yet implemented"); - } - - kpm_ind_msg_format_1_t const* msg_frm_1 = &msg_frm_3->meas_report_per_ue[i].ind_msg_format_1; - - // UE Measurements per granularity period - for (size_t j = 0; j<msg_frm_1->meas_data_lst_len; j++) - { - for (size_t z = 0; z<msg_frm_1->meas_data_lst[j].meas_record_len; z++) - { - if (msg_frm_1->meas_info_lst_len > 0) - { - switch (msg_frm_1->meas_info_lst[z].meas_type.type) - { - case NAME_MEAS_TYPE: - { - // Get the Measurement Name - char meas_info_name_str[msg_frm_1->meas_info_lst[z].meas_type.name.len + 1]; - memcpy(meas_info_name_str, msg_frm_1->meas_info_lst[z].meas_type.name.buf, msg_frm_1->meas_info_lst[z].meas_type.name.len); - meas_info_name_str[msg_frm_1->meas_info_lst[z].meas_type.name.len] = '\0'; - - // Get the value of the Measurement - switch (msg_frm_1->meas_data_lst[j].meas_record_lst[z].value) - { - case REAL_MEAS_VALUE: - { - if (strcmp(meas_info_name_str, "DRB.RlcSduDelayDl") == 0) - { - printf("DRB.RlcSduDelayDl = %.2f [μs]\n", msg_frm_1->meas_data_lst[j].meas_record_lst[z].real_val); - } - else if (strcmp(meas_info_name_str, "DRB.UEThpDl") == 0) - { - printf("DRB.UEThpDl = %.2f [kbps]\n", msg_frm_1->meas_data_lst[j].meas_record_lst[z].real_val); - } - else if (strcmp(meas_info_name_str, "DRB.UEThpUl") == 0) - { - printf("DRB.UEThpUl = %.2f [kbps]\n", msg_frm_1->meas_data_lst[j].meas_record_lst[z].real_val); - } - else - { - printf("Measurement Name not yet implemented %s\n", meas_info_name_str); - //assert(false && "Measurement Name not yet implemented"); - } - - break; - } - - - case INTEGER_MEAS_VALUE: - { - if (strcmp(meas_info_name_str, "RRU.PrbTotDl") == 0) - { - printf("RRU.PrbTotDl = %d [PRBs]\n", msg_frm_1->meas_data_lst[j].meas_record_lst[z].int_val); - } - else if (strcmp(meas_info_name_str, "RRU.PrbTotUl") == 0) - { - printf("RRU.PrbTotUl = %d [PRBs]\n", msg_frm_1->meas_data_lst[j].meas_record_lst[z].int_val); - } - else if (strcmp(meas_info_name_str, "DRB.PdcpSduVolumeDL") == 0) - { - printf("DRB.PdcpSduVolumeDL = %d [kb]\n", msg_frm_1->meas_data_lst[j].meas_record_lst[z].int_val); - } - else if (strcmp(meas_info_name_str, "DRB.PdcpSduVolumeUL") == 0) - { - printf("DRB.PdcpSduVolumeUL = %d [kb]\n", msg_frm_1->meas_data_lst[j].meas_record_lst[z].int_val); - } - else - { - printf("Measurement Name not yet implemented %s\n", meas_info_name_str); - //assert(false && "Measurement Name not yet implemented"); - } - - break; - } - - default: - assert(0 != 0 && "Value not recognized"); - } - - break; - } - case ID_MEAS_TYPE: - printf(" ID_MEAS_TYPE \n"); - break; - - default: - assert(false && "Measurement Type not yet implemented"); - } - } - - - if (msg_frm_1->meas_data_lst[j].incomplete_flag && *msg_frm_1->meas_data_lst[j].incomplete_flag == TRUE_ENUM_VALUE) - printf("Measurement Record not reliable"); - } - } } counter++; } } static -kpm_event_trigger_def_t gen_ev_trig(uint64_t period) +test_info_lst_t filter_predicate(test_cond_type_e type, test_cond_e cond, int value) { - kpm_event_trigger_def_t dst = {0}; + test_info_lst_t dst = {0}; + + dst.test_cond_type = type; + // It can only be TRUE_TEST_COND_TYPE so it does not matter the type + // but ugly ugly... + dst.S_NSSAI = TRUE_TEST_COND_TYPE; - dst.type = FORMAT_1_RIC_EVENT_TRIGGER; - dst.kpm_ric_event_trigger_format_1.report_period_ms = period; + dst.test_cond = calloc(1, sizeof(test_cond_e)); + assert(dst.test_cond != NULL && "Memory exhausted"); + *dst.test_cond = cond; + + dst.test_cond_value = calloc(1, sizeof(test_cond_value_t)); + assert(dst.test_cond_value != NULL && "Memory exhausted"); + dst.test_cond_value->type = OCTET_STRING_TEST_COND_VALUE; + + dst.test_cond_value->octet_string_value = calloc(1, sizeof(byte_array_t)); + assert(dst.test_cond_value->octet_string_value != NULL && "Memory exhausted"); + const size_t len_nssai = 1; + dst.test_cond_value->octet_string_value->len = len_nssai; + dst.test_cond_value->octet_string_value->buf = calloc(len_nssai, sizeof(uint8_t)); + assert(dst.test_cond_value->octet_string_value->buf != NULL && "Memory exhausted"); + dst.test_cond_value->octet_string_value->buf[0] = value; return dst; } static -meas_info_format_1_lst_t gen_meas_info_format_1_lst(const char* action) +label_info_lst_t fill_kpm_label(void) { - meas_info_format_1_lst_t dst = {0}; - - dst.meas_type.type = NAME_MEAS_TYPE; - // ETSI TS 128 552 - dst.meas_type.name = cp_str_to_ba(action); + label_info_lst_t label_item = {0}; - dst.label_info_lst_len = 1; - dst.label_info_lst = calloc(1, sizeof(label_info_lst_t)); - assert(dst.label_info_lst != NULL && "Memory exhausted"); - dst.label_info_lst[0].noLabel = calloc(1, sizeof(enum_value_e)); - assert(dst.label_info_lst[0].noLabel != NULL && "Memory exhausted"); - *dst.label_info_lst[0].noLabel = TRUE_ENUM_VALUE; + label_item.noLabel = ecalloc(1, sizeof(enum_value_e)); + *label_item.noLabel = TRUE_ENUM_VALUE; - return dst; + return label_item; } static -kpm_act_def_format_1_t gen_act_def_frmt_1(char** action) +kpm_act_def_format_1_t fill_act_def_frm_1(ric_report_style_item_t const* report_item) { - kpm_act_def_format_1_t dst = {0}; + assert(report_item != NULL); + + kpm_act_def_format_1_t ad_frm_1 = {0}; - dst.gran_period_ms = 1000; + size_t const sz = report_item->meas_info_for_action_lst_len; // [1, 65535] - size_t count = 0; - while (action[count] != NULL) { - count++; + ad_frm_1.meas_info_lst_len = sz; + ad_frm_1.meas_info_lst = calloc(sz, sizeof(meas_info_format_1_lst_t)); + assert(ad_frm_1.meas_info_lst != NULL && "Memory exhausted"); + + for (size_t i = 0; i < sz; i++) { + meas_info_format_1_lst_t* meas_item = &ad_frm_1.meas_info_lst[i]; + // 8.3.9 + // Measurement Name + meas_item->meas_type.type = NAME_MEAS_TYPE; + meas_item->meas_type.name = copy_byte_array(report_item->meas_info_for_action_lst[i].name); + + // [1, 2147483647] + // 8.3.11 + meas_item->label_info_lst_len = 1; + meas_item->label_info_lst = ecalloc(1, sizeof(label_info_lst_t)); + meas_item->label_info_lst[0] = fill_kpm_label(); } - dst.meas_info_lst_len = count; - dst.meas_info_lst = calloc(count, sizeof(meas_info_format_1_lst_t)); - assert(dst.meas_info_lst != NULL && "Memory exhausted"); - for(size_t i = 0; i < dst.meas_info_lst_len; i++) { - dst.meas_info_lst[i] = gen_meas_info_format_1_lst(action[i]); - } + // 8.3.8 [0, 4294967295] + ad_frm_1.gran_period_ms = period_ms; - return dst; + // 8.3.20 - OPTIONAL + ad_frm_1.cell_global_id = NULL; + +#if defined KPM_V2_03 || defined KPM_V3_00 + // [0, 65535] + ad_frm_1.meas_bin_range_info_lst_len = 0; + ad_frm_1.meas_bin_info_lst = NULL; +#endif + + return ad_frm_1; } static -test_info_lst_t filter_predicate(test_cond_type_e type, test_cond_e cond, int value) +kpm_act_def_t fill_report_style_4(ric_report_style_item_t const* report_item) { - test_info_lst_t dst = {0}; + assert(report_item != NULL); + assert(report_item->act_def_format_type == FORMAT_4_ACTION_DEFINITION); - dst.test_cond_type = type; - // It can only be TRUE_TEST_COND_TYPE so it does not matter the type - dst.S_NSSAI = TRUE_TEST_COND_TYPE; + kpm_act_def_t act_def = {.type = FORMAT_4_ACTION_DEFINITION}; - dst.test_cond = calloc(1, sizeof(test_cond_e)); - assert(dst.test_cond != NULL && "Memory exhausted"); - *dst.test_cond = cond; + // Fill matching condition + // [1, 32768] + act_def.frm_4.matching_cond_lst_len = 1; + act_def.frm_4.matching_cond_lst = calloc(act_def.frm_4.matching_cond_lst_len, sizeof(matching_condition_format_4_lst_t)); + assert(act_def.frm_4.matching_cond_lst != NULL && "Memory exhausted"); + // Filter connected UEs by S-NSSAI criteria + test_cond_type_e const type = S_NSSAI_TEST_COND_TYPE; // CQI_TEST_COND_TYPE + test_cond_e const condition = EQUAL_TEST_COND; // GREATERTHAN_TEST_COND + int const value = 1; + act_def.frm_4.matching_cond_lst[0].test_info_lst = filter_predicate(type, condition, value); - dst.test_cond_value = calloc(1, sizeof(test_cond_value_t)); - assert(dst.test_cond_value != NULL && "Memory exhausted"); - dst.test_cond_value->type = INTEGER_TEST_COND_VALUE; + // Fill Action Definition Format 1 + // 8.2.1.2.1 + act_def.frm_4.action_def_format_1 = fill_act_def_frm_1(report_item); - dst.test_cond_value->int_value = calloc(1, sizeof(int64_t)); - assert(dst.test_cond_value->int_value != NULL && "Memory exhausted"); - *dst.test_cond_value->int_value = value; + return act_def; +} - return dst; -} +typedef kpm_act_def_t (*fill_kpm_act_def)(ric_report_style_item_t const* report_item); +static +fill_kpm_act_def get_kpm_act_def[END_RIC_SERVICE_REPORT] = { + NULL, + NULL, + NULL, + fill_report_style_4, + NULL, +}; static -kpm_act_def_format_4_t gen_act_def_frmt_4(char** action) +kpm_sub_data_t gen_kpm_subs(kpm_ran_function_def_t const* ran_func) { - kpm_act_def_format_4_t dst = {0}; + assert(ran_func != NULL); + assert(ran_func->ric_event_trigger_style_list != NULL); - // [1, 32768] - dst.matching_cond_lst_len = 1; + kpm_sub_data_t kpm_sub = {0}; - dst.matching_cond_lst = calloc(dst.matching_cond_lst_len, sizeof(matching_condition_format_4_lst_t)); - assert(dst.matching_cond_lst != NULL && "Memory exhausted"); + // Generate Event Trigger + assert(ran_func->ric_event_trigger_style_list[0].format_type == FORMAT_1_RIC_EVENT_TRIGGER); + kpm_sub.ev_trg_def.type = FORMAT_1_RIC_EVENT_TRIGGER; + kpm_sub.ev_trg_def.kpm_ric_event_trigger_format_1.report_period_ms = period_ms; - // Filter connected UEs by S-NSSAI criteria - test_cond_type_e const type = S_NSSAI_TEST_COND_TYPE; - test_cond_e const condition = EQUAL_TEST_COND; - int const value = 1; - dst.matching_cond_lst[0].test_info_lst = filter_predicate(type, condition, value); + // Generate Action Definition + kpm_sub.sz_ad = 1; + kpm_sub.ad = calloc(kpm_sub.sz_ad, sizeof(kpm_act_def_t)); + assert(kpm_sub.ad != NULL && "Memory exhausted"); - printf("[xApp]: Filter UEs by S-NSSAI criteria where SST = %lu\n", *dst.matching_cond_lst[0].test_info_lst.test_cond_value->int_value); + // Multiple Action Definitions in one SUBSCRIPTION message is not supported in this project + // Multiple REPORT Styles = Multiple Action Definition = Multiple SUBSCRIPTION messages + ric_report_style_item_t* const report_item = &ran_func->ric_report_style_list[0]; + ric_service_report_e const report_style_type = report_item->report_style_type; + *kpm_sub.ad = get_kpm_act_def[report_style_type](report_item); - // Action definition Format 1 - dst.action_def_format_1 = gen_act_def_frmt_1(action); // 8.2.1.2.1 - - return dst; + return kpm_sub; } static -kpm_act_def_t gen_act_def(char** act) +bool eq_sm(sm_ran_function_t const* elem, int const id) { - kpm_act_def_t dst = {0}; + if (elem->id == id) + return true; - dst.type = FORMAT_4_ACTION_DEFINITION; - dst.frm_4 = gen_act_def_frmt_4(act); - return dst; + return false; } static -char** lst_kpm_measurement(kpm_ran_function_def_t const* src) +size_t find_sm_idx(sm_ran_function_t* rf, size_t sz, bool (*f)(sm_ran_function_t const*, int const), int const id) { - assert(src != NULL); - const size_t sz = src->ric_report_style_list[0].meas_info_for_action_lst_len; - char** dst = calloc(sz + 1, sizeof(char*)); - for(size_t i = 0; i < sz; ++i){ - const size_t len = src->ric_report_style_list[0].meas_info_for_action_lst[i].name.len; - const uint8_t* buf = src->ric_report_style_list[0].meas_info_for_action_lst[i].name.buf; - dst[i] = calloc(len+1, sizeof(uint8_t)); - memcpy(dst[i], buf, len); + for (size_t i = 0; i < sz; i++) { + if (f(&rf[i], id)) + return i; } - return dst; -} + assert(0 != 0 && "SM ID could not be found in the RAN Function List"); +} -int main(int argc, char *argv[]) +int main(int argc, char* argv[]) { fr_args_t args = init_fr_args(argc, argv); - //Init the xApp + // Init the xApp init_xapp_api(&args); sleep(1); @@ -331,103 +388,47 @@ int main(int argc, char *argv[]) int rc = pthread_mutex_init(&mtx, &attr); assert(rc == 0); - // KPM indication - sm_ans_xapp_t* kpm_handle = NULL; - if(nodes.len > 0){ - kpm_handle = calloc( nodes.len, sizeof(sm_ans_xapp_t) ); - assert(kpm_handle != NULL); - } + sm_ans_xapp_t* hndl = calloc(nodes.len, sizeof(sm_ans_xapp_t)); + assert(hndl != NULL); - const int KPM_ran_function = 2; + //////////// + // START KPM + //////////// + int const KPM_ran_function = 2; - for (int i = 0; i < nodes.len; i++) { + for (size_t i = 0; i < nodes.len; ++i) { e2_node_connected_xapp_t* n = &nodes.n[i]; - char** lst = NULL; - for (size_t j = 0; j < n->len_rf; j++){ - printf("[xApp]: registered node %lu ran func id = %d \n ", j, n->rf[j].id); - if(n->rf[j].id == KPM_ran_function){ - lst = lst_kpm_measurement(&n->rf[j].defn.kpm); - } - } - - //////////// - // START KPM - //////////// - kpm_sub_data_t kpm_sub = {0}; - defer({ free_kpm_sub_data(&kpm_sub); }); - - // KPM Event Trigger - uint64_t period_ms = 1000; - kpm_sub.ev_trg_def = gen_ev_trig(period_ms); - printf("[xApp]: reporting period = %lu [ms]\n", period_ms); - - // KPM Action Definition - kpm_sub.sz_ad = 1; - kpm_sub.ad = calloc(1, sizeof(kpm_act_def_t)); - assert(kpm_sub.ad != NULL && "Memory exhausted"); - - *kpm_sub.ad = gen_act_def(lst); - - - - switch (n->id.type) - { - case ngran_gNB: ; - char *act_gnb[] = {"DRB.PdcpSduVolumeDL", "DRB.PdcpSduVolumeUL", "DRB.RlcSduDelayDl", "DRB.UEThpDl", "DRB.UEThpUl", "RRU.PrbTotDl", "RRU.PrbTotUl", NULL}; // 3GPP TS 28.552 - *kpm_sub.ad = gen_act_def(act_gnb); - break; - case ngran_eNB: ; - char *act_enb[] = {"DRB.PdcpSduVolumeDL", "DRB.PdcpSduVolumeUL", "RRU.PrbTotDl", "RRU.PrbTotUl", NULL}; // 3GPP TS 32.425 - *kpm_sub.ad = gen_act_def(act_enb); - break; - - case ngran_gNB_CUUP: ; - case ngran_gNB_CU: ; - char *act_gnb_cu[] = {"DRB.PdcpSduVolumeDL", "DRB.PdcpSduVolumeUL", NULL}; // 3GPP TS 28.552 - *kpm_sub.ad = gen_act_def(act_gnb_cu); - break; - - case ngran_gNB_DU: ; - char *act_gnb_du[] = {"DRB.RlcSduDelayDl", "DRB.UEThpDl", "DRB.UEThpUl", "RRU.PrbTotDl", "RRU.PrbTotUl", NULL}; // 3GPP TS 28.552 - *kpm_sub.ad = gen_act_def(act_gnb_du); - break; - - case ngran_gNB_CUCP: ; - continue; - - default: - assert(false && "NG-RAN Type not yet implemented"); - } + size_t const idx = find_sm_idx(n->rf, n->len_rf, eq_sm, KPM_ran_function); + assert(n->rf[idx].defn.type == KPM_RAN_FUNC_DEF_E && "KPM is not the received RAN Function"); + // if REPORT Service is supported by E2 node, send SUBSCRIPTION + // e.g. OAI CU-CP + if (n->rf[idx].defn.kpm.ric_report_style_list != NULL) { + // Generate KPM SUBSCRIPTION message + kpm_sub_data_t kpm_sub = gen_kpm_subs(&n->rf[idx].defn.kpm); - - kpm_handle[i] = report_sm_xapp_api(&nodes.n[i].id, KPM_ran_function, &kpm_sub, sm_cb_kpm); - assert(kpm_handle[i].success == true); + hndl[i] = report_sm_xapp_api(&n->id, KPM_ran_function, &kpm_sub, sm_cb_kpm); + assert(hndl[i].success == true); - if(lst != NULL){ - for(size_t i = 0; lst[i] != NULL; ++i){ - free(lst[i]); - } - free(lst); + free_kpm_sub_data(&kpm_sub); } } + //////////// + // END KPM + //////////// sleep(10); - for(int i = 0; i < nodes.len; ++i){ + for (int i = 0; i < nodes.len; ++i) { // Remove the handle previously returned - if (kpm_handle[i].success == true) - rm_report_sm_xapp_api(kpm_handle[i].u.handle); + if (hndl[i].success == true) + rm_report_sm_xapp_api(hndl[i].u.handle); } + free(hndl); - if(nodes.len > 0){ - free(kpm_handle); - } - - //Stop the xApp - while(try_stop_xapp_api() == false) + // Stop the xApp + while (try_stop_xapp_api() == false) usleep(1000); printf("Test xApp run SUCCESSFULLY\n"); } -