diff --git a/ci-scripts/cls_containerize.py b/ci-scripts/cls_containerize.py index 3cebcb24d7..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 @@ -165,25 +166,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 @@ -215,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}") @@ -715,7 +735,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' @@ -726,6 +745,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: @@ -750,36 +770,68 @@ 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 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.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' with cls_cmd.getConnection(node) as ssh: ExistEnvFilePrint(ssh, wd) - services = GetRunningServices(ssh, f"{wd}/docker-compose.y*ml") + 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}/docker-compose.y*ml stop -- {all_serv}') - copyin_res = [CopyinServiceLog(ssh, lSourcePath, s, f"{wd}/docker-compose.y*ml", 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}/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)']) - 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) 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 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 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/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 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 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/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]; 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..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 @@ -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}; @@ -57,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; @@ -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}; @@ -76,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; @@ -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 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 diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 1466099ab1..fd1cf7f9f3 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -1223,7 +1223,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); @@ -1337,7 +1337,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; @@ -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.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 17a4ad5a42..3f546d41b4 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;