From 81547750f3f9222b99d91bc4354aa4c7f7815d63 Mon Sep 17 00:00:00 2001 From: Xin Zhe Khooi Date: Sun, 18 Feb 2024 02:55:20 +0000 Subject: [PATCH 01/39] added telnetsrv_rrc for rrc release --- common/utils/telnetsrv/CMakeLists.txt | 7 +- common/utils/telnetsrv/telnetsrv_rrc.c | 108 +++++++++++++++++++++++++ 2 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 common/utils/telnetsrv/telnetsrv_rrc.c diff --git a/common/utils/telnetsrv/CMakeLists.txt b/common/utils/telnetsrv/CMakeLists.txt index d7b9b3cf9d..a7a364d80e 100644 --- a/common/utils/telnetsrv/CMakeLists.txt +++ b/common/utils/telnetsrv/CMakeLists.txt @@ -64,8 +64,13 @@ add_library(telnetsrv_bearer MODULE telnetsrv_bearer.c) target_link_libraries(telnetsrv_bearer PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) add_dependencies(telnetsrv telnetsrv_bearer) +message(STATUS "Add RRC specific telnet functions in libtelnetsrv_rrc.so") +add_library(telnetsrv_rrc MODULE telnetsrv_rrc.c) +target_link_libraries(telnetsrv_rrc PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) +add_dependencies(telnetsrv telnetsrv_rrc) + # all libraries should be written to root build dir -set_target_properties(telnetsrv telnetsrv_enb telnetsrv_5Gue telnetsrv_ci telnetsrv_bearer +set_target_properties(telnetsrv telnetsrv_enb telnetsrv_5Gue telnetsrv_ci telnetsrv_bearer telnetsrv_rrc PROPERTIES LIBRARY_OUTPUT_DIRECTORY ../../.. ) diff --git a/common/utils/telnetsrv/telnetsrv_rrc.c b/common/utils/telnetsrv/telnetsrv_rrc.c new file mode 100644 index 0000000000..ad5ca94c43 --- /dev/null +++ b/common/utils/telnetsrv/telnetsrv_rrc.c @@ -0,0 +1,108 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "openair2/RRC/NR/rrc_gNB_UE_context.h" + +#define TELNETSERVERCODE +#include "telnetsrv.h" + +#define ERROR_MSG_RET(mSG, aRGS...) do { prnt(mSG, ##aRGS); return 1; } while (0) + +static int get_single_ue_id(void) +{ + rrc_gNB_ue_context_t *ue_context_p = NULL; + RB_FOREACH(ue_context_p, rrc_nr_ue_tree_s, &(RC.nrrrc[0]->rrc_ue_head)) { + return ue_context_p->ue_context.rrc_ue_id; + } + return -1; +} + +int rrc_gNB_trigger_release(char *buf, int debug, telnet_printfunc_t prnt) { + ue_id_t ue_id = -1; + protocol_ctxt_t ctxt; + gNB_RRC_INST *rrc = RC.nrrrc[0]; + + if (!buf) { + ue_id = get_single_ue_id(); + if (ue_id < 1) { + prnt("no UE found\n"); + ERROR_MSG_RET("no UE found\n"); + } + } else { + ue_id = strtol(buf, NULL, 10); + if (ue_id < 1 || ue_id >= 0xfffffe) { + prnt("UE ID needs to be [1,0xfffffe]\n"); + ERROR_MSG_RET("UE ID needs to be [1,0xfffffe]\n"); + } + } + + /* get RRC and UE */ + rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(rrc, ue_id); + if (!ue_context_p) { + prnt("Could not find UE context associated with UE ID %u\n", ue_id); + LOG_E(RRC, "Could not find UE context associated with UE ID %u\n", ue_id); + return -1; + } + gNB_RRC_UE_t *UE = &ue_context_p->ue_context; + + PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, 0, GNB_FLAG_YES, UE->rrc_ue_id, 0, 0); + ctxt.eNB_index = 0; + + rrc_gNB_generate_RRCRelease(&ctxt, ue_context_p); + prnt("RRC Release triggered for UE %u\n", ue_id); + + return 0; +} + +int rrc_gNB_trigger_release_all(char *buf, int debug, telnet_printfunc_t prnt) { + rrc_gNB_ue_context_t *ue_context_p = NULL; + protocol_ctxt_t ctxt; + RB_FOREACH(ue_context_p, rrc_nr_ue_tree_s, &(RC.nrrrc[0]->rrc_ue_head)) { + gNB_RRC_UE_t *UE = &ue_context_p->ue_context; + PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, 0, GNB_FLAG_YES, UE->rrc_ue_id, 0, 0); + ctxt.eNB_index = 0; + rrc_gNB_generate_RRCRelease(&ctxt, ue_context_p); + prnt("RRC Release triggered for UE %u\n", UE->rrc_ue_id); + } + return -1; +} + +static telnetshell_cmddef_t rrc_cmds[] = { + {"release_rrc", "[rrc_ue_id(int,opt)]", rrc_gNB_trigger_release}, + {"release_rrc_all", "", rrc_gNB_trigger_release_all}, + {"", "", NULL}, +}; + +static telnetshell_vardef_t rrc_vars[] = { + {"", 0, 0, NULL} +}; + +void add_rrc_cmds(void) { + add_telnetcmd("rrc", rrc_vars, rrc_cmds); +} From 4003936da580faba038d093dc518f5dd8e800ac1 Mon Sep 17 00:00:00 2001 From: Xin Zhe Khooi Date: Sun, 18 Feb 2024 02:57:09 +0000 Subject: [PATCH 02/39] telnetsrv_rrc: resolve warning --- common/utils/telnetsrv/telnetsrv_rrc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/utils/telnetsrv/telnetsrv_rrc.c b/common/utils/telnetsrv/telnetsrv_rrc.c index ad5ca94c43..3e879aa988 100644 --- a/common/utils/telnetsrv/telnetsrv_rrc.c +++ b/common/utils/telnetsrv/telnetsrv_rrc.c @@ -65,8 +65,8 @@ int rrc_gNB_trigger_release(char *buf, int debug, telnet_printfunc_t prnt) { /* get RRC and UE */ rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(rrc, ue_id); if (!ue_context_p) { - prnt("Could not find UE context associated with UE ID %u\n", ue_id); - LOG_E(RRC, "Could not find UE context associated with UE ID %u\n", ue_id); + prnt("Could not find UE context associated with UE ID %lu\n", ue_id); + LOG_E(RRC, "Could not find UE context associated with UE ID %lu\n", ue_id); return -1; } gNB_RRC_UE_t *UE = &ue_context_p->ue_context; From 819f7c1d22b3e9df5e71b4c0949145905b6a357e Mon Sep 17 00:00:00 2001 From: Xin Zhe Khooi Date: Sun, 18 Feb 2024 03:23:00 +0000 Subject: [PATCH 03/39] telnetsrv_rrc: clean up and documentation --- common/utils/telnetsrv/telnetsrv_rrc.c | 37 +++++++++++++++++++++----- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/common/utils/telnetsrv/telnetsrv_rrc.c b/common/utils/telnetsrv/telnetsrv_rrc.c index 3e879aa988..464fb99853 100644 --- a/common/utils/telnetsrv/telnetsrv_rrc.c +++ b/common/utils/telnetsrv/telnetsrv_rrc.c @@ -34,6 +34,18 @@ #define ERROR_MSG_RET(mSG, aRGS...) do { prnt(mSG, ##aRGS); return 1; } while (0) +/** + * Module brief: + * This module is used to add RRCRelease commands to the telnet server in the + * absence of full support for E2SM RAN Control (RC) function in the RIC. + * This provides similar functionality to the ORAN.WG3.E2SM-RC-R003-v05.00 + * 8.4.5.4 RRC Connection Release Control which is initiated by the RIC. + * + * Implementation notes: + * We refer to the method call rrc_gNB_generate_RRCRelease at rrc_gNB_NGAP.c + * during rrc_gNB_process_NGAP_UE_CONTEXT_RELEASE_COMMAND message generation. +*/ + static int get_single_ue_id(void) { rrc_gNB_ue_context_t *ue_context_p = NULL; @@ -43,16 +55,22 @@ static int get_single_ue_id(void) return -1; } +/** + * @brief Trigger RRC Release for a specific UE + * @param buf: RRC UE ID + * @param debug: Debug flag + * @param prnt: Print function + * @return 0 on success, -1 on failure +*/ int rrc_gNB_trigger_release(char *buf, int debug, telnet_printfunc_t prnt) { ue_id_t ue_id = -1; protocol_ctxt_t ctxt; - gNB_RRC_INST *rrc = RC.nrrrc[0]; if (!buf) { ue_id = get_single_ue_id(); if (ue_id < 1) { - prnt("no UE found\n"); - ERROR_MSG_RET("no UE found\n"); + prnt("No UE found!\n"); + ERROR_MSG_RET("No UE found!\n"); } } else { ue_id = strtol(buf, NULL, 10); @@ -63,14 +81,15 @@ int rrc_gNB_trigger_release(char *buf, int debug, telnet_printfunc_t prnt) { } /* get RRC and UE */ + gNB_RRC_INST *rrc = RC.nrrrc[0]; rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(rrc, ue_id); if (!ue_context_p) { prnt("Could not find UE context associated with UE ID %lu\n", ue_id); LOG_E(RRC, "Could not find UE context associated with UE ID %lu\n", ue_id); return -1; } + gNB_RRC_UE_t *UE = &ue_context_p->ue_context; - PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, 0, GNB_FLAG_YES, UE->rrc_ue_id, 0, 0); ctxt.eNB_index = 0; @@ -80,17 +99,23 @@ int rrc_gNB_trigger_release(char *buf, int debug, telnet_printfunc_t prnt) { return 0; } +/** + * @brief Trigger RRC Release for all UEs +*/ int rrc_gNB_trigger_release_all(char *buf, int debug, telnet_printfunc_t prnt) { rrc_gNB_ue_context_t *ue_context_p = NULL; - protocol_ctxt_t ctxt; + protocol_ctxt_t ctxt; /* Not sure what exactly is this */ + RB_FOREACH(ue_context_p, rrc_nr_ue_tree_s, &(RC.nrrrc[0]->rrc_ue_head)) { gNB_RRC_UE_t *UE = &ue_context_p->ue_context; PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, 0, GNB_FLAG_YES, UE->rrc_ue_id, 0, 0); ctxt.eNB_index = 0; + rrc_gNB_generate_RRCRelease(&ctxt, ue_context_p); prnt("RRC Release triggered for UE %u\n", UE->rrc_ue_id); } - return -1; + + return 0; } static telnetshell_cmddef_t rrc_cmds[] = { From 13521c681f2f63463e8368b7697351f0b3d1d921 Mon Sep 17 00:00:00 2001 From: Xin Zhe Khooi Date: Sun, 18 Feb 2024 03:24:10 +0000 Subject: [PATCH 04/39] telnetsrv_rrc: update documentation --- common/utils/telnetsrv/telnetsrv_rrc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/utils/telnetsrv/telnetsrv_rrc.c b/common/utils/telnetsrv/telnetsrv_rrc.c index 464fb99853..b7ded95802 100644 --- a/common/utils/telnetsrv/telnetsrv_rrc.c +++ b/common/utils/telnetsrv/telnetsrv_rrc.c @@ -37,7 +37,7 @@ /** * Module brief: * This module is used to add RRCRelease commands to the telnet server in the - * absence of full support for E2SM RAN Control (RC) function in the RIC. + * absence of full support for E2SM RAN Control (RC). * This provides similar functionality to the ORAN.WG3.E2SM-RC-R003-v05.00 * 8.4.5.4 RRC Connection Release Control which is initiated by the RIC. * From 7ca22db7d25de732f1a97597ebb8655d2cfa6df5 Mon Sep 17 00:00:00 2001 From: Xin Zhe Khooi Date: Sun, 18 Feb 2024 03:29:31 +0000 Subject: [PATCH 05/39] telnetsrv_rrc: update documentation on building and usage --- common/utils/telnetsrv/telnetsrv_rrc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/common/utils/telnetsrv/telnetsrv_rrc.c b/common/utils/telnetsrv/telnetsrv_rrc.c index b7ded95802..aab85a825f 100644 --- a/common/utils/telnetsrv/telnetsrv_rrc.c +++ b/common/utils/telnetsrv/telnetsrv_rrc.c @@ -44,6 +44,12 @@ * Implementation notes: * We refer to the method call rrc_gNB_generate_RRCRelease at rrc_gNB_NGAP.c * during rrc_gNB_process_NGAP_UE_CONTEXT_RELEASE_COMMAND message generation. + * + * Building the telnetsrv and module: + * ./build_oai --build-lib telnetsrv + * + * Loading the module: + * sudo ./nr-softmodem --sa -E --rfsim --log_config.global_log_options level,nocolor,time -O ~/gnb.sa.band78.106prb.rfsim.conf --telnetsrv --telnetsrv.shrmod rrc */ static int get_single_ue_id(void) From 3ecd2e6b624377a77cae88bffcc2bc3bd8845d23 Mon Sep 17 00:00:00 2001 From: Romain Beurdouche Date: Mon, 26 Feb 2024 16:04:25 +0100 Subject: [PATCH 06/39] fix(doc): add ptp4l service configuration file in 7.2 documentation --- doc/ORAN_FHI7.2_Tutorial.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/ORAN_FHI7.2_Tutorial.md b/doc/ORAN_FHI7.2_Tutorial.md index 3c3e9e61b4..ef2937c378 100644 --- a/doc/ORAN_FHI7.2_Tutorial.md +++ b/doc/ORAN_FHI7.2_Tutorial.md @@ -203,6 +203,12 @@ hybrid_e2e 0 ``` Probably you need to increase `tx_timestamp_timeout` to 50 or 100 for Intel E-810. You will see that in the logs of ptp. +Create the configuration file for ptp4l (`/etc/sysconfig/ptp4l`) + +``` +OPTIONS="-f /etc/ptp4l.conf" +``` + Create the configuration file for phc2sys (`/etc/sysconfig/phc2sys`) ``` From 819455d375a3a53d9546b335f6966ee97423a8b8 Mon Sep 17 00:00:00 2001 From: Romain Beurdouche Date: Mon, 4 Mar 2024 14:50:16 +0100 Subject: [PATCH 07/39] fix(doc): FHI 7.2, add core in our environment for system core --- doc/ORAN_FHI7.2_Tutorial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ORAN_FHI7.2_Tutorial.md b/doc/ORAN_FHI7.2_Tutorial.md index ef2937c378..33695dd387 100644 --- a/doc/ORAN_FHI7.2_Tutorial.md +++ b/doc/ORAN_FHI7.2_Tutorial.md @@ -634,7 +634,7 @@ Edit the sample OAI gNB configuration file and check following parameters: that is employed by the xRAN library (`xran_fh_init` and `xran_fh_config` structs in the code): * `dpdk_devices`: PCI addresses of NIC VFs binded to the DPDK (not the physical NIC but the VFs, use `lspci | grep Virtual`) - * `system_core`: absolute CPU core ID for DPDK control threads + * `system_core`: absolute CPU core ID for DPDK control threads, it should be an isolated core, in our environment we are using CPU 0 (`rte_mp_handle`, `eal-intr-thread`, `iavf-event-thread`) * `io_core`: absolute CPU core ID for XRAN library, it should be an isolated core, in our environment we are using CPU 4 * `worker_cores`: array of absolute CPU core IDs for XRAN library, they should be isolated cores, in our environment we are using CPU 2 From 1fa6be2a3d7db56061c5b0317546fcc645293504 Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 5 Mar 2024 19:03:21 +0100 Subject: [PATCH 08/39] fix procedure after T300 expiry --- executables/nr-ue.c | 2 +- .../PHY/NR_UE_TRANSPORT/nr_initial_sync.c | 20 +++++++++---------- openair2/LAYER2/NR_MAC_UE/config_ue.c | 1 - openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c | 12 +++++------ openair2/RRC/NR/MESSAGES/asn1_msg.h | 2 -- openair2/RRC/NR_UE/rrc_UE.c | 7 +++++-- openair2/RRC/NR_UE/rrc_defs.h | 2 +- 7 files changed, 22 insertions(+), 24 deletions(-) diff --git a/executables/nr-ue.c b/executables/nr-ue.c index c93cb1064b..a03b1afe78 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -538,7 +538,7 @@ void processSlotTX(void *arg) { nr_rxtx_thread_data_t *rxtxD = (nr_rxtx_thread_data_t *) arg; const UE_nr_rxtx_proc_t *proc = &rxtxD->proc; - PHY_VARS_NR_UE *UE = rxtxD->UE; + PHY_VARS_NR_UE *UE = rxtxD->UE; nr_phy_data_tx_t phy_data = {0}; if (UE->if_inst) diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c b/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c index 52fc2569bb..5873384a10 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c @@ -105,8 +105,7 @@ int nr_pbch_detection(const UE_nr_rxtx_proc_t *proc, int pbch_initial_symbol, c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP]) { - NR_DL_FRAME_PARMS *frame_parms=&ue->frame_parms; - int ret =-1; + NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; NR_UE_SSB *best_ssb = NULL; NR_UE_SSB *current_ssb; @@ -138,8 +137,9 @@ int nr_pbch_detection(const UE_nr_rxtx_proc_t *proc, } } - NR_UE_SSB *temp_ptr=best_ssb; - while (ret!=0 && temp_ptr != NULL) { + NR_UE_SSB *temp_ptr = best_ssb; + int ret = -1; + while (ret != 0 && temp_ptr != NULL) { start_meas(&ue->dlsch_channel_estimation_stats); // computing channel estimation for selected best ssb @@ -165,14 +165,10 @@ int nr_pbch_detection(const UE_nr_rxtx_proc_t *proc, free_list(best_ssb); - if (ret == 0) + if (ret == 0) { frame_parms->nb_antenna_ports_gNB = 1; // pbch_tx_ant; - - // set initial transmission mode to 1 or 2 depending on number of detected TX antennas - // frame_parms->mode1_flag = (pbch_tx_ant==1); - // openair_daq_vars.dlsch_transmission_mode = (pbch_tx_ant>1) ? 2 : 1; - - LOG_I(PHY, "[UE%d] Initial sync: pbch decoded sucessfully, ssb index %d\n", ue->Mod_id, frame_parms->ssb_index); + LOG_I(PHY, "[UE%d] Initial sync: pbch decoded sucessfully, ssb index %d\n", ue->Mod_id, frame_parms->ssb_index); + } return ret; } @@ -429,6 +425,8 @@ nr_initial_sync_t nr_initial_sync(UE_nr_rxtx_proc_t *proc, PHY_VARS_NR_UE *ue, i #ifdef DEBUG_INITIAL_SYNCH LOG_I(PHY, "[UE%d] Initial sync : Estimated power: %d dB\n", ue->Mod_id, ue->measurements.rx_power_avg_dB[0]); #endif + } else { + LOG_A(PHY, "Initial sync successful\n"); } // exit_fun("debug exit"); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_INITIAL_UE_SYNC, VCD_FUNCTION_OUT); diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index ef5df5beb9..0282b3489f 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -1358,7 +1358,6 @@ void nr_rrc_mac_config_req_reset(module_id_t module_id, NR_UE_MAC_reset_cause_t cause) { NR_UE_MAC_INST_t *mac = get_mac_inst(module_id); - switch (cause) { case GO_TO_IDLE: reset_ra(&mac->ra); diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c index e6013fdc37..526a406d9c 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c @@ -86,26 +86,26 @@ void init_RA(NR_UE_MAC_INST_t *mac, if (rach_ConfigDedicated) { if (rach_ConfigDedicated->cfra){ - LOG_I(MAC, "Initialization of 2-step contention-free random access procedure\n"); + LOG_I(NR_MAC, "Initialization of 2-step contention-free random access procedure\n"); prach_resources->RA_TYPE = RA_2STEP; ra->cfra = 1; } else if (rach_ConfigDedicated->ext1){ if (rach_ConfigDedicated->ext1->cfra_TwoStep_r16){ - LOG_I(MAC, "Setting RA type to 2-step...\n"); + LOG_I(NR_MAC, "Setting RA type to 2-step...\n"); prach_resources->RA_TYPE = RA_2STEP; ra->cfra = 1; } else { - LOG_E(MAC, "Config not handled\n"); + LOG_E(NR_MAC, "Config not handled\n"); } } else { - LOG_E(MAC, "Config not handled\n"); + LOG_E(NR_MAC, "Config not handled\n"); } } else if (nr_rach_ConfigCommon){ - LOG_I(MAC, "Initialization of 4-step contention-based random access procedure\n"); + LOG_I(NR_MAC, "Initialization of 4-step contention-based random access procedure\n"); prach_resources->RA_TYPE = RA_4STEP; ra->cfra = 0; } else { - LOG_E(MAC, "Config not handled\n"); + LOG_E(NR_MAC, "Config not handled\n"); } switch (rach_ConfigGeneric->powerRampingStep){ // in dB diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.h b/openair2/RRC/NR/MESSAGES/asn1_msg.h index de57a339d5..99fb0efda4 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.h +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.h @@ -41,10 +41,8 @@ #include -#include "RRC/NR/nr_rrc_defs.h" #include "RRC/NR/nr_rrc_config.h" - /* * The variant of the above function which dumps the BASIC-XER (XER_F_BASIC) * output into the chosen string buffer. diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index a2056e5be7..23da4916e0 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -616,7 +616,7 @@ static void nr_rrc_handle_msg3_indication(NR_UE_RRC_INST_t *rrc, rnti_t rnti) { NR_UE_Timers_Constants_t *tac = &rrc->timers_and_constants; switch (rrc->ra_trigger) { - case INITIAL_ACCESS_FROM_RRC_IDLE: + case RRC_CONNECTION_SETUP: // After SIB1 is received, prepare RRCConnectionRequest rrc->rnti = rnti; // start timer T300 @@ -744,7 +744,7 @@ static int8_t nr_rrc_ue_decode_NR_BCCH_DL_SCH_Message(NR_UE_RRC_INST_t *rrc, LOG_A(NR_RRC, "SIB1 decoded\n"); nr_timer_start(&SI_info->sib1_timer); if (rrc->nrRrcState == RRC_STATE_IDLE_NR) { - rrc->ra_trigger = INITIAL_ACCESS_FROM_RRC_IDLE; + rrc->ra_trigger = RRC_CONNECTION_SETUP; // preparing RRC setup request payload in advance nr_rrc_ue_prepare_RRCSetupRequest(rrc); } @@ -2221,6 +2221,9 @@ void nr_rrc_going_to_IDLE(NR_UE_RRC_INST_t *rrc, void handle_t300_expiry(NR_UE_RRC_INST_t *rrc) { + rrc->ra_trigger = RRC_CONNECTION_SETUP; + nr_rrc_ue_prepare_RRCSetupRequest(rrc); + // reset MAC, release the MAC configuration NR_UE_MAC_reset_cause_t cause = T300_EXPIRY; nr_rrc_mac_config_req_reset(rrc->ue_id, cause); diff --git a/openair2/RRC/NR_UE/rrc_defs.h b/openair2/RRC/NR_UE/rrc_defs.h index 936247f655..621eec6443 100644 --- a/openair2/RRC/NR_UE/rrc_defs.h +++ b/openair2/RRC/NR_UE/rrc_defs.h @@ -105,7 +105,7 @@ typedef enum requested_SI_List_e { // 3GPP TS 38.300 Section 9.2.6 typedef enum RA_trigger_e { RA_NOT_RUNNING, - INITIAL_ACCESS_FROM_RRC_IDLE, + RRC_CONNECTION_SETUP, RRC_CONNECTION_REESTABLISHMENT, DURING_HANDOVER, NON_SYNCHRONISED, From ee3dcc5c77ca3f0a8271d97c110549ca1e7456fc Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 13 Mar 2024 14:34:44 +0100 Subject: [PATCH 09/39] replacing cell_notdetected with cell_detected in initial_sync structure --- executables/nr-ue.c | 2 +- .../PHY/NR_UE_TRANSPORT/nr_initial_sync.c | 45 +++++++++++-------- .../NR_UE_TRANSPORT/nr_transport_proto_ue.h | 2 +- openair1/SIMULATION/NR_PHY/pbchsim.c | 8 ++-- 4 files changed, 32 insertions(+), 25 deletions(-) diff --git a/executables/nr-ue.c b/executables/nr-ue.c index a03b1afe78..4d29d5f8e2 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -440,7 +440,7 @@ static void UE_synch(void *arg) { uint64_t dl_carrier, ul_carrier; nr_get_carrier_frequencies(UE, &dl_carrier, &ul_carrier); nr_initial_sync_t ret = nr_initial_sync(&syncD->proc, UE, 2, get_softmodem_params()->sa); - if (!ret.cell_notdetected) { + if (ret.cell_detected) { syncD->rx_offset = ret.rx_offset; freq_offset = UE->common_vars.freq_offset; // frequency offset computed with pss in initial sync hw_slot_offset = diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c b/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c index 5873384a10..09ea85fbd4 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c @@ -100,10 +100,10 @@ void free_list(NR_UE_SSB *node) { free(node); } -int nr_pbch_detection(const UE_nr_rxtx_proc_t *proc, - PHY_VARS_NR_UE *ue, - int pbch_initial_symbol, - c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP]) +static bool nr_pbch_detection(const UE_nr_rxtx_proc_t *proc, + PHY_VARS_NR_UE *ue, + int pbch_initial_symbol, + c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP]) { NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; @@ -138,8 +138,8 @@ int nr_pbch_detection(const UE_nr_rxtx_proc_t *proc, } NR_UE_SSB *temp_ptr = best_ssb; - int ret = -1; - while (ret != 0 && temp_ptr != NULL) { + bool ret = false; + while (!ret && temp_ptr != NULL) { start_meas(&ue->dlsch_channel_estimation_stats); // computing channel estimation for selected best ssb @@ -153,11 +153,18 @@ int nr_pbch_detection(const UE_nr_rxtx_proc_t *proc, stop_meas(&ue->dlsch_channel_estimation_stats); fapiPbch_t result = {0}; - ret = nr_rx_pbch(ue, proc, estimateSz, dl_ch_estimates, frame_parms, temp_ptr->i_ssb, &result, rxdataF); - if (DUMP_PBCH_CH_ESTIMATES && (ret == 0)) { + int pbch_res = nr_rx_pbch(ue, proc, estimateSz, dl_ch_estimates, frame_parms, temp_ptr->i_ssb, &result, rxdataF); + ret = pbch_res == 0; + + if (DUMP_PBCH_CH_ESTIMATES && ret) { write_output("pbch_ch_estimates.m", "pbch_ch_estimates", dl_ch_estimates, frame_parms->nb_antennas_rx*estimateSz, 1, 1); - write_output("pbch_ch_estimates_time.m", "pbch_ch_estimates_time", dl_ch_estimates_time, frame_parms->nb_antennas_rx*frame_parms->ofdm_symbol_size, 1, 1); + write_output("pbch_ch_estimates_time.m", + "pbch_ch_estimates_time", + dl_ch_estimates_time, + frame_parms->nb_antennas_rx * frame_parms->ofdm_symbol_size, + 1, + 1); } temp_ptr=temp_ptr->next_ssb; @@ -165,7 +172,7 @@ int nr_pbch_detection(const UE_nr_rxtx_proc_t *proc, free_list(best_ssb); - if (ret == 0) { + if (ret) { frame_parms->nb_antenna_ports_gNB = 1; // pbch_tx_ant; LOG_I(PHY, "[UE%d] Initial sync: pbch decoded sucessfully, ssb index %d\n", ue->Mod_id, frame_parms->ssb_index); } @@ -258,7 +265,7 @@ nr_initial_sync_t nr_initial_sync(UE_nr_rxtx_proc_t *proc, PHY_VARS_NR_UE *ue, i int freq_offset_sss = 0; bool ret_sss = rx_sss_nr(ue, proc, &metric_tdd_ncp, &phase_tdd_ncp, &freq_offset_sss, rxdataF); - ret.cell_notdetected = !ret_sss; // rx_sss_nr returns true if success + ret.cell_detected = ret_sss; // rx_sss_nr returns true if success // digital compensation of FFO for SSB symbols if (ue->UE_fo_compensation) { double s_time = 1 / (1.0e3 * fp->samples_per_subframe); // sampling time @@ -278,12 +285,12 @@ nr_initial_sync_t nr_initial_sync(UE_nr_rxtx_proc_t *proc, PHY_VARS_NR_UE *ue, i ue->common_vars.freq_offset += freq_offset_sss; } - if (ret.cell_notdetected == 0) { // we got sss channel + if (ret.cell_detected) { // we got sss channel nr_gold_pbch(ue); - ret.cell_notdetected = nr_pbch_detection(proc, ue, 1, rxdataF); // start pbch detection at first symbol after pss + ret.cell_detected = nr_pbch_detection(proc, ue, 1, rxdataF); // start pbch detection at first symbol after pss } - if (ret.cell_notdetected == 0) { + if (ret.cell_detected) { // sync at symbol ue->symbol_offset // computing the offset wrt the beginning of the frame int mu = fp->numerology_index; @@ -343,7 +350,7 @@ nr_initial_sync_t nr_initial_sync(UE_nr_rxtx_proc_t *proc, PHY_VARS_NR_UE *ue, i fp->Nid_cell, metric_tdd_ncp, phase_tdd_ncp, - !ret.cell_notdetected, + ret.cell_detected, ret.rx_offset); #endif @@ -352,11 +359,11 @@ nr_initial_sync_t nr_initial_sync(UE_nr_rxtx_proc_t *proc, PHY_VARS_NR_UE *ue, i LOG_I(PHY, "TDD Normal prefix: SSS error condition: sync_pos %d\n", sync_pos); #endif } - if (ret.cell_notdetected == 0) + if (ret.cell_detected) break; } } else { - ret.cell_notdetected = true; + ret.cell_detected = false; } /* Consider this is a false detection if the offset is > 1000 Hz @@ -367,7 +374,7 @@ nr_initial_sync_t nr_initial_sync(UE_nr_rxtx_proc_t *proc, PHY_VARS_NR_UE *ue, i LOG_E(HW, "Ignore MIB with high freq offset [%d Hz] estimation \n",ue->common_vars.freq_offset); }*/ - if (ret.cell_notdetected == 0) { // PBCH found so indicate sync to higher layers and configure frame parameters + if (ret.cell_detected) { // PBCH found so indicate sync to higher layers and configure frame parameters //#ifdef DEBUG_INITIAL_SYNCH @@ -402,7 +409,7 @@ nr_initial_sync_t nr_initial_sync(UE_nr_rxtx_proc_t *proc, PHY_VARS_NR_UE *ue, i } // gain control - if (ret.cell_notdetected != 0) { // we are not synched, so we cannot use rssi measurement (which is based on channel estimates) + if (!ret.cell_detected) { // we are not synched, so we cannot use rssi measurement (which is based on channel estimates) int rx_power = 0; // do a measurement on the best guess of the PSS diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h index 6e37549349..c58fd5888e 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h @@ -319,7 +319,7 @@ int dump_ue_stats(PHY_VARS_NR_UE *phy_vars_ue, @param sa current running mode */ typedef struct { - bool cell_notdetected; + bool cell_detected; int rx_offset; } nr_initial_sync_t; nr_initial_sync_t nr_initial_sync(UE_nr_rxtx_proc_t *proc, PHY_VARS_NR_UE *phy_vars_ue, int n_frames, int sa); diff --git a/openair1/SIMULATION/NR_PHY/pbchsim.c b/openair1/SIMULATION/NR_PHY/pbchsim.c index 7d738c4ed7..b79f438e17 100644 --- a/openair1/SIMULATION/NR_PHY/pbchsim.c +++ b/openair1/SIMULATION/NR_PHY/pbchsim.c @@ -766,10 +766,10 @@ int main(int argc, char **argv) } if (UE->is_synchronized == 0) { UE_nr_rxtx_proc_t proc={0}; - nr_initial_sync_t ret = nr_initial_sync(&proc, UE, 1, 0); - printf("nr_initial_sync1 returns %d\n", ret.cell_notdetected); - if (ret.cell_notdetected) - n_errors++; + nr_initial_sync_t ret = nr_initial_sync(&proc, UE, 1, 0); + printf("nr_initial_sync1 returns %s\n", ret.cell_detected ? "cell detected" : "cell not detected"); + if (!ret.cell_detected) + n_errors++; } else { UE_nr_rxtx_proc_t proc={0}; From 8a65ca93fc689e054a22a3a512058ed560bc3c3e Mon Sep 17 00:00:00 2001 From: Romain Beurdouche Date: Tue, 19 Mar 2024 08:45:37 +0100 Subject: [PATCH 10/39] fix(doc): fhi7.2: experience return from Christ --- doc/ORAN_FHI7.2_Tutorial.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/ORAN_FHI7.2_Tutorial.md b/doc/ORAN_FHI7.2_Tutorial.md index 33695dd387..66ff0df93c 100644 --- a/doc/ORAN_FHI7.2_Tutorial.md +++ b/doc/ORAN_FHI7.2_Tutorial.md @@ -379,6 +379,7 @@ git checkout oran_e_maintenance_release_v1.0 Apply the patch (available in `oai_folder/cmake_targets/tools/oran_fhi_integration_patches/E`): ```bash +cd ~/phy git apply ~/openairinterface5g/cmake_targets/tools/oran_fhi_integration_patches/E/oaioran_E.patch ``` From 513f56e215743f514c1e7ceccf5ddb9a2d702fed Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 19 Mar 2024 15:26:49 +0100 Subject: [PATCH 11/39] One RFsimulator end, close open connections Use the correct function in order to close open RFsim connections, instead of a simple close(). If this is not done correctly, it might happen that the softmodem closes, but an L1 thread might still read samples (bug in higher layers). Then, RFsim tries to read a socket (because it has an open connection), but the actual connection had been close()d. This commit fixes this behavior. --- radio/rfsimulator/simulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/rfsimulator/simulator.c b/radio/rfsimulator/simulator.c index 0bfc26b10b..62d08da212 100644 --- a/radio/rfsimulator/simulator.c +++ b/radio/rfsimulator/simulator.c @@ -1038,7 +1038,7 @@ static void rfsimulator_end(openair0_device *device) { for (int i = 0; i < MAX_FD_RFSIMU; i++) { buffer_t *b = &s->buf[i]; if (b->conn_sock >= 0 ) - close(b->conn_sock); + removeCirBuf(s, b->conn_sock); } close(s->epollfd); } From ab2a08fd43f226269ad0dc9a084c7be48c89695c Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 19 Mar 2024 16:07:58 +0100 Subject: [PATCH 12/39] functions to map LCID to structures in the UE MAC --- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 119 ++++++++++++-------- 1 file changed, 71 insertions(+), 48 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index e9b188cfba..4bd1e29ca9 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -91,6 +91,30 @@ fapi_nr_ul_config_request_pdu_t *lockGet_ul_config(NR_UE_MAC_INST_t *mac, frame_ return pdu; } +static nr_lcordered_info_t *get_lc_info_from_lcid(NR_UE_MAC_INST_t *mac, NR_LogicalChannelIdentity_t lcid) +{ + nr_lcordered_info_t *lc_info = NULL; + for (int i = 0; i < mac->lc_ordered_list.count; i++) { + if (mac->lc_ordered_list.array[i]->lcid == lcid) { + lc_info = mac->lc_ordered_list.array[i]; + break; + } + } + return lc_info; +} + +static int lcid_buffer_index(NR_LogicalChannelIdentity_t lcid) +{ + AssertFatal(lcid > 0 && lcid <= NR_MAX_NUM_LCID, "Invalid LCID %ld\n", lcid); + return lcid - 1; +} + +static NR_LC_SCHEDULING_INFO *get_scheduling_info_from_lcid(NR_UE_MAC_INST_t *mac, NR_LogicalChannelIdentity_t lcid) +{ + int idx = lcid_buffer_index(lcid); + return &mac->scheduling_info.lc_sched_info[idx]; +} + void update_mac_timers(NR_UE_MAC_INST_t *mac) { nr_timer_tick(&mac->ra.contention_resolution_timer); @@ -1133,14 +1157,15 @@ void nr_ue_ul_scheduler(NR_UE_MAC_INST_t *mac, nr_uplink_indication_t *ul_info) measure Bj increment the value of Bj by product PBR * T */ + NR_LC_SCHEDULING_INFO *sched_info = get_scheduling_info_from_lcid(mac, lcid); int T = 1; // time elapsed since Bj was last incremented - int32_t bj = mac->scheduling_info.lc_sched_info[lcid - 1].Bj; + int32_t bj = sched_info->Bj; bj += nr_get_pbr(lc_info->prioritisedBitRate) * T; if (lc_info->prioritisedBitRate == NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity) bj = nr_get_pbr(lc_info->prioritisedBitRate); // bj > max bucket size, set bj to max bucket size, as in ts38.321 5.4.3.1 Logical Channel Prioritization - mac->scheduling_info.lc_sched_info[lcid - 1].Bj = min(bj, bucketSize_max); + sched_info->Bj = min(bj, bucketSize_max); } // Call BSR procedure as described in Section 5.4.5 in 38.321 @@ -1188,13 +1213,11 @@ bool nr_update_bsr(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t slotP, uint8_t //uint8_t highest_priority = 16; uint8_t array_index = 0; // Reset All BSR Infos - lcid_bytes_in_buffer[0] = 0; - // TO BE NOTED LCID = 0 is excluded from buffers - // so they need to be addressed with lcid - 1 for (int lcid = 1; lcid <= NR_MAX_NUM_LCID; lcid++) { // Reset transmission status - lcid_bytes_in_buffer[lcid - 1] = 0; - mac->scheduling_info.lc_sched_info[lcid - 1].LCID_buffer_with_data = false; + int idx = lcid_buffer_index(lcid); + lcid_bytes_in_buffer[idx] = 0; + mac->scheduling_info.lc_sched_info[idx].LCID_buffer_with_data = false; } for (int lcgid = 0; lcgid < NR_MAX_NUM_LCGID; lcgid++) { @@ -1206,11 +1229,12 @@ bool nr_update_bsr(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t slotP, uint8_t //Get Buffer Occupancy and fill lcid_reordered_array for (int i = 0; i < mac->lc_ordered_list.count; i++) { int lcid = mac->lc_ordered_list.array[i]->lcid; - int lcgid = mac->scheduling_info.lc_sched_info[lcid - 1].LCGID; + NR_LC_SCHEDULING_INFO *sched_info = get_scheduling_info_from_lcid(mac, lcid); + int lcgid = sched_info->LCGID; // Store already available data to transmit per Group if (lcgid < NR_MAX_NUM_LCGID) { - lcgid_buffer_remain[lcgid] += mac->scheduling_info.lc_sched_info[lcid - 1].LCID_buffer_remain; + lcgid_buffer_remain[lcgid] += sched_info->LCID_buffer_remain; } mac_rlc_status_resp_t rlc_status = mac_rlc_status_ind(mac->ue_id, @@ -1224,7 +1248,8 @@ bool nr_update_bsr(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t slotP, uint8_t 0, 0); - lcid_bytes_in_buffer[lcid - 1] = rlc_status.bytes_in_buffer; + int lc_idx = lcid_buffer_index(lcid); + lcid_bytes_in_buffer[lc_idx] = rlc_status.bytes_in_buffer; if (rlc_status.bytes_in_buffer > 0) { LOG_D(NR_MAC, @@ -1235,7 +1260,7 @@ bool nr_update_bsr(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t slotP, uint8_t rlc_status.bytes_in_buffer, frameP, slotP); - mac->scheduling_info.lc_sched_info[lcid - 1].LCID_buffer_with_data = true; + sched_info->LCID_buffer_with_data = true; //Update BSR_bytes and position in lcid_reordered_array only if Group is defined if (lcgid < NR_MAX_NUM_LCGID) { @@ -1276,7 +1301,7 @@ bool nr_update_bsr(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t slotP, uint8_t for (array_index = 0; array_index < num_lcid_with_data; array_index++) { int lcid = lcid_reordered_array[array_index]; - + NR_LC_SCHEDULING_INFO *sched_info = get_scheduling_info_from_lcid(mac, lcid); /* UL data, for a logical channel which belongs to a LCG, becomes available for transmission in the RLC entity either the data belongs to a logical channel with higher priority than the priorities of the logical channels which belong to any LCG and for which data is already available for transmission @@ -1287,7 +1312,7 @@ bool nr_update_bsr(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t slotP, uint8_t "[UE %d] PDCCH Tick : MAC BSR Triggered LCID%d LCGID%ld data become available at frame %d slot %d\n", mac->ue_id, lcid, - mac->scheduling_info.lc_sched_info[lcid - 1].LCGID, + sched_info->LCGID, frameP, slotP); break; @@ -1306,7 +1331,8 @@ bool nr_update_bsr(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t slotP, uint8_t //Store Buffer Occupancy in remain buffers for next TTI for (int lcid = 1; lcid <= NR_MAX_NUM_LCID; lcid++) { - mac->scheduling_info.lc_sched_info[lcid - 1].LCID_buffer_remain = lcid_bytes_in_buffer[lcid - 1]; + NR_LC_SCHEDULING_INFO *sched_info = get_scheduling_info_from_lcid(mac, lcid); + sched_info->LCID_buffer_remain = lcid_bytes_in_buffer[lcid_buffer_index(lcid)]; } return bsr_regular_triggered; @@ -2722,7 +2748,8 @@ static void nr_ue_get_sdu_mac_ce_post(NR_UE_MAC_INST_t *mac, // REPORT SHORT TRUNCATED BSR // Get LCGID of highest priority LCID with data (todo) for (int lcid = 1; lcid <= NR_MAX_NUM_LCID; lcid++) { - lcg_id = mac->scheduling_info.lc_sched_info[lcid - 1].LCGID; + NR_LC_SCHEDULING_INFO *sched_info = get_scheduling_info_from_lcid(mac, lcid); + lcg_id = sched_info->LCGID; if ((lcg_id < NR_MAX_NUM_LCGID) && (mac->scheduling_info.lcg_sched_info[lcg_id].BSR_bytes)) { lcg_id_bsr_trunc = lcg_id; } @@ -2854,16 +2881,11 @@ long get_num_bytes_to_reqlc(NR_UE_MAC_INST_t *mac, long *target) { /* Calculates the number of bytes the logical channel should request from the correcponding RLC buffer*/ - long found_pbr = -1; - for (int i = 0; i < mac->lc_ordered_list.count; i++) { - if (mac->lc_ordered_list.array[i]->lcid == lc_num) { - found_pbr = mac->lc_ordered_list.array[i]->prioritisedBitRate; - break; - } - } - AssertFatal(found_pbr >= 0, "Couldn't find LC config for ID %d\n", lc_num); - uint32_t pbr = nr_get_pbr(found_pbr); - int32_t lcid_remain_buffer = mac->scheduling_info.lc_sched_info[lc_num - 1].LCID_buffer_remain; + nr_lcordered_info_t *lc_info = get_lc_info_from_lcid(mac, lc_num); + AssertFatal(lc_info, "Couldn't find logical channel with LCID %d\n", lc_num); + uint32_t pbr = nr_get_pbr(lc_info->prioritisedBitRate); + NR_LC_SCHEDULING_INFO *sched_info = get_scheduling_info_from_lcid(mac, lc_num); + int32_t lcid_remain_buffer = sched_info->LCID_buffer_remain; *target = (same_priority_count > 1) ? min(buflen_remain_ep, pbr) : pbr; long num_remaining_bytes = 0; @@ -2893,7 +2915,7 @@ bool get_dataavailability_buffers(uint8_t total_active_lcids, nr_lcordered_info_ // check whether there is any data in the rlc buffer corresponding to active lcs for (uint8_t id = 0; id < total_active_lcids; id++) { int lcid = lcid_ordered_array[id].lcid; - if (data_status_lcbuffers[lcid - 1]) { + if (data_status_lcbuffers[lcid_buffer_index(lcid)]) { return true; } } @@ -2908,7 +2930,8 @@ static void select_logical_channels(NR_UE_MAC_INST_t *mac, int *num_active_lcids // selection of logical channels with Bj > 0 for (int i = 0; i < mac->lc_ordered_list.count; i++) { int lcid = mac->lc_ordered_list.array[i]->lcid; - if (mac->scheduling_info.lc_sched_info[lcid - 1].Bj > 0) { + NR_LC_SCHEDULING_INFO *sched_info = get_scheduling_info_from_lcid(mac, lcid); + if (sched_info->Bj > 0) { active_lcids[*num_active_lcids] = *mac->lc_ordered_list.array[i]; (*num_active_lcids)++; LOG_D(NR_MAC, "The available lcid is %d with total active channels count = %d\n", lcid, *num_active_lcids); @@ -2933,11 +2956,11 @@ static bool fill_mac_sdu(NR_UE_MAC_INST_t *mac, bool *lcids_data_status, uint8_t *num_lcids_same_priority) { - NR_UE_SCHEDULING_INFO *sched_info = &mac->scheduling_info; const uint8_t sh_size = sizeof(NR_MAC_SUBHEADER_LONG); /* prepare the MAC sdu */ - int32_t lcid_remain_buffer = sched_info->lc_sched_info[lcid - 1].LCID_buffer_remain; + NR_LC_SCHEDULING_INFO *sched_info = get_scheduling_info_from_lcid(mac, lcid); + int32_t lcid_remain_buffer = sched_info->LCID_buffer_remain; LOG_D(NR_MAC, "[UE %d] [%d.%d] lcp round = %d, remaining mac pdu length = %d, lcid buffer remaining = %d, lcid = %d \n", mac->ue_id, @@ -2980,14 +3003,15 @@ static bool fill_mac_sdu(NR_UE_MAC_INST_t *mac, // currently the Bj is drecremented by size of MAC SDus everytime it is served to logical channel, so by this approach there // will be more chance for lower priority logical channels to be served in the next TTI // second approach can also be followed where Bj is decremented only in the first round but not in the subsequent rounds - sched_info->lc_sched_info[lcid - 1].Bj -= sdu_length; // TODO avoid Bj to go below 0 + sched_info->Bj -= sdu_length; // TODO avoid Bj to go below 0 LOG_D(NR_MAC, "decrement Bj of the lcid %d by size of sdu length = %d and new Bj for lcid %d is %d\n", lcid, sdu_length, lcid, - sched_info->lc_sched_info[lcid - 1].Bj); + sched_info->Bj); + int lc_idx = lcid_buffer_index(lcid); if (sdu_length > 0) { LOG_D(NR_MAC, "[UE %d] [%d.%d] UL-DXCH -> ULSCH, Generating UL MAC sub-PDU for SDU %d, length %d bytes, RB with LCID " @@ -3019,7 +3043,7 @@ static bool fill_mac_sdu(NR_UE_MAC_INST_t *mac, (*num_sdus)++; } else { *pdu -= sh_size; - lcids_data_status[lcid - 1] = false; + lcids_data_status[lc_idx] = false; (*num_lcids_same_priority)--; LOG_D(NR_MAC, "No data to transmit for RB with LCID 0x%02x\n and hence set to false", lcid); return 0; @@ -3028,31 +3052,30 @@ static bool fill_mac_sdu(NR_UE_MAC_INST_t *mac, *buflen_remain = buflen - (mac_ce_p->total_mac_pdu_header_len + mac_ce_p->sdu_length_total + sh_size); // Update Buffer remain and BSR bytes after transmission - NR_LC_SCHEDULING_INFO *lc_info = &sched_info->lc_sched_info[0] + lcid - 1; - NR_LCG_SCHEDULING_INFO *lcg_info = &sched_info->lcg_sched_info[0]; - lc_info->LCID_buffer_remain -= sdu_length; - (lcg_info + lc_info->LCGID)->BSR_bytes -= sdu_length; + NR_LCG_SCHEDULING_INFO *lcg_info = &mac->scheduling_info.lcg_sched_info[0]; + sched_info->LCID_buffer_remain -= sdu_length; + (lcg_info + sched_info->LCGID)->BSR_bytes -= sdu_length; LOG_D(NR_MAC, "[UE %d] Update BSR [%d.%d] BSR_bytes for LCG%ld = %d\n", mac->ue_id, frameP, subframe, - lc_info->LCGID, - (lcg_info + lc_info->LCGID)->BSR_bytes); - if ((lcg_info + lc_info->LCGID)->BSR_bytes < 0) - (lcg_info + lc_info->LCGID)->BSR_bytes = 0; + sched_info->LCGID, + (lcg_info + sched_info->LCGID)->BSR_bytes); + if ((lcg_info + sched_info->LCGID)->BSR_bytes < 0) + (lcg_info + sched_info->LCGID)->BSR_bytes = 0; // update number of bytes served from the current lcid - lcids_bytes_tot[lcid - 1] += (sdu_length + (count_same_priority_lcids > 1 ? 1 : 0) * sh_size); + lcids_bytes_tot[lc_idx] += (sdu_length + (count_same_priority_lcids > 1 ? 1 : 0) * sh_size); - if ((*counter == 0 && lcids_bytes_tot[lcid - 1] >= target) + if ((*counter == 0 && lcids_bytes_tot[lc_idx] >= target) || (count_same_priority_lcids > 1 - && lcids_bytes_tot[lcid - 1] >= buflen_ep)) { // only prioritized bit rate should be taken from logical channel in + && lcids_bytes_tot[lc_idx] >= buflen_ep)) { // only prioritized bit rate should be taken from logical channel in // the first lcp run except when infinity LOG_D(NR_MAC, "Total number bytes read from rlc buffer for lcid %d are %d\n", lcid, - lcids_bytes_tot[lcid - 1]); + lcids_bytes_tot[lc_idx]); (*num_lcids_same_priority)--; return 0; } @@ -3099,7 +3122,6 @@ uint8_t nr_ue_get_sdu(NR_UE_MAC_INST_t *mac, //NR_POWER_HEADROOM_CMD phr; //mac_ce_p->phr_p = &phr; - NR_UE_SCHEDULING_INFO *sched_info = &mac->scheduling_info; //int highest_priority = 16; const uint8_t sh_size = sizeof(NR_MAC_SUBHEADER_LONG); @@ -3147,11 +3169,12 @@ uint8_t nr_ue_get_sdu(NR_UE_MAC_INST_t *mac, is placed in the MAC PDU before going on to next high priority logical channel */ int lcid = lcids_bj_pos[id].lcid; - + NR_LC_SCHEDULING_INFO *lc_sched_info = get_scheduling_info_from_lcid(mac, lcid); + int idx = lcid_buffer_index(lcid); // skip the logical channel if no data in the buffer initially or the data in the buffer was zero because it was written in to // MAC PDU - if (!sched_info->lc_sched_info[lcid - 1].LCID_buffer_with_data || !lcids_data_status[lcid - 1]) { - lcids_data_status[lcid - 1] = false; + if (!lc_sched_info->LCID_buffer_with_data || !lcids_data_status[idx]) { + lcids_data_status[idx] = false; continue; } From a47fd7fcfb46170b511bc9282c3a5e3512b8c037 Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 20 Mar 2024 10:11:09 +0100 Subject: [PATCH 13/39] fix to avoid do-ra to perform synchronization twice on attachment --- executables/nr-ue.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/executables/nr-ue.c b/executables/nr-ue.c index c93cb1064b..7ed4e592a0 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -767,7 +767,7 @@ void *UE_thread(void *arg) void *rxp[NB_ANTENNAS_RX]; int start_rx_stream = 0; fapi_nr_config_request_t *cfg = &UE->nrUE_config; - AssertFatal(0== openair0_device_load(&(UE->rfdevice), &openair0_cfg[0]), ""); + AssertFatal(0 == openair0_device_load(&(UE->rfdevice), &openair0_cfg[0]), "Could not load the device\n"); UE->rfdevice.host_type = RAU_HOST; UE->is_synchronized = 0; AssertFatal(UE->rfdevice.trx_start_func(&UE->rfdevice) == 0, "Could not start the device\n"); @@ -784,13 +784,13 @@ void *UE_thread(void *arg) int timing_advance = UE->timing_advance; NR_UE_MAC_INST_t *mac = get_mac_inst(0); - bool syncRunning=false; + bool syncRunning = false; const int nb_slot_frame = UE->frame_parms.slots_per_frame; - int absolute_slot=0, decoded_frame_rx=INT_MAX, trashed_frames=0; + int absolute_slot = 0, decoded_frame_rx = INT_MAX, trashed_frames = 0; int tx_wait_for_dlsch[NR_MAX_SLOTS_PER_FRAME]; int num_ind_fifo = nb_slot_frame; - for(int i=0; i < num_ind_fifo; i++) { + for(int i = 0; i < num_ind_fifo; i++) { initNotifiedFIFO(UE->tx_resume_ind_fifo + i); } int shiftForNextFrame = 0; @@ -801,8 +801,9 @@ void *UE_thread(void *arg) notifiedFIFO_elt_t *res=tryPullTpool(&nf,&(get_nrUE_params()->Tpool)); if (res) { - syncRunning=false; + syncRunning = false; if (UE->is_synchronized) { + UE->synch_request.received_synch_request = 0; decoded_frame_rx = mac->mib_frame; LOG_A(PHY, "UE synchronized! decoded_frame_rx=%d UE->init_sync_frame=%d trashed_frames=%d\n", @@ -815,7 +816,7 @@ void *UE_thread(void *arg) intialSyncOffset = syncMsg->rx_offset; } delNotifiedFIFO_elt(res); - start_rx_stream=0; + start_rx_stream = 0; } else { if (IS_SOFTMODEM_IQPLAYER || IS_SOFTMODEM_IQRECORDER) { // For IQ recorder-player we force synchronization to happen in 280 ms From 9e6f82399f57a14995725b64fa94b0391d291dd1 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 20 Mar 2024 15:56:19 +0100 Subject: [PATCH 14/39] Move BladeRF config to right subfolder --- .../PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.25prb.bladerf.conf | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename configuration/bladeRF/enb-band7-5mhz.conf => targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.25prb.bladerf.conf (100%) diff --git a/configuration/bladeRF/enb-band7-5mhz.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.25prb.bladerf.conf similarity index 100% rename from configuration/bladeRF/enb-band7-5mhz.conf rename to targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.25prb.bladerf.conf From 73f2c9108de4edb34c375620b0808cebfa774c82 Mon Sep 17 00:00:00 2001 From: Romain Beurdouche Date: Wed, 20 Mar 2024 16:45:54 +0100 Subject: [PATCH 15/39] fix(doc): fhi7.2: fix missing "/cmake_targets" in OAI build directory path --- doc/ORAN_FHI7.2_Tutorial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ORAN_FHI7.2_Tutorial.md b/doc/ORAN_FHI7.2_Tutorial.md index 66ff0df93c..807f26eaef 100644 --- a/doc/ORAN_FHI7.2_Tutorial.md +++ b/doc/ORAN_FHI7.2_Tutorial.md @@ -671,7 +671,7 @@ xRAN SRS reception is not supported. Run the `nr-softmodem` from the build directory: ```bash -cd ~/openairinterface5g/ran_build/build +cd ~/openairinterface5g/cmake_targets/ran_build/build sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/oran.fh.band78.fr1.273PRB.conf --sa --reorder-thread-disable 1 --thread-pool ``` From 9c4da620b9afd35e81cc035a2e9991cda6966487 Mon Sep 17 00:00:00 2001 From: Romain Beurdouche Date: Wed, 20 Mar 2024 17:07:50 +0100 Subject: [PATCH 16/39] feat(doc): fhi7.2: add Benetel 550 CAT-A RU support --- doc/ORAN_FHI7.2_Tutorial.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/doc/ORAN_FHI7.2_Tutorial.md b/doc/ORAN_FHI7.2_Tutorial.md index 807f26eaef..69094a0482 100644 --- a/doc/ORAN_FHI7.2_Tutorial.md +++ b/doc/ORAN_FHI7.2_Tutorial.md @@ -57,11 +57,12 @@ We have only verified LLS-C3 configuration in our lab, i.e. using an external grandmaster, a switch as a boundary clock, and the gNB/DU and RU. We haven't tested any RU without S-plane. Radio units we are testing/integrating: -|Vendor |Software Version | -|-----------|-----------------| -|VVDN LPRU |03-v3.0.4 | -|LiteON RU |01.00.08/02.00.03| -|Benetel 650|v0.8.1 | +|Vendor |Software Version | +|-----------------|-----------------| +|VVDN LPRU |03-v3.0.4 | +|LiteON RU |01.00.08/02.00.03| +|Benetel 650 |v0.8.1 | +|Benetel 550 CAT-A|v0.8.1 | Tested libxran releases: From 06c4f4690abacb4a0f48297c5fca06f91121c90d Mon Sep 17 00:00:00 2001 From: Romain Beurdouche Date: Wed, 20 Mar 2024 17:56:41 +0100 Subject: [PATCH 17/39] fix(doc): fhi7.2: add config file warning after nr-softmodem usage example --- doc/ORAN_FHI7.2_Tutorial.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/ORAN_FHI7.2_Tutorial.md b/doc/ORAN_FHI7.2_Tutorial.md index 69094a0482..79b8352007 100644 --- a/doc/ORAN_FHI7.2_Tutorial.md +++ b/doc/ORAN_FHI7.2_Tutorial.md @@ -676,6 +676,8 @@ cd ~/openairinterface5g/cmake_targets/ran_build/build sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/oran.fh.band78.fr1.273PRB.conf --sa --reorder-thread-disable 1 --thread-pool ``` +**Warning**: Make sure that the config file you add after the `-O` option is adapted to your machine, especially to its isolated cores. + **Note**: You may run OAI with O-RAN 7.2 Fronthaul without a RU attached (e.g. for benchmarking). In such case, you would generate artificial traffic by replacing the `--sa` option by the `--phy-test` option. From 2b37edaa3c99c9316f6f37167699a6cd05f17f8e Mon Sep 17 00:00:00 2001 From: vijay chadachan Date: Mon, 18 Mar 2024 12:47:30 +0100 Subject: [PATCH 18/39] Additional memory allocation for MAC stats logging to enable 32 UE support The memory allocation is increased to enable the periodic mac stats logging to enable increased number of UEs data. --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c | 2 +- openair2/LAYER2/NR_MAC_gNB/main.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c index af8b077dea..2c3ca94393 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c @@ -241,7 +241,7 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frame, sub_frame_ } if ((slot == 0) && (frame & 127) == 0) { - char stats_output[16000] = {0}; + char stats_output[32656] = {0}; dump_mac_stats(gNB, stats_output, sizeof(stats_output), true); LOG_I(NR_MAC, "Frame.Slot %d.%d\n%s\n", frame, slot, stats_output); } diff --git a/openair2/LAYER2/NR_MAC_gNB/main.c b/openair2/LAYER2/NR_MAC_gNB/main.c index 72689dd90d..320aa273b7 100644 --- a/openair2/LAYER2/NR_MAC_gNB/main.c +++ b/openair2/LAYER2/NR_MAC_gNB/main.c @@ -45,7 +45,7 @@ extern RAN_CONTEXT_t RC; -#define MACSTATSSTRLEN 16000 +#define MACSTATSSTRLEN 36256 void *nrmac_stats_thread(void *arg) { From 740bec4ac0dcea02f67fe206176094ae5f98c97f Mon Sep 17 00:00:00 2001 From: vijay chadachan Date: Mon, 18 Mar 2024 12:51:02 +0100 Subject: [PATCH 19/39] Fix max_sched_ues in DL/UL Scheduler to match MAX_DCI_CORESET - Added the limit as MAX_DCI_CORESET for max_sched_ues in DL/UL scheduler. This is needed because gNB crashes when tested with 100MHz cell as the scheduler tries to schedule 11 UEs in a slot and the DCI informaiton is corrupted due to the limitation in NFAPI interface because of MAX_DCI_CORESET size. --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 3 +++ openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index caef6d8822..20e8a6d624 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -875,6 +875,9 @@ static void nr_fr1_dlsch_preprocessor(module_id_t module_id, frame_t frame, sub_ int average_agg_level = 4; // TODO find a better estimation int max_sched_ues = bw / (average_agg_level * NR_NB_REG_PER_CCE); + // FAPI cannot handle more than MAX_DCI_CORESET DCIs + max_sched_ues = min(max_sched_ues, MAX_DCI_CORESET); + /* proportional fair scheduling algorithm */ pf_dl(module_id, frame, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 1aee6f613e..beb31fca8e 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -2028,6 +2028,9 @@ static bool nr_fr1_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_ int average_agg_level = 4; // TODO find a better estimation int max_sched_ues = bw / (average_agg_level * NR_NB_REG_PER_CCE); + // FAPI cannot handle more than MAX_DCI_CORESET DCIs + max_sched_ues = min(max_sched_ues, MAX_DCI_CORESET); + /* proportional fair scheduling algorithm */ pf_ul(module_id, frame, From 5697f396f65531a6f02db494152d366b24166f82 Mon Sep 17 00:00:00 2001 From: vijay chadachan Date: Mon, 18 Mar 2024 12:55:06 +0100 Subject: [PATCH 20/39] Adjusted the num_dl_sched > 3 while adapting DL MCS for DL grants - The DL MCS adapted based on the BLER for the minimum number of DL(numd_sched) grants for the UE in the pre_configured number of frames. The current threshold value is set to be >9 for 16 UE capacity. - With increased number of UE to 32 and when all the UEs are DL data active the num_dl_sched is not meeting the threshold value. Due to whcih the MCS of all the UEs are stuck with MCS 10-12 in good channel condition. - The threshold value is adjusted to support 32 UE capacity increase. --- .../LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 932e11035b..46bd086d3f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -678,24 +678,24 @@ int get_mcs_from_bler(const NR_bler_options_t *bler_options, return old_mcs; // no update // last update is longer than x frames ago - const int dtx = (int)(stats->rounds[0] - bler_stats->rounds[0]); - const int dretx = (int)(stats->rounds[1] - bler_stats->rounds[1]); - const float bler_window = dtx > 0 ? (float) dretx / dtx : bler_stats->bler; + const int num_dl_sched = (int)(stats->rounds[0] - bler_stats->rounds[0]); + const int num_dl_retx = (int)(stats->rounds[1] - bler_stats->rounds[1]); + const float bler_window = num_dl_sched > 0 ? (float) num_dl_retx / num_dl_sched : bler_stats->bler; bler_stats->bler = BLER_FILTER * bler_stats->bler + (1 - BLER_FILTER) * bler_window; int new_mcs = old_mcs; - if (bler_stats->bler < bler_options->lower && old_mcs < max_mcs && dtx > 9) + if (bler_stats->bler < bler_options->lower && old_mcs < max_mcs && num_dl_sched > 3) new_mcs += 1; else if ((bler_stats->bler > bler_options->upper && old_mcs > 6) // above threshold - || (dtx <= 3 && old_mcs > 9)) // no activity + || (num_dl_sched <= 3 && old_mcs > 9)) // no activity new_mcs -= 1; // else we are within threshold boundaries bler_stats->last_frame = frame; bler_stats->mcs = new_mcs; memcpy(bler_stats->rounds, stats->rounds, sizeof(stats->rounds)); - LOG_D(MAC, "frame %4d MCS %d -> %d (dtx %d, dretx %d, BLER wnd %.3f avg %.6f)\n", - frame, old_mcs, new_mcs, dtx, dretx, bler_window, bler_stats->bler); + LOG_D(MAC, "frame %4d MCS %d -> %d (num_dl_sched %d, num_dl_retx %d, BLER wnd %.3f avg %.6f)\n", + frame, old_mcs, new_mcs, num_dl_sched, num_dl_retx, bler_window, bler_stats->bler); return new_mcs; } From 9efc692ad512328bfd02b388b015d8aa238fd179 Mon Sep 17 00:00:00 2001 From: Romain Beurdouche Date: Thu, 21 Mar 2024 09:24:55 +0100 Subject: [PATCH 21/39] fix(doc): fhi7.2: replace configuration file by wildcard in nr-softmodem usage example --- doc/ORAN_FHI7.2_Tutorial.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/ORAN_FHI7.2_Tutorial.md b/doc/ORAN_FHI7.2_Tutorial.md index 79b8352007..1498b07844 100644 --- a/doc/ORAN_FHI7.2_Tutorial.md +++ b/doc/ORAN_FHI7.2_Tutorial.md @@ -673,10 +673,10 @@ xRAN SRS reception is not supported. Run the `nr-softmodem` from the build directory: ```bash cd ~/openairinterface5g/cmake_targets/ran_build/build -sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/oran.fh.band78.fr1.273PRB.conf --sa --reorder-thread-disable 1 --thread-pool +sudo ./nr-softmodem -O --sa --thread-pool ``` -**Warning**: Make sure that the config file you add after the `-O` option is adapted to your machine, especially to its isolated cores. +**Warning**: Make sure that the configuration file you add after the `-O` option is adapted to your machine, especially to its isolated cores. **Note**: You may run OAI with O-RAN 7.2 Fronthaul without a RU attached (e.g. for benchmarking). In such case, you would generate artificial traffic by replacing the `--sa` option by the `--phy-test` option. From 8d93ab5fedab76c8998d1d0196c900e8566d6e95 Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 20 Mar 2024 16:34:57 +0100 Subject: [PATCH 22/39] fix gold pdcch --- openair1/PHY/NR_REFSIG/nr_gold.c | 20 +++++++++----------- openair1/PHY/NR_REFSIG/nr_gold_ue.c | 14 +++++++------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/openair1/PHY/NR_REFSIG/nr_gold.c b/openair1/PHY/NR_REFSIG/nr_gold.c index 29fd60fb5a..145fe11fab 100644 --- a/openair1/PHY/NR_REFSIG/nr_gold.c +++ b/openair1/PHY/NR_REFSIG/nr_gold.c @@ -55,25 +55,23 @@ void nr_init_pbch_dmrs(PHY_VARS_gNB* gNB) void nr_init_pdcch_dmrs(PHY_VARS_gNB* gNB, uint32_t Nid) { - uint32_t x1 = 0, x2 = 0; - uint8_t reset; NR_DL_FRAME_PARMS *fp = &gNB->frame_parms; uint32_t ***pdcch_dmrs = gNB->nr_gold_pdcch_dmrs; - int pdcch_dmrs_init_length = (((fp->N_RB_DL<<1)*3)>>5)+1; + int pdcch_dmrs_init_length = (((fp->N_RB_DL << 1) * 3) >> 5) + 1; - for (uint8_t slot=0; slotslots_per_frame; slot++) { - for (uint8_t symb=0; symbsymbols_per_slot; symb++) { - - reset = 1; - x2 = ((1<<17) * (fp->symbols_per_slot*slot+symb+1) * ((Nid<<1)+1) + (Nid<<1)); - LOG_D(PHY,"PDCCH DMRS slot %d, symb %d, Nid %d, x2 %x\n",slot,symb,Nid,x2); - for (uint32_t n=0; nslots_per_frame; slot++) { + for (int symb = 0; symb < fp->symbols_per_slot; symb++) { + uint8_t reset = 1; + uint32_t x1 = 0; + uint64_t temp_x2 = ((1UL << 17) * (fp->symbols_per_slot * slot + symb + 1) * ((Nid << 1) + 1) + (Nid << 1)); + uint32_t x2 = temp_x2 % (1U << 31); + LOG_D(PHY,"PDCCH DMRS slot %d, symb %d, Nid %d, x2 %x\n", slot, symb, Nid, x2); + for (uint32_t n = 0; n < pdcch_dmrs_init_length; n++) { pdcch_dmrs[slot][symb][n] = lte_gold_generic(&x1, &x2, reset); reset = 0; } } } - } diff --git a/openair1/PHY/NR_REFSIG/nr_gold_ue.c b/openair1/PHY/NR_REFSIG/nr_gold_ue.c index 2fa1fe00b7..9048d162dc 100644 --- a/openair1/PHY/NR_REFSIG/nr_gold_ue.c +++ b/openair1/PHY/NR_REFSIG/nr_gold_ue.c @@ -54,17 +54,17 @@ void nr_gold_pbch(PHY_VARS_NR_UE* ue) void nr_gold_pdcch(PHY_VARS_NR_UE* ue, unsigned short nid) { - unsigned int n = 0, x1 = 0, x2 = 0, x2tmp0 = 0; - uint8_t reset; int pdcch_dmrs_init_length = (((ue->frame_parms.N_RB_DL << 1) * 3) >> 5) + 1; - for (int ns = 0; ns < ue->frame_parms.slots_per_frame; ns++) { for (int l = 0; l < ue->frame_parms.symbols_per_slot; l++) { - reset = 1; - x2tmp0 = ((ue->frame_parms.symbols_per_slot * ns + l + 1) * ((nid << 1) + 1)); + uint8_t reset = 1; + uint64_t x2tmp0 = ((ue->frame_parms.symbols_per_slot * ns + l + 1) * ((nid << 1) + 1)); x2tmp0 <<= 17; - x2 = (x2tmp0 + (nid << 1)) % (1U << 31); //cinit - for (n=0; nnr_gold_pdcch[0][ns][l][n] = lte_gold_generic(&x1, &x2, reset); reset = 0; } From 557f3e6f0536b689d90026edd909244b5fc027bb Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 20 Mar 2024 16:56:10 +0100 Subject: [PATCH 23/39] fix gold pdsch --- openair1/PHY/NR_REFSIG/nr_gold.c | 23 +++++++++++------------ openair1/PHY/NR_REFSIG/nr_gold_ue.c | 22 +++++++++------------- 2 files changed, 20 insertions(+), 25 deletions(-) diff --git a/openair1/PHY/NR_REFSIG/nr_gold.c b/openair1/PHY/NR_REFSIG/nr_gold.c index 145fe11fab..8bee50eea7 100644 --- a/openair1/PHY/NR_REFSIG/nr_gold.c +++ b/openair1/PHY/NR_REFSIG/nr_gold.c @@ -75,20 +75,19 @@ void nr_init_pdcch_dmrs(PHY_VARS_gNB* gNB, uint32_t Nid) } -void nr_init_pdsch_dmrs(PHY_VARS_gNB* gNB, uint8_t nscid, uint32_t Nid) { - uint32_t x1 = 0, x2 = 0; - uint8_t reset; +void nr_init_pdsch_dmrs(PHY_VARS_gNB* gNB, uint8_t nscid, uint32_t Nid) +{ NR_DL_FRAME_PARMS *fp = &gNB->frame_parms; uint32_t ****pdsch_dmrs = gNB->nr_gold_pdsch_dmrs; - int pdsch_dmrs_init_length = ((fp->N_RB_DL*12)>>5)+1; - - for (uint8_t slot=0; slotslots_per_frame; slot++) { - - for (uint8_t symb=0; symbsymbols_per_slot; symb++) { - reset = 1; - x2 = ((1<<17) * (fp->symbols_per_slot*slot+symb+1) * ((Nid<<1)+1) +((Nid<<1)+nscid)); - LOG_D(PHY,"PDSCH DMRS slot %d, symb %d x2 %x, Nid %d,nscid %d\n",slot,symb,x2,Nid,nscid); - for (uint32_t n=0; nN_RB_DL * 12) >> 5) + 1; + for (int slot = 0; slot < fp->slots_per_frame; slot++) { + for (int symb = 0; symb < fp->symbols_per_slot; symb++) { + uint8_t reset = 1; + uint32_t x1 = 0; + uint64_t temp_x2 = ((1UL << 17) * (fp->symbols_per_slot * slot + symb + 1) * ((Nid << 1) + 1) + ((Nid << 1) + nscid)); + uint32_t x2 = temp_x2 % (1U << 31); + LOG_D(PHY,"PDSCH DMRS slot %d, symb %d, Nid %d, nscid %d, x2 %x\n",slot, symb, Nid, nscid, x2); + for (uint32_t n = 0; n < pdsch_dmrs_init_length; n++) { pdsch_dmrs[slot][symb][nscid][n] = lte_gold_generic(&x1, &x2, reset); reset = 0; } diff --git a/openair1/PHY/NR_REFSIG/nr_gold_ue.c b/openair1/PHY/NR_REFSIG/nr_gold_ue.c index 9048d162dc..b8ab04b5ee 100644 --- a/openair1/PHY/NR_REFSIG/nr_gold_ue.c +++ b/openair1/PHY/NR_REFSIG/nr_gold_ue.c @@ -74,21 +74,17 @@ void nr_gold_pdcch(PHY_VARS_NR_UE* ue, void nr_gold_pdsch(PHY_VARS_NR_UE* ue, int nscid, - uint32_t nid) { - unsigned int x1 = 0, x2 = 0, x2tmp0 = 0; - uint8_t reset; - int pdsch_dmrs_init_length = ((ue->frame_parms.N_RB_DL*12)>>5)+1; - + uint32_t nid) +{ + int pdsch_dmrs_init_length = ((ue->frame_parms.N_RB_DL * 12) >> 5) + 1; for (int ns=0; nsframe_parms.slots_per_frame; ns++) { - for (int l=0; lframe_parms.symbols_per_slot; l++) { - - reset = 1; - x2tmp0 = ((ue->frame_parms.symbols_per_slot*ns+l+1)*((nid<<1)+1))<<17; - x2 = (x2tmp0+(nid<<1)+nscid)%(1U<<31); //cinit - LOG_D(PHY,"UE DMRS slot %d, symb %d, x2 %x, nscid %d\n",ns,l,x2,nscid); - - for (int n=0; nframe_parms.symbols_per_slot * ns + l + 1) * ((nid << 1) + 1)) << 17; + uint32_t x1 = 0; + uint32_t x2 = (x2tmp0 + (nid << 1) + nscid) % (1U << 31); //cinit + LOG_D(PHY,"UE DMRS slot %d, symb %d, nscid %d, x2 %x\n", ns, l, nscid, x2); + for (int n = 0; n < pdsch_dmrs_init_length; n++) { ue->nr_gold_pdsch[0][ns][l][nscid][n] = lte_gold_generic(&x1, &x2, reset); reset = 0; } From de82f516feedee6ec132421aa03c4e8dd3c67e26 Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 20 Mar 2024 17:08:22 +0100 Subject: [PATCH 24/39] fix gold pusch --- openair1/PHY/NR_REFSIG/nr_gold.c | 26 +++++++++++--------------- openair1/PHY/NR_REFSIG/nr_gold_ue.c | 14 ++++++-------- 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/openair1/PHY/NR_REFSIG/nr_gold.c b/openair1/PHY/NR_REFSIG/nr_gold.c index 8bee50eea7..1e7a4b8b8f 100644 --- a/openair1/PHY/NR_REFSIG/nr_gold.c +++ b/openair1/PHY/NR_REFSIG/nr_gold.c @@ -96,22 +96,18 @@ void nr_init_pdsch_dmrs(PHY_VARS_gNB* gNB, uint8_t nscid, uint32_t Nid) } -void nr_gold_pusch(PHY_VARS_gNB* gNB, int nscid, uint32_t nid) { - - unsigned char ns; - unsigned int n = 0, x1 = 0, x2 = 0; - int reset; +void nr_gold_pusch(PHY_VARS_gNB* gNB, int nscid, uint32_t nid) +{ NR_DL_FRAME_PARMS *fp = &gNB->frame_parms; - unsigned short l; - int pusch_dmrs_init_length = ((fp->N_RB_UL*12)>>5)+1; - - for (ns=0; nsslots_per_frame; ns++) { - for (l=0; lsymbols_per_slot; l++) { - reset = 1; - x2 = ((1<<17) * (fp->symbols_per_slot*ns+l+1) * ((nid<<1)+1) +((nid<<1)+nscid)); - LOG_D(PHY,"DMRS slot %d, symb %d x2 %x\n",ns,l,x2); - - for (n=0; nN_RB_UL * 12) >> 5) + 1; + for (int ns = 0; ns < fp->slots_per_frame; ns++) { + for (int l = 0; l < fp->symbols_per_slot; l++) { + int reset = 1; + uint32_t x1 = 0; + uint64_t temp_x2 = ((1UL << 17) * (fp->symbols_per_slot * ns + l + 1) * ((nid << 1) + 1) + ((nid << 1) + nscid)); + uint32_t x2 = temp_x2 % (1U << 31); + LOG_D(PHY,"DMRS slot %d, symb %d, nscid %d, nid %d, x2 %x\n", ns, l, nscid, nid, x2); + for (int n = 0; n < pusch_dmrs_init_length; n++) { gNB->nr_gold_pusch_dmrs[nscid][ns][l][n] = lte_gold_generic(&x1, &x2, reset); reset = 0; } diff --git a/openair1/PHY/NR_REFSIG/nr_gold_ue.c b/openair1/PHY/NR_REFSIG/nr_gold_ue.c index b8ab04b5ee..122cc11dd3 100644 --- a/openair1/PHY/NR_REFSIG/nr_gold_ue.c +++ b/openair1/PHY/NR_REFSIG/nr_gold_ue.c @@ -92,21 +92,19 @@ void nr_gold_pdsch(PHY_VARS_NR_UE* ue, } } -void nr_init_pusch_dmrs(PHY_VARS_NR_UE* ue, - uint16_t N_n_scid, - uint8_t n_scid) +void nr_init_pusch_dmrs(PHY_VARS_NR_UE* ue, uint16_t N_n_scid, uint8_t n_scid) { - uint32_t x1 = 0, x2 = 0, n = 0; NR_DL_FRAME_PARMS *fp = &ue->frame_parms; uint32_t ****pusch_dmrs = ue->nr_gold_pusch_dmrs; int pusch_dmrs_init_length = ((fp->N_RB_UL * 12) >> 5) + 1; - for (int slot = 0; slot < fp->slots_per_frame; slot++) { for (int symb = 0; symb < fp->symbols_per_slot; symb++) { int reset = 1; - x2 = ((1U << 17) * (fp->symbols_per_slot*slot + symb + 1) * ((N_n_scid << 1) + 1) + ((N_n_scid << 1) + n_scid)); - LOG_D(PHY,"DMRS slot %d, symb %d x2 %x\n", slot, symb, x2); - for (n=0; nsymbols_per_slot*slot + symb + 1) * ((N_n_scid << 1) + 1) + ((N_n_scid << 1) + n_scid)); + uint32_t x2 = t_x2 % (1U << 31); + LOG_D(PHY,"DMRS slot %d, symb %d, N_n_scid %d, n_scid %d, x2 %x\n", slot, symb, N_n_scid, n_scid, x2); + for (int n = 0; n < pusch_dmrs_init_length; n++) { pusch_dmrs[slot][symb][n_scid][n] = lte_gold_generic(&x1, &x2, reset); reset = 0; } From 5df946fab6df1c45bd9624db30f7dc22c5510ce8 Mon Sep 17 00:00:00 2001 From: francescomani Date: Mon, 26 Feb 2024 19:14:01 +0100 Subject: [PATCH 25/39] improvements in Bj computation and implementing a timer to compute time elapsed since last Bj update --- common/utils/nr/nr_common.c | 9 ++ common/utils/nr/nr_common.h | 7 ++ openair2/LAYER2/NR_MAC_UE/config_ue.c | 74 +++++++++++++- openair2/LAYER2/NR_MAC_UE/mac_defs.h | 3 +- openair2/LAYER2/NR_MAC_UE/mac_proto.h | 7 -- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 104 ++++---------------- 6 files changed, 105 insertions(+), 99 deletions(-) diff --git a/common/utils/nr/nr_common.c b/common/utils/nr/nr_common.c index f7ea7304e4..fbff9bf94b 100644 --- a/common/utils/nr/nr_common.c +++ b/common/utils/nr/nr_common.c @@ -1011,6 +1011,8 @@ bool nr_timer_tick(NR_timer_t *timer) bool expired = false; if (timer->active) { timer->counter += timer->step; + if (timer->target == UINT_MAX) // infinite target, never expires + return false; expired = nr_timer_expired(*timer); if (expired) timer->active = false; @@ -1020,9 +1022,16 @@ bool nr_timer_tick(NR_timer_t *timer) bool nr_timer_expired(NR_timer_t timer) { + if (timer.target == UINT_MAX) // infinite target, never expires + return false; return (timer.counter >= timer.target); } +uint32_t nr_timer_elapsed_time(NR_timer_t timer) +{ + return timer.counter; +} + void nr_timer_setup(NR_timer_t *timer, const uint32_t target, const uint32_t step) { timer->target = target; diff --git a/common/utils/nr/nr_common.h b/common/utils/nr/nr_common.h index c76969a8e8..4a90d79578 100644 --- a/common/utils/nr/nr_common.h +++ b/common/utils/nr/nr_common.h @@ -158,6 +158,13 @@ bool nr_timer_expired(NR_timer_t timer); * @return Indication if the timer is active or not */ bool is_nr_timer_active(NR_timer_t timer); +/** + * @brief To return how much time has passed since start of timer + * @param timer Timer to be checked + * @return Time passed since start of timer + */ +uint32_t nr_timer_elapsed_time(NR_timer_t timer); + extern const nr_bandentry_t nr_bandtable[]; diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index ef5df5beb9..c86aad9ab2 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -657,10 +657,70 @@ static int nr_get_ms_bucketsizeduration(long bucketsizeduration) } } +static uint32_t nr_get_pbr(long prioritizedbitrate) // returns Bps +{ + uint32_t pbr = 0; + switch (prioritizedbitrate) { + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps0: + pbr = 0; + break; + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps8: + pbr = 8; + break; + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps16: + pbr = 16; + break; + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps32: + pbr = 32; + break; + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps64: + pbr = 64; + break; + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps128: + pbr = 128; + break; + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps256: + pbr = 256; + break; + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps512: + pbr = 512; + break; + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps1024: + pbr = 1024; + break; + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps2048: + pbr = 2048; + break; + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps4096: + pbr = 4096; + break; + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps8192: + pbr = 8192; + break; + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps16384: + pbr = 16384; + break; + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps32768: + pbr = 32768; + break; + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps65536: + pbr = 65536; + break; + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity: + pbr = UINT_MAX; + break; + default: + AssertFatal(false, "The proritized bit rate value is not one of the enum values\n"); + } + uint32_t pbr_bytes = + (prioritizedbitrate < NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity) ? pbr * 1000 : pbr; + return pbr_bytes; +} + static uint32_t get_lc_bucket_size(long prioritisedBitRate, long bucketSizeDuration) { - int pbr = nr_get_pbr(prioritisedBitRate); - // in infinite pbr, the bucket is saturated by pbr + uint32_t pbr = nr_get_pbr(prioritisedBitRate); + // if infinite pbr, the bucket is saturated by pbr int bsd = 0; if (prioritisedBitRate == NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity) bsd = 1; @@ -675,8 +735,8 @@ static void set_default_logicalchannelconfig(nr_lcordered_info_t *lc_info, NR_SR { lc_info->lcid = srb_id; lc_info->priority = srb_id == 2 ? 3 : 1; - lc_info->prioritisedBitRate = NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity; - lc_info->bucket_size = get_lc_bucket_size(lc_info->prioritisedBitRate, 0); + lc_info->pbr = UINT_MAX; + lc_info->bucket_size = UINT_MAX; } static void nr_configure_lc_config(NR_UE_MAC_INST_t *mac, @@ -693,10 +753,14 @@ static void nr_configure_lc_config(NR_UE_MAC_INST_t *mac, AssertFatal(mac_lc_config->ul_SpecificParameters, "UL parameters shouldn't be NULL for DRBs\n"); struct NR_LogicalChannelConfig__ul_SpecificParameters *ul_parm = mac_lc_config->ul_SpecificParameters; lc_info->priority = ul_parm->priority; - lc_info->prioritisedBitRate = ul_parm->prioritisedBitRate; + lc_info->pbr = nr_get_pbr(ul_parm->prioritisedBitRate); // TODO Verify setting to 0 is ok, 331 just says need R (release if NULL) mac->scheduling_info.lc_sched_info[lc_info->lcid - 1].LCGID = ul_parm->logicalChannelGroup ? *ul_parm->logicalChannelGroup : 0; lc_info->bucket_size = get_lc_bucket_size(ul_parm->prioritisedBitRate, ul_parm->bucketSizeDuration); + // setup and start Bj timer for this LC + NR_timer_t *bjt = &mac->scheduling_info.lc_sched_info[lc_info->lcid - 1].Bj_timer; + nr_timer_setup(bjt, UINT_MAX, 1); // this timer never expires in principle, counter incremented by number of slots + nr_timer_start(bjt); } static void configure_logicalChannelBearer(NR_UE_MAC_INST_t *mac, diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h index 0c112ac66d..97c1860d1b 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h @@ -185,6 +185,7 @@ typedef struct { long LCGID; // Bj bucket usage per lcid int32_t Bj; + NR_timer_t Bj_timer; } NR_LC_SCHEDULING_INFO; typedef struct { @@ -441,7 +442,7 @@ typedef struct nr_lcordered_info_s { // logical channels ids ordered as per priority NR_LogicalChannelIdentity_t lcid; long priority; - long prioritisedBitRate; + uint32_t pbr; // in B/s (UINT_MAX = infinite) // Bucket size per lcid uint32_t bucket_size; } nr_lcordered_info_t; diff --git a/openair2/LAYER2/NR_MAC_UE/mac_proto.h b/openair2/LAYER2/NR_MAC_UE/mac_proto.h index 7322024e7b..e3d887f2a3 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_proto.h @@ -138,13 +138,6 @@ bool nr_update_bsr(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t slotP, uint8_t uint8_t nr_locate_BsrIndexByBufferSize(const uint32_t *table, int size, int value); -/*! \fn int nr_get_pbr(long prioritizedbitrate) - \brief get the rate in kbps from the rate configured by the higher layer -\param[in] prioritizedbitrate -\return the rate in kbps -*/ -uint32_t nr_get_pbr(long prioritizedbitrate); - /*! \fn int nr_get_sf_periodicBSRTimer(uint8_t periodicBSR_Timer) \brief get the number of subframe from the periodic BSR timer configured by the higher layers \param[in] periodicBSR_Timer timer for periodic BSR diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 4bd1e29ca9..bfded89c15 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -118,6 +118,10 @@ static NR_LC_SCHEDULING_INFO *get_scheduling_info_from_lcid(NR_UE_MAC_INST_t *ma void update_mac_timers(NR_UE_MAC_INST_t *mac) { nr_timer_tick(&mac->ra.contention_resolution_timer); + for (int i = 0; i < NR_MAX_NUM_LCID; i++) + AssertFatal(!nr_timer_tick(&mac->scheduling_info.lc_sched_info[i].Bj_timer), + "Bj timer for LCID %d expired! That should never happen\n", + i); } void remove_ul_config_last_item(fapi_nr_ul_config_request_pdu_t *pdu) @@ -1150,22 +1154,27 @@ void nr_ue_ul_scheduler(NR_UE_MAC_INST_t *mac, nr_uplink_indication_t *ul_info) nr_lcordered_info_t *lc_info = mac->lc_ordered_list.array[i]; int lcid = lc_info->lcid; // max amount of data that can be buffered/accumulated in a logical channel buffer - int32_t bucketSize_max = lc_info->bucket_size; - AssertFatal(bucketSize_max >= 0, "negative bucketSize_max %d, will never schedule UE: lcid %d\n",bucketSize_max, lcid); + uint32_t bucketSize_max = lc_info->bucket_size; /* measure Bj increment the value of Bj by product PBR * T */ NR_LC_SCHEDULING_INFO *sched_info = get_scheduling_info_from_lcid(mac, lcid); - int T = 1; // time elapsed since Bj was last incremented int32_t bj = sched_info->Bj; - bj += nr_get_pbr(lc_info->prioritisedBitRate) * T; - if (lc_info->prioritisedBitRate == NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity) - bj = nr_get_pbr(lc_info->prioritisedBitRate); + if (lc_info->pbr < UINT_MAX) { + uint32_t slots_elapsed = nr_timer_elapsed_time(sched_info->Bj_timer); // slots elapsed since Bj was last incremented + // it is safe to divide by 1k since pbr in lc_info is computed multiplying by 1000 the RRC value to convert kB/s to B/s + uint32_t pbr_ms = lc_info->pbr / 1000; + bj += ((pbr_ms * slots_elapsed) >> mac->current_UL_BWP->scs); // each slot length is 1/scs ms + } + else + bj = INT_MAX; // bj > max bucket size, set bj to max bucket size, as in ts38.321 5.4.3.1 Logical Channel Prioritization sched_info->Bj = min(bj, bucketSize_max); + // reset bj timer + nr_timer_start(&sched_info->Bj_timer); } // Call BSR procedure as described in Section 5.4.5 in 38.321 @@ -2883,7 +2892,7 @@ long get_num_bytes_to_reqlc(NR_UE_MAC_INST_t *mac, /* Calculates the number of bytes the logical channel should request from the correcponding RLC buffer*/ nr_lcordered_info_t *lc_info = get_lc_info_from_lcid(mac, lc_num); AssertFatal(lc_info, "Couldn't find logical channel with LCID %d\n", lc_num); - uint32_t pbr = nr_get_pbr(lc_info->prioritisedBitRate); + uint32_t pbr = lc_info->pbr; NR_LC_SCHEDULING_INFO *sched_info = get_scheduling_info_from_lcid(mac, lc_num); int32_t lcid_remain_buffer = sched_info->LCID_buffer_remain; *target = (same_priority_count > 1) ? min(buflen_remain_ep, pbr) : pbr; @@ -3132,8 +3141,8 @@ uint8_t nr_ue_get_sdu(NR_UE_MAC_INST_t *mac, bool lcids_data_status[NR_MAX_NUM_LCID] = {0}; memset(lcids_data_status, 1, NR_MAX_NUM_LCID); - uint32_t lcp_allocation_counter = - 0; // in the first run all the lc are allocated as per bj and prioritized bit rate but in subsequent runs, no need to consider + // in the first run all the lc are allocated as per bj and prioritized bit rate but in subsequent runs, no need to consider + uint32_t lcp_allocation_counter = 0; // bj and prioritized bit rate but just consider priority uint16_t buflen_ep = 0; // this variable holds the length in bytes in mac pdu when multiple equal priority channels are present // because as per standard(TS38.321), all equal priority channels should be served equally @@ -3300,80 +3309,3 @@ static void schedule_ta_command(fapi_nr_dl_config_request_t *dl_config, NR_UL_TI dl_config->number_pdus += 1; ul_time_alignment->ta_apply = no_ta; } - -uint32_t nr_get_pbr(long prioritizedbitrate) -{ - int32_t pbr = -1; - switch (prioritizedbitrate) { - case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps0: - pbr = 0; - break; - - case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps8: - pbr = 8; - break; - - case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps16: - pbr = 16; - break; - - case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps32: - pbr = 32; - break; - - case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps64: - pbr = 64; - break; - - case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps128: - pbr = 128; - break; - - case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps256: - pbr = 256; - break; - - case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps512: - pbr = 512; - break; - - case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps1024: - pbr = 1024; - break; - - case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps2048: - pbr = 2048; - break; - - case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps4096: - pbr = 4096; - break; - - case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps8192: - pbr = 8192; - break; - - case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps16384: - pbr = 16384; - break; - - case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps32768: - pbr = 32768; - break; - - case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps65536: - pbr = 65536; - break; - - case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity: - pbr = INT32_MAX; - break; - - default: - pbr = -1; - } - AssertFatal(pbr >= 0, "The proritized bit rate value is not one of the enum values\n"); - uint32_t pbr_bytes = - (prioritizedbitrate < NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity) ? pbr * 1000 : pbr; - return pbr_bytes; -} From 04ac336c80366fc13fcc4c31e1d14399f5838007 Mon Sep 17 00:00:00 2001 From: francescomani Date: Fri, 1 Mar 2024 19:11:04 +0100 Subject: [PATCH 26/39] improvements in function to update BSR status --- openair2/LAYER2/NR_MAC_COMMON/nr_mac.h | 5 - openair2/LAYER2/NR_MAC_UE/config_ue.c | 55 +++++- openair2/LAYER2/NR_MAC_UE/mac_defs.h | 10 ++ openair2/LAYER2/NR_MAC_UE/mac_proto.h | 3 +- openair2/LAYER2/NR_MAC_UE/main_ue_nr.c | 9 + openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 184 ++++++-------------- 6 files changed, 123 insertions(+), 143 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h index b131b726da..703ff05e32 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h @@ -63,11 +63,6 @@ #define RAR_PAYLOAD_SIZE_MAX 128 #define MAX_CSI_REPORTCONFIG 48 -#define NR_BSR_TRIGGER_NONE (0) /* No BSR Trigger */ -#define NR_BSR_TRIGGER_REGULAR (1) /* For Regular and ReTxBSR Expiry Triggers */ -#define NR_BSR_TRIGGER_PERIODIC (2) /* For BSR Periodic Timer Expiry Trigger */ -#define NR_BSR_TRIGGER_PADDING (4) /* For Padding BSR Trigger */ - // For both DL/UL-SCH // Except: // - UL/DL-SCH: fixed-size MAC CE(known by LCID) diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index c86aad9ab2..d449f089f6 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -744,21 +744,24 @@ static void nr_configure_lc_config(NR_UE_MAC_INST_t *mac, NR_LogicalChannelConfig_t *mac_lc_config, NR_SRB_Identity_t srb_id) { + NR_LC_SCHEDULING_INFO *lc_sched_info = get_scheduling_info_from_lcid(mac, lc_info->lcid); if (srb_id > 0 && !mac_lc_config->ul_SpecificParameters) { // release configuration and reset to default set_default_logicalchannelconfig(lc_info, srb_id); - mac->scheduling_info.lc_sched_info[lc_info->lcid - 1].LCGID = 0; + // invalid LCGID to signal it is absent in the configuration + lc_sched_info->LCGID = NR_INVALID_LCGID; return; } AssertFatal(mac_lc_config->ul_SpecificParameters, "UL parameters shouldn't be NULL for DRBs\n"); struct NR_LogicalChannelConfig__ul_SpecificParameters *ul_parm = mac_lc_config->ul_SpecificParameters; lc_info->priority = ul_parm->priority; + lc_info->sr_DelayTimerApplied = ul_parm->logicalChannelSR_DelayTimerApplied; lc_info->pbr = nr_get_pbr(ul_parm->prioritisedBitRate); - // TODO Verify setting to 0 is ok, 331 just says need R (release if NULL) - mac->scheduling_info.lc_sched_info[lc_info->lcid - 1].LCGID = ul_parm->logicalChannelGroup ? *ul_parm->logicalChannelGroup : 0; + // if logicalChannelGroup we release LCGID and set it to invalid + lc_sched_info->LCGID = ul_parm->logicalChannelGroup ? *ul_parm->logicalChannelGroup : NR_INVALID_LCGID; lc_info->bucket_size = get_lc_bucket_size(ul_parm->prioritisedBitRate, ul_parm->bucketSizeDuration); // setup and start Bj timer for this LC - NR_timer_t *bjt = &mac->scheduling_info.lc_sched_info[lc_info->lcid - 1].Bj_timer; + NR_timer_t *bjt = &lc_sched_info->Bj_timer; nr_timer_setup(bjt, UINT_MAX, 1); // this timer never expires in principle, counter incremented by number of slots nr_timer_start(bjt); } @@ -1557,6 +1560,37 @@ static void configure_physicalcellgroup(NR_UE_MAC_INST_t *mac, *p_UE_FR1 : *p_NR_FR1); } +static uint32_t get_sr_DelayTimer(long logicalChannelSR_DelayTimer) +{ + uint32_t timer = 0; + switch (logicalChannelSR_DelayTimer) { + case NR_BSR_Config__logicalChannelSR_DelayTimer_sf20 : + timer = 20; + break; + case NR_BSR_Config__logicalChannelSR_DelayTimer_sf40 : + timer = 40; + break; + case NR_BSR_Config__logicalChannelSR_DelayTimer_sf64 : + timer = 64; + break; + case NR_BSR_Config__logicalChannelSR_DelayTimer_sf128 : + timer = 128; + break; + case NR_BSR_Config__logicalChannelSR_DelayTimer_sf512 : + timer = 512; + break; + case NR_BSR_Config__logicalChannelSR_DelayTimer_sf1024 : + timer = 1024; + break; + case NR_BSR_Config__logicalChannelSR_DelayTimer_sf2560 : + timer = 2560; + break; + default : + AssertFatal(false, "Invalid SR_DelayTimer %ld\n", logicalChannelSR_DelayTimer); + } + return timer; +} + static void configure_maccellgroup(NR_UE_MAC_INST_t *mac, const NR_MAC_CellGroupConfig_t *mcg) { NR_UE_SCHEDULING_INFO *si = &mac->scheduling_info; @@ -1590,10 +1624,13 @@ static void configure_maccellgroup(NR_UE_MAC_INST_t *mac, const NR_MAC_CellGroup } } if (mcg->bsr_Config) { + int subframes_per_slot = nr_slots_per_frame[mac->current_UL_BWP->scs] / 10; si->periodicBSR_Timer = mcg->bsr_Config->periodicBSR_Timer; si->retxBSR_Timer = mcg->bsr_Config->retxBSR_Timer; - if (mcg->bsr_Config->logicalChannelSR_DelayTimer) - LOG_E(NR_MAC, "Handling of logicalChannelSR_DelayTimer not implemented\n"); + if (mcg->bsr_Config->logicalChannelSR_DelayTimer) { + uint32_t target_sf = get_sr_DelayTimer(*mcg->bsr_Config->logicalChannelSR_DelayTimer); + nr_timer_setup(&si->sr_DelayTimer, target_sf * subframes_per_slot, 1); // 1 slot update rate + } } if (mcg->tag_Config) { // TODO TAG not handled @@ -2053,9 +2090,6 @@ void nr_rrc_mac_config_req_cg(module_id_t module_id, AssertFatal(cell_group_config, "CellGroupConfig should not be NULL\n"); NR_UE_MAC_INST_t *mac = get_mac_inst(module_id); - if (cell_group_config->mac_CellGroupConfig) - configure_maccellgroup(mac, cell_group_config->mac_CellGroupConfig); - if (cell_group_config->physicalCellGroupConfig) configure_physicalcellgroup(mac, cell_group_config->physicalCellGroupConfig); @@ -2073,6 +2107,9 @@ void nr_rrc_mac_config_req_cg(module_id_t module_id, } } + if (cell_group_config->mac_CellGroupConfig) + configure_maccellgroup(mac, cell_group_config->mac_CellGroupConfig); + configure_logicalChannelBearer(mac, cell_group_config->rlc_BearerToAddModList, cell_group_config->rlc_BearerToReleaseList); diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h index 97c1860d1b..259c7cc2b1 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h @@ -68,6 +68,13 @@ // NR UE defs // ========== +#define NR_BSR_TRIGGER_NONE (0) /* No BSR Trigger */ +#define NR_BSR_TRIGGER_REGULAR (1) /* For Regular and ReTxBSR Expiry Triggers */ +#define NR_BSR_TRIGGER_PERIODIC (2) /* For BSR Periodic Timer Expiry Trigger */ +#define NR_BSR_TRIGGER_PADDING (4) /* For Padding BSR Trigger */ + +#define NR_INVALID_LCGID (NR_MAX_NUM_LCGID) + #define MAX_NUM_BWP_UE 5 #define NUM_SLOT_FRAME 10 @@ -205,6 +212,8 @@ typedef struct { uint8_t SR_pending; /// SR_COUNTER as defined in 38.321 uint16_t SR_COUNTER; + // logicalChannelSR-DelayTimer + NR_timer_t sr_DelayTimer; /// retxBSR-Timer, default value is sf2560 uint16_t retxBSR_Timer; /// retxBSR_SF, number of subframe before triggering a regular BSR @@ -445,6 +454,7 @@ typedef struct nr_lcordered_info_s { uint32_t pbr; // in B/s (UINT_MAX = infinite) // Bucket size per lcid uint32_t bucket_size; + bool sr_DelayTimerApplied; } nr_lcordered_info_t; diff --git a/openair2/LAYER2/NR_MAC_UE/mac_proto.h b/openair2/LAYER2/NR_MAC_UE/mac_proto.h index e3d887f2a3..109e7455b5 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_proto.h @@ -47,6 +47,7 @@ void nr_ue_init_mac(NR_UE_MAC_INST_t *mac); void send_srb0_rrc(int ue_id, const uint8_t *sdu, sdu_size_t sdu_len, void *data); void update_mac_timers(NR_UE_MAC_INST_t *mac); +NR_LC_SCHEDULING_INFO *get_scheduling_info_from_lcid(NR_UE_MAC_INST_t *mac, NR_LogicalChannelIdentity_t lcid); /**\brief apply default configuration values in nr_mac instance \param mac mac instance */ @@ -126,7 +127,7 @@ int8_t nr_ue_get_SR(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t slotP); \param[in] slotP number \param[in] gNB_index */ -bool nr_update_bsr(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t slotP, uint8_t gNB_index); +void nr_update_bsr(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t slotP, uint8_t gNB_index); /*! \fn nr_locate_BsrIndexByBufferSize (int *table, int size, int value) \brief locate the BSR level in the table as defined in 38.321. This function requires that he values in table to be monotonic, either increasing or decreasing. The returned value is not less than 0, nor greater than n-1, where n is the size of table. diff --git a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c index c8119a8ef4..bb9f1437e7 100644 --- a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c +++ b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c @@ -72,6 +72,9 @@ void nr_ue_init_mac(NR_UE_MAC_INST_t *mac) mac->p_Max_alt = INT_MIN; reset_mac_inst(mac); + // need to inizialize because might not been setup (optional timer) + nr_timer_stop(&mac->scheduling_info.sr_DelayTimer); + memset(&mac->ssb_measurements, 0, sizeof(mac->ssb_measurements)); memset(&mac->ul_time_alignment, 0, sizeof(mac->ul_time_alignment)); memset(mac->ssb_list, 0, sizeof(mac->ssb_list)); @@ -144,13 +147,19 @@ void reset_mac_inst(NR_UE_MAC_INST_t *nr_mac) // initialize Bj for each logical channel to zero // TODO reset also other status variables of LC, is this ok? for (int i = 0; i < NR_MAX_NUM_LCID; i++) { + LOG_D(NR_MAC, "Applying default logical channel config for LCID %d\n", i); nr_mac->scheduling_info.lc_sched_info[i].Bj = 0; nr_mac->scheduling_info.lc_sched_info[i].LCID_buffer_with_data = false; nr_mac->scheduling_info.lc_sched_info[i].LCID_buffer_remain = 0; } // TODO stop all running timers + for (int i = 0; i < NR_MAX_NUM_LCID; i++) { + nr_mac->scheduling_info.lc_sched_info[i].Bj = 0; + nr_timer_stop(&nr_mac->scheduling_info.lc_sched_info[i].Bj_timer); + } nr_timer_stop(&nr_mac->ra.contention_resolution_timer); + nr_timer_stop(&nr_mac->scheduling_info.sr_DelayTimer); // consider all timeAlignmentTimers as expired and perform the corresponding actions in clause 5.2 // TODO diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index bfded89c15..6f3510d6c4 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -109,7 +109,7 @@ static int lcid_buffer_index(NR_LogicalChannelIdentity_t lcid) return lcid - 1; } -static NR_LC_SCHEDULING_INFO *get_scheduling_info_from_lcid(NR_UE_MAC_INST_t *mac, NR_LogicalChannelIdentity_t lcid) +NR_LC_SCHEDULING_INFO *get_scheduling_info_from_lcid(NR_UE_MAC_INST_t *mac, NR_LogicalChannelIdentity_t lcid) { int idx = lcid_buffer_index(lcid); return &mac->scheduling_info.lc_sched_info[idx]; @@ -118,6 +118,7 @@ static NR_LC_SCHEDULING_INFO *get_scheduling_info_from_lcid(NR_UE_MAC_INST_t *ma void update_mac_timers(NR_UE_MAC_INST_t *mac) { nr_timer_tick(&mac->ra.contention_resolution_timer); + nr_timer_tick(&mac->scheduling_info.sr_DelayTimer); for (int i = 0; i < NR_MAX_NUM_LCID; i++) AssertFatal(!nr_timer_tick(&mac->scheduling_info.lc_sched_info[i].Bj_timer), "Bj timer for LCID %d expired! That should never happen\n", @@ -1190,43 +1191,18 @@ void nr_ue_ul_scheduler(NR_UE_MAC_INST_t *mac, nr_uplink_indication_t *ul_info) mac->scheduling_info.periodicBSR_SF--; } - //Check whether Regular BSR is triggered - if (nr_update_bsr(mac, frame_tx, slot_tx, gNB_index) == true) { - // call SR procedure to generate pending SR and BSR for next PUCCH/PUSCH TxOp. This should implement the procedures - // outlined in Sections 5.4.4 an 5.4.5 of 38.321 - mac->scheduling_info.SR_pending = 1; - // Regular BSR trigger - mac->BSR_reporting_active |= NR_BSR_TRIGGER_REGULAR; - LOG_D(NR_MAC, "[UE %d][BSR] Regular BSR Triggered Frame %d slot %d SR for PUSCH is pending\n", mac->ue_id, frame_tx, slot_tx); - } + //Check whether BSR is triggered + nr_update_bsr(mac, frame_tx, slot_tx, gNB_index); if(mac->state >= UE_PERFORMING_RA) nr_ue_pucch_scheduler(mac, frame_tx, slot_tx, ul_info->phy_data); } -bool nr_update_bsr(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t slotP, uint8_t gNB_index) +void nr_update_bsr(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t slotP, uint8_t gNB_index) { - bool bsr_regular_triggered = false; - uint8_t num_lcid_with_data = 0; // for LCID with data only if LCGID is defined - uint32_t lcgid_buffer_remain[NR_MAX_NUM_LCGID] = {0,0,0,0,0,0,0,0}; - int32_t lcid_bytes_in_buffer[NR_MAX_NUM_LCID]; - /* Array for ordering LCID with data per decreasing priority order */ - uint8_t lcid_reordered_array[NR_MAX_NUM_LCID] = { - NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, - NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, - NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, - NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, - NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, - }; - uint8_t pos_next = 0; - //uint8_t highest_priority = 16; - uint8_t array_index = 0; - // Reset All BSR Infos for (int lcid = 1; lcid <= NR_MAX_NUM_LCID; lcid++) { // Reset transmission status - int idx = lcid_buffer_index(lcid); - lcid_bytes_in_buffer[idx] = 0; - mac->scheduling_info.lc_sched_info[idx].LCID_buffer_with_data = false; + mac->scheduling_info.lc_sched_info[lcid_buffer_index(lcid)].LCID_buffer_with_data = false; } for (int lcgid = 0; lcgid < NR_MAX_NUM_LCGID; lcgid++) { @@ -1235,116 +1211,68 @@ bool nr_update_bsr(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t slotP, uint8_t mac->scheduling_info.lcg_sched_info[lcgid].BSR_bytes = 0; } - //Get Buffer Occupancy and fill lcid_reordered_array + bool bsr_regular_triggered = mac->BSR_reporting_active & NR_BSR_TRIGGER_REGULAR; for (int i = 0; i < mac->lc_ordered_list.count; i++) { - int lcid = mac->lc_ordered_list.array[i]->lcid; - NR_LC_SCHEDULING_INFO *sched_info = get_scheduling_info_from_lcid(mac, lcid); - int lcgid = sched_info->LCGID; + nr_lcordered_info_t *lc_info = mac->lc_ordered_list.array[i]; + int lcid = lc_info->lcid; + NR_LC_SCHEDULING_INFO *lc_sched_info = get_scheduling_info_from_lcid(mac, lcid); + int lcgid = lc_sched_info->LCGID; - // Store already available data to transmit per Group - if (lcgid < NR_MAX_NUM_LCGID) { - lcgid_buffer_remain[lcgid] += sched_info->LCID_buffer_remain; - } + // check if UL data for a logical channel which belongs to a LCG becomes available for transmission + if (lcgid != NR_INVALID_LCGID) { + mac_rlc_status_resp_t rlc_status = mac_rlc_status_ind(mac->ue_id, + mac->ue_id, + gNB_index, + frameP, + slotP, + ENB_FLAG_NO, + MBMS_FLAG_NO, + lcid, + 0, + 0); - mac_rlc_status_resp_t rlc_status = mac_rlc_status_ind(mac->ue_id, - mac->ue_id, - gNB_index, - frameP, - slotP, - ENB_FLAG_NO, - MBMS_FLAG_NO, - lcid, - 0, - 0); + lc_sched_info->LCID_buffer_remain = rlc_status.bytes_in_buffer; - int lc_idx = lcid_buffer_index(lcid); - lcid_bytes_in_buffer[lc_idx] = rlc_status.bytes_in_buffer; - - if (rlc_status.bytes_in_buffer > 0) { - LOG_D(NR_MAC, - "[UE %d] PDCCH Tick : LCID%d LCGID%d has data to transmit =%d bytes at frame %d slot %d\n", - mac->ue_id, - lcid, - lcgid, - rlc_status.bytes_in_buffer, - frameP, - slotP); - sched_info->LCID_buffer_with_data = true; - - //Update BSR_bytes and position in lcid_reordered_array only if Group is defined - if (lcgid < NR_MAX_NUM_LCGID) { - num_lcid_with_data ++; - // sum lcid buffer which has same lcgid - mac->scheduling_info.lcg_sched_info[lcgid].BSR_bytes += rlc_status.bytes_in_buffer; - //Fill in the array - array_index = 0; - - do { - //if (mac->logicalChannelConfig[lcid]->ul_SpecificParameters->priority <= highest_priority) { - if (1) { // todo - //Insert if priority is higher or equal (lower or equal in value) - for (pos_next = num_lcid_with_data - 1; pos_next > array_index; pos_next--) { - lcid_reordered_array[pos_next] = lcid_reordered_array[pos_next - 1]; - } - - lcid_reordered_array[array_index] = lcid; - break; - } - - array_index ++; - } while ((array_index < num_lcid_with_data) && (array_index <= NR_MAX_NUM_LCID)); - } - } - } - - // Check whether a regular BSR can be triggered according to the first cases in 38.321 - if (num_lcid_with_data) { - LOG_D(NR_MAC, "[UE %d] PDCCH Tick at frame %d slot %d: NumLCID with data=%d Reordered LCID0=%d LCID1=%d LCID2=%d\n", - mac->ue_id, - frameP, - slotP, - num_lcid_with_data, - lcid_reordered_array[0], - lcid_reordered_array[1], - lcid_reordered_array[2]); - - for (array_index = 0; array_index < num_lcid_with_data; array_index++) { - int lcid = lcid_reordered_array[array_index]; - NR_LC_SCHEDULING_INFO *sched_info = get_scheduling_info_from_lcid(mac, lcid); - /* UL data, for a logical channel which belongs to a LCG, becomes available for transmission in the RLC entity - either the data belongs to a logical channel with higher priority than the priorities of the logical channels - which belong to any LCG and for which data is already available for transmission - */ - { - bsr_regular_triggered = true; + if (rlc_status.bytes_in_buffer > 0) { LOG_D(NR_MAC, - "[UE %d] PDCCH Tick : MAC BSR Triggered LCID%d LCGID%ld data become available at frame %d slot %d\n", + "[UE %d] PDCCH Tick : LCID %d LCGID %d has data to transmit %d bytes at frame %d slot %d\n", mac->ue_id, lcid, - sched_info->LCGID, + lcgid, + rlc_status.bytes_in_buffer, frameP, slotP); - break; - } - } - // Trigger Regular BSR if ReTxBSR Timer has expired and UE has data for transmission - if (mac->scheduling_info.retxBSR_SF == 0) { - bsr_regular_triggered = true; + lc_sched_info->LCID_buffer_with_data = true; - if ((mac->BSR_reporting_active & NR_BSR_TRIGGER_REGULAR) == 0) { - LOG_I(NR_MAC, "[UE %d] PDCCH Tick : MAC BSR Triggered ReTxBSR Timer expiry at frame %d slot %d\n", mac->ue_id, frameP, slotP); + //Update BSR_bytes + mac->scheduling_info.lcg_sched_info[lcgid].BSR_bytes += rlc_status.bytes_in_buffer; + + if (!bsr_regular_triggered) { + bsr_regular_triggered = true; + // call SR procedure to generate pending SR and BSR for next PUCCH/PUSCH TxOp. This should implement the procedures + // outlined in Sections 5.4.4 an 5.4.5 of 38.321 + mac->scheduling_info.SR_pending = 1; + // Regular BSR trigger + mac->BSR_reporting_active |= NR_BSR_TRIGGER_REGULAR; + LOG_D(NR_MAC, + "[UE %d] MAC BSR Triggered LCID %d LCGID %d data become available at frame %d slot %d\n", + mac->ue_id, + lcid, + lcgid, + frameP, + slotP); + // if the BSR is triggered for a logical channel for which logicalChannelSR-DelayTimerApplied with value true + // start or restart the logicalChannelSR-DelayTimer + // else stop the logicalChannelSR-DelayTimer + if (lc_info->sr_DelayTimerApplied) + nr_timer_start(&mac->scheduling_info.sr_DelayTimer); + else + nr_timer_stop(&mac->scheduling_info.sr_DelayTimer); + } } } } - - //Store Buffer Occupancy in remain buffers for next TTI - for (int lcid = 1; lcid <= NR_MAX_NUM_LCID; lcid++) { - NR_LC_SCHEDULING_INFO *sched_info = get_scheduling_info_from_lcid(mac, lcid); - sched_info->LCID_buffer_remain = lcid_bytes_in_buffer[lcid_buffer_index(lcid)]; - } - - return bsr_regular_triggered; } uint8_t nr_locate_BsrIndexByBufferSize(const uint32_t *table, int size, int value) @@ -2627,7 +2555,7 @@ static int nr_ue_get_sdu_mac_ce_pre(NR_UE_MAC_INST_t *mac, mac_ce_p->bsr_header_len = 0; mac_ce_p->phr_header_len = 0; //sizeof(SCH_SUBHEADER_FIXED); int lcg_id = 0; - while (lcg_id < NR_MAX_NUM_LCGID) { + while (lcg_id != NR_INVALID_LCGID) { if (mac->scheduling_info.lcg_sched_info[lcg_id].BSR_bytes) { num_lcg_id_with_data++; } @@ -2759,7 +2687,7 @@ static void nr_ue_get_sdu_mac_ce_post(NR_UE_MAC_INST_t *mac, for (int lcid = 1; lcid <= NR_MAX_NUM_LCID; lcid++) { NR_LC_SCHEDULING_INFO *sched_info = get_scheduling_info_from_lcid(mac, lcid); lcg_id = sched_info->LCGID; - if ((lcg_id < NR_MAX_NUM_LCGID) && (mac->scheduling_info.lcg_sched_info[lcg_id].BSR_bytes)) { + if ((lcg_id != NR_INVALID_LCGID) && (mac->scheduling_info.lcg_sched_info[lcg_id].BSR_bytes)) { lcg_id_bsr_trunc = lcg_id; } } From e60af1c8f68a8e3fceefb4f1ba46e4c7de69e26e Mon Sep 17 00:00:00 2001 From: francescomani Date: Mon, 4 Mar 2024 11:02:50 +0100 Subject: [PATCH 27/39] improvements in retxBSR_Timer implementation --- openair2/LAYER2/NR_MAC_UE/config_ue.c | 51 ++++++++- openair2/LAYER2/NR_MAC_UE/mac_defs.h | 6 +- openair2/LAYER2/NR_MAC_UE/mac_proto.h | 7 -- openair2/LAYER2/NR_MAC_UE/main_ue_nr.c | 9 +- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 116 +++++++------------- 5 files changed, 94 insertions(+), 95 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index d449f089f6..30450c8609 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -1591,6 +1591,50 @@ static uint32_t get_sr_DelayTimer(long logicalChannelSR_DelayTimer) return timer; } +static uint32_t nr_get_sf_retxBSRTimer(long retxBSR_Timer) +{ + uint32_t timer = 0; + switch (retxBSR_Timer) { + case NR_BSR_Config__retxBSR_Timer_sf10: + timer = 10; + break; + case NR_BSR_Config__retxBSR_Timer_sf20: + timer = 20; + break; + case NR_BSR_Config__retxBSR_Timer_sf40: + timer = 40; + break; + case NR_BSR_Config__retxBSR_Timer_sf80: + timer = 80; + break; + case NR_BSR_Config__retxBSR_Timer_sf160: + timer = 160; + break; + case NR_BSR_Config__retxBSR_Timer_sf320: + timer = 320; + break; + case NR_BSR_Config__retxBSR_Timer_sf640: + timer = 640; + break; + case NR_BSR_Config__retxBSR_Timer_sf1280: + timer = 1280; + break; + case NR_BSR_Config__retxBSR_Timer_sf2560: + timer = 2560; + break; + case NR_BSR_Config__retxBSR_Timer_sf5120: + timer = 5120; + break; + case NR_BSR_Config__retxBSR_Timer_sf10240: + timer = 10240; + break; + default: + AssertFatal(false, "Invalid retxBSR_Timer %ld\n", retxBSR_Timer); + } + return timer; +} + + static void configure_maccellgroup(NR_UE_MAC_INST_t *mac, const NR_MAC_CellGroupConfig_t *mcg) { NR_UE_SCHEDULING_INFO *si = &mac->scheduling_info; @@ -1626,10 +1670,11 @@ static void configure_maccellgroup(NR_UE_MAC_INST_t *mac, const NR_MAC_CellGroup if (mcg->bsr_Config) { int subframes_per_slot = nr_slots_per_frame[mac->current_UL_BWP->scs] / 10; si->periodicBSR_Timer = mcg->bsr_Config->periodicBSR_Timer; - si->retxBSR_Timer = mcg->bsr_Config->retxBSR_Timer; + uint32_t retx_sf = nr_get_sf_retxBSRTimer(mcg->bsr_Config->retxBSR_Timer); + nr_timer_setup(&si->retxBSR_Timer, retx_sf * subframes_per_slot, 1); // 1 slot update rate if (mcg->bsr_Config->logicalChannelSR_DelayTimer) { - uint32_t target_sf = get_sr_DelayTimer(*mcg->bsr_Config->logicalChannelSR_DelayTimer); - nr_timer_setup(&si->sr_DelayTimer, target_sf * subframes_per_slot, 1); // 1 slot update rate + uint32_t dt_sf = get_sr_DelayTimer(*mcg->bsr_Config->logicalChannelSR_DelayTimer); + nr_timer_setup(&si->sr_DelayTimer, dt_sf * subframes_per_slot, 1); // 1 slot update rate } } if (mcg->tag_Config) { diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h index 259c7cc2b1..c06918a948 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h @@ -214,10 +214,8 @@ typedef struct { uint16_t SR_COUNTER; // logicalChannelSR-DelayTimer NR_timer_t sr_DelayTimer; - /// retxBSR-Timer, default value is sf2560 - uint16_t retxBSR_Timer; - /// retxBSR_SF, number of subframe before triggering a regular BSR - uint16_t retxBSR_SF; + /// retxBSR-Timer + NR_timer_t retxBSR_Timer; /// periodicBSR-Timer, default to infinity uint16_t periodicBSR_Timer; /// periodicBSR_SF, number of subframe before triggering a periodic BSR diff --git a/openair2/LAYER2/NR_MAC_UE/mac_proto.h b/openair2/LAYER2/NR_MAC_UE/mac_proto.h index 109e7455b5..fef9810d39 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_proto.h @@ -146,13 +146,6 @@ uint8_t nr_locate_BsrIndexByBufferSize(const uint32_t *table, int size, */ int nr_get_sf_periodicBSRTimer(uint8_t bucketSize); -/*! \fn int nr_get_sf_retxBSRTimer(uint8_t retxBSR_Timer) - \brief get the number of subframe form the bucket size duration configured by the higher layer -\param[in] retxBSR_Timer timer for regular BSR -\return the time in sf -*/ -int nr_get_sf_retxBSRTimer(uint8_t retxBSR_Timer); - int8_t nr_ue_process_dci(NR_UE_MAC_INST_t *mac, int cc_id, frame_t frame, diff --git a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c index bb9f1437e7..55bc8a4101 100644 --- a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c +++ b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c @@ -84,7 +84,12 @@ void nr_ue_init_mac(NR_UE_MAC_INST_t *mac) void nr_ue_mac_default_configs(NR_UE_MAC_INST_t *mac) { // default values as defined in 38.331 sec 9.2.2 - mac->scheduling_info.retxBSR_Timer = NR_BSR_Config__retxBSR_Timer_sf80; + + // sf80 default for retxBSR_Timer + int mu = mac->current_UL_BWP ? mac->current_UL_BWP->scs : get_softmodem_params()->numerology; + int subframes_per_slot = nr_slots_per_frame[mu] / 10; + nr_timer_setup(&mac->scheduling_info.retxBSR_Timer, 80 * subframes_per_slot, 1); // 1 slot update rate + mac->scheduling_info.periodicBSR_Timer = NR_BSR_Config__periodicBSR_Timer_sf10; mac->scheduling_info.periodicPHR_Timer = NR_PHR_Config__phr_PeriodicTimer_sf10; mac->scheduling_info.prohibitPHR_Timer = NR_PHR_Config__phr_ProhibitTimer_sf10; @@ -160,6 +165,7 @@ void reset_mac_inst(NR_UE_MAC_INST_t *nr_mac) } nr_timer_stop(&nr_mac->ra.contention_resolution_timer); nr_timer_stop(&nr_mac->scheduling_info.sr_DelayTimer); + nr_timer_stop(&nr_mac->scheduling_info.retxBSR_Timer); // consider all timeAlignmentTimers as expired and perform the corresponding actions in clause 5.2 // TODO @@ -187,7 +193,6 @@ void reset_mac_inst(NR_UE_MAC_INST_t *nr_mac) // cancel any triggered Buffer Status Reporting procedure nr_mac->scheduling_info.periodicBSR_SF = NR_MAC_UE_BSR_TIMER_NOT_RUNNING; - nr_mac->scheduling_info.retxBSR_SF = NR_MAC_UE_BSR_TIMER_NOT_RUNNING; nr_mac->BSR_reporting_active = NR_BSR_TRIGGER_NONE; // cancel any triggered Power Headroom Reporting procedure diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 6f3510d6c4..363e3981a2 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -115,10 +115,40 @@ NR_LC_SCHEDULING_INFO *get_scheduling_info_from_lcid(NR_UE_MAC_INST_t *mac, NR_L return &mac->scheduling_info.lc_sched_info[idx]; } +static void trigger_regular_bsr(NR_UE_MAC_INST_t *mac, bool sr_DelayTimerApplied) +{ + // call SR procedure to generate pending SR and BSR for next PUCCH/PUSCH TxOp. This should implement the procedures + // outlined in Sections 5.4.4 an 5.4.5 of 38.321 + mac->scheduling_info.SR_pending = 1; + // Regular BSR trigger + mac->BSR_reporting_active |= NR_BSR_TRIGGER_REGULAR; + // if the BSR is triggered for a logical channel for which logicalChannelSR-DelayTimerApplied with value true + // start or restart the logicalChannelSR-DelayTimer + // else stop the logicalChannelSR-DelayTimer + if (sr_DelayTimerApplied) + nr_timer_start(&mac->scheduling_info.sr_DelayTimer); + else + nr_timer_stop(&mac->scheduling_info.sr_DelayTimer); +} + void update_mac_timers(NR_UE_MAC_INST_t *mac) { nr_timer_tick(&mac->ra.contention_resolution_timer); nr_timer_tick(&mac->scheduling_info.sr_DelayTimer); + bool retxBSR_expired = nr_timer_tick(&mac->scheduling_info.retxBSR_Timer); + if (retxBSR_expired) { + LOG_D(NR_MAC, "retxBSR timer expired\n"); + for (int i = 0; i < mac->lc_ordered_list.count; i++) { + nr_lcordered_info_t *lc_info = mac->lc_ordered_list.array[i]; + NR_LogicalChannelIdentity_t lcid = lc_info->lcid; + // if at least one of the logical channels which belong to an LCG contains UL data + NR_LC_SCHEDULING_INFO *lc_sched_info = get_scheduling_info_from_lcid(mac, lcid); + if (lc_sched_info->LCGID < NR_MAX_NUM_LCGID && lc_sched_info->LCID_buffer_remain > 0) { + LOG_D(NR_MAC, "Triggering regular BSR after retxBSR timer expired\n"); + trigger_regular_bsr(mac, lc_info->sr_DelayTimerApplied); + } + } + } for (int i = 0; i < NR_MAX_NUM_LCID; i++) AssertFatal(!nr_timer_tick(&mac->scheduling_info.lc_sched_info[i].Bj_timer), "Bj timer for LCID %d expired! That should never happen\n", @@ -574,7 +604,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, //Optional Data only included if indicated in pduBitmap pusch_config_pdu->pusch_data.rv_index = 0; // 8.3 in 38.213 pusch_config_pdu->pusch_data.harq_process_id = 0; - pusch_config_pdu->pusch_data.new_data_indicator = 1; // new data + pusch_config_pdu->pusch_data.new_data_indicator = true; // new data pusch_config_pdu->pusch_data.num_cb = 0; pusch_config_pdu->tbslbrm = 0; @@ -825,6 +855,10 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, pusch_config_pdu->ldpcBaseGraph = get_BG(pusch_config_pdu->pusch_data.tb_size << 3, pusch_config_pdu->target_code_rate); + //The MAC entity shall restart retxBSR-Timer upon reception of a grant for transmission of new data on any UL-SCH + if (pusch_config_pdu->pusch_data.new_data_indicator && dci && dci->ulsch_indicator) + nr_timer_start(&mac->scheduling_info.retxBSR_Timer); + if (pusch_config_pdu->pusch_data.tb_size == 0) { LOG_E(MAC, "Invalid TBS = 0. Probably caused by missed detection of DCI\n"); return -1; @@ -1180,12 +1214,6 @@ void nr_ue_ul_scheduler(NR_UE_MAC_INST_t *mac, nr_uplink_indication_t *ul_info) // Call BSR procedure as described in Section 5.4.5 in 38.321 - // First check ReTxBSR Timer because it is always configured - // Decrement ReTxBSR Timer if it is running and not null - if ((mac->scheduling_info.retxBSR_SF != NR_MAC_UE_BSR_TIMER_NOT_RUNNING) && (mac->scheduling_info.retxBSR_SF != 0)) { - mac->scheduling_info.retxBSR_SF--; - } - // Decrement Periodic Timer if it is running and not null if ((mac->scheduling_info.periodicBSR_SF != NR_MAC_UE_BSR_TIMER_NOT_RUNNING) && (mac->scheduling_info.periodicBSR_SF != 0)) { mac->scheduling_info.periodicBSR_SF--; @@ -1250,11 +1278,7 @@ void nr_update_bsr(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t slotP, uint8_t if (!bsr_regular_triggered) { bsr_regular_triggered = true; - // call SR procedure to generate pending SR and BSR for next PUCCH/PUSCH TxOp. This should implement the procedures - // outlined in Sections 5.4.4 an 5.4.5 of 38.321 - mac->scheduling_info.SR_pending = 1; - // Regular BSR trigger - mac->BSR_reporting_active |= NR_BSR_TRIGGER_REGULAR; + trigger_regular_bsr(mac, lc_info->sr_DelayTimerApplied); LOG_D(NR_MAC, "[UE %d] MAC BSR Triggered LCID %d LCGID %d data become available at frame %d slot %d\n", mac->ue_id, @@ -1262,13 +1286,6 @@ void nr_update_bsr(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t slotP, uint8_t lcgid, frameP, slotP); - // if the BSR is triggered for a logical channel for which logicalChannelSR-DelayTimerApplied with value true - // start or restart the logicalChannelSR-DelayTimer - // else stop the logicalChannelSR-DelayTimer - if (lc_info->sr_DelayTimerApplied) - nr_timer_start(&mac->scheduling_info.sr_DelayTimer); - else - nr_timer_stop(&mac->scheduling_info.sr_DelayTimer); } } } @@ -1379,58 +1396,6 @@ int nr_get_sf_periodicBSRTimer(uint8_t sf_offset) { } } -int nr_get_sf_retxBSRTimer(uint8_t sf_offset) { - switch (sf_offset) { - case NR_BSR_Config__retxBSR_Timer_sf10: - return 10; - break; - - case NR_BSR_Config__retxBSR_Timer_sf20: - return 20; - break; - - case NR_BSR_Config__retxBSR_Timer_sf40: - return 40; - break; - - case NR_BSR_Config__retxBSR_Timer_sf80: - return 80; - break; - - case NR_BSR_Config__retxBSR_Timer_sf160: - return 160; - break; - - case NR_BSR_Config__retxBSR_Timer_sf320: - return 320; - break; - - case NR_BSR_Config__retxBSR_Timer_sf640: - return 640; - break; - - case NR_BSR_Config__retxBSR_Timer_sf1280: - return 1280; - break; - - case NR_BSR_Config__retxBSR_Timer_sf2560: - return 2560; - break; - - case NR_BSR_Config__retxBSR_Timer_sf5120: - return 5120; - break; - - case NR_BSR_Config__retxBSR_Timer_sf10240: - return 10240; - break; - - default: - return -1; - break; - } -} - // PUSCH scheduler: // - Calculate the slot in which ULSCH should be scheduled. This is current slot + K2, // - where K2 is the offset between the slot in which UL DCI is received and the slot @@ -2563,11 +2528,6 @@ static int nr_ue_get_sdu_mac_ce_pre(NR_UE_MAC_INST_t *mac, lcg_id++; } - //Restart ReTxBSR Timer at new grant indication (38.321) - if (mac->scheduling_info.retxBSR_SF != NR_MAC_UE_BSR_TIMER_NOT_RUNNING) { - mac->scheduling_info.retxBSR_SF = nr_get_sf_retxBSRTimer(mac->scheduling_info.retxBSR_Timer); - } - // periodicBSR-Timer expires, trigger BSR if ((mac->scheduling_info.periodicBSR_Timer != NR_BSR_Config__periodicBSR_Timer_infinity) && (mac->scheduling_info.periodicBSR_SF == 0)) { @@ -2780,9 +2740,7 @@ static void nr_ue_get_sdu_mac_ce_post(NR_UE_MAC_INST_t *mac, mac_ce_p->bsr_header_len, buflen); // Reset ReTx BSR Timer - mac->scheduling_info.retxBSR_SF = nr_get_sf_retxBSRTimer(mac->scheduling_info.retxBSR_Timer); - LOG_D(NR_MAC, "[UE %d] MAC ReTx BSR Timer Reset =%d\n", mac->ue_id, mac->scheduling_info.retxBSR_SF); - + nr_timer_start(&mac->scheduling_info.retxBSR_Timer); // Reset Periodic Timer except when BSR is truncated if ((mac_ce_p->bsr_t == NULL) && (mac->scheduling_info.periodicBSR_Timer != NR_BSR_Config__periodicBSR_Timer_infinity)) { mac->scheduling_info.periodicBSR_SF = nr_get_sf_periodicBSRTimer(mac->scheduling_info.periodicBSR_Timer); From 310f62604cd7f4669c535f37cab661714e512f19 Mon Sep 17 00:00:00 2001 From: francescomani Date: Mon, 4 Mar 2024 16:00:13 +0100 Subject: [PATCH 28/39] improvements in periodicBSR_Timer implementation --- openair2/LAYER2/NR_MAC_UE/config_ue.c | 61 ++++++++++++- openair2/LAYER2/NR_MAC_UE/mac_defs.h | 10 +-- openair2/LAYER2/NR_MAC_UE/mac_proto.h | 7 -- openair2/LAYER2/NR_MAC_UE/main_ue_nr.c | 5 +- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 99 ++------------------- 5 files changed, 73 insertions(+), 109 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index 30450c8609..ac5a0fd02e 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -1634,6 +1634,62 @@ static uint32_t nr_get_sf_retxBSRTimer(long retxBSR_Timer) return timer; } +static uint32_t nr_get_sf_periodicBSRTimer(long periodicBSR) +{ + uint32_t timer = 0; + switch (periodicBSR) { + case NR_BSR_Config__periodicBSR_Timer_sf1: + timer = 1; + break; + case NR_BSR_Config__periodicBSR_Timer_sf5: + timer = 5; + break; + case NR_BSR_Config__periodicBSR_Timer_sf10: + timer = 10; + break; + case NR_BSR_Config__periodicBSR_Timer_sf16: + timer = 16; + break; + case NR_BSR_Config__periodicBSR_Timer_sf20: + timer = 20; + break; + case NR_BSR_Config__periodicBSR_Timer_sf32: + timer = 32; + break; + case NR_BSR_Config__periodicBSR_Timer_sf40: + timer = 40; + break; + case NR_BSR_Config__periodicBSR_Timer_sf64: + timer = 64; + break; + case NR_BSR_Config__periodicBSR_Timer_sf80: + timer = 80; + break; + case NR_BSR_Config__periodicBSR_Timer_sf128: + timer = 128; + break; + case NR_BSR_Config__periodicBSR_Timer_sf160: + timer = 160; + break; + case NR_BSR_Config__periodicBSR_Timer_sf320: + timer = 320; + break; + case NR_BSR_Config__periodicBSR_Timer_sf640: + timer = 640; + break; + case NR_BSR_Config__periodicBSR_Timer_sf1280: + timer = 1280; + break; + case NR_BSR_Config__periodicBSR_Timer_sf2560: + timer = 2560; + break; + case NR_BSR_Config__periodicBSR_Timer_infinity: + timer = UINT_MAX; + default: + AssertFatal(false, "Invalid periodicBSR_Timer %ld\n", periodicBSR); + } + return timer; +} static void configure_maccellgroup(NR_UE_MAC_INST_t *mac, const NR_MAC_CellGroupConfig_t *mcg) { @@ -1669,7 +1725,10 @@ static void configure_maccellgroup(NR_UE_MAC_INST_t *mac, const NR_MAC_CellGroup } if (mcg->bsr_Config) { int subframes_per_slot = nr_slots_per_frame[mac->current_UL_BWP->scs] / 10; - si->periodicBSR_Timer = mcg->bsr_Config->periodicBSR_Timer; + uint32_t periodic_sf = nr_get_sf_periodicBSRTimer(mcg->bsr_Config->periodicBSR_Timer); + uint32_t target = periodic_sf < UINT_MAX ? periodic_sf * subframes_per_slot : periodic_sf; + nr_timer_setup(&si->periodicBSR_Timer, target, 1); // 1 slot update rate + nr_timer_start(&si->periodicBSR_Timer); uint32_t retx_sf = nr_get_sf_retxBSRTimer(mcg->bsr_Config->retxBSR_Timer); nr_timer_setup(&si->retxBSR_Timer, retx_sf * subframes_per_slot, 1); // 1 slot update rate if (mcg->bsr_Config->logicalChannelSR_DelayTimer) { diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h index c06918a948..cb589a1ae3 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h @@ -216,10 +216,8 @@ typedef struct { NR_timer_t sr_DelayTimer; /// retxBSR-Timer NR_timer_t retxBSR_Timer; - /// periodicBSR-Timer, default to infinity - uint16_t periodicBSR_Timer; - /// periodicBSR_SF, number of subframe before triggering a periodic BSR - uint16_t periodicBSR_SF; + /// periodicBSR-Timer + NR_timer_t periodicBSR_Timer; /// default value is 0: not configured uint16_t sr_ProhibitTimer; /// sr ProhibitTime running @@ -239,10 +237,6 @@ typedef struct { int16_t prohibitPHR_SF; ///DL Pathloss Change in db uint16_t PathlossChange_db; - /// default value is false - uint16_t extendedBSR_Sizes_r10; - /// default value is false - uint16_t extendedPHR_r10; } NR_UE_SCHEDULING_INFO; typedef enum { diff --git a/openair2/LAYER2/NR_MAC_UE/mac_proto.h b/openair2/LAYER2/NR_MAC_UE/mac_proto.h index fef9810d39..4aeb902c56 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_proto.h @@ -139,13 +139,6 @@ void nr_update_bsr(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t slotP, uint8_t uint8_t nr_locate_BsrIndexByBufferSize(const uint32_t *table, int size, int value); -/*! \fn int nr_get_sf_periodicBSRTimer(uint8_t periodicBSR_Timer) - \brief get the number of subframe from the periodic BSR timer configured by the higher layers -\param[in] periodicBSR_Timer timer for periodic BSR -\return the number of subframe -*/ -int nr_get_sf_periodicBSRTimer(uint8_t bucketSize); - int8_t nr_ue_process_dci(NR_UE_MAC_INST_t *mac, int cc_id, frame_t frame, diff --git a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c index 55bc8a4101..be9434f1a3 100644 --- a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c +++ b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c @@ -85,12 +85,12 @@ void nr_ue_mac_default_configs(NR_UE_MAC_INST_t *mac) { // default values as defined in 38.331 sec 9.2.2 - // sf80 default for retxBSR_Timer + // sf80 default for retxBSR_Timer sf10 for periodicBSR_Timer int mu = mac->current_UL_BWP ? mac->current_UL_BWP->scs : get_softmodem_params()->numerology; int subframes_per_slot = nr_slots_per_frame[mu] / 10; nr_timer_setup(&mac->scheduling_info.retxBSR_Timer, 80 * subframes_per_slot, 1); // 1 slot update rate + nr_timer_setup(&mac->scheduling_info.periodicBSR_Timer, 10 * subframes_per_slot, 1); // 1 slot update rate - mac->scheduling_info.periodicBSR_Timer = NR_BSR_Config__periodicBSR_Timer_sf10; mac->scheduling_info.periodicPHR_Timer = NR_PHR_Config__phr_PeriodicTimer_sf10; mac->scheduling_info.prohibitPHR_Timer = NR_PHR_Config__phr_ProhibitTimer_sf10; } @@ -192,7 +192,6 @@ void reset_mac_inst(NR_UE_MAC_INST_t *nr_mac) nr_mac->scheduling_info.sr_id = -1; // invalid init value // cancel any triggered Buffer Status Reporting procedure - nr_mac->scheduling_info.periodicBSR_SF = NR_MAC_UE_BSR_TIMER_NOT_RUNNING; nr_mac->BSR_reporting_active = NR_BSR_TRIGGER_NONE; // cancel any triggered Power Headroom Reporting procedure diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 363e3981a2..d1d2067df5 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -149,6 +149,12 @@ void update_mac_timers(NR_UE_MAC_INST_t *mac) } } } + bool periodicBSR_expired = nr_timer_tick(&mac->scheduling_info.periodicBSR_Timer); + if (periodicBSR_expired) { + // periodicBSR-Timer expires, trigger BSR + mac->BSR_reporting_active |= NR_BSR_TRIGGER_PERIODIC; + LOG_D(NR_MAC, "[UE %d] MAC BSR Triggered PeriodicBSR Timer expiry\n", mac->ue_id); + } for (int i = 0; i < NR_MAX_NUM_LCID; i++) AssertFatal(!nr_timer_tick(&mac->scheduling_info.lc_sched_info[i].Bj_timer), "Bj timer for LCID %d expired! That should never happen\n", @@ -1214,11 +1220,6 @@ void nr_ue_ul_scheduler(NR_UE_MAC_INST_t *mac, nr_uplink_indication_t *ul_info) // Call BSR procedure as described in Section 5.4.5 in 38.321 - // Decrement Periodic Timer if it is running and not null - if ((mac->scheduling_info.periodicBSR_SF != NR_MAC_UE_BSR_TIMER_NOT_RUNNING) && (mac->scheduling_info.periodicBSR_SF != 0)) { - mac->scheduling_info.periodicBSR_SF--; - } - //Check whether BSR is triggered nr_update_bsr(mac, frame_tx, slot_tx, gNB_index); @@ -1327,75 +1328,6 @@ uint8_t nr_locate_BsrIndexByBufferSize(const uint32_t *table, int size, int valu } } -int nr_get_sf_periodicBSRTimer(uint8_t sf_offset) { - switch (sf_offset) { - case NR_BSR_Config__periodicBSR_Timer_sf1: - return 1; - break; - - case NR_BSR_Config__periodicBSR_Timer_sf5: - return 5; - break; - - case NR_BSR_Config__periodicBSR_Timer_sf10: - return 10; - break; - - case NR_BSR_Config__periodicBSR_Timer_sf16: - return 16; - break; - - case NR_BSR_Config__periodicBSR_Timer_sf20: - return 20; - break; - - case NR_BSR_Config__periodicBSR_Timer_sf32: - return 32; - break; - - case NR_BSR_Config__periodicBSR_Timer_sf40: - return 40; - break; - - case NR_BSR_Config__periodicBSR_Timer_sf64: - return 64; - break; - - case NR_BSR_Config__periodicBSR_Timer_sf80: - return 80; - break; - - case NR_BSR_Config__periodicBSR_Timer_sf128: - return 128; - break; - - case NR_BSR_Config__periodicBSR_Timer_sf160: - return 160; - break; - - case NR_BSR_Config__periodicBSR_Timer_sf320: - return 320; - break; - - case NR_BSR_Config__periodicBSR_Timer_sf640: - return 640; - break; - - case NR_BSR_Config__periodicBSR_Timer_sf1280: - return 1280; - break; - - case NR_BSR_Config__periodicBSR_Timer_sf2560: - return 2560; - break; - - case NR_BSR_Config__periodicBSR_Timer_infinity: - default: - return 0xFFFF; - break; - } -} - // PUSCH scheduler: // - Calculate the slot in which ULSCH should be scheduled. This is current slot + K2, // - where K2 is the offset between the slot in which UL DCI is received and the slot @@ -2528,19 +2460,6 @@ static int nr_ue_get_sdu_mac_ce_pre(NR_UE_MAC_INST_t *mac, lcg_id++; } - // periodicBSR-Timer expires, trigger BSR - if ((mac->scheduling_info.periodicBSR_Timer != NR_BSR_Config__periodicBSR_Timer_infinity) - && (mac->scheduling_info.periodicBSR_SF == 0)) { - // Trigger BSR Periodic - mac->BSR_reporting_active |= NR_BSR_TRIGGER_PERIODIC; - LOG_D(NR_MAC, - "[UE %d] MAC BSR Triggered PeriodicBSR Timer expiry at frame%d subframe %d TBS=%d\n", - mac->ue_id, - frameP, - subframe, - buflen); - } - //Compute BSR Length if Regular or Periodic BSR is triggered //WARNING: if BSR long is computed, it may be changed to BSR short during or after multiplexing if there remains less than 1 LCGROUP with data after Tx if (mac->BSR_reporting_active) { @@ -2742,9 +2661,9 @@ static void nr_ue_get_sdu_mac_ce_post(NR_UE_MAC_INST_t *mac, // Reset ReTx BSR Timer nr_timer_start(&mac->scheduling_info.retxBSR_Timer); // Reset Periodic Timer except when BSR is truncated - if ((mac_ce_p->bsr_t == NULL) && (mac->scheduling_info.periodicBSR_Timer != NR_BSR_Config__periodicBSR_Timer_infinity)) { - mac->scheduling_info.periodicBSR_SF = nr_get_sf_periodicBSRTimer(mac->scheduling_info.periodicBSR_Timer); - LOG_D(NR_MAC, "[UE %d] MAC Periodic BSR Timer Reset =%d\n", mac->ue_id, mac->scheduling_info.periodicBSR_SF); + if (mac_ce_p->bsr_t == NULL) { + nr_timer_start(&mac->scheduling_info.periodicBSR_Timer); + LOG_D(NR_MAC, "[UE %d] MAC Periodic BSR Timer Reset\n", mac->ue_id); } // Reset BSR Trigger flags From c090b1f767c6e73f650f946abac30b7a051010ae Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 5 Mar 2024 12:31:52 +0100 Subject: [PATCH 29/39] further improvements in BSR handling after being triggered --- openair2/LAYER2/NR_MAC_UE/config_ue.c | 1 + openair2/LAYER2/NR_MAC_UE/mac_defs.h | 8 +- openair2/LAYER2/NR_MAC_UE/mac_proto.h | 19 - openair2/LAYER2/NR_MAC_UE/main_ue_nr.c | 2 +- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 3 +- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 346 ++++++++++--------- 6 files changed, 195 insertions(+), 184 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index ac5a0fd02e..6387b6f1a3 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -756,6 +756,7 @@ static void nr_configure_lc_config(NR_UE_MAC_INST_t *mac, struct NR_LogicalChannelConfig__ul_SpecificParameters *ul_parm = mac_lc_config->ul_SpecificParameters; lc_info->priority = ul_parm->priority; lc_info->sr_DelayTimerApplied = ul_parm->logicalChannelSR_DelayTimerApplied; + lc_info->lc_SRMask = ul_parm->logicalChannelSR_Mask; lc_info->pbr = nr_get_pbr(ul_parm->prioritisedBitRate); // if logicalChannelGroup we release LCGID and set it to invalid lc_sched_info->LCGID = ul_parm->logicalChannelGroup ? *ul_parm->logicalChannelGroup : NR_INVALID_LCGID; diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h index cb589a1ae3..4a79b6e38d 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h @@ -208,6 +208,10 @@ typedef struct { NR_LC_SCHEDULING_INFO lc_sched_info[NR_MAX_NUM_LCID]; // lcg scheduling info NR_LCG_SCHEDULING_INFO lcg_sched_info[NR_MAX_NUM_LCGID]; + /// BSR report flag management + uint8_t BSR_reporting_active; + // LCID triggering BSR + NR_LogicalChannelIdentity_t regularBSR_trigger_lcid; /// SR pending as defined in 38.321 uint8_t SR_pending; /// SR_COUNTER as defined in 38.321 @@ -447,6 +451,7 @@ typedef struct nr_lcordered_info_s { // Bucket size per lcid uint32_t bucket_size; bool sr_DelayTimerApplied; + bool lc_SRMask; } nr_lcordered_info_t; @@ -524,9 +529,6 @@ typedef struct NR_UE_MAC_INST_s { nr_phy_config_t phy_config; nr_synch_request_t synch_request; - /// BSR report flag management - uint8_t BSR_reporting_active; - // order lc info A_SEQUENCE_OF(nr_lcordered_info_t) lc_ordered_list; diff --git a/openair2/LAYER2/NR_MAC_UE/mac_proto.h b/openair2/LAYER2/NR_MAC_UE/mac_proto.h index 4aeb902c56..0dfe61e3b1 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_proto.h @@ -120,25 +120,6 @@ subframe number \param[in] slotP slot number */ int8_t nr_ue_get_SR(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t slotP); -/*! \fn nr_update_bsr - \brief get the rlc stats and update the bsr level for each lcid -\param[in] mac pointer to UE MAC instance -\param[in] frameP Frame index -\param[in] slotP number -\param[in] gNB_index -*/ -void nr_update_bsr(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t slotP, uint8_t gNB_index); - -/*! \fn nr_locate_BsrIndexByBufferSize (int *table, int size, int value) - \brief locate the BSR level in the table as defined in 38.321. This function requires that he values in table to be monotonic, either increasing or decreasing. The returned value is not less than 0, nor greater than n-1, where n is the size of table. -\param[in] *table Pointer to BSR table -\param[in] size Size of the table -\param[in] value Value of the buffer -\return the index in the BSR_LEVEL table -*/ -uint8_t nr_locate_BsrIndexByBufferSize(const uint32_t *table, int size, - int value); - int8_t nr_ue_process_dci(NR_UE_MAC_INST_t *mac, int cc_id, frame_t frame, diff --git a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c index be9434f1a3..be7f83bf92 100644 --- a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c +++ b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c @@ -192,7 +192,7 @@ void reset_mac_inst(NR_UE_MAC_INST_t *nr_mac) nr_mac->scheduling_info.sr_id = -1; // invalid init value // cancel any triggered Buffer Status Reporting procedure - nr_mac->BSR_reporting_active = NR_BSR_TRIGGER_NONE; + nr_mac->scheduling_info.BSR_reporting_active = NR_BSR_TRIGGER_NONE; // cancel any triggered Power Headroom Reporting procedure // TODO PHR not implemented yet diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 3ef15ce4d4..73a373af9b 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -2511,8 +2511,7 @@ int8_t nr_ue_get_SR(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t slot) // release all pucch resource //mac->physicalConfigDedicated = NULL; // todo //mac->ul_active = 0; // todo - mac->BSR_reporting_active = - NR_BSR_TRIGGER_NONE; + si->BSR_reporting_active = NR_BSR_TRIGGER_NONE; LOG_I(NR_MAC, "[UE %d] Release all SRs \n", mac->ue_id); } si->SR_pending = 0; diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index d1d2067df5..7bd757c977 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -115,13 +115,12 @@ NR_LC_SCHEDULING_INFO *get_scheduling_info_from_lcid(NR_UE_MAC_INST_t *mac, NR_L return &mac->scheduling_info.lc_sched_info[idx]; } -static void trigger_regular_bsr(NR_UE_MAC_INST_t *mac, bool sr_DelayTimerApplied) +static void trigger_regular_bsr(NR_UE_MAC_INST_t *mac, NR_LogicalChannelIdentity_t lcid, bool sr_DelayTimerApplied) { - // call SR procedure to generate pending SR and BSR for next PUCCH/PUSCH TxOp. This should implement the procedures - // outlined in Sections 5.4.4 an 5.4.5 of 38.321 - mac->scheduling_info.SR_pending = 1; // Regular BSR trigger - mac->BSR_reporting_active |= NR_BSR_TRIGGER_REGULAR; + mac->scheduling_info.BSR_reporting_active |= NR_BSR_TRIGGER_REGULAR; + mac->scheduling_info.regularBSR_trigger_lcid = lcid; + LOG_D(NR_MAC, "Triggering regular BSR for LCID %ld\n", lcid); // if the BSR is triggered for a logical channel for which logicalChannelSR-DelayTimerApplied with value true // start or restart the logicalChannelSR-DelayTimer // else stop the logicalChannelSR-DelayTimer @@ -143,16 +142,17 @@ void update_mac_timers(NR_UE_MAC_INST_t *mac) NR_LogicalChannelIdentity_t lcid = lc_info->lcid; // if at least one of the logical channels which belong to an LCG contains UL data NR_LC_SCHEDULING_INFO *lc_sched_info = get_scheduling_info_from_lcid(mac, lcid); - if (lc_sched_info->LCGID < NR_MAX_NUM_LCGID && lc_sched_info->LCID_buffer_remain > 0) { + if (lc_sched_info->LCGID != NR_INVALID_LCGID && lc_sched_info->LCID_buffer_remain > 0) { LOG_D(NR_MAC, "Triggering regular BSR after retxBSR timer expired\n"); - trigger_regular_bsr(mac, lc_info->sr_DelayTimerApplied); + trigger_regular_bsr(mac, lcid, lc_info->sr_DelayTimerApplied); + break; } } } bool periodicBSR_expired = nr_timer_tick(&mac->scheduling_info.periodicBSR_Timer); if (periodicBSR_expired) { // periodicBSR-Timer expires, trigger BSR - mac->BSR_reporting_active |= NR_BSR_TRIGGER_PERIODIC; + mac->scheduling_info.BSR_reporting_active |= NR_BSR_TRIGGER_PERIODIC; LOG_D(NR_MAC, "[UE %d] MAC BSR Triggered PeriodicBSR Timer expiry\n", mac->ue_id); } for (int i = 0; i < NR_MAX_NUM_LCID; i++) @@ -1106,6 +1106,97 @@ void nr_ue_dl_scheduler(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_info LOG_E(NR_MAC, "Internal error, no scheduled_response function\n"); } +static void nr_trigger_sr(NR_UE_MAC_INST_t *mac) +{ + NR_UE_SCHEDULING_INFO *sched_info = &mac->scheduling_info; + // if a Regular BSR has been triggered and logicalChannelSR-DelayTimer is not running + if (((sched_info->BSR_reporting_active & NR_BSR_TRIGGER_REGULAR) == 0) + || is_nr_timer_active(sched_info->sr_DelayTimer)) + return; + + nr_lcordered_info_t *lc_info = get_lc_info_from_lcid(mac, sched_info->regularBSR_trigger_lcid); + AssertFatal(lc_info, "Couldn't find logical channel with LCID %ld\n", sched_info->regularBSR_trigger_lcid); + + // if there is no UL-SCH resource available for a new transmission (ie we are at this point) + + // if the MAC entity is configured with configured uplink grant(s) and the Regular BSR was triggered for a + // logical channel for which logicalChannelSR-Mask is set to false or + if (mac->current_UL_BWP->configuredGrantConfig && lc_info->lc_SRMask) + return; + // if the UL-SCH resources available for a new transmission do not meet the LCP mapping restrictions + // TODO not implemented + + // trigger SR + sched_info->SR_pending = 1; +} + +static void nr_update_bsr(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t slotP, uint8_t gNB_index) +{ + // Reset All BSR Infos + for (int id = 0; id < NR_MAX_NUM_LCID; id++) { + // Reset transmission status + mac->scheduling_info.lc_sched_info[id].LCID_buffer_with_data = false; + } + + for (int lcgid = 0; lcgid < NR_MAX_NUM_LCGID; lcgid++) { + // Reset Buffer Info + mac->scheduling_info.lcg_sched_info[lcgid].BSR = 0; + mac->scheduling_info.lcg_sched_info[lcgid].BSR_bytes = 0; + } + + bool bsr_regular_triggered = mac->scheduling_info.BSR_reporting_active & NR_BSR_TRIGGER_REGULAR; + for (int i = 0; i < mac->lc_ordered_list.count; i++) { + nr_lcordered_info_t *lc_info = mac->lc_ordered_list.array[i]; + int lcid = lc_info->lcid; + NR_LC_SCHEDULING_INFO *lc_sched_info = get_scheduling_info_from_lcid(mac, lcid); + int lcgid = lc_sched_info->LCGID; + + // check if UL data for a logical channel which belongs to a LCG becomes available for transmission + if (lcgid != NR_INVALID_LCGID) { + mac_rlc_status_resp_t rlc_status = mac_rlc_status_ind(mac->ue_id, + mac->ue_id, + gNB_index, + frameP, + slotP, + ENB_FLAG_NO, + MBMS_FLAG_NO, + lcid, + 0, + 0); + + lc_sched_info->LCID_buffer_remain = rlc_status.bytes_in_buffer; + + if (rlc_status.bytes_in_buffer > 0) { + LOG_D(NR_MAC, + "[UE %d] LCID %d LCGID %d has %d bytes to transmit at frame %d slot %d\n", + mac->ue_id, + lcid, + lcgid, + rlc_status.bytes_in_buffer, + frameP, + slotP); + + lc_sched_info->LCID_buffer_with_data = true; + + //Update BSR_bytes + mac->scheduling_info.lcg_sched_info[lcgid].BSR_bytes += rlc_status.bytes_in_buffer; + + if (!bsr_regular_triggered) { + bsr_regular_triggered = true; + trigger_regular_bsr(mac, lcid, lc_info->sr_DelayTimerApplied); + LOG_D(NR_MAC, + "[UE %d] MAC BSR Triggered LCID %d LCGID %d data become available at %d.%d\n", + mac->ue_id, + lcid, + lcgid, + frameP, + slotP); + } + } + } + } +} + void nr_ue_ul_scheduler(NR_UE_MAC_INST_t *mac, nr_uplink_indication_t *ul_info) { int cc_id = ul_info->cc_id; @@ -1123,6 +1214,11 @@ void nr_ue_ul_scheduler(NR_UE_MAC_INST_t *mac, nr_uplink_indication_t *ul_info) if(mac->state == UE_CONNECTED) nr_ue_periodic_srs_scheduling(mac, frame_tx, slot_tx); + // Call BSR procedure as described in Section 5.4.5 in 38.321 + // Check whether BSR is triggered before scheduling ULSCH + if(mac->state == UE_CONNECTED) + nr_update_bsr(mac, frame_tx, slot_tx, gNB_index); + // Schedule ULSCH only if the current frame and slot match those in ul_config_req // AND if a UL grant (UL DCI or Msg3) has been received (as indicated by num_pdus) uint8_t ulsch_input_buffer_array[NFAPI_MAX_NUM_UL_PDU][MAX_ULSCH_PAYLOAD_BYTES]; @@ -1189,6 +1285,9 @@ void nr_ue_ul_scheduler(NR_UE_MAC_INST_t *mac, nr_uplink_indication_t *ul_info) mac->if_module->scheduled_response(&scheduled_response); } + if(mac->state == UE_CONNECTED) + nr_trigger_sr(mac); + // update Bj for all active lcids before LCP procedure LOG_D(NR_MAC, "====================[Frame %d][Slot %d]Logical Channel Prioritization===========\n", frame_tx, slot_tx); for (int i = 0; i < mac->lc_ordered_list.count; i++) { @@ -1218,82 +1317,11 @@ void nr_ue_ul_scheduler(NR_UE_MAC_INST_t *mac, nr_uplink_indication_t *ul_info) nr_timer_start(&sched_info->Bj_timer); } - // Call BSR procedure as described in Section 5.4.5 in 38.321 - - //Check whether BSR is triggered - nr_update_bsr(mac, frame_tx, slot_tx, gNB_index); - if(mac->state >= UE_PERFORMING_RA) nr_ue_pucch_scheduler(mac, frame_tx, slot_tx, ul_info->phy_data); } -void nr_update_bsr(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t slotP, uint8_t gNB_index) -{ - for (int lcid = 1; lcid <= NR_MAX_NUM_LCID; lcid++) { - // Reset transmission status - mac->scheduling_info.lc_sched_info[lcid_buffer_index(lcid)].LCID_buffer_with_data = false; - } - - for (int lcgid = 0; lcgid < NR_MAX_NUM_LCGID; lcgid++) { - // Reset Buffer Info - mac->scheduling_info.lcg_sched_info[lcgid].BSR = 0; - mac->scheduling_info.lcg_sched_info[lcgid].BSR_bytes = 0; - } - - bool bsr_regular_triggered = mac->BSR_reporting_active & NR_BSR_TRIGGER_REGULAR; - for (int i = 0; i < mac->lc_ordered_list.count; i++) { - nr_lcordered_info_t *lc_info = mac->lc_ordered_list.array[i]; - int lcid = lc_info->lcid; - NR_LC_SCHEDULING_INFO *lc_sched_info = get_scheduling_info_from_lcid(mac, lcid); - int lcgid = lc_sched_info->LCGID; - - // check if UL data for a logical channel which belongs to a LCG becomes available for transmission - if (lcgid != NR_INVALID_LCGID) { - mac_rlc_status_resp_t rlc_status = mac_rlc_status_ind(mac->ue_id, - mac->ue_id, - gNB_index, - frameP, - slotP, - ENB_FLAG_NO, - MBMS_FLAG_NO, - lcid, - 0, - 0); - - lc_sched_info->LCID_buffer_remain = rlc_status.bytes_in_buffer; - - if (rlc_status.bytes_in_buffer > 0) { - LOG_D(NR_MAC, - "[UE %d] PDCCH Tick : LCID %d LCGID %d has data to transmit %d bytes at frame %d slot %d\n", - mac->ue_id, - lcid, - lcgid, - rlc_status.bytes_in_buffer, - frameP, - slotP); - - lc_sched_info->LCID_buffer_with_data = true; - - //Update BSR_bytes - mac->scheduling_info.lcg_sched_info[lcgid].BSR_bytes += rlc_status.bytes_in_buffer; - - if (!bsr_regular_triggered) { - bsr_regular_triggered = true; - trigger_regular_bsr(mac, lc_info->sr_DelayTimerApplied); - LOG_D(NR_MAC, - "[UE %d] MAC BSR Triggered LCID %d LCGID %d data become available at frame %d slot %d\n", - mac->ue_id, - lcid, - lcgid, - frameP, - slotP); - } - } - } - } -} - -uint8_t nr_locate_BsrIndexByBufferSize(const uint32_t *table, int size, int value) +static uint8_t nr_locate_BsrIndexByBufferSize(const uint32_t *table, int size, int value) { uint8_t ju, jm, jl; int ascend; @@ -2456,25 +2484,26 @@ static int nr_ue_get_sdu_mac_ce_pre(NR_UE_MAC_INST_t *mac, if (mac->scheduling_info.lcg_sched_info[lcg_id].BSR_bytes) { num_lcg_id_with_data++; } - lcg_id++; } - //Compute BSR Length if Regular or Periodic BSR is triggered - //WARNING: if BSR long is computed, it may be changed to BSR short during or after multiplexing if there remains less than 1 LCGROUP with data after Tx - if (mac->BSR_reporting_active) { - AssertFatal((mac->BSR_reporting_active & NR_BSR_TRIGGER_PADDING) == 0, + // Compute BSR Length if Regular or Periodic BSR is triggered + // WARNING: if BSR long is computed, it may be changed to BSR short during or after multiplexing + // if there remains less than 1 LCGROUP with data after Tx + if (mac->scheduling_info.BSR_reporting_active) { + AssertFatal((mac->scheduling_info.BSR_reporting_active & NR_BSR_TRIGGER_PADDING) == 0, "Inconsistent BSR Trigger=%d !\n", - mac->BSR_reporting_active); + mac->scheduling_info.BSR_reporting_active); - //A Regular or Periodic BSR can only be sent if TBS is sufficient as transmitting only a BSR is not allowed if UE has data to transmit + // A Regular or Periodic BSR can only be sent if TBS is sufficient + // as transmitting only a BSR is not allowed if UE has data to transmit if (num_lcg_id_with_data <= 1) { - if (buflen >= (sizeof(NR_BSR_SHORT)+sizeof(NR_MAC_SUBHEADER_FIXED)+1)) { + if (buflen >= (sizeof(NR_BSR_SHORT) + sizeof(NR_MAC_SUBHEADER_FIXED) + 1)) { mac_ce_p->bsr_ce_len = sizeof(NR_BSR_SHORT); // 1 byte mac_ce_p->bsr_header_len = sizeof(NR_MAC_SUBHEADER_FIXED); // 1 byte } } else { - if (buflen >= (num_lcg_id_with_data+1+sizeof(NR_MAC_SUBHEADER_SHORT)+1)) { + if (buflen >= (num_lcg_id_with_data + 1 + sizeof(NR_MAC_SUBHEADER_SHORT) + 1)) { mac_ce_p->bsr_ce_len = num_lcg_id_with_data + 1; // variable size mac_ce_p->bsr_header_len = sizeof(NR_MAC_SUBHEADER_SHORT); // 2 bytes } @@ -2504,8 +2533,8 @@ static int nr_ue_get_sdu_mac_ce_pre(NR_UE_MAC_INST_t *mac, */ static void nr_ue_get_sdu_mac_ce_post(NR_UE_MAC_INST_t *mac, int CC_id, - frame_t frameP, - sub_frame_t subframe, + frame_t frame, + slot_t slot, uint8_t gNB_index, uint8_t *ulsch_buffer, uint16_t buflen, @@ -2513,22 +2542,22 @@ static void nr_ue_get_sdu_mac_ce_post(NR_UE_MAC_INST_t *mac, { // Compute BSR Values and update Nb LCGID with data after multiplexing unsigned short padding_len = 0; - int lcg_id = 0; int num_lcg_id_with_data = 0; int lcg_id_bsr_trunc = 0; - for (lcg_id = 0; lcg_id < NR_MAX_NUM_LCGID; lcg_id++) { + NR_UE_SCHEDULING_INFO *sched_info = &mac->scheduling_info; + for (int lcg_id = 0; lcg_id < NR_MAX_NUM_LCGID; lcg_id++) { if (mac_ce_p->bsr_ce_len == sizeof(NR_BSR_SHORT)) { - mac->scheduling_info.lcg_sched_info[lcg_id].BSR = + sched_info->lcg_sched_info[lcg_id].BSR = nr_locate_BsrIndexByBufferSize(NR_SHORT_BSR_TABLE, NR_SHORT_BSR_TABLE_SIZE, - mac->scheduling_info.lcg_sched_info[lcg_id].BSR_bytes); + sched_info->lcg_sched_info[lcg_id].BSR_bytes); } else { - mac->scheduling_info.lcg_sched_info[lcg_id].BSR = + sched_info->lcg_sched_info[lcg_id].BSR = nr_locate_BsrIndexByBufferSize(NR_LONG_BSR_TABLE, NR_LONG_BSR_TABLE_SIZE, - mac->scheduling_info.lcg_sched_info[lcg_id].BSR_bytes); + sched_info->lcg_sched_info[lcg_id].BSR_bytes); } - if (mac->scheduling_info.lcg_sched_info[lcg_id].BSR_bytes) { + if (sched_info->lcg_sched_info[lcg_id].BSR_bytes) { num_lcg_id_with_data++; lcg_id_bsr_trunc = lcg_id; } @@ -2551,11 +2580,11 @@ static void nr_ue_get_sdu_mac_ce_post(NR_UE_MAC_INST_t *mac, if ((padding_len) && (mac_ce_p->bsr_len == 0)) { /* if the number of padding bits is equal to or larger than the size of the Long BSR plus its subheader, report Long BSR */ - if (padding_len >= (num_lcg_id_with_data+1+sizeof(NR_MAC_SUBHEADER_SHORT))) { + if (padding_len >= (num_lcg_id_with_data + 1 + sizeof(NR_MAC_SUBHEADER_SHORT))) { mac_ce_p->bsr_ce_len = num_lcg_id_with_data + 1; //variable size mac_ce_p->bsr_header_len = sizeof(NR_MAC_SUBHEADER_SHORT); //2 bytes // Trigger BSR Padding - mac->BSR_reporting_active |= NR_BSR_TRIGGER_PADDING; + sched_info->BSR_reporting_active |= NR_BSR_TRIGGER_PADDING; } else if (padding_len >= (sizeof(NR_BSR_SHORT)+sizeof(NR_MAC_SUBHEADER_FIXED))) { mac_ce_p->bsr_ce_len = sizeof(NR_BSR_SHORT); //1 byte mac_ce_p->bsr_header_len = sizeof(NR_MAC_SUBHEADER_FIXED); //1 byte @@ -2565,9 +2594,8 @@ static void nr_ue_get_sdu_mac_ce_post(NR_UE_MAC_INST_t *mac, // Get LCGID of highest priority LCID with data (todo) for (int lcid = 1; lcid <= NR_MAX_NUM_LCID; lcid++) { NR_LC_SCHEDULING_INFO *sched_info = get_scheduling_info_from_lcid(mac, lcid); - lcg_id = sched_info->LCGID; - if ((lcg_id != NR_INVALID_LCGID) && (mac->scheduling_info.lcg_sched_info[lcg_id].BSR_bytes)) { - lcg_id_bsr_trunc = lcg_id; + if ((sched_info->LCGID != NR_INVALID_LCGID) && (mac->scheduling_info.lcg_sched_info[sched_info->LCGID].BSR_bytes)) { + lcg_id_bsr_trunc = sched_info->LCGID; } } } else { @@ -2576,7 +2604,7 @@ static void nr_ue_get_sdu_mac_ce_post(NR_UE_MAC_INST_t *mac, } // Trigger BSR Padding - mac->BSR_reporting_active |= NR_BSR_TRIGGER_PADDING; + sched_info->BSR_reporting_active |= NR_BSR_TRIGGER_PADDING; } mac_ce_p->bsr_len = mac_ce_p->bsr_header_len + mac_ce_p->bsr_ce_len; @@ -2592,63 +2620,63 @@ static void nr_ue_get_sdu_mac_ce_post(NR_UE_MAC_INST_t *mac, } else if (mac_ce_p->bsr_header_len == sizeof(NR_MAC_SUBHEADER_SHORT)) { mac_ce_p->bsr_s = NULL; mac_ce_p->bsr_t = NULL; - mac_ce_p->bsr_l->Buffer_size0 = mac->scheduling_info.lcg_sched_info[0].BSR; - mac_ce_p->bsr_l->Buffer_size1 = mac->scheduling_info.lcg_sched_info[1].BSR; - mac_ce_p->bsr_l->Buffer_size2 = mac->scheduling_info.lcg_sched_info[2].BSR; - mac_ce_p->bsr_l->Buffer_size3 = mac->scheduling_info.lcg_sched_info[3].BSR; - mac_ce_p->bsr_l->Buffer_size4 = mac->scheduling_info.lcg_sched_info[4].BSR; - mac_ce_p->bsr_l->Buffer_size5 = mac->scheduling_info.lcg_sched_info[5].BSR; - mac_ce_p->bsr_l->Buffer_size6 = mac->scheduling_info.lcg_sched_info[6].BSR; - mac_ce_p->bsr_l->Buffer_size7 = mac->scheduling_info.lcg_sched_info[7].BSR; + mac_ce_p->bsr_l->Buffer_size0 = sched_info->lcg_sched_info[0].BSR; + mac_ce_p->bsr_l->Buffer_size1 = sched_info->lcg_sched_info[1].BSR; + mac_ce_p->bsr_l->Buffer_size2 = sched_info->lcg_sched_info[2].BSR; + mac_ce_p->bsr_l->Buffer_size3 = sched_info->lcg_sched_info[3].BSR; + mac_ce_p->bsr_l->Buffer_size4 = sched_info->lcg_sched_info[4].BSR; + mac_ce_p->bsr_l->Buffer_size5 = sched_info->lcg_sched_info[5].BSR; + mac_ce_p->bsr_l->Buffer_size6 = sched_info->lcg_sched_info[6].BSR; + mac_ce_p->bsr_l->Buffer_size7 = sched_info->lcg_sched_info[7].BSR; LOG_D(NR_MAC, "[UE %d] Frame %d subframe %d BSR Trig=%d report LONG BSR (level LCGID0 %d,level LCGID1 %d,level LCGID2 %d,level LCGID3 " "%d level LCGID4 %d,level LCGID5 %d,level LCGID6 %d,level LCGID7 %d)\n", mac->ue_id, - frameP, - subframe, - mac->BSR_reporting_active, - mac->scheduling_info.lcg_sched_info[0].BSR, - mac->scheduling_info.lcg_sched_info[1].BSR, - mac->scheduling_info.lcg_sched_info[2].BSR, - mac->scheduling_info.lcg_sched_info[3].BSR, - mac->scheduling_info.lcg_sched_info[4].BSR, - mac->scheduling_info.lcg_sched_info[5].BSR, - mac->scheduling_info.lcg_sched_info[6].BSR, - mac->scheduling_info.lcg_sched_info[7].BSR); + frame, + slot, + sched_info->BSR_reporting_active, + sched_info->lcg_sched_info[0].BSR, + sched_info->lcg_sched_info[1].BSR, + sched_info->lcg_sched_info[2].BSR, + sched_info->lcg_sched_info[3].BSR, + sched_info->lcg_sched_info[4].BSR, + sched_info->lcg_sched_info[5].BSR, + sched_info->lcg_sched_info[6].BSR, + sched_info->lcg_sched_info[7].BSR); } else if (mac_ce_p->bsr_header_len == sizeof(NR_MAC_SUBHEADER_FIXED)) { mac_ce_p->bsr_l = NULL; - if ((mac_ce_p->bsr_t != NULL) && (mac->BSR_reporting_active & NR_BSR_TRIGGER_PADDING)) { + if ((mac_ce_p->bsr_t != NULL) && (sched_info->BSR_reporting_active & NR_BSR_TRIGGER_PADDING)) { //Truncated BSR mac_ce_p->bsr_s = NULL; mac_ce_p->bsr_t->LcgID = lcg_id_bsr_trunc; - mac_ce_p->bsr_t->Buffer_size = mac->scheduling_info.lcg_sched_info[lcg_id_bsr_trunc].BSR; + mac_ce_p->bsr_t->Buffer_size = sched_info->lcg_sched_info[lcg_id_bsr_trunc].BSR; LOG_D(NR_MAC, "[UE %d] Frame %d subframe %d BSR Trig=%d report TRUNCATED BSR with level %d for LCGID %d\n", mac->ue_id, - frameP, - subframe, - mac->BSR_reporting_active, - mac->scheduling_info.lcg_sched_info[lcg_id_bsr_trunc].BSR, + frame, + slot, + sched_info->BSR_reporting_active, + sched_info->lcg_sched_info[lcg_id_bsr_trunc].BSR, lcg_id_bsr_trunc); } else { mac_ce_p->bsr_t = NULL; mac_ce_p->bsr_s->LcgID = lcg_id_bsr_trunc; - mac_ce_p->bsr_s->Buffer_size = mac->scheduling_info.lcg_sched_info[lcg_id_bsr_trunc].BSR; + mac_ce_p->bsr_s->Buffer_size = sched_info->lcg_sched_info[lcg_id_bsr_trunc].BSR; LOG_D(NR_MAC, "[UE %d] Frame %d subframe %d BSR Trig=%d report SHORT BSR with level %d for LCGID %d\n", mac->ue_id, - frameP, - subframe, - mac->BSR_reporting_active, - mac->scheduling_info.lcg_sched_info[lcg_id_bsr_trunc].BSR, + frame, + slot, + sched_info->BSR_reporting_active, + sched_info->lcg_sched_info[lcg_id_bsr_trunc].BSR, lcg_id_bsr_trunc); } } LOG_D(NR_MAC, "[UE %d][SR] Gave SDU to PHY, clearing any scheduling request\n", mac->ue_id); - mac->scheduling_info.SR_pending = 0; - mac->scheduling_info.SR_COUNTER = 0; + sched_info->SR_pending = 0; + sched_info->SR_COUNTER = 0; /* Actions when a BSR is sent */ if (mac_ce_p->bsr_ce_len) { @@ -2659,15 +2687,15 @@ static void nr_ue_get_sdu_mac_ce_post(NR_UE_MAC_INST_t *mac, mac_ce_p->bsr_header_len, buflen); // Reset ReTx BSR Timer - nr_timer_start(&mac->scheduling_info.retxBSR_Timer); + nr_timer_start(&sched_info->retxBSR_Timer); // Reset Periodic Timer except when BSR is truncated if (mac_ce_p->bsr_t == NULL) { - nr_timer_start(&mac->scheduling_info.periodicBSR_Timer); + nr_timer_start(&sched_info->periodicBSR_Timer); LOG_D(NR_MAC, "[UE %d] MAC Periodic BSR Timer Reset\n", mac->ue_id); } // Reset BSR Trigger flags - mac->BSR_reporting_active = NR_BSR_TRIGGER_NONE; + sched_info->BSR_reporting_active = NR_BSR_TRIGGER_NONE; } } @@ -2754,8 +2782,8 @@ static void select_logical_channels(NR_UE_MAC_INST_t *mac, int *num_active_lcids } static bool fill_mac_sdu(NR_UE_MAC_INST_t *mac, - frame_t frameP, - sub_frame_t subframe, + frame_t frame, + slot_t slot, uint8_t gNB_index, uint16_t buflen, int16_t *buflen_remain, @@ -2778,8 +2806,8 @@ static bool fill_mac_sdu(NR_UE_MAC_INST_t *mac, LOG_D(NR_MAC, "[UE %d] [%d.%d] lcp round = %d, remaining mac pdu length = %d, lcid buffer remaining = %d, lcid = %d \n", mac->ue_id, - frameP, - subframe, + frame, + slot, *counter, *buflen_remain, lcid_remain_buffer, @@ -2798,7 +2826,7 @@ static bool fill_mac_sdu(NR_UE_MAC_INST_t *mac, uint16_t sdu_length = mac_rlc_data_req(mac->ue_id, mac->ue_id, gNB_index, - frameP, + frame, ENB_FLAG_NO, MBMS_FLAG_NO, lcid, @@ -2831,8 +2859,8 @@ static bool fill_mac_sdu(NR_UE_MAC_INST_t *mac, "[UE %d] [%d.%d] UL-DXCH -> ULSCH, Generating UL MAC sub-PDU for SDU %d, length %d bytes, RB with LCID " "0x%02x (buflen (TBS) %d bytes)\n", mac->ue_id, - frameP, - subframe, + frame, + slot, (*num_sdus) + 1, sdu_length, lcid, @@ -2872,8 +2900,8 @@ static bool fill_mac_sdu(NR_UE_MAC_INST_t *mac, LOG_D(NR_MAC, "[UE %d] Update BSR [%d.%d] BSR_bytes for LCG%ld = %d\n", mac->ue_id, - frameP, - subframe, + frame, + slot, sched_info->LCGID, (lcg_info + sched_info->LCGID)->BSR_bytes); if ((lcg_info + sched_info->LCGID)->BSR_bytes < 0) @@ -2902,16 +2930,16 @@ static bool fill_mac_sdu(NR_UE_MAC_INST_t *mac, the selected sub-header for the payload sub-PDUs is NR_MAC_SUBHEADER_LONG * @module_idP Module ID * @CC_id Component Carrier index - * @frameP current UL frame - * @subframe current UL slot + * @frame current UL frame + * @slot current UL slot * @gNB_index gNB index * @ulsch_buffer Pointer to ULSCH PDU * @buflen TBS */ uint8_t nr_ue_get_sdu(NR_UE_MAC_INST_t *mac, int CC_id, - frame_t frameP, - sub_frame_t subframe, + frame_t frame, + slot_t slot, uint8_t gNB_index, uint8_t *ulsch_buffer, uint16_t buflen) @@ -2953,10 +2981,10 @@ uint8_t nr_ue_get_sdu(NR_UE_MAC_INST_t *mac, // because as per standard(TS38.321), all equal priority channels should be served equally // nr_ue_get_sdu_mac_ce_pre updates all mac_ce related header field related to length - mac_ce_p->tot_mac_ce_len = nr_ue_get_sdu_mac_ce_pre(mac, CC_id, frameP, subframe, gNB_index, ulsch_buffer, buflen, mac_ce_p); + mac_ce_p->tot_mac_ce_len = nr_ue_get_sdu_mac_ce_pre(mac, CC_id, frame, slot, gNB_index, ulsch_buffer, buflen, mac_ce_p); mac_ce_p->total_mac_pdu_header_len = mac_ce_p->tot_mac_ce_len; - LOG_D(NR_MAC, "[UE %d] [%d.%d] process UL transport block at with size TBS = %d bytes \n", mac->ue_id, frameP, subframe, buflen); + LOG_D(NR_MAC, "[UE %d] [%d.%d] process UL transport block at with size TBS = %d bytes \n", mac->ue_id, frame, slot, buflen); // selection of logical channels int avail_lcids_count = 0; @@ -3005,8 +3033,8 @@ uint8_t nr_ue_get_sdu(NR_UE_MAC_INST_t *mac, "len %d bytes," "buflen_remain %d bytes)\n", mac->ue_id, - frameP, - subframe, + frame, + slot, lcid, buflen, mac_ce_p->sdu_length_total, @@ -3025,8 +3053,8 @@ uint8_t nr_ue_get_sdu(NR_UE_MAC_INST_t *mac, the target number of bytes to request from RLC via 'mac_rlc_data_req' */ if (!fill_mac_sdu(mac, - frameP, - subframe, + frame, + slot, gNB_index, buflen, &buflen_remain, @@ -3050,7 +3078,7 @@ uint8_t nr_ue_get_sdu(NR_UE_MAC_INST_t *mac, //nr_ue_get_sdu_mac_ce_post recalculates all mac_ce related header fields since buffer has been changed after mac_rlc_data_req. //Also, BSR padding is handled here after knowing mac_ce_p->sdu_length_total. - nr_ue_get_sdu_mac_ce_post(mac, CC_id, frameP, subframe, gNB_index, ulsch_buffer, buflen, mac_ce_p); + nr_ue_get_sdu_mac_ce_post(mac, CC_id, frame, slot, gNB_index, ulsch_buffer, buflen, mac_ce_p); if (mac_ce_p->tot_mac_ce_len > 0) { From 4f884db3d65d122fd2c57bf84fa77c1cc120161b Mon Sep 17 00:00:00 2001 From: francescomani Date: Fri, 22 Mar 2024 09:48:13 +0100 Subject: [PATCH 30/39] correct use of dataScramblingID for PDSCH at UE --- .../nfapi/public_inc/fapi_nr_ue_interface.h | 1 + openair1/SCHED_NR_UE/phy_procedures_nr_ue.c | 4 ++-- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 18 ++++++++++++++---- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h index f370927378..f0c31b9682 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h @@ -494,6 +494,7 @@ typedef struct { uint32_t tbslbrm; uint8_t nscid; uint16_t dlDmrsScramblingId; + uint16_t dlDataScramblingId; uint16_t pduBitmap; uint32_t k1_feedback; uint8_t ldpcBaseGraph; diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index 7bb1683507..0c253bb198 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -691,7 +691,7 @@ static bool nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t * nr_dlsch_unscrambling(llr[0], dl_harq0->G, 0, - ue->frame_parms.Nid_cell, + dlsch[0].dlsch_config.dlDataScramblingId, dlsch[0].rnti); @@ -787,7 +787,7 @@ static bool nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t * nr_dlsch_unscrambling(llr[1], dl_harq1->G, 0, - ue->frame_parms.Nid_cell, + dlsch[1].dlsch_config.dlDataScramblingId, dlsch[1].rnti); stop_meas(&ue->dlsch_unscrambling_stats); diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 3ef15ce4d4..a926429d2b 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -189,10 +189,8 @@ int get_rnti_type(const NR_UE_MAC_INST_t *mac, const uint16_t rnti) } else { AssertFatal(1 == 0, "Not identified/handled rnti %d \n", rnti); } - - LOG_D(MAC, "Returning rnti_type %s \n", rnti_types(rnti_type)); - - return rnti_type; + LOG_D(MAC, "Returning rnti_type %s \n", rnti_types(rnti_type)); + return rnti_type; } void nr_ue_decode_mib(NR_UE_MAC_INST_t *mac, int cc_id) @@ -664,6 +662,13 @@ static int nr_ue_process_dci_dl_10(NR_UE_MAC_INST_t *mac, else dlsch_pdu->dlDmrsScramblingId = mac->physCellId; + if (get_rnti_type(mac, dci_ind->rnti) == TYPE_C_RNTI_ + && dci_ind->ss_type != NR_SearchSpace__searchSpaceType_PR_common + && pdsch_config->dataScramblingIdentityPDSCH) + dlsch_pdu->dlDataScramblingId = *pdsch_config->dataScramblingIdentityPDSCH; + else + dlsch_pdu->dlDataScramblingId = mac->physCellId; + /* dmrs symbol positions*/ dlsch_pdu->dlDmrsSymbPos = fill_dmrs_mask(pdsch_config, NR_DL_DCI_FORMAT_1_0, @@ -975,6 +980,11 @@ static int nr_ue_process_dci_dl_11(NR_UE_MAC_INST_t *mac, return -1; } + if (pdsch_Config->dataScramblingIdentityPDSCH) + dlsch_pdu->dlDataScramblingId = *pdsch_Config->dataScramblingIdentityPDSCH; + else + dlsch_pdu->dlDataScramblingId = mac->physCellId; + dlsch_pdu->dmrsConfigType = dl_dmrs_config->dmrs_Type == NULL ? NFAPI_NR_DMRS_TYPE1 : NFAPI_NR_DMRS_TYPE2; /* TODO: fix number of DM-RS CDM groups without data according to subclause 5.1.6.2 of 3GPP TS 38.214, From 91e5d80002a28db1f07b6633ee8a682b6e195fff Mon Sep 17 00:00:00 2001 From: francescomani Date: Fri, 22 Mar 2024 11:08:19 +0100 Subject: [PATCH 31/39] correct use of dataScramblingID for PUSCH at UE --- openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c | 15 ++------ openair2/LAYER2/NR_MAC_UE/mac_proto.h | 1 + openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 13 +++++-- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 39 ++++++++++---------- 4 files changed, 34 insertions(+), 34 deletions(-) diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c index 9c59535e16..885fcd403a 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c @@ -55,11 +55,7 @@ //extern int32_t uplink_counter; -void nr_pusch_codeword_scrambling_uci(uint8_t *in, - uint32_t size, - uint32_t Nid, - uint32_t n_RNTI, - uint32_t* out) +void nr_pusch_codeword_scrambling_uci(uint8_t *in, uint32_t size, uint32_t Nid, uint32_t n_RNTI, uint32_t* out) { uint8_t reset, b_idx; uint32_t x1 = 0, x2 = 0, s = 0, temp_out = 0; @@ -93,12 +89,7 @@ void nr_pusch_codeword_scrambling_uci(uint8_t *in, } } -void nr_pusch_codeword_scrambling(uint8_t *in, - uint32_t size, - uint32_t Nid, - uint32_t n_RNTI, - bool uci_on_pusch, - uint32_t* out) +void nr_pusch_codeword_scrambling(uint8_t *in, uint32_t size, uint32_t Nid, uint32_t n_RNTI, bool uci_on_pusch, uint32_t* out) { if (uci_on_pusch) nr_pusch_codeword_scrambling_uci(in, size, Nid, n_RNTI, out); @@ -221,7 +212,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, nr_pusch_codeword_scrambling(harq_process_ul_ue->f, available_bits, - ulsch_ue->Nid_cell, + pusch_pdu->data_scrambling_id, rnti, false, scrambled_output); diff --git a/openair2/LAYER2/NR_MAC_UE/mac_proto.h b/openair2/LAYER2/NR_MAC_UE/mac_proto.h index 7322024e7b..e4d8cdaecd 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_proto.h @@ -413,6 +413,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, dci_pdu_rel15_t *dci, RAR_grant_t *rar_grant, uint16_t rnti, + int ss_type, const nr_dci_format_t dci_format); int nr_rrc_mac_config_req_sl_preconfig(module_id_t module_id, diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index a926429d2b..0e19702ee8 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -445,7 +445,7 @@ static int nr_ue_process_dci_ul_00(NR_UE_MAC_INST_t *mac, if (!pdu) return -1; - int ret = nr_config_pusch_pdu(mac, &tda_info, &pdu->pusch_config_pdu, dci, NULL, dci_ind->rnti, NR_UL_DCI_FORMAT_0_0); + int ret = nr_config_pusch_pdu(mac, &tda_info, &pdu->pusch_config_pdu, dci, NULL, dci_ind->rnti, dci_ind->ss_type, NR_UL_DCI_FORMAT_0_0); if (ret != 0) remove_ul_config_last_item(pdu); release_ul_config(pdu, false); @@ -518,7 +518,7 @@ static int nr_ue_process_dci_ul_01(NR_UE_MAC_INST_t *mac, fapi_nr_ul_config_request_pdu_t *pdu = lockGet_ul_config(mac, frame_tx, slot_tx, FAPI_NR_UL_CONFIG_TYPE_PUSCH); if (!pdu) return -1; - int ret = nr_config_pusch_pdu(mac, &tda_info, &pdu->pusch_config_pdu, dci, NULL, dci_ind->rnti, NR_UL_DCI_FORMAT_0_1); + int ret = nr_config_pusch_pdu(mac, &tda_info, &pdu->pusch_config_pdu, dci, NULL, dci_ind->rnti, dci_ind->ss_type, NR_UL_DCI_FORMAT_0_1); if (ret != 0) remove_ul_config_last_item(pdu); release_ul_config(pdu, false); @@ -3990,7 +3990,14 @@ static void nr_ue_process_rar(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *d if (!pdu) return; // Config Msg3 PDU - int ret = nr_config_pusch_pdu(mac, &tda_info, &pdu->pusch_config_pdu, NULL, &rar_grant, rnti, NR_DCI_NONE); + int ret = nr_config_pusch_pdu(mac, + &tda_info, + &pdu->pusch_config_pdu, + NULL, + &rar_grant, + rnti, + NR_SearchSpace__searchSpaceType_PR_common, + NR_DCI_NONE); if (ret != 0) remove_ul_config_last_item(pdu); release_ul_config(pdu, false); diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index e9b188cfba..a9ea346441 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -437,6 +437,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, dci_pdu_rel15_t *dci, RAR_grant_t *rar_grant, uint16_t rnti, + int ss_type, const nr_dci_format_t dci_format) { uint16_t l_prime_mask = 0; @@ -448,10 +449,10 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, // Common configuration pusch_config_pdu->dmrs_config_type = pusch_dmrs_type1; - pusch_config_pdu->pdu_bit_map = PUSCH_PDU_BITMAP_PUSCH_DATA; - pusch_config_pdu->nrOfLayers = 1; - pusch_config_pdu->Tpmi = 0; - pusch_config_pdu->rnti = rnti; + pusch_config_pdu->pdu_bit_map = PUSCH_PDU_BITMAP_PUSCH_DATA; + pusch_config_pdu->nrOfLayers = 1; + pusch_config_pdu->Tpmi = 0; + pusch_config_pdu->rnti = rnti; pusch_dmrs_AdditionalPosition_t add_pos = pusch_dmrs_pos2; int dmrslength = 1; @@ -560,16 +561,13 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, pusch_config_pdu->transform_precoding = get_transformPrecoding(current_UL_BWP, dci_format, 0); /*DCI format-related configuration*/ - int target_ss; if (dci_format == NR_UL_DCI_FORMAT_0_0) { - target_ss = NR_SearchSpace__searchSpaceType_PR_common; if ((pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_disabled) && pusch_config_pdu->nr_of_symbols < 3) pusch_config_pdu->num_dmrs_cdm_grps_no_data = 1; else pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2; } else if (dci_format == NR_UL_DCI_FORMAT_0_1) { - target_ss = NR_SearchSpace__searchSpaceType_PR_ue_Specific; ul_layers_config(mac, pusch_config_pdu, dci, dci_format); ul_ports_config(mac, &dmrslength, pusch_config_pdu, dci, dci_format); } else { @@ -587,6 +585,12 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, } pusch_config_pdu->scid = 0; + pusch_config_pdu->data_scrambling_id = mac->physCellId; + if (pusch_Config->dataScramblingIdentityPUSCH + && rnti_type == TYPE_C_RNTI_ + && !(dci_format == NR_UL_DCI_FORMAT_0_0 && ss_type == NR_SearchSpace__searchSpaceType_PR_common)) + pusch_config_pdu->data_scrambling_id = *pusch_Config->dataScramblingIdentityPUSCH; + pusch_config_pdu->ul_dmrs_scrambling_id = mac->physCellId; if (dci_format == NR_UL_DCI_FORMAT_0_1) pusch_config_pdu->scid = dci->dmrs_sequence_initialization.val; @@ -641,7 +645,9 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, } /* FREQ_HOPPING_FLAG */ - if ((pusch_Config!=NULL) && (pusch_Config->frequencyHopping!=NULL) && (pusch_Config->resourceAllocation != NR_PUSCH_Config__resourceAllocation_resourceAllocationType0)){ + if ((pusch_Config != NULL) + && (pusch_Config->frequencyHopping != NULL) + && (pusch_Config->resourceAllocation != NR_PUSCH_Config__resourceAllocation_resourceAllocationType0)) { pusch_config_pdu->frequency_hopping = dci->frequency_hopping_flag.val; } @@ -649,17 +655,12 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, pusch_config_pdu->mcs_index = dci->mcs; /* MCS TABLE */ - if (pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_disabled) { - pusch_config_pdu->mcs_table = - get_pusch_mcs_table(pusch_Config ? pusch_Config->mcs_Table : NULL, 0, dci_format, rnti_type, target_ss, false); - } else { - pusch_config_pdu->mcs_table = get_pusch_mcs_table(pusch_Config ? pusch_Config->mcs_TableTransformPrecoder : NULL, - 1, - dci_format, - rnti_type, - target_ss, - false); - } + pusch_config_pdu->mcs_table = get_pusch_mcs_table(pusch_Config ? pusch_Config->mcs_TableTransformPrecoder : NULL, + pusch_config_pdu->transform_precoding != NR_PUSCH_Config__transformPrecoder_disabled, + dci_format, + rnti_type, + ss_type, + false); /* NDI */ NR_UL_HARQ_INFO_t *harq = &mac->ul_harq_info[dci->harq_pid]; From 7258f78fbf8621d7560430d11367f4142afffaad Mon Sep 17 00:00:00 2001 From: Jaroslava Fiedlerova Date: Thu, 14 Mar 2024 12:52:49 +0100 Subject: [PATCH 32/39] CI: set mem limit for docker build cache to 1h Co-authored-by: Robert Schmidt --- ci-scripts/cls_containerize.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/ci-scripts/cls_containerize.py b/ci-scripts/cls_containerize.py index d37330d519..860412e9f3 100644 --- a/ci-scripts/cls_containerize.py +++ b/ci-scripts/cls_containerize.py @@ -517,9 +517,13 @@ class Containerize(): # Remove all intermediate build images and clean up cmd.run(f"{self.cli} image rm ran-build:{imageTag} ran-build-asan:{imageTag}") cmd.run(f"{self.cli} volume prune --force") - # Remove any cached artifacts: we don't use the cache for now, prevent - # out of diskspace problem - cmd.run(f"{self.cli} buildx prune --filter=until=6h --force") + + # Remove some cached artifacts to prevent out of diskspace problem + logging.debug(cmd.run("df -h").stdout) + logging.debug(cmd.run("docker system df").stdout) + cmd.run(f"{self.cli} buildx prune --filter until=1h --force") + logging.debug(cmd.run("df -h").stdout) + logging.debug(cmd.run("docker system df").stdout) # create a zip with all logs build_log_name = f'build_log_{self.testCase_id}' From 6cf2ab2a15a90872b1bec4a86f3bad0234c082ed Mon Sep 17 00:00:00 2001 From: Romain Beurdouche Date: Thu, 15 Feb 2024 11:10:48 +0100 Subject: [PATCH 33/39] feat(phy-test): disable CQI and RSRP evaluation when running in phy-test mode In phy-test, the scheduler has a hardcoded UE allocation; if CQI and RSRP are not evaluated, there is no change in the scheduler function. Also, this avoids misleading error messages if no UE is connected. --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index e949d84dca..ad7286e8c1 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -1109,7 +1109,8 @@ void handle_nr_uci_pucch_2_3_4(module_id_t mod_id, } free(uci_234->harq.harq_payload); } - if ((uci_234->pduBitmap >> 2) & 0x01) { + /* phy-test has hardcoded allocation, so no use to handle CSI reports */ + if ((uci_234->pduBitmap >> 2) & 0x01 && !get_softmodem_params()->phy_test) { //API to parse the csi report and store it into sched_ctrl extract_pucch_csi_report(csi_MeasConfig, uci_234, frame, slot, UE, nrmac->common_channels->ServingCellConfigCommon); //TCI handling function From c45fb431106ecb52dab09e53547c2bc30a032a67 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Sat, 23 Mar 2024 10:18:14 +0100 Subject: [PATCH 34/39] Fix: handle CU-to-DU info in UE Ctxt setup Req --- openair2/RRC/NR/mac_rrc_dl_f1ap.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/openair2/RRC/NR/mac_rrc_dl_f1ap.c b/openair2/RRC/NR/mac_rrc_dl_f1ap.c index e501dde45b..b440f1818a 100644 --- a/openair2/RRC/NR/mac_rrc_dl_f1ap.c +++ b/openair2/RRC/NR/mac_rrc_dl_f1ap.c @@ -50,7 +50,21 @@ static void ue_context_setup_request_f1ap(sctp_assoc_t assoc_id, const f1ap_ue_c msg->ittiMsgHeader.originInstance = assoc_id; f1ap_ue_context_setup_t *f1ap_msg = &F1AP_UE_CONTEXT_SETUP_REQ(msg); *f1ap_msg = *req; - AssertFatal(req->cu_to_du_rrc_information == NULL, "cu_to_du_rrc_information not supported yet\n"); + if (req->cu_to_du_rrc_information != NULL) { + f1ap_msg->cu_to_du_rrc_information = calloc(1, sizeof(*f1ap_msg->cu_to_du_rrc_information)); + AssertFatal(f1ap_msg->cu_to_du_rrc_information != NULL, "out of memory\n"); + AssertFatal(req->cu_to_du_rrc_information->cG_ConfigInfo == NULL && req->cu_to_du_rrc_information->cG_ConfigInfo_length == 0, "cg_ConfigInfo not implemented\n"); + AssertFatal(req->cu_to_du_rrc_information->measConfig == NULL && req->cu_to_du_rrc_information->measConfig_length == 0, "cg_ConfigInfo not implemented\n"); + if (req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList != NULL) { + const cu_to_du_rrc_information_t *du2cu_req = req->cu_to_du_rrc_information; + cu_to_du_rrc_information_t* du2cu_new = f1ap_msg->cu_to_du_rrc_information; + DevAssert(du2cu_req->uE_CapabilityRAT_ContainerList_length > 0); + du2cu_new->uE_CapabilityRAT_ContainerList_length = du2cu_req->uE_CapabilityRAT_ContainerList_length; + du2cu_new->uE_CapabilityRAT_ContainerList = malloc(du2cu_new->uE_CapabilityRAT_ContainerList_length); + AssertFatal(du2cu_new->uE_CapabilityRAT_ContainerList != NULL, "out of memory\n"); + memcpy(du2cu_new->uE_CapabilityRAT_ContainerList, du2cu_req->uE_CapabilityRAT_ContainerList, du2cu_new->uE_CapabilityRAT_ContainerList_length); + } + } if (req->drbs_to_be_setup_length > 0) { int n = req->drbs_to_be_setup_length; f1ap_msg->drbs_to_be_setup_length = n; From fc4c4fc599c82bb92bcfbd11638ef024e869a9ff Mon Sep 17 00:00:00 2001 From: Teodora Date: Mon, 25 Mar 2024 13:10:44 +0100 Subject: [PATCH 35/39] Add mutual O-RAN E2SM UE ID filling info --- openair2/E2AP/RAN_FUNCTION/CMakeLists.txt | 2 + .../E2AP/RAN_FUNCTION/O-RAN/ran_e2sm_ue_id.c | 143 ++++++++++++++++++ .../E2AP/RAN_FUNCTION/O-RAN/ran_e2sm_ue_id.h | 42 +++++ 3 files changed, 187 insertions(+) create mode 100644 openair2/E2AP/RAN_FUNCTION/O-RAN/ran_e2sm_ue_id.c create mode 100644 openair2/E2AP/RAN_FUNCTION/O-RAN/ran_e2sm_ue_id.h diff --git a/openair2/E2AP/RAN_FUNCTION/CMakeLists.txt b/openair2/E2AP/RAN_FUNCTION/CMakeLists.txt index 3cb3d062f4..7feaf80bb1 100644 --- a/openair2/E2AP/RAN_FUNCTION/CMakeLists.txt +++ b/openair2/E2AP/RAN_FUNCTION/CMakeLists.txt @@ -6,6 +6,7 @@ add_library(e2_ran_func_cuup STATIC CUSTOMIZED/ran_func_pdcp.c # current implementation doesn't take split architecture into account, neither CU/DU nor CU-UP/CU-CP CUSTOMIZED/ran_func_tc.c # currently, not implemented; therefore, filling rnd data ../flexric/test/rnd/fill_rnd_data_tc.c + O-RAN/ran_e2sm_ue_id.c O-RAN/ran_func_kpm.c # this file should only contain PDCP-U/GTP; to be done in the future ../flexric/test/rnd/fill_rnd_data_kpm.c # this dependancy will be taken out once RAN Function Definition is implemented O-RAN/ran_func_rc.c # this file should only contain PDCP-U/GTP; to be done in the future @@ -23,6 +24,7 @@ add_library(e2_ran_func_du_cucp_cuup STATIC ../flexric/test/rnd/fill_rnd_data_e2_setup_req.c # this is not rnd data; it is used to fill E2 Node Component Configuration Addition List in E2 Setup Request message CUSTOMIZED/ran_func_gtp.c # current implementation doesn't take split architecture into account, neither CU/DU nor CU-UP/CU-CP CUSTOMIZED/ran_func_pdcp.c # current implementation doesn't take split architecture into account, neither CU/DU nor CU-UP/CU-CP + O-RAN/ran_e2sm_ue_id.c O-RAN/ran_func_kpm.c # this file should only contain RRC/PDCP-C; to be done in the future # when nr-softmodem is divided in separate executables ../flexric/test/rnd/fill_rnd_data_kpm.c # this dependancy will be taken out once RAN Function Definition is implemented diff --git a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_e2sm_ue_id.c b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_e2sm_ue_id.c new file mode 100644 index 0000000000..c3f6277f6f --- /dev/null +++ b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_e2sm_ue_id.c @@ -0,0 +1,143 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "ran_e2sm_ue_id.h" + +ue_id_e2sm_t fill_e2sm_gnb_ue_id_data(const gNB_RRC_UE_t *rrc_ue_context, __attribute__((unused))const uint32_t rrc_ue_id, __attribute__((unused))const ue_id_t cucp_ue_id) +{ + ue_id_e2sm_t ue_id = {0}; + + ue_id.type = GNB_UE_ID_E2SM; + + // 6.2.3.16 + // Mandatory + // AMF UE NGAP ID + ue_id.gnb.amf_ue_ngap_id = rrc_ue_context->amf_ue_ngap_id; + + // Mandatory + //GUAMI 6.2.3.17 + ue_id.gnb.guami.plmn_id = (e2sm_plmn_t) { + .mcc = rrc_ue_context->ue_guami.mcc, + .mnc = rrc_ue_context->ue_guami.mnc, + .mnc_digit_len = rrc_ue_context->ue_guami.mnc_len + }; + + ue_id.gnb.guami.amf_region_id = rrc_ue_context->ue_guami.amf_region_id; + ue_id.gnb.guami.amf_set_id = rrc_ue_context->ue_guami.amf_set_id; + ue_id.gnb.guami.amf_ptr = rrc_ue_context->ue_guami.amf_pointer; + + // RAN UE ID + // Optional + // 6.2.3.25 + // OCTET STRING (SIZE (8)) + // Defined in TS 38.473 (F1AP) + // clause 9.2.2.1 + // UE CONTEXT SETUP REQUEST + ue_id.gnb.ran_ue_id = calloc(1, sizeof(uint64_t)); + assert(ue_id.gnb.ran_ue_id != NULL); + *ue_id.gnb.ran_ue_id = rrc_ue_context->rrc_ue_id; + + return ue_id; +} + +ue_id_e2sm_t fill_e2sm_cu_ue_id_data(const gNB_RRC_UE_t *rrc_ue_context, const uint32_t rrc_ue_id, const ue_id_t cucp_ue_id) +{ + ue_id_e2sm_t ue_id = fill_e2sm_gnb_ue_id_data(rrc_ue_context, rrc_ue_id, cucp_ue_id); + + // gNB-CU UE F1AP ID List + // C-ifCUDUseparated + ue_id.gnb.gnb_cu_ue_f1ap_lst_len = 1; + ue_id.gnb.gnb_cu_ue_f1ap_lst = calloc(ue_id.gnb.gnb_cu_ue_f1ap_lst_len, sizeof(uint32_t)); + assert(ue_id.gnb.gnb_cu_ue_f1ap_lst != NULL && "Memory exhausted"); + ue_id.gnb.gnb_cu_ue_f1ap_lst[0] = rrc_ue_context->rrc_ue_id; + + return ue_id; +} + +ue_id_e2sm_t fill_e2sm_du_ue_id_data(__attribute__((unused))const gNB_RRC_UE_t *rrc_ue_context, const uint32_t rrc_ue_id, __attribute__((unused))const ue_id_t cucp_ue_id) +{ + ue_id_e2sm_t ue_id = {0}; + + ue_id.type = GNB_DU_UE_ID_E2SM; + + // 6.2.3.21 + // gNB CU UE F1AP + // Mandatory + ue_id.gnb_du.gnb_cu_ue_f1ap = rrc_ue_id; + + // 6.2.3.25 + // RAN UE ID + // Optional + ue_id.gnb_du.ran_ue_id = calloc(1, sizeof(uint64_t)); + assert(ue_id.gnb_du.ran_ue_id != NULL); + *ue_id.gnb_du.ran_ue_id = rrc_ue_id; + + return ue_id; +} + +ue_id_e2sm_t fill_e2sm_cucp_ue_id_data(const gNB_RRC_UE_t *rrc_ue_context, const uint32_t rrc_ue_id, const ue_id_t cucp_ue_id) +{ + ue_id_e2sm_t ue_id = fill_e2sm_gnb_ue_id_data(rrc_ue_context, rrc_ue_id, cucp_ue_id); + + //gNB-CU-CP UE E1AP ID List + //C-ifCPUPseparated + ue_id.gnb.gnb_cu_cp_ue_e1ap_lst_len = 1; + ue_id.gnb.gnb_cu_cp_ue_e1ap_lst = calloc(ue_id.gnb.gnb_cu_cp_ue_e1ap_lst_len, sizeof(uint32_t)); + assert(ue_id.gnb.gnb_cu_cp_ue_e1ap_lst != NULL && "Memory exhausted"); + ue_id.gnb.gnb_cu_cp_ue_e1ap_lst[0] = rrc_ue_context->rrc_ue_id; + + return ue_id; +} + +ue_id_e2sm_t fill_e2sm_cuup_ue_id_data(__attribute__((unused))const gNB_RRC_UE_t *rrc_ue_context, __attribute__((unused))const uint32_t rrc_ue_id, const ue_id_t cucp_ue_id) +{ + ue_id_e2sm_t ue_id = {0}; + + ue_id.type = GNB_CU_UP_UE_ID_E2SM; + + // 6.2.3.20 + // Mandatory + ue_id.gnb_cu_up.gnb_cu_cp_ue_e1ap = cucp_ue_id; // RAN UE NGAP ID = gNB UE NGAP ID = rrc_ue_id + + // 6.2.3.25 + // RAN UE ID + // Optional + ue_id.gnb_cu_up.ran_ue_id = calloc(1, sizeof(uint64_t)); + assert(ue_id.gnb_cu_up.ran_ue_id != NULL); + *ue_id.gnb_cu_up.ran_ue_id = cucp_ue_id; // RAN UE NGAP ID = gNB UE NGAP ID = rrc_ue_id + + return ue_id; +} + +get_ue_id fill_ue_id_data[END_NGRAN_NODE_TYPE] = +{ + NULL, + NULL, + fill_e2sm_gnb_ue_id_data, + NULL, + NULL, + fill_e2sm_cu_ue_id_data, + NULL, + fill_e2sm_du_ue_id_data, + NULL, + fill_e2sm_cucp_ue_id_data, + fill_e2sm_cuup_ue_id_data, +}; diff --git a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_e2sm_ue_id.h b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_e2sm_ue_id.h new file mode 100644 index 0000000000..769ff12673 --- /dev/null +++ b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_e2sm_ue_id.h @@ -0,0 +1,42 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef RAN_E2SM_UE_ID_H +#define RAN_E2SM_UE_ID_H + +#include "openair2/E2AP/flexric/src/agent/../sm/sm_io.h" +#include "openair2/RRC/NR/rrc_gNB_UE_context.h" + +ue_id_e2sm_t fill_e2sm_gnb_ue_id_data(const gNB_RRC_UE_t *rrc_ue_context, const uint32_t rrc_ue_id, const ue_id_t cucp_ue_id); + +ue_id_e2sm_t fill_e2sm_cu_ue_id_data(const gNB_RRC_UE_t *rrc_ue_context, const uint32_t rrc_ue_id, const ue_id_t cucp_ue_id); + +ue_id_e2sm_t fill_e2sm_du_ue_id_data(const gNB_RRC_UE_t *rrc_ue_context, const uint32_t rrc_ue_id, const ue_id_t cucp_ue_id); + +ue_id_e2sm_t fill_e2sm_cucp_ue_id_data(const gNB_RRC_UE_t *rrc_ue_context, const uint32_t rrc_ue_id, const ue_id_t cucp_ue_id); + +ue_id_e2sm_t fill_e2sm_cuup_ue_id_data(const gNB_RRC_UE_t *rrc_ue_context, const uint32_t rrc_ue_id, const ue_id_t cucp_ue_id); + +typedef ue_id_e2sm_t (*get_ue_id)(const gNB_RRC_UE_t *rrc_ue_context, const uint32_t rrc_ue_id, const ue_id_t cucp_ue_id); + +extern get_ue_id fill_ue_id_data[END_NGRAN_NODE_TYPE]; + +#endif From ba003cc649fd9253770167a1a03da14c0cf71e2e Mon Sep 17 00:00:00 2001 From: Teodora Date: Thu, 29 Feb 2024 10:26:58 +0100 Subject: [PATCH 36/39] KPM cleanup - RAN Function Definition implemented - ran_func_kpm.c - use function pointers based on the matching condition, and node type - ran_func_kpm_subs.h/c - for measurement collection within MAC/RLC/PDCP layers; for CU-UP node only PDCP included (otherwise, we would get undefined reference to MAC/RLC) - use mutual E2SM UE ID file --- openair2/E2AP/RAN_FUNCTION/CMakeLists.txt | 4 +- .../E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.c | 1089 ++++++----------- .../RAN_FUNCTION/O-RAN/ran_func_kpm_subs.c | 232 ++++ .../RAN_FUNCTION/O-RAN/ran_func_kpm_subs.h | 49 + 4 files changed, 656 insertions(+), 718 deletions(-) create mode 100644 openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm_subs.c create mode 100644 openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm_subs.h diff --git a/openair2/E2AP/RAN_FUNCTION/CMakeLists.txt b/openair2/E2AP/RAN_FUNCTION/CMakeLists.txt index 7feaf80bb1..906a3d2c55 100644 --- a/openair2/E2AP/RAN_FUNCTION/CMakeLists.txt +++ b/openair2/E2AP/RAN_FUNCTION/CMakeLists.txt @@ -8,7 +8,7 @@ add_library(e2_ran_func_cuup STATIC ../flexric/test/rnd/fill_rnd_data_tc.c O-RAN/ran_e2sm_ue_id.c O-RAN/ran_func_kpm.c # this file should only contain PDCP-U/GTP; to be done in the future - ../flexric/test/rnd/fill_rnd_data_kpm.c # this dependancy will be taken out once RAN Function Definition is implemented + O-RAN/ran_func_kpm_subs.c O-RAN/ran_func_rc.c # this file should only contain PDCP-U/GTP; to be done in the future O-RAN/ran_func_rc_subs.c ../flexric/test/rnd/fill_rnd_data_rc.c # this dependancy will be taken out once RAN Function Definition is implemented @@ -27,7 +27,7 @@ add_library(e2_ran_func_du_cucp_cuup STATIC O-RAN/ran_e2sm_ue_id.c O-RAN/ran_func_kpm.c # this file should only contain RRC/PDCP-C; to be done in the future # when nr-softmodem is divided in separate executables - ../flexric/test/rnd/fill_rnd_data_kpm.c # this dependancy will be taken out once RAN Function Definition is implemented + O-RAN/ran_func_kpm_subs.c O-RAN/ran_func_rc.c # this file should only contain RRC/PDCP-C; to be done in the future # when nr-softmodem is divided in separate executables O-RAN/ran_func_rc_subs.c 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 357a82b277..1a3099bbaf 100644 --- a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.c +++ b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.c @@ -20,39 +20,162 @@ */ #include "ran_func_kpm.h" -#include "openair2/E2AP/flexric/test/rnd/fill_rnd_data_kpm.h" // this dependancy will be taken out once RAN Function Definition is implemented -#include "openair2/E2AP/flexric/src/util/time_now_us.h" -#include "common/utils/assertions.h" +#include "ran_func_kpm_subs.h" +#include "ran_e2sm_ue_id.h" -#if defined (NGRAN_GNB_DU) -#include "openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h" -#include "openair2/LAYER2/nr_rlc/nr_rlc_entity.h" -#include "openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h" -#endif - -#if defined (NGRAN_GNB_CUCP) -#include "openair2/RRC/NR/rrc_gNB_UE_context.h" -#include "openair3/NGAP/ngap_gNB_ue_context.h" -#endif - -#if defined (NGRAN_GNB_CUUP) -#include "openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h" -#include "openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h" #include "openair2/E1AP/e1ap_common.h" +#include "openair2/E2AP/flexric/src/util/time_now_us.h" +#include "openair2/F1AP/f1ap_ids.h" + +static pthread_once_t once_kpm_mutex = PTHREAD_ONCE_INIT; + +static void init_once_kpm(void) +{ + init_kpm_subs_data(); +} + +static ngran_node_t get_e2_node_type(void) +{ + ngran_node_t node_type = 0; + +#if defined(NGRAN_GNB_DU) && defined(NGRAN_GNB_CUUP) && defined(NGRAN_GNB_CUCP) + node_type = RC.nrrrc[0]->node_type; +#elif defined (NGRAN_GNB_CUUP) + node_type = ngran_gNB_CUUP; #endif -#include "openair2/F1AP/f1ap_ids.h" -#include -#include + return node_type; +} -/* Please note that only one executable nr-softmodem exists for DU, CU, CU-CP and gNB-mono nodes; - the layer separation should be done better in the future */ +typedef struct { + size_t sz; + ue_id_e2sm_t* ue_id; -#if defined (NGRAN_GNB_CUUP) -typedef struct uldlcounter { - uint32_t dl; - uint32_t ul; -} uldlcounter_t; + // Optional + // only used to retreive MAC/RLC stats + NR_UE_info_t* ue_info_list; +}arr_ue_id_t; + +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}; + + // Measurement Record + data_item.meas_record_len = len; // record data list length corresponds to info list length from action definition + + data_item.meas_record_lst = calloc(len, sizeof(meas_record_lst_t)); + assert(data_item.meas_record_lst != NULL && "Memory exhausted"); + + for (size_t i = 0; i < len; i++) { + // Measurement Type as requested in Action Definition + assert(meas_info_lst[i].meas_type.type == NAME_MEAS_TYPE && "Only NAME supported"); + + 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); + + free(meas_info_name_str); + } + + return data_item; +} + +static kpm_ind_msg_format_1_t fill_kpm_ind_msg_frm_1(cudu_ue_info_pair_t ue_info, const size_t ue_idx, const kpm_act_def_format_1_t* act_def_fr_1) +{ + kpm_ind_msg_format_1_t msg_frm_1 = {0}; + + // Measurement Data contains a set of Meas Records, each collected at each granularity period + msg_frm_1.meas_data_lst_len = 1; /* this value is equal to (kpm_ric_event_trigger_format_1.report_period_ms/act_def_fr_1->gran_period_ms) + please, check their values in xApp */ + + msg_frm_1.meas_data_lst = calloc(msg_frm_1.meas_data_lst_len, sizeof(*msg_frm_1.meas_data_lst)); + assert(msg_frm_1.meas_data_lst != NULL && "Memory exhausted" ); + + msg_frm_1.meas_data_lst[0] = fill_kpm_meas_data_item(act_def_fr_1->meas_info_lst, + act_def_fr_1->meas_info_lst_len, + act_def_fr_1->gran_period_ms, + ue_info, + ue_idx); + + // Measurement Information - OPTIONAL + msg_frm_1.meas_info_lst_len = act_def_fr_1->meas_info_lst_len; + msg_frm_1.meas_info_lst = calloc(msg_frm_1.meas_info_lst_len, sizeof(meas_info_format_1_lst_t)); + assert(msg_frm_1.meas_info_lst != NULL && "Memory exhausted"); + for (size_t i = 0; i < msg_frm_1.meas_info_lst_len; i++) { + msg_frm_1.meas_info_lst[i] = cp_meas_info_format_1_lst(&act_def_fr_1->meas_info_lst[i]); + } + + return msg_frm_1; +} + +static cudu_ue_info_pair_t fill_ue_related_info(arr_ue_id_t* arr_ue_id, const size_t ue_idx) +{ + cudu_ue_info_pair_t ue_info = {0}; + + if (arr_ue_id->ue_id[ue_idx].type == GNB_UE_ID_E2SM) { + ue_info.rrc_ue_id = *arr_ue_id->ue_id[ue_idx].gnb.ran_ue_id; // rrc_ue_id + ue_info.ue = &arr_ue_id->ue_info_list[ue_idx]; + } else if (arr_ue_id->ue_id[ue_idx].type == GNB_CU_UP_UE_ID_E2SM) { + /* in OAI implementation, CU-UP ue id = CU-CP ue id + => CU-UP ue id = rrc_ue_id, but it should not be the case by the spec */ + ue_info.rrc_ue_id = *arr_ue_id->ue_id[ue_idx].gnb_cu_up.ran_ue_id; // cucp_ue_id = rrc_ue_id + } else if (arr_ue_id->ue_id[ue_idx].type == GNB_DU_UE_ID_E2SM) { + ue_info.rrc_ue_id = *arr_ue_id->ue_id[ue_idx].gnb_du.ran_ue_id; // rrc_ue_id + ue_info.ue = &arr_ue_id->ue_info_list[ue_idx]; + } + + return ue_info; +} + +static kpm_ind_msg_format_3_t fill_kpm_ind_msg_frm_3(arr_ue_id_t* arr_ue_id, const kpm_act_def_format_1_t* act_def_fr_1) +{ + assert(act_def_fr_1 != NULL); + + kpm_ind_msg_format_3_t msg_frm_3 = {0}; + + // Fill UE Measurement Reports + msg_frm_3.ue_meas_report_lst_len = arr_ue_id->sz; + msg_frm_3.meas_report_per_ue = calloc(msg_frm_3.ue_meas_report_lst_len, sizeof(meas_report_per_ue_t)); + assert(msg_frm_3.meas_report_per_ue != NULL && "Memory exhausted"); + + for (size_t i = 0; iue_id[i]); + + // Fill UE related info + cudu_ue_info_pair_t ue_info = fill_ue_related_info(arr_ue_id, i); + + // Fill UE measurements + 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); + } + + return msg_frm_3; +} + +static void capture_sst_sd(test_cond_value_t* test_cond_value, uint8_t *sst, uint32_t **sd) +{ + DevAssert(sst != NULL); + DevAssert(sd != NULL); + + // S-NSSAI is an OCTET_STRING, as defined by spec + switch (test_cond_value->type) { + case OCTET_STRING_TEST_COND_VALUE: { + if (test_cond_value->octet_string_value->len == 1) { + *sst = test_cond_value->octet_string_value->buf[0]; + *sd = NULL; + } else { + DevAssert(test_cond_value->octet_string_value->len == 4); + uint8_t *buf = test_cond_value->octet_string_value->buf; + *sst = buf[0]; + *sd = malloc(**sd); + **sd = buf[1] << 16 | buf[2] << 8 | buf[3]; + } + break; + } + default: + AssertFatal(false, "test condition value %d impossible\n", test_cond_value->type); + } +} static bool nssai_matches(nssai_t a_nssai, uint8_t b_sst, const uint32_t *b_sd) { @@ -64,552 +187,162 @@ static bool nssai_matches(nssai_t a_nssai, uint8_t b_sst, const uint32_t *b_sd) } } -static uldlcounter_t last_pdcp_sdu_total_bytes[MAX_MOBILES_PER_GNB] = {0}; - -static gnb_cu_up_e2sm_t fill_gnb_cu_up_data(const ue_id_t cucp_ue_id) +static arr_ue_id_t filter_ues_by_s_nssai_in_cu(const test_info_lst_t test_info) { - gnb_cu_up_e2sm_t gnb_cu_up = {0}; + assert(test_info.S_NSSAI == TRUE_TEST_COND_TYPE && "Must be true"); + assert(test_info.test_cond != NULL && "Must be filled, even though it's optional by the specification"); + assert(*test_info.test_cond == EQUAL_TEST_COND && "Currently support EQUAL test condition"); + assert(test_info.test_cond_value != NULL && "Must be filled, even though it's optional by the specification"); + + uint8_t sst = 0; + uint32_t *sd = NULL; + capture_sst_sd(test_info.test_cond_value, &sst, &sd); - // 6.2.3.20 - // Mandatory - gnb_cu_up.gnb_cu_cp_ue_e1ap = cucp_ue_id; + arr_ue_id_t arr_ue_id = {.sz = 0}; + arr_ue_id.ue_id = calloc(MAX_MOBILES_PER_GNB, sizeof(ue_id_e2sm_t)); + assert(arr_ue_id.ue_id != NULL); - // 6.2.3.25 - // RAN UE ID - // Optional - gnb_cu_up.ran_ue_id = NULL; + struct rrc_gNB_ue_context_s* rrc_ue_context = NULL; + RB_FOREACH(rrc_ue_context, rrc_nr_ue_tree_s, &RC.nrrrc[0]->rrc_ue_head) { + gNB_RRC_UE_t *ue = &rrc_ue_context->ue_context; + for (int p = 0; p < ue->nb_of_pdusessions; ++p) { + pdusession_t *pdu = &ue->pduSession[p].param; + if (nssai_matches(pdu->nssai, sst, sd)) { + arr_ue_id.ue_id[arr_ue_id.sz] = fill_ue_id_data[ngran_gNB_CU](ue, 0, 0); - return gnb_cu_up; + arr_ue_id.sz++; + break; + } + } + AssertFatal(arr_ue_id.sz < MAX_MOBILES_PER_GNB, "cannot have more UEs than global UE number maximum\n"); + } + + free(sd); // if NULL, nothing happens + + return arr_ue_id; } -typedef struct { - ue_id_t pdcp_ue_id_list[MAX_MOBILES_PER_GNB]; // list of matched UEs on PDCP-U level - size_t num_ues; - -} matched_ues_pdcp_t; - - __attribute__((unused)) -static size_t filter_ues_by_s_nssai_in_cuup(test_cond_e const condition, uint8_t sst, const uint32_t *sd, matched_ues_pdcp_t* matches) +static arr_ue_id_t filter_ues_by_s_nssai_in_cuup(const test_info_lst_t test_info) { - DevAssert(matches != NULL); - AssertFatal(condition == EQUAL_TEST_COND, "Condition %d not yet implemented\n", condition); + assert(test_info.S_NSSAI == TRUE_TEST_COND_TYPE && "Must be true"); + assert(test_info.test_cond != NULL && "Must be filled, even though it's optional by the specification"); + assert(*test_info.test_cond == EQUAL_TEST_COND && "Currently support EQUAL test condition"); + assert(test_info.test_cond_value != NULL && "Must be filled, even though it's optional by the specification"); + + uint8_t sst = 0; + uint32_t *sd = NULL; + capture_sst_sd(test_info.test_cond_value, &sst, &sd); + + arr_ue_id_t arr_ue_id = {.sz = 0}; + arr_ue_id.ue_id = calloc(MAX_MOBILES_PER_GNB, sizeof(ue_id_e2sm_t)); + assert(arr_ue_id.ue_id != NULL); // Get NSSAI info from E1 context - const instance_t CUuniqInstance = 0; - const e1ap_upcp_inst_t *e1inst = getCxtE1(CUuniqInstance); + const instance_t e1_inst = 0; + const e1ap_upcp_inst_t *e1inst = getCxtE1(e1_inst); // currently the CU-UP does not store the slices, so we can only do this "coarse filtering" for(int s = 0; s < e1inst->cuup.setupReq.plmn[0].supported_slices; s++) { if (nssai_matches(e1inst->cuup.setupReq.plmn[0].slice[s], sst, sd)) { - matches->num_ues = nr_pdcp_get_num_ues(matches->pdcp_ue_id_list, MAX_MOBILES_PER_GNB); - } - } - - return matches->num_ues; -} + ue_id_t *pdcp_ue_id_list = calloc(MAX_MOBILES_PER_GNB, sizeof(ue_id_t)); + assert(pdcp_ue_id_list != NULL); -static nr_pdcp_statistics_t get_pdcp_stats_per_drb(const uint32_t rrc_ue_id) -{ - nr_pdcp_statistics_t pdcp = {0}; - const int srb_flag = 0; - const int rb_id = 1; // at the moment, only 1 DRB is supported - - // Get PDCP stats for specific DRB - const bool rc = nr_pdcp_get_statistics(rrc_ue_id, srb_flag, rb_id, &pdcp); - assert(rc == true && "Cannot get PDCP stats\n"); - - return pdcp; -} - -static meas_record_lst_t fill_ue_pdcp_data(const uint32_t rrc_ue_id, const size_t ue_idx, const char * meas_info_name_str) -{ - meas_record_lst_t meas_record = {0}; - - // Get PDCP stats per DRB - nr_pdcp_statistics_t pdcp = get_pdcp_stats_per_drb(rrc_ue_id); - - // Measurement Type as requested in Action Definition - if (strcmp(meas_info_name_str, "DRB.PdcpSduVolumeDL") == 0) { // 3GPP TS 28.522 - section 5.1.2.1.1.1 - meas_record.value = INTEGER_MEAS_VALUE; - - // Get DL data volume delivered to PDCP layer - meas_record.int_val = (pdcp.rxsdu_bytes - last_pdcp_sdu_total_bytes[ue_idx].dl)*8/1000; // [kb] - last_pdcp_sdu_total_bytes[ue_idx].dl = pdcp.rxsdu_bytes; - /* note: this measurement is calculated as per spec */ - } else if (strcmp(meas_info_name_str, "DRB.PdcpSduVolumeUL") == 0) { // 3GPP TS 28.522 - section 5.1.2.1.2.1 - meas_record.value = INTEGER_MEAS_VALUE; - - // Get UL data volume delivered from PDCP layer - meas_record.int_val = (pdcp.txsdu_bytes - last_pdcp_sdu_total_bytes[ue_idx].ul)*8/1000; // [kb] - last_pdcp_sdu_total_bytes[ue_idx].ul = pdcp.txsdu_bytes; - /* note: this measurement is calculated as per spec */ - } else { - assert(false && "Measurement Name not yet implemented"); - } - - - return meas_record; -} - -static kpm_ind_msg_format_1_t fill_kpm_ind_msg_frm_1_in_cu(const uint32_t rrc_ue_id, const size_t ue_idx, const kpm_act_def_format_1_t * act_def_fr_1) -{ - kpm_ind_msg_format_1_t msg_frm_1 = {0}; - - // Measurement Data contains a set of Meas Records, each collected at each granularity period - msg_frm_1.meas_data_lst_len = 1; /* this value is equal to (kpm_ric_event_trigger_format_1.report_period_ms/act_def_fr_1->gran_period_ms) - please, check their values in xApp */ - - msg_frm_1.meas_data_lst = calloc(msg_frm_1.meas_data_lst_len, sizeof(*msg_frm_1.meas_data_lst)); - assert(msg_frm_1.meas_data_lst != NULL && "Memory exhausted" ); - - for (size_t i = 0; imeas_info_lst_len; // record data list length corresponds to info list length from action definition - - msg_frm_1.meas_data_lst[i].meas_record_lst = calloc(msg_frm_1.meas_data_lst[i].meas_record_len, sizeof(meas_record_lst_t)); - assert(msg_frm_1.meas_data_lst[i].meas_record_lst != NULL && "Memory exhausted"); - - for (size_t j = 0; j < msg_frm_1.meas_data_lst[i].meas_record_len; j++) { // each meas record corresponds to one meas type - // Measurement Type as requested in Action Definition - switch (act_def_fr_1->meas_info_lst[j].meas_type.type) { - case NAME_MEAS_TYPE: { - char meas_info_name_str[act_def_fr_1->meas_info_lst[j].meas_type.name.len + 1]; - memcpy(meas_info_name_str, act_def_fr_1->meas_info_lst[j].meas_type.name.buf, act_def_fr_1->meas_info_lst[j].meas_type.name.len); - meas_info_name_str[act_def_fr_1->meas_info_lst[j].meas_type.name.len] = '\0'; - - msg_frm_1.meas_data_lst[i].meas_record_lst[j] = fill_ue_pdcp_data(rrc_ue_id, ue_idx, meas_info_name_str); - break; - } - case ID_MEAS_TYPE: - assert(false && "ID Measurement Type not yet implemented"); - - default: - assert(false && "Measurement Type not recognized"); + arr_ue_id.sz = nr_pdcp_get_num_ues(pdcp_ue_id_list, MAX_MOBILES_PER_GNB); + for (size_t i = 0; i < arr_ue_id.sz; i++) { + arr_ue_id.ue_id[i] = fill_ue_id_data[ngran_gNB_CUUP](NULL, 0, pdcp_ue_id_list[i]); } + free(pdcp_ue_id_list); } } - // Measurement Information - OPTIONAL - msg_frm_1.meas_info_lst_len = act_def_fr_1->meas_info_lst_len; - msg_frm_1.meas_info_lst = calloc(msg_frm_1.meas_info_lst_len, sizeof(meas_info_format_1_lst_t)); - assert(msg_frm_1.meas_info_lst != NULL && "Memory exhausted"); - for (size_t i = 0; i < msg_frm_1.meas_info_lst_len; i++) { - msg_frm_1.meas_info_lst[i] = cp_meas_info_format_1_lst(&act_def_fr_1->meas_info_lst[i]); - } + free(sd); // if NULL, nothing happens - return msg_frm_1; + return arr_ue_id; } - __attribute__((unused)) -static kpm_ind_msg_format_3_t fill_kpm_ind_msg_frm_3_in_cuup(const matched_ues_pdcp_t* matched_ues, - const kpm_act_def_format_1_t* act_def_fr_1) +static arr_ue_id_t filter_ues_by_s_nssai_in_du_or_monolithic(const test_info_lst_t test_info) { - assert(act_def_fr_1 != NULL); - - kpm_ind_msg_format_3_t msg_frm_3 = {0}; - - // Fill UE Measurement Reports - - msg_frm_3.ue_meas_report_lst_len = matched_ues->num_ues; - msg_frm_3.meas_report_per_ue = calloc(msg_frm_3.ue_meas_report_lst_len, sizeof(meas_report_per_ue_t)); - assert(msg_frm_3.meas_report_per_ue != NULL && "Memory exhausted"); - - for (size_t i = 0; ipdcp_ue_id_list[i]); - - // Fill UE related info - msg_frm_3.meas_report_per_ue[i].ind_msg_format_1 = - fill_kpm_ind_msg_frm_1_in_cu(matched_ues->pdcp_ue_id_list[i], i, act_def_fr_1); - } - - return msg_frm_3; -} -#endif - -#if defined (NGRAN_GNB_DU) -static uldlcounter_t last_rlc_pdu_total_bytes[MAX_MOBILES_PER_GNB] = {0}; -static uldlcounter_t last_total_prbs[MAX_MOBILES_PER_GNB] = {0}; - -static gnb_e2sm_t fill_gnb_data(rrc_gNB_ue_context_t * ue_context_p) -{ - gnb_e2sm_t gnb = {0}; - - // 6.2.3.16 - // Mandatory - // AMF UE NGAP ID - gnb.amf_ue_ngap_id = ue_context_p->ue_context.rrc_ue_id; - - // Mandatory - //GUAMI 6.2.3.17 - gnb.guami.plmn_id = (e2sm_plmn_t) { - .mcc = ue_context_p->ue_context.ue_guami.mcc, - .mnc = ue_context_p->ue_context.ue_guami.mnc, - .mnc_digit_len = ue_context_p->ue_context.ue_guami.mnc_len - }; + assert(test_info.S_NSSAI == TRUE_TEST_COND_TYPE && "Must be true"); + assert(test_info.test_cond != NULL && "Must be filled, even though it's optional by the specification"); + assert(*test_info.test_cond == EQUAL_TEST_COND && "Currently support EQUAL test condition"); + assert(test_info.test_cond_value != NULL && "Must be filled, even though it's optional by the specification"); - gnb.guami.amf_region_id = ue_context_p->ue_context.ue_guami.amf_region_id; - gnb.guami.amf_set_id = ue_context_p->ue_context.ue_guami.amf_set_id; - gnb.guami.amf_ptr = ue_context_p->ue_context.ue_guami.amf_pointer; + uint8_t sst = 0; + uint32_t *sd = NULL; + capture_sst_sd(test_info.test_cond_value, &sst, &sd); - // gNB-CU UE F1AP ID List - // C-ifCUDUseparated - if (NODE_IS_CU(RC.nrrrc[0]->node_type)) { - gnb.gnb_cu_ue_f1ap_lst_len = 1; - gnb.gnb_cu_ue_f1ap_lst = calloc(gnb.gnb_cu_ue_f1ap_lst_len, sizeof(uint32_t)); - assert(gnb.gnb_cu_ue_f1ap_lst != NULL); + arr_ue_id_t arr_ue_id = {.sz = 0}; + arr_ue_id.ue_id = calloc(MAX_MOBILES_PER_GNB, sizeof(ue_id_e2sm_t)); + assert(arr_ue_id.ue_id != NULL); - for (size_t i = 0; i < gnb.gnb_cu_ue_f1ap_lst_len; i++) { - gnb.gnb_cu_ue_f1ap_lst[i] = ue_context_p->ue_context.rrc_ue_id; - } - } + arr_ue_id.ue_info_list = calloc(MAX_MOBILES_PER_GNB, sizeof(NR_UE_info_t)); + assert(arr_ue_id.ue_info_list != NULL); - return gnb; -} - -static gnb_du_e2sm_t fill_gnb_du_data(const f1_ue_data_t * rrc_ue_id) -{ - gnb_du_e2sm_t gnb_du = {0}; - - // 6.2.3.21 - // gNB CU UE F1AP - // Mandatory - gnb_du.gnb_cu_ue_f1ap = rrc_ue_id->secondary_ue; - - // 6.2.3.25 - // RAN UE ID - // Optional - gnb_du.ran_ue_id = NULL; - - return gnb_du; -} -typedef struct { - NR_UE_info_t* ue_list[MAX_MOBILES_PER_GNB]; - size_t num_ues; -} matched_ues_mac_t; - -static size_t filter_ues_by_s_nssai_in_du_or_monolithic(test_cond_e const condition, - uint8_t sst, - const uint32_t *sd, - matched_ues_mac_t* matches) -{ - DevAssert(matches != NULL); - AssertFatal(condition == EQUAL_TEST_COND, "Condition %d not yet implemented", condition); + const ngran_node_t node_type = get_e2_node_type(); // Take MAC info - size_t i = 0; UE_iterator (RC.nrmac[0]->UE_info.list, ue) { NR_UE_sched_ctrl_t *sched_ctrl = &ue->UE_sched_ctrl; // UE matches if any of its DRBs matches for (int l = 0; l < sched_ctrl->dl_lc_num; ++l) { long lcid = sched_ctrl->dl_lc_ids[l]; if (nssai_matches(sched_ctrl->dl_lc_nssai[lcid], sst, sd)) { - matches->ue_list[i++] = ue; - break; - } - } - AssertFatal(i < MAX_MOBILES_PER_GNB, "cannot have more UEs than global UE number maximum\n"); - } - - matches->num_ues = i; - - return i; -} - -static nr_rlc_statistics_t get_rlc_stats_per_drb(NR_UE_info_t const * UE) -{ - assert(UE != NULL); - - nr_rlc_statistics_t rlc = {0}; - const int srb_flag = 0; - const int rb_id = 1; // at the moment, only 1 DRB is supported - - // Get RLC stats for specific DRB - const bool rc = nr_rlc_get_statistics(UE->rnti, srb_flag, rb_id, &rlc); - assert(rc == true && "Cannot get RLC stats\n"); - - // Activate average sojourn time at the RLC buffer for specific DRB - nr_rlc_activate_avg_time_to_tx(UE->rnti, rb_id+3, 1); - - return rlc; -} - -static meas_record_lst_t fill_ue_mac_rlc_data(const NR_UE_info_t* UE, const size_t ue_idx, const char * meas_info_name_str, const uint32_t gran_period_ms) -{ - assert(UE != NULL); - - meas_record_lst_t meas_record = {0}; - - // Get RLC stats per DRB - nr_rlc_statistics_t rlc = get_rlc_stats_per_drb(UE); - - // Measurement Type as requested in Action Definition - if (strcmp(meas_info_name_str, "DRB.UEThpDl") == 0) { // 3GPP TS 28.522 - section 5.1.1.3.1 - meas_record.value = REAL_MEAS_VALUE; - - // Calculate DL Thp - meas_record.real_val = (double)(rlc.txpdu_bytes - last_rlc_pdu_total_bytes[ue_idx].dl)*8/gran_period_ms; // [kbps] - last_rlc_pdu_total_bytes[ue_idx].dl = rlc.txpdu_bytes; - /* note: per spec, average UE throughput in DL (taken into consideration values from all UEs, and averaged) - here calculated as: UE specific throughput in DL */ - } else if (strcmp(meas_info_name_str, "DRB.UEThpUl") == 0) { // 3GPP TS 28.522 - section 5.1.1.3.3 - meas_record.value = REAL_MEAS_VALUE; - - // Calculate UL Thp - meas_record.real_val = (double)(rlc.rxpdu_bytes - last_rlc_pdu_total_bytes[ue_idx].ul)*8/gran_period_ms; // [kbps] - last_rlc_pdu_total_bytes[ue_idx].ul = rlc.rxpdu_bytes; - /* note: per spec, average UE throughput in UL (taken into consideration values from all UEs, and averaged) - here calculated as: UE specific throughput in UL */ - } else if (strcmp(meas_info_name_str, "DRB.RlcSduDelayDl") == 0) { // 3GPP TS 28.522 - section 5.1.3.3.3 - meas_record.value = REAL_MEAS_VALUE; - - // Get the value of sojourn time at the RLC buffer - meas_record.real_val = rlc.txsdu_avg_time_to_tx; // [μs] - /* note: by default this measurement is calculated for previous 100ms (openair2/LAYER2/nr_rlc/nr_rlc_entity.c:118, 173, 213); please, update according to your needs */ - } else if (strcmp(meas_info_name_str, "RRU.PrbTotDl") == 0) { // 3GPP TS 28.522 - section 5.1.1.2.1 - meas_record.value = INTEGER_MEAS_VALUE; - - // Get the number of DL PRBs - meas_record.int_val = UE->mac_stats.dl.total_rbs - last_total_prbs[ue_idx].dl; // [PRBs] - last_total_prbs[ue_idx].dl = UE->mac_stats.dl.total_rbs; - /* note: per spec, DL PRB usage [%] = (total used PRBs for DL traffic / total available PRBs for DL traffic) * 100 - here calculated as: aggregated DL PRBs (t) - aggregated DL PRBs (t-gran_period) */ - } else if (strcmp(meas_info_name_str, "RRU.PrbTotUl") == 0) { // 3GPP TS 28.522 - section 5.1.1.2.2 - meas_record.value = INTEGER_MEAS_VALUE; - - // Get the number of UL PRBs - meas_record.int_val = UE->mac_stats.ul.total_rbs - last_total_prbs[ue_idx].ul; // [PRBs] - last_total_prbs[ue_idx].ul = UE->mac_stats.ul.total_rbs; - /* note: per spec, UL PRB usage [%] = (total used PRBs for UL traffic / total available PRBs for UL traffic) * 100 - here calculated as: aggregated UL PRBs (t) - aggregated UL PRBs (t-gran_period) */ - } else { - assert(false && "Measurement Name not yet implemented"); - } - - return meas_record; -} - -static kpm_ind_msg_format_1_t fill_kpm_ind_msg_frm_1_in_du(const NR_UE_info_t* UE, const size_t ue_idx, const kpm_act_def_format_1_t * act_def_fr_1) -{ - kpm_ind_msg_format_1_t msg_frm_1 = {0}; - - // Measurement Data contains a set of Meas Records, each collected at each granularity period - msg_frm_1.meas_data_lst_len = 1; /* this value is equal to (kpm_ric_event_trigger_format_1.report_period_ms/act_def_fr_1->gran_period_ms) - please, check their values in xApp */ - - msg_frm_1.meas_data_lst = calloc(msg_frm_1.meas_data_lst_len, sizeof(*msg_frm_1.meas_data_lst)); - assert(msg_frm_1.meas_data_lst != NULL && "Memory exhausted" ); - - for (size_t i = 0; imeas_info_lst_len; // record data list length corresponds to info list length from action definition - - msg_frm_1.meas_data_lst[i].meas_record_lst = calloc(msg_frm_1.meas_data_lst[i].meas_record_len, sizeof(meas_record_lst_t)); - assert(msg_frm_1.meas_data_lst[i].meas_record_lst != NULL && "Memory exhausted"); - - for (size_t j = 0; j < msg_frm_1.meas_data_lst[i].meas_record_len; j++) { // each meas record corresponds to one meas type - // Measurement Type as requested in Action Definition - switch (act_def_fr_1->meas_info_lst[j].meas_type.type) { - case NAME_MEAS_TYPE: { - char meas_info_name_str[act_def_fr_1->meas_info_lst[j].meas_type.name.len + 1]; - memcpy(meas_info_name_str, act_def_fr_1->meas_info_lst[j].meas_type.name.buf, act_def_fr_1->meas_info_lst[j].meas_type.name.len); - meas_info_name_str[act_def_fr_1->meas_info_lst[j].meas_type.name.len] = '\0'; - - msg_frm_1.meas_data_lst[i].meas_record_lst[j] = fill_ue_mac_rlc_data(UE, ue_idx, meas_info_name_str, act_def_fr_1->gran_period_ms); - break; - } - case ID_MEAS_TYPE: - assert(false && "ID Measurement Type not yet implemented"); - - default: - assert(false && "Measurement Type not recognized"); - } - } - } - - // Measurement Information - OPTIONAL - msg_frm_1.meas_info_lst_len = act_def_fr_1->meas_info_lst_len; - msg_frm_1.meas_info_lst = calloc(msg_frm_1.meas_info_lst_len, sizeof(meas_info_format_1_lst_t)); - assert(msg_frm_1.meas_info_lst != NULL && "Memory exhausted"); - for (size_t i = 0; i < msg_frm_1.meas_info_lst_len; i++) { - msg_frm_1.meas_info_lst[i] = cp_meas_info_format_1_lst(&act_def_fr_1->meas_info_lst[i]); - } - - return msg_frm_1; -} - -static kpm_ind_msg_format_3_t fill_kpm_ind_msg_frm_3_in_du(const matched_ues_mac_t* matched_ues, - const kpm_act_def_format_1_t* act_def_fr_1) -{ - assert(act_def_fr_1 != NULL); - - - kpm_ind_msg_format_3_t msg_frm_3 = {0}; - - // Fill UE Measurement Reports - - msg_frm_3.ue_meas_report_lst_len = matched_ues->num_ues; - msg_frm_3.meas_report_per_ue = calloc(msg_frm_3.ue_meas_report_lst_len, sizeof(meas_report_per_ue_t)); - assert(msg_frm_3.meas_report_per_ue != NULL && "Memory exhausted"); - - for (size_t i = 0; iue_list[i]->rnti); // get gNB CU UE ID as rrc_ue_id - msg_frm_3.meas_report_per_ue[i].ue_meas_report_lst.type = GNB_DU_UE_ID_E2SM; - msg_frm_3.meas_report_per_ue[i].ue_meas_report_lst.gnb_du = fill_gnb_du_data(&rrc_ue_id); - - // Fill UE related info - msg_frm_3.meas_report_per_ue[i].ind_msg_format_1 = fill_kpm_ind_msg_frm_1_in_du(matched_ues->ue_list[i], i, act_def_fr_1); - } - - - return msg_frm_3; -} - -static kpm_ind_msg_format_1_t fill_kpm_ind_msg_frm_1_in_monolithic(const NR_UE_info_t* UE, const size_t ue_idx, const uint32_t rrc_ue_id, const kpm_act_def_format_1_t * act_def_fr_1) -{ - kpm_ind_msg_format_1_t msg_frm_1 = {0}; - - // Measurement Data contains a set of Meas Records, each collected at each granularity period - msg_frm_1.meas_data_lst_len = 1; /* this value is equal to (kpm_ric_event_trigger_format_1.report_period_ms/act_def_fr_1->gran_period_ms) - please, check their values in xApp */ - - msg_frm_1.meas_data_lst = calloc(msg_frm_1.meas_data_lst_len, sizeof(*msg_frm_1.meas_data_lst)); - assert(msg_frm_1.meas_data_lst != NULL && "Memory exhausted" ); - - for (size_t i = 0; imeas_info_lst_len; // record data list length corresponds to info list length from action definition - - msg_frm_1.meas_data_lst[i].meas_record_lst = calloc(msg_frm_1.meas_data_lst[i].meas_record_len, sizeof(meas_record_lst_t)); - assert(msg_frm_1.meas_data_lst[i].meas_record_lst != NULL && "Memory exhausted"); - - for (size_t j = 0; j < msg_frm_1.meas_data_lst[i].meas_record_len; j++) { // each meas record corresponds to one meas type - // Measurement Type as requested in Action Definition - switch (act_def_fr_1->meas_info_lst[j].meas_type.type) { - case NAME_MEAS_TYPE: { - char meas_info_name_str[act_def_fr_1->meas_info_lst[j].meas_type.name.len + 1]; - memcpy(meas_info_name_str, act_def_fr_1->meas_info_lst[j].meas_type.name.buf, act_def_fr_1->meas_info_lst[j].meas_type.name.len); - meas_info_name_str[act_def_fr_1->meas_info_lst[j].meas_type.name.len] = '\0'; - - if (strcmp(meas_info_name_str, "DRB.PdcpSduVolumeDL") == 0 || strcmp(meas_info_name_str, "DRB.PdcpSduVolumeUL") == 0) { - msg_frm_1.meas_data_lst[i].meas_record_lst[j] = fill_ue_pdcp_data(rrc_ue_id, ue_idx, meas_info_name_str); + if (node_type == ngran_gNB_DU) { + f1_ue_data_t rrc_ue_id = du_get_f1_ue_data(ue->rnti); // gNB CU UE ID = rrc_ue_id + arr_ue_id.ue_id[arr_ue_id.sz] = fill_ue_id_data[ngran_gNB_DU](NULL, rrc_ue_id.secondary_ue, 0); } else { - msg_frm_1.meas_data_lst[i].meas_record_lst[j] = fill_ue_mac_rlc_data(UE, ue_idx, meas_info_name_str, act_def_fr_1->gran_period_ms); + rrc_gNB_ue_context_t* rrc_ue_context = rrc_gNB_get_ue_context_by_rnti(RC.nrrrc[0], -1, ue->rnti); + arr_ue_id.ue_id[arr_ue_id.sz] = fill_ue_id_data[ngran_gNB](&rrc_ue_context->ue_context, 0, 0); } - - break; - } - case ID_MEAS_TYPE: - assert(false && "ID Measurement Type not yet implemented"); - default: - assert(false && "Measurement Type not recognized"); - } - } - } + // store NR_UE_info_t + arr_ue_id.ue_info_list[arr_ue_id.sz] = *ue; - // Measurement Information - OPTIONAL - msg_frm_1.meas_info_lst_len = act_def_fr_1->meas_info_lst_len; - msg_frm_1.meas_info_lst = calloc(msg_frm_1.meas_info_lst_len, sizeof(meas_info_format_1_lst_t)); - assert(msg_frm_1.meas_info_lst != NULL && "Memory exhausted"); - for (size_t i = 0; i < msg_frm_1.meas_info_lst_len; i++) { - msg_frm_1.meas_info_lst[i] = cp_meas_info_format_1_lst(&act_def_fr_1->meas_info_lst[i]); - } - - return msg_frm_1; -} - -static kpm_ind_msg_format_3_t fill_kpm_ind_msg_frm_3_in_monolithic(const matched_ues_mac_t* matched_ues, - const kpm_act_def_format_1_t* act_def_fr_1) -{ - assert(act_def_fr_1 != NULL); - - - kpm_ind_msg_format_3_t msg_frm_3 = {0}; - - // Fill UE Measurement Reports - - msg_frm_3.ue_meas_report_lst_len = matched_ues->num_ues; - msg_frm_3.meas_report_per_ue = calloc(msg_frm_3.ue_meas_report_lst_len, sizeof(meas_report_per_ue_t)); - assert(msg_frm_3.meas_report_per_ue != NULL && "Memory exhausted"); - - - for (size_t i = 0; iue_list[i]->rnti); - msg_frm_3.meas_report_per_ue[i].ue_meas_report_lst.type = GNB_UE_ID_E2SM; - msg_frm_3.meas_report_per_ue[i].ue_meas_report_lst.gnb = fill_gnb_data(rrc_ue_context_list); - - // Fill UE related info - msg_frm_3.meas_report_per_ue[i].ind_msg_format_1 = - fill_kpm_ind_msg_frm_1_in_monolithic(matched_ues->ue_list[i], i, rrc_ue_context_list->ue_context.rrc_ue_id, act_def_fr_1); - } - - return msg_frm_3; -} -#endif - -#if defined (NGRAN_GNB_CUCP) -typedef struct { - uint32_t rrc_ue_id_list[MAX_MOBILES_PER_GNB]; // list of matched UEs on RRC level containing only rrc_ue_id (gNB CU UE ID) - size_t num_ues; - -} matched_ues_rrc_t; - -static size_t filter_ues_by_s_nssai_in_cu(test_cond_e const condition, uint8_t sst, const uint32_t *sd, matched_ues_rrc_t* matches) -{ - DevAssert(matches != NULL); - AssertFatal(condition == EQUAL_TEST_COND, "Condition %d not yet implemented\n", condition); - - struct rrc_gNB_ue_context_s *ue_context_p1 = NULL; - size_t i = 0; - RB_FOREACH(ue_context_p1, rrc_nr_ue_tree_s, &RC.nrrrc[0]->rrc_ue_head) { - gNB_RRC_UE_t *ue = &ue_context_p1->ue_context; - for (int p = 0; p < ue->nb_of_pdusessions; ++p) { - pdusession_t *pdu = &ue->pduSession[0].param; - if (nssai_matches(pdu->nssai, sst, sd)) { - matches->rrc_ue_id_list[i++] = ue_context_p1->ue_context.rrc_ue_id; + arr_ue_id.sz++; break; } } - AssertFatal(i < MAX_MOBILES_PER_GNB, "cannot have more UEs than global UE number maximum\n"); + AssertFatal(arr_ue_id.sz < MAX_MOBILES_PER_GNB, "cannot have more UEs than global UE number maximum\n"); } - matches->num_ues = i; - - return i; + free(sd); // if NULL, nothing happens + + return arr_ue_id; } -static kpm_ind_msg_format_3_t fill_kpm_ind_msg_frm_3_in_cu(const matched_ues_rrc_t* matched_ues, - const kpm_act_def_format_1_t* act_def_fr_1) +typedef arr_ue_id_t (*ue_type_matcher)(const test_info_lst_t test_info); + +static ue_type_matcher match_s_nssai_test_cond_type[END_NGRAN_NODE_TYPE] = { - assert(act_def_fr_1 != NULL); + NULL, + NULL, + filter_ues_by_s_nssai_in_du_or_monolithic, + NULL, + NULL, + filter_ues_by_s_nssai_in_cu, + NULL, + filter_ues_by_s_nssai_in_du_or_monolithic, + NULL, + NULL, // for CU-CP we don't use this + filter_ues_by_s_nssai_in_cuup, +}; +typedef ue_type_matcher (*filter_ues)[END_NGRAN_NODE_TYPE]; - kpm_ind_msg_format_3_t msg_frm_3 = {0}; +static filter_ues match_cond_arr[END_TEST_COND_TYPE_KPM_V2_01] = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + &match_s_nssai_test_cond_type, +}; - // Fill UE Measurement Reports - - msg_frm_3.ue_meas_report_lst_len = matched_ues->num_ues; - msg_frm_3.meas_report_per_ue = calloc(msg_frm_3.ue_meas_report_lst_len, sizeof(meas_report_per_ue_t)); - assert(msg_frm_3.meas_report_per_ue != NULL && "Memory exhausted"); - - for (size_t i = 0; irrc_ue_id_list[i]); - msg_frm_3.meas_report_per_ue[i].ue_meas_report_lst.type = GNB_UE_ID_E2SM; - msg_frm_3.meas_report_per_ue[i].ue_meas_report_lst.gnb = fill_gnb_data(rrc_ue_context_list); - - // Fill UE related info - msg_frm_3.meas_report_per_ue[i].ind_msg_format_1 = - fill_kpm_ind_msg_frm_1_in_cu(matched_ues->rrc_ue_id_list[i], i, act_def_fr_1); - } - - return msg_frm_3; -} -#endif static kpm_ric_ind_hdr_format_1_t kpm_ind_hdr_frm_1(void) { @@ -627,60 +360,10 @@ static kpm_ric_ind_hdr_format_1_t kpm_ind_hdr_frm_1(void) hdr_frm_1.fileformat_version = NULL; // Check E2 Node NG-RAN Type - #if defined (NGRAN_GNB_DU) - if (RC.nrrrc[0]->node_type == ngran_gNB_DU) { - hdr_frm_1.sender_name = calloc(1, sizeof(byte_array_t)); - hdr_frm_1.sender_name->buf = calloc(strlen("OAI-DU") + 1, sizeof(char)); - memcpy(hdr_frm_1.sender_name->buf, "OAI-DU", strlen("OAI-DU")); - hdr_frm_1.sender_name->len = strlen("OAI-DU"); - - hdr_frm_1.sender_type = calloc(1, sizeof(byte_array_t)); - hdr_frm_1.sender_type->buf = calloc(strlen("DU") + 1, sizeof(char)); - memcpy(hdr_frm_1.sender_type->buf, "DU", strlen("DU")); - hdr_frm_1.sender_type->len = strlen("DU"); - } else if (RC.nrrrc[0]->node_type == ngran_gNB_CU) { - hdr_frm_1.sender_name = calloc(1, sizeof(byte_array_t)); - hdr_frm_1.sender_name->buf = calloc(strlen("OAI-CU") + 1, sizeof(char)); - memcpy(hdr_frm_1.sender_name->buf, "OAI-CU", strlen("OAI-CU")); - hdr_frm_1.sender_name->len = strlen("OAI-CU"); - - hdr_frm_1.sender_type = calloc(1, sizeof(byte_array_t)); - hdr_frm_1.sender_type->buf = calloc(strlen("CU") + 1, sizeof(char)); - memcpy(hdr_frm_1.sender_type->buf, "CU", strlen("CU")); - hdr_frm_1.sender_type->len = strlen("CU"); - } else if (RC.nrrrc[0]->node_type == ngran_gNB) { - hdr_frm_1.sender_name = calloc(1, sizeof(byte_array_t)); - hdr_frm_1.sender_name->buf = calloc(strlen("OAI-MONO") + 1, sizeof(char)); - memcpy(hdr_frm_1.sender_name->buf, "OAI-MONO", strlen("OAI-MONO")); - hdr_frm_1.sender_name->len = strlen("OAI-MONO"); - - hdr_frm_1.sender_type = calloc(1, sizeof(byte_array_t)); - hdr_frm_1.sender_type->buf = calloc(strlen("MONO") + 1, sizeof(char)); - memcpy(hdr_frm_1.sender_type->buf, "MONO", strlen("MONO")); - hdr_frm_1.sender_type->len = strlen("MONO"); - } else if (RC.nrrrc[0]->node_type == ngran_gNB_CUCP) { - return hdr_frm_1; // nothing to fill - } else { - assert(0!=0 && "Unknown node type"); - } - #endif - - #if defined (NGRAN_GNB_CUUP) + const ngran_node_t node_type = get_e2_node_type(); + const char* sender_name = get_ngran_name(node_type); hdr_frm_1.sender_name = calloc(1, sizeof(byte_array_t)); - hdr_frm_1.sender_name->buf = calloc(strlen("OAI-CU-UP") + 1, sizeof(char)); - memcpy(hdr_frm_1.sender_name->buf, "OAI-CU-UP", strlen("OAI-CU-UP")); - hdr_frm_1.sender_name->len = strlen("OAI-CU-UP"); - - hdr_frm_1.sender_type = calloc(1, sizeof(byte_array_t)); - hdr_frm_1.sender_type->buf = calloc(strlen("CU-UP") + 1, sizeof(char)); - memcpy(hdr_frm_1.sender_type->buf, "CU-UP", strlen("CU-UP")); - hdr_frm_1.sender_type->len = strlen("CU-UP"); - #endif - - hdr_frm_1.vendor_name = calloc(1, sizeof(byte_array_t)); - hdr_frm_1.vendor_name->buf = calloc(strlen("OAI") + 1, sizeof(char)); - memcpy(hdr_frm_1.vendor_name->buf, "OAI", strlen("OAI")); - hdr_frm_1.vendor_name->len = strlen("OAI"); + *hdr_frm_1.sender_name = cp_str_to_ba(sender_name); return hdr_frm_1; } @@ -695,40 +378,6 @@ kpm_ind_hdr_t kpm_ind_hdr(void) return hdr; } -static void capture_sst_sd(test_info_lst_t* test, uint8_t *sst, uint32_t **sd) -{ - DevAssert(test != NULL && test->test_cond_value != NULL); - DevAssert(sst != NULL); - DevAssert(sd != NULL); - - // we made a mistake in the past: NSSAI is supposed to be an OCTET_STRING, - // but earlier version of the RAN function and the xApp used integer, so - // handle this gracefully by accepting integer as well - switch (test->test_cond_value->type) { - case INTEGER_TEST_COND_VALUE: { - AssertFatal(*test->test_cond_value->int_value <= 0xff, "illegal SST %ld\n", *test->test_cond_value->int_value); - *sst = *test->test_cond_value->int_value; - *sd = NULL; - break; - } - case OCTET_STRING_TEST_COND_VALUE: { - if (test->test_cond_value->octet_string_value->len == 1) { - *sst = test->test_cond_value->octet_string_value->buf[0]; - *sd = NULL; - } else { - DevAssert(test->test_cond_value->octet_string_value->len == 4); - uint8_t *buf = test->test_cond_value->octet_string_value->buf; - *sst = buf[0]; - *sd = malloc(**sd); - **sd = buf[1] << 16 | buf[2] << 8 | buf[3]; - } - break; - } - default: - AssertFatal(false, "test condition value %d impossible\n", test->test_cond_value->type); - } -} - bool read_kpm_sm(void* data) { assert(data != NULL); @@ -748,113 +397,17 @@ bool read_kpm_sm(void* data) // Filter the UE by the test condition criteria kpm_act_def_format_4_t const* frm_4 = &kpm->act_def->frm_4; // 8.2.1.2.4 for (size_t i = 0; i < frm_4->matching_cond_lst_len; i++) { - switch (frm_4->matching_cond_lst[i].test_info_lst.test_cond_type) { - case GBR_TEST_COND_TYPE: { - assert(0 != 0 && "Not implemented"); - break; - } - case AMBR_TEST_COND_TYPE: { - assert(0 != 0 && "Not implemented"); - break; - } - case IsStat_TEST_COND_TYPE: { - assert(0 != 0 && "Not implemented"); - break; - } - case IsCatM_TEST_COND_TYPE: { - assert(0 != 0 && "Not implemented"); - break; - } + const test_info_lst_t test_info = frm_4->matching_cond_lst[i].test_info_lst; + const ngran_node_t node_type = get_e2_node_type(); - case DL_RSRP_TEST_COND_TYPE: { - assert(0 != 0 && "Not implemented"); - break; - } + /* Based on the node type (gNB-mono, CU, DU,...) and matching condition (S-NSSAI, DL RSRP, GBR,...) + get array of E2SM UE IDs with optionally their MAC info */ + ue_type_matcher fp_match_cond_type = (*match_cond_arr[test_info.test_cond_type])[node_type]; + arr_ue_id_t arr_ue_id = fp_match_cond_type(test_info); - case DL_RSRQ_TEST_COND_TYPE: { - assert(0 != 0 && "Not implemented"); - break; - } - - case UL_RSRP_TEST_COND_TYPE: { - assert(0 != 0 && "Not implemented"); - break; - } - - case CQI_TEST_COND_TYPE: { - assert(0 != 0 && "Not implemented"); - break; - } - - case fiveQI_TEST_COND_TYPE: { - assert(0 != 0 && "Not implemented"); - break; - } - - case QCI_TEST_COND_TYPE: { - ; - assert(0 != 0 && "Not implemented"); - break; - } - case S_NSSAI_TEST_COND_TYPE: { - assert(frm_4->matching_cond_lst[i].test_info_lst.S_NSSAI == TRUE_TEST_COND_TYPE && "Must be true"); - assert(frm_4->matching_cond_lst[i].test_info_lst.test_cond != NULL && "Even though is optional.."); - assert(frm_4->matching_cond_lst[i].test_info_lst.test_cond_value != NULL && "Even though is optional.."); - - test_cond_e const test_cond = *frm_4->matching_cond_lst[i].test_info_lst.test_cond; - uint8_t sst = 0; - uint32_t *sd = NULL; - capture_sst_sd(&frm_4->matching_cond_lst[i].test_info_lst, &sst, &sd); - // Check E2 Node NG-RAN Type - /* Current implementation: - - we only have one executable nr-softmodem for 4 node types: DU, CU, gNB-mono, CU-CP - In the future, when nr-softmodem is separated, linking should be done as following: - DU: e2_ran_func_du - CU-CP : e2_ran_func_cucp - CU-UP: e2_ran_func_cuup (this is available at the moment, executable nr-cuup) - CU: e2_ran_func_cucp + e2_ran_func_cuup - gNB-mono: e2_ran_func_du + e2_ran_func_cucp + e2_ran_func_cuup */ - #if defined (NGRAN_GNB_DU) - if (RC.nrrrc[0]->node_type == ngran_gNB_DU) { - matched_ues_mac_t matched_ues = {0}; - matched_ues.num_ues = filter_ues_by_s_nssai_in_du_or_monolithic(test_cond, sst, sd, &matched_ues); - if (matched_ues.num_ues == 0) return false; - kpm->ind.msg.frm_3 = fill_kpm_ind_msg_frm_3_in_du(&matched_ues, &frm_4->action_def_format_1); - } else if (RC.nrrrc[0]->node_type == ngran_gNB_CU) { - matched_ues_rrc_t matched_ues = {0}; - matched_ues.num_ues = filter_ues_by_s_nssai_in_cu(test_cond, sst, sd, &matched_ues); - if (matched_ues.num_ues == 0) return false; - kpm->ind.msg.frm_3 = fill_kpm_ind_msg_frm_3_in_cu(&matched_ues, &frm_4->action_def_format_1); - } else if (RC.nrrrc[0]->node_type == ngran_gNB) { - matched_ues_mac_t matched_ues = {0}; - matched_ues.num_ues = filter_ues_by_s_nssai_in_du_or_monolithic(test_cond, sst, sd, &matched_ues); - if (matched_ues.num_ues == 0) return false; - kpm->ind.msg.frm_3 = fill_kpm_ind_msg_frm_3_in_monolithic(&matched_ues, &frm_4->action_def_format_1); - } else if (RC.nrrrc[0]->node_type == ngran_gNB_CUCP) { - return false; // at the moment, measurements regarding CU-CP node are not yet implemented - } else { - assert(false && "NG-RAN Type not implemented"); - } - - - #elif defined (NGRAN_GNB_CUUP) - matched_ues_pdcp_t matched_ues = {0}; - matched_ues.num_ues = filter_ues_by_s_nssai_in_cuup(test_cond, sst, sd, &matched_ues); - if (matched_ues.num_ues == 0) return false; - kpm->ind.msg.frm_3 = fill_kpm_ind_msg_frm_3_in_cuup(&matched_ues, &frm_4->action_def_format_1); - #endif - - - free(sd); // if NULL, nothing happens - - break; - } - - default: - assert(false && "Unknown Test condition"); - } + if (arr_ue_id.sz == 0) return false; + kpm->ind.msg.frm_3 = fill_kpm_ind_msg_frm_3(&arr_ue_id, &frm_4->action_def_format_1); } - break; } @@ -866,13 +419,117 @@ bool read_kpm_sm(void* data) return true; } +static const char* kpm_meas_du[] = { + "DRB.RlcSduDelayDl", + "DRB.UEThpDl", + "DRB.UEThpUl", + "RRU.PrbTotDl", + "RRU.PrbTotUl", +}; + +static const char* kpm_meas_gnb[] = { + "DRB.PdcpSduVolumeDL", + "DRB.PdcpSduVolumeUL", + "DRB.RlcSduDelayDl", + "DRB.UEThpDl", + "DRB.UEThpUl", + "RRU.PrbTotDl", + "RRU.PrbTotUl", +}; + +static const char* kpm_meas_cuup[] = { + "DRB.PdcpSduVolumeDL", + "DRB.PdcpSduVolumeUL", +}; + +typedef const char** meas_list; + +static const meas_list ran_def_kpm[END_NGRAN_NODE_TYPE] = { + NULL, + NULL, + kpm_meas_gnb, + NULL, + NULL, + kpm_meas_cuup, // at the moment, for CU, we use the same function as for CU-UP + NULL, + kpm_meas_du, + NULL, + NULL, // at the moment, no measurement is implemented in CU-CP + kpm_meas_cuup, +}; + void read_kpm_setup_sm(void* e2ap) { assert(e2ap != NULL); // assert(e2ap->type == KPM_V3_0_AGENT_IF_E2_SETUP_ANS_V0); kpm_e2_setup_t* kpm = (kpm_e2_setup_t*)(e2ap); - kpm->ran_func_def = fill_rnd_kpm_ran_func_def(); + + /* Fill the RAN Function Definition with currently supported measurements */ + + // RAN Function Name is already filled in fill_ran_function_name() in kpm_sm_agent.c + + // Fill supported measurements depending on the E2 node + // [1, 65535] + // 3GPP TS 28.552 + const ngran_node_t node_type = get_e2_node_type(); + const char** kpm_meas = ran_def_kpm[node_type]; + if (kpm_meas == NULL) return; // e.g. CU-CP node, doesn't support any measurements + size_t sz = 0; + while (kpm_meas[sz] != NULL) { + sz++; + } + + // Sequence of Report styles + const size_t sz_report = 1; + kpm->ran_func_def.sz_ric_report_style_list = sz_report; + kpm->ran_func_def.ric_report_style_list = calloc(sz_report, sizeof(ric_report_style_item_t)); + assert(kpm->ran_func_def.ric_report_style_list != NULL && "Memory exhausted"); + + ric_report_style_item_t* report_item = &kpm->ran_func_def.ric_report_style_list[0]; + + report_item->report_style_type = STYLE_4_RIC_SERVICE_REPORT; + const char report_style_name[] = "Common Condition-based, UE-level Measurement"; + report_item->report_style_name = cp_str_to_ba(report_style_name); + report_item->act_def_format_type = FORMAT_4_ACTION_DEFINITION; + + report_item->meas_info_for_action_lst_len = sz; + report_item->meas_info_for_action_lst = calloc(sz, sizeof(meas_info_for_action_lst_t)); + assert(report_item->meas_info_for_action_lst != NULL && "Memory exhausted"); + + for(size_t i = 0; i < sz; i++) { + meas_info_for_action_lst_t* meas_item = &report_item->meas_info_for_action_lst[i]; + // 8.3.9 + meas_item->name = cp_str_to_ba(kpm_meas[i]); + + // 8.3.10 - OPTIONAL + meas_item->id = NULL; + + // 8.3.26 - OPTIONAL + meas_item->bin_range_def = NULL; + } + + // Sequence of Event Trigger styles + const size_t sz_ev_tr = 1; + kpm->ran_func_def.sz_ric_event_trigger_style_list = sz_ev_tr; + kpm->ran_func_def.ric_event_trigger_style_list = calloc(sz_ev_tr, sizeof(ric_event_trigger_style_item_t)); + assert(kpm->ran_func_def.ric_event_trigger_style_list != NULL && "Memory exhausted"); + + ric_event_trigger_style_item_t* ev_tr_item = &kpm->ran_func_def.ric_event_trigger_style_list[0]; + + ev_tr_item->style_type = STYLE_1_RIC_EVENT_TRIGGER; + const char ev_style_name[] = "Periodic Report"; + ev_tr_item->style_name = cp_str_to_ba(ev_style_name); + ev_tr_item->format_type = FORMAT_1_RIC_EVENT_TRIGGER; + + // Supported RIC Indication Formats + report_item->ind_hdr_format_type = FORMAT_1_INDICATION_HEADER; // 8.3.5 + report_item->ind_msg_format_type = FORMAT_3_INDICATION_MESSAGE; // 8.3.5 + + // E2 Setup Request is sent periodically until the connection is established + // RC subscritpion data should be initialized only once + const int ret = pthread_once(&once_kpm_mutex, init_once_kpm); + DevAssert(ret == 0); } sm_ag_if_ans_t write_ctrl_kpm_sm(void const* src) 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 new file mode 100644 index 0000000000..80579e1754 --- /dev/null +++ b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm_subs.c @@ -0,0 +1,232 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "ran_func_kpm_subs.h" + +#include + +/* 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 { + uint32_t dl; + uint32_t ul; +} uldlcounter_t; + +static uldlcounter_t last_pdcp_sdu_total_bytes[MAX_MOBILES_PER_GNB] = {0}; + +static nr_pdcp_statistics_t get_pdcp_stats_per_drb(const uint32_t rrc_ue_id, const int rb_id) +{ + nr_pdcp_statistics_t pdcp = {0}; + const int srb_flag = 0; + + // Get PDCP stats for specific DRB + const bool rc = nr_pdcp_get_statistics(rrc_ue_id, srb_flag, rb_id, &pdcp); + assert(rc == true && "Cannot get PDCP stats\n"); + + return pdcp; +} + +/* 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) +{ + meas_record_lst_t meas_record = {0}; + + // Get PDCP stats per DRB + const int rb_id = 1; // at the moment, only 1 DRB is supported + nr_pdcp_statistics_t pdcp = get_pdcp_stats_per_drb(ue_info.rrc_ue_id, rb_id); + + meas_record.value = INTEGER_MEAS_VALUE; + + // Get DL data volume delivered to PDCP layer + meas_record.int_val = (pdcp.rxsdu_bytes - last_pdcp_sdu_total_bytes[ue_idx].dl)*8/1000; // [kb] + last_pdcp_sdu_total_bytes[ue_idx].dl = pdcp.rxsdu_bytes; + + return meas_record; +} + +/* 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) +{ + meas_record_lst_t meas_record = {0}; + + // Get PDCP stats per DRB + const int rb_id = 1; // at the moment, only 1 DRB is supported + nr_pdcp_statistics_t pdcp = get_pdcp_stats_per_drb(ue_info.rrc_ue_id, rb_id); + + meas_record.value = INTEGER_MEAS_VALUE; + + // Get UL data volume delivered from PDCP layer + meas_record.int_val = (pdcp.txsdu_bytes - last_pdcp_sdu_total_bytes[ue_idx].ul)*8/1000; // [kb] + last_pdcp_sdu_total_bytes[ue_idx].ul = pdcp.txsdu_bytes; + + return meas_record; +} + +#if defined (NGRAN_GNB_DU) +static uldlcounter_t last_rlc_pdu_total_bytes[MAX_MOBILES_PER_GNB] = {0}; +static uldlcounter_t last_total_prbs[MAX_MOBILES_PER_GNB] = {0}; + +static nr_rlc_statistics_t get_rlc_stats_per_drb(const rnti_t rnti, const int rb_id) +{ + nr_rlc_statistics_t rlc = {0}; + const int srb_flag = 0; + + // Get RLC stats for specific DRB + const bool rc = nr_rlc_get_statistics(rnti, srb_flag, rb_id, &rlc); + assert(rc == true && "Cannot get RLC stats\n"); + + // Activate average sojourn time at the RLC buffer for specific DRB + nr_rlc_activate_avg_time_to_tx(rnti, rb_id+3, 1); + + return rlc; +} + +/* 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) +{ + meas_record_lst_t meas_record = {0}; + + // Get RLC stats per DRB + const int rb_id = 1; // at the moment, only 1 DRB is supported + nr_rlc_statistics_t rlc = get_rlc_stats_per_drb(ue_info.ue->rnti, rb_id); + + meas_record.value = REAL_MEAS_VALUE; + + // Get the value of sojourn time at the RLC buffer + meas_record.real_val = rlc.txsdu_avg_time_to_tx; // [μs] + + return meas_record; +} + +/* 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) +{ + meas_record_lst_t meas_record = {0}; + + // Get RLC stats per DRB + const int rb_id = 1; // at the moment, only 1 DRB is supported + nr_rlc_statistics_t rlc = get_rlc_stats_per_drb(ue_info.ue->rnti, rb_id); + meas_record.value = REAL_MEAS_VALUE; + + // Calculate DL Thp + meas_record.real_val = (double)(rlc.txpdu_bytes - last_rlc_pdu_total_bytes[ue_idx].dl)*8/gran_period_ms; // [kbps] + last_rlc_pdu_total_bytes[ue_idx].dl = rlc.txpdu_bytes; + + return meas_record; +} + +/* 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) +{ + meas_record_lst_t meas_record = {0}; + + // Get RLC stats per DRB + const int rb_id = 1; // at the moment, only 1 DRB is supported + nr_rlc_statistics_t rlc = get_rlc_stats_per_drb(ue_info.ue->rnti, rb_id); + + meas_record.value = REAL_MEAS_VALUE; + + // Calculate UL Thp + meas_record.real_val = (double)(rlc.rxpdu_bytes - last_rlc_pdu_total_bytes[ue_idx].ul)*8/gran_period_ms; // [kbps] + last_rlc_pdu_total_bytes[ue_idx].ul = rlc.rxpdu_bytes; + + return meas_record; +} + +/* 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) +{ + 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] + 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) +{ + 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] + last_total_prbs[ue_idx].ul = ue_info.ue->mac_stats.ul.total_rbs; + + return meas_record; +} +#endif + +static kv_measure_t lst_measure[] = { + {.key = "DRB.PdcpSduVolumeDL", .value = fill_DRB_PdcpSduVolumeDL }, + {.key = "DRB.PdcpSduVolumeUL", .value = fill_DRB_PdcpSduVolumeUL }, +#if defined (NGRAN_GNB_DU) + {.key = "DRB.RlcSduDelayDl", .value = fill_DRB_RlcSduDelayDl }, + {.key = "DRB.UEThpDl", .value = fill_DRB_UEThpDl }, + {.key = "DRB.UEThpUl", .value = fill_DRB_UEThpUl }, + {.key = "RRU.PrbTotDl", .value = fill_RRU_PrbTotDl }, + {.key = "RRU.PrbTotUl", .value = fill_RRU_PrbTotUl }, +#endif +}; + +void init_kpm_subs_data(void) +{ + const size_t ht_len = sizeof(lst_measure) / sizeof(lst_measure[0]); + hcreate(ht_len); + + ENTRY kv_pair; + + for (size_t i = 0; i < ht_len; i++) { + kv_pair.key = lst_measure[i].key; + kv_pair.data = &lst_measure[i]; + hsearch(kv_pair, ENTER); + } +} + +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) +{ + assert(kpm_meas_name != NULL); + + ENTRY search_entry = {.key = kpm_meas_name}; + ENTRY *found_entry = hsearch(search_entry, FIND); + 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); + + 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 new file mode 100644 index 0000000000..7dbd807fa1 --- /dev/null +++ b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm_subs.h @@ -0,0 +1,49 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef RAN_FUNC_SM_KPM_SUBSCRIPTION_AGENT_H +#define RAN_FUNC_SM_KPM_SUBSCRIPTION_AGENT_H + +#include "openair2/E2AP/flexric/src/sm/kpm_sm/kpm_data_ie_wrapper.h" + +#include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h" +#include "openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h" +#include "openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h" + +typedef struct { + uint32_t rrc_ue_id; + NR_UE_info_t* ue; + +} 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{ + char* key; + kpm_meas_fp value; +} kv_measure_t; + + +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); + +#endif From 6a0e636f00afb04c07e00955b2f647d92ea92706 Mon Sep 17 00:00:00 2001 From: Teodora Date: Mon, 4 Mar 2024 14:36:49 +0100 Subject: [PATCH 37/39] RAN Control cleanup - RAN Function Definition implemented - use mutual E2SM UE ID file - write_ctrl_rc_sm function cleanup --- openair2/E2AP/RAN_FUNCTION/CMakeLists.txt | 4 +- .../E2AP/RAN_FUNCTION/O-RAN/ran_func_rc.c | 545 +++++++++++++++--- 2 files changed, 465 insertions(+), 84 deletions(-) diff --git a/openair2/E2AP/RAN_FUNCTION/CMakeLists.txt b/openair2/E2AP/RAN_FUNCTION/CMakeLists.txt index 906a3d2c55..acada2c6dd 100644 --- a/openair2/E2AP/RAN_FUNCTION/CMakeLists.txt +++ b/openair2/E2AP/RAN_FUNCTION/CMakeLists.txt @@ -11,10 +11,9 @@ add_library(e2_ran_func_cuup STATIC O-RAN/ran_func_kpm_subs.c O-RAN/ran_func_rc.c # this file should only contain PDCP-U/GTP; to be done in the future O-RAN/ran_func_rc_subs.c - ../flexric/test/rnd/fill_rnd_data_rc.c # this dependancy will be taken out once RAN Function Definition is implemented ) -target_link_libraries(e2_ran_func_cuup PUBLIC asn1_nr_rrc nr_rrc asn1_nr_rrc_hdrs e2_time_obj kpm_ric_info_common_obj 3gpp_derived_ie_obj) +target_link_libraries(e2_ran_func_cuup PUBLIC asn1_nr_rrc nr_rrc asn1_nr_rrc_hdrs e2_time_obj kpm_ric_info_common_obj 3gpp_derived_ie_obj sm_common_ie_obj) target_compile_definitions(e2_ran_func_cuup PUBLIC ${E2AP_VERSION} ${KPM_VERSION} NGRAN_GNB_CUUP) @@ -31,7 +30,6 @@ add_library(e2_ran_func_du_cucp_cuup STATIC O-RAN/ran_func_rc.c # this file should only contain RRC/PDCP-C; to be done in the future # when nr-softmodem is divided in separate executables O-RAN/ran_func_rc_subs.c - ../flexric/test/rnd/fill_rnd_data_rc.c # this dependancy will be taken out once RAN Function Definition is implemented ../flexric/src/sm/rc_sm/ie/rc_data_ie.c CUSTOMIZED/ran_func_mac.c CUSTOMIZED/ran_func_rlc.c diff --git a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc.c b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc.c index 7cf3e94f64..ef23bf2fd4 100644 --- a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc.c +++ b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc.c @@ -22,7 +22,7 @@ #include "ran_func_rc.h" #include "ran_func_rc_subs.h" #include "ran_func_rc_extern.h" -#include "../../flexric/test/rnd/fill_rnd_data_rc.h" // this dependancy will be taken out once RAN Function Definition is implemented +#include "ran_e2sm_ue_id.h" #include "../../flexric/src/sm/rc_sm/ie/ir/lst_ran_param.h" #include "../../flexric/src/sm/rc_sm/ie/ir/ran_param_list.h" #include "../../flexric/src/agent/e2_agent_api.h" @@ -35,17 +35,440 @@ static pthread_once_t once_rc_mutex = PTHREAD_ONCE_INIT; static rc_subs_data_t rc_subs_data = {0}; static pthread_mutex_t rc_mutex = PTHREAD_MUTEX_INITIALIZER; +static ngran_node_t get_e2_node_type(void) +{ + ngran_node_t node_type = 0; + +#if defined(NGRAN_GNB_DU) && defined(NGRAN_GNB_CUUP) && defined(NGRAN_GNB_CUCP) + node_type = RC.nrrrc[0]->node_type; +#elif defined (NGRAN_GNB_CUUP) + node_type = ngran_gNB_CUUP; +#endif + + return node_type; +} + static void init_once_rc(void) { init_rc_subs_data(&rc_subs_data); } +static void fill_rc_ev_trig(ran_func_def_ev_trig_t* ev_trig) +{ + // Sequence of EVENT TRIGGER styles + // [1 - 63] + ev_trig->sz_seq_ev_trg_style = 1; + ev_trig->seq_ev_trg_style = calloc(ev_trig->sz_seq_ev_trg_style, sizeof(seq_ev_trg_style_t)); + assert(ev_trig->seq_ev_trg_style != NULL && "Memory exhausted"); + + seq_ev_trg_style_t* ev_trig_style = &ev_trig->seq_ev_trg_style[0]; + + // RIC Event Trigger Style Type + // Mandatory + // 9.3.3 + // 6.2.2.2. + // INTEGER + ev_trig_style->style = 4; + + // RIC Event Trigger Style Name + // Mandatory + // 9.3.4 + // 6.2.2.3 + //PrintableString(SIZE(1..150,...)) + const char ev_style_name[] = "UE Information Change"; + ev_trig_style->name = cp_str_to_ba(ev_style_name); + + // RIC Event Trigger Format Type + // Mandatory + // 9.3.5 + // 6.2.2.4. + // INTEGER + ev_trig_style->format = FORMAT_4_E2SM_RC_EV_TRIGGER_FORMAT; + + // Sequence of RAN Parameters for L2 Variables + // [0 - 65535] + ev_trig->sz_seq_ran_param_l2_var = 0; + ev_trig->seq_ran_param_l2_var = NULL; + + //Sequence of Call Process Types + // [0-65535] + ev_trig->sz_seq_call_proc_type = 0; + ev_trig->seq_call_proc_type = NULL; + + // Sequence of RAN Parameters for Identifying UEs + // 0-65535 + ev_trig->sz_seq_ran_param_id_ue = 0; + ev_trig->seq_ran_param_id_ue = NULL; + + // Sequence of RAN Parameters for Identifying Cells + // 0-65535 + ev_trig->sz_seq_ran_param_id_cell = 0; + ev_trig->seq_ran_param_id_cell = NULL; +} + +static void fill_rc_report(ran_func_def_report_t* report) +{ + // Sequence of REPORT styles + // [1 - 63] + report->sz_seq_report_sty = 1; + report->seq_report_sty = calloc(report->sz_seq_report_sty, sizeof(seq_report_sty_t)); + assert(report->seq_report_sty != NULL && "Memory exhausted"); + + seq_report_sty_t* report_style = &report->seq_report_sty[0]; + + // RIC Report Style Type + // Mandatory + // 9.3.3 + // 6.2.2.2. + // INTEGER + report_style->report_type = 4; + + // RIC Report Style Name + // Mandatory + // 9.3.4 + // 6.2.2.3. + // PrintableString(SIZE(1..150,...)) + const char report_name[] = "UE Information"; + report_style->name = cp_str_to_ba(report_name); + + // Supported RIC Event Trigger Style Type + // Mandatory + // 9.3.3 + // 6.2.2.2. + // INTEGER + report_style->ev_trig_type = FORMAT_4_E2SM_RC_EV_TRIGGER_FORMAT; + + // RIC Report Action Format Type + // Mandatory + // 9.3.5 + // 6.2.2.4. + // INTEGER + report_style->act_frmt_type = FORMAT_1_E2SM_RC_ACT_DEF; + + // RIC Indication Header Format Type + // Mandatory + // 9.3.5 + // 6.2.2.4. + // INTEGER + report_style->ind_hdr_type = FORMAT_1_E2SM_RC_IND_HDR; + + // RIC Indication Message Format Type + // Mandatory + // 9.3.5 + // 6.2.2.4. + // INTEGER + report_style->ind_msg_type = FORMAT_2_E2SM_RC_IND_MSG; + + // Sequence of RAN Parameters Supported + // [0 - 65535] + report_style->sz_seq_ran_param = 1; + report_style->ran_param = calloc(report_style->sz_seq_ran_param, sizeof(seq_ran_param_3_t)); + assert(report_style->ran_param != NULL && "Memory exhausted"); + + // RAN Parameter ID + // Mandatory + // 9.3.8 + // [1- 4294967295] + report_style->ran_param[0].id = RRC_STATE_CHANGED_TO_E2SM_RC_RAN_PARAM_ID; + + // RAN Parameter Name + // Mandatory + // 9.3.9 + // [1-150] + const char ran_param_name[] = "RRC State"; + report_style->ran_param[0].name = cp_str_to_ba(ran_param_name); + + // RAN Parameter Definition + // Optional + // 9.3.51 + report_style->ran_param[0].def = NULL; +} + +static void fill_rc_control(ran_func_def_ctrl_t* ctrl) +{ + // Sequence of CONTROL styles + // [1 - 63] + ctrl->sz_seq_ctrl_style = 1; + ctrl->seq_ctrl_style = calloc(ctrl->sz_seq_ctrl_style, sizeof(seq_ctrl_style_t)); + assert(ctrl->seq_ctrl_style != NULL && "Memory exhausted"); + + seq_ctrl_style_t* ctrl_style = &ctrl->seq_ctrl_style[0]; + + // RIC Control Style Type + // Mandatory + // 9.3.3 + // 6.2.2.2 + ctrl_style->style_type = 1; + + //RIC Control Style Name + //Mandatory + //9.3.4 + // [1 -150] + const char control_name[] = "Radio Bearer Control"; + ctrl_style->name = cp_str_to_ba(control_name); + + // RIC Control Header Format Type + // Mandatory + // 9.3.5 + ctrl_style->hdr = FORMAT_1_E2SM_RC_CTRL_HDR; + + // RIC Control Message Format Type + // Mandatory + // 9.3.5 + ctrl_style->msg = FORMAT_1_E2SM_RC_CTRL_MSG; + + // RIC Call Process ID Format Type + // Optional + ctrl_style->call_proc_id_type = NULL; + + // RIC Control Outcome Format Type + // Mandatory + // 9.3.5 + ctrl_style->out_frmt = FORMAT_1_E2SM_RC_CTRL_OUT; + + // Sequence of Control Actions + // [0-65535] + ctrl_style->sz_seq_ctrl_act = 1; + ctrl_style->seq_ctrl_act = calloc(ctrl_style->sz_seq_ctrl_act, sizeof(seq_ctrl_act_2_t)); + assert(ctrl_style->seq_ctrl_act != NULL && "Memory exhausted"); + + seq_ctrl_act_2_t* ctrl_act = &ctrl_style->seq_ctrl_act[0]; + + // Control Action ID + // Mandatory + // 9.3.6 + // [1-65535] + ctrl_act->id = 2; + + // Control Action Name + // Mandatory + // 9.3.7 + // [1-150] + const char control_act_name[] = "QoS flow mapping configuration"; + ctrl_act->name = cp_str_to_ba(control_act_name); + + // Sequence of Associated RAN Parameters + // [0-65535] + ctrl_act->sz_seq_assoc_ran_param = 2; + ctrl_act->assoc_ran_param = calloc(ctrl_act->sz_seq_assoc_ran_param, sizeof(seq_ran_param_3_t)); + assert(ctrl_act->assoc_ran_param != NULL && "Memory exhausted"); + + seq_ran_param_3_t* assoc_ran_param = ctrl_act->assoc_ran_param; + + // DRB ID + assoc_ran_param[0].id = 1; + const char ran_param_drb_id[] = "DRB ID"; + assoc_ran_param[0].name = cp_str_to_ba(ran_param_drb_id); + assoc_ran_param[0].def = NULL; + + // List of QoS Flows to be modified in DRB + assoc_ran_param[1].id = 2; + const char ran_param_list_qos_flow[] = "List of QoS Flows to be modified in DRB"; + assoc_ran_param[1].name = cp_str_to_ba(ran_param_list_qos_flow); + assoc_ran_param[1].def = calloc(1, sizeof(ran_param_def_t)); + assert(assoc_ran_param[1].def != NULL && "Memory exhausted"); + + assoc_ran_param[1].def->type = LIST_RAN_PARAMETER_DEF_TYPE; + assoc_ran_param[1].def->lst = calloc(1, sizeof(ran_param_type_t)); + assert(assoc_ran_param[1].def->lst != NULL && "Memory exhausted"); + + ran_param_type_t* lst = assoc_ran_param[1].def->lst; + lst->sz_ran_param = 2; + lst->ran_param = calloc(lst->sz_ran_param, sizeof(ran_param_lst_struct_t)); + assert(lst->ran_param != NULL && "Memory exhausted"); + + // QoS Flow Identifier + lst->ran_param[0].ran_param_id = 4; + const char ran_param_qos_flow_id[] = "QoS Flow Identifier"; + lst->ran_param[0].ran_param_name = cp_str_to_ba(ran_param_qos_flow_id); + lst->ran_param[0].ran_param_def = NULL; + + // QoS Flow Mapping Indication + lst->ran_param[1].ran_param_id = 5; + const char ran_param_qos_flow_mapping_ind[] = "QoS Flow Mapping Indication"; + lst->ran_param[1].ran_param_name = cp_str_to_ba(ran_param_qos_flow_mapping_ind); + lst->ran_param[1].ran_param_def = NULL; + + // Sequence of Associated RAN + // Parameters for Control Outcome + // [0- 255] + ctrl_style->sz_ran_param_ctrl_out = 0; + ctrl_style->ran_param_ctrl_out = NULL; +} + +e2sm_rc_func_def_t fill_rc_ran_def_gnb(void) +{ + e2sm_rc_func_def_t def = {0}; + + // RAN Function Definition for EVENT TRIGGER + // Optional + // 9.2.2.2 + def.ev_trig = calloc(1, sizeof(ran_func_def_ev_trig_t)); + assert(def.ev_trig != NULL && "Memory exhausted"); + fill_rc_ev_trig(def.ev_trig); + + // RAN Function Definition for REPORT + // Optional + // 9.2.2.3 + def.report = calloc(1, sizeof(ran_func_def_report_t)); + assert(def.report != NULL && "Memory exhausted"); + fill_rc_report(def.report); + + // RAN Function Definition for INSERT + // Optional + // 9.2.2.4 + def.insert = NULL; + + // RAN Function Definition for CONTROL + // Optional + // 9.2.2.5 + def.ctrl = calloc(1, sizeof(ran_func_def_ctrl_t)); + assert(def.ctrl != NULL && "Memory exhausted"); + fill_rc_control(def.ctrl); + + // RAN Function Definition for POLICY + // Optional + // 9.2.2.6 + def.policy = NULL; + + return def; +} + +static e2sm_rc_func_def_t fill_rc_ran_def_cu(void) +{ + e2sm_rc_func_def_t def = {0}; + + // RAN Function Definition for EVENT TRIGGER + // Optional + // 9.2.2.2 + def.ev_trig = calloc(1, sizeof(ran_func_def_ev_trig_t)); + assert(def.ev_trig != NULL && "Memory exhausted"); + fill_rc_ev_trig(def.ev_trig); + + // RAN Function Definition for REPORT + // Optional + // 9.2.2.3 + def.report = calloc(1, sizeof(ran_func_def_report_t)); + assert(def.report != NULL && "Memory exhausted"); + fill_rc_report(def.report); + + // RAN Function Definition for INSERT + // Optional + // 9.2.2.4 + def.insert = NULL; + + // RAN Function Definition for CONTROL + // Optional + // 9.2.2.5 + def.ctrl = calloc(1, sizeof(ran_func_def_ctrl_t)); + assert(def.ctrl != NULL && "Memory exhausted"); + fill_rc_control(def.ctrl); + + // RAN Function Definition for POLICY + // Optional + // 9.2.2.6 + def.policy = NULL; + + return def; +} + +static e2sm_rc_func_def_t fill_rc_ran_def_null(void) +{ + e2sm_rc_func_def_t def = {0}; + + // RAN Function Definition for EVENT TRIGGER + // Optional + // 9.2.2.2 + def.ev_trig = NULL; + + // RAN Function Definition for REPORT + // Optional + // 9.2.2.3 + def.report = NULL; + + // RAN Function Definition for INSERT + // Optional + // 9.2.2.4 + def.insert = NULL; + + // RAN Function Definition for CONTROL + // Optional + // 9.2.2.5 + def.ctrl = NULL; + + // RAN Function Definition for POLICY + // Optional + // 9.2.2.6 + def.policy = NULL; + + return def; +} + +static e2sm_rc_func_def_t fill_rc_ran_def_cucp(void) +{ + e2sm_rc_func_def_t def = {0}; + + // RAN Function Definition for EVENT TRIGGER + // Optional + // 9.2.2.2 + def.ev_trig = calloc(1, sizeof(ran_func_def_ev_trig_t)); + assert(def.ev_trig != NULL && "Memory exhausted"); + fill_rc_ev_trig(def.ev_trig); + + // RAN Function Definition for REPORT + // Optional + // 9.2.2.3 + def.report = calloc(1, sizeof(ran_func_def_report_t)); + assert(def.report != NULL && "Memory exhausted"); + fill_rc_report(def.report); + + // RAN Function Definition for INSERT + // Optional + // 9.2.2.4 + def.insert = NULL; + + // RAN Function Definition for CONTROL + // Optional + // 9.2.2.5 + def.ctrl = NULL; + + // RAN Function Definition for POLICY + // Optional + // 9.2.2.6 + def.policy = NULL; + + return def; +} + +typedef e2sm_rc_func_def_t (*fp_rc_func_def)(void); + +static const fp_rc_func_def ran_def_rc[END_NGRAN_NODE_TYPE] = +{ + NULL, + NULL, + fill_rc_ran_def_gnb, + NULL, + NULL, + fill_rc_ran_def_cu, + NULL, + fill_rc_ran_def_null, // DU - at the moment, no Service is supported + NULL, + fill_rc_ran_def_cucp, + fill_rc_ran_def_null, // CU-UP - at the moment, no Service is supported +}; + void read_rc_setup_sm(void* data) { assert(data != NULL); // assert(data->type == RAN_CTRL_V1_3_AGENT_IF_E2_SETUP_ANS_V0); rc_e2_setup_t* rc = (rc_e2_setup_t*)data; - rc->ran_func_def = fill_rc_ran_func_def(); + + /* Fill the RAN Function Definition with currently supported measurements */ + + // RAN Function Name is already filled in fill_ran_function_name() in rc_sm_agent.c + + const ngran_node_t node_type = get_e2_node_type(); + rc->ran_func_def = ran_def_rc[node_type](); // E2 Setup Request is sent periodically until the connection is established // RC subscritpion data should be initialized only once @@ -56,53 +479,6 @@ void read_rc_setup_sm(void* data) RB_PROTOTYPE(ric_id_2_param_id_trees, ric_req_id_s, entries, cmp_ric_req_id); -static ue_id_e2sm_t fill_ue_id_data(const gNB_RRC_UE_t *rrc_ue_context) -{ - ue_id_e2sm_t ue_id = {0}; - - // Check the E2 node type - #if defined (NGRAN_GNB_CUUP) && defined (NGRAN_GNB_CUCP) - ue_id.type = GNB_UE_ID_E2SM; - if (RC.nrrrc[0]->node_type == ngran_gNB_CU) { - // gNB-CU UE F1AP ID List - // C-ifCUDUseparated - ue_id.gnb.gnb_cu_ue_f1ap_lst_len = 1; - ue_id.gnb.gnb_cu_ue_f1ap_lst = calloc(ue_id.gnb.gnb_cu_ue_f1ap_lst_len, sizeof(uint32_t)); - assert(ue_id.gnb.gnb_cu_ue_f1ap_lst != NULL && "Memory exhausted"); - - for(size_t i = 0; i < ue_id.gnb.gnb_cu_ue_f1ap_lst_len; i++) { - ue_id.gnb.gnb_cu_ue_f1ap_lst[i] = rrc_ue_context->rrc_ue_id; - } - } else if (RC.nrrrc[0]->node_type == ngran_gNB_CUCP) { - //gNB-CU-CP UE E1AP ID List - //C-ifCPUPseparated - ue_id.gnb.gnb_cu_cp_ue_e1ap_lst_len = 1; - ue_id.gnb.gnb_cu_cp_ue_e1ap_lst = calloc(ue_id.gnb.gnb_cu_cp_ue_e1ap_lst_len, sizeof(uint32_t)); - assert(ue_id.gnb.gnb_cu_cp_ue_e1ap_lst != NULL && "Memory exhausted"); - - for(size_t i = 0; i < ue_id.gnb.gnb_cu_cp_ue_e1ap_lst_len; i++) { - ue_id.gnb.gnb_cu_cp_ue_e1ap_lst[i] = rrc_ue_context->rrc_ue_id; - } - } else if (RC.nrrrc[0]->node_type == ngran_gNB_DU) { - assert(false && "RRC state change cannot be triggered from DU\n"); - } - - #elif defined (NGRAN_GNB_CUUP) - assert(false && "RRC state change cannot be triggered from CU-UP\n"); - - #endif - - ue_id.gnb.amf_ue_ngap_id = rrc_ue_context->rrc_ue_id; - ue_id.gnb.guami.amf_ptr = rrc_ue_context->ue_guami.amf_pointer; - ue_id.gnb.guami.amf_region_id = rrc_ue_context->ue_guami.amf_region_id; - ue_id.gnb.guami.amf_set_id = rrc_ue_context->ue_guami.amf_set_id; - ue_id.gnb.guami.plmn_id.mcc = rrc_ue_context->ue_guami.mcc; - ue_id.gnb.guami.plmn_id.mnc = rrc_ue_context->ue_guami.mnc; - ue_id.gnb.guami.plmn_id.mnc_digit_len = rrc_ue_context->ue_guami.mnc_len; - - return ue_id; -} - static seq_ran_param_t fill_rrc_state_change_seq_ran(const rc_sm_rrc_state_e rrc_state) { seq_ran_param_t seq_ran_param = {0}; @@ -138,7 +514,8 @@ static rc_ind_data_t* fill_ue_rrc_state_change(const gNB_RRC_UE_t *rrc_ue_contex // UE ID // Mandatory // 9.3.10 - rc_ind->msg.frmt_2.seq_ue_id[0].ue_id = fill_ue_id_data(rrc_ue_context); + const ngran_node_t node_type = get_e2_node_type(); + rc_ind->msg.frmt_2.seq_ue_id[0].ue_id = fill_ue_id_data[node_type](rrc_ue_context, 0, 0); // Sequence of // RAN Parameter @@ -221,39 +598,45 @@ sm_ag_if_ans_t write_ctrl_rc_sm(void const* data) // assert(data->type == RAN_CONTROL_CTRL_V1_03 ); rc_ctrl_req_data_t const* ctrl = (rc_ctrl_req_data_t const*)data; - if(ctrl->hdr.format == FORMAT_1_E2SM_RC_CTRL_HDR){ - if(ctrl->hdr.frmt_1.ric_style_type == 1 && ctrl->hdr.frmt_1.ctrl_act_id == 2){ - printf("QoS flow mapping configuration \n"); - e2sm_rc_ctrl_msg_frmt_1_t const* frmt_1 = &ctrl->msg.frmt_1; - for(size_t i = 0; i < frmt_1->sz_ran_param; ++i){ - seq_ran_param_t const* rp = frmt_1->ran_param; - if(rp[i].ran_param_id == 1){ - assert(rp[i].ran_param_val.type == ELEMENT_KEY_FLAG_TRUE_RAN_PARAMETER_VAL_TYPE ); - printf("DRB ID %ld \n", rp[i].ran_param_val.flag_true->int_ran); - } else if(rp[i].ran_param_id == 2){ - assert(rp[i].ran_param_val.type == LIST_RAN_PARAMETER_VAL_TYPE); - printf("List of QoS Flows to be modified \n"); - for(size_t j = 0; j < ctrl->msg.frmt_1.ran_param[i].ran_param_val.lst->sz_lst_ran_param; ++j){ - lst_ran_param_t const* lrp = rp[i].ran_param_val.lst->lst_ran_param; - // The following assertion should be true, but there is a bug in the std - // check src/sm/rc_sm/enc/rc_enc_asn.c:1085 and src/sm/rc_sm/enc/rc_enc_asn.c:984 - // assert(lrp[j].ran_param_id == 3); - assert(lrp[j].ran_param_struct.ran_param_struct[0].ran_param_id == 4) ; - assert(lrp[j].ran_param_struct.ran_param_struct[0].ran_param_val.type == ELEMENT_KEY_FLAG_TRUE_RAN_PARAMETER_VAL_TYPE); - int64_t qfi = lrp[j].ran_param_struct.ran_param_struct[0].ran_param_val.flag_true->int_ran; - assert(qfi > -1 && qfi < 65); + assert(ctrl->hdr.format == FORMAT_1_E2SM_RC_CTRL_HDR && "Indication Header Format received not valid"); + assert(ctrl->msg.format == FORMAT_1_E2SM_RC_CTRL_MSG && "Indication Message Format received not valid"); + assert(ctrl->hdr.frmt_1.ctrl_act_id == 2 && "Currently only QoS flow mapping configuration supported"); + + printf("QoS flow mapping configuration\n"); + + const seq_ran_param_t* ran_param = ctrl->msg.frmt_1.ran_param; + + // DRB ID + assert(ran_param[0].ran_param_id == 1 && "First RAN Parameter ID has to be DRB ID"); + assert(ran_param[0].ran_param_val.type == ELEMENT_KEY_FLAG_TRUE_RAN_PARAMETER_VAL_TYPE); + printf("DRB ID %ld \n", ran_param[0].ran_param_val.flag_true->int_ran); + + + // List of QoS Flows to be modified in DRB + assert(ran_param[1].ran_param_id == 2 && "Second RAN Parameter ID has to be List of QoS Flows"); + assert(ran_param[1].ran_param_val.type == LIST_RAN_PARAMETER_VAL_TYPE); + printf("List of QoS Flows to be modified in DRB\n"); + const lst_ran_param_t* lrp = ran_param[1].ran_param_val.lst->lst_ran_param; + + // The following assertion should be true, but there is a bug in the std + // check src/sm/rc_sm/enc/rc_enc_asn.c:1085 and src/sm/rc_sm/enc/rc_enc_asn.c:984 + // assert(lrp->ran_param_struct.ran_param_struct[0].ran_param_id == 3); + + // QoS Flow Identifier + assert(lrp->ran_param_struct.ran_param_struct[0].ran_param_id == 4); + assert(lrp->ran_param_struct.ran_param_struct[0].ran_param_val.type == ELEMENT_KEY_FLAG_TRUE_RAN_PARAMETER_VAL_TYPE); + int64_t qfi = lrp->ran_param_struct.ran_param_struct[0].ran_param_val.flag_true->int_ran; + assert(qfi > -1 && qfi < 65); + + // QoS Flow Mapping Indication + assert(lrp->ran_param_struct.ran_param_struct[1].ran_param_id == 5); + assert(lrp->ran_param_struct.ran_param_struct[1].ran_param_val.type == ELEMENT_KEY_FLAG_FALSE_RAN_PARAMETER_VAL_TYPE); + int64_t dir = lrp->ran_param_struct.ran_param_struct[1].ran_param_val.flag_false->int_ran; + assert(dir == 0 || dir == 1); + + printf("qfi = %ld, dir %ld \n", qfi, dir); - assert(lrp[j].ran_param_struct.ran_param_struct[1].ran_param_id == 5); - assert(lrp[j].ran_param_struct.ran_param_struct[1].ran_param_val.type == ELEMENT_KEY_FLAG_FALSE_RAN_PARAMETER_VAL_TYPE); - int64_t dir = lrp[j].ran_param_struct.ran_param_struct[1].ran_param_val.flag_false->int_ran; - assert(dir == 0 || dir == 1); - printf("qfi = %ld dir %ld \n", qfi, dir); - } - } - } - } - } sm_ag_if_ans_t ans = {.type = CTRL_OUTCOME_SM_AG_IF_ANS_V0}; ans.ctrl_out.type = RAN_CTRL_V1_3_AGENT_IF_CTRL_ANS_V0; From 7bfa2d71f47ab649a80c4ef150303fc9ca9d6f63 Mon Sep 17 00:00:00 2001 From: Teodora Date: Mon, 25 Mar 2024 13:15:05 +0100 Subject: [PATCH 38/39] E2SM cmake update - hardcoded data for E2 Setup Request; fill_rnd_data_e2_setup_req.c dependancy taken out --- openair2/E2AP/RAN_FUNCTION/CMakeLists.txt | 46 +++++---- openair2/E2AP/RAN_FUNCTION/read_setup_ran.c | 101 +++++++++++++++++++- 2 files changed, 126 insertions(+), 21 deletions(-) diff --git a/openair2/E2AP/RAN_FUNCTION/CMakeLists.txt b/openair2/E2AP/RAN_FUNCTION/CMakeLists.txt index acada2c6dd..1d47f029d9 100644 --- a/openair2/E2AP/RAN_FUNCTION/CMakeLists.txt +++ b/openair2/E2AP/RAN_FUNCTION/CMakeLists.txt @@ -1,16 +1,15 @@ add_library(e2_ran_func_cuup STATIC init_ran_func.c read_setup_ran.c - ../flexric/test/rnd/fill_rnd_data_e2_setup_req.c # this is not rnd data; it is used to fill E2 Node Component Configuration Addition List in E2 Setup Request message - CUSTOMIZED/ran_func_gtp.c # current implementation doesn't take split architecture into account, neither CU/DU nor CU-UP/CU-CP - CUSTOMIZED/ran_func_pdcp.c # current implementation doesn't take split architecture into account, neither CU/DU nor CU-UP/CU-CP + O-RAN/ran_e2sm_ue_id.c + O-RAN/ran_func_kpm.c + O-RAN/ran_func_kpm_subs.c + O-RAN/ran_func_rc.c + O-RAN/ran_func_rc_subs.c + CUSTOMIZED/ran_func_gtp.c # GTP SM not yet implemented in CU-UP + CUSTOMIZED/ran_func_pdcp.c CUSTOMIZED/ran_func_tc.c # currently, not implemented; therefore, filling rnd data ../flexric/test/rnd/fill_rnd_data_tc.c - O-RAN/ran_e2sm_ue_id.c - O-RAN/ran_func_kpm.c # this file should only contain PDCP-U/GTP; to be done in the future - O-RAN/ran_func_kpm_subs.c - O-RAN/ran_func_rc.c # this file should only contain PDCP-U/GTP; to be done in the future - O-RAN/ran_func_rc_subs.c ) target_link_libraries(e2_ran_func_cuup PUBLIC asn1_nr_rrc nr_rrc asn1_nr_rrc_hdrs e2_time_obj kpm_ric_info_common_obj 3gpp_derived_ie_obj sm_common_ie_obj) @@ -20,24 +19,31 @@ target_compile_definitions(e2_ran_func_cuup PUBLIC ${E2AP_VERSION} ${KPM_VERSIO add_library(e2_ran_func_du_cucp_cuup STATIC init_ran_func.c read_setup_ran.c - ../flexric/test/rnd/fill_rnd_data_e2_setup_req.c # this is not rnd data; it is used to fill E2 Node Component Configuration Addition List in E2 Setup Request message - CUSTOMIZED/ran_func_gtp.c # current implementation doesn't take split architecture into account, neither CU/DU nor CU-UP/CU-CP - CUSTOMIZED/ran_func_pdcp.c # current implementation doesn't take split architecture into account, neither CU/DU nor CU-UP/CU-CP O-RAN/ran_e2sm_ue_id.c - O-RAN/ran_func_kpm.c # this file should only contain RRC/PDCP-C; to be done in the future - # when nr-softmodem is divided in separate executables + O-RAN/ran_func_kpm.c O-RAN/ran_func_kpm_subs.c - O-RAN/ran_func_rc.c # this file should only contain RRC/PDCP-C; to be done in the future - # when nr-softmodem is divided in separate executables + O-RAN/ran_func_rc.c O-RAN/ran_func_rc_subs.c ../flexric/src/sm/rc_sm/ie/rc_data_ie.c + CUSTOMIZED/ran_func_gtp.c + CUSTOMIZED/ran_func_pdcp.c CUSTOMIZED/ran_func_mac.c CUSTOMIZED/ran_func_rlc.c - CUSTOMIZED/ran_func_slice.c - CUSTOMIZED/ran_func_tc.c - ../flexric/test/rnd/fill_rnd_data_tc.c + CUSTOMIZED/ran_func_slice.c # currently, not implemented; therefore, filling rnd data ../flexric/test/rnd/fill_rnd_data_slice.c + CUSTOMIZED/ran_func_tc.c # currently, not implemented; therefore, filling rnd data + ../flexric/test/rnd/fill_rnd_data_tc.c ) -target_link_libraries(e2_ran_func_du_cucp_cuup PUBLIC asn1_nr_rrc nr_rrc asn1_nr_rrc_hdrs e2_time_obj kpm_ric_info_common_obj 3gpp_derived_ie_obj e2sm_rc_ir_obj sm_common_ie_obj e2_agent) -target_compile_definitions(e2_ran_func_du_cucp_cuup PUBLIC ${E2AP_VERSION} ${KPM_VERSION} NGRAN_GNB_DU NGRAN_GNB_CUCP NGRAN_GNB_CUUP) +target_link_libraries(e2_ran_func_du_cucp_cuup PUBLIC asn1_nr_rrc nr_rrc asn1_nr_rrc_hdrs e2_time_obj kpm_ric_info_common_obj 3gpp_derived_ie_obj e2sm_rc_ir_obj sm_common_ie_obj) +target_compile_definitions(e2_ran_func_du_cucp_cuup PUBLIC ${E2AP_VERSION} ${KPM_VERSION} NGRAN_GNB_DU NGRAN_GNB_CUCP NGRAN_GNB_CUUP) + +# Current implementation: +# - we only have one executable nr-softmodem for 4 node types: DU, CU, gNB-mono, CU-CP + +# In the future, when nr-softmodem is separated, linking should be done as following: +# - DU: e2_ran_func_du +# - CU-CP : e2_ran_func_cucp +# - CU-UP: e2_ran_func_cuup (this is available at the moment, executable nr-cuup) +# - CU: e2_ran_func_cucp + e2_ran_func_cuup +# - gNB-mono: e2_ran_func_du + e2_ran_func_cucp + e2_ran_func_cuup diff --git a/openair2/E2AP/RAN_FUNCTION/read_setup_ran.c b/openair2/E2AP/RAN_FUNCTION/read_setup_ran.c index 774ea290d6..922816f5fc 100644 --- a/openair2/E2AP/RAN_FUNCTION/read_setup_ran.c +++ b/openair2/E2AP/RAN_FUNCTION/read_setup_ran.c @@ -21,10 +21,109 @@ #include "read_setup_ran.h" #include "../../E2AP/flexric/src/lib/e2ap/e2ap_node_component_config_add_wrapper.h" -#include "../../E2AP/flexric/test/rnd/fill_rnd_data_e2_setup_req.h" #include #include +#if defined(E2AP_V2) || defined(E2AP_V3) +// NGAP +static e2ap_node_component_config_add_t fill_ngap_e2ap_node_component_config_add(void) +{ + e2ap_node_component_config_add_t dst = {0}; + + // Mandatory + // 9.2.26 + dst.e2_node_comp_interface_type = NG_E2AP_NODE_COMP_INTERFACE_TYPE; + // Bug!! Optional in the standard, mandatory in ASN.1 + // 9.2.32 + dst.e2_node_comp_id.type = NG_E2AP_NODE_COMP_INTERFACE_TYPE; + + const char ng_msg[] = "Dummy message"; + dst.e2_node_comp_id.ng_amf_name = cp_str_to_ba(ng_msg); + + // Mandatory + // 9.2.27 + const char req[] = "NGAP Request Message sent"; + const char res[] = "NGAP Response Message reveived"; + + dst.e2_node_comp_conf.request = cp_str_to_ba(req); + dst.e2_node_comp_conf.response = cp_str_to_ba(res); + return dst; +} + +// F1AP +static e2ap_node_component_config_add_t fill_f1ap_e2ap_node_component_config_add(void) +{ + e2ap_node_component_config_add_t dst = {0}; + + // Mandatory + // 9.2.26 + dst.e2_node_comp_interface_type = F1_E2AP_NODE_COMP_INTERFACE_TYPE; + // Bug!! Optional in the standard, mandatory in ASN.1 + // 9.2.32 + dst.e2_node_comp_id.type = F1_E2AP_NODE_COMP_INTERFACE_TYPE; + + dst.e2_node_comp_id.f1_gnb_du_id = 1023; + + // Mandatory + // 9.2.27 + const char req[] = "F1AP Request Message sent"; + const char res[] = "F1AP Response Message reveived"; + + dst.e2_node_comp_conf.request = cp_str_to_ba(req); + dst.e2_node_comp_conf.response = cp_str_to_ba(res); + return dst; +} + +// E1AP +static e2ap_node_component_config_add_t fill_e1ap_e2ap_node_component_config_add(void) +{ + e2ap_node_component_config_add_t dst = {0}; + + // Mandatory + // 9.2.26 + dst.e2_node_comp_interface_type = E1_E2AP_NODE_COMP_INTERFACE_TYPE; + // Bug!! Optional in the standard, mandatory in ASN.1 + // 9.2.32 + dst.e2_node_comp_id.type = E1_E2AP_NODE_COMP_INTERFACE_TYPE; + + dst.e2_node_comp_id.e1_gnb_cu_up_id = 1025; + + // Mandatory + // 9.2.27 + const char req[] = "E1AP Request Message sent"; + const char res[] = "E1AP Response Message reveived"; + + dst.e2_node_comp_conf.request = cp_str_to_ba(req); + dst.e2_node_comp_conf.response = cp_str_to_ba(res); + return dst; +} + +// S1AP +static e2ap_node_component_config_add_t fill_s1ap_e2ap_node_component_config_add(void) +{ + e2ap_node_component_config_add_t dst = {0}; + + // Mandatory + // 9.2.26 + dst.e2_node_comp_interface_type = S1_E2AP_NODE_COMP_INTERFACE_TYPE; + // Bug!! Optional in the standard, mandatory in ASN.1 + // 9.2.32 + dst.e2_node_comp_id.type = S1_E2AP_NODE_COMP_INTERFACE_TYPE; + + const char str[] = "S1 NAME"; + dst.e2_node_comp_id.s1_mme_name = cp_str_to_ba(str); + + // Mandatory + // 9.2.27 + const char req[] = "S1AP Request Message sent"; + const char res[] = "S1AP Response Message reveived"; + + dst.e2_node_comp_conf.request = cp_str_to_ba(req); + dst.e2_node_comp_conf.response = cp_str_to_ba(res); + return dst; +} +#endif + void read_setup_ran(void* data, const ngran_node_t node_type) { assert(data != NULL); From 7535e999443ad31307a5259a66e6f579b1b779be Mon Sep 17 00:00:00 2001 From: Teodora Date: Thu, 7 Mar 2024 21:01:51 +0100 Subject: [PATCH 39/39] E2AP README & FlexRIC commit ID update --- openair2/E2AP/README.md | 176 ++++++++++++++++++++++++---------------- openair2/E2AP/flexric | 2 +- 2 files changed, 107 insertions(+), 71 deletions(-) diff --git a/openair2/E2AP/README.md b/openair2/E2AP/README.md index cf6e8b8cd5..08cdf37067 100644 --- a/openair2/E2AP/README.md +++ b/openair2/E2AP/README.md @@ -13,6 +13,8 @@ Please see [NOTICE](NOTICE.md) file for third party software that is included in This tutorial describes the steps of deployment 5G OAI RAN, with integrated E2 agent and a nearRT-RIC using O-RAN compliant FlexRIC. +[[_TOC_]] + # 1. Installation ## 1.1 Install prerequisites @@ -21,7 +23,7 @@ This tutorial describes the steps of deployment 5G OAI RAN, with integrated E2 a On Ubuntu, you might want to use [this PPA](https://apt.kitware.com/) to install an up-to-date version. -- SWIG (at least v.4.0). +- SWIG (at least v.4.1). We use SWIG as an interface generator to enable the multi-language feature (i.e., C/C++ and Python) for the xApps. Please, check your SWIG version (i.e, `swig -version`) and install it from scratch if necessary as described here: https://swig.org/svn.html or via the code below: @@ -69,17 +71,11 @@ Currently available versions: | E2AP v2.03 | Y | Y | | E2AP v3.01 | Y | Y | - Please note that KPM SM v2.01 is supported only in FlexRIC, but not in OAI. +Please note that KPM SM v2.01 is supported only in FlexRIC, but not in OAI. ```bash cd cmake_targets/ ./build_oai -I -w SIMU --gNB --nrUE --build-e2 --ninja -``` -If the openair2/E2AP/flexric folder is empty, try manually the following commands - -```bash -git submodule init -git submodule update ``` * `-I` option is to install pre-requisites, you only need it the first time you build the softmodem or when some oai dependencies have changed. @@ -89,16 +85,22 @@ git submodule update * `--ninja` is to use the ninja build tool, which speeds up compilation * `--build-e2` option is to use the E2 agent, integrated within RAN. +If the openair2/E2AP/flexric folder is empty, try manually the following commands: +```bash +git submodule init +git submodule update +``` + ## 2.2 FlexRIC -- By default, FlexRIC will build the nearRT-RIC with E2AP v2 and KPM v2. If you want a different version, edit the variable E2AP\_VERSION and KPM\_VERSION at FlexRIC's CMakeLists.txt file. Note that OAI's and FlexRIC's E2AP\_VERSION and KPM\_VERSION need to match due to O-RAN incompatibilities among versions. +By default, FlexRIC will build the nearRT-RIC with E2AP v2 and KPM v2. If you want a different version, edit the variable E2AP\_VERSION and KPM\_VERSION at FlexRIC's CMakeLists.txt file. Note that OAI's and FlexRIC's E2AP\_VERSION and KPM\_VERSION need to match due to O-RAN incompatibilities among versions. ### 2.2.1 Clone the FlexRIC repository ```bash git clone https://gitlab.eurecom.fr/mosaic5g/flexric flexric cd flexric/ -git checkout 29af8408afad3da36824bd7912562202023ae924 +git checkout 34d6810f9ab435ac3a4023d5e1917669e24341da ``` ### 2.2.2 Build FlexRIC @@ -113,27 +115,47 @@ sudo make install By default the service model libraries will be installed in the path `/usr/local/lib/flexric` while the configuration file in `/usr/local/etc/flexric`. -#### 2.2.3.1 Available Service Models -1. KPM v02.03 and KPM v03.00 (`xapp_kpm_moni`) -At the moment, the following measurements are supported in OAI RAN: -* "DRB.PdcpSduVolumeDL" -* "DRB.PdcpSduVolumeUL" -* "DRB.RlcSduDelayDl" -* "DRB.UEThpDl" -* "DRB.UEThpUl" -* "RRU.PrbTotDl" -* "RRU.PrbTotUl" +# 3. Service Models available in OAI RAN -2. RC v01.03 -Currently available RC xApps: -* `xapp_kpm_rc` - RAN control function "QoS flow mapping configuration" support, i.e. creating a new DRB. -* `xapp_rc_moni` - aperiodic subscription support for "UE RRC State Change" +## 3.1 O-RAN -3. MAC + RLC + PDCP + GTP (`xapp_gtp_mac_rlc_pdcp_moni`) +We assume that user is familiar with O-RAN WG3 specifications that can be found at https://orandownloadsweb.azurewebsites.net/specifications. + +### 3.1.1 E2SM-KPM + +As mentioned in section [2.1.2 Build OAI with E2 Agent](#212-build-oai-with-e2-agent), we support KPM v2.03/v3.00. Uses ASN.1 encoding. + +Per O-RAN specifications, 5G measurements supported by KPM are specified in 3GPP TS 28.552. + +From 3GPP TS 28.552, we support the following list: + * "DRB.PdcpSduVolumeDL" + * "DRB.PdcpSduVolumeUL" + * "DRB.RlcSduDelayDl" + * "DRB.UEThpDl" + * "DRB.UEThpUl" + * "RRU.PrbTotDl" + * "RRU.PrbTotUl" + +From O-RAN.WG3.E2SM-KPM-version specification, we implemented: + * REPORT Service Style 4 ("Common condition-based, UE-level" - section 7.4.5) - fetch above measurements per each UE that matches common criteria (e.g. S-NSSAI). + +### 3.1.2 E2SM-RC + +We support RC v1.03. Uses ASN.1 encoding. + +From ORAN.WG3.E2SM-RC-v01.03 specification, we implemented: + * REPORT Service Style 4 ("UE Information" - section 7.4.5) - aperiodic subscription for "UE RRC State Change" + * CONTROL Service Style 1 ("Radio Bearer Control" - section 7.6.2) - "QoS flow mapping configuration" (e.g creating a new DRB) + +## 3.2 Custom Service Models + +In addition, we support custom Service Models, such are MAC, RLC, PDCP, and GTP. Use plain encoding. If you are interested in TC and SLICE SMs, please follow the instructions at https://gitlab.eurecom.fr/mosaic5g/flexric. -# 3. Start the process +# 4. Start the process + +At this point, we assume the 5G Core Network is already running in the background. For more information, please follow the tutorial at https://gitlab.eurecom.fr/oai/openairinterface5g/-/blob/develop/doc/NR_SA_Tutorial_OAI_CN5G.md. In order to configure E2 agent, please, add the following block in OAI's configuration file: ```bash @@ -142,61 +164,75 @@ e2_agent = { sm_dir = "/usr/local/lib/flexric/" } ``` +* start E2 Node agents -* start the gNB-mono -```bash -cd oai/cmake_targets/ran_build/build -sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf --rfsim --sa -E -``` + As per O-RAN.WG3.E2SM-v02.00 specifications, UE ID (section 6.2.2.6) representation in OAI is: + | | gNB-mono | CU | CU-CP | CU-UP | DU | + |:----------------------|:----------------|:----------------|:----------------|:----------------------|:-------------------| + | CHOICE UE ID case | GNB_UE_ID_E2SM | GNB_UE_ID_E2SM | GNB_UE_ID_E2SM | GNB_CU_UP_UE_ID_E2SM | GNB_DU_UE_ID_E2SM | + | AMF UE NGAP ID | amf_ue_ngap_id | amf_ue_ngap_id | amf_ue_ngap_id | | | + | GUAMI | guami | guami | guami | | | + | gNB-CU UE F1AP ID | | rrc_ue_id | | | rrc_ue_id | + | gNB-CU-CP UE E1AP ID | | | rrc_ue_id | rrc_ue_id | | + | RAN UE ID | rrc_ue_id | rrc_ue_id | rrc_ue_id | rrc_ue_id | rrc_ue_id | -* if CU/DU split is used, start the gNB as follows -```bash -sudo ./nr-softmodem -O --rfsim --sa -E -sudo ./nr-softmodem -O --sa -``` + * start the gNB-mono + ```bash + cd oai/cmake_targets/ran_build/build + sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf --rfsim --sa -E + ``` -* if CU-CP/CU-UP/DU split is used, start the gNB as follows -```bash -sudo ./nr-softmodem -O --rfsim --sa -E -sudo ./nr-softmodem -O --sa -sudo ./nr-cuup -O --sa -``` + * if CU/DU split is used, start the gNB as follows + ```bash + sudo ./nr-softmodem -O --rfsim --sa -E + sudo ./nr-softmodem -O --sa + ``` + + * if CU-CP/CU-UP/DU split is used, start the gNB as follows + ```bash + sudo ./nr-softmodem -O --rfsim --sa -E + sudo ./nr-softmodem -O --sa + sudo ./nr-cuup -O --sa + ``` * start the nrUE -```bash -cd oai/cmake_targets/ran_build/build -sudo ./nr-uesoftmodem -r 106 --numerology 1 --band 78 -C 3619200000 --rfsim --sa --uicc0.imsi 001010000000001 --rfsimulator.serveraddr 127.0.0.1 -``` + ```bash + cd oai/cmake_targets/ran_build/build + sudo ./nr-uesoftmodem -r 106 --numerology 1 --band 78 -C 3619200000 --rfsim --sa --uicc0.imsi 001010000000001 --rfsimulator.serveraddr 127.0.0.1 + ``` * start the nearRT-RIC -```bash -cd flexric -./build/examples/ric/nearRT-RIC -``` + ```bash + cd flexric + ./build/examples/ric/nearRT-RIC + ``` -* start the KPM monitor xApp -```bash -cd flexric -./build/examples/xApp/c/monitor/xapp_kpm_moni -``` +* Start different xApps -* start the RC monitor xApp -```bash -cd flexric -./build/examples/xApp/c/monitor/xapp_rc_moni -``` + * start the KPM monitor xApp - measurements stated in [3.1.1 E2SM-KPM](#311-e2sm-kpm) for each UE that matches S-NSSAI common criteria + ```bash + cd flexric + ./build/examples/xApp/c/monitor/xapp_kpm_moni + ``` + Note: we assume that each UE has only 1 DRB; CU-UP does not store the slices, therefore "coarse filtering" is used -* start the RC control xApp -```bash -cd flexric -./build/examples/xApp/c/kpm_rc/xapp_kpm_rc -``` + * start the RC monitor xApp - aperiodic subscription for "UE RRC State Change" + ```bash + cd flexric + ./build/examples/xApp/c/monitor/xapp_rc_moni + ``` -* start the (MAC + RLC + PDCP + GTP) monitor xApp -```bash -cd flexric -./build/examples/xApp/c/monitor/xapp_gtp_mac_rlc_pdcp_moni -``` + * start the RC control xApp - RAN control function "QoS flow mapping configuration" (e.g. creating a new DRB) + ```bash + cd flexric + ./build/examples/xApp/c/kpm_rc/xapp_kpm_rc + ``` + + * start the (MAC + RLC + PDCP + GTP) monitor xApp + ```bash + cd flexric + ./build/examples/xApp/c/monitor/xapp_gtp_mac_rlc_pdcp_moni + ``` The latency that you observe in your monitor xApp is the latency from the E2 Agent to the nearRT-RIC and xApp. Therefore, FlexRIC is well suited for use cases with ultra low-latency requirements. Additionally, all the data received in the `xapp_gtp_mac_rlc_pdcp_moni` xApp is also written to /tmp/xapp_db in case that offline data processing is wanted (e.g., Machine Learning/Artificial Intelligence applications). You can browse the data using e.g., sqlitebrowser. diff --git a/openair2/E2AP/flexric b/openair2/E2AP/flexric index 7c424e882a..34d6810f9a 160000 --- a/openair2/E2AP/flexric +++ b/openair2/E2AP/flexric @@ -1 +1 @@ -Subproject commit 7c424e882adae6ad72a24470d8c3e731189062c0 +Subproject commit 34d6810f9ab435ac3a4023d5e1917669e24341da