diff --git a/ci-scripts/conf_files/gnb-du.sa.band78.106prb.rfsim.conf b/ci-scripts/conf_files/gnb-du.sa.band78.106prb.rfsim.conf index 9d8a3cb57b..328bbe4f16 100644 --- a/ci-scripts/conf_files/gnb-du.sa.band78.106prb.rfsim.conf +++ b/ci-scripts/conf_files/gnb-du.sa.band78.106prb.rfsim.conf @@ -231,3 +231,31 @@ log_config: { rlc_log_level = "info"; f1ap_log_level = "info"; }; + +#/* configuration for channel modelisation */ +#/* To be included in main config file when */ +#/* channel modelisation is used (rfsimulator with chanmod options enabled) */ +channelmod = { + max_chan = 10; + modellist = "modellist_rfsimu_1"; + modellist_rfsimu_1 = ( + { # DL, modify on UE side + model_name = "rfsimu_channel_enB0" + type = "AWGN"; + ploss_dB = 20; + noise_power_dB = -4; + forgetfact = 0; + offset = 0; + ds_tdl = 0; + }, + { # UL, modify on gNB side + model_name = "rfsimu_channel_ue0" + type = "AWGN"; + ploss_dB = 20; + noise_power_dB = -2; + forgetfact = 0; + offset = 0; + ds_tdl = 0; + } + ); +}; diff --git a/ci-scripts/conf_files/nrue.uicc.conf b/ci-scripts/conf_files/nrue.uicc.conf index ce6094c71c..afd2c0142e 100644 --- a/ci-scripts/conf_files/nrue.uicc.conf +++ b/ci-scripts/conf_files/nrue.uicc.conf @@ -5,3 +5,31 @@ uicc0 = { dnn= "oai"; nssai_sst=1; } + +#/* configuration for channel modelisation */ +#/* To be included in main config file when */ +#/* channel modelisation is used (rfsimulator with chanmod options enabled) */ +channelmod = { + max_chan = 10; + modellist = "modellist_rfsimu_1"; + modellist_rfsimu_1 = ( + { # DL, modify on UE side + model_name = "rfsimu_channel_enB0" + type = "AWGN"; + ploss_dB = 20; + noise_power_dB = -4; + forgetfact = 0; + offset = 0; + ds_tdl = 0; + }, + { # UL, modify on gNB side + model_name = "rfsimu_channel_ue0" + type = "AWGN"; + ploss_dB = 20; + noise_power_dB = -2; + forgetfact = 0; + offset = 0; + ds_tdl = 0; + } + ); +}; diff --git a/ci-scripts/main.py b/ci-scripts/main.py index 615246c808..03c99d9741 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -581,8 +581,8 @@ elif re.match('^InitiateHtml$', mode, re.IGNORECASE): if (os.path.isfile(xml_test_file)): try: xmlTree = ET.parse(xml_test_file) - except: - print("Error while parsing file: " + xml_test_file) + except Exception as e: + print(f"Error: {e} while parsing file: {xml_test_file}.") xmlRoot = xmlTree.getroot() HTML.htmlTabRefs.append(xmlRoot.findtext('htmlTabRef',default='test-tab-' + str(count))) HTML.htmlTabNames.append(xmlRoot.findtext('htmlTabName',default='test-tab-' + str(count))) diff --git a/ci-scripts/ran.py b/ci-scripts/ran.py index afa6036c7e..031de4b70e 100644 --- a/ci-scripts/ran.py +++ b/ci-scripts/ran.py @@ -264,7 +264,7 @@ class RANManagement(): cmd = cls_cmd.getConnection(self.node) ret = cmd.run(self.command) cmd.close() - logging.debug(f"Custum command : {self.command} on node : {self.node} returnCode : {ret.returncode}") + logging.debug(f"CustomCommand: {self.command} on node: {self.node} - {'OK, command succeeded' if ret.returncode == 0 else f'Error, return code: {ret.returncode}'}") status = 'OK' message = [] if ret.returncode != 0 and not self.command_fail: diff --git a/ci-scripts/xml_files/container_5g_f1_rfsim.xml b/ci-scripts/xml_files/container_5g_f1_rfsim.xml index fc35442088..6c95796d87 100644 --- a/ci-scripts/xml_files/container_5g_f1_rfsim.xml +++ b/ci-scripts/xml_files/container_5g_f1_rfsim.xml @@ -31,6 +31,7 @@ 000022 000023 020021 + 030020 030021 030022 100021 @@ -74,10 +75,18 @@ 5 + + Custom_Command + Simulate a DL radio channel with noise (3 dB) + localhost + echo channelmod modify 0 noise_power_dB 3 | nc --send-only 192.168.71.181 8091 + yes + + Iperf - Iperf (DL/20Mbps/UDP)(30 sec) - -u -b 20M -t 30 -R + Iperf (DL/5Mbps/UDP)(30 sec) + -u -b 5M -t 30 -R rfsim5g_ue rfsim5g_ext_dn 5 @@ -86,20 +95,52 @@ Iperf - Iperf (UL/5Mbps/UDP)(30 sec) - -u -b 5M -t 30 + Iperf (UL/3Mbps/UDP)(30 sec) + -u -b 3M -t 30 rfsim5g_ue rfsim5g_ext_dn 5 90 + + Custom_Command + Simulate a disruption of DL radio channel (ploss 55)(5 sec) + localhost + echo channelmod modify 0 ploss 55 | nc -N 192.168.71.181 8091 && sleep 5 + yes + + + + Custom_Command + Get UE sync state (UE ID 0) + localhost + echo ciUE sync_state 0 | nc -N 192.168.71.181 8091 | grep -E UE_NOT_SYNC + yes + + + + Custom_Command + Restoration of the original DL channel conditions (ploss 0)(5 sec) + localhost + echo channelmod modify 0 ploss 0 | nc -N 192.168.71.181 8091 && sleep 5 + yes + + + + Custom_Command + Get UE sync state (UE ID 0) + localhost + echo ciUE sync_state 0 | nc -N 192.168.71.181 8091 | grep -E UE_CONNECTED && sleep 10 + yes + + UndeployGenObject Undeploy all OAI 5G stack yaml_files/5g_f1_rfsimulator - 1,0,0,0 - 1,0,0,0 + 30,30,100,100 + 30,30,100,100 diff --git a/ci-scripts/yaml_files/5g_f1_rfsimulator/docker-compose.yaml b/ci-scripts/yaml_files/5g_f1_rfsimulator/docker-compose.yaml index 294091c648..70a67346a7 100644 --- a/ci-scripts/yaml_files/5g_f1_rfsimulator/docker-compose.yaml +++ b/ci-scripts/yaml_files/5g_f1_rfsimulator/docker-compose.yaml @@ -108,7 +108,10 @@ services: privileged: true container_name: rfsim5g-oai-du environment: - USE_ADDITIONAL_OPTIONS: --sa --rfsim --log_config.global_log_options level,nocolor,time + USE_ADDITIONAL_OPTIONS: --sa --rfsim + --log_config.global_log_options level,nocolor,time + --rfsimulator.options chanmod + --telnetsrv --telnetsrv.listenaddr 192.168.71.171 ASAN_OPTIONS: detect_leaks=0 depends_on: - oai-cu @@ -117,6 +120,7 @@ services: ipv4_address: 192.168.71.171 volumes: - ../../conf_files/gnb-du.sa.band78.106prb.rfsim.conf:/opt/oai-gnb/etc/gnb.conf + - ../../conf_files/rfsim_channel_ci.conf:/opt/oai-gnb/etc/rfsim_channel_ci.conf healthcheck: test: /bin/bash -c "pgrep nr-softmodem" interval: 10s @@ -132,6 +136,8 @@ services: -r 106 --numerology 1 -C 3619200000 --uicc0.imsi 208990100001100 --rfsimulator.serveraddr 192.168.71.171 + --rfsimulator.options chanmod + --telnetsrv --telnetsrv.shrmod ciUE --telnetsrv.listenaddr 192.168.71.181 --telnetsrv.listenport 8091 depends_on: - oai-du networks: @@ -139,6 +145,7 @@ services: ipv4_address: 192.168.71.181 volumes: - ../../conf_files/nrue.uicc.conf:/opt/oai-nr-ue/etc/nr-ue.conf + - ../../conf_files/rfsim_channel_ci.conf:/opt/oai-nr-ue/etc/rfsim_channel_ci.conf healthcheck: test: /bin/bash -c "pgrep nr-uesoftmodem" interval: 10s diff --git a/common/utils/telnetsrv/CMakeLists.txt b/common/utils/telnetsrv/CMakeLists.txt index a7a364d80e..7f2d7a02e5 100644 --- a/common/utils/telnetsrv/CMakeLists.txt +++ b/common/utils/telnetsrv/CMakeLists.txt @@ -59,6 +59,11 @@ add_library(telnetsrv_ci MODULE telnetsrv_ci.c) target_link_libraries(telnetsrv_ci PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) add_dependencies(telnetsrv telnetsrv_ci) +message(STATUS "Add CI specific telnet functions for nrUE in telnetsrv_ciUE.so") +add_library(telnetsrv_ciUE MODULE telnetsrv_ciUE.c) +target_link_libraries(telnetsrv_ciUE PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) +add_dependencies(telnetsrv telnetsrv_ciUE) + message(STATUS "Add bearer specific telnet functions in libtelnetsrv_bearer.so") add_library(telnetsrv_bearer MODULE telnetsrv_bearer.c) target_link_libraries(telnetsrv_bearer PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) @@ -70,7 +75,7 @@ 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 telnetsrv_rrc +set_target_properties(telnetsrv telnetsrv_enb telnetsrv_5Gue telnetsrv_ci telnetsrv_ciUE telnetsrv_bearer telnetsrv_rrc PROPERTIES LIBRARY_OUTPUT_DIRECTORY ../../.. ) diff --git a/common/utils/telnetsrv/DOC/telnetusage.md b/common/utils/telnetsrv/DOC/telnetusage.md index 8c69d247a8..b58684aee7 100644 --- a/common/utils/telnetsrv/DOC/telnetusage.md +++ b/common/utils/telnetsrv/DOC/telnetusage.md @@ -8,7 +8,17 @@ By default the embedded telnet server, which is implemented in a shared library, ./build_oai --build-lib telnetsrv ``` -This will create the `libtelnetsrv.so` and `libtelnetsrv_` file in the `cmake_targets/ran_build/build` subdirectory of the oai repository. `` can be "enb", "gnb", "4GUE", "5GUE", or "ci", each library containing functions specific to a given executable. +This will create the `libtelnetsrv.so` and `libtelnetsrv_` file in the `cmake_targets/ran_build/build` subdirectory of the oai repository. `` can be "enb", "gnb", "4GUE", "5GUE", "ci" or "ciUE" each library containing functions specific to a given executable: + +| **Library Name** | **Description** | +|---------------------------|-------------------------------------| +| `libtelnetsrv.so` | General telnet server library | +| `libtelnetsrv_enb` | eNodeB specific functions | +| `libtelnetsrv_gnb` | gNodeB specific functions | +| `libtelnetsrv_4GUE` | 4G NR UE specific functions | +| `libtelnetsrv_5GUE` | 5G NR UE specific functions | +| `libtelnetsrv_ci` | gNB specific CI functions | +| `libtelnetsrv_ciUE` | UE specific CI functions | When starting the softmodem, you must specify the **_\-\-telnetsrv_** option to load and start the telnet server. The telnet server is loaded via the [oai shared library loader](loader). diff --git a/common/utils/telnetsrv/telnetsrv_ci.c b/common/utils/telnetsrv/telnetsrv_ci.c index 0f56f72cfd..9f3c03c39a 100644 --- a/common/utils/telnetsrv/telnetsrv_ci.c +++ b/common/utils/telnetsrv/telnetsrv_ci.c @@ -19,6 +19,11 @@ * contact@openairinterface.org */ +/*! \file telnetsrv_ci.c + * \brief Implementation of telnet CI functions for gNB + * \note This file contains telnet-related functions specific to 5G gNB. + */ + #include #include #include diff --git a/common/utils/telnetsrv/telnetsrv_ciUE.c b/common/utils/telnetsrv/telnetsrv_ciUE.c new file mode 100644 index 0000000000..673d904969 --- /dev/null +++ b/common/utils/telnetsrv/telnetsrv_ciUE.c @@ -0,0 +1,91 @@ +/* + * 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 + */ + +/*! \file telnetsrv_ciUE.c + * \brief Implementation of telnet CI functions for nrUE + * \author Guido Casati + * \date 2024 + * \version 0.1 + * \note This file contains telnet-related functions specific to 5G NR UE (nrUE). + */ + +#include +#include +#include +#include +#include +#include +#include +#include "openair2/LAYER2/NR_MAC_UE/mac_defs.h" +#include "openair2/LAYER2/NR_MAC_UE/mac_proto.h" + +#define TELNETSERVERCODE +#include "telnetsrv.h" + +#define ERROR_MSG_RET(mSG, aRGS...) do { prnt(mSG, ##aRGS); return 1; } while (0) + +/* UE L2 state string */ +const char* NR_UE_L2_STATE_STR[] = { +#define UE_STATE(state) #state, + NR_UE_L2_STATES +#undef UE_STATE +}; + +/** + * Get the synchronization state of a UE. + * + * @param buf User input buffer containing UE ID + * @param debug Debug flag (not used) + * @param prnt Function to print output + * @return 0 on success, error code otherwise + */ +int get_sync_state(char *buf, int debug, telnet_printfunc_t prnt) +{ + int ue_id = -1; + if (!buf) { + ERROR_MSG_RET("no UE ID provided to telnet command\n"); + } else { + ue_id = strtol(buf, NULL, 10); + if (ue_id < 0) + ERROR_MSG_RET("UE ID needs to be positive\n"); + } + /* get sync state */ + int sync_state = nr_ue_get_sync_state(ue_id); + prnt("UE sync state = %s\n", NR_UE_L2_STATE_STR[sync_state]); + return 0; +} + +/* Telnet shell command definitions */ +static telnetshell_cmddef_t cicmds[] = { + {"sync_state", "[UE_ID(int,opt)]", get_sync_state}, + {"", "", NULL}, +}; + +/* Telnet shell variable definitions (if needed) */ +static telnetshell_vardef_t civars[] = { + {"", 0, 0, NULL} +}; + +/* Add CI UE commands */ +void add_ciUE_cmds(void) { + add_telnetcmd("ciUE", civars, cicmds); +} + diff --git a/docker/Dockerfile.nrUE.ubuntu20 b/docker/Dockerfile.nrUE.ubuntu20 index e6f8d45e53..dfbd5f93e6 100644 --- a/docker/Dockerfile.nrUE.ubuntu20 +++ b/docker/Dockerfile.nrUE.ubuntu20 @@ -90,6 +90,7 @@ COPY --from=nr-ue-build \ /oai-ran/cmake_targets/ran_build/build/libdfts.so \ /oai-ran/cmake_targets/ran_build/build/libldpc*.so \ /oai-ran/cmake_targets/ran_build/build/libtelnetsrv.so \ + /oai-ran/cmake_targets/ran_build/build/libtelnetsrv_ciUE.so \ /oai-ran/cmake_targets/ran_build/build/libtelnetsrv_5Gue.so \ /usr/local/lib/ diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h index 67e4a0f078..fa58cf4676 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h @@ -164,13 +164,19 @@ #define PRACH_MASK_INDEX 54 #define RESERVED_NR_DCI 55 +// Define the UE L2 states with X-Macro +#define NR_UE_L2_STATES \ + UE_STATE(UE_NOT_SYNC) \ + UE_STATE(UE_SYNC) \ + UE_STATE(UE_PERFORMING_RA) \ + UE_STATE(UE_CONNECTED) \ + UE_STATE(UE_DETACHING) + /*!\brief UE layer 2 status */ typedef enum { - UE_NOT_SYNC = 0, - UE_SYNC, - UE_PERFORMING_RA, - UE_CONNECTED, - UE_DETACHING +#define UE_STATE(state) state, + NR_UE_L2_STATES +#undef UE_STATE } NR_UE_L2_STATE_t; typedef enum { diff --git a/openair2/LAYER2/NR_MAC_UE/mac_proto.h b/openair2/LAYER2/NR_MAC_UE/mac_proto.h index 003d4fc12d..b13c2a9865 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_proto.h @@ -297,6 +297,13 @@ void configure_initial_pucch(PUCCH_sched_t *pucch, int res_ind); void nr_ue_reset_sync_state(NR_UE_MAC_INST_t *mac); void nr_ue_send_synch_request(NR_UE_MAC_INST_t *mac, module_id_t module_id, int cc_id, int cell_id); +/** + * @brief Get UE sync state + * @param mod_id UE ID + * @return UE sync state + */ +NR_UE_L2_STATE_t nr_ue_get_sync_state(module_id_t mod_id); + void init_RA(NR_UE_MAC_INST_t *mac, NR_PRACH_RESOURCES_t *prach_resources, NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon, diff --git a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c index 666506b2fc..8d13ddfb68 100644 --- a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c +++ b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c @@ -115,6 +115,12 @@ void nr_ue_reset_sync_state(NR_UE_MAC_INST_t *mac) mac->ra.ra_state = nrRA_UE_IDLE; } +NR_UE_L2_STATE_t nr_ue_get_sync_state(module_id_t mod_id) +{ + NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id); + return mac->state; +} + NR_UE_MAC_INST_t *nr_l2_init_ue(int nb_inst) { //init mac here