From 17ee9db07281d51a4cc7a681b1e454af3f022f89 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 10 Nov 2025 18:29:36 +0100 Subject: [PATCH 01/12] MAC: total_prb_aggregate: collect over carrierBandwidth --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index d848cf99c8..1990eb2e26 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -1387,8 +1387,8 @@ void nr_schedule_ue_spec(module_id_t module_id, return; NR_ServingCellConfigCommon_t *scc = gNB_mac->common_channels[CC_id].ServingCellConfigCommon; - const NR_BWP_t *initialDL = &scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters; - gNB_mac->mac_stats.total_prb_aggregate += NRRIV2BW(initialDL->locationAndBandwidth, MAX_BWP_SIZE); + int bw = scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth; + gNB_mac->mac_stats.total_prb_aggregate += bw; nfapi_nr_dl_tti_request_body_t *dl_req = &DL_req->dl_tti_request_body; post_process_pdsch_t pdsch = { frame, slot, dl_req, TX_req }; From 021b546cf3f79663b2db9f65bead3b8767331cbf Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 24 Oct 2025 16:27:45 +0200 Subject: [PATCH 02/12] Add UL mac stats and create a common struct for both DL and UL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DL stats (aggregated total and used PRBs) previosuly used only for O1 interface, now finds the purpose for E2 interface as well. New UL stats (aggregated total and used PRBs) serve for E2 interface only. Co-authored-by: Teodora Vladić --- common/utils/telnetsrv/telnetsrv_o1.c | 8 ++++---- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 6 +++--- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 2 ++ openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 7 ++++++- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/common/utils/telnetsrv/telnetsrv_o1.c b/common/utils/telnetsrv/telnetsrv_o1.c index ac368885f6..9ff56e3521 100644 --- a/common/utils/telnetsrv/telnetsrv_o1.c +++ b/common/utils/telnetsrv/telnetsrv_o1.c @@ -105,10 +105,10 @@ static int get_stats(char *buf, int debug, telnet_printfunc_t prnt) int bw_index = get_supported_band_index(scs, fr, nrb); int bw_mhz = get_supported_bw_mhz(fr, bw_index); - const mac_stats_t *stat = &mac->mac_stats; - static mac_stats_t last = {0}; - int diff_used = stat->used_prb_aggregate - last.used_prb_aggregate; - int diff_total = stat->total_prb_aggregate - last.total_prb_aggregate; + const dlul_mac_stats_t *stat = &mac->mac_stats; + static dlul_mac_stats_t last = {0}; + int diff_used = stat->dl.used_prb_aggregate - last.dl.used_prb_aggregate; + int diff_total = stat->dl.total_prb_aggregate - last.dl.total_prb_aggregate; int load = diff_total > 0 ? 100 * diff_used / diff_total : 0; last = *stat; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 1990eb2e26..adf091ed7c 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -1224,7 +1224,7 @@ void post_process_dlsch(gNB_MAC_INST *nr_mac, post_process_pdsch_t *pdsch, NR_UE T(T_GNB_MAC_RETRANSMISSION_DL_PDU_WITH_DATA, T_INT(module_id), T_INT(CC_id), T_INT(rnti), T_INT(frame), T_INT(slot), T_INT(current_harq_pid), T_INT(harq->round), T_BUFFER(harq->transportBlock.buf, TBS)); UE->mac_stats.dl.total_rbs_retx += sched_pdsch->rbSize; - nr_mac->mac_stats.used_prb_aggregate += sched_pdsch->rbSize; + nr_mac->mac_stats.dl.used_prb_aggregate += sched_pdsch->rbSize; } else { /* initial transmission */ LOG_D(NR_MAC, "Initial HARQ transmission in %d.%d\n", frame, slot); uint8_t *buf = allocate_transportBlock_buffer(&harq->transportBlock, TBS); @@ -1338,7 +1338,7 @@ void post_process_dlsch(gNB_MAC_INST *nr_mac, post_process_pdsch_t *pdsch, NR_UE UE->mac_stats.dl.num_mac_sdu += sdus; UE->mac_stats.dl.current_rbs = sched_pdsch->rbSize; UE->mac_stats.dl.total_sdu_bytes += dlsch_total_bytes; - nr_mac->mac_stats.used_prb_aggregate += sched_pdsch->rbSize; + nr_mac->mac_stats.dl.used_prb_aggregate += sched_pdsch->rbSize; /* save retransmission information */ harq->sched_pdsch = *sched_pdsch; @@ -1388,7 +1388,7 @@ void nr_schedule_ue_spec(module_id_t module_id, NR_ServingCellConfigCommon_t *scc = gNB_mac->common_channels[CC_id].ServingCellConfigCommon; int bw = scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth; - gNB_mac->mac_stats.total_prb_aggregate += bw; + gNB_mac->mac_stats.dl.total_prb_aggregate += bw; nfapi_nr_dl_tti_request_body_t *dl_req = &DL_req->dl_tti_request_body; post_process_pdsch_t pdsch = { frame, slot, dl_req, TX_req }; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 94325bf26b..cf699d1bae 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -2455,6 +2455,7 @@ void post_process_ulsch(gNB_MAC_INST *nr_mac, post_process_pusch_t *pusch, NR_UE } UE->mac_stats.ul.current_bytes = sched_pusch->tb_size; UE->mac_stats.ul.current_rbs = sched_pusch->rbSize; + nr_mac->mac_stats.ul.used_prb_aggregate += sched_pusch->rbSize; sched_ctrl->last_ul_frame = sched_pusch->frame; sched_ctrl->last_ul_slot = sched_pusch->slot; @@ -2697,6 +2698,7 @@ static void nr_ulsch_preprocessor(gNB_MAC_INST *nr_mac, post_process_pusch_t *pp int tda = seq_arr_dist(&nr_mac->ul_tda, seq_arr_front(&nr_mac->ul_tda), tda_info); AssertFatal(tda >= 0 && tda < 16, "illegal TDA index %d\n", tda); + nr_mac->mac_stats.ul.total_prb_aggregate += bw; int len[num_beams]; for (int i = 0; i < num_beams; i++) len[i] = rb_len; diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index d6a9ae1497..aa8b2b8644 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -870,6 +870,11 @@ typedef struct { uint64_t used_prb_aggregate; } mac_stats_t; +typedef struct dlul_mac_stats { + mac_stats_t dl; + mac_stats_t ul; +} dlul_mac_stats_t; + /// helper type to encapsulate a frame/slot combination in a single type. /// Currently only used in the UL preprocessor. Note: if you use this type /// further, please refactor it into a common type first. @@ -996,7 +1001,7 @@ typedef struct gNB_MAC_INST_s { pthread_mutex_t sched_lock; - mac_stats_t mac_stats; + dlul_mac_stats_t mac_stats; uint64_t num_scheduled_prach_rx; } gNB_MAC_INST; From d0a582e73d0ac2c1f2c3f070daad8a53a22c3e5b Mon Sep 17 00:00:00 2001 From: Teodora Date: Fri, 24 Oct 2025 16:36:44 +0200 Subject: [PATCH 03/12] Implement E2 node level stats For now, only DL/UL MAC stats. This commit fixes the "RRU.PrbTotDl" and "RRU.PrbTotUl" measurement calculation to align with the TS 28.552 specifications. --- .../E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.c | 16 ++++++-- .../RAN_FUNCTION/O-RAN/ran_func_kpm_subs.c | 40 ++++++++++++------- .../RAN_FUNCTION/O-RAN/ran_func_kpm_subs.h | 10 ++++- 3 files changed, 46 insertions(+), 20 deletions(-) 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 02760c4984..8933b802a0 100644 --- a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.c +++ b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.c @@ -54,10 +54,12 @@ typedef struct { ue_id_e2sm_t* ue_id; // Optional - // only used to retreive MAC/RLC stats + // only used to retrieve MAC/RLC stats NR_UE_info_t** ue_info_list; }arr_ue_id_t; +static e2_node_level_stats_t node_stats[2] = {0}; // [0] node stats collected in previous reporting period; [1] current node stats + static meas_data_lst_t fill_kpm_meas_data_item(const meas_info_format_1_lst_t* meas_info_lst, const size_t len, const uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx) { meas_data_lst_t data_item = {0}; @@ -74,7 +76,7 @@ static meas_data_lst_t fill_kpm_meas_data_item(const meas_info_format_1_lst_t* m char* meas_info_name_str = cp_ba_to_str(meas_info_lst[i].meas_type.name); - data_item.meas_record_lst[i] = get_kpm_meas_value(meas_info_name_str, gran_period_ms, ue_info, ue_idx); + data_item.meas_record_lst[i] = get_kpm_meas_value(meas_info_name_str, gran_period_ms, ue_info, ue_idx, node_stats); free(meas_info_name_str); } @@ -153,6 +155,8 @@ static kpm_ind_msg_format_3_t fill_kpm_ind_msg_frm_3(arr_ue_id_t* arr_ue_id, con msg_frm_3.meas_report_per_ue[i].ind_msg_format_1 = fill_kpm_ind_msg_frm_1(ue_info, i, act_def_fr_1); } + node_stats[0] = cp_node_level_stats(&node_stats[1]); + return msg_frm_3; } @@ -288,8 +292,10 @@ static arr_ue_id_t filter_ues_by_s_nssai_in_du_or_monolithic(const test_info_lst const ngran_node_t node_type = get_e2_node_type(); + gNB_MAC_INST *mac = RC.nrmac[0]; + NR_SCHED_LOCK(&mac->sched_lock); // Take MAC info - UE_iterator(RC.nrmac[0]->UE_info.connected_ue_list, ue) { + UE_iterator(mac->UE_info.connected_ue_list, ue) { NR_UE_sched_ctrl_t *sched_ctrl = &ue->UE_sched_ctrl; // UE matches if any of its DRBs matches for (size_t l = 0; l < seq_arr_size(&sched_ctrl->lc_config); ++l) { @@ -316,6 +322,10 @@ static arr_ue_id_t filter_ues_by_s_nssai_in_du_or_monolithic(const test_info_lst AssertFatal(arr_ue_id.sz < MAX_MOBILES_PER_GNB, "cannot have more UEs than global UE number maximum\n"); } + node_stats[1].mac_stats.dl.total_prb_aggregate = mac->mac_stats.dl.total_prb_aggregate; + node_stats[1].mac_stats.ul.total_prb_aggregate = mac->mac_stats.ul.total_prb_aggregate; + NR_SCHED_UNLOCK(&mac->sched_lock); + free(sd); // if NULL, nothing happens return arr_ue_id; diff --git a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm_subs.c b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm_subs.c index 80579e1754..a8ebe580ab 100644 --- a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm_subs.c +++ b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm_subs.c @@ -23,6 +23,18 @@ #include +e2_node_level_stats_t cp_node_level_stats(const e2_node_level_stats_t *src) +{ + e2_node_level_stats_t dst = { + .mac_stats.dl.total_prb_aggregate = src->mac_stats.dl.total_prb_aggregate, + .mac_stats.dl.used_prb_aggregate = src->mac_stats.dl.used_prb_aggregate, + .mac_stats.ul.total_prb_aggregate = src->mac_stats.ul.total_prb_aggregate, + .mac_stats.ul.used_prb_aggregate = src->mac_stats.ul.used_prb_aggregate, + }; + + return dst; +} + /* measurements that need to store values from previous reporting period have a limitation when it comes to multiple subscriptions to the same UEs; ric_req_id is unique per subscription */ typedef struct uldlcounter { @@ -46,7 +58,7 @@ static nr_pdcp_statistics_t get_pdcp_stats_per_drb(const uint32_t rrc_ue_id, con /* 3GPP TS 28.522 - section 5.1.2.1.1.1 note: this measurement is calculated as per spec */ -static meas_record_lst_t fill_DRB_PdcpSduVolumeDL(__attribute__((unused))uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx) +static meas_record_lst_t fill_DRB_PdcpSduVolumeDL(__attribute__((unused))uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx, __attribute__((unused))e2_node_level_stats_t* node_stats) { meas_record_lst_t meas_record = {0}; @@ -65,7 +77,7 @@ static meas_record_lst_t fill_DRB_PdcpSduVolumeDL(__attribute__((unused))uint32_ /* 3GPP TS 28.522 - section 5.1.2.1.2.1 note: this measurement is calculated as per spec */ -static meas_record_lst_t fill_DRB_PdcpSduVolumeUL(__attribute__((unused))uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx) +static meas_record_lst_t fill_DRB_PdcpSduVolumeUL(__attribute__((unused))uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx, __attribute__((unused))e2_node_level_stats_t* node_stats) { meas_record_lst_t meas_record = {0}; @@ -103,7 +115,7 @@ static nr_rlc_statistics_t get_rlc_stats_per_drb(const rnti_t rnti, const int rb /* 3GPP TS 28.522 - section 5.1.3.3.3 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 */ -static meas_record_lst_t fill_DRB_RlcSduDelayDl(__attribute__((unused))uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, __attribute__((unused))const size_t ue_idx) +static meas_record_lst_t fill_DRB_RlcSduDelayDl(__attribute__((unused))uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, __attribute__((unused))const size_t ue_idx, __attribute__((unused))e2_node_level_stats_t* node_stats) { meas_record_lst_t meas_record = {0}; @@ -122,7 +134,7 @@ static meas_record_lst_t fill_DRB_RlcSduDelayDl(__attribute__((unused))uint32_t /* 3GPP TS 28.522 - section 5.1.1.3.1 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 */ -static meas_record_lst_t fill_DRB_UEThpDl(uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx) +static meas_record_lst_t fill_DRB_UEThpDl(uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx, __attribute__((unused))e2_node_level_stats_t* node_stats) { meas_record_lst_t meas_record = {0}; @@ -141,7 +153,7 @@ static meas_record_lst_t fill_DRB_UEThpDl(uint32_t gran_period_ms, cudu_ue_info_ /* 3GPP TS 28.522 - section 5.1.1.3.3 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 */ -static meas_record_lst_t fill_DRB_UEThpUl(uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx) +static meas_record_lst_t fill_DRB_UEThpUl(uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx, __attribute__((unused))e2_node_level_stats_t* node_stats) { meas_record_lst_t meas_record = {0}; @@ -159,32 +171,30 @@ static meas_record_lst_t fill_DRB_UEThpUl(uint32_t gran_period_ms, cudu_ue_info_ } /* 3GPP TS 28.522 - section 5.1.1.2.1 - 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) */ -static meas_record_lst_t fill_RRU_PrbTotDl(__attribute__((unused))uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx) + note: this measurement is calculated as per spec */ +static meas_record_lst_t fill_RRU_PrbTotDl(__attribute__((unused))uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx, e2_node_level_stats_t* node_stats) { meas_record_lst_t meas_record = {0}; meas_record.value = INTEGER_MEAS_VALUE; // Get the number of DL PRBs - meas_record.int_val = ue_info.ue->mac_stats.dl.total_rbs - last_total_prbs[ue_idx].dl; // [PRBs] + meas_record.int_val = (ue_info.ue->mac_stats.dl.total_rbs - last_total_prbs[ue_idx].dl) * 100 / (node_stats[1].mac_stats.dl.total_prb_aggregate - node_stats[0].mac_stats.dl.total_prb_aggregate); // [%] last_total_prbs[ue_idx].dl = ue_info.ue->mac_stats.dl.total_rbs; return meas_record; } /* 3GPP TS 28.522 - section 5.1.1.2.2 - 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) */ -static meas_record_lst_t fill_RRU_PrbTotUl(__attribute__((unused))uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx) + note: this measurement is calculated as per spec */ +static meas_record_lst_t fill_RRU_PrbTotUl(__attribute__((unused))uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx, e2_node_level_stats_t* node_stats) { meas_record_lst_t meas_record = {0}; meas_record.value = INTEGER_MEAS_VALUE; // Get the number of UL PRBs - meas_record.int_val = ue_info.ue->mac_stats.ul.total_rbs - last_total_prbs[ue_idx].ul; // [PRBs] + meas_record.int_val = (ue_info.ue->mac_stats.ul.total_rbs - last_total_prbs[ue_idx].ul) * 100 / (node_stats[1].mac_stats.ul.total_prb_aggregate - node_stats[0].mac_stats.ul.total_prb_aggregate); // [%] last_total_prbs[ue_idx].ul = ue_info.ue->mac_stats.ul.total_rbs; return meas_record; @@ -217,7 +227,7 @@ void init_kpm_subs_data(void) } } -meas_record_lst_t get_kpm_meas_value(char* kpm_meas_name, uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx) +meas_record_lst_t get_kpm_meas_value(char* kpm_meas_name, uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx, e2_node_level_stats_t* node_stats) { assert(kpm_meas_name != NULL); @@ -226,7 +236,7 @@ meas_record_lst_t get_kpm_meas_value(char* kpm_meas_name, uint32_t gran_period_m assert(found_entry != NULL && "Unsupported KPM measurement name"); kv_measure_t *kv_found = (kv_measure_t *)found_entry->data; - meas_record_lst_t meas_record = kv_found->value(gran_period_ms, ue_info, ue_idx); + meas_record_lst_t meas_record = kv_found->value(gran_period_ms, ue_info, ue_idx, node_stats); return meas_record; } diff --git a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm_subs.h b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm_subs.h index 7dbd807fa1..e612ca2bab 100644 --- a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm_subs.h +++ b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm_subs.h @@ -34,7 +34,13 @@ typedef struct { } cudu_ue_info_pair_t; -typedef meas_record_lst_t (*kpm_meas_fp)(uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx); +typedef struct { + dlul_mac_stats_t mac_stats; +} e2_node_level_stats_t; + +e2_node_level_stats_t cp_node_level_stats(const e2_node_level_stats_t *src); + +typedef meas_record_lst_t (*kpm_meas_fp)(uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx, e2_node_level_stats_t* node_stats); typedef struct{ char* key; @@ -44,6 +50,6 @@ typedef struct{ void init_kpm_subs_data(void); -meas_record_lst_t get_kpm_meas_value(char* kpm_meas_name, uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx); +meas_record_lst_t get_kpm_meas_value(char* kpm_meas_name, uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx, e2_node_level_stats_t* node_stats); #endif From f88b93d14729e911a6dab262967c3ca3147b5e0f Mon Sep 17 00:00:00 2001 From: Teodora Date: Mon, 3 Nov 2025 12:14:50 +0100 Subject: [PATCH 04/12] Use the correct unit for PDCP SDU volume: [Mb] instead of [kb] --- openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm_subs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm_subs.c b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm_subs.c index a8ebe580ab..d3381cadd3 100644 --- a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm_subs.c +++ b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm_subs.c @@ -69,7 +69,7 @@ static meas_record_lst_t fill_DRB_PdcpSduVolumeDL(__attribute__((unused))uint32_ 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] + meas_record.int_val = (pdcp.rxsdu_bytes - last_pdcp_sdu_total_bytes[ue_idx].dl)*8/1000000; // [Mb] last_pdcp_sdu_total_bytes[ue_idx].dl = pdcp.rxsdu_bytes; return meas_record; @@ -88,7 +88,7 @@ static meas_record_lst_t fill_DRB_PdcpSduVolumeUL(__attribute__((unused))uint32_ 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] + meas_record.int_val = (pdcp.txsdu_bytes - last_pdcp_sdu_total_bytes[ue_idx].ul)*8/1000000; // [Mb] last_pdcp_sdu_total_bytes[ue_idx].ul = pdcp.txsdu_bytes; return meas_record; From e96cfbd88a8607aded713ecb8f287edd48b8cc41 Mon Sep 17 00:00:00 2001 From: Teodora Date: Thu, 6 Nov 2025 15:30:46 +0100 Subject: [PATCH 05/12] Update the FlexRIC submodule Needed notably due to https://gitlab.eurecom.fr/mosaic5g/flexric/-/merge_requests/68. --- openair2/E2AP/flexric | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/E2AP/flexric b/openair2/E2AP/flexric index df754a8553..6a595d8b24 160000 --- a/openair2/E2AP/flexric +++ b/openair2/E2AP/flexric @@ -1 +1 @@ -Subproject commit df754a85537f6db255b5330b8d83eda6a2742f25 +Subproject commit 6a595d8b243601b7148f60b5cb2cec47658e58c5 From b6bda6d97461dc1bffa6ef5f5f4e1e584cc5ea34 Mon Sep 17 00:00:00 2001 From: Teodora Date: Thu, 6 Nov 2025 15:26:49 +0100 Subject: [PATCH 06/12] RIC IP address within fr_args_t struct is not const anymore Related FlexRIC commit ID: https://gitlab.eurecom.fr/mosaic5g/flexric/-/commit/fd26e7474d18e90097bc1b2487d00598e9383400 --- executables/nr-cuup.c | 5 +++-- executables/nr-softmodem.c | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/executables/nr-cuup.c b/executables/nr-cuup.c index 0c2c9cdf3f..df2f633d95 100644 --- a/executables/nr-cuup.c +++ b/executables/nr-cuup.c @@ -51,8 +51,9 @@ static void initialize_agent(ngran_node_t node_type, e2_agent_args_t oai_args) 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); + fr_args_t args = {0}; + memcpy(args.ip, oai_args.ip, FR_IP_ADDRESS_LEN); + memcpy(args.libs_dir, oai_args.sm_dir, FR_CONF_FILE_LEN); sleep(1); diff --git a/executables/nr-softmodem.c b/executables/nr-softmodem.c index 0bd583662b..945e7e4cae 100644 --- a/executables/nr-softmodem.c +++ b/executables/nr-softmodem.c @@ -473,8 +473,9 @@ static void initialize_agent(ngran_node_t node_type, e2_agent_args_t oai_args) 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); + fr_args_t args = {0}; + memcpy(args.ip, oai_args.ip, FR_IP_ADDRESS_LEN); + memcpy(args.libs_dir, oai_args.sm_dir, FR_CONF_FILE_LEN); sleep(1); const gNB_RRC_INST* rrc = RC.nrrrc[0]; From 8cf7dd860796d1b7937f376bccbe8df976fe09b2 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 10 Nov 2025 17:49:54 +0100 Subject: [PATCH 07/12] CI: use intermediate variable for YAML file This harmonizes with DeployObject() (which uses the same variable) and shortens some lines for readability. --- ci-scripts/cls_containerize.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ci-scripts/cls_containerize.py b/ci-scripts/cls_containerize.py index 3cebcb24d7..32ce498be0 100644 --- a/ci-scripts/cls_containerize.py +++ b/ci-scripts/cls_containerize.py @@ -760,17 +760,18 @@ class Containerize(): logging.debug(f'\u001B[1m Undeploying OAI Object from server: {node}\u001B[0m') yaml = self.yamlPath.strip('/') wd = f'{lSourcePath}/{yaml}' + wd_yaml = f'{wd}/docker-compose.y*ml' with cls_cmd.getConnection(node) as ssh: ExistEnvFilePrint(ssh, wd) - services = GetRunningServices(ssh, f"{wd}/docker-compose.y*ml") + services = GetRunningServices(ssh, wd_yaml) copyin_res = None if services is not None: all_serv = " ".join([s for s, _ in services]) - ssh.run(f'docker compose -f {wd}/docker-compose.y*ml stop -- {all_serv}') - copyin_res = [CopyinServiceLog(ssh, lSourcePath, s, f"{wd}/docker-compose.y*ml", ctx) for s, _ in services] + ssh.run(f'docker compose -f {wd_yaml} stop -- {all_serv}') + copyin_res = [CopyinServiceLog(ssh, lSourcePath, s, wd_yaml, ctx) for s, _ in services] else: logging.warning('could not identify services to stop => no log file') - ssh.run(f'docker compose -f {wd}/docker-compose.y*ml down -v') + ssh.run(f'docker compose -f {wd_yaml} down -v') ssh.run(f'rm {wd}/.env') if not copyin_res: HTML.CreateHtmlTestRowQueue('N/A', 'KO', ['Could not copy logfile(s)']) From 247e908b6eb97c82800d4602ff45506c6a13a693 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 10 Nov 2025 14:31:23 +0100 Subject: [PATCH 08/12] Simplify UndeployObject() and GetDeployedObjects() GetRunningServices() was returning all services, running or stopped. Hence, rename to reflect what this function does, and rewrite slightly to better capture what is actually happening. Also, don't return the container ID, as we don't use it. Call stop on all services, as we will down the deployment right after. The list of services is still used to retrieve logs. Remove a stray "return False", which would sometimes prevent us from seeing all error messages. --- ci-scripts/cls_containerize.py | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/ci-scripts/cls_containerize.py b/ci-scripts/cls_containerize.py index 32ce498be0..ee295b1f79 100644 --- a/ci-scripts/cls_containerize.py +++ b/ci-scripts/cls_containerize.py @@ -165,25 +165,26 @@ def CopyinServiceLog(ssh, lSourcePath, svcName, wd_yaml, ctx): ssh.run(f'docker compose -f {wd_yaml} logs {svcName} --no-log-prefix &> {remote_filename}') return archiveArtifact(ssh, ctx, remote_filename) -def GetRunningServices(ssh, file): +def GetDeployedServices(ssh, file): ret = ssh.run(f'docker compose -f {file} config --services') if ret.returncode != 0: + logging.error("could not get services") return None allServices = ret.stdout.splitlines() - running_services = [] + deployed_services = [] for s in allServices: - # outputs the hash if the container is running - ret = ssh.run(f'docker compose -f {file} ps --all --quiet -- {s}') + # outputs the hash if the container has been deployed (but might be stopped) + ret = ssh.run(f'docker compose -f {file} ps --all --quiet -- {s}', silent=True) if ret.returncode != 0: - logging.info(f"service {s}: {ret.stdout}") + # error: should not happen as we iterate over docker-provided service list + logging.error(f"service {s}: {ret.stdout}") elif ret.stdout == "": - logging.warning(f"could not retrieve information for service {s}") + logging.info(f"service {s} not deployed") else: c = ret.stdout - logging.debug(f'running service {s} with container id {c}') - running_services.append((s, c)) - logging.info(f'stopping services: {running_services}') - return running_services + logging.info(f'service {s} with container id {c}') + deployed_services.append(s) + return deployed_services def CheckLogs(self, filename, HTML, RAN): success = True @@ -763,19 +764,19 @@ class Containerize(): wd_yaml = f'{wd}/docker-compose.y*ml' with cls_cmd.getConnection(node) as ssh: ExistEnvFilePrint(ssh, wd) - services = GetRunningServices(ssh, wd_yaml) + services = GetDeployedServices(ssh, wd_yaml) copyin_res = None + ssh.run(f'docker compose -f {wd_yaml} stop') if services is not None: - all_serv = " ".join([s for s, _ in services]) - ssh.run(f'docker compose -f {wd_yaml} stop -- {all_serv}') - copyin_res = [CopyinServiceLog(ssh, lSourcePath, s, wd_yaml, ctx) for s, _ in services] + copyin_res = [CopyinServiceLog(ssh, lSourcePath, s, wd_yaml, ctx) for s in services] else: logging.warning('could not identify services to stop => no log file') ssh.run(f'docker compose -f {wd_yaml} down -v') ssh.run(f'rm {wd}/.env') if not copyin_res: HTML.CreateHtmlTestRowQueue('N/A', 'KO', ['Could not copy logfile(s)']) - return False + logging.error(f"could not copy all files: {copyin_res=} {services=}") + success = False else: log_results = [CheckLogs(self, f, HTML, RAN) for f in copyin_res] success = all(log_results) From ddcb216a3543d96a1c86f4b3a8c5bcb19d342f4f Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 13 Nov 2025 15:04:14 +0100 Subject: [PATCH 09/12] Improve logging in CI Undeploy/DeployObject() Consistently print requested services (if applicable) and outcome of the step. --- ci-scripts/cls_containerize.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/ci-scripts/cls_containerize.py b/ci-scripts/cls_containerize.py index ee295b1f79..367bb47eb5 100644 --- a/ci-scripts/cls_containerize.py +++ b/ci-scripts/cls_containerize.py @@ -716,7 +716,6 @@ class Containerize(): def DeployObject(self, ctx, node, HTML): num_attempts = self.num_attempts lSourcePath = self.eNBSourceCodePath - logging.debug(f'Deploying OAI Object on server: {node}') yaml = self.yamlPath.strip('/') wd = f'{lSourcePath}/{yaml}' wd_yaml = f'{wd}/docker-compose.y*ml' @@ -727,6 +726,7 @@ class Containerize(): logging.error(msg) HTML.CreateHtmlTestRowQueue('N/A', 'KO', [msg]) return False + logging.info(f'\u001B[1mDeploying object(s) "{services}" on server {node}\u001B[0m') ExistEnvFilePrint(ssh, wd) WriteEnvFile(ssh, services, wd, self.deploymentTag, self.flexricTag) if num_attempts <= 0: @@ -751,14 +751,16 @@ class Containerize(): imagesInfo = info.stdout.splitlines()[1:] logging.debug(f'{info.stdout.splitlines()[1:]}') if deployed: - HTML.CreateHtmlTestRowQueue('N/A', 'OK', ['\n'.join(imagesInfo)]) + HTML.CreateHtmlTestRowQueue(self.services, 'OK', ['\n'.join(imagesInfo)]) + logging.info('\u001B[1m Deploying objects Pass\u001B[0m') else: - HTML.CreateHtmlTestRowQueue('N/A', 'KO', ['\n'.join(imagesInfo)]) + HTML.CreateHtmlTestRowQueue(self.services, 'KO', ['\n'.join(imagesInfo)]) + logging.error('\u001B[1m Deploying objects Failed\u001B[0m') return deployed def UndeployObject(self, ctx, node, HTML, RAN): lSourcePath = self.eNBSourceCodePath - logging.debug(f'\u001B[1m Undeploying OAI Object from server: {node}\u001B[0m') + logging.info(f'\u001B[1m Undeploying all objects from server {node}\u001B[0m') yaml = self.yamlPath.strip('/') wd = f'{lSourcePath}/{yaml}' wd_yaml = f'{wd}/docker-compose.y*ml' @@ -781,7 +783,7 @@ class Containerize(): log_results = [CheckLogs(self, f, HTML, RAN) for f in copyin_res] success = all(log_results) if success: - logging.info('\u001B[1m Undeploying OAI Object Pass\u001B[0m') + logging.info('\u001B[1m Undeploying objects Pass\u001B[0m') else: - logging.error('\u001B[1m Undeploying OAI Object Failed\u001B[0m') + logging.error('\u001B[1m Undeploying objects Failed\u001B[0m') return success From de8d0991ec290b537b1d515808d62edaa48c837b Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 13 Nov 2025 11:34:30 +0100 Subject: [PATCH 10/12] Remove services to be undeployed from XML files In all these cases, the intention is to undeploy all services. Correspondingly, remove the services from the XML to avoid any ambiguity. --- ci-scripts/xml_files/container_5g_rfsim_u0_25prb.xml | 1 - ci-scripts/xml_files/container_sa_n310_2X2_100MHz_quectel.xml | 1 - ci-scripts/xml_files/container_sa_n310_2X2_60MHz_quectel.xml | 1 - ci-scripts/xml_files/container_sa_n310_4X4_60MHz_quectel.xml | 1 - 4 files changed, 4 deletions(-) diff --git a/ci-scripts/xml_files/container_5g_rfsim_u0_25prb.xml b/ci-scripts/xml_files/container_5g_rfsim_u0_25prb.xml index d563b3aab4..86b9040b63 100644 --- a/ci-scripts/xml_files/container_5g_rfsim_u0_25prb.xml +++ b/ci-scripts/xml_files/container_5g_rfsim_u0_25prb.xml @@ -144,7 +144,6 @@ true Undeploy all OAI 5G stack localhost - oai-vnf oai-pnf ci-scripts/yaml_files/5g_rfsimulator_u0_25prb 1,0,0,0 1,0,0,0 diff --git a/ci-scripts/xml_files/container_sa_n310_2X2_100MHz_quectel.xml b/ci-scripts/xml_files/container_sa_n310_2X2_100MHz_quectel.xml index a4d72398e1..ad98afcd32 100644 --- a/ci-scripts/xml_files/container_sa_n310_2X2_100MHz_quectel.xml +++ b/ci-scripts/xml_files/container_sa_n310_2X2_100MHz_quectel.xml @@ -146,7 +146,6 @@ Undeploy gNB matix ci-scripts/yaml_files/5g_sa_n310_2x2_100MHz - oai-gnb 10,100,100,100 10,100,100,100 diff --git a/ci-scripts/xml_files/container_sa_n310_2X2_60MHz_quectel.xml b/ci-scripts/xml_files/container_sa_n310_2X2_60MHz_quectel.xml index ab7188c023..a809fafa2c 100644 --- a/ci-scripts/xml_files/container_sa_n310_2X2_60MHz_quectel.xml +++ b/ci-scripts/xml_files/container_sa_n310_2X2_60MHz_quectel.xml @@ -146,7 +146,6 @@ Undeploy gNB matix ci-scripts/yaml_files/5g_sa_n310_2x2_60MHz - oai-gnb 15,100,100,100 20,100,100,100 diff --git a/ci-scripts/xml_files/container_sa_n310_4X4_60MHz_quectel.xml b/ci-scripts/xml_files/container_sa_n310_4X4_60MHz_quectel.xml index d7cf992aa4..d4d0d51258 100644 --- a/ci-scripts/xml_files/container_sa_n310_4X4_60MHz_quectel.xml +++ b/ci-scripts/xml_files/container_sa_n310_4X4_60MHz_quectel.xml @@ -146,7 +146,6 @@ Undeploy VNF-PNF matix ci-scripts/yaml_files/5g_sa_n310_4x4_60MHz - oai-vnf oai-pnf 10,100,100,100 10,100,100,100 From 81680e29a9f7d91c2fe6bf46971a4566af7655d8 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 13 Nov 2025 15:04:10 +0100 Subject: [PATCH 11/12] Implement StopObject() For some test cases, we might want to stop a service earlier. This functionality is done by StopObject(). Test log collection is still done by UndeployObject(), which will collect the logs of all services (at that point, stopped or not). --- ci-scripts/cls_containerize.py | 29 +++++++++++++++++++ ci-scripts/main.py | 4 ++- ci-scripts/tests/deployment.py | 27 +++++++++++++++++ .../tests/simple-undep/docker-compose.yml | 23 +++++++++++++++ ci-scripts/xml_class_list.yml | 1 + 5 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 ci-scripts/tests/simple-undep/docker-compose.yml diff --git a/ci-scripts/cls_containerize.py b/ci-scripts/cls_containerize.py index 367bb47eb5..c94b0c8dfb 100644 --- a/ci-scripts/cls_containerize.py +++ b/ci-scripts/cls_containerize.py @@ -758,6 +758,35 @@ class Containerize(): logging.error('\u001B[1m Deploying objects Failed\u001B[0m') return deployed + def StopObject(self, ctx, node, HTML): + lSourcePath = self.eNBSourceCodePath + if not self.services: + raise ValueError(f'no services provided') + logging.info(f'\u001B[1m Stopping objects "{self.services}" from server: {node}\u001B[0m') + reqServices = self.services.split() + yaml = self.yamlPath.strip('/') + wd = f'{lSourcePath}/{yaml}' + wd_yaml = f'{wd}/docker-compose.y*ml' + with cls_cmd.getConnection(node) as ssh: + ExistEnvFilePrint(ssh, wd) + services = GetDeployedServices(ssh, wd_yaml) + success = [] + fail = [] + for s in reqServices: + if s in services: + ssh.run(f'docker compose -f {wd_yaml} stop -- {s}') + success.append(s) + else: + logging.error(f"no such service {s}") + fail.append(s) + if success == reqServices: + logging.info('\u001B[1m Stopping object Pass\u001B[0m') + HTML.CreateHtmlTestRowQueue(self.services, 'OK', [f'Stopped {self.services}']) + else: + logging.error('\u001B[1m Stopping object Failed\u001B[0m') + HTML.CreateHtmlTestRowQueue(self.services, 'KO', [f'Failed stopping {" ".join(fail)}, succeeded {" ".join(success)}']) + return success + def UndeployObject(self, ctx, node, HTML, RAN): lSourcePath = self.eNBSourceCodePath logging.info(f'\u001B[1m Undeploying all objects from server {node}\u001B[0m') diff --git a/ci-scripts/main.py b/ci-scripts/main.py index 2428df83af..8aadad76bb 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -214,7 +214,7 @@ def ExecuteActionWithParam(action, ctx, node): core_op = getattr(cls_oaicitest.OaiCiTest, action) success = core_op(cn_id, ctx, HTML) - elif action == 'Deploy_Object' or action == 'Undeploy_Object' or action == "Create_Workspace": + elif action == 'Deploy_Object' or action == 'Undeploy_Object' or action == "Create_Workspace" or action == "Stop_Object": CONTAINERS.yamlPath = test.findtext('yaml_path') string_field=test.findtext('d_retx_th') if (string_field is not None): @@ -227,6 +227,8 @@ def ExecuteActionWithParam(action, ctx, node): CONTAINERS.deploymentTag = cls_containerize.CreateTag(CONTAINERS.ranCommitID, CONTAINERS.ranBranch, CONTAINERS.ranAllowMerge) if action == 'Deploy_Object': success = CONTAINERS.DeployObject(ctx, node, HTML) + elif action == 'Stop_Object': + success = CONTAINERS.StopObject(ctx, node, HTML) elif action == 'Undeploy_Object': success = CONTAINERS.UndeployObject(ctx, node, HTML, RAN) elif action == 'Create_Workspace': diff --git a/ci-scripts/tests/deployment.py b/ci-scripts/tests/deployment.py index e7efc707bf..10bd2c843f 100644 --- a/ci-scripts/tests/deployment.py +++ b/ci-scripts/tests/deployment.py @@ -60,6 +60,33 @@ class TestDeploymentMethods(unittest.TestCase): self.assertTrue(deploy) self.assertTrue(undeploy) + def test_stop_services(self): + self.cont.yamlPath = 'tests/simple-undep/' + self.cont.deploymentTag = "noble" + # should deploy both testA and testB + deploy = self.cont.DeployObject(self.ctx, self.node, self.html) + # should fail (no such service) + self.cont.services = "testC" + stopC = self.cont.StopObject(self.ctx, self.node, self.html) + # should stop testA + self.cont.services = "testA" + stopA = self.cont.StopObject(self.ctx, self.node, self.html) + # should (re-)stop testA (no-op) + self.cont.services = "testA" + stopA2 = self.cont.StopObject(self.ctx, self.node, self.html) + # should deploy testB + self.cont.services = "testB" + stopB = self.cont.StopObject(self.ctx, self.node, self.html) + # should not undeploy anything (everything already stopped) + self.cont.services = None + undeployAll = self.cont.UndeployObject(self.ctx, self.node, self.html, self.ran) + self.assertTrue(deploy) + self.assertFalse(stopC) + self.assertTrue(stopA) + self.assertTrue(stopA2) + self.assertTrue(stopB) + self.assertTrue(undeployAll) + def test_deployfails(self): # fails reliably old = self.cont.yamlPath diff --git a/ci-scripts/tests/simple-undep/docker-compose.yml b/ci-scripts/tests/simple-undep/docker-compose.yml new file mode 100644 index 0000000000..6f88826a9a --- /dev/null +++ b/ci-scripts/tests/simple-undep/docker-compose.yml @@ -0,0 +1,23 @@ +services: + testA: + image: ubuntu:${TAG:-jammy} + container_name: test_container_A + cap_drop: + - ALL + entrypoint: /bin/bash -c "sleep infinity" + healthcheck: + test: /bin/bash -c "true" + interval: 1s + timeout: 1s + retries: 1 + testB: + image: ubuntu:${TAG:-jammy} + container_name: test_container_B + cap_drop: + - ALL + entrypoint: /bin/bash -c "sleep infinity" + healthcheck: + test: /bin/bash -c "true" + interval: 1s + timeout: 1s + retries: 1 diff --git a/ci-scripts/xml_class_list.yml b/ci-scripts/xml_class_list.yml index 615454bbea..a20b78fc99 100755 --- a/ci-scripts/xml_class_list.yml +++ b/ci-scripts/xml_class_list.yml @@ -20,6 +20,7 @@ - Build_Image - Build_Run_Tests - Deploy_Object + - Stop_Object - Undeploy_Object - Cppcheck_Analysis - Deploy_Run_OC_PhySim From 6a6588e9cbb13ffdaa01c88537293d431be9f96b Mon Sep 17 00:00:00 2001 From: Teodora Date: Thu, 13 Nov 2025 12:11:03 +0100 Subject: [PATCH 12/12] OAI-FLEXRIC-RAN-Integration-Test CI pipeline 1. Rename oai-flexric to nearRT-RIC. FlexRIC is a project combining nearRT-RIC, xApps, and E2 agent emulators. 2. Instead of undeploying all the containers at the same time, and not checking the logs for xApps and nearRT-RIC, do the following: - Stop containers (docker compose stop) - one or subgroup of running containers in the following order: a) xapp-kpm-moni b) xapp-kpm-rc c) xapp-gtp-mac-rlc-pdcp-moni d) oai-nr-ue oai-nr-ue2 e) oai-gnb f) nearRT-RIC - Undeploy containers (docker compose down), collect and analyze all the logs. --- ci-scripts/cls_containerize.py | 19 +++++ .../xml_files/container_5g_flexric_rfsim.xml | 79 +++++++++++++++++-- .../5g_rfsimulator_flexric/docker-compose.yml | 14 ++-- 3 files changed, 97 insertions(+), 15 deletions(-) diff --git a/ci-scripts/cls_containerize.py b/ci-scripts/cls_containerize.py index c94b0c8dfb..cd07851319 100644 --- a/ci-scripts/cls_containerize.py +++ b/ci-scripts/cls_containerize.py @@ -47,6 +47,7 @@ import helpreadme as HELP import constants as CONST import cls_oaicitest from cls_ci_helper import archiveArtifact +from collections import deque #----------------------------------------------------------- # Helper functions used here and in other classes @@ -216,6 +217,24 @@ def CheckLogs(self, filename, HTML, RAN): else: HTML.CreateHtmlTestRowQueue(opt, 'OK', [HTML.htmleNBFailureMsg]) HTML.htmleNBFailureMsg = "" + elif 'xapp' in name: + opt = f"Undeploy {name}" + with open(f'{filename}', "r") as f: + last_line = deque(f, maxlen=1).pop() + if ('Test xApp run SUCCESSFULLY' in last_line): + HTML.CreateHtmlTestRowQueue(opt, 'OK', ["xApp run successfully"]) + else: + HTML.CreateHtmlTestRowQueue(opt, 'KO', ["xApp didn't run successfully"]) + success = False + elif 'RIC' in name: + opt = f"Undeploy {name}" + with open(f'{filename}', 'r') as f: + last_line = deque(f, maxlen=1).pop() + if ('Removing E2 Node' in last_line): + HTML.CreateHtmlTestRowQueue(opt, 'OK', ["nearRT-RIC run successfully"]) + else: + HTML.CreateHtmlTestRowQueue(opt, 'KO', ["nearRT-RIC didn't run successfully"]) + success = False else: logging.info(f"Skipping analysis of log '{filename}': no submatch for xNB/UE") logging.debug(f"log check: file {filename} passed analysis {success}") diff --git a/ci-scripts/xml_files/container_5g_flexric_rfsim.xml b/ci-scripts/xml_files/container_5g_flexric_rfsim.xml index 536952a2bc..135eab6b68 100644 --- a/ci-scripts/xml_files/container_5g_flexric_rfsim.xml +++ b/ci-scripts/xml_files/container_5g_flexric_rfsim.xml @@ -42,6 +42,13 @@ 002006 444444 100002 + 100003 + 100004 + 100005 + 100006 + 100007 + 100008 + 100009 100001 222221 222222 @@ -95,10 +102,10 @@ Deploy_Object - Deploy OAI FlexRIC + Deploy OAI nearRT-RIC localhost ci-scripts/yaml_files/5g_rfsimulator_flexric - oai-flexric + nearRT-RIC @@ -151,16 +158,72 @@ + Stop_Object + Stop RC monitoring xApp + localhost + ci-scripts/yaml_files/5g_rfsimulator_flexric + xapp-rc-moni + + + + Stop_Object + Stop KPM monitoring xApp + localhost + ci-scripts/yaml_files/5g_rfsimulator_flexric + xapp-kpm-moni + + + + Stop_Object + Stop KPM monitoring and RC control xApp + localhost + ci-scripts/yaml_files/5g_rfsimulator_flexric + xapp-kpm-rc + + + + Stop_Object + Stop custom SMs monitoring xApp + localhost + ci-scripts/yaml_files/5g_rfsimulator_flexric + xapp-gtp-mac-rlc-pdcp-moni + + + + Stop_Object + Stop OAI UEs + localhost + ci-scripts/yaml_files/5g_rfsimulator_flexric + oai-nr-ue oai-nr-ue2 + + + + Stop_Object + Stop OAI gNB + localhost + ci-scripts/yaml_files/5g_rfsimulator_flexric + oai-gnb + + + + Stop_Object + Stop nearRT-RIC + localhost + ci-scripts/yaml_files/5g_rfsimulator_flexric + nearRT-RIC + + + Undeploy_Object - Undeploy RAN and Flexric + Undeploy RAN and FlexRIC localhost ci-scripts/yaml_files/5g_rfsimulator_flexric true - + Deploy_Object - RC monitoring + Deploy RC monitoring localhost ci-scripts/yaml_files/5g_rfsimulator_flexric xapp-rc-moni @@ -168,7 +231,7 @@ Deploy_Object - KPM monitoring + Deploy KPM monitoring localhost ci-scripts/yaml_files/5g_rfsimulator_flexric xapp-kpm-moni @@ -176,7 +239,7 @@ Deploy_Object - KPM monitoring and RC control + Deploy KPM monitoring and RC control localhost ci-scripts/yaml_files/5g_rfsimulator_flexric xapp-kpm-rc @@ -184,7 +247,7 @@ Deploy_Object - Custom SMs monitoring + Deploy custom SMs monitoring localhost ci-scripts/yaml_files/5g_rfsimulator_flexric xapp-gtp-mac-rlc-pdcp-moni diff --git a/ci-scripts/yaml_files/5g_rfsimulator_flexric/docker-compose.yml b/ci-scripts/yaml_files/5g_rfsimulator_flexric/docker-compose.yml index 8e1688dff3..5bb8d0246d 100644 --- a/ci-scripts/yaml_files/5g_rfsimulator_flexric/docker-compose.yml +++ b/ci-scripts/yaml_files/5g_rfsimulator_flexric/docker-compose.yml @@ -1,7 +1,7 @@ services: - oai-flexric: + nearRT-RIC: image: ${REGISTRY-oaisoftwarealliance/}oai-flexric:${FLEXRIC_TAG:-develop} - container_name: oai-flexric + container_name: nearRT-RIC networks: public_net: ipv4_address: 192.168.70.150 @@ -17,7 +17,7 @@ services: command: "stdbuf -o0 /usr/local/flexric/xApp/c/monitor/xapp_rc_moni" container_name: xapp-rc-moni depends_on: - - oai-flexric + - nearRT-RIC - oai-gnb networks: public_net: @@ -34,7 +34,7 @@ services: command: "stdbuf -o0 /usr/local/flexric/xApp/c/monitor/xapp_kpm_moni" container_name: xapp-kpm-moni depends_on: - - oai-flexric + - nearRT-RIC - oai-gnb networks: public_net: @@ -51,7 +51,7 @@ services: command: "stdbuf -o0 /usr/local/flexric/xApp/c/kpm_rc/xapp_kpm_rc" container_name: xapp-kpm-rc depends_on: - - oai-flexric + - nearRT-RIC - oai-gnb networks: public_net: @@ -68,7 +68,7 @@ services: command: "stdbuf -o0 /usr/local/flexric/xApp/c/monitor/xapp_gtp_mac_rlc_pdcp_moni" container_name: xapp-gtp-mac-rlc-pdcp-moni depends_on: - - oai-flexric + - nearRT-RIC - oai-gnb networks: public_net: @@ -88,7 +88,7 @@ services: USE_ADDITIONAL_OPTIONS: -E --rfsim --log_config.global_log_options level,nocolor,time ASAN_OPTIONS: detect_leaks=0 depends_on: - - oai-flexric + - nearRT-RIC networks: public_net: ipv4_address: 192.168.70.151