mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-13 12:40:28 +00:00
Compare commits
4 Commits
config_api
...
microamp_E
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
83d5255bb5 | ||
|
|
6449c334be | ||
|
|
de8b43bbe0 | ||
|
|
7bae2fe095 |
@@ -62,7 +62,6 @@ ForEachMacros:
|
||||
- BOOST_FOREACH
|
||||
- RB_FOREACH
|
||||
- UE_iterator
|
||||
- FOR_EACH_SEQ_ARR
|
||||
IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
- Regex: '^<ext/.*\.h>'
|
||||
|
||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -20,14 +20,6 @@ GRTAGS
|
||||
GTAGS
|
||||
tags
|
||||
|
||||
# Package conffiles
|
||||
|
||||
tools/packages/oai-lte/conffiles
|
||||
tools/packages/oai-nr/conffiles
|
||||
tools/packages/liboai-common/conffiles
|
||||
tools/packages/liboai-usrp/conffiles
|
||||
|
||||
|
||||
# others
|
||||
nfapi_nr_interface_scf
|
||||
*.log
|
||||
|
||||
66
CHANGELOG.md
66
CHANGELOG.md
@@ -1,71 +1,5 @@
|
||||
# RELEASE NOTES: #
|
||||
|
||||
## [v2.4.0](https://gitlab.eurecom.fr/oai/openairinterface5g/-/tags/v2.4.0) -> December 2025. ##
|
||||
|
||||
General new features and improvements (both RAN and UE):
|
||||
- Rework LDPC BBdev/AAL interface and support both AMD T2/Intel vRAN Boost
|
||||
(VRB) 1 accelerators
|
||||
- Add a taps client for vrtsim real-time simulator (check: vrtsim release?)
|
||||
- Add new RFemulator virtual radio driver to emulate radio (including noise
|
||||
generation) for gNB/UE standalone operation
|
||||
- RLC AM reception improvements for high-throughput scenarios (!3512)
|
||||
- Small NTN fixes (!3659, !3666, !3581, !3652)
|
||||
- Improvements to imScope
|
||||
|
||||
Stability and bug fixes:
|
||||
- RFsimulator: fix concurrency problems during multi-client connection
|
||||
- USRP driver: support synchronization of USRP B200
|
||||
- MAC scheduler improvements
|
||||
- General L1 improvements for efficiency and stability
|
||||
- Correct PRS bug and test in CI
|
||||
- Upgrade Ubuntu container images to Ubuntu 24.04
|
||||
- All build system targets compile (`make/ninja all`)
|
||||
- Minor cleanup, harmonization, and performance improvements all over the stack
|
||||
- Simplify CI code
|
||||
|
||||
RAN changes (gNB/CU/CU-CP/CU-UP/DU/DU-high/DU-low):
|
||||
- Support of N2 handover
|
||||
- Support of "UL-heavy" TDD patterns, e.g., DSUUU
|
||||
- Open Fronthaul M-plane: CM improvements, PM implementation, and additional
|
||||
v16.01 support
|
||||
- Improve interoperability with Nvidia Aerial L1 to support 2 layer UL
|
||||
- Add O-RAN OSC WLS library as FAPI transport and enable L1/L2 shared memory
|
||||
split
|
||||
- Implement FAPI Stop exchange
|
||||
- Improve interoperability with srsRAN_Project DU
|
||||
- Add new synchronized real-time data recording application (!3462)
|
||||
- Support for measurement gaps and general handover fixes
|
||||
- Support of RRC PDU session release procedure
|
||||
- Add CU-UP load tester
|
||||
- Correct BWP scheduling and support multiple BWPs per UE
|
||||
|
||||
nrUE changes:
|
||||
- Support one additional PDU session (see !3486)
|
||||
- L3 measurements for A2 measurement reports
|
||||
- Support for type0 PDSCH frequency allocation
|
||||
- UE symbol based PDCCH receiver
|
||||
|
||||
Regression or removals:
|
||||
- No known regressions
|
||||
- Unused L2 simulator code has been removed
|
||||
- Unused Benetel radio driver code (not FHI 7.2!) has been removed
|
||||
|
||||
Configuration file changes:
|
||||
- `gNBs.[0].servingCellConfigCommon.[0].ra_ResponseWindow` is automatically
|
||||
computed and can be removed
|
||||
- `gNBs.[0].bwp_list` has been added (moved from entries in
|
||||
`gNBs.[0].servingCellConfigDedicated`)
|
||||
- `gNBs.[0].phaseTrackingRS` has been added (moved from entries in
|
||||
`gNBs.[0].servingCellConfigDedicated`)
|
||||
- `gNBs.[0].local_s_portc` and `gNBs.[0].remote_s_portc` have no effect and
|
||||
should be removed
|
||||
- `gNBs.[0].CSI_report_type` has been added
|
||||
- `MACRLCs.[0].ulsch_max_frame_inactivity` is automatically computed and can be
|
||||
removed
|
||||
- `MACRLCs.[0].local_n_portc` and `MACRLCs.[0].remote_n_portc` have no effect and
|
||||
should be removed
|
||||
- `MACRLCs.[0].stats_max_ue` has been added
|
||||
|
||||
## [v2.3.0](https://gitlab.eurecom.fr/oai/openairinterface5g/-/tags/v2.3.0) -> July 2025. ##
|
||||
|
||||
General new features and improvements (both RAN and UE):
|
||||
|
||||
330
CMakeLists.txt
330
CMakeLists.txt
@@ -22,39 +22,6 @@
|
||||
cmake_minimum_required (VERSION 3.16)
|
||||
project (OpenAirInterface LANGUAGES C CXX)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(OAI_VERSION 2.4.0)
|
||||
|
||||
option(CUDA_ENABLE "Enable CUDA accelerated channel simulation" OFF)
|
||||
if(CUDA_ENABLE)
|
||||
find_package(CUDA REQUIRED)
|
||||
find_package(CUDAToolkit REQUIRED)
|
||||
message(STATUS "CUDA explicitly enabled, building with GPU acceleration support.")
|
||||
|
||||
enable_language(CUDA)
|
||||
|
||||
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
|
||||
set(CMAKE_CUDA_ARCHITECTURES 90)
|
||||
endif()
|
||||
|
||||
option(USE_UNIFIED_MEMORY "Enable CUDA Unified Memory path" OFF)
|
||||
option(USE_ATS_MEMORY "Enable ATS Hybrid Memory path" ON)
|
||||
|
||||
if(USE_UNIFIED_MEMORY AND USE_ATS_MEMORY)
|
||||
message(FATAL_ERROR "Cannot enable both USE_UNIFIED_MEMORY and USE_ATS_MEMORY at the same time.")
|
||||
endif()
|
||||
|
||||
if(USE_UNIFIED_MEMORY)
|
||||
add_compile_definitions(USE_UNIFIED_MEMORY)
|
||||
message(STATUS "CUDA Unified Memory path enabled.")
|
||||
elseif(USE_ATS_MEMORY)
|
||||
add_compile_definitions(USE_ATS_MEMORY)
|
||||
message(STATUS "CUDA ATS Hybrid Memory path enabled.")
|
||||
else()
|
||||
message(STATUS "CUDA Explicit Copy path enabled (default ATS was overridden).")
|
||||
endif()
|
||||
|
||||
add_compile_definitions(ENABLE_CUDA)
|
||||
endif()
|
||||
|
||||
#########################################################
|
||||
# Base directories, compatible with legacy OAI building #
|
||||
@@ -94,15 +61,6 @@ endif()
|
||||
###################################
|
||||
include(FindPkgConfig)
|
||||
|
||||
|
||||
option(PACKAGING_RPM "By default will create debian packages, with this option willl create rpm packages" OFF)
|
||||
option(PACKAGING_NR "Will produce a package containing nr target, configuration files and docs" OFF)
|
||||
option(PACKAGING_LTE "Will produce a package containing lte target, configuration files and docs" OFF)
|
||||
option(PACKAGING_COMMON "Will produce a package containing common target, configuration files and docs" OFF)
|
||||
option(PACKAGING_USRP "Will produce a package containing usrp target, configuration files and docs" OFF)
|
||||
option(PACKAGING_PHYSIM "Will produce a package containing physim target, configuration files and docs" OFF)
|
||||
|
||||
|
||||
# Check if asn1c is installed, and check if it supports all options we need
|
||||
# a user can provide ASN1C_EXEC to override an asn1c to use (e.g., parallel
|
||||
# installation)
|
||||
@@ -129,6 +87,8 @@ set (NFAPI_USER_DIR ${OPENAIR_DIR}/nfapi/oai_integration)
|
||||
set (OPENAIR1_DIR ${OPENAIR_DIR}/openair1)
|
||||
set (OPENAIR2_DIR ${OPENAIR_DIR}/openair2)
|
||||
set (OPENAIR3_DIR ${OPENAIR_DIR}/openair3)
|
||||
set (OPENAIR3_DIR ${OPENAIR_DIR}/openair3)
|
||||
set (OPENAIR_CMAKE ${OPENAIR_DIR}/cmake_targets)
|
||||
|
||||
project (OpenAirInterface)
|
||||
|
||||
@@ -198,8 +158,6 @@ elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
|
||||
set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -gdwarf-2 -mcpu=neoverse-n1 -lgcc -lrt")
|
||||
elseif (CPUPART MATCHES "0xd49") # Neoverse-N2
|
||||
set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -gdwarf-2 -mcpu=neoverse-n2 -ftree-vectorize -lgcc -lrt")
|
||||
elseif (CPUPART MATCHES "0xd03") # Cortex-A53
|
||||
set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -gdwarf-2 -mcpu=cortex-a53 -lgcc -lrt")
|
||||
else ()
|
||||
set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -gdwarf-2 -mcpu=native -lgcc -lrt")
|
||||
endif()
|
||||
@@ -208,12 +166,7 @@ else()
|
||||
endif()
|
||||
|
||||
if (NOT CROSS_COMPILE)
|
||||
if (CPUPART MATCHES "0xd03")
|
||||
# Cortex-A53 does not support ARMv8.2-A extensions
|
||||
set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -march=armv8-a+simd")
|
||||
else()
|
||||
set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -march=native")
|
||||
endif()
|
||||
set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -march=native")
|
||||
else ()
|
||||
set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -march=armv8.2-a")
|
||||
endif()
|
||||
@@ -269,16 +222,9 @@ endif()
|
||||
|
||||
add_definitions("-DASN_DISABLE_OER_SUPPORT -DHAVE_CONFIG_H -DHAVE_CONFIG_H_")
|
||||
|
||||
set(CMAKE_SKIP_BUILD_RPATH FALSE)
|
||||
set(CMAKE_BUILD_RPATH ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
|
||||
set(CMAKE_INSTALL_RPATH "")
|
||||
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE)
|
||||
|
||||
if(PACKAGING_LTE OR PACKAGING_NR OR PACKAGING_COMMON OR PACKAGING_USRP OR PACKAGING_PHYSIM)
|
||||
set(CMAKE_SKIP_INSTALL_RPATH TRUE)
|
||||
endif()
|
||||
|
||||
#########################
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -ggdb2 -Wl,-rpath -Wl,${CMAKE_CURRENT_BINARY_DIR}")
|
||||
#########################
|
||||
# set a flag for changes in the source code
|
||||
# these changes are related to hardcoded path to include .h files
|
||||
set(debugOpt "-ggdb2 -DMALLOC_CHECK_=3 -fno-delete-null-pointer-checks")
|
||||
@@ -321,22 +267,6 @@ if(GIT_FOUND)
|
||||
)
|
||||
endif()
|
||||
|
||||
option(USE_UNIFIED_MEMORY "Enable CUDA Unified Memory path instead of explicit copies" OFF)
|
||||
|
||||
option(USE_ATS_MEMORY "Enable Hybrid ATS (CPU->GPU) and Explicit Copy (GPU->CPU) path" OFF)
|
||||
|
||||
if(USE_UNIFIED_MEMORY AND USE_ATS_MEMORY)
|
||||
message(FATAL_ERROR "Cannot enable both USE_UNIFIED_MEMORY and USE_ATS_MEMORY at the same time.")
|
||||
endif()
|
||||
|
||||
if(USE_UNIFIED_MEMORY)
|
||||
add_compile_definitions(USE_UNIFIED_MEMORY)
|
||||
message(STATUS "CUDA Unified Memory path enabled.")
|
||||
elseif(USE_ATS_MEMORY)
|
||||
add_compile_definitions(USE_ATS_MEMORY)
|
||||
message(STATUS "CUDA ATS Hybrid Memory path enabled.")
|
||||
endif()
|
||||
|
||||
# Debug related options
|
||||
#########################################
|
||||
# asn1c skeletons have hardcoded this flag to make customized debug logs
|
||||
@@ -352,7 +282,7 @@ add_boolean_option(TRACY_ENABLE OFF "Enable tracy instrumentation" ON)
|
||||
if (TRACY_ENABLE)
|
||||
# the tracy version here should match the tracy server version
|
||||
# below is latest release as of this commit
|
||||
CPMAddPackage("gh:wolfpld/tracy#v0.13.1")
|
||||
CPMAddPackage("gh:wolfpld/tracy#0.12.2")
|
||||
endif()
|
||||
|
||||
set (OCP_ITTI ${OPENAIR_DIR}/common/utils/ocp_itti)
|
||||
@@ -397,7 +327,7 @@ target_link_libraries(lte_rrc PRIVATE nr_rrc)
|
||||
#NR RRC
|
||||
#######
|
||||
add_library(nr_rrc ${OPENAIR2_DIR}/RRC/NR/MESSAGES/asn1_msg.c)
|
||||
target_link_libraries(nr_rrc PUBLIC asn1_nr_rrc asn1_lte_rrc rrc_cell_management)
|
||||
target_link_libraries(nr_rrc PUBLIC asn1_nr_rrc asn1_lte_rrc)
|
||||
|
||||
# S1AP
|
||||
##############
|
||||
@@ -434,9 +364,7 @@ add_library(ngap
|
||||
${NGAP_DIR}/ngap_gNB_handlers.c
|
||||
${NGAP_DIR}/ngap_gNB_itti_messaging.c
|
||||
${NGAP_DIR}/ngap_gNB_management_procedures.c
|
||||
${NGAP_DIR}/ngap_gNB_paging.c
|
||||
${NGAP_DIR}/ngap_gNB_nas_procedures.c
|
||||
${NGAP_DIR}/ngap_gNB_pdu_session_management.c
|
||||
${NGAP_DIR}/ngap_gNB_nnsf.c
|
||||
${NGAP_DIR}/ngap_gNB_overload.c
|
||||
${NGAP_DIR}/ngap_gNB_trace.c
|
||||
@@ -444,9 +372,6 @@ add_library(ngap
|
||||
)
|
||||
target_link_libraries(ngap PUBLIC asn1_ngap)
|
||||
target_link_libraries(ngap PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs)
|
||||
if(ENABLE_TESTS)
|
||||
target_compile_definitions(ngap PRIVATE ENABLE_TESTS)
|
||||
endif()
|
||||
|
||||
#M2AP
|
||||
##############
|
||||
@@ -537,11 +462,8 @@ add_library(f1ap
|
||||
${F1AP_DIR}/f1ap_itti_messaging.c)
|
||||
target_include_directories(f1ap PUBLIC F1AP_DIR)
|
||||
target_link_libraries(f1ap PUBLIC asn1_f1ap GTPV1U)
|
||||
target_link_libraries(f1ap PRIVATE ngap nr_rrc ds f1ap_lib)
|
||||
target_link_libraries(f1ap PRIVATE ngap nr_rrc HASHTABLE f1ap_lib)
|
||||
target_include_directories(f1ap PRIVATE ${F1AP_DIR}/lib)
|
||||
if(E2_AGENT)
|
||||
target_compile_definitions(f1ap PRIVATE E2_AGENT)
|
||||
endif()
|
||||
|
||||
# LPP
|
||||
##############
|
||||
@@ -549,10 +471,8 @@ endif()
|
||||
|
||||
# Hardware dependant options
|
||||
###################################
|
||||
set(NB_ANTENNAS_RX "4" CACHE STRING "Number of antennas in reception")
|
||||
set_property(CACHE NB_ANTENNAS_RX PROPERTY STRINGS "1" "2" "4" "8")
|
||||
set(NB_ANTENNAS_TX "4" CACHE STRING "Number of antennas in transmission")
|
||||
set_property(CACHE NB_ANTENNAS_TX PROPERTY STRINGS "1" "2" "4" "8")
|
||||
add_list1_option(NB_ANTENNAS_RX "4" "Number of antennas in reception" "1" "2" "4")
|
||||
add_list1_option(NB_ANTENNAS_TX "4" "Number of antennas in transmission" "1" "2" "4")
|
||||
|
||||
set (CONFIG_ROOTDIR ${OPENAIR_DIR}/common/config)
|
||||
add_library(config_internals OBJECT
|
||||
@@ -577,6 +497,8 @@ target_link_libraries(params_libconfig PRIVATE config_internals ${libconfig_LIBR
|
||||
add_library(shlib_loader OBJECT common/utils/load_module_shlib.c)
|
||||
target_link_libraries(shlib_loader PRIVATE CONFIG_LIB)
|
||||
|
||||
include_directories ("${OPENAIR_DIR}/radio/COMMON")
|
||||
|
||||
##############################################################
|
||||
# ???!!! TO BE DOCUMENTED OPTIONS !!!???
|
||||
##############################################################
|
||||
@@ -655,6 +577,7 @@ include_directories("${OPENAIR3_DIR}/S1AP")
|
||||
include_directories("${OPENAIR2_DIR}/X2AP")
|
||||
include_directories("${OPENAIR2_DIR}/M2AP")
|
||||
include_directories("${OPENAIR2_DIR}/F1AP")
|
||||
include_directories("${OPENAIR3_DIR}/ocp-gtpu")
|
||||
include_directories("${OPENAIR3_DIR}/M3AP")
|
||||
include_directories("${OPENAIR3_DIR}/MME_APP")
|
||||
include_directories("${OPENAIR_DIR}/radio/COMMON")
|
||||
@@ -676,6 +599,12 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/common/utils/T
|
||||
# set the T_LIB name to T if the target exists, otherwise leave empty
|
||||
set(T_LIB $<TARGET_NAME_IF_EXISTS:T>)
|
||||
|
||||
add_library(HASHTABLE
|
||||
${OPENAIR_DIR}/common/utils/hashtable/hashtable.c
|
||||
${OPENAIR_DIR}/common/utils/hashtable/obj_hashtable.c
|
||||
)
|
||||
include_directories(${OPENAIR_DIR}/common/utils/hashtable)
|
||||
|
||||
add_library(UTIL
|
||||
${OPENAIR_DIR}/common/utils/LOG/vcd_signal_dumper.c
|
||||
${OPENAIR2_DIR}/UTIL/OPT/probe.c
|
||||
@@ -723,6 +652,7 @@ add_library(SCHED_LIB ${SCHED_SRC})
|
||||
target_link_libraries(SCHED_LIB PRIVATE asn1_lte_rrc_hdrs)
|
||||
|
||||
set(SCHED_NR_SRC
|
||||
${OPENAIR1_DIR}/SCHED_NR/fapi_nr_l1.c
|
||||
${OPENAIR1_DIR}/SCHED_NR/phy_procedures_nr_gNB.c
|
||||
${OPENAIR1_DIR}/SCHED_NR/nr_prach_procedures.c
|
||||
${OPENAIR1_DIR}/SCHED_NR/phy_frame_config_nr.c
|
||||
@@ -833,6 +763,24 @@ include_directories(${NFAPI_USER_DIR})
|
||||
|
||||
# Layer 1
|
||||
#############################
|
||||
set(PHY_POLARSRC
|
||||
${OPENAIR1_DIR}/PHY/CODING/nrPolar_tools/nr_polar_init.c
|
||||
${OPENAIR1_DIR}/PHY/CODING/nrPolar_tools/nr_bitwise_operations.c
|
||||
${OPENAIR1_DIR}/PHY/CODING/nrPolar_tools/nr_crc_byte.c
|
||||
${OPENAIR1_DIR}/PHY/CODING/nrPolar_tools/nr_polar_decoder.c
|
||||
${OPENAIR1_DIR}/PHY/CODING/nrPolar_tools/nr_polar_decoding_tools.c
|
||||
${OPENAIR1_DIR}/PHY/CODING/nrPolar_tools/nr_polar_encoder.c
|
||||
${OPENAIR1_DIR}/PHY/CODING/nrPolar_tools/nr_polar_interleaving_pattern.c
|
||||
${OPENAIR1_DIR}/PHY/CODING/nrPolar_tools/nr_polar_kernal_operation.c
|
||||
${OPENAIR1_DIR}/PHY/CODING/nrPolar_tools/nr_polar_kronecker_power_matrices.c
|
||||
${OPENAIR1_DIR}/PHY/CODING/nrPolar_tools/nr_polar_matrix_and_array.c
|
||||
${OPENAIR1_DIR}/PHY/CODING/nrPolar_tools/nr_polar_procedures.c
|
||||
${OPENAIR1_DIR}/PHY/CODING/nrPolar_tools/nr_polar_sequence_pattern.c
|
||||
)
|
||||
set(PHY_SMALLBLOCKSRC
|
||||
${OPENAIR1_DIR}/PHY/CODING/nrSmallBlock/encodeSmallBlock.c
|
||||
${OPENAIR1_DIR}/PHY/CODING/nrSmallBlock/decodeSmallBlock.c
|
||||
)
|
||||
set(PHY_TURBOIF
|
||||
${OPENAIR1_DIR}/PHY/CODING/coding_load.c
|
||||
)
|
||||
@@ -843,6 +791,8 @@ set(PHY_NRLDPC_CODINGIF
|
||||
|
||||
add_library(dfts MODULE ${OPENAIR1_DIR}/PHY/TOOLS/oai_dfts.c ${OPENAIR1_DIR}/PHY/TOOLS/oai_dfts_neon.c)
|
||||
|
||||
add_library(crc_byte OBJECT ${OPENAIR1_DIR}/PHY/CODING/crc_byte.c)
|
||||
|
||||
set(PHY_SRC_COMMON
|
||||
${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dci_tools_common.c
|
||||
${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/lte_mcs.c
|
||||
@@ -932,6 +882,7 @@ set(PHY_SRC_UE
|
||||
${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/sss_gen.c
|
||||
${OPENAIR1_DIR}/PHY/LTE_UE_TRANSPORT/dlsch_demodulation.c
|
||||
${OPENAIR1_DIR}/PHY/LTE_UE_TRANSPORT/dlsch_llr_computation.c
|
||||
${OPENAIR1_DIR}/PHY/LTE_UE_TRANSPORT/linear_preprocessing_rec.c
|
||||
${OPENAIR1_DIR}/PHY/LTE_UE_TRANSPORT/dlsch_decoding.c
|
||||
${OPENAIR1_DIR}/PHY/LTE_UE_TRANSPORT/dci_tools_ue.c
|
||||
${OPENAIR1_DIR}/PHY/LTE_UE_TRANSPORT/uci_tools_ue.c
|
||||
@@ -988,6 +939,7 @@ set(PHY_SRC_UE
|
||||
${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_dci.c
|
||||
${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_dci_tools.c
|
||||
${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_dlsch.c
|
||||
${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_dlsch_tools.c
|
||||
${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_dlsch_coding.c
|
||||
${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_ulsch_decoding.c
|
||||
${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_ulsch.c
|
||||
@@ -1010,6 +962,8 @@ set(PHY_SRC_UE
|
||||
${OPENAIR1_DIR}/PHY/TOOLS/dB_routines.c
|
||||
${OPENAIR1_DIR}/PHY/TOOLS/sqrt.c
|
||||
${OPENAIR1_DIR}/PHY/TOOLS/oai_arith_operations.c
|
||||
${PHY_POLARSRC}
|
||||
${PHY_SMALLBLOCKSRC}
|
||||
${PHY_NRLDPC_CODINGIF}
|
||||
${OPENAIR1_DIR}/PHY/NR_TRANSPORT/pucch_rx.c
|
||||
${OPENAIR1_DIR}/PHY/NR_TRANSPORT/srs_rx.c
|
||||
@@ -1024,7 +978,6 @@ set(PHY_SRC_UE
|
||||
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/cic_filter_nr.c
|
||||
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_initial_sync.c
|
||||
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_initial_sync_sl.c
|
||||
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_ntn_l1.c
|
||||
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_ue_rf_helpers.c
|
||||
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_pbch.c
|
||||
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_psbch_rx.c
|
||||
@@ -1059,6 +1012,8 @@ set(PHY_SRC_UE
|
||||
${OPENAIR1_DIR}/PHY/TOOLS/sqrt.c
|
||||
${OPENAIR1_DIR}/PHY/TOOLS/oai_arith_operations.c
|
||||
${OPENAIR1_DIR}/PHY/INIT/nr_init_ue.c
|
||||
${PHY_POLARSRC}
|
||||
${PHY_SMALLBLOCKSRC}
|
||||
${PHY_NRLDPC_CODINGIF}
|
||||
)
|
||||
|
||||
@@ -1077,21 +1032,29 @@ add_dependencies(PHY_COMMON dfts)
|
||||
add_library(PHY ${PHY_SRC})
|
||||
target_link_libraries(PHY PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs)
|
||||
|
||||
pkg_check_modules(blas REQUIRED blas)
|
||||
pkg_check_modules(lapacke REQUIRED lapacke)
|
||||
|
||||
add_library(PHY_UE ${PHY_SRC_UE})
|
||||
target_link_libraries(PHY_UE PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs UTIL)
|
||||
# RHEL needs also cblas, but Ubuntu does not have it. So `cblas_LIBRARIES` will
|
||||
# be empty for Ubuntu, a no-op
|
||||
pkg_check_modules(cblas cblas)
|
||||
target_link_libraries(PHY_UE PRIVATE ${blas_LIBRARIES} ${cblas_LIBRARIES} ${lapacke_LIBRARIES})
|
||||
target_include_directories(PHY_UE PRIVATE ${blas_INCLUDE_DIRS} ${lapacke_INCLUDE_DIRS})
|
||||
|
||||
add_library(PHY_NR_COMMON ${PHY_NR_SRC_COMMON})
|
||||
target_link_libraries(PHY_NR_COMMON PUBLIC UTIL)
|
||||
|
||||
add_library(PHY_NR ${PHY_NR_SRC})
|
||||
target_link_libraries(PHY_NR nr_phy_common nr_common nr_fapi_p5 polar smallblock)
|
||||
target_link_libraries(PHY_NR nr_phy_common nr_common nr_fapi_p5)
|
||||
|
||||
add_library(PHY_NR_NO_AVX_256 ${PHY_NR_SRC})
|
||||
target_link_libraries(PHY_NR_NO_AVX_256 nr_phy_common nr_common)
|
||||
target_compile_definitions(PHY_NR_NO_AVX_256 PUBLIC USE_128BIT)
|
||||
|
||||
add_library(PHY_NR_UE ${PHY_NR_UE_SRC})
|
||||
target_link_libraries(PHY_NR_UE PRIVATE asn1_nr_rrc_hdrs nr_phy_common nr_common UTIL polar smallblock)
|
||||
target_link_libraries(PHY_NR_UE PRIVATE asn1_nr_rrc_hdrs nr_phy_common nr_common UTIL)
|
||||
|
||||
add_library(PHY_RU ${PHY_SRC_RU})
|
||||
target_link_libraries(PHY_RU PRIVATE asn1_lte_rrc_hdrs UTIL)
|
||||
@@ -1155,7 +1118,7 @@ set(L2_SRC
|
||||
${RRC_DIR}/rrc_eNB_S1AP.c
|
||||
${RRC_DIR}/rrc_eNB_M2AP.c
|
||||
${RRC_DIR}/rrc_eNB_UE_context.c
|
||||
${RRC_DIR}/rrc_eNB_GTPV1U.c
|
||||
${NR_RRC_DIR}/rrc_gNB_UE_context.c
|
||||
${RRC_DIR}/rrc_common.c
|
||||
${RRC_DIR}/L2_interface.c
|
||||
${RRC_DIR}/L2_interface_common.c
|
||||
@@ -1221,7 +1184,6 @@ set(NR_L2_SRC_UE
|
||||
${NR_UE_RRC_DIR}/L2_interface_ue.c
|
||||
${NR_UE_RRC_DIR}/main_ue.c
|
||||
${NR_UE_RRC_DIR}/rrc_UE.c
|
||||
${NR_UE_RRC_DIR}/verify_RRC.c
|
||||
${NR_UE_RRC_DIR}/rrc_timers_and_constants.c
|
||||
${NR_UE_RRC_DIR}/rrc_sl_preconfig.c
|
||||
)
|
||||
@@ -1253,6 +1215,7 @@ set (MAC_SRC
|
||||
|
||||
set (MAC_NR_SRC
|
||||
${NR_PHY_INTERFACE_DIR}/NR_IF_Module.c
|
||||
${NR_PHY_INTERFACE_DIR}/nr_sched_response.c
|
||||
${NR_GNB_MAC_DIR}/main.c
|
||||
${NR_GNB_MAC_DIR}/config.c
|
||||
${NR_GNB_MAC_DIR}/gNB_scheduler.c
|
||||
@@ -1320,6 +1283,12 @@ set (MISC_NFAPI_LTE
|
||||
|
||||
add_library(MISC_NFAPI_LTE_LIB ${MISC_NFAPI_LTE})
|
||||
|
||||
set (MISC_NFAPI_NR
|
||||
${OPENAIR1_DIR}/SCHED/nfapi_nr_dummy.c
|
||||
)
|
||||
|
||||
add_library(MISC_NFAPI_NR_LIB ${MISC_NFAPI_NR})
|
||||
|
||||
add_library(L2
|
||||
${L2_SRC}
|
||||
${MAC_SRC}
|
||||
@@ -1328,9 +1297,6 @@ add_library(L2
|
||||
)
|
||||
target_link_libraries(L2 PRIVATE x2ap s1ap lte_rrc m2ap)
|
||||
target_link_libraries(L2 PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs)
|
||||
if(E2_AGENT)
|
||||
target_compile_definitions(L2 PRIVATE ${E2AP_VERSION} ${KPM_VERSION} E2_AGENT)
|
||||
endif()
|
||||
|
||||
add_library(MAC_UE_NR ${MAC_NR_SRC_UE})
|
||||
target_link_libraries(MAC_UE_NR PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs PUBLIC nr_ue_power_procedures nr_ue_ra_procedures)
|
||||
@@ -1346,9 +1312,6 @@ add_library(L2_NR
|
||||
target_link_libraries(L2_NR PRIVATE ds alg)
|
||||
target_link_libraries(L2_NR PRIVATE f1ap_lib)
|
||||
target_include_directories(L2_NR PRIVATE ${F1AP_DIR}/lib)
|
||||
if(E2_AGENT)
|
||||
target_compile_definitions(L2_NR PRIVATE ${E2AP_VERSION} ${KPM_VERSION} E2_AGENT)
|
||||
endif()
|
||||
|
||||
add_library(e1_if
|
||||
${NR_RRC_DIR}/cucp_cuup_direct.c
|
||||
@@ -1402,6 +1365,15 @@ include_directories("${OPENAIR1_DIR}/SCHED_NR_UE")
|
||||
# CN libs
|
||||
##########################
|
||||
|
||||
add_library (GTPV1U
|
||||
${RRC_DIR}/rrc_eNB_GTPV1U.c
|
||||
${OPENAIR3_DIR}/ocp-gtpu/gtp_itf.cpp
|
||||
${OPENAIR3_DIR}/ocp-gtpu/gtpu_extensions.c
|
||||
)
|
||||
target_link_libraries(GTPV1U PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs)
|
||||
target_link_libraries(GTPV1U PRIVATE SIMU ds)
|
||||
include_directories(${OPENAIR3_DIR}/ocp-gtp)
|
||||
|
||||
set (MME_APP_SRC
|
||||
${OPENAIR3_DIR}/MME_APP/mme_app.c
|
||||
${OPENAIR3_DIR}/MME_APP/mme_config.c
|
||||
@@ -1699,17 +1671,6 @@ set (SIMUSRC
|
||||
add_library(SIMU STATIC ${SIMUSRC} )
|
||||
target_include_directories(SIMU PUBLIC ${OPENAIR1_DIR}/SIMULATION/TOOLS ${OPENAIR1_DIR}/SIMULATION/RF)
|
||||
|
||||
option(CHANNEL_SSE "Enable SSE optimizations for channel simulation" OFF)
|
||||
if(CHANNEL_SSE)
|
||||
message(STATUS "SSE-optimized channel simulation enabled.")
|
||||
target_compile_definitions(SIMU PRIVATE CHANNEL_SSE)
|
||||
endif()
|
||||
|
||||
if(CUDA_FOUND)
|
||||
set_property(TARGET SIMU PROPERTY CUDA_ARCHITECTURES ${CMAKE_CUDA_ARCHITECTURES})
|
||||
set_property(TARGET SIMU PROPERTY LINKER_LANGUAGE CXX)
|
||||
endif()
|
||||
|
||||
include_directories("${NFAPI_DIR}/nfapi/public_inc")
|
||||
include_directories("${NFAPI_DIR}/common/public_inc")
|
||||
include_directories("${NFAPI_DIR}/pnf/public_inc")
|
||||
@@ -1740,9 +1701,12 @@ add_executable(lte-softmodem
|
||||
${OPENAIR_DIR}/executables/lte-ru.c
|
||||
${OPENAIR_DIR}/executables/ru_control.c
|
||||
${OPENAIR_DIR}/executables/lte-softmodem.c
|
||||
${OPENAIR_DIR}/executables/softmodem-common.c
|
||||
${OPENAIR2_DIR}/ENB_APP/NB_IoT_interface.c
|
||||
${OPENAIR_DIR}/executables/create_tasks.c
|
||||
${OPENAIR_DIR}/executables/create_tasks_mbms.c
|
||||
${OPENAIR_DIR}/radio/COMMON/common_lib.c
|
||||
${OPENAIR_DIR}/radio/COMMON/record_player.c
|
||||
${OPENAIR3_DIR}/NAS/UE/nas_ue_task.c
|
||||
${PHY_INTERFACE_DIR}/queue_t.c
|
||||
${OPENAIR_DIR}/common/utils/lte/ue_power.c
|
||||
@@ -1753,14 +1717,15 @@ add_dependencies(lte-softmodem oai_iqplayer)
|
||||
|
||||
target_link_libraries(lte-softmodem PRIVATE
|
||||
-Wl,--start-group
|
||||
lte_rrc nr_rrc s1ap m2ap x2ap m3ap GTPV1U SECURITY UTIL SCTP_CLIENT MME_APP SCHED_LIB SCHED_RU_LIB
|
||||
lte_rrc nr_rrc s1ap m2ap x2ap m3ap GTPV1U SECURITY UTIL HASHTABLE SCTP_CLIENT MME_APP SCHED_LIB SCHED_RU_LIB
|
||||
PHY_COMMON PHY PHY_RU L2 L2_LTE NFAPI_LIB NFAPI_VNF_LIB NFAPI_PNF_LIB NFAPI_USER_LIB MISC_NFAPI_LTE_LIB
|
||||
${NAS_UE_LIB} ITTI SIMU radio_common softmodem_common
|
||||
${NAS_UE_LIB} ITTI SIMU shlib_loader
|
||||
-Wl,--end-group z dl)
|
||||
|
||||
target_link_libraries(lte-softmodem PRIVATE pthread m CONFIG_LIB rt)
|
||||
target_link_libraries(lte-softmodem PRIVATE ${T_LIB})
|
||||
target_link_libraries(lte-softmodem PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs)
|
||||
target_link_libraries(lte-softmodem PRIVATE ${blas_LIBRARIES} ${cblas_LIBRARIES} ${lapacke_LIBRARIES} ${lapack_LIBRARIES})
|
||||
|
||||
if(E2_AGENT)
|
||||
target_link_libraries(lte-softmodem PUBLIC e2_agent e2_agent_arg e2_ran_func_du_cucp_cuup)
|
||||
@@ -1770,13 +1735,16 @@ endif()
|
||||
add_executable(oairu
|
||||
${OPENAIR_DIR}/executables/lte-ru.c
|
||||
${OPENAIR_DIR}/executables/ru_control.c
|
||||
${OPENAIR_DIR}/radio/COMMON/common_lib.c
|
||||
${OPENAIR_DIR}/radio/COMMON/record_player.c
|
||||
${OPENAIR_DIR}/executables/softmodem-common.c
|
||||
${OPENAIR_DIR}/openair1/SCHED/phy_procedures_lte_common.c
|
||||
${OPENAIR_DIR}/executables/main_ru.c
|
||||
${OPENAIR_DIR}/common/utils/lte/prach_utils.c
|
||||
)
|
||||
target_link_libraries(oairu PRIVATE
|
||||
-Wl,--start-group
|
||||
SCHED_RU_LIB PHY_COMMON PHY_RU UTIL radio_common softmodem_common
|
||||
SCHED_RU_LIB PHY_COMMON PHY_RU UTIL shlib_loader
|
||||
-Wl,--end-group z dl)
|
||||
|
||||
target_link_libraries(oairu PRIVATE pthread m CONFIG_LIB rt ${T_LIB})
|
||||
@@ -1793,7 +1761,10 @@ target_link_libraries(lte-softmodem PRIVATE
|
||||
add_executable(lte-uesoftmodem
|
||||
${OPENAIR_DIR}/executables/lte-ue.c
|
||||
${OPENAIR_DIR}/executables/lte-uesoftmodem.c
|
||||
${OPENAIR_DIR}/executables/softmodem-common.c
|
||||
${OPENAIR_DIR}/executables/create_tasks_ue.c
|
||||
${OPENAIR_DIR}/radio/COMMON/common_lib.c
|
||||
${OPENAIR_DIR}/radio/COMMON/record_player.c
|
||||
${OPENAIR3_DIR}/NAS/UE/nas_ue_task.c
|
||||
${OPENAIR_DIR}/common/utils/lte/ue_power.c
|
||||
${OPENAIR_DIR}/common/utils/lte/prach_utils.c
|
||||
@@ -1803,35 +1774,20 @@ add_executable(lte-uesoftmodem
|
||||
target_link_libraries(lte-uesoftmodem PRIVATE
|
||||
-Wl,--start-group
|
||||
lte_rrc nr_rrc s1ap x2ap m2ap m3ap
|
||||
SECURITY UTIL SCTP_CLIENT MME_APP SCHED_RU_LIB SCHED_UE_LIB PHY_COMMON
|
||||
SECURITY UTIL HASHTABLE SCTP_CLIENT MME_APP SCHED_RU_LIB SCHED_UE_LIB PHY_COMMON
|
||||
PHY_UE PHY_RU L2_UE L2_LTE SIMU NFAPI_LIB NFAPI_PNF_LIB NFAPI_USER_LIB MISC_NFAPI_LTE_LIB
|
||||
${NAS_UE_LIB} ITTI radio_common softmodem_common
|
||||
${NAS_UE_LIB} ITTI shlib_loader
|
||||
-Wl,--end-group z dl)
|
||||
|
||||
target_link_libraries(lte-uesoftmodem PRIVATE pthread m CONFIG_LIB rt)
|
||||
target_link_libraries(lte-uesoftmodem PRIVATE ${T_LIB})
|
||||
target_link_libraries(lte-uesoftmodem PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs)
|
||||
target_link_libraries(lte-uesoftmodem PRIVATE ${blas_LIBRARIES} ${cblas_LIBRARIES} ${lapacke_LIBRARIES} ${lapack_LIBRARIES})
|
||||
|
||||
# force the generation of ASN.1 so that we don't need to wait during the build
|
||||
target_link_libraries(lte-uesoftmodem PRIVATE
|
||||
asn1_lte_rrc asn1_s1ap asn1_m2ap asn1_m3ap asn1_x2ap)
|
||||
|
||||
# nr RRU
|
||||
add_executable(nr-oru
|
||||
${OPENAIR_DIR}/executables/nr-ru.c
|
||||
${OPENAIR_DIR}/openair1/PHY/INIT/nr_parms.c
|
||||
${OPENAIR_DIR}/openair1/SCHED_NR/phy_frame_config_nr.c
|
||||
${OPENAIR_DIR}/openair1/SCHED_NR/nr_prach_procedures.c
|
||||
${OPENAIR_DIR}/openair1/SCHED/phy_procedures_lte_common.c
|
||||
${OPENAIR_DIR}/executables/main_nr_ru.c
|
||||
)
|
||||
target_link_libraries(nr-oru PRIVATE
|
||||
UTIL SCHED_RU_LIB PHY_COMMON PHY_RU PHY_NR shlib_loader z dl
|
||||
radio_common softmodem_common)
|
||||
target_link_libraries(nr-oru PRIVATE pthread m CONFIG_LIB rt ${T_LIB} utils
|
||||
barrier actor)
|
||||
target_link_libraries(nr-oru PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs nr_phy_common time_management)
|
||||
|
||||
# nr-softmodem
|
||||
###################################################
|
||||
|
||||
@@ -1842,6 +1798,9 @@ add_executable(nr-softmodem
|
||||
${OPENAIR_DIR}/executables/nr-gnb.c
|
||||
${OPENAIR_DIR}/executables/nr-ru.c
|
||||
${OPENAIR_DIR}/executables/nr-softmodem.c
|
||||
${OPENAIR_DIR}/executables/softmodem-common.c
|
||||
${OPENAIR_DIR}/radio/COMMON/common_lib.c
|
||||
${OPENAIR_DIR}/radio/COMMON/record_player.c
|
||||
${OPENAIR_DIR}/common/utils/lte/ue_power.c
|
||||
${OPENAIR_DIR}/common/utils/lte/prach_utils.c
|
||||
${PHY_INTERFACE_DIR}/queue_t.c
|
||||
@@ -1850,11 +1809,11 @@ add_executable(nr-softmodem
|
||||
|
||||
target_link_libraries(nr-softmodem PRIVATE
|
||||
-Wl,--start-group
|
||||
UTIL SCTP_CLIENT SCHED_LIB SCHED_RU_LIB SCHED_NR_LIB PHY_NR PHY PHY_COMMON PHY_NR_COMMON PHY_RU GTPV1U SECURITY
|
||||
UTIL HASHTABLE SCTP_CLIENT SCHED_LIB SCHED_RU_LIB SCHED_NR_LIB PHY_NR PHY PHY_COMMON PHY_NR_COMMON PHY_RU GTPV1U SECURITY
|
||||
ITTI ${NAS_UE_LIB} lte_rrc nr_rrc
|
||||
ngap s1ap L2_LTE_NR L2_NR MAC_NR_COMMON NFAPI_LIB NFAPI_VNF_LIB NFAPI_PNF_LIB NFAPI_USER_LIB SIMU
|
||||
x2ap f1ap m2ap m3ap e1ap radio_common
|
||||
time_management softmodem_common
|
||||
x2ap f1ap m2ap m3ap e1ap shlib_loader
|
||||
time_management
|
||||
-Wl,--end-group z dl)
|
||||
|
||||
target_link_libraries(nr-softmodem PRIVATE pthread m CONFIG_LIB rt)
|
||||
@@ -1884,6 +1843,7 @@ target_link_libraries(nr-softmodem PRIVATE
|
||||
|
||||
add_executable(nr-cuup
|
||||
executables/nr-cuup.c
|
||||
executables/softmodem-common.c
|
||||
${NR_RRC_DIR}/rrc_gNB_UE_context.c
|
||||
${OPENAIR2_DIR}/E1AP/e1ap_setup.c
|
||||
${NR_PDCP_SRC}
|
||||
@@ -1893,9 +1853,9 @@ add_executable(nr-cuup
|
||||
target_link_libraries(nr-cuup PRIVATE
|
||||
CONFIG_LIB ITTI SCTP_CLIENT
|
||||
GTPV1U e1ap f1ap
|
||||
time_management softmodem_common
|
||||
time_management
|
||||
alg
|
||||
z dl pthread ${T_LIB})
|
||||
z dl pthread shlib_loader ${T_LIB})
|
||||
target_link_libraries(nr-cuup PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs)
|
||||
if(E2_AGENT)
|
||||
target_link_libraries(nr-cuup PRIVATE e2_agent e2_agent_arg e2_ran_func_cuup)
|
||||
@@ -1911,7 +1871,11 @@ add_executable(nr-uesoftmodem
|
||||
${OPENAIR_DIR}/executables/nr-uesoftmodem.c
|
||||
${OPENAIR_DIR}/executables/position_interface.c
|
||||
${OPENAIR_DIR}/executables/nr-ue.c
|
||||
${OPENAIR_DIR}/executables/nr-ue-ru.c
|
||||
${OPENAIR_DIR}/executables/softmodem-common.c
|
||||
${OPENAIR_DIR}/radio/COMMON/common_lib.c
|
||||
${OPENAIR_DIR}/radio/COMMON/record_player.c
|
||||
${OPENAIR2_DIR}/LAYER2/NR_MAC_COMMON/nr_mac_common.c
|
||||
${OPENAIR2_DIR}/LAYER2/NR_MAC_COMMON/nr_mac_common_tdd.c
|
||||
${OPENAIR1_DIR}/PHY/TOOLS/phy_scope_interface.c
|
||||
${NFAPI_USER_DIR}/nfapi.c
|
||||
${PHY_INTERFACE_DIR}/queue_t.c
|
||||
@@ -1919,10 +1883,10 @@ add_executable(nr-uesoftmodem
|
||||
|
||||
target_link_libraries(nr-uesoftmodem PRIVATE
|
||||
-Wl,--start-group
|
||||
nr_rrc SECURITY UTIL SCHED_RU_LIB SCHED_NR_UE_LIB
|
||||
nr_rrc SECURITY UTIL HASHTABLE SCHED_RU_LIB SCHED_NR_UE_LIB
|
||||
PHY_COMMON PHY_NR_COMMON PHY_NR_UE NR_L2_UE MAC_NR_COMMON NFAPI_LIB
|
||||
ITTI SIMU radio_common
|
||||
time_management softmodem_common
|
||||
ITTI SIMU shlib_loader
|
||||
time_management
|
||||
-Wl,--end-group z dl)
|
||||
|
||||
target_link_libraries(nr-uesoftmodem PRIVATE pthread m CONFIG_LIB rt nr_ue_phy_meas)
|
||||
@@ -1955,10 +1919,10 @@ target_link_libraries(nr-uesoftmodem PRIVATE
|
||||
add_executable(rftest
|
||||
${OPENAIR_DIR}/openair1/PHY/TOOLS/calibration_test.c
|
||||
${OPENAIR_DIR}/openair1/PHY/TOOLS/calibration_scope.c
|
||||
${OPENAIR_DIR}/radio/COMMON/common_lib.c
|
||||
${OPENAIR_DIR}/executables/softmodem-common.c
|
||||
)
|
||||
target_link_libraries(rftest PRIVATE
|
||||
minimal_lib PHY_NR_COMMON UTIL forms pthread dl m ${T_LIB}
|
||||
radio_common softmodem_common)
|
||||
target_link_libraries(rftest PRIVATE minimal_lib PHY_NR_COMMON UTIL forms pthread dl m ${T_LIB} shlib_loader)
|
||||
target_link_libraries(rftest PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs)
|
||||
|
||||
add_executable(polartest
|
||||
@@ -1975,7 +1939,7 @@ add_executable(smallblocktest
|
||||
|
||||
target_link_libraries(smallblocktest PRIVATE
|
||||
-Wl,--start-group UTIL SIMU PHY_NR PHY_COMMON PHY_NR_COMMON -Wl,--end-group
|
||||
m pthread dl ${T_LIB}
|
||||
m pthread dl shlib_loader ${T_LIB}
|
||||
)
|
||||
|
||||
|
||||
@@ -1985,7 +1949,7 @@ add_executable(ldpctest
|
||||
)
|
||||
target_link_libraries(ldpctest PRIVATE
|
||||
-Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON -Wl,--end-group
|
||||
m pthread dl ${T_LIB}
|
||||
m pthread dl shlib_loader ${T_LIB}
|
||||
# link 'check_crc' to make it resolved in the LDPC coding libraries
|
||||
# 'check_crc' is not used in ldpctest so it is not linked in the executable by default
|
||||
# --whole-archive links 'check_crc' in the executable even though it is note used, see 'man ld'
|
||||
@@ -1998,53 +1962,54 @@ target_link_libraries(physim_common PRIVATE UTIL)
|
||||
add_executable(nr_dlschsim ${OPENAIR1_DIR}/SIMULATION/NR_PHY/dlschsim.c)
|
||||
target_link_libraries(nr_dlschsim PRIVATE
|
||||
-Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB CONFIG_LIB MAC_NR_COMMON -Wl,--end-group
|
||||
m pthread ${T_LIB} ITTI dl physim_common
|
||||
m pthread ${T_LIB} ITTI dl shlib_loader physim_common
|
||||
)
|
||||
target_link_libraries(nr_dlschsim PRIVATE asn1_nr_rrc_hdrs)
|
||||
|
||||
add_executable(nr_pbchsim ${OPENAIR1_DIR}/SIMULATION/NR_PHY/pbchsim.c)
|
||||
target_link_libraries(nr_pbchsim PRIVATE
|
||||
-Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB CONFIG_LIB MAC_NR_COMMON -Wl,--end-group
|
||||
m pthread ${T_LIB} ITTI dl physim_common
|
||||
m pthread ${T_LIB} ITTI dl shlib_loader physim_common
|
||||
)
|
||||
target_link_libraries(nr_pbchsim PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs)
|
||||
|
||||
add_executable(nr_psbchsim
|
||||
${OPENAIR1_DIR}/SIMULATION/NR_PHY/psbchsim.c
|
||||
${OPENAIR_DIR}/executables/softmodem-common.c
|
||||
${NFAPI_USER_DIR}/nfapi.c
|
||||
${NFAPI_USER_DIR}/gnb_ind_vars.c
|
||||
${PHY_INTERFACE_DIR}/queue_t.c
|
||||
)
|
||||
target_link_libraries(nr_psbchsim PRIVATE
|
||||
-Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB SCHED_NR_UE_LIB MAC_UE_NR MAC_NR_COMMON CONFIG_LIB L2_NR -Wl,--end-group
|
||||
m pthread ${T_LIB} ITTI dl physim_common softmodem_common
|
||||
-Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB SCHED_NR_UE_LIB MAC_UE_NR MAC_NR_COMMON CONFIG_LIB L2_NR -lz -Wl,--end-group
|
||||
m pthread ${T_LIB} ITTI dl shlib_loader physim_common
|
||||
)
|
||||
target_link_libraries(nr_psbchsim PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs)
|
||||
|
||||
add_executable(nr_pucchsim ${OPENAIR1_DIR}/SIMULATION/NR_PHY/pucchsim.c)
|
||||
target_link_libraries(nr_pucchsim PRIVATE
|
||||
-Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB CONFIG_LIB MAC_NR_COMMON -Wl,--end-group
|
||||
m pthread ${T_LIB} ITTI dl physim_common
|
||||
m pthread ${T_LIB} ITTI dl shlib_loader physim_common
|
||||
)
|
||||
target_link_libraries(nr_pucchsim PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs)
|
||||
|
||||
add_executable(nr_dlsim
|
||||
${OPENAIR1_DIR}/SIMULATION/NR_PHY/dlsim.c
|
||||
${OPENAIR_DIR}/executables/softmodem-common.c
|
||||
${NFAPI_USER_DIR}/nfapi.c
|
||||
${NFAPI_USER_DIR}/gnb_ind_vars.c
|
||||
${PHY_INTERFACE_DIR}/queue_t.c
|
||||
)
|
||||
target_link_libraries(nr_dlsim PRIVATE
|
||||
-Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB SCHED_NR_UE_LIB MAC_UE_NR MAC_NR_COMMON nr_rrc CONFIG_LIB L2_NR x2ap SECURITY ngap -Wl,--end-group
|
||||
m pthread ${T_LIB} ITTI dl nr_ue_phy_meas physim_common
|
||||
softmodem_common
|
||||
-Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB SCHED_NR_UE_LIB MAC_UE_NR MAC_NR_COMMON nr_rrc CONFIG_LIB L2_NR HASHTABLE x2ap SECURITY ngap -lz -Wl,--end-group
|
||||
m pthread ${T_LIB} ITTI dl shlib_loader nr_ue_phy_meas physim_common
|
||||
)
|
||||
target_link_libraries(nr_dlsim PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs)
|
||||
|
||||
add_executable(nr_prachsim ${OPENAIR1_DIR}/SIMULATION/NR_PHY/prachsim.c)
|
||||
target_link_libraries(nr_prachsim PRIVATE
|
||||
-Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_RU PHY_NR_UE MAC_NR_COMMON SCHED_NR_LIB CONFIG_LIB -Wl,--end-group
|
||||
m pthread ${T_LIB} ITTI dl physim_common)
|
||||
-Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_RU PHY_NR_UE MAC_NR_COMMON SCHED_NR_LIB CONFIG_LIB -lz -Wl,--end-group
|
||||
m pthread ${T_LIB} ITTI dl shlib_loader physim_common)
|
||||
target_link_libraries(nr_prachsim PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs)
|
||||
|
||||
add_executable(nr_ulschsim
|
||||
@@ -2053,48 +2018,28 @@ add_executable(nr_ulschsim
|
||||
)
|
||||
target_link_libraries(nr_ulschsim PRIVATE
|
||||
-Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB CONFIG_LIB MAC_NR_COMMON -Wl,--end-group
|
||||
m pthread ${T_LIB} ITTI dl physim_common
|
||||
m pthread ${T_LIB} ITTI dl shlib_loader physim_common
|
||||
)
|
||||
target_link_libraries(nr_ulschsim PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs)
|
||||
|
||||
add_executable(nr_ulsim
|
||||
${OPENAIR1_DIR}/SIMULATION/NR_PHY/ulsim.c
|
||||
${OPENAIR_DIR}/executables/softmodem-common.c
|
||||
${NFAPI_USER_DIR}/nfapi.c
|
||||
${NFAPI_USER_DIR}/gnb_ind_vars.c
|
||||
${PHY_INTERFACE_DIR}/queue_t.c
|
||||
)
|
||||
|
||||
target_link_libraries(nr_ulsim PRIVATE
|
||||
-Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB SCHED_NR_UE_LIB MAC_UE_NR MAC_NR_COMMON nr_rrc CONFIG_LIB L2_NR x2ap SECURITY ngap -Wl,--end-group
|
||||
m pthread ${T_LIB} ITTI dl nr_ue_phy_meas physim_common softmodem_common
|
||||
-Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB SCHED_NR_UE_LIB MAC_UE_NR MAC_NR_COMMON nr_rrc CONFIG_LIB L2_NR HASHTABLE x2ap SECURITY ngap -lz -Wl,--end-group
|
||||
m pthread ${T_LIB} ITTI dl shlib_loader nr_ue_phy_meas physim_common
|
||||
)
|
||||
target_link_libraries(nr_ulsim PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs)
|
||||
|
||||
add_executable(nr_srssim
|
||||
${OPENAIR1_DIR}/SIMULATION/NR_PHY/srssim.c
|
||||
${NFAPI_USER_DIR}/nfapi.c
|
||||
${NFAPI_USER_DIR}/gnb_ind_vars.c
|
||||
${PHY_INTERFACE_DIR}/queue_t.c
|
||||
)
|
||||
|
||||
target_link_libraries(nr_srssim PRIVATE
|
||||
-Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB SCHED_NR_UE_LIB MAC_UE_NR MAC_NR_COMMON -Wl,--end-group
|
||||
m pthread ITTI dl nr_ue_phy_meas physim_common softmodem_common
|
||||
)
|
||||
|
||||
if(CUDA_ENABLE)
|
||||
if (TARGET oai_cuda_lib)
|
||||
target_link_libraries(nr_dlsim PRIVATE oai_cuda_lib)
|
||||
target_link_libraries(nr_ulsim PRIVATE oai_cuda_lib)
|
||||
|
||||
target_compile_definitions(nr_dlsim PRIVATE ENABLE_CUDA)
|
||||
target_compile_definitions(nr_ulsim PRIVATE ENABLE_CUDA)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# these simulators do not compile:
|
||||
# dlsim_tm7 pbchsim scansim mbmssim pdcchsim pucchsim prachsim syncsim
|
||||
foreach(myExe dlsim ulsim)
|
||||
|
||||
add_executable(${myExe}
|
||||
${OPENAIR1_DIR}/SIMULATION/LTE_PHY/${myExe}.c
|
||||
${OPENAIR_DIR}/common/utils/lte/ue_power.c
|
||||
@@ -2104,7 +2049,7 @@ foreach(myExe dlsim ulsim)
|
||||
)
|
||||
target_link_libraries (${myExe} PRIVATE
|
||||
-Wl,--start-group SIMU UTIL SCHED_LIB SCHED_RU_LIB SCHED_UE_LIB PHY_COMMON PHY_NR_COMMON PHY PHY_UE PHY_RU ITTI -Wl,--end-group
|
||||
pthread m rt CONFIG_LIB ${T_LIB} dl
|
||||
pthread m rt CONFIG_LIB ${T_LIB} dl shlib_loader
|
||||
)
|
||||
target_link_libraries(${myExe} PRIVATE asn1_lte_rrc_hdrs)
|
||||
add_dependencies(${myExe} coding)
|
||||
@@ -2139,14 +2084,14 @@ if (${T_TRACER})
|
||||
nr-uesoftmodem dlsim dlsim_tm4 dlsim_tm7
|
||||
ulsim pbchsim scansim mbmssim pdcchsim pucchsim prachsim
|
||||
syncsim nr_ulsim nr_dlsim nr_dlschsim nr_pbchsim nr_pucchsim
|
||||
nr_ulschsim ldpctest polartest smallblocktest nr_srssim
|
||||
nr_ulschsim ldpctest polartest smallblocktest
|
||||
#all "add_library" definitions
|
||||
ITTI lte_rrc nr_rrc s1ap x2ap m2ap m3ap f1ap
|
||||
params_libconfig
|
||||
oai_eth_transpro UTIL
|
||||
oai_eth_transpro HASHTABLE UTIL
|
||||
SECURITY SCHED_LIB SCHED_NR_LIB SCHED_RU_LIB SCHED_UE_LIB SCHED_NR_UE_LIB
|
||||
NFAPI_LIB NFAPI_PNF_LIB NFAPI_VNF_LIB NFAPI_USER_LIB
|
||||
MISC_NFAPI_LTE_LIB
|
||||
MISC_NFAPI_LTE_LIB MISC_NFAPI_NR_LIB
|
||||
PHY_COMMON PHY PHY_UE PHY_NR PHY_NR_COMMON PHY_NR_UE PHY_RU
|
||||
L2 L2_LTE L2_NR L2_LTE_NR L2_UE NR_L2_UE MAC_NR_COMMON MAC_UE_NR ngap
|
||||
GTPV1U SCTP_CLIENT MME_APP LIB_NAS_UE SIMU
|
||||
@@ -2196,7 +2141,6 @@ if(ENABLE_TESTS)
|
||||
endif()
|
||||
|
||||
add_subdirectory(common)
|
||||
add_subdirectory(executables)
|
||||
add_subdirectory(doc)
|
||||
add_subdirectory(nfapi)
|
||||
add_subdirectory(openair1)
|
||||
@@ -2204,13 +2148,3 @@ add_subdirectory(openair2)
|
||||
add_subdirectory(openair3)
|
||||
add_subdirectory(radio)
|
||||
add_subdirectory(tests)
|
||||
|
||||
if(TARGET oai_cuda_lib)
|
||||
message(STATUS "CUDA library 'oai_cuda_lib' found, linking to targets...")
|
||||
target_link_libraries(nr_dlsim PRIVATE oai_cuda_lib)
|
||||
target_link_libraries(nr_ulsim PRIVATE oai_cuda_lib)
|
||||
endif()
|
||||
|
||||
if(PACKAGING_LTE OR PACKAGING_NR OR PACKAGING_COMMON OR PACKAGING_USRP OR PACKAGING_PHYSIM)
|
||||
include("tools/packages/packages.cmake")
|
||||
endif()
|
||||
|
||||
233
ci-scripts/Jenkinsfile
vendored
233
ci-scripts/Jenkinsfile
vendored
@@ -1,233 +0,0 @@
|
||||
#!/bin/groovy
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
def pythonExecutor = params.pythonExecutor
|
||||
def testXMLFile = params.pythonTestXmlFile
|
||||
def mainPythonAllXmlFiles = ""
|
||||
def buildStageStatus = true
|
||||
def JOB_TIMESTAMP
|
||||
|
||||
// Choose test stage name or fallback default
|
||||
def testStageName = params.pipelineTestStageName != null ? params.pipelineTestStageName : 'Template Test Stage'
|
||||
|
||||
// Name of the resource
|
||||
def lockResources = []
|
||||
if (params.LockResources != null && params.LockResources.trim().length() > 0)
|
||||
params.LockResources.trim().split(",").each{lockResources += [resource: it.trim()]}
|
||||
|
||||
// Global Parameters. Normally they should be populated when the master job
|
||||
// triggers the slave job with parameters
|
||||
|
||||
def sourceRepository = params.eNB_Repository ?: env.GIT_URL
|
||||
def sourceBranch = params.eNB_Branch ?: env.GIT_BRANCH
|
||||
def targetRepository = params.Target_Repository ?: sourceRepository
|
||||
def targetBranch = params.eNB_TargetBranch ?: 'develop'
|
||||
def commitID = params.eNB_CommitID ?: env.GIT_COMMIT
|
||||
def is_MR = params.eNB_mergeRequest ?: false
|
||||
|
||||
def flexricOption = ""
|
||||
def runWithOC = false
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Pipeline start
|
||||
pipeline {
|
||||
agent {
|
||||
label pythonExecutor
|
||||
}
|
||||
options {
|
||||
timestamps()
|
||||
ansiColor('xterm')
|
||||
lock(extra: lockResources)
|
||||
}
|
||||
|
||||
stages {
|
||||
stage("Build Init") {
|
||||
steps {
|
||||
script {
|
||||
echo '\u2705 \u001B[94mBuild Init\u001B[0m'
|
||||
JOB_TIMESTAMP = sh(returnStdout: true, script: 'date --utc --rfc-3339=seconds | sed -e "s#+00:00##"').trim()
|
||||
}
|
||||
// update the build name and description
|
||||
buildName "${params.eNB_MR}"
|
||||
buildDescription "Branch : ${sourceBranch}"
|
||||
}
|
||||
}
|
||||
stage ('Verify Parameters') {
|
||||
steps {
|
||||
script {
|
||||
echo '\u2705 \u001B[94mVerify Parameters\u001B[0m'
|
||||
def allParametersPresent = true
|
||||
|
||||
if (params.LockResources == null) {
|
||||
echo "no LockResources given"
|
||||
allParametersPresent = false
|
||||
}
|
||||
if (params.eNB_SourceCodePath == null) {
|
||||
echo "no eNB_SourceCodePath given"
|
||||
allParametersPresent = false
|
||||
}
|
||||
if (params.OC_Credentials != null) {
|
||||
echo "This pipeline is configured to run with Opensift Cluster."
|
||||
runWithOC = true
|
||||
if (params.OC_ProjectName == null) {
|
||||
echo "no OC_ProjectName given"
|
||||
allParametersPresent = false
|
||||
}
|
||||
}
|
||||
if (params.Flexric_Tag != null) {
|
||||
echo "This pipeline is configured to run with a FlexRIC deployment."
|
||||
echo "Appending FlexRicTag option to the list of options"
|
||||
flexricOption = "--FlexRicTag=${params.Flexric_Tag}"
|
||||
echo "Using new Flexric option: ${flexricOption}"
|
||||
}
|
||||
|
||||
echo "CI executor node : ${pythonExecutor}"
|
||||
echo "Source Repository : ${sourceRepository}"
|
||||
echo "Source Branch : ${sourceBranch}"
|
||||
echo "Target Repository : ${targetRepository}"
|
||||
echo "Target Branch : ${targetBranch}"
|
||||
echo "Commit ID : ${commitID}"
|
||||
|
||||
if (allParametersPresent) {
|
||||
echo '\u2705 \u001B[94m All parameters are present\u001B[0m'
|
||||
if (is_MR) {
|
||||
sh "git fetch"
|
||||
sh "./ci-scripts/doGitLabMerge.sh --src-branch ${sourceBranch} --src-commit ${commitID} --target-branch ${targetBranch} --target-commit latest"
|
||||
} else {
|
||||
sh "git fetch"
|
||||
sh "git checkout -f ${commitID}"
|
||||
}
|
||||
} else {
|
||||
echo "\u274C Some parameters are missing"
|
||||
sh "./ci-scripts/fail.sh"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage ("Deploy and Test") {
|
||||
steps {
|
||||
script {
|
||||
dir ('ci-scripts') {
|
||||
echo "\u2705 \u001B[94m Deploy and Test: ${testStageName}\u001B[0m"
|
||||
String[] myXmlTestSuite = testXMLFile.split("\\r?\\n")
|
||||
for (xmlFile in myXmlTestSuite) {
|
||||
if (fileExists(xmlFile)) {
|
||||
mainPythonAllXmlFiles += "--XMLTestFile=" + xmlFile + " "
|
||||
echo "Test XML file : ${xmlFile}"
|
||||
} else {
|
||||
echo "Test XML file ${xmlFile}: no such file"
|
||||
}
|
||||
}
|
||||
sh """
|
||||
python3 main.py --mode=InitiateHtml --ranRepository=${targetRepository} \
|
||||
--ranBranch=${sourceBranch} --ranCommitID=${commitID} \
|
||||
--ranAllowMerge=${is_MR} --ranTargetBranch=${targetBranch} \
|
||||
${flexricOption} ${mainPythonAllXmlFiles}
|
||||
"""
|
||||
if (runWithOC) {
|
||||
withCredentials([usernamePassword(credentialsId: "${params.OC_Credentials}", usernameVariable: 'OC_Username', passwordVariable: 'OC_Password')]) {
|
||||
sh """
|
||||
python3 main.py --mode=InitiateHtml --ranRepository=${targetRepository} \
|
||||
--ranBranch=${sourceBranch} --ranCommitID=${commitID} \
|
||||
--ranAllowMerge=${is_MR} --ranTargetBranch=${targetBranch} \
|
||||
${flexricOption} ${mainPythonAllXmlFiles}
|
||||
"""
|
||||
for (xmlFile in myXmlTestSuite) {
|
||||
if (fileExists(xmlFile)) {
|
||||
try {
|
||||
timeout (time: 60, unit: 'MINUTES') {
|
||||
sh """
|
||||
python3 main.py --mode=TesteNB --ranRepository=${targetRepository} \
|
||||
--ranBranch=${sourceBranch} --ranCommitID=${commitID} \
|
||||
--ranAllowMerge=${is_MR} --ranTargetBranch=${targetBranch} \
|
||||
--eNBSourceCodePath=${params.eNB_SourceCodePath} --XMLTestFile=${xmlFile} \
|
||||
--OCUserName=${OC_Username} --OCPassword=${OC_Password} --OCProjectName=${OC_ProjectName} \
|
||||
${flexricOption}
|
||||
"""
|
||||
}
|
||||
} catch (Exception e) {
|
||||
currentBuild.result = 'FAILURE'
|
||||
buildStageStatus = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (xmlFile in myXmlTestSuite) {
|
||||
if (fileExists(xmlFile)) {
|
||||
try {
|
||||
timeout (time: 60, unit: 'MINUTES') {
|
||||
sh """
|
||||
python3 main.py --mode=TesteNB --ranRepository=${targetRepository} \
|
||||
--ranBranch=${sourceBranch} --ranCommitID=${commitID} \
|
||||
--ranAllowMerge=${is_MR} --ranTargetBranch=${targetBranch} \
|
||||
--eNBSourceCodePath=${params.eNB_SourceCodePath} --XMLTestFile=${xmlFile} \
|
||||
${flexricOption}
|
||||
"""
|
||||
}
|
||||
} catch (Exception e) {
|
||||
currentBuild.result = 'FAILURE'
|
||||
buildStageStatus = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage ("Log Collection") {
|
||||
steps {
|
||||
script {
|
||||
echo '\u2705 \u001B[94mLog Collection\u001B[0m'
|
||||
dir ('ci-scripts') {
|
||||
// Zipping all archived log files
|
||||
sh "mkdir test_logs"
|
||||
sh "mv *.log* test_logs || true"
|
||||
// Zip all log files matching cmake_targets/{*.log*,log/*} into test_logs_XXXX.zip
|
||||
if (fileExists('../cmake_targets/log')) {
|
||||
sh "mv ../cmake_targets/log/* test_logs || true"
|
||||
}
|
||||
sh "zip -r -qq test_logs_${env.BUILD_ID}.zip *test_log*/"
|
||||
sh "rm -rf *test_log*/"
|
||||
if (fileExists("test_logs_${env.BUILD_ID}.zip")) {
|
||||
archiveArtifacts artifacts: "test_logs_${env.BUILD_ID}.zip"
|
||||
}
|
||||
if (fileExists("test_results.html")) {
|
||||
def reportName = "test_results-${env.JOB_NAME}.html"
|
||||
sh "mv test_results.html ${reportName}"
|
||||
sh """
|
||||
sed -i -e 's#TEMPLATE_BUILD_TIME#${JOB_TIMESTAMP}#' \
|
||||
-e 's#TEMPLATE_JOB_NAME#${JOB_NAME}#' \
|
||||
-e 's@build #TEMPLATE_BUILD_ID@build #${BUILD_ID}@' \
|
||||
-e 's#Build-ID: TEMPLATE_BUILD_ID#Build-ID: <a href=\"${BUILD_URL}\">${BUILD_ID}</a>#' \
|
||||
-e 's#TEMPLATE_STAGE_NAME#${testStageName}#' ${reportName}
|
||||
"""
|
||||
archiveArtifacts artifacts: "${reportName}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -334,29 +334,6 @@ pipeline {
|
||||
}
|
||||
}
|
||||
}
|
||||
stage ("Channel-Simulation") {
|
||||
when { expression {do5Gtest || do5GUeTest} }
|
||||
steps {
|
||||
script {
|
||||
triggerSlaveJob ('RAN-Channel-Simulation', 'Channel-Simulation')
|
||||
}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
script {
|
||||
// Using a unique variable name for each test stage to avoid overwriting on a global variable
|
||||
// due to parallel-time concurrency
|
||||
channelSimStatus = finalizeSlaveJob('RAN-Channel-Simulation')
|
||||
}
|
||||
}
|
||||
failure {
|
||||
script {
|
||||
currentBuild.result = 'FAILURE'
|
||||
failingStages += channelSimStatus
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage ("PhySim-Cluster-4G") {
|
||||
when { expression {do4Gtest} }
|
||||
steps {
|
||||
@@ -403,29 +380,6 @@ pipeline {
|
||||
}
|
||||
}
|
||||
}
|
||||
stage ("VRT-Sim-Test-5G") {
|
||||
when { expression {do5Gtest || do5GUeTest} }
|
||||
steps {
|
||||
script {
|
||||
triggerSlaveJob ('RAN-VRT-Sim-Test-5G', 'VRT-Sim-Test-5G')
|
||||
}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
script {
|
||||
// Using a unique variable name for each test stage to avoid overwriting on a global variable
|
||||
// due to parallel-time concurrency
|
||||
vrtSim5GStatus = finalizeSlaveJob('RAN-VRT-Sim-Test-5G')
|
||||
}
|
||||
}
|
||||
failure {
|
||||
script {
|
||||
currentBuild.result = 'FAILURE'
|
||||
failingStages += vrtSim5GStatus
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage ("RF-Sim-Test-5G") {
|
||||
when { expression {do5Gtest || do5GUeTest} }
|
||||
steps {
|
||||
@@ -726,11 +680,11 @@ pipeline {
|
||||
}
|
||||
}
|
||||
}
|
||||
stage ("SA-Multi-Antenna-CN5G") {
|
||||
stage ("SA-2x2-Module-CN5G") {
|
||||
when { expression {do5Gtest} }
|
||||
steps {
|
||||
script {
|
||||
triggerSlaveJob ('RAN-SA-Multi-Antenna-CN5G', 'SA-Multi-Antenna-CN5G')
|
||||
triggerSlaveJob ('RAN-SA-2x2-Module-CN5G', 'SA-2x2-Module-CN5G')
|
||||
}
|
||||
}
|
||||
post {
|
||||
@@ -738,13 +692,13 @@ pipeline {
|
||||
script {
|
||||
// Using a unique variable name for each test stage to avoid overwriting on a global variable
|
||||
// due to parallel-time concurrency
|
||||
saMultiAntennaStatus = finalizeSlaveJob('RAN-SA-Multi-Antenna-CN5G')
|
||||
saTDD2x2Status = finalizeSlaveJob('RAN-SA-2x2-Module-CN5G')
|
||||
}
|
||||
}
|
||||
failure {
|
||||
script {
|
||||
currentBuild.result = 'FAILURE'
|
||||
failingStages += saMultiAntennaStatus
|
||||
failingStages += saTDD2x2Status
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
228
ci-scripts/Jenkinsfile-cluster
Normal file
228
ci-scripts/Jenkinsfile-cluster
Normal file
@@ -0,0 +1,228 @@
|
||||
#!/bin/groovy
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
// Location of the executor node
|
||||
def pythonExecutor = params.pythonExecutor
|
||||
|
||||
// Location of the test XML file to be run
|
||||
def testXMLFile = params.pythonTestXmlFile
|
||||
def mainPythonAllXmlFiles = ""
|
||||
def buildStageStatus = true
|
||||
|
||||
// Name of the test stage
|
||||
def testStageName = params.pipelineTestStageName
|
||||
|
||||
// Name of the resource
|
||||
def lockResources = []
|
||||
if (params.LockResources != null && params.LockResources.trim().length() > 0)
|
||||
params.LockResources.trim().split(",").each{lockResources += [resource: it.trim()]}
|
||||
|
||||
// Global Parameters. Normally they should be populated when the master job
|
||||
// triggers the slave job with parameters
|
||||
def eNB_Repository
|
||||
def eNB_Branch
|
||||
def eNB_CommitID
|
||||
def eNB_AllowMergeRequestProcess = false
|
||||
def eNB_TargetBranch
|
||||
|
||||
def directoryExistsGlob(fileNameWithGlob) {
|
||||
/* if multiple directories match, will join their names and call fileExists() on that */
|
||||
def dir = sh returnStdout: true, script: 'find . -name \'' + fileNameWithGlob + '\' -type d'
|
||||
dir = dir.replaceAll("\n", "").trim()
|
||||
echo "matching '" + fileNameWithGlob + "' found: '" + dir + "'"
|
||||
if (dir == "")
|
||||
return false
|
||||
return fileExists(dir)
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Pipeline start
|
||||
pipeline {
|
||||
agent {
|
||||
label pythonExecutor
|
||||
}
|
||||
options {
|
||||
timestamps()
|
||||
ansiColor('xterm')
|
||||
lock(extra: lockResources)
|
||||
}
|
||||
|
||||
stages {
|
||||
stage("Build Init") {
|
||||
steps {
|
||||
// update the build name and description
|
||||
buildName "${params.eNB_MR}"
|
||||
buildDescription "Branch : ${params.eNB_Branch}"
|
||||
}
|
||||
}
|
||||
stage ('Verify Parameters') {
|
||||
steps {
|
||||
script {
|
||||
echo '\u2705 \u001B[32mVerify Parameters\u001B[0m'
|
||||
|
||||
JOB_TIMESTAMP = sh returnStdout: true, script: 'date --utc --rfc-3339=seconds | sed -e "s#+00:00##"'
|
||||
JOB_TIMESTAMP = JOB_TIMESTAMP.trim()
|
||||
|
||||
def allParametersPresent = true
|
||||
|
||||
// It is already to late to check it
|
||||
if (params.pythonExecutor != null) {
|
||||
echo "eNB CI executor node : ${pythonExecutor}"
|
||||
}
|
||||
// If not present picking a default Stage Name
|
||||
if (params.pipelineTestStageName == null) {
|
||||
// picking default
|
||||
testStageName = 'Template Test Stage'
|
||||
}
|
||||
|
||||
if (params.LockResources == null) {
|
||||
echo "no LockResources given"
|
||||
allParametersPresent = false
|
||||
}
|
||||
if (params.eNB_SourceCodePath == null) {
|
||||
echo "no eNB_SourceCodePath given"
|
||||
allParametersPresent = false
|
||||
}
|
||||
// the following 4 parameters should be pushed by the master trigger
|
||||
// if not present, take the job GIT variables (used for developing)
|
||||
if (params.eNB_Repository == null) {
|
||||
eNB_Repository = env.GIT_URL
|
||||
} else {
|
||||
eNB_Repository = params.eNB_Repository
|
||||
}
|
||||
echo "eNB_Repository : ${eNB_Repository}"
|
||||
if (params.eNB_Branch == null) {
|
||||
eNB_Branch = env.GIT_BRANCH
|
||||
} else {
|
||||
eNB_Branch = params.eNB_Branch
|
||||
}
|
||||
echo "eNB_Branch : ${eNB_Branch}"
|
||||
if (params.eNB_CommitID == null) {
|
||||
eNB_CommitID = env.GIT_COMMIT
|
||||
} else {
|
||||
eNB_CommitID = params.eNB_CommitID
|
||||
}
|
||||
echo "eNB_CommitID : ${eNB_CommitID}"
|
||||
if (params.eNB_mergeRequest != null) {
|
||||
eNB_AllowMergeRequestProcess = params.eNB_mergeRequest
|
||||
if (eNB_AllowMergeRequestProcess) {
|
||||
if (params.eNB_TargetBranch != null) {
|
||||
eNB_TargetBranch = params.eNB_TargetBranch
|
||||
} else {
|
||||
eNB_TargetBranch = 'develop'
|
||||
}
|
||||
echo "eNB_TargetBranch : ${eNB_TargetBranch}"
|
||||
}
|
||||
} else {
|
||||
echo "no eNB_mergeRequest given - not merging develop"
|
||||
}
|
||||
|
||||
if (params.OC_Credentials == null) {
|
||||
echo "no OC_Credentials given"
|
||||
allParametersPresent = false
|
||||
}
|
||||
if (params.OC_ProjectName == null) {
|
||||
echo "no OC_ProjectName given"
|
||||
allParametersPresent = false
|
||||
}
|
||||
if (params.pythonTestXmlFile == null) {
|
||||
echo "no pythonTestXmlFile given"
|
||||
allParametersPresent = false
|
||||
}
|
||||
if (allParametersPresent) {
|
||||
echo "All parameters are present"
|
||||
if (eNB_AllowMergeRequestProcess) {
|
||||
sh "git fetch"
|
||||
sh "./ci-scripts/doGitLabMerge.sh --src-branch ${eNB_Branch} --src-commit ${eNB_CommitID} --target-branch ${eNB_TargetBranch} --target-commit latest"
|
||||
} else {
|
||||
sh "git fetch"
|
||||
sh "git checkout -f ${eNB_CommitID}"
|
||||
}
|
||||
} else {
|
||||
echo "Some parameters are missing"
|
||||
sh "./ci-scripts/fail.sh"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage ("Deploy and Test") {
|
||||
steps {
|
||||
script {
|
||||
dir ('ci-scripts') {
|
||||
echo "\u2705 \u001B[32m${testStageName}\u001B[0m"
|
||||
String[] myXmlTestSuite = testXMLFile.split("\\r?\\n")
|
||||
for (xmlFile in myXmlTestSuite) {
|
||||
if (fileExists(xmlFile)) {
|
||||
mainPythonAllXmlFiles += "--XMLTestFile=" + xmlFile + " "
|
||||
echo "Test XML file : ${xmlFile}"
|
||||
} else {
|
||||
echo "Test XML file ${xmlFile}: no such file"
|
||||
}
|
||||
}
|
||||
withCredentials([
|
||||
[$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.OC_Credentials}", usernameVariable: 'OC_Username', passwordVariable: 'OC_Password']
|
||||
]) {
|
||||
sh "python3 main.py --mode=InitiateHtml --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} ${mainPythonAllXmlFiles}"
|
||||
for (xmlFile in myXmlTestSuite) {
|
||||
if (fileExists(xmlFile)) {
|
||||
try {
|
||||
timeout (time: 60, unit: 'MINUTES') {
|
||||
sh "python3 main.py --mode=TesteNB --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} --eNBSourceCodePath=${params.eNB_SourceCodePath} --XMLTestFile=${xmlFile} --OCUserName=${OC_Username} --OCPassword=${OC_Password} --OCProjectName=${OC_ProjectName}"
|
||||
}
|
||||
} catch (Exception e) {
|
||||
currentBuild.result = 'FAILURE'
|
||||
buildStageStatus = false
|
||||
}
|
||||
}
|
||||
}
|
||||
sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage ("Log Collection") {
|
||||
steps {
|
||||
script {
|
||||
dir ('ci-scripts') {
|
||||
if (directoryExistsGlob("build_log_*")) {
|
||||
sh "zip -r -qq build_log_${env.BUILD_ID}.zip build_log_*/*"
|
||||
sh "rm -rf build_log_*/"
|
||||
archiveArtifacts artifacts: "build_log_${env.BUILD_ID}.zip"
|
||||
}
|
||||
if (directoryExistsGlob("test_log_*")) {
|
||||
sh "zip -r -qq test_log_${env.BUILD_ID}.zip test_log_*/*"
|
||||
sh "rm -rf test_log_*/"
|
||||
archiveArtifacts artifacts: "test_log_${env.BUILD_ID}.zip"
|
||||
}
|
||||
if (fileExists("test_results.html")) {
|
||||
sh "mv test_results.html test_results-${env.JOB_NAME}.html"
|
||||
sh "sed -i -e 's#TEMPLATE_JOB_NAME#${JOB_NAME}#' -e 's@build #TEMPLATE_BUILD_ID@build #${BUILD_ID}@' -e 's#Build-ID: TEMPLATE_BUILD_ID#Build-ID: <a href=\"${BUILD_URL}\">${BUILD_ID}</a>#' -e 's#TEMPLATE_STAGE_NAME#${testStageName}#' test_results-${JOB_NAME}.html"
|
||||
archiveArtifacts artifacts: "test_results-${env.JOB_NAME}.html"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
223
ci-scripts/Jenkinsfile-nrue
Normal file
223
ci-scripts/Jenkinsfile-nrue
Normal file
@@ -0,0 +1,223 @@
|
||||
#!/bin/groovy
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
// Location of the executor node
|
||||
def pythonExecutor = params.pythonExecutor
|
||||
|
||||
// Location of the test XML file to be run
|
||||
def testXMLFile = params.pythonTestXmlFile
|
||||
def mainPythonAllXmlFiles = ""
|
||||
def buildStageStatus = true
|
||||
|
||||
// Name of the test stage
|
||||
def testStageName = params.pipelineTestStageName
|
||||
|
||||
// Name of the resource
|
||||
def lockResources = []
|
||||
if (params.LockResources != null && params.LockResources.trim().length() > 0)
|
||||
params.LockResources.trim().split(",").each{lockResources += [resource: it.trim()]}
|
||||
|
||||
// Global Parameters. Normally they should be populated when the master job
|
||||
// triggers the slave job with parameters
|
||||
def eNB_Repository
|
||||
def eNB_Branch
|
||||
def eNB_CommitID
|
||||
def eNB_AllowMergeRequestProcess = false
|
||||
def eNB_TargetBranch
|
||||
|
||||
// Flags
|
||||
def scmEvent = false
|
||||
def upstreamEvent = false
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Pipeline start
|
||||
pipeline {
|
||||
agent {
|
||||
label pythonExecutor
|
||||
}
|
||||
options {
|
||||
timestamps()
|
||||
ansiColor('xterm')
|
||||
lock(extra: lockResources)
|
||||
}
|
||||
|
||||
stages {
|
||||
stage("Build Init") {
|
||||
steps {
|
||||
// update the build name and description
|
||||
buildName "${params.eNB_MR}"
|
||||
buildDescription "Branch : ${params.eNB_Branch}"
|
||||
}
|
||||
}
|
||||
stage ('Verify Parameters') {
|
||||
steps {
|
||||
script {
|
||||
echo '\u2705 \u001B[32mVerify Parameters\u001B[0m'
|
||||
|
||||
JOB_TIMESTAMP = sh returnStdout: true, script: 'date --utc --rfc-3339=seconds | sed -e "s#+00:00##"'
|
||||
JOB_TIMESTAMP = JOB_TIMESTAMP.trim()
|
||||
|
||||
def allParametersPresent = true
|
||||
|
||||
// It is already to late to check it
|
||||
if (params.pythonExecutor != null) {
|
||||
echo "eNB CI executor node : ${pythonExecutor}"
|
||||
}
|
||||
// If not present picking a default Stage Name
|
||||
if (params.pipelineTestStageName == null) {
|
||||
// picking default
|
||||
testStageName = 'Template Test Stage'
|
||||
}
|
||||
if (params.LockResources == null) {
|
||||
echo "no LockResources given"
|
||||
allParametersPresent = false
|
||||
}
|
||||
if (params.eNB_SourceCodePath == null) {
|
||||
allParametersPresent = false
|
||||
}
|
||||
// the following 4 parameters should be pushed by the master trigger
|
||||
// if not present, take the job GIT variables (used for developing)
|
||||
if (params.eNB_Repository == null) {
|
||||
eNB_Repository = env.GIT_URL
|
||||
} else {
|
||||
eNB_Repository = params.eNB_Repository
|
||||
}
|
||||
echo "eNB_Repository : ${eNB_Repository}"
|
||||
if (params.eNB_Branch == null) {
|
||||
eNB_Branch = env.GIT_BRANCH
|
||||
} else {
|
||||
eNB_Branch = params.eNB_Branch
|
||||
}
|
||||
echo "eNB_Branch : ${eNB_Branch}"
|
||||
if (params.eNB_CommitID == null) {
|
||||
eNB_CommitID = env.GIT_COMMIT
|
||||
} else {
|
||||
eNB_CommitID = params.eNB_CommitID
|
||||
}
|
||||
echo "eNB_CommitID : ${eNB_CommitID}"
|
||||
if (params.eNB_mergeRequest != null) {
|
||||
eNB_AllowMergeRequestProcess = params.eNB_mergeRequest
|
||||
if (eNB_AllowMergeRequestProcess) {
|
||||
if (params.eNB_TargetBranch != null) {
|
||||
eNB_TargetBranch = params.eNB_TargetBranch
|
||||
} else {
|
||||
eNB_TargetBranch = 'develop'
|
||||
}
|
||||
echo "eNB_TargetBranch : ${eNB_TargetBranch}"
|
||||
}
|
||||
}
|
||||
|
||||
if (params.OC_Credentials == null) {
|
||||
allParametersPresent = false
|
||||
}
|
||||
if (params.OC_ProjectName == null) {
|
||||
allParametersPresent = false
|
||||
}
|
||||
if (allParametersPresent) {
|
||||
echo "All parameters are present"
|
||||
if (eNB_AllowMergeRequestProcess) {
|
||||
sh "git fetch"
|
||||
sh "./ci-scripts/doGitLabMerge.sh --src-branch ${eNB_Branch} --src-commit ${eNB_CommitID} --target-branch ${eNB_TargetBranch} --target-commit latest"
|
||||
} else {
|
||||
sh "git fetch"
|
||||
sh "git checkout -f ${eNB_CommitID}"
|
||||
}
|
||||
} else {
|
||||
echo "Some parameters are missing"
|
||||
sh "./ci-scripts/fail.sh"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage ("Deploy and Test") {
|
||||
steps {
|
||||
script {
|
||||
dir ('ci-scripts') {
|
||||
echo "\u2705 \u001B[32m${testStageName}\u001B[0m"
|
||||
// If not present picking a default XML file
|
||||
if (params.pythonTestXmlFile == null) {
|
||||
// picking default
|
||||
testXMLFile = 'xml_files/enb_usrpB210_band7_50PRB.xml'
|
||||
echo "Test XML file(default): ${testXMLFile}"
|
||||
mainPythonAllXmlFiles += "--XMLTestFile=" + testXMLFile + " "
|
||||
} else {
|
||||
String[] myXmlTestSuite = testXMLFile.split("\\r?\\n")
|
||||
for (xmlFile in myXmlTestSuite) {
|
||||
if (fileExists(xmlFile)) {
|
||||
mainPythonAllXmlFiles += "--XMLTestFile=" + xmlFile + " "
|
||||
echo "Test XML file : ${xmlFile}"
|
||||
} else {
|
||||
echo "Test XML file ${xmlFile}: no such file"
|
||||
}
|
||||
}
|
||||
}
|
||||
withCredentials([
|
||||
[$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.OC_Credentials}", usernameVariable: 'OC_Username', passwordVariable: 'OC_Password']
|
||||
]) {
|
||||
sh "python3 main.py --mode=InitiateHtml --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} ${mainPythonAllXmlFiles}"
|
||||
String[] myXmlTestSuite = testXMLFile.split("\\r?\\n")
|
||||
for (xmlFile in myXmlTestSuite) {
|
||||
if (fileExists(xmlFile)) {
|
||||
try {
|
||||
timeout (time: 60, unit: 'MINUTES') {
|
||||
sh "python3 main.py --mode=TesteNB --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} --eNBSourceCodePath=${params.eNB_SourceCodePath} --XMLTestFile=${xmlFile} --OCUserName=${OC_Username} --OCPassword=${OC_Password} --OCProjectName=${OC_ProjectName}"
|
||||
}
|
||||
} catch (Exception e) {
|
||||
currentBuild.result = 'FAILURE'
|
||||
buildStageStatus = false
|
||||
}
|
||||
}
|
||||
}
|
||||
sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage ("Log Collection") {
|
||||
steps {
|
||||
script {
|
||||
dir ('ci-scripts') {
|
||||
// Zipping all archived log files
|
||||
sh "mkdir test_logs"
|
||||
sh "mv *.log* test_logs || true"
|
||||
// Zip all log files matching cmake_targets/{*.log*,log/*} into test_logs_XXXX.zip
|
||||
if (fileExists('../cmake_targets/log')) {
|
||||
sh "mv ../cmake_targets/log/* test_logs || true"
|
||||
}
|
||||
sh "zip -r -qq test_logs_${env.BUILD_ID}.zip *test_log*/"
|
||||
sh "rm -rf *test_log*/"
|
||||
if (fileExists("test_logs_${env.BUILD_ID}.zip")) {
|
||||
archiveArtifacts artifacts: "test_logs_${env.BUILD_ID}.zip"
|
||||
}
|
||||
if (fileExists("test_results.html")) {
|
||||
sh "mv test_results.html test_results-${env.JOB_NAME}.html"
|
||||
sh "sed -i -e 's#TEMPLATE_JOB_NAME#${JOB_NAME}#' -e 's@build #TEMPLATE_BUILD_ID@build #${BUILD_ID}@' -e 's#Build-ID: TEMPLATE_BUILD_ID#Build-ID: <a href=\"${BUILD_URL}\">${BUILD_ID}</a>#' -e 's#TEMPLATE_STAGE_NAME#${testStageName}#' test_results-${JOB_NAME}.html"
|
||||
archiveArtifacts artifacts: "test_results-${env.JOB_NAME}.html"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
224
ci-scripts/Jenkinsfile-physim-deploy
Normal file
224
ci-scripts/Jenkinsfile-physim-deploy
Normal file
@@ -0,0 +1,224 @@
|
||||
#!/bin/groovy
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
// Location of the executor node
|
||||
def pythonExecutor = params.pythonExecutor
|
||||
|
||||
// Location of the test XML file to be run
|
||||
def testXMLFile = params.pythonTestXmlFile
|
||||
def mainPythonAllXmlFiles = ""
|
||||
def buildStageStatus = true
|
||||
|
||||
// Name of the test stage
|
||||
def testStageName = params.pipelineTestStageName
|
||||
|
||||
// Name of the resource
|
||||
def lockResources = []
|
||||
if (params.LockResources != null && params.LockResources.trim().length() > 0)
|
||||
params.LockResources.trim().split(",").each{lockResources += [resource: it.trim()]}
|
||||
|
||||
// Global Parameters. Normally they should be populated when the master job
|
||||
// triggers the slave job with parameters
|
||||
def eNB_Repository
|
||||
def eNB_Branch
|
||||
def eNB_CommitID
|
||||
def eNB_AllowMergeRequestProcess = false
|
||||
def eNB_TargetBranch
|
||||
|
||||
// Flags
|
||||
def scmEvent = false
|
||||
def upstreamEvent = false
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Pipeline start
|
||||
pipeline {
|
||||
agent {
|
||||
label pythonExecutor
|
||||
}
|
||||
options {
|
||||
timestamps()
|
||||
ansiColor('xterm')
|
||||
lock(extra: lockResources)
|
||||
}
|
||||
|
||||
stages {
|
||||
stage("Build Init") {
|
||||
steps {
|
||||
// update the build name and description
|
||||
buildName "${params.eNB_MR}"
|
||||
buildDescription "Branch : ${params.eNB_Branch}"
|
||||
}
|
||||
}
|
||||
stage ('Verify Parameters') {
|
||||
steps {
|
||||
script {
|
||||
echo '\u2705 \u001B[32mVerify Parameters\u001B[0m'
|
||||
|
||||
JOB_TIMESTAMP = sh returnStdout: true, script: 'date --utc --rfc-3339=seconds | sed -e "s#+00:00##"'
|
||||
JOB_TIMESTAMP = JOB_TIMESTAMP.trim()
|
||||
|
||||
def allParametersPresent = true
|
||||
|
||||
// It is already to late to check it
|
||||
if (params.pythonExecutor != null) {
|
||||
echo "eNB CI executor node : ${pythonExecutor}"
|
||||
}
|
||||
// If not present picking a default Stage Name
|
||||
if (params.pipelineTestStageName == null) {
|
||||
// picking default
|
||||
testStageName = 'Template Test Stage'
|
||||
}
|
||||
|
||||
if (params.LockResources == null) {
|
||||
echo "no LockResources given"
|
||||
allParametersPresent = false
|
||||
}
|
||||
if (params.eNB_SourceCodePath == null) {
|
||||
allParametersPresent = false
|
||||
}
|
||||
// the following 4 parameters should be pushed by the master trigger
|
||||
// if not present, take the job GIT variables (used for developing)
|
||||
if (params.eNB_Repository == null) {
|
||||
eNB_Repository = env.GIT_URL
|
||||
} else {
|
||||
eNB_Repository = params.eNB_Repository
|
||||
}
|
||||
echo "eNB_Repository : ${eNB_Repository}"
|
||||
if (params.eNB_Branch == null) {
|
||||
eNB_Branch = env.GIT_BRANCH
|
||||
} else {
|
||||
eNB_Branch = params.eNB_Branch
|
||||
}
|
||||
echo "eNB_Branch : ${eNB_Branch}"
|
||||
if (params.eNB_CommitID == null) {
|
||||
eNB_CommitID = env.GIT_COMMIT
|
||||
} else {
|
||||
eNB_CommitID = params.eNB_CommitID
|
||||
}
|
||||
echo "eNB_CommitID : ${eNB_CommitID}"
|
||||
if (params.eNB_mergeRequest != null) {
|
||||
eNB_AllowMergeRequestProcess = params.eNB_mergeRequest
|
||||
if (eNB_AllowMergeRequestProcess) {
|
||||
if (params.eNB_TargetBranch != null) {
|
||||
eNB_TargetBranch = params.eNB_TargetBranch
|
||||
} else {
|
||||
eNB_TargetBranch = 'develop'
|
||||
}
|
||||
echo "eNB_TargetBranch : ${eNB_TargetBranch}"
|
||||
}
|
||||
}
|
||||
|
||||
if (params.OC_Credentials == null) {
|
||||
allParametersPresent = false
|
||||
}
|
||||
if (params.OC_ProjectName == null) {
|
||||
allParametersPresent = false
|
||||
}
|
||||
if (allParametersPresent) {
|
||||
echo "All parameters are present"
|
||||
if (eNB_AllowMergeRequestProcess) {
|
||||
sh "git fetch"
|
||||
sh "./ci-scripts/doGitLabMerge.sh --src-branch ${eNB_Branch} --src-commit ${eNB_CommitID} --target-branch ${eNB_TargetBranch} --target-commit latest"
|
||||
} else {
|
||||
sh "git fetch"
|
||||
sh "git checkout -f ${eNB_CommitID}"
|
||||
}
|
||||
} else {
|
||||
echo "Some parameters are missing"
|
||||
sh "./ci-scripts/fail.sh"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage ("Deploy and Test") {
|
||||
steps {
|
||||
script {
|
||||
dir ('ci-scripts') {
|
||||
echo "\u2705 \u001B[32m${testStageName}\u001B[0m"
|
||||
// If not present picking a default XML file
|
||||
if (params.pythonTestXmlFile == null) {
|
||||
// picking default
|
||||
testXMLFile = 'xml_files/enb_usrpB210_band7_50PRB.xml'
|
||||
echo "Test XML file(default): ${testXMLFile}"
|
||||
mainPythonAllXmlFiles += "--XMLTestFile=" + testXMLFile + " "
|
||||
} else {
|
||||
String[] myXmlTestSuite = testXMLFile.split("\\r?\\n")
|
||||
for (xmlFile in myXmlTestSuite) {
|
||||
if (fileExists(xmlFile)) {
|
||||
mainPythonAllXmlFiles += "--XMLTestFile=" + xmlFile + " "
|
||||
echo "Test XML file : ${xmlFile}"
|
||||
} else {
|
||||
echo "Test XML file ${xmlFile}: no such file"
|
||||
}
|
||||
}
|
||||
}
|
||||
withCredentials([
|
||||
[$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.OC_Credentials}", usernameVariable: 'OC_Username', passwordVariable: 'OC_Password']
|
||||
]) {
|
||||
sh "python3 main.py --mode=InitiateHtml --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} ${mainPythonAllXmlFiles}"
|
||||
String[] myXmlTestSuite = testXMLFile.split("\\r?\\n")
|
||||
for (xmlFile in myXmlTestSuite) {
|
||||
if (fileExists(xmlFile)) {
|
||||
try {
|
||||
timeout (time: 60, unit: 'MINUTES') {
|
||||
sh "python3 main.py --mode=TesteNB --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} --eNBSourceCodePath=${params.eNB_SourceCodePath} --XMLTestFile=${xmlFile} --OCUserName=${OC_Username} --OCPassword=${OC_Password} --OCProjectName=${OC_ProjectName}"
|
||||
}
|
||||
} catch (Exception e) {
|
||||
currentBuild.result = 'FAILURE'
|
||||
buildStageStatus = false
|
||||
}
|
||||
}
|
||||
}
|
||||
sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage ("Log Collection") {
|
||||
steps {
|
||||
script {
|
||||
dir ('ci-scripts') {
|
||||
// Zipping all archived log files
|
||||
sh "mkdir test_logs"
|
||||
sh "mv *.log* test_logs || true"
|
||||
// Zip all log files matching cmake_targets/{*.log*,log/*} into test_logs_XXXX.zip
|
||||
if (fileExists('../cmake_targets/log')) {
|
||||
sh "mv ../cmake_targets/log/* test_logs || true"
|
||||
}
|
||||
sh "zip -r -qq test_logs_${env.BUILD_ID}.zip *test_log*/"
|
||||
sh "rm -rf *test_log*/"
|
||||
if (fileExists("test_logs_${env.BUILD_ID}.zip")) {
|
||||
archiveArtifacts artifacts: "test_logs_${env.BUILD_ID}.zip"
|
||||
}
|
||||
if (fileExists("test_results.html")) {
|
||||
sh "mv test_results.html test_results-${env.JOB_NAME}.html"
|
||||
sh "sed -i -e 's#TEMPLATE_JOB_NAME#${JOB_NAME}#' -e 's@build #TEMPLATE_BUILD_ID@build #${BUILD_ID}@' -e 's#Build-ID: TEMPLATE_BUILD_ID#Build-ID: <a href=\"${BUILD_URL}\">${BUILD_ID}</a>#' -e 's#TEMPLATE_STAGE_NAME#${testStageName}#' test_results-${JOB_NAME}.html"
|
||||
archiveArtifacts artifacts: "test_results-${env.JOB_NAME}.html"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
250
ci-scripts/Jenkinsfile-tmp-full-ran
Normal file
250
ci-scripts/Jenkinsfile-tmp-full-ran
Normal file
@@ -0,0 +1,250 @@
|
||||
#!/bin/groovy
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
// Template Jenkins Declarative Pipeline script to run Test w/ RF HW
|
||||
|
||||
// Location of the python executor node shall be in the same subnet as the others servers
|
||||
def pythonExecutor = params.pythonExecutor
|
||||
|
||||
// Location of the test XML file to be run
|
||||
def testXMLFile = params.pythonTestXmlFile
|
||||
def mainPythonAllXmlFiles = ""
|
||||
def buildStageStatus = true
|
||||
|
||||
// Name of the test stage
|
||||
def testStageName = params.pipelineTestStageName
|
||||
|
||||
def lockResources = []
|
||||
if (params.LockResources != null && params.LockResources.trim().length() > 0)
|
||||
params.LockResources.trim().split(",").each{lockResources += [resource: it.trim()]}
|
||||
|
||||
// Terminate Status
|
||||
def termENB = 0
|
||||
def termStatusArray = new Boolean[termENB + 1]
|
||||
termStatusArray[termENB] = false
|
||||
|
||||
// Global Parameters. Normally they should be populated when the master job
|
||||
// triggers the slave job with parameters
|
||||
def eNB_Repository
|
||||
def eNB_Branch
|
||||
def eNB_CommitID
|
||||
def eNB_AllowMergeRequestProcess = false
|
||||
def eNB_TargetBranch
|
||||
|
||||
def doEpcLogCollection = true
|
||||
|
||||
|
||||
|
||||
pipeline {
|
||||
agent {
|
||||
label pythonExecutor
|
||||
}
|
||||
options {
|
||||
ansiColor('xterm')
|
||||
lock(extra: lockResources)
|
||||
}
|
||||
|
||||
stages {
|
||||
stage("Build Init") {
|
||||
steps {
|
||||
// update the build name and description
|
||||
buildName "${params.eNB_MR}"
|
||||
buildDescription "Branch : ${params.eNB_Branch}"
|
||||
}
|
||||
}
|
||||
stage ("Verify Parameters") {
|
||||
steps {
|
||||
script {
|
||||
echo '\u2705 \u001B[32mVerify Parameters\u001B[0m'
|
||||
def allParametersPresent = true
|
||||
|
||||
// It is already to late to check it
|
||||
if (params.pythonExecutor != null) {
|
||||
echo "eNB CI executor node : ${pythonExecutor}"
|
||||
}
|
||||
// If not present picking a default Stage Name
|
||||
if (params.pipelineTestStageName == null) {
|
||||
// picking default
|
||||
testStageName = 'Template Test Stage'
|
||||
}
|
||||
|
||||
if (params.LockResources == null) {
|
||||
echo "no LockResources given"
|
||||
allParametersPresent = false
|
||||
}
|
||||
if (params.eNB_SourceCodePath == null) {
|
||||
allParametersPresent = false
|
||||
}
|
||||
// the following 4 parameters should be pushed by the master trigger
|
||||
// if not present, take the job GIT variables (used for developing)
|
||||
if (params.eNB_Repository == null) {
|
||||
eNB_Repository = env.GIT_URL
|
||||
} else {
|
||||
eNB_Repository = params.eNB_Repository
|
||||
}
|
||||
echo "eNB_Repository : ${eNB_Repository}"
|
||||
if (params.eNB_Branch == null) {
|
||||
eNB_Branch = env.GIT_BRANCH
|
||||
} else {
|
||||
eNB_Branch = params.eNB_Branch
|
||||
}
|
||||
echo "eNB_Branch : ${eNB_Branch}"
|
||||
if (params.eNB_CommitID == null) {
|
||||
eNB_CommitID = env.GIT_COMMIT
|
||||
} else {
|
||||
eNB_CommitID = params.eNB_CommitID
|
||||
}
|
||||
echo "eNB_CommitID : ${eNB_CommitID}"
|
||||
if (params.eNB_mergeRequest != null) {
|
||||
eNB_AllowMergeRequestProcess = params.eNB_mergeRequest
|
||||
if (eNB_AllowMergeRequestProcess) {
|
||||
if (params.eNB_TargetBranch != null) {
|
||||
eNB_TargetBranch = params.eNB_TargetBranch
|
||||
} else {
|
||||
eNB_TargetBranch = 'develop'
|
||||
}
|
||||
echo "eNB_TargetBranch : ${eNB_TargetBranch}"
|
||||
}
|
||||
}
|
||||
|
||||
if (allParametersPresent) {
|
||||
echo "All parameters are present"
|
||||
if (eNB_AllowMergeRequestProcess) {
|
||||
sh "git fetch"
|
||||
sh "./ci-scripts/doGitLabMerge.sh --src-branch ${eNB_Branch} --src-commit ${eNB_CommitID} --target-branch ${eNB_TargetBranch} --target-commit latest"
|
||||
} else {
|
||||
sh "git fetch"
|
||||
sh "git checkout -f ${eNB_CommitID}"
|
||||
}
|
||||
} else {
|
||||
currentBuild.result = 'ABORTED'
|
||||
error('Stopping early because some parameters are missing')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage ("Build and Test") {
|
||||
steps {
|
||||
script {
|
||||
dir ('ci-scripts') {
|
||||
echo "\u2705 \u001B[32m${testStageName}\u001B[0m"
|
||||
// If not present picking a default XML file
|
||||
if (params.pythonTestXmlFile == null) {
|
||||
// picking default
|
||||
testXMLFile = 'xml_files/enb_usrpB210_band7_50PRB.xml'
|
||||
echo "Test XML file(default): ${testXMLFile}"
|
||||
mainPythonAllXmlFiles += "--XMLTestFile=" + testXMLFile + " "
|
||||
} else {
|
||||
String[] myXmlTestSuite = testXMLFile.split("\\r?\\n")
|
||||
for (xmlFile in myXmlTestSuite) {
|
||||
if (fileExists(xmlFile)) {
|
||||
mainPythonAllXmlFiles += "--XMLTestFile=" + xmlFile + " "
|
||||
echo "Test XML file : ${xmlFile}"
|
||||
} else {
|
||||
echo "Test XML file ${xmlFile}: no such file"
|
||||
}
|
||||
}
|
||||
}
|
||||
sh "python3 main.py --mode=InitiateHtml --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} ${mainPythonAllXmlFiles}"
|
||||
String[] myXmlTestSuite = testXMLFile.split("\\r?\\n")
|
||||
for (xmlFile in myXmlTestSuite) {
|
||||
if (fileExists(xmlFile)) {
|
||||
try {
|
||||
timeout (time: 60, unit: 'MINUTES') {
|
||||
sh "python3 main.py --mode=TesteNB --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} --eNBSourceCodePath=${params.eNB_SourceCodePath} --XMLTestFile=${xmlFile}"
|
||||
}
|
||||
} catch (Exception e) {
|
||||
currentBuild.result = 'FAILURE'
|
||||
buildStageStatus = false
|
||||
}
|
||||
}
|
||||
}
|
||||
sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage ("Terminate") {
|
||||
parallel {
|
||||
stage('Terminate eNB') {
|
||||
steps {
|
||||
echo '\u2705 \u001B[32mTerminate eNB\u001B[0m'
|
||||
sh "python3 ci-scripts/main.py --mode=TerminateeNB"
|
||||
}
|
||||
post {
|
||||
success {
|
||||
script {
|
||||
termStatusArray[termENB] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Log Collection') {
|
||||
parallel {
|
||||
stage('Log Collection (eNB - Run)') {
|
||||
steps {
|
||||
echo '\u2705 \u001B[32mLog Collection (eNB - Run)\u001B[0m'
|
||||
sh "python3 ci-scripts/main.py --mode=LogCollecteNB --eNBSourceCodePath=${params.eNB_SourceCodePath} --BuildId=${env.BUILD_ID}"
|
||||
|
||||
script {
|
||||
if(fileExists("enb.log.${env.BUILD_ID}.zip")) {
|
||||
archiveArtifacts "enb.log.${env.BUILD_ID}.zip"
|
||||
}
|
||||
if(fileExists("ci-scripts/test_results.html")) {
|
||||
sh "mv ci-scripts/test_results.html test_results-${JOB_NAME}.html"
|
||||
sh "sed -i -e 's#TEMPLATE_JOB_NAME#${JOB_NAME}#' -e 's@build #TEMPLATE_BUILD_ID@build #${BUILD_ID}@' -e 's#Build-ID: TEMPLATE_BUILD_ID#Build-ID: <a href=\"${BUILD_URL}\">${BUILD_ID}</a>#' -e 's#TEMPLATE_STAGE_NAME#${testStageName}#' test_results-${JOB_NAME}.html"
|
||||
archiveArtifacts "test_results-${JOB_NAME}.html"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
always {
|
||||
script {
|
||||
if (params.pipelineZipsConsoleLog != null) {
|
||||
if (params.pipelineZipsConsoleLog) {
|
||||
echo "Archiving Jenkins console log"
|
||||
sh "wget --no-check-certificate --no-proxy ${env.JENKINS_URL}/job/${env.JOB_NAME}/${env.BUILD_ID}/consoleText -O consoleText.log || true"
|
||||
sh "zip -m consoleText.log.${env.BUILD_ID}.zip consoleText.log || true"
|
||||
if(fileExists("consoleText.log.${env.BUILD_ID}.zip")) {
|
||||
archiveArtifacts "consoleText.log.${env.BUILD_ID}.zip"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Making sure that we really shutdown every thing before leaving
|
||||
failure {
|
||||
script {
|
||||
if (!termStatusArray[termENB]) {
|
||||
sh "python3 ci-scripts/main.py --mode=TerminateeNB"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
225
ci-scripts/Jenkinsfile-tmp-multi-enb
Normal file
225
ci-scripts/Jenkinsfile-tmp-multi-enb
Normal file
@@ -0,0 +1,225 @@
|
||||
#!/bin/groovy
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
// Template Jenkins Declarative Pipeline script to run Test w/ RF HW
|
||||
|
||||
// Location of the python executor node shall be in the same subnet as the others servers
|
||||
def pythonExecutor = params.pythonExecutor
|
||||
|
||||
// Location of the test XML file to be run
|
||||
def testXMLFile = params.pythonTestXmlFile
|
||||
def mainPythonAllXmlFiles = ""
|
||||
def buildStageStatus = true
|
||||
|
||||
// Name of the test stage
|
||||
def testStageName = params.pipelineTestStageName
|
||||
|
||||
def lockResources = []
|
||||
if (params.LockResources != null && params.LockResources.trim().length() > 0)
|
||||
params.LockResources.trim().split(",").each{lockResources += [resource: it.trim()]}
|
||||
|
||||
// Global Parameters. Normally they should be populated when the master job
|
||||
// triggers the slave job with parameters
|
||||
def eNB_Repository
|
||||
def eNB_Branch
|
||||
def eNB_CommitID
|
||||
def eNB_AllowMergeRequestProcess = false
|
||||
def eNB_TargetBranch
|
||||
|
||||
pipeline {
|
||||
agent {
|
||||
label pythonExecutor
|
||||
}
|
||||
options {
|
||||
ansiColor('xterm')
|
||||
lock(extra: lockResources)
|
||||
}
|
||||
stages {
|
||||
stage("Build Init") {
|
||||
steps {
|
||||
// update the build name and description
|
||||
buildName "${params.eNB_MR}"
|
||||
buildDescription "Branch : ${params.eNB_Branch}"
|
||||
}
|
||||
}
|
||||
stage ("Verify Parameters") {
|
||||
steps {
|
||||
script {
|
||||
echo '\u2705 \u001B[32mVerify Parameters\u001B[0m'
|
||||
def allParametersPresent = true
|
||||
|
||||
// It is already to late to check it
|
||||
if (params.pythonExecutor != null) {
|
||||
echo "eNB CI executor node : ${pythonExecutor}"
|
||||
}
|
||||
// If not present picking a default Stage Name
|
||||
if (params.pipelineTestStageName == null) {
|
||||
// picking default
|
||||
testStageName = 'Template Test Stage'
|
||||
}
|
||||
|
||||
if (params.LockResources == null) {
|
||||
echo "no LockResources given"
|
||||
allParametersPresent = false
|
||||
}
|
||||
if (params.eNB_SourceCodePath == null) {
|
||||
allParametersPresent = false
|
||||
}
|
||||
// the following 4 parameters should be pushed by the master trigger
|
||||
// if not present, take the job GIT variables (used for developing)
|
||||
if (params.eNB_Repository == null) {
|
||||
eNB_Repository = env.GIT_URL
|
||||
} else {
|
||||
eNB_Repository = params.eNB_Repository
|
||||
}
|
||||
echo "eNB_Repository : ${eNB_Repository}"
|
||||
if (params.eNB_Branch == null) {
|
||||
eNB_Branch = env.GIT_BRANCH
|
||||
} else {
|
||||
eNB_Branch = params.eNB_Branch
|
||||
}
|
||||
echo "eNB_Branch : ${eNB_Branch}"
|
||||
if (params.eNB_CommitID == null) {
|
||||
eNB_CommitID = env.GIT_COMMIT
|
||||
} else {
|
||||
eNB_CommitID = params.eNB_CommitID
|
||||
}
|
||||
echo "eNB_CommitID : ${eNB_CommitID}"
|
||||
if (params.eNB_mergeRequest != null) {
|
||||
eNB_AllowMergeRequestProcess = params.eNB_mergeRequest
|
||||
if (eNB_AllowMergeRequestProcess) {
|
||||
if (params.eNB_TargetBranch != null) {
|
||||
eNB_TargetBranch = params.eNB_TargetBranch
|
||||
} else {
|
||||
eNB_TargetBranch = 'develop'
|
||||
}
|
||||
echo "eNB_TargetBranch : ${eNB_TargetBranch}"
|
||||
}
|
||||
}
|
||||
|
||||
if (allParametersPresent) {
|
||||
echo "All parameters are present"
|
||||
if (eNB_AllowMergeRequestProcess) {
|
||||
sh "git fetch"
|
||||
sh "./ci-scripts/doGitLabMerge.sh --src-branch ${eNB_Branch} --src-commit ${eNB_CommitID} --target-branch ${eNB_TargetBranch} --target-commit latest"
|
||||
} else {
|
||||
sh "git fetch"
|
||||
sh "git checkout -f ${eNB_CommitID}"
|
||||
}
|
||||
} else {
|
||||
echo "Some parameters are missing"
|
||||
sh "./ci-scripts/fail.sh"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage ("Build and Test") {
|
||||
steps {
|
||||
script {
|
||||
dir ('ci-scripts') {
|
||||
echo "\u2705 \u001B[32m${testStageName}\u001B[0m"
|
||||
// If not present picking a default XML file
|
||||
if (params.pythonTestXmlFile == null) {
|
||||
// picking default
|
||||
testXMLFile = 'xml_files/enb_usrpB210_band7_50PRB.xml'
|
||||
echo "Test XML file(default): ${testXMLFile}"
|
||||
mainPythonAllXmlFiles += "--XMLTestFile=" + testXMLFile + " "
|
||||
} else {
|
||||
String[] myXmlTestSuite = testXMLFile.split("\\r?\\n")
|
||||
for (xmlFile in myXmlTestSuite) {
|
||||
if (fileExists(xmlFile)) {
|
||||
mainPythonAllXmlFiles += "--XMLTestFile=" + xmlFile + " "
|
||||
echo "Test XML file : ${xmlFile}"
|
||||
} else {
|
||||
echo "Test XML file ${xmlFile}: no such file"
|
||||
}
|
||||
}
|
||||
}
|
||||
sh "python3 main.py --mode=InitiateHtml --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} ${mainPythonAllXmlFiles}"
|
||||
String[] myXmlTestSuite = testXMLFile.split("\\r?\\n")
|
||||
for (xmlFile in myXmlTestSuite) {
|
||||
if (fileExists(xmlFile)) {
|
||||
try {
|
||||
timeout (time: 60, unit: 'MINUTES') {
|
||||
sh "python3 main.py --mode=TesteNB --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} --eNBSourceCodePath=${params.eNB_SourceCodePath} --XMLTestFile=${xmlFile}"
|
||||
}
|
||||
} catch (Exception e) {
|
||||
currentBuild.result = 'FAILURE'
|
||||
buildStageStatus = false
|
||||
}
|
||||
}
|
||||
}
|
||||
sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage ("Terminate") {
|
||||
parallel {
|
||||
stage('Terminate eNB') {
|
||||
steps {
|
||||
echo '\u2705 \u001B[32mTerminate eNB\u001B[0m'
|
||||
sh "python3 ci-scripts/main.py --mode=TerminateeNB"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Log Collection') {
|
||||
parallel {
|
||||
stage('Log Collection (eNB - Run)') {
|
||||
steps {
|
||||
echo '\u2705 \u001B[32mLog Collection (eNB - Run)\u001B[0m'
|
||||
sh "python3 ci-scripts/main.py --mode=LogCollecteNB --eNBSourceCodePath=${params.eNB_SourceCodePath} --BuildId=${env.BUILD_ID}"
|
||||
|
||||
script {
|
||||
if(fileExists("enb.log.${env.BUILD_ID}.zip")) {
|
||||
archiveArtifacts "enb.log.${env.BUILD_ID}.zip"
|
||||
}
|
||||
if(fileExists("ci-scripts/test_results.html")) {
|
||||
sh "mv ci-scripts/test_results.html test_results-${JOB_NAME}.html"
|
||||
sh "sed -i -e 's#TEMPLATE_JOB_NAME#${JOB_NAME}#' -e 's@build #TEMPLATE_BUILD_ID@build #${BUILD_ID}@' -e 's#Build-ID: TEMPLATE_BUILD_ID#Build-ID: <a href=\"${BUILD_URL}\">${BUILD_ID}</a>#' -e 's#TEMPLATE_STAGE_NAME#${testStageName}#' test_results-${JOB_NAME}.html"
|
||||
archiveArtifacts "test_results-${JOB_NAME}.html"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
always {
|
||||
script {
|
||||
if (params.pipelineZipsConsoleLog != null) {
|
||||
if (params.pipelineZipsConsoleLog) {
|
||||
echo "Archiving Jenkins console log"
|
||||
sh "wget --no-check-certificate --no-proxy ${env.JENKINS_URL}/job/${env.JOB_NAME}/${env.BUILD_ID}/consoleText -O consoleText.log || true"
|
||||
sh "zip -m consoleText.log.${env.BUILD_ID}.zip consoleText.log || true"
|
||||
if(fileExists("consoleText.log.${env.BUILD_ID}.zip")) {
|
||||
archiveArtifacts "consoleText.log.${env.BUILD_ID}.zip"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
216
ci-scripts/Jenkinsfile-tmp-multi-enb-nsa
Normal file
216
ci-scripts/Jenkinsfile-tmp-multi-enb-nsa
Normal file
@@ -0,0 +1,216 @@
|
||||
#!/bin/groovy
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
// Template Jenkins Declarative Pipeline script to run Test w/ RF HW
|
||||
|
||||
// Location of the python executor node shall be in the same subnet as the others servers
|
||||
def pythonExecutor = params.pythonExecutor
|
||||
|
||||
// Location of the test XML file to be run
|
||||
def testXMLFile = params.pythonTestXmlFile
|
||||
def mainPythonAllXmlFiles = ""
|
||||
def buildStageStatus = true
|
||||
|
||||
// Name of the test stage
|
||||
def testStageName = params.pipelineTestStageName
|
||||
|
||||
def lockResources = []
|
||||
if (params.LockResources != null && params.LockResources.trim().length() > 0)
|
||||
params.LockResources.trim().split(",").each{lockResources += [resource: it.trim()]}
|
||||
|
||||
// Global Parameters. Normally they should be populated when the master job
|
||||
// triggers the slave job with parameters
|
||||
def eNB_Repository
|
||||
def eNB_Branch
|
||||
def eNB_CommitID
|
||||
def eNB_AllowMergeRequestProcess
|
||||
def eNB_TargetBranch
|
||||
|
||||
//Status fed to the database
|
||||
def StatusForDb = ""
|
||||
|
||||
|
||||
pipeline {
|
||||
agent {label pythonExecutor}
|
||||
options {
|
||||
ansiColor('xterm')
|
||||
lock(extra: lockResources)
|
||||
}
|
||||
stages {
|
||||
stage("Build Init") {
|
||||
steps {
|
||||
// update the build name and description
|
||||
buildName "${params.eNB_MR}"
|
||||
buildDescription "Branch : ${params.eNB_Branch}"
|
||||
}
|
||||
}
|
||||
stage ("Verify Parameters") {
|
||||
steps {
|
||||
script {
|
||||
echo '\u2705 \u001B[32mVerify Parameters\u001B[0m'
|
||||
def allParametersPresent = true
|
||||
|
||||
// It is already to late to check it
|
||||
if (params.pythonExecutor != null) {
|
||||
echo "eNB CI executor node : ${pythonExecutor}"
|
||||
}
|
||||
// If not present picking a default Stage Name
|
||||
if (params.pipelineTestStageName == null) {
|
||||
// picking default
|
||||
testStageName = 'Template Test Stage'
|
||||
}
|
||||
|
||||
if (params.LockResources == null) {
|
||||
echo "no LockResources given"
|
||||
allParametersPresent = false
|
||||
}
|
||||
if (params.eNB_SourceCodePath == null) {
|
||||
allParametersPresent = false
|
||||
}
|
||||
// the following 4 parameters should be pushed by the master trigger
|
||||
// if not present, take the job GIT variables (used for developing)
|
||||
if (params.eNB_Repository == null) {
|
||||
eNB_Repository = env.GIT_URL
|
||||
} else {
|
||||
eNB_Repository = params.eNB_Repository
|
||||
}
|
||||
echo "eNB_Repository : ${eNB_Repository}"
|
||||
if (params.eNB_Branch == null) {
|
||||
eNB_Branch = env.GIT_BRANCH
|
||||
} else {
|
||||
eNB_Branch = params.eNB_Branch
|
||||
}
|
||||
echo "eNB_Branch : ${eNB_Branch}"
|
||||
if (params.eNB_CommitID == null) {
|
||||
eNB_CommitID = env.GIT_COMMIT
|
||||
} else {
|
||||
eNB_CommitID = params.eNB_CommitID
|
||||
}
|
||||
echo "eNB_CommitID : ${eNB_CommitID}"
|
||||
if (params.eNB_mergeRequest!= null) {
|
||||
eNB_AllowMergeRequestProcess = params.eNB_mergeRequest
|
||||
if (eNB_AllowMergeRequestProcess) {
|
||||
if (params.eNB_TargetBranch != null) {
|
||||
eNB_TargetBranch = params.eNB_TargetBranch
|
||||
} else {
|
||||
eNB_TargetBranch = 'develop'
|
||||
}
|
||||
echo "eNB_TargetBranch : ${eNB_TargetBranch}"
|
||||
}
|
||||
}
|
||||
|
||||
if (allParametersPresent) {
|
||||
echo "All parameters are present"
|
||||
if (eNB_AllowMergeRequestProcess) {
|
||||
sh "git fetch"
|
||||
sh "./ci-scripts/doGitLabMerge.sh --src-branch ${eNB_Branch} --src-commit ${eNB_CommitID} --target-branch ${eNB_TargetBranch} --target-commit latest"
|
||||
} else {
|
||||
sh "git fetch"
|
||||
sh "git checkout -f ${eNB_CommitID}"
|
||||
}
|
||||
} else {
|
||||
echo "Some parameters are missing"
|
||||
sh "./ci-scripts/fail.sh"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage ("Build and Test") {
|
||||
steps {
|
||||
script {
|
||||
dir ('ci-scripts') {
|
||||
echo "\u2705 \u001B[32m${testStageName}\u001B[0m"
|
||||
// If not present picking a default XML file
|
||||
if (params.pythonTestXmlFile == null) {
|
||||
// picking default
|
||||
testXMLFile = 'xml_files/enb_usrpB210_band7_50PRB.xml'
|
||||
echo "Test XML file(default): ${testXMLFile}"
|
||||
mainPythonAllXmlFiles += "--XMLTestFile=" + testXMLFile + " "
|
||||
} else {
|
||||
String[] myXmlTestSuite = testXMLFile.split("\\r?\\n")
|
||||
for (xmlFile in myXmlTestSuite) {
|
||||
if (fileExists(xmlFile)) {
|
||||
mainPythonAllXmlFiles += "--XMLTestFile=" + xmlFile + " "
|
||||
echo "Test XML file : ${xmlFile}"
|
||||
} else {
|
||||
echo "Test XML file ${xmlFile}: no such file"
|
||||
}
|
||||
}
|
||||
}
|
||||
sh "python3 main.py --mode=InitiateHtml --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} ${mainPythonAllXmlFiles}"
|
||||
String[] myXmlTestSuite = testXMLFile.split("\\r?\\n")
|
||||
for (xmlFile in myXmlTestSuite) {
|
||||
if (fileExists(xmlFile)) {
|
||||
try {
|
||||
timeout (time: 60, unit: 'MINUTES') {
|
||||
sh "python3 main.py --mode=TesteNB --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} --eNBSourceCodePath=${params.eNB_SourceCodePath} --XMLTestFile=${xmlFile}"
|
||||
}
|
||||
} catch (Exception e) {
|
||||
currentBuild.result = 'FAILURE'
|
||||
buildStageStatus = false
|
||||
}
|
||||
}
|
||||
}
|
||||
sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Log Collection') {
|
||||
parallel {
|
||||
stage('Log Collection (eNB - Run)') {
|
||||
steps {
|
||||
echo '\u2705 \u001B[32mLog Collection (eNB - Run)\u001B[0m'
|
||||
sh "python3 ci-scripts/main.py --mode=LogCollecteNB --eNBSourceCodePath=${params.eNB_SourceCodePath} --BuildId=${env.BUILD_ID}"
|
||||
script {
|
||||
if(fileExists("enb.log.${env.BUILD_ID}.zip")) {
|
||||
archiveArtifacts "enb.log.${env.BUILD_ID}.zip"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
always {
|
||||
script {
|
||||
if(fileExists("ci-scripts/test_results.html")) {
|
||||
sh "mv ci-scripts/test_results.html test_results-${JOB_NAME}.html"
|
||||
sh "sed -i -e 's#TEMPLATE_JOB_NAME#${JOB_NAME}#' -e 's@build #TEMPLATE_BUILD_ID@build #${BUILD_ID}@' -e 's#Build-ID: TEMPLATE_BUILD_ID#Build-ID: <a href=\"${BUILD_URL}\">${BUILD_ID}</a>#' -e 's#TEMPLATE_STAGE_NAME#${testStageName}#' test_results-${JOB_NAME}.html"
|
||||
archiveArtifacts "test_results-${JOB_NAME}.html"
|
||||
}
|
||||
if (params.pipelineZipsConsoleLog != null) {
|
||||
if (params.pipelineZipsConsoleLog) {
|
||||
echo "Archiving Jenkins console log"
|
||||
sh "wget --no-check-certificate --no-proxy ${env.JENKINS_URL}/job/${env.JOB_NAME}/${env.BUILD_ID}/consoleText -O consoleText.log || true"
|
||||
sh "zip -m consoleText.log.${env.BUILD_ID}.zip consoleText.log || true"
|
||||
if(fileExists("consoleText.log.${env.BUILD_ID}.zip")) {
|
||||
archiveArtifacts "consoleText.log.${env.BUILD_ID}.zip"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
260
ci-scripts/Jenkinsfile-tmp-ran
Normal file
260
ci-scripts/Jenkinsfile-tmp-ran
Normal file
@@ -0,0 +1,260 @@
|
||||
#!/bin/groovy
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
// Template Jenkins Declarative Pipeline script to run Test w/ RF HW
|
||||
|
||||
// Location of the python executor node shall be in the same subnet as the others servers
|
||||
def pythonExecutor = params.pythonExecutor
|
||||
|
||||
// Location of the test XML file to be run
|
||||
def testXMLFile = params.pythonTestXmlFile
|
||||
def mainPythonAllXmlFiles = ""
|
||||
def buildStageStatus = true
|
||||
|
||||
// Name of the test stage
|
||||
def testStageName = params.pipelineTestStageName
|
||||
|
||||
def lockResources = []
|
||||
if (params.LockResources != null && params.LockResources.trim().length() > 0)
|
||||
params.LockResources.trim().split(",").each{lockResources += [resource: it.trim()]}
|
||||
|
||||
// Terminate Status
|
||||
def termUE = 0
|
||||
def termENB = 1
|
||||
def termSPGW = 2
|
||||
def termMME = 3
|
||||
def termHSS = 4
|
||||
def termStatusArray = new Boolean[termHSS + 1]
|
||||
termStatusArray[termUE] = false
|
||||
termStatusArray[termENB] = false
|
||||
termStatusArray[termSPGW] = false
|
||||
termStatusArray[termMME] = false
|
||||
termStatusArray[termHSS] = false
|
||||
|
||||
// Global Parameters. Normally they should be populated when the master job
|
||||
// triggers the slave job with parameters
|
||||
def eNB_Repository
|
||||
def eNB_Branch
|
||||
def eNB_CommitID
|
||||
def eNB_AllowMergeRequestProcess = false
|
||||
def eNB_TargetBranch
|
||||
|
||||
def flexricOption = ""
|
||||
|
||||
pipeline {
|
||||
agent {
|
||||
label pythonExecutor
|
||||
}
|
||||
options {
|
||||
ansiColor('xterm')
|
||||
lock(extra: lockResources)
|
||||
}
|
||||
stages {
|
||||
stage("Build Init") {
|
||||
steps {
|
||||
// update the build name and description
|
||||
buildName "${params.eNB_MR}"
|
||||
buildDescription "Branch : ${params.eNB_Branch}"
|
||||
}
|
||||
}
|
||||
stage ("Verify Parameters") {
|
||||
steps {
|
||||
script {
|
||||
echo '\u2705 \u001B[32mVerify Parameters\u001B[0m'
|
||||
def allParametersPresent = true
|
||||
|
||||
// It is already to late to check it
|
||||
if (params.pythonExecutor != null) {
|
||||
echo "eNB CI executor node : ${pythonExecutor}"
|
||||
}
|
||||
// If not present picking a default Stage Name
|
||||
if (params.pipelineTestStageName == null) {
|
||||
// picking default
|
||||
testStageName = 'Template Test Stage'
|
||||
}
|
||||
|
||||
if (params.LockResources == null) {
|
||||
echo "no LockResources given"
|
||||
allParametersPresent = false
|
||||
}
|
||||
if (params.eNB_SourceCodePath == null) {
|
||||
allParametersPresent = false
|
||||
}
|
||||
// the following 4 parameters should be pushed by the master trigger
|
||||
// if not present, take the job GIT variables (used for developing)
|
||||
if (params.eNB_Repository == null) {
|
||||
eNB_Repository = env.GIT_URL
|
||||
} else {
|
||||
eNB_Repository = params.eNB_Repository
|
||||
}
|
||||
echo "eNB_Repository : ${eNB_Repository}"
|
||||
if (params.eNB_Branch == null) {
|
||||
eNB_Branch = env.GIT_BRANCH
|
||||
} else {
|
||||
eNB_Branch = params.eNB_Branch
|
||||
}
|
||||
echo "eNB_Branch : ${eNB_Branch}"
|
||||
if (params.eNB_CommitID == null) {
|
||||
eNB_CommitID = env.GIT_COMMIT
|
||||
} else {
|
||||
eNB_CommitID = params.eNB_CommitID
|
||||
}
|
||||
echo "eNB_CommitID : ${eNB_CommitID}"
|
||||
if (params.eNB_mergeRequest != null) {
|
||||
eNB_AllowMergeRequestProcess = params.eNB_mergeRequest
|
||||
if (eNB_AllowMergeRequestProcess) {
|
||||
if (params.eNB_TargetBranch != null) {
|
||||
eNB_TargetBranch = params.eNB_TargetBranch
|
||||
} else {
|
||||
eNB_TargetBranch = 'develop'
|
||||
}
|
||||
echo "eNB_TargetBranch : ${eNB_TargetBranch}"
|
||||
}
|
||||
}
|
||||
|
||||
if (params.Flexric_Tag != null) {
|
||||
echo "This pipeline is configured to run with a FlexRIC deployment."
|
||||
echo "Appending FlexRicTag option to the list of options"
|
||||
flexricOption = "--FlexRicTag=${params.Flexric_Tag}"
|
||||
echo "Using new Flexric option: ${flexricOption}"
|
||||
}
|
||||
|
||||
if (allParametersPresent) {
|
||||
echo "All parameters are present"
|
||||
if (eNB_AllowMergeRequestProcess) {
|
||||
sh "git fetch"
|
||||
sh "./ci-scripts/doGitLabMerge.sh --src-branch ${eNB_Branch} --src-commit ${eNB_CommitID} --target-branch ${eNB_TargetBranch} --target-commit latest"
|
||||
} else if (eNB_CommitID != 'develop') {
|
||||
sh "git fetch"
|
||||
sh "git checkout -f ${eNB_CommitID}"
|
||||
}
|
||||
} else {
|
||||
error "Some parameters are missing"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage ("Build and Test") {
|
||||
steps {
|
||||
script {
|
||||
dir ('ci-scripts') {
|
||||
echo "\u2705 \u001B[32m${testStageName}\u001B[0m"
|
||||
// If not present picking a default XML file
|
||||
if (params.pythonTestXmlFile == null) {
|
||||
// picking default
|
||||
testXMLFile = 'xml_files/enb_usrpB210_band7_50PRB.xml'
|
||||
echo "Test XML file(default): ${testXMLFile}"
|
||||
mainPythonAllXmlFiles += "--XMLTestFile=" + testXMLFile + " "
|
||||
} else {
|
||||
String[] myXmlTestSuite = testXMLFile.split("\\r?\\n")
|
||||
for (xmlFile in myXmlTestSuite) {
|
||||
if (fileExists(xmlFile)) {
|
||||
mainPythonAllXmlFiles += "--XMLTestFile=" + xmlFile + " "
|
||||
echo "Test XML file : ${xmlFile}"
|
||||
} else {
|
||||
echo "Test XML file ${xmlFile}: no such file"
|
||||
}
|
||||
}
|
||||
}
|
||||
sh "python3 main.py --mode=InitiateHtml --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} ${flexricOption} ${mainPythonAllXmlFiles}"
|
||||
String[] myXmlTestSuite = testXMLFile.split("\\r?\\n")
|
||||
for (xmlFile in myXmlTestSuite) {
|
||||
if (fileExists(xmlFile)) {
|
||||
try {
|
||||
timeout (time: 60, unit: 'MINUTES') {
|
||||
sh "python3 main.py --mode=TesteNB --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} ${flexricOption} --eNBSourceCodePath=${params.eNB_SourceCodePath} --XMLTestFile=${xmlFile}"
|
||||
}
|
||||
} catch (Exception e) {
|
||||
currentBuild.result = 'FAILURE'
|
||||
buildStageStatus = false
|
||||
}
|
||||
}
|
||||
}
|
||||
sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage ("Terminate") {
|
||||
parallel {
|
||||
stage('Terminate eNB') {
|
||||
steps {
|
||||
echo '\u2705 \u001B[32mTerminate eNB\u001B[0m'
|
||||
sh "python3 ci-scripts/main.py --mode=TerminateeNB"
|
||||
}
|
||||
post {
|
||||
success {
|
||||
script {
|
||||
termStatusArray[termENB] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Log Collection') {
|
||||
parallel {
|
||||
stage('Log Collection (eNB - Run)') {
|
||||
steps {
|
||||
echo '\u2705 \u001B[32mLog Collection (eNB - Run)\u001B[0m'
|
||||
sh "python3 ci-scripts/main.py --mode=LogCollecteNB --eNBSourceCodePath=${params.eNB_SourceCodePath} --BuildId=${env.BUILD_ID}"
|
||||
script {
|
||||
if(fileExists("enb.log.${env.BUILD_ID}.zip")) {
|
||||
archiveArtifacts "enb.log.${env.BUILD_ID}.zip"
|
||||
}
|
||||
if(fileExists("ci-scripts/test_results.html")) {
|
||||
sh "mv ci-scripts/test_results.html test_results-${JOB_NAME}.html"
|
||||
sh "sed -i -e 's#TEMPLATE_JOB_NAME#${JOB_NAME}#' -e 's@build #TEMPLATE_BUILD_ID@build #${BUILD_ID}@' -e 's#Build-ID: TEMPLATE_BUILD_ID#Build-ID: <a href=\"${BUILD_URL}\">${BUILD_ID}</a>#' -e 's#TEMPLATE_STAGE_NAME#${testStageName}#' test_results-${JOB_NAME}.html"
|
||||
archiveArtifacts "test_results-${JOB_NAME}.html"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
always {
|
||||
script {
|
||||
if (params.pipelineZipsConsoleLog != null) {
|
||||
if (params.pipelineZipsConsoleLog) {
|
||||
echo "Archiving Jenkins console log"
|
||||
sh "wget --no-check-certificate --no-proxy ${env.JENKINS_URL}/job/${env.JOB_NAME}/${env.BUILD_ID}/consoleText -O consoleText.log || true"
|
||||
sh "zip -m consoleText.log.${env.BUILD_ID}.zip consoleText.log || true"
|
||||
if(fileExists("consoleText.log.${env.BUILD_ID}.zip")) {
|
||||
archiveArtifacts "consoleText.log.${env.BUILD_ID}.zip"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Making sure that we really shutdown every thing before leaving
|
||||
failure {
|
||||
script {
|
||||
if (!termStatusArray[termENB]) {
|
||||
sh "python3 ci-scripts/main.py --mode=TerminateeNB"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,7 @@
|
||||
#-----------------------------------------------------------
|
||||
import sys # arg
|
||||
import re # reg
|
||||
import yaml
|
||||
import constants as CONST
|
||||
|
||||
#-----------------------------------------------------------
|
||||
@@ -42,8 +43,11 @@ import constants as CONST
|
||||
|
||||
def ArgsParse(argvs,CiTestObj,RAN,HTML,CONTAINERS,HELP,SCA,CLUSTER):
|
||||
|
||||
|
||||
py_param_file_present = False
|
||||
py_params={}
|
||||
|
||||
force_local = False
|
||||
date_fmt = None
|
||||
while len(argvs) > 1:
|
||||
myArgv = argvs.pop(1) # 0th is this file's name
|
||||
|
||||
@@ -56,9 +60,6 @@ def ArgsParse(argvs,CiTestObj,RAN,HTML,CONTAINERS,HELP,SCA,CLUSTER):
|
||||
|
||||
|
||||
#consider inline parameters
|
||||
elif re.match(r'^\-\-datefmt=(.+)$', myArgv, re.IGNORECASE):
|
||||
matchReg = re.match(r'^\-\-datefmt=(.+)$', myArgv, re.IGNORECASE)
|
||||
date_fmt = matchReg.group(1)
|
||||
elif re.match(r'^\-\-mode=(.+)$', myArgv, re.IGNORECASE):
|
||||
matchReg = re.match(r'^\-\-mode=(.+)$', myArgv, re.IGNORECASE)
|
||||
mode = matchReg.group(1)
|
||||
@@ -161,6 +162,9 @@ def ArgsParse(argvs,CiTestObj,RAN,HTML,CONTAINERS,HELP,SCA,CLUSTER):
|
||||
elif re.match(r'^\-\-OCRegistry=(.+)$', myArgv, re.IGNORECASE):
|
||||
matchReg = re.match(r'^\-\-OCRegistry=(.+)$', myArgv, re.IGNORECASE)
|
||||
CLUSTER.OCRegistry = matchReg.group(1)
|
||||
elif re.match(r'^\-\-BuildId=(.+)$', myArgv, re.IGNORECASE):
|
||||
matchReg = re.match(r'^\-\-BuildId=(.+)$', myArgv, re.IGNORECASE)
|
||||
RAN.BuildId = matchReg.group(1)
|
||||
elif re.match(r'^\-\-FlexRicTag=(.+)$', myArgv, re.IGNORECASE):
|
||||
matchReg = re.match(r'^\-\-FlexRicTag=(.+)$', myArgv, re.IGNORECASE)
|
||||
CONTAINERS.flexricTag = matchReg.group(1)
|
||||
@@ -168,4 +172,4 @@ def ArgsParse(argvs,CiTestObj,RAN,HTML,CONTAINERS,HELP,SCA,CLUSTER):
|
||||
HELP.GenericHelp(CONST.Version)
|
||||
sys.exit('Invalid Parameter: ' + myArgv)
|
||||
|
||||
return mode, force_local, date_fmt
|
||||
return py_param_file_present, py_params, mode, force_local
|
||||
|
||||
@@ -22,15 +22,10 @@
|
||||
|
||||
import re
|
||||
import os
|
||||
import logging
|
||||
import yaml
|
||||
import signal
|
||||
|
||||
import xml.etree.ElementTree as ET
|
||||
import json
|
||||
|
||||
import importlib, inspect
|
||||
|
||||
class Analysis():
|
||||
|
||||
def _get_test_description(properties):
|
||||
@@ -114,134 +109,3 @@ class Analysis():
|
||||
test_summary['Nbpass'] = nb_tests - nb_failed
|
||||
test_summary['Nbfail'] = nb_failed
|
||||
return nb_failed == 0, test_summary, test_result
|
||||
|
||||
def analyze_rt_stats(thresholds, L1_stats, MAC_stats):
|
||||
with open(thresholds, 'r') as f:
|
||||
datalog_rt_stats = yaml.load(f, Loader=yaml.FullLoader)
|
||||
|
||||
rt_keys = datalog_rt_stats['Ref']
|
||||
real_time_stats = {}
|
||||
for sf in [L1_stats, MAC_stats]:
|
||||
with open(sf, 'r') as f:
|
||||
for line in f.readlines():
|
||||
for k in rt_keys:
|
||||
result = re.search(k, line)
|
||||
if result is not None:
|
||||
tmp = re.match(rf'^.*?(\b{k}\b.*)', line.rstrip())
|
||||
if tmp is not None:
|
||||
real_time_stats[k] = tmp.group(1)
|
||||
|
||||
# datalog_rt_stats format must align with HTML.CreateHtmlDataLogTable()
|
||||
datalog_rt_stats['Data']={}
|
||||
for k in real_time_stats:
|
||||
tmp = re.match(r'^(?P<metric>.*):\s+(?P<avg>\d+\.\d+) us;\s+(?P<count>\d+);\s+(?P<max>\d+\.\d+) us;', real_time_stats[k])
|
||||
if tmp is not None:
|
||||
metric = tmp.group('metric')
|
||||
avg = float(tmp.group('avg'))
|
||||
max = float(tmp.group('max'))
|
||||
count = int(tmp.group('count'))
|
||||
datalog_rt_stats['Data'][metric] = ["{:.0f}".format(avg),"{:.0f}".format(max),"{:d}".format(count),"{:.2f}".format(avg / datalog_rt_stats['Ref'][metric])]
|
||||
|
||||
success = True
|
||||
for k in datalog_rt_stats['Data']:
|
||||
valnorm = float(datalog_rt_stats['Data'][k][3])
|
||||
dev = datalog_rt_stats['DeviationThreshold'][k]
|
||||
if valnorm > 1.0 + dev or valnorm < 1.0 - dev: # condition for fail: avg/ref deviates by more than "deviation threshold"
|
||||
logging.debug(f'\u001B[1;30;43m normalized metric {k}={valnorm} deviates by more than {dev}\u001B[0m')
|
||||
success = False
|
||||
return success, datalog_rt_stats
|
||||
|
||||
|
||||
# returns tuple of (service, analyzer, option string)
|
||||
def _lookupServiceAnalyzerOpt(s, analyzers):
|
||||
res = s.split("=", 2)
|
||||
name = res[0]
|
||||
if len(res) == 1:
|
||||
return res[0], analyzers["Default"], None
|
||||
opt = res[2] if len(res) > 2 else None
|
||||
func = res[1]
|
||||
a = analyzers[func] if func in analyzers else None
|
||||
return name, a, opt
|
||||
|
||||
# groups requested service analysis (service=func[=option]) on per service
|
||||
# basis and looks up analyzer func. If log analysis is requested, will always
|
||||
# run Default log analysis
|
||||
def _groupServices(to_analyze):
|
||||
req_analysis = {}
|
||||
# get content of cls_loganalysis module, then get all analyzers (classes) in this module
|
||||
mod = importlib.import_module("cls_loganalysis")
|
||||
analyzers = {name:cl for name, cl in inspect.getmembers(mod, inspect.isclass)}
|
||||
for req in to_analyze:
|
||||
s, func, opt = _lookupServiceAnalyzerOpt(req, analyzers)
|
||||
logging.debug(f"requested check '{req}' => service {s}, function {func.__name__}, options '{opt}'")
|
||||
# always put default analyzer first
|
||||
l = req_analysis[s] if s in req_analysis else [(analyzers["Default"], None, "default")]
|
||||
if func is not analyzers["Default"]:
|
||||
l.append((func, opt, req))
|
||||
req_analysis[s] = l
|
||||
return req_analysis
|
||||
|
||||
def _describe_exit_code(code):
|
||||
if code > 128:
|
||||
sig = code - 128
|
||||
try:
|
||||
return f"terminated by signal {sig} ({signal.Signals(sig).name})"
|
||||
except ValueError:
|
||||
return f"terminated by unknown signal {sig}"
|
||||
else:
|
||||
return f"custom exit code"
|
||||
|
||||
def AnalyzeServices(HTML, service_desc, to_analyze):
|
||||
success = True
|
||||
# hack: we want to give as a description "log analysis", but the description
|
||||
# is set outside, so retain what was set before
|
||||
orig_html_desc = HTML.desc
|
||||
# group analysis on a per-service basis, then iterate
|
||||
for serv, list_analysis in _groupServices(to_analyze).items():
|
||||
HTML.desc = f"Log analysis for service {serv}"
|
||||
if serv not in service_desc:
|
||||
success = False
|
||||
logging.error(f"requested service {serv} not in list of services")
|
||||
HTML.CreateHtmlTestRowQueue("N/A", 'KO', ["service not detected"])
|
||||
continue
|
||||
# pre-initialize with return code
|
||||
rc = service_desc[serv]["returncode"]
|
||||
logging.info(f"analyze service {serv}: return code {rc}")
|
||||
service_success = True # TODO rc == 0: too many functions (eNB, lteUE, RIC, nrUE) fail non-zero
|
||||
logs = []
|
||||
if rc != 0:
|
||||
logs.append(f"=> return code {rc}, likely " + _describe_exit_code(rc) + " [ignored by CI]")
|
||||
# skip if the file is too big
|
||||
logfile = service_desc[serv]["logfile"]
|
||||
filename = os.path.basename(logfile)
|
||||
b = os.path.getsize(logfile)
|
||||
logging.debug(f"using logfile {logfile} of size {b} bytes")
|
||||
if b > 10 * 1024 * 1024:
|
||||
success = False
|
||||
logs.append(f"logfile too big (>10MB)")
|
||||
logging.error(logs)
|
||||
HTML.CreateHtmlTestRowQueue(filename, 'KO', ["\n".join(logs)])
|
||||
continue
|
||||
# run each analyzer with its options on the logfile
|
||||
for (func, opt, desc) in list_analysis:
|
||||
if func is None:
|
||||
service_success = False
|
||||
logging.error(f"request analysis function for desc {desc} not found")
|
||||
HTML.CreateHtmlTestRowQueue(serv, 'KO', [f"no analysis function for {desc}"])
|
||||
continue
|
||||
result, l = func.run(logfile, opt)
|
||||
logging.info(f"service {serv}: analysis with func {func}, result {result}, logs '{l}'")
|
||||
service_success = service_success and result
|
||||
if not result:
|
||||
logs.append(f"=> {func.__name__} check (options '{opt}') FAILED")
|
||||
logs.append(l)
|
||||
logs = '\n'.join(logs)
|
||||
if not service_success:
|
||||
logging.error(l)
|
||||
else:
|
||||
logging.info(l)
|
||||
all_funcs = ", ".join([f.__name__ for (f, _, _) in list_analysis])
|
||||
HTML.CreateHtmlTestRowQueue(f"Check {all_funcs} on {filename}", 'OK' if service_success else 'KO', [logs])
|
||||
success = success and service_success
|
||||
HTML.desc = orig_html_desc
|
||||
return success
|
||||
|
||||
@@ -24,14 +24,15 @@ from typing import NamedTuple
|
||||
import logging
|
||||
|
||||
class TestCaseCtx(NamedTuple):
|
||||
test_idx: int
|
||||
count: int
|
||||
test_id: int
|
||||
logPath: str
|
||||
|
||||
def Default(logPath):
|
||||
return TestCaseCtx(112233, logPath)
|
||||
return TestCaseCtx(123, 112233, logPath)
|
||||
def baseFilename(self):
|
||||
# typically, the test ID is of form 001234 (6 digits)
|
||||
return f"{self.logPath}/{self.test_idx:06d}"
|
||||
return f"{self.logPath}/{self.count}-{self.test_id:06d}"
|
||||
|
||||
def archiveArtifact(cmd, ctx, remote_path):
|
||||
base = os.path.basename(remote_path)
|
||||
|
||||
@@ -164,6 +164,7 @@ class Cluster:
|
||||
|
||||
def PullClusterImage(self, HTML, node, images, tag_prefix):
|
||||
logging.debug(f'Pull OC image {images} to server {node}')
|
||||
self.testCase_id = HTML.testCase_id
|
||||
with cls_cmd.getConnection(node) as cmd:
|
||||
succeeded = OC_login(cmd, self.OCUserName, self.OCPassword, CI_OC_RAN_NAMESPACE)
|
||||
if not succeeded:
|
||||
@@ -210,6 +211,8 @@ class Cluster:
|
||||
logging.debug(f'Building on cluster triggered from server: {node}')
|
||||
self.cmd = cls_cmd.RemoteCmd(node)
|
||||
|
||||
self.testCase_id = HTML.testCase_id
|
||||
|
||||
# Workaround for some servers, we need to erase completely the workspace
|
||||
self.cmd.cd(lSourcePath)
|
||||
# to reduce the amount of data send to OpenShift, we
|
||||
@@ -394,9 +397,9 @@ class Cluster:
|
||||
# Analyze the logs
|
||||
collectInfo = {}
|
||||
for image, lf in log_files:
|
||||
imgStatus, errors = cls_containerize.AnalyzeBuildLogs(image, lf)
|
||||
info = f"Analysis of {os.path.basename(lf)}: {imgStatus=}, size {imageSize[image]}, {len(errors)} errors"
|
||||
msg = "\n".join([info] + errors)
|
||||
ret = cls_containerize.AnalyzeBuildLogs(image, lf)
|
||||
imgStatus = ret['status']
|
||||
msg = f"size {imageSize[image]}, analysis of {os.path.basename(lf)}: {ret['errors']} errors, {ret['warnings']} warnings"
|
||||
HTML.CreateHtmlTestRowQueue(image, 'OK' if imgStatus else 'KO', [msg])
|
||||
status = status and imgStatus
|
||||
|
||||
@@ -409,7 +412,7 @@ class Cluster:
|
||||
# the groovy scripts expects all logs in
|
||||
# <jenkins-workspace>/<pipeline>/ci-scripts, so copy it there
|
||||
with cls_cmd.LocalCmd() as c:
|
||||
c.run(f'mkdir -p {os.getcwd()}/test_log_{ctx.test_idx}/')
|
||||
c.run(f'cp -r {ctx.logPath} {os.getcwd()}/test_log_{ctx.test_idx}/')
|
||||
c.run(f'mkdir -p {os.getcwd()}/test_log_{ctx.test_id}/')
|
||||
c.run(f'cp -r {ctx.logPath} {os.getcwd()}/test_log_{ctx.test_id}/')
|
||||
|
||||
return status
|
||||
|
||||
@@ -31,16 +31,21 @@
|
||||
#-----------------------------------------------------------
|
||||
# Import
|
||||
#-----------------------------------------------------------
|
||||
import sys # arg
|
||||
import re # reg
|
||||
import logging
|
||||
import os
|
||||
import shutil
|
||||
import time
|
||||
from zipfile import ZipFile
|
||||
|
||||
#-----------------------------------------------------------
|
||||
# OAI Testing modules
|
||||
#-----------------------------------------------------------
|
||||
import cls_cmd
|
||||
import helpreadme as HELP
|
||||
import constants as CONST
|
||||
import cls_analysis
|
||||
import cls_oaicitest
|
||||
from cls_ci_helper import archiveArtifact
|
||||
|
||||
#-----------------------------------------------------------
|
||||
@@ -80,9 +85,9 @@ def CreateTag(ranCommitID, ranBranch, ranAllowMerge):
|
||||
return tagToUse
|
||||
|
||||
def AnalyzeBuildLogs(image, lf):
|
||||
errorandwarnings = {}
|
||||
committed = False
|
||||
tagged = False
|
||||
errors = []
|
||||
with open(lf, mode='r') as inputfile:
|
||||
for line in inputfile:
|
||||
lineHasTag = re.search(f'Successfully tagged {image}:', str(line)) is not None
|
||||
@@ -91,13 +96,11 @@ def AnalyzeBuildLogs(image, lf):
|
||||
# the OpenShift Cluster builder prepends image registry URL
|
||||
lineHasCommit = re.search(r'COMMIT [a-zA-Z0-9\.:/\-]*' + image, str(line)) is not None
|
||||
committed = committed or lineHasCommit
|
||||
if re.search(r'error:|Errors|ERROR', line):
|
||||
errors.append(f"=> {line.strip()}")
|
||||
status = (committed or tagged) and len(errors) == 0
|
||||
logging.info(f"Analyzing {image}, file {lf}: {status=}, {len(errors)} errors")
|
||||
for e in errors:
|
||||
logging.info(e)
|
||||
return status, errors
|
||||
errorandwarnings['errors'] = 0 if committed or tagged else 1
|
||||
errorandwarnings['warnings'] = 0
|
||||
errorandwarnings['status'] = committed or tagged
|
||||
logging.info(f"Analyzing {image}, file {lf}: {errorandwarnings}")
|
||||
return errorandwarnings
|
||||
|
||||
def GetImageName(ssh, svcName, file):
|
||||
ret = ssh.run(f"docker compose -f {file} config --format json {svcName} | jq -r '.services.\"{svcName}\".image'", silent=True)
|
||||
@@ -116,7 +119,7 @@ def ExistEnvFilePrint(ssh, wd, prompt='env vars in existing'):
|
||||
|
||||
def WriteEnvFile(ssh, services, wd, tag, flexric_tag):
|
||||
ret = ssh.run(f'cat {wd}/.env', silent=True, reportNonZero=False)
|
||||
registry = "oai-ci/" # pull_images() gives us this registry path
|
||||
registry = "oai-ci" # pull_images() gives us this registry path
|
||||
envs = {"REGISTRY":registry, "TAG": tag, "FLEXRIC_TAG": flexric_tag}
|
||||
if ret.returncode == 0: # it exists, we have to update
|
||||
# transforms env file to dictionary
|
||||
@@ -131,8 +134,7 @@ def WriteEnvFile(ssh, services, wd, tag, flexric_tag):
|
||||
# or -asan images. We need to detect which kind we did pull.
|
||||
fullImageName = GetImageName(ssh, svc, f"{wd}/docker-compose.y*ml")
|
||||
image = fullImageName.split("/")[-1].split(":")[0]
|
||||
# registry now includes the trailing slash ("oai-ci/")
|
||||
checkimg = f"{registry}{image}-asan:{tag}"
|
||||
checkimg = f"{registry}/{image}-asan:{tag}"
|
||||
ret = ssh.run(f'docker image inspect {checkimg}', reportNonZero=False)
|
||||
if ret.returncode == 0:
|
||||
logging.info(f"detected pulled image {checkimg}")
|
||||
@@ -162,26 +164,60 @@ def CopyinServiceLog(ssh, lSourcePath, svcName, wd_yaml, ctx):
|
||||
ssh.run(f'docker compose -f {wd_yaml} logs {svcName} --no-log-prefix &> {remote_filename}')
|
||||
return archiveArtifact(ssh, ctx, remote_filename)
|
||||
|
||||
def GetDeployedServices(ssh, file):
|
||||
def GetRunningServices(ssh, file):
|
||||
ret = ssh.run(f'docker compose -f {file} config --services')
|
||||
if ret.returncode != 0:
|
||||
logging.error("could not get services")
|
||||
return None
|
||||
allServices = ret.stdout.splitlines()
|
||||
deployed_services = []
|
||||
running_services = []
|
||||
for s in allServices:
|
||||
# outputs the hash if the container has been deployed (but might be stopped)
|
||||
ret = ssh.run(f'docker compose -f {file} ps --all --quiet -- {s}', silent=True)
|
||||
# outputs the hash if the container is running
|
||||
ret = ssh.run(f'docker compose -f {file} ps --all --quiet -- {s}')
|
||||
if ret.returncode != 0:
|
||||
# error: should not happen as we iterate over docker-provided service list
|
||||
logging.error(f"service {s}: {ret.stdout}")
|
||||
logging.info(f"service {s}: {ret.stdout}")
|
||||
elif ret.stdout == "":
|
||||
logging.info(f"service {s} not deployed")
|
||||
logging.warning(f"could not retrieve information for service {s}")
|
||||
else:
|
||||
c = ret.stdout
|
||||
logging.info(f'service {s} with container id {c}')
|
||||
deployed_services.append((s, c))
|
||||
return deployed_services
|
||||
logging.debug(f'running service {s} with container id {c}')
|
||||
running_services.append((s, c))
|
||||
logging.info(f'stopping services: {running_services}')
|
||||
return running_services
|
||||
|
||||
def CheckLogs(self, filename, HTML, RAN):
|
||||
success = True
|
||||
name = os.path.basename(filename)
|
||||
if (any(sub in name for sub in ['oai_ue','oai-nr-ue','lte_ue'])):
|
||||
logging.debug(f'\u001B[1m Analyzing UE logfile {filename} \u001B[0m')
|
||||
logStatus = cls_oaicitest.OaiCiTest().AnalyzeLogFile_UE(filename, HTML, RAN)
|
||||
opt = f"UE log analysis ({name})"
|
||||
# usage of htmlUEFailureMsg/htmleNBFailureMsg is because Analyze log files
|
||||
# abuse HTML to store their reports, and we here want to put custom options,
|
||||
# which is not possible with CreateHtmlTestRow
|
||||
# solution: use HTML templates, where we don't need different HTML write funcs
|
||||
if (logStatus < 0):
|
||||
HTML.CreateHtmlTestRowQueue(opt, 'KO', [HTML.htmlUEFailureMsg])
|
||||
success = False
|
||||
else:
|
||||
HTML.CreateHtmlTestRowQueue(opt, 'OK', [HTML.htmlUEFailureMsg])
|
||||
HTML.htmlUEFailureMsg = ""
|
||||
elif 'nv-cubb' in name:
|
||||
msg = 'Undeploy PNF/Nvidia CUBB'
|
||||
HTML.CreateHtmlTestRow(msg, 'OK', CONST.ALL_PROCESSES_OK)
|
||||
elif (any(sub in name for sub in ['enb','rru','rcc','cu','du','gnb'])):
|
||||
logging.debug(f'\u001B[1m Analyzing XnB logfile {filename}\u001B[0m')
|
||||
logStatus = RAN.AnalyzeLogFile_eNB(filename, HTML, self.ran_checkers)
|
||||
opt = f"xNB log analysis ({name})"
|
||||
if (logStatus < 0):
|
||||
HTML.CreateHtmlTestRowQueue(opt, 'KO', [HTML.htmleNBFailureMsg])
|
||||
success = False
|
||||
else:
|
||||
HTML.CreateHtmlTestRowQueue(opt, 'OK', [HTML.htmleNBFailureMsg])
|
||||
HTML.htmleNBFailureMsg = ""
|
||||
else:
|
||||
logging.info(f"Skipping analysis of log '{filename}': no submatch for xNB/UE")
|
||||
logging.debug(f"log check: file {filename} passed analysis {success}")
|
||||
return success
|
||||
|
||||
#-----------------------------------------------------------
|
||||
# Class Declaration
|
||||
@@ -207,6 +243,8 @@ class Containerize():
|
||||
self.dockerfileprefix = ''
|
||||
self.host = ''
|
||||
|
||||
#checkers from xml
|
||||
self.ran_checkers={}
|
||||
self.num_attempts = 1
|
||||
|
||||
self.flexricTag = ''
|
||||
@@ -243,7 +281,7 @@ class Containerize():
|
||||
result = re.search('gNB', self.imageKind)
|
||||
if result is not None:
|
||||
imageNames.append(('oai-gnb', 'gNB', 'oai-gnb', ''))
|
||||
result = re.search('x86', self.imageKind)
|
||||
result = re.search('all', self.imageKind)
|
||||
if result is not None:
|
||||
imageNames.append(('oai-enb', 'eNB', 'oai-enb', ''))
|
||||
imageNames.append(('oai-gnb', 'gNB', 'oai-gnb', ''))
|
||||
@@ -254,6 +292,7 @@ class Containerize():
|
||||
imageNames.append(('oai-physim', 'phySim', 'oai-physim', ''))
|
||||
if self.host == 'Ubuntu':
|
||||
imageNames.append(('oai-lte-ru', 'lteRU', 'oai-lte-ru', ''))
|
||||
imageNames.append(('oai-gnb-aerial', 'gNB.aerial', 'oai-gnb-aerial', ''))
|
||||
# Building again the 5G images with Address Sanitizer
|
||||
imageNames.append(('ran-build', 'build', 'ran-build-asan', '--build-arg "BUILD_OPTION=--sanitize"'))
|
||||
imageNames.append(('oai-enb', 'eNB', 'oai-enb-asan', '--build-arg "BUILD_OPTION=--sanitize"'))
|
||||
@@ -263,7 +302,6 @@ class Containerize():
|
||||
imageNames.append(('oai-nr-cuup', 'nr-cuup', 'oai-nr-cuup-asan', '--build-arg "BUILD_OPTION=--sanitize"'))
|
||||
imageNames.append(('ran-build-fhi72', 'build.fhi72', 'ran-build-fhi72', ''))
|
||||
imageNames.append(('oai-gnb', 'gNB.fhi72', 'oai-gnb-fhi72', ''))
|
||||
imageNames.append(('oai-nr-oru', 'nrORU.fhi72', 'oai-nr-oru', ''))
|
||||
result = re.search('build_cross_arm64', self.imageKind)
|
||||
if result is not None:
|
||||
self.dockerfileprefix = '.ubuntu.cross-arm64'
|
||||
@@ -311,16 +349,12 @@ class Containerize():
|
||||
for image,pattern,name,option in imageNames:
|
||||
cmd.run(f"{self.cli} image rm {name}:{imageTag}", reportNonZero=False)
|
||||
|
||||
cmd.run(f'docker login -u oaicicd -p oaicicd {DEFAULT_REGISTRY}')
|
||||
ubuntuImage = "ubuntu:noble"
|
||||
# Build the base image only on Push Events (not on Merge Requests)
|
||||
# On when the base image docker file is being modified.
|
||||
if forceBaseImageBuild:
|
||||
cmd.run(f"{self.cli} image rm {baseImage}:{baseTag}")
|
||||
logfile = f'{lSourcePath}/cmake_targets/log/ran-base.docker.log'
|
||||
if self.host == 'Ubuntu':
|
||||
option = f" --build-arg UBUNTU_IMAGE={DEFAULT_REGISTRY}/{ubuntuImage}"
|
||||
cmd.run(f"{self.cli} build {self.cliBuildOptions} --target {baseImage} --tag {baseImage}:{baseTag} --file docker/Dockerfile.base{self.dockerfileprefix} {option} . &> {logfile}", timeout=1600)
|
||||
cmd.run(f"{self.cli} build {self.cliBuildOptions} --target {baseImage} --tag {baseImage}:{baseTag} --file docker/Dockerfile.base{self.dockerfileprefix} . &> {logfile}", timeout=1600)
|
||||
t = ("ran-base", archiveArtifact(cmd, ctx, logfile))
|
||||
log_files.append(t)
|
||||
|
||||
@@ -356,20 +390,18 @@ class Containerize():
|
||||
# target images should use the proper ran-build image
|
||||
if image != 'ran-build' and "-asan" in name:
|
||||
cmd.run(f'sed -i -e "s#ran-build:latest#ran-build-asan:{imageTag}#" docker/Dockerfile.{pattern}{self.dockerfileprefix}')
|
||||
elif "fhi72" in name or name == "oai-nr-oru":
|
||||
elif "fhi72" in name:
|
||||
cmd.run(f'sed -i -e "s#ran-build-fhi72:latest#ran-build-fhi72:{imageTag}#" docker/Dockerfile.{pattern}{self.dockerfileprefix}')
|
||||
elif image != 'ran-build':
|
||||
cmd.run(f'sed -i -e "s#ran-build:latest#ran-build:{imageTag}#" docker/Dockerfile.{pattern}{self.dockerfileprefix}')
|
||||
if image == 'oai-gnb-aerial':
|
||||
cmd.run('cp -f /opt/nvidia-ipc/nvipc_src.2026.01.07.tar.gz .')
|
||||
cmd.run('cp -f /opt/nvidia-ipc/nvipc_src.2025.10.09.tar.gz .')
|
||||
logfile = f'{lSourcePath}/cmake_targets/log/{name}.docker.log'
|
||||
if self.host == 'Ubuntu':
|
||||
option = option + f" --build-arg UBUNTU_IMAGE={DEFAULT_REGISTRY}/{ubuntuImage}"
|
||||
ret = cmd.run(f'{self.cli} build {self.cliBuildOptions} --target {image} --tag {name}:{imageTag} --file docker/Dockerfile.{pattern}{self.dockerfileprefix} {option} . > {logfile} 2>&1', timeout=1200)
|
||||
t = (name, archiveArtifact(cmd, ctx, logfile))
|
||||
log_files.append(t)
|
||||
if image == 'oai-gnb-aerial':
|
||||
cmd.run('rm -f nvipc_src.2026.01.07.tar.gz')
|
||||
cmd.run('rm -f nvipc_src.2025.10.09.tar.gz')
|
||||
# check the status of the build
|
||||
ret = cmd.run(f"{self.cli} image inspect --format=\'Size = {{{{.Size}}}} bytes\' {name}:{imageTag}")
|
||||
if ret.returncode != 0:
|
||||
@@ -391,7 +423,7 @@ class Containerize():
|
||||
allImagesSize[name] = 'unknown'
|
||||
# Now pruning dangling images in between target builds
|
||||
cmd.run(f"{self.cli} image prune --force")
|
||||
cmd.run(f'docker logout {DEFAULT_REGISTRY}')
|
||||
|
||||
# Remove all intermediate build images and clean up
|
||||
cmd.run(f"{self.cli} image rm ran-build:{imageTag} ran-build-asan:{imageTag} ran-build-fhi72:{imageTag} || true")
|
||||
cmd.run(f"{self.cli} volume prune --force")
|
||||
@@ -407,9 +439,9 @@ class Containerize():
|
||||
|
||||
# Analyze the logs
|
||||
for name, lf in log_files:
|
||||
imgStatus, errors = AnalyzeBuildLogs(name, lf)
|
||||
info = f"Analysis of {os.path.basename(lf)}: {imgStatus=}, size {allImagesSize[name]}, {len(errors)} errors"
|
||||
msg = "\n".join([info] + errors)
|
||||
ret = AnalyzeBuildLogs(name, lf)
|
||||
imgStatus = ret['status']
|
||||
msg = f"size {allImagesSize[name]}, analysis of {os.path.basename(lf)}: {ret['errors']} errors, {ret['warnings']} warnings"
|
||||
HTML.CreateHtmlTestRowQueue(name, 'OK' if imgStatus else 'KO', [msg])
|
||||
status = status and imgStatus
|
||||
|
||||
@@ -527,7 +559,7 @@ class Containerize():
|
||||
ret = cmd.run(f"docker image inspect --format=\'Size = {{{{.Size}}}} bytes\' {baseImage}:{baseTag}")
|
||||
if ret.returncode != 0:
|
||||
logging.error(f'No {baseImage} image present, cannot build tests')
|
||||
HTML.CreateHtmlTestRow("Unit test build failed", 'KO', CONST.ALL_PROCESSES_OK)
|
||||
HTML.CreateHtmlTestRow(self.imageKind, 'KO', CONST.ALL_PROCESSES_OK)
|
||||
return False
|
||||
|
||||
# build ran-unittests image
|
||||
@@ -682,6 +714,7 @@ class Containerize():
|
||||
def DeployObject(self, ctx, node, HTML):
|
||||
num_attempts = self.num_attempts
|
||||
lSourcePath = self.eNBSourceCodePath
|
||||
logging.debug(f'Deploying OAI Object on server: {node}')
|
||||
yaml = self.yamlPath.strip('/')
|
||||
wd = f'{lSourcePath}/{yaml}'
|
||||
wd_yaml = f'{wd}/docker-compose.y*ml'
|
||||
@@ -692,7 +725,6 @@ class Containerize():
|
||||
logging.error(msg)
|
||||
HTML.CreateHtmlTestRowQueue('N/A', 'KO', [msg])
|
||||
return False
|
||||
logging.info(f'\u001B[1mDeploying object(s) "{services}" on server {node}\u001B[0m')
|
||||
ExistEnvFilePrint(ssh, wd)
|
||||
WriteEnvFile(ssh, services, wd, self.deploymentTag, self.flexricTag)
|
||||
if num_attempts <= 0:
|
||||
@@ -717,94 +749,36 @@ class Containerize():
|
||||
imagesInfo = info.stdout.splitlines()[1:]
|
||||
logging.debug(f'{info.stdout.splitlines()[1:]}')
|
||||
if deployed:
|
||||
HTML.CreateHtmlTestRowQueue(self.services, 'OK', ['\n'.join(imagesInfo)])
|
||||
logging.info('\u001B[1m Deploying objects Pass\u001B[0m')
|
||||
HTML.CreateHtmlTestRowQueue('N/A', 'OK', ['\n'.join(imagesInfo)])
|
||||
else:
|
||||
HTML.CreateHtmlTestRowQueue(self.services, 'KO', ['\n'.join(imagesInfo)])
|
||||
logging.error('\u001B[1m Deploying objects Failed\u001B[0m')
|
||||
HTML.CreateHtmlTestRowQueue('N/A', 'KO', ['\n'.join(imagesInfo)])
|
||||
return deployed
|
||||
|
||||
def StopObject(self, ctx, node, HTML):
|
||||
def UndeployObject(self, ctx, node, HTML, RAN):
|
||||
lSourcePath = self.eNBSourceCodePath
|
||||
if not self.services:
|
||||
raise ValueError(f'no services provided')
|
||||
logging.info(f'\u001B[1m Stopping objects "{self.services}" from server: {node}\u001B[0m')
|
||||
reqServices = self.services.split()
|
||||
logging.debug(f'\u001B[1m Undeploying OAI Object from server: {node}\u001B[0m')
|
||||
yaml = self.yamlPath.strip('/')
|
||||
wd = f'{lSourcePath}/{yaml}'
|
||||
wd_yaml = f'{wd}/docker-compose.y*ml'
|
||||
with cls_cmd.getConnection(node) as ssh:
|
||||
ExistEnvFilePrint(ssh, wd)
|
||||
services = [s for s, _ in GetDeployedServices(ssh, wd_yaml)]
|
||||
success = []
|
||||
fail = []
|
||||
for s in reqServices:
|
||||
if s in services:
|
||||
ssh.run(f'docker compose -f {wd_yaml} stop -- {s}')
|
||||
success.append(s)
|
||||
else:
|
||||
logging.error(f"no such service {s}")
|
||||
fail.append(s)
|
||||
if success == reqServices:
|
||||
logging.info('\u001B[1m Stopping object Pass\u001B[0m')
|
||||
HTML.CreateHtmlTestRowQueue(self.services, 'OK', [f'Stopped {self.services}'])
|
||||
else:
|
||||
logging.error('\u001B[1m Stopping object Failed\u001B[0m')
|
||||
HTML.CreateHtmlTestRowQueue(self.services, 'KO', [f'Failed stopping {" ".join(fail)}, succeeded {" ".join(success)}'])
|
||||
return success
|
||||
|
||||
def UndeployObject(self, ctx, node, HTML, to_analyze):
|
||||
lSourcePath = self.eNBSourceCodePath
|
||||
logging.info(f'\u001B[1m Undeploying all objects from server {node}\u001B[0m')
|
||||
yaml = self.yamlPath.strip('/')
|
||||
wd = f'{lSourcePath}/{yaml}'
|
||||
wd_yaml = f'{wd}/docker-compose.y*ml'
|
||||
with cls_cmd.getConnection(node) as ssh:
|
||||
ExistEnvFilePrint(ssh, wd)
|
||||
services = GetDeployedServices(ssh, wd_yaml)
|
||||
all_logs = True
|
||||
ssh.run(f'docker compose -f {wd_yaml} stop')
|
||||
services = GetRunningServices(ssh, f"{wd}/docker-compose.y*ml")
|
||||
copyin_res = None
|
||||
if services is not None:
|
||||
service_desc = {}
|
||||
for s, c in services:
|
||||
ret = ssh.run(f'docker inspect {c} --format="{{{{.State.ExitCode}}}}"')
|
||||
rc = int(ret.stdout.strip())
|
||||
f = CopyinServiceLog(ssh, lSourcePath, s, wd_yaml, ctx)
|
||||
all_logs = all_logs and f is not None
|
||||
service_desc[s] = {'returncode': rc, 'logfile': f}
|
||||
all_serv = " ".join([s for s, _ in services])
|
||||
ssh.run(f'docker compose -f {wd}/docker-compose.y*ml stop -- {all_serv}')
|
||||
copyin_res = [CopyinServiceLog(ssh, lSourcePath, s, f"{wd}/docker-compose.y*ml", ctx) for s, _ in services]
|
||||
else:
|
||||
logging.warning('could not identify services to stop => no log file')
|
||||
ssh.run(f'docker compose -f {wd_yaml} down -v')
|
||||
HTML.CreateHtmlTestRowQueue(node, 'OK', ['Undeployment successful'])
|
||||
ssh.run(f'docker compose -f {wd}/docker-compose.y*ml down -v')
|
||||
ssh.run(f'rm {wd}/.env')
|
||||
if not all_logs:
|
||||
if not copyin_res:
|
||||
HTML.CreateHtmlTestRowQueue('N/A', 'KO', ['Could not copy logfile(s)'])
|
||||
logging.error(f"could not copy all files: {all_logs=} {services=}")
|
||||
success = False
|
||||
return False
|
||||
else:
|
||||
success = cls_analysis.AnalyzeServices(HTML, service_desc, to_analyze)
|
||||
log_results = [CheckLogs(self, f, HTML, RAN) for f in copyin_res]
|
||||
success = all(log_results)
|
||||
if success:
|
||||
logging.info('\u001B[1m Undeploying objects Pass\u001B[0m')
|
||||
logging.info('\u001B[1m Undeploying OAI Object Pass\u001B[0m')
|
||||
else:
|
||||
logging.error('\u001B[1m Undeploying objects Failed\u001B[0m')
|
||||
return success
|
||||
|
||||
def AnalyzeRTStatsObject(self, HTML, node, ctx, thresholds):
|
||||
logging.info(f'Analyzing realtime stats from server: {node}')
|
||||
yaml = self.yamlPath.strip('/')
|
||||
wd = f'{self.eNBSourceCodePath}/{yaml}'
|
||||
wd_yaml = f'{wd}/docker-compose.y*ml'
|
||||
|
||||
with cls_cmd.getConnection(node) as cmd:
|
||||
services = GetDeployedServices(cmd, wd_yaml)
|
||||
s, _ = services[0] # we simply assume something is deployed, if not Exception will report
|
||||
# similar to BuildRunTests(), use docker cp to avoid problems with permissions
|
||||
cmd.run(f'docker compose -f {wd_yaml} cp {s}:/opt/oai-gnb/nrL1_stats.log {wd}/')
|
||||
l1_file = archiveArtifact(cmd, ctx, f"{wd}/nrL1_stats.log")
|
||||
cmd.run(f'docker compose -f {wd_yaml} cp {s}:/opt/oai-gnb/nrMAC_stats.log {wd}/')
|
||||
mac_file = archiveArtifact(cmd, ctx, f"{wd}/nrMAC_stats.log")
|
||||
|
||||
logging.info(f"check against thresholds from {thresholds}")
|
||||
success, datalog_rt_stats = cls_analysis.Analysis.analyze_rt_stats(thresholds, l1_file, mac_file)
|
||||
HTML.CreateHtmlDataLogTable(datalog_rt_stats)
|
||||
logging.error('\u001B[1m Undeploying OAI Object Failed\u001B[0m')
|
||||
return success
|
||||
|
||||
@@ -1,161 +0,0 @@
|
||||
#/*
|
||||
# * 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
|
||||
# */
|
||||
#---------------------------------------------------------------------
|
||||
|
||||
import re
|
||||
import os
|
||||
import logging
|
||||
from collections import deque
|
||||
|
||||
class Default:
|
||||
def run(file, opt=None):
|
||||
success = True
|
||||
logs = []
|
||||
with open(file, "r") as f:
|
||||
for line in f.readlines():
|
||||
result = re.search('[Aa]ssertion', line)
|
||||
if result:
|
||||
logs.append(line)
|
||||
success = False
|
||||
return success, "\n".join(logs)
|
||||
|
||||
class ContainsString:
|
||||
def run(file, needle):
|
||||
with open(file, "r") as f:
|
||||
for line in f.readlines():
|
||||
if re.search(needle, line):
|
||||
return True, ""
|
||||
return False, f"could not find '{needle}' in logs"
|
||||
|
||||
class LastLineContains:
|
||||
def run(file, string):
|
||||
with open(file, "r") as f:
|
||||
last_line = deque(f, maxlen=1).pop()
|
||||
success = string in last_line
|
||||
log = "" if success else f"could not find '{string}' in last line"
|
||||
return success, log
|
||||
|
||||
class EndsWithBye:
|
||||
def run(file, option):
|
||||
# no option: we ignore any
|
||||
with open(file, "r") as f:
|
||||
n = 0
|
||||
for line in reversed(f.readlines()):
|
||||
if re.search(r'^Bye.\n', line, re.MULTILINE) is not None:
|
||||
return True, ""
|
||||
n = n + 1
|
||||
if n > 50: # if not found in last 50 lines, assume it does not exist
|
||||
break
|
||||
return False, "No Bye. message found, did not stop properly"
|
||||
|
||||
class RetxCheck():
|
||||
def _parseList(s):
|
||||
if not s:
|
||||
return []
|
||||
return [int(n) for n in s.split(",")]
|
||||
|
||||
def _get_ul_dl(s):
|
||||
dl, ul = (None, None)
|
||||
for o in s.split(";", 1):
|
||||
if o.startswith("dl="):
|
||||
dl = o[3:]
|
||||
elif o.startswith("ul="):
|
||||
ul = o[3:]
|
||||
else:
|
||||
raise ValueError(f"unrecognized option {s}: needs format '[ul=,dl=]X,Y,...[;ul=Z,V,...]'")
|
||||
return dl, ul
|
||||
|
||||
def _parseRetxCheckers(options):
|
||||
if not "=" in options:
|
||||
dlul = RetxCheck._parseList(options)
|
||||
return dlul, dlul
|
||||
dl, ul = RetxCheck._get_ul_dl(options)
|
||||
return RetxCheck._parseList(dl), RetxCheck._parseList(ul)
|
||||
|
||||
def _analyzeUeRetx(rounds, checkers, regex):
|
||||
perc = list(0 for i in checkers) # results in %
|
||||
stats = list(False for i in checkers) # status if succeeded
|
||||
tmp = re.match(regex, rounds)
|
||||
if tmp is None:
|
||||
logging.error('_analyzeUeRetx: did not match regex for DL retx analysis')
|
||||
return stats
|
||||
retx_data = [float(x) for x in tmp.groups()]
|
||||
for i in range(0, len(perc)):
|
||||
#case where numerator > denumerator with denum ==0 is disregarded, cannot hapen in principle, will lead to 0%
|
||||
perc[i] = 0 if (retx_data[i] == 0) else 100 * retx_data[i + 1] / retx_data[i]
|
||||
#treating % > 100 , % > requirement
|
||||
stats[i] = perc[i] <= 100 and perc[i] <= checkers[i]
|
||||
return stats
|
||||
|
||||
def _filter_retx_rounds(l):
|
||||
# map to round number if False, else None
|
||||
l = [i+1 if x is False else None for i, x in enumerate(l)]
|
||||
# filter out None
|
||||
return [x for x in l if x is not None]
|
||||
|
||||
def run(file, options):
|
||||
# aggregate statistics per UE
|
||||
dlsch_ulsch_stats = {}
|
||||
status = True
|
||||
with open(file, "r") as f:
|
||||
for line in f.readlines():
|
||||
keys = {'dlsch_rounds','ulsch_rounds'}
|
||||
for k in keys:
|
||||
result = re.search(k, line)
|
||||
if result is None:
|
||||
continue
|
||||
result = re.search('UE (?:RNTI )?([0-9a-f]{4})', line)
|
||||
if result is None:
|
||||
logging.error(f'did not find RNTI while matching key {k}')
|
||||
status = False
|
||||
continue
|
||||
rnti = result.group(1)
|
||||
if not rnti in dlsch_ulsch_stats:
|
||||
dlsch_ulsch_stats[rnti] = {}
|
||||
dlsch_ulsch_stats[rnti][k]=re.sub(r'^.*\]\s+', r'' , line.rstrip())
|
||||
|
||||
dl, ul = RetxCheck._parseRetxCheckers(options)
|
||||
msgs = []
|
||||
for ue in dlsch_ulsch_stats:
|
||||
dlulstat = dlsch_ulsch_stats[ue]
|
||||
|
||||
for key in dlulstat:
|
||||
msgs.append(dlulstat[key])
|
||||
|
||||
retx_dl = RetxCheck._analyzeUeRetx(dlulstat['dlsch_rounds'], dl, r'^.*dlsch_rounds\s+(\d+)\/(\d+)\/(\d+)\/(\d+),\s+dlsch_errors\s+(\d+)')
|
||||
retx_ul = RetxCheck._analyzeUeRetx(dlulstat['ulsch_rounds'], ul, r'^.*ulsch_rounds\s+(\d+)\/(\d+)\/(\d+)\/(\d+),\s+ulsch_errors\s+(\d+)')
|
||||
|
||||
if False in retx_dl or False in retx_ul:
|
||||
dlstr = RetxCheck._filter_retx_rounds(retx_dl)
|
||||
ulstr = RetxCheck._filter_retx_rounds(retx_ul)
|
||||
msg = f"UE {ue}: retx rounds"
|
||||
if dlstr:
|
||||
msg = f"{msg} DL {dlstr}"
|
||||
if ulstr:
|
||||
msg = f"{msg} UL {ulstr}"
|
||||
msg = f"{msg} exceeded threshold"
|
||||
msgs.append('!!! Failure: ' + msg)
|
||||
logging.error(f'\u001B[1;37;41m {msg}\u001B[0m')
|
||||
status = False
|
||||
else:
|
||||
msg = f"UE {ue} retransmissions within bounds"
|
||||
logging.debug(msg)
|
||||
return status, "\n".join(msgs)
|
||||
@@ -111,7 +111,7 @@ class Module_UE:
|
||||
return self._collectTrace(ctx)
|
||||
return None
|
||||
|
||||
def attach(self, attach_tries = 3, attach_timeout = 40):
|
||||
def attach(self, attach_tries = 4, attach_timeout = 60):
|
||||
ip = None
|
||||
while attach_tries > 0:
|
||||
self._command(self.cmd_dict["attach"])
|
||||
@@ -125,7 +125,6 @@ class Module_UE:
|
||||
if ip:
|
||||
break
|
||||
logging.warning(f"UE did not receive IP address after {attach_timeout} s, detaching")
|
||||
attach_timeout += 20
|
||||
attach_tries -= 1
|
||||
self._command(self.cmd_dict["detach"])
|
||||
time.sleep(5)
|
||||
|
||||
@@ -34,8 +34,9 @@ DPDK_PATH = '/opt/dpdk-t2-22.11.0'
|
||||
|
||||
class Native():
|
||||
|
||||
def Build(ctx, node, HTML, directory, options):
|
||||
def Build(ctx, node, test_case, HTML, directory, options):
|
||||
logging.debug(f'Building on server: {node}')
|
||||
HTML.testCase_id = test_case
|
||||
|
||||
with cls_cmd.getConnection(node) as ssh:
|
||||
base = f"{directory}/cmake_targets"
|
||||
|
||||
@@ -67,7 +67,7 @@ class HTMLManagement():
|
||||
self.htmlUEFailureMsg = ''
|
||||
|
||||
self.startTime = int(round(time.time() * 1000))
|
||||
self.testCaseIdx = ''
|
||||
self.testCase_id = ''
|
||||
self.desc = ''
|
||||
|
||||
#-----------------------------------------------------------
|
||||
@@ -191,7 +191,7 @@ class HTMLManagement():
|
||||
self.htmlFile.write(' <table class="table" border = "1">\n')
|
||||
self.htmlFile.write(' <tr bgcolor = "#33CCFF" >\n')
|
||||
self.htmlFile.write(' <th style="width:5%">Relative Time (s)</th>\n')
|
||||
self.htmlFile.write(' <th style="width:5%">Test Index</th>\n')
|
||||
self.htmlFile.write(' <th style="width:5%">Test Id</th>\n')
|
||||
self.htmlFile.write(' <th>Test Desc</th>\n')
|
||||
self.htmlFile.write(' <th>Test Options</th>\n')
|
||||
self.htmlFile.write(' <th style="width:5%">Test Status</th>\n')
|
||||
@@ -218,7 +218,7 @@ class HTMLManagement():
|
||||
cmd = "sed -i -e 's/__STATE_" + self.htmlTabNames[0] + "__//' test_results.html"
|
||||
subprocess.run(cmd, shell=True)
|
||||
else:
|
||||
cmd = "sed -i -e 's/__STATE_" + self.htmlTabNames[0] + r"__/<span class=\"glyphicon glyphicon-remove\"><\/span>/' test_results.html"
|
||||
cmd = "sed -i -e 's/__STATE_" + self.htmlTabNames[0] + "__/<span class=\"glyphicon glyphicon-remove\"><\/span>/' test_results.html"
|
||||
subprocess.run(cmd, shell=True)
|
||||
self.htmlFooterCreated = False
|
||||
|
||||
@@ -259,7 +259,7 @@ class HTMLManagement():
|
||||
currentTime = int(round(time.time() * 1000)) - self.startTime
|
||||
self.htmlFile.write(' <tr>\n')
|
||||
self.htmlFile.write(' <td bgcolor = "lightcyan" >' + format(currentTime / 1000, '.1f') + '</td>\n')
|
||||
self.htmlFile.write(' <td bgcolor = "lightcyan" >' + self.testCaseIdx + '</td>\n')
|
||||
self.htmlFile.write(' <td bgcolor = "lightcyan" >' + self.testCase_id + '</td>\n')
|
||||
self.htmlFile.write(' <td>' + self.desc + '</td>\n')
|
||||
self.htmlFile.write(' <td>' + str(options) + '</td>\n')
|
||||
if (str(status) == 'OK'):
|
||||
@@ -374,7 +374,7 @@ class HTMLManagement():
|
||||
addOrangeBK = False
|
||||
self.htmlFile.write(' <tr>\n')
|
||||
self.htmlFile.write(' <td bgcolor = "lightcyan" >' + format(currentTime / 1000, '.1f') + '</td>\n')
|
||||
self.htmlFile.write(' <td bgcolor = "lightcyan" >' + self.testCaseIdx + '</td>\n')
|
||||
self.htmlFile.write(' <td bgcolor = "lightcyan" >' + self.testCase_id + '</td>\n')
|
||||
self.htmlFile.write(' <td>' + self.desc + '</td>\n')
|
||||
self.htmlFile.write(' <td>' + str(options) + '</td>\n')
|
||||
if (str(status) == 'OK'):
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#-----------------------------------------------------------
|
||||
# Import Libs
|
||||
#-----------------------------------------------------------
|
||||
import sys # arg
|
||||
import re # reg
|
||||
import time # sleep
|
||||
import os
|
||||
@@ -40,6 +41,7 @@ import concurrent.futures
|
||||
import json
|
||||
|
||||
#import our libs
|
||||
import helpreadme as HELP
|
||||
import constants as CONST
|
||||
|
||||
import cls_module
|
||||
@@ -231,10 +233,10 @@ def Custom_Command(HTML, node, command):
|
||||
HTML.CreateHtmlTestRowQueue(command, status, message)
|
||||
return status == 'OK' or status == 'Warning'
|
||||
|
||||
def Custom_Script(HTML, node, script, args):
|
||||
def Custom_Script(HTML, node, script):
|
||||
logging.info(f"Executing custom script on {node}")
|
||||
with cls_cmd.getConnection(node) as c:
|
||||
ret = c.exec_script(script, 90, args)
|
||||
ret = c.exec_script(script, 90)
|
||||
logging.debug(f"Custom_Script: {script} on node: {node} - return code {ret.returncode}, output:\n{ret.stdout}")
|
||||
status = 'OK'
|
||||
message = [ret.stdout]
|
||||
@@ -253,7 +255,7 @@ def Deploy_Physim(ctx, HTML, node, workdir, script, options):
|
||||
logging.debug(f'Running physims on server {node} workdir {workdir}')
|
||||
with cls_cmd.getConnection(node) as c:
|
||||
sys_info = c.exec_script("scripts/sys-info.sh", 5)
|
||||
ret = c.exec_script(script, 1500, options)
|
||||
ret = c.exec_script(script, 1000, options)
|
||||
logging.debug(f'"{script}" finished with code {ret.returncode}, output:\n{ret.stdout}')
|
||||
HTML.CreateHtmlTestRowQueue('Query system info', 'OK', [sys_info.stdout])
|
||||
with cls_cmd.getConnection(node) as ssh:
|
||||
@@ -297,15 +299,18 @@ class OaiCiTest():
|
||||
self.iperf_packetloss_threshold = ''
|
||||
self.iperf_bitrate_threshold = ''
|
||||
self.iperf_profile = ''
|
||||
self.iperf_options = ''
|
||||
self.iperf_tcp_rate_target = ''
|
||||
self.finalStatus = False
|
||||
self.air_interface=''
|
||||
self.ue_ids = []
|
||||
self.nodes = []
|
||||
self.svr_node = None
|
||||
self.svr_id = None
|
||||
self.cmd_prefix = '' # prefix before {lte,nr}-uesoftmodem
|
||||
|
||||
def InitializeUE(self, node, HTML):
|
||||
ues = [cls_module.Module_UE(n.strip(), node) for n in self.ue_ids]
|
||||
def InitializeUE(self, HTML):
|
||||
ues = [cls_module.Module_UE(n.strip()) for n in self.ue_ids]
|
||||
messages = []
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=64) as executor:
|
||||
futures = [executor.submit(ue.initialize) for ue in ues]
|
||||
@@ -316,8 +321,8 @@ class OaiCiTest():
|
||||
HTML.CreateHtmlTestRowQueue('N/A', 'OK', messages)
|
||||
return True
|
||||
|
||||
def AttachUE(self, node, HTML):
|
||||
ues = [cls_module.Module_UE(ue_id, node) for ue_id in self.ue_ids]
|
||||
def AttachUE(self, HTML):
|
||||
ues = [cls_module.Module_UE(ue_id, server_name) for ue_id, server_name in zip(self.ue_ids, self.nodes)]
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=64) as executor:
|
||||
futures = [executor.submit(ue.attach) for ue in ues]
|
||||
attached = [f.result() for f in futures]
|
||||
@@ -332,8 +337,8 @@ class OaiCiTest():
|
||||
HTML.CreateHtmlTestRowQueue('N/A', 'KO', ["Could not retrieve UE IP address(es) or MTU(s) wrong!"])
|
||||
return success
|
||||
|
||||
def DetachUE(self, node, HTML):
|
||||
ues = [cls_module.Module_UE(ue_id, node) for ue_id in self.ue_ids]
|
||||
def DetachUE(self, HTML):
|
||||
ues = [cls_module.Module_UE(ue_id, server_name) for ue_id, server_name in zip(self.ue_ids, self.nodes)]
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=64) as executor:
|
||||
futures = [executor.submit(ue.detach) for ue in ues]
|
||||
[f.result() for f in futures]
|
||||
@@ -341,8 +346,8 @@ class OaiCiTest():
|
||||
HTML.CreateHtmlTestRowQueue('NA', 'OK', messages)
|
||||
return True
|
||||
|
||||
def DataDisableUE(self, node, HTML):
|
||||
ues = [cls_module.Module_UE(n.strip(), node) for n in self.ue_ids]
|
||||
def DataDisableUE(self, HTML):
|
||||
ues = [cls_module.Module_UE(n.strip()) for n in self.ue_ids]
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=64) as executor:
|
||||
futures = [executor.submit(ue.dataDisable) for ue in ues]
|
||||
status = [f.result() for f in futures]
|
||||
@@ -355,8 +360,8 @@ class OaiCiTest():
|
||||
HTML.CreateHtmlTestRowQueue('N/A', 'KO', ["Could not disable UE data!"])
|
||||
return success
|
||||
|
||||
def DataEnableUE(self, node, HTML):
|
||||
ues = [cls_module.Module_UE(n.strip(), node) for n in self.ue_ids]
|
||||
def DataEnableUE(self, HTML):
|
||||
ues = [cls_module.Module_UE(n.strip()) for n in self.ue_ids]
|
||||
logging.debug(f'disabling data for UEs {ues}')
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=64) as executor:
|
||||
futures = [executor.submit(ue.dataEnable) for ue in ues]
|
||||
@@ -370,8 +375,8 @@ class OaiCiTest():
|
||||
HTML.CreateHtmlTestRowQueue('N/A', 'KO', ["Could not enable UE data!"])
|
||||
return success
|
||||
|
||||
def CheckStatusUE(self, node, HTML):
|
||||
ues = [cls_module.Module_UE(n.strip(), node) for n in self.ue_ids]
|
||||
def CheckStatusUE(self,HTML):
|
||||
ues = [cls_module.Module_UE(n.strip()) for n in self.ue_ids]
|
||||
logging.debug(f'checking status of UEs {ues}')
|
||||
messages = []
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=64) as executor:
|
||||
@@ -441,10 +446,10 @@ class OaiCiTest():
|
||||
|
||||
return (True, message)
|
||||
|
||||
def Ping(self, ctx, node, HTML, infra_file="ci_infra.yaml"):
|
||||
def Ping(self, ctx, HTML, infra_file="ci_infra.yaml"):
|
||||
if self.ue_ids == [] or self.svr_id == None:
|
||||
raise Exception("no module names in self.ue_ids or/and self.svr_id provided")
|
||||
ues = [cls_module.Module_UE(ue_id, node, infra_file) for ue_id in self.ue_ids]
|
||||
ues = [cls_module.Module_UE(ue_id, server_name, infra_file) for ue_id, server_name in zip(self.ue_ids, self.nodes)]
|
||||
cn = cls_corenetwork.CoreNetwork(self.svr_id, self.svr_node, filename=infra_file)
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=64) as executor:
|
||||
futures = [executor.submit(self.Ping_common, ctx, cn, ue) for ue in ues]
|
||||
@@ -498,11 +503,6 @@ class OaiCiTest():
|
||||
t = iperf_time * 2.5
|
||||
cmd_ue.run(f'rm {client_filename}', reportNonZero=False, silent=True)
|
||||
if cn.runIperf3Server():
|
||||
# Clean up any existing iperf3 server processes on this port.
|
||||
ret = cmd_svr.run(f"{cn.getCmdPrefix()} pkill -f '.*iperf3.*{port}'", reportNonZero=False)
|
||||
# If pkill succeeds, it means there was a leftover iperf3 server.
|
||||
if ret.returncode == 0:
|
||||
logging.warning(f'Iperf3 server on port {port} detected and terminated')
|
||||
cmd_svr.run(f'{cn.getCmdPrefix()} timeout -vk3 {t} iperf3 -s -B {svrIP} -p {port} -1 {jsonReport} >> /dev/null &', timeout=t)
|
||||
cmd_ue.run(f'{ue.getCmdPrefix()} timeout -vk3 {t} {iperf_ue} -B {ueIP} -c {svrIP} -p {port} {iperf_opt} {jsonReport} {serverReport} -O 5 >> {client_filename}', timeout=t)
|
||||
dest_filename = archiveArtifact(cmd_ue, ctx, client_filename)
|
||||
@@ -515,12 +515,12 @@ class OaiCiTest():
|
||||
|
||||
return (status, f'{ue_header}\n{msg}')
|
||||
|
||||
def Iperf(self, ctx, node, HTML, infra_file="ci_infra.yaml"):
|
||||
logging.debug(f'Iperf: iperf_args "{self.iperf_args}" iperf_packetloss_threshold "{self.iperf_packetloss_threshold}" iperf_bitrate_threshold "{self.iperf_bitrate_threshold}" iperf_profile "{self.iperf_profile}"')
|
||||
def Iperf(self, ctx, HTML, infra_file="ci_infra.yaml"):
|
||||
logging.debug(f'Iperf: iperf_args "{self.iperf_args}" iperf_packetloss_threshold "{self.iperf_packetloss_threshold}" iperf_bitrate_threshold "{self.iperf_bitrate_threshold}" iperf_profile "{self.iperf_profile}" iperf_options "{self.iperf_options}"')
|
||||
|
||||
if self.ue_ids == [] or self.svr_id == None:
|
||||
raise Exception("no module names in self.ue_ids or/and self.svr_id provided")
|
||||
ues = [cls_module.Module_UE(ue_id, node, infra_file) for ue_id in self.ue_ids]
|
||||
ues = [cls_module.Module_UE(ue_id, server_name, infra_file) for ue_id, server_name in zip(self.ue_ids, self.nodes)]
|
||||
cn = cls_corenetwork.CoreNetwork(self.svr_id, self.svr_node, filename=infra_file)
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=64) as executor:
|
||||
futures = [executor.submit(self.Iperf_Module, ctx, cn, ue, i, len(ues)) for i, ue in enumerate(ues)]
|
||||
@@ -544,10 +544,10 @@ class OaiCiTest():
|
||||
HTML.CreateHtmlTestRowQueue(self.iperf_args, 'KO', messages)
|
||||
return success
|
||||
|
||||
def Iperf2_Unidir(self, ctx, node, HTML, infra_file="ci_infra.yaml"):
|
||||
def Iperf2_Unidir(self, ctx, HTML, infra_file="ci_infra.yaml"):
|
||||
if self.ue_ids == [] or self.svr_id == None or len(self.ue_ids) != 1:
|
||||
raise Exception("no module names in self.ue_ids or/and self.svr_id provided, multi UE scenario not supported")
|
||||
ue = cls_module.Module_UE(self.ue_ids[0].strip(), node, infra_file)
|
||||
ue = cls_module.Module_UE(self.ue_ids[0].strip(),self.nodes[0].strip(), infra_file)
|
||||
cn = cls_corenetwork.CoreNetwork(self.svr_id, self.svr_node, filename=infra_file)
|
||||
ueIP = ue.getIP()
|
||||
if not ueIP:
|
||||
@@ -576,8 +576,279 @@ class OaiCiTest():
|
||||
HTML.CreateHtmlTestRowQueue(self.iperf_args, 'KO', [f'{ue_header}\n{msg}'])
|
||||
return success
|
||||
|
||||
def TerminateUE(self, ctx, node, HTML):
|
||||
ues = [cls_module.Module_UE(n.strip(), node) for n in self.ue_ids]
|
||||
def AnalyzeLogFile_UE(self, UElogFile,HTML,RAN):
|
||||
if (not os.path.isfile(f'{UElogFile}')):
|
||||
return -1
|
||||
ue_log_file = open(f'{UElogFile}', 'r')
|
||||
exitSignalReceived = False
|
||||
foundAssertion = False
|
||||
msgAssertion = ''
|
||||
msgLine = 0
|
||||
foundSegFault = False
|
||||
foundRealTimeIssue = False
|
||||
uciStatMsgCount = 0
|
||||
pdcpDataReqFailedCount = 0
|
||||
badDciCount = 0
|
||||
f1aRetransmissionCount = 0
|
||||
fatalErrorCount = 0
|
||||
macBsrTimerExpiredCount = 0
|
||||
rrcConnectionRecfgComplete = 0
|
||||
no_cell_sync_found = False
|
||||
mib_found = False
|
||||
frequency_found = False
|
||||
plmn_found = False
|
||||
nrUEFlag = False
|
||||
nrDecodeMib = 0
|
||||
nrFoundDCI = 0
|
||||
nrCRCOK = 0
|
||||
mbms_messages = 0
|
||||
nbPduSessAccept = 0
|
||||
nbPduDiscard = 0
|
||||
HTML.htmlUEFailureMsg=''
|
||||
global_status = CONST.ALL_PROCESSES_OK
|
||||
for line in ue_log_file.readlines():
|
||||
result = re.search('nr_synchro_time|Starting NR UE soft modem', str(line))
|
||||
sidelink = re.search('sl-mode', str(line))
|
||||
if result is not None:
|
||||
nrUEFlag = True
|
||||
if sidelink is not None:
|
||||
nrUEFlag = False
|
||||
if nrUEFlag:
|
||||
result = re.search('decode mib', str(line))
|
||||
if result is not None:
|
||||
nrDecodeMib += 1
|
||||
result = re.search('found 1 DCIs', str(line))
|
||||
if result is not None:
|
||||
nrFoundDCI += 1
|
||||
result = re.search('CRC OK', str(line))
|
||||
if result is not None:
|
||||
nrCRCOK += 1
|
||||
result = re.search('Received PDU Session Establishment Accept', str(line))
|
||||
if result is not None:
|
||||
nbPduSessAccept += 1
|
||||
result = re.search('warning: discard PDU, sn out of window', str(line))
|
||||
if result is not None:
|
||||
nbPduDiscard += 1
|
||||
result = re.search('--nfapi STANDALONE_PNF --node-number 2', str(line))
|
||||
if result is not None:
|
||||
frequency_found = True
|
||||
result = re.search('Exiting OAI softmodem', str(line))
|
||||
if result is not None:
|
||||
exitSignalReceived = True
|
||||
result = re.search('System error|[Ss]egmentation [Ff]ault|======= Backtrace: =========|======= Memory map: ========', str(line))
|
||||
if result is not None and not exitSignalReceived:
|
||||
foundSegFault = True
|
||||
result = re.search('[Cc]ore [dD]ump', str(line))
|
||||
if result is not None and not exitSignalReceived:
|
||||
foundSegFault = True
|
||||
result = re.search('[Aa]ssertion', str(line))
|
||||
if result is not None and not exitSignalReceived:
|
||||
foundAssertion = True
|
||||
result = re.search('LLL', str(line))
|
||||
if result is not None and not exitSignalReceived:
|
||||
foundRealTimeIssue = True
|
||||
if foundAssertion and (msgLine < 3):
|
||||
msgLine += 1
|
||||
msgAssertion += str(line)
|
||||
result = re.search('uci->stat', str(line))
|
||||
if result is not None and not exitSignalReceived:
|
||||
uciStatMsgCount += 1
|
||||
result = re.search('PDCP data request failed', str(line))
|
||||
if result is not None and not exitSignalReceived:
|
||||
pdcpDataReqFailedCount += 1
|
||||
result = re.search('bad DCI 1', str(line))
|
||||
if result is not None and not exitSignalReceived:
|
||||
badDciCount += 1
|
||||
result = re.search('Format1A Retransmission but TBS are different', str(line))
|
||||
if result is not None and not exitSignalReceived:
|
||||
f1aRetransmissionCount += 1
|
||||
result = re.search('FATAL ERROR', str(line))
|
||||
if result is not None and not exitSignalReceived:
|
||||
fatalErrorCount += 1
|
||||
result = re.search('MAC BSR Triggered ReTxBSR Timer expiry', str(line))
|
||||
if result is not None and not exitSignalReceived:
|
||||
macBsrTimerExpiredCount += 1
|
||||
result = re.search('Generating RRCConnectionReconfigurationComplete', str(line))
|
||||
if result is not None:
|
||||
rrcConnectionRecfgComplete += 1
|
||||
# No cell synchronization found, abandoning
|
||||
result = re.search('No cell synchronization found, abandoning', str(line))
|
||||
if result is not None:
|
||||
no_cell_sync_found = True
|
||||
if RAN.eNBmbmsEnables[0]:
|
||||
result = re.search('TRIED TO PUSH MBMS DATA', str(line))
|
||||
if result is not None:
|
||||
mbms_messages += 1
|
||||
result = re.search(r"MIB Information => ([a-zA-Z]{1,10}), ([a-zA-Z]{1,10}), NidCell (?P<nidcell>\d{1,3}), N_RB_DL (?P<n_rb_dl>\d{1,3}), PHICH DURATION (?P<phich_duration>\d), PHICH RESOURCE (?P<phich_resource>.{1,4}), TX_ANT (?P<tx_ant>\d)", str(line))
|
||||
if result is not None and (not mib_found):
|
||||
try:
|
||||
mibMsg = "MIB Information: " + result.group(1) + ', ' + result.group(2)
|
||||
HTML.htmlUEFailureMsg=HTML.htmlUEFailureMsg + mibMsg + '\n'
|
||||
logging.debug(f'\033[94m{mibMsg}\033[0m')
|
||||
mibMsg = " nidcell = " + result.group('nidcell')
|
||||
HTML.htmlUEFailureMsg=HTML.htmlUEFailureMsg + mibMsg
|
||||
logging.debug(f'\033[94m{mibMsg}\033[0m')
|
||||
mibMsg = " n_rb_dl = " + result.group('n_rb_dl')
|
||||
HTML.htmlUEFailureMsg=HTML.htmlUEFailureMsg + mibMsg + '\n'
|
||||
logging.debug(f'\033[94m{mibMsg}\033[0m')
|
||||
mibMsg = " phich_duration = " + result.group('phich_duration')
|
||||
HTML.htmlUEFailureMsg=HTML.htmlUEFailureMsg + mibMsg
|
||||
logging.debug(f'\033[94m{mibMsg}\033[0m')
|
||||
mibMsg = " phich_resource = " + result.group('phich_resource')
|
||||
HTML.htmlUEFailureMsg=HTML.htmlUEFailureMsg + mibMsg + '\n'
|
||||
logging.debug(f'\033[94m{mibMsg}\033[0m')
|
||||
mibMsg = " tx_ant = " + result.group('tx_ant')
|
||||
HTML.htmlUEFailureMsg=HTML.htmlUEFailureMsg + mibMsg + '\n'
|
||||
logging.debug(f'\033[94m{mibMsg}\033[0m')
|
||||
mib_found = True
|
||||
except Exception as e:
|
||||
logging.error(f'\033[91m MIB marker was not found \033[0m')
|
||||
result = re.search("Initial sync: pbch decoded sucessfully", str(line))
|
||||
if result is not None and (not frequency_found):
|
||||
try:
|
||||
mibMsg = f"UE decoded PBCH successfully"
|
||||
HTML.htmlUEFailureMsg=HTML.htmlUEFailureMsg + mibMsg + '\n'
|
||||
logging.debug(f'\033[94m{mibMsg}\033[0m')
|
||||
frequency_found = True
|
||||
except Exception as e:
|
||||
logging.error(f'\033[91m UE did not find PBCH\033[0m')
|
||||
result = re.search(r"PLMN MCC (?P<mcc>\d{1,3}), MNC (?P<mnc>\d{1,3}), TAC", str(line))
|
||||
if result is not None and (not plmn_found):
|
||||
try:
|
||||
mibMsg = f"PLMN MCC = {result.group('mcc')} MNC = {result.group('mnc')}"
|
||||
HTML.htmlUEFailureMsg=HTML.htmlUEFailureMsg + mibMsg + '\n'
|
||||
logging.debug(f'\033[94m{mibMsg}\033[0m')
|
||||
plmn_found = True
|
||||
except Exception as e:
|
||||
logging.error(f'\033[91m PLMN not found \033[0m')
|
||||
result = re.search(r"Found (?P<operator>[\w,\s]{1,15}) \(name from internal table\)", str(line))
|
||||
if result is not None:
|
||||
try:
|
||||
mibMsg = f"The operator is: {result.group('operator')}"
|
||||
HTML.htmlUEFailureMsg=HTML.htmlUEFailureMsg + mibMsg + '\n'
|
||||
logging.debug(f'\033[94m{mibMsg}\033[0m')
|
||||
except Exception as e:
|
||||
logging.error(f'\033[91m Operator name not found \033[0m')
|
||||
result = re.search("SIB5 InterFreqCarrierFreq element (.{1,4})/(.{1,4})", str(line))
|
||||
if result is not None:
|
||||
try:
|
||||
mibMsg = f'SIB5 InterFreqCarrierFreq element {result.group(1)}/{result.group(2)}'
|
||||
HTML.htmlUEFailureMsg=HTML.htmlUEFailureMsg + mibMsg + ' -> '
|
||||
logging.debug(f'\033[94m{mibMsg}\033[0m')
|
||||
except Exception as e:
|
||||
logging.error(f'\033[91m SIB5 InterFreqCarrierFreq element not found \033[0m')
|
||||
result = re.search(r"DL Carrier Frequency/ARFCN : \-*(?P<carrier_frequency>\d{1,15}/\d{1,4})", str(line))
|
||||
if result is not None:
|
||||
try:
|
||||
freq = result.group('carrier_frequency')
|
||||
new_freq = re.sub('/[0-9]+','',freq)
|
||||
float_freq = float(new_freq) / 1000000
|
||||
HTML.htmlUEFailureMsg=HTML.htmlUEFailureMsg + 'DL Freq: ' + ('%.1f' % float_freq) + ' MHz'
|
||||
logging.debug(f'\033[94m DL Carrier Frequency is: {freq}\033[0m')
|
||||
except Exception as e:
|
||||
logging.error(f'\033[91m DL Carrier Frequency not found \033[0m')
|
||||
result = re.search(r"AllowedMeasBandwidth : (?P<allowed_bandwidth>\d{1,7})", str(line))
|
||||
if result is not None:
|
||||
try:
|
||||
prb = result.group('allowed_bandwidth')
|
||||
HTML.htmlUEFailureMsg=HTML.htmlUEFailureMsg + ' -- PRB: ' + prb + '\n'
|
||||
logging.debug(f'\033[94m AllowedMeasBandwidth: {prb}\033[0m')
|
||||
except Exception as e:
|
||||
logging.error(f'\033[91m AllowedMeasBandwidth not found \033[0m')
|
||||
ue_log_file.close()
|
||||
if rrcConnectionRecfgComplete > 0:
|
||||
statMsg = f'UE connected to eNB ({rrcConnectionRecfgComplete}) RRCConnectionReconfigurationComplete message(s) generated)'
|
||||
logging.debug(f'\033[94m{statMsg}\033[0m')
|
||||
HTML.htmlUEFailureMsg=HTML.htmlUEFailureMsg + statMsg + '\n'
|
||||
if nrUEFlag:
|
||||
if nrDecodeMib > 0:
|
||||
statMsg = f'UE showed {nrDecodeMib} "MIB decode" message(s)'
|
||||
logging.debug(f'\u001B[1;30;43m{statMsg}\u001B[0m')
|
||||
HTML.htmlUEFailureMsg=HTML.htmlUEFailureMsg + statMsg + '\n'
|
||||
if nrFoundDCI > 0:
|
||||
statMsg = f'UE showed {nrFoundDCI} "DCI found" message(s)'
|
||||
logging.debug(f'\u001B[1;30;43m{statMsg}\u001B[0m')
|
||||
HTML.htmlUEFailureMsg=HTML.htmlUEFailureMsg + statMsg + '\n'
|
||||
if nrCRCOK > 0:
|
||||
statMsg = f'UE showed {nrCRCOK} "PDSCH decoding" message(s)'
|
||||
logging.debug(f'\u001B[1;30;43m{statMsg}\u001B[0m')
|
||||
HTML.htmlUEFailureMsg=HTML.htmlUEFailureMsg + statMsg + '\n'
|
||||
if not frequency_found:
|
||||
statMsg = 'NR-UE could NOT synch!'
|
||||
logging.error(f'\u001B[1;30;43m{statMsg}\u001B[0m')
|
||||
HTML.htmlUEFailureMsg=HTML.htmlUEFailureMsg + statMsg + '\n'
|
||||
if nbPduSessAccept > 0:
|
||||
statMsg = f'UE showed {nbPduSessAccept} "Received PDU Session Establishment Accept" message(s)'
|
||||
logging.debug(f'\u001B[1;30;43m{statMsg}\u001B[0m')
|
||||
HTML.htmlUEFailureMsg=HTML.htmlUEFailureMsg + statMsg + '\n'
|
||||
if nbPduDiscard > 0:
|
||||
statMsg = f'UE showed {nbPduDiscard} "warning: discard PDU, sn out of window" message(s)'
|
||||
logging.debug(f'\u001B[1;30;43m{statMsg}\u001B[0m')
|
||||
HTML.htmlUEFailureMsg=HTML.htmlUEFailureMsg + statMsg + '\n'
|
||||
if uciStatMsgCount > 0:
|
||||
statMsg = f'UE showed {uciStatMsgCount} "uci->stat" message(s)'
|
||||
logging.debug(f'\u001B[1;30;43m{statMsg}\u001B[0m')
|
||||
HTML.htmlUEFailureMsg=HTML.htmlUEFailureMsg + statMsg + '\n'
|
||||
if pdcpDataReqFailedCount > 0:
|
||||
statMsg = f'UE showed {pdcpDataReqFailedCount} "PDCP data request failed" message(s)'
|
||||
logging.debug(f'\u001B[1;30;43m{statMsg}\u001B[0m')
|
||||
HTML.htmlUEFailureMsg=HTML.htmlUEFailureMsg + statMsg + '\n'
|
||||
if badDciCount > 0:
|
||||
statMsg = f'UE showed {badDciCount} "bad DCI 1(A)" message(s)'
|
||||
logging.debug(f'\u001B[1;30;43m{statMsg}\u001B[0m')
|
||||
HTML.htmlUEFailureMsg=HTML.htmlUEFailureMsg + statMsg + '\n'
|
||||
if f1aRetransmissionCount > 0:
|
||||
statMsg = f'UE showed {f1aRetransmissionCount} "Format1A Retransmission but TBS are different" message(s)'
|
||||
logging.debug(f'\u001B[1;30;43m{statMsg}\u001B[0m')
|
||||
HTML.htmlUEFailureMsg=HTML.htmlUEFailureMsg + statMsg + '\n'
|
||||
if fatalErrorCount > 0:
|
||||
statMsg = f'UE showed {fatalErrorCount} "FATAL ERROR:" message(s)'
|
||||
logging.debug(f'\u001B[1;30;43m{statMsg}\u001B[0m')
|
||||
HTML.htmlUEFailureMsg=HTML.htmlUEFailureMsg + statMsg + '\n'
|
||||
if macBsrTimerExpiredCount > 0:
|
||||
statMsg = f'UE showed {fatalErrorCount} "MAC BSR Triggered ReTxBSR Timer expiry" message(s)'
|
||||
logging.debug(f'\u001B[1;30;43m{statMsg}\u001B[0m')
|
||||
HTML.htmlUEFailureMsg=HTML.htmlUEFailureMsg + statMsg + '\n'
|
||||
if RAN.eNBmbmsEnables[0]:
|
||||
if mbms_messages > 0:
|
||||
statMsg = f'UE showed {mbms_messages} "TRIED TO PUSH MBMS DATA" message(s)'
|
||||
logging.debug(f'\u001B[1;30;43m{statMsg}\u001B[0m')
|
||||
else:
|
||||
statMsg = 'UE did NOT SHOW "TRIED TO PUSH MBMS DATA" message(s)'
|
||||
logging.debug(f'\u001B[1;30;41m{statMsg}\u001B[0m')
|
||||
global_status = CONST.OAI_UE_PROCESS_NO_MBMS_MSGS
|
||||
HTML.htmlUEFailureMsg=HTML.htmlUEFailureMsg + statMsg + '\n'
|
||||
if foundSegFault:
|
||||
logging.debug('\u001B[1;37;41m UE ended with a Segmentation Fault! \u001B[0m')
|
||||
if not nrUEFlag:
|
||||
global_status = CONST.OAI_UE_PROCESS_SEG_FAULT
|
||||
else:
|
||||
if not frequency_found:
|
||||
global_status = CONST.OAI_UE_PROCESS_SEG_FAULT
|
||||
if foundAssertion:
|
||||
logging.debug('\u001B[1;30;43m UE showed an assertion! \u001B[0m')
|
||||
HTML.htmlUEFailureMsg=HTML.htmlUEFailureMsg + 'UE showed an assertion!\n'
|
||||
if not nrUEFlag:
|
||||
if not mib_found or not frequency_found:
|
||||
global_status = CONST.OAI_UE_PROCESS_ASSERTION
|
||||
else:
|
||||
if not frequency_found:
|
||||
global_status = CONST.OAI_UE_PROCESS_ASSERTION
|
||||
if foundRealTimeIssue:
|
||||
logging.debug('\u001B[1;37;41m UE faced real time issues! \u001B[0m')
|
||||
HTML.htmlUEFailureMsg=HTML.htmlUEFailureMsg + 'UE faced real time issues!\n'
|
||||
if nrUEFlag:
|
||||
if not frequency_found:
|
||||
global_status = CONST.OAI_UE_PROCESS_COULD_NOT_SYNC
|
||||
else:
|
||||
if no_cell_sync_found and not mib_found:
|
||||
logging.debug('\u001B[1;37;41m UE could not synchronize ! \u001B[0m')
|
||||
HTML.htmlUEFailureMsg=HTML.htmlUEFailureMsg + 'UE could not synchronize!\n'
|
||||
global_status = CONST.OAI_UE_PROCESS_COULD_NOT_SYNC
|
||||
return global_status
|
||||
|
||||
def TerminateUE(self, ctx, HTML):
|
||||
ues = [cls_module.Module_UE(n.strip()) for n in self.ue_ids]
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=64) as executor:
|
||||
futures = [executor.submit(ue.terminate, ctx) for ue in ues]
|
||||
archives = [f.result() for f in futures]
|
||||
|
||||
@@ -88,8 +88,9 @@ class StaticCodeAnalysis():
|
||||
raise ValueError(f"{lSourcePath=} {node=}")
|
||||
logging.debug('Building on server: ' + node)
|
||||
cmd = cls_cmd.getConnection(node)
|
||||
self.testCase_id = HTML.testCase_id
|
||||
# on RedHat/CentOS .git extension is mandatory
|
||||
result = re.search(r'([a-zA-Z0-9\:\-\.\/])+\.git', self.ranRepository)
|
||||
result = re.search('([a-zA-Z0-9\:\-\.\/])+\.git', self.ranRepository)
|
||||
if result is not None:
|
||||
full_ran_repo_name = self.ranRepository.replace('git/', 'git')
|
||||
else:
|
||||
@@ -121,7 +122,7 @@ class StaticCodeAnalysis():
|
||||
xmlStart = False
|
||||
with open(filename, 'r') as logfile:
|
||||
for line in logfile:
|
||||
ret = re.search(r'cppcheck version="(?P<version>[0-9\.]+)"', str(line))
|
||||
ret = re.search('cppcheck version="(?P<version>[0-9\.]+)"', str(line))
|
||||
if ret is not None:
|
||||
CCR.versions[vId] = ret.group('version')
|
||||
if re.search('RUN cat cmake_targets/log/cppcheck.xml', str(line)) is not None:
|
||||
@@ -186,6 +187,8 @@ class StaticCodeAnalysis():
|
||||
raise ValueError(f"{lSourcePath=} {node=}")
|
||||
logging.debug('Building on server: ' + node)
|
||||
cmd = cls_cmd.getConnection(node)
|
||||
self.testCase_id = HTML.testCase_id
|
||||
|
||||
check_options = ''
|
||||
if self.ranAllowMerge:
|
||||
check_options = f'--build-arg MERGE_REQUEST=true --build-arg SRC_BRANCH={self.ranBranch}'
|
||||
|
||||
@@ -200,11 +200,9 @@ RUs = (
|
||||
}
|
||||
);
|
||||
|
||||
rfsimulator = (
|
||||
{
|
||||
rfsimulator: {
|
||||
serveraddr = "server";
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
THREAD_STRUCT = (
|
||||
{
|
||||
|
||||
@@ -233,11 +233,9 @@ RUs =
|
||||
}
|
||||
);
|
||||
|
||||
rfsimulator = (
|
||||
{
|
||||
rfsimulator: {
|
||||
serveraddr = "server";
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
THREAD_STRUCT =
|
||||
(
|
||||
|
||||
@@ -233,11 +233,9 @@ RUs =
|
||||
}
|
||||
);
|
||||
|
||||
rfsimulator = (
|
||||
{
|
||||
rfsimulator: {
|
||||
serveraddr = "server";
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
THREAD_STRUCT =
|
||||
(
|
||||
|
||||
@@ -233,11 +233,9 @@ RUs =
|
||||
}
|
||||
);
|
||||
|
||||
rfsimulator = (
|
||||
{
|
||||
rfsimulator: {
|
||||
serveraddr = "server";
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
THREAD_STRUCT =
|
||||
(
|
||||
|
||||
@@ -233,11 +233,9 @@ RUs =
|
||||
}
|
||||
);
|
||||
|
||||
rfsimulator = (
|
||||
{
|
||||
rfsimulator: {
|
||||
serveraddr = "server";
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
THREAD_STRUCT =
|
||||
(
|
||||
|
||||
@@ -362,11 +362,9 @@ RUs = (
|
||||
}
|
||||
);
|
||||
|
||||
rfsimulator = (
|
||||
{
|
||||
rfsimulator: {
|
||||
serveraddr = "server";
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
THREAD_STRUCT = (
|
||||
{
|
||||
|
||||
@@ -53,7 +53,7 @@ security = {
|
||||
# preferred ciphering algorithms
|
||||
# the first one of the list that an UE supports in chosen
|
||||
# valid values: nea0, nea1, nea2, nea3
|
||||
ciphering_algorithms = ( "nea2", "nea0" );
|
||||
ciphering_algorithms = ( "nea0" );
|
||||
|
||||
# preferred integrity algorithms
|
||||
# the first one of the list that an UE supports in chosen
|
||||
@@ -63,7 +63,7 @@ security = {
|
||||
# setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter
|
||||
# what 'ciphering_algorithms' configures; same thing for 'drb_integrity'
|
||||
drb_ciphering = "yes";
|
||||
drb_integrity = "yes";
|
||||
drb_integrity = "no";
|
||||
};
|
||||
|
||||
log_config :
|
||||
|
||||
@@ -21,10 +21,10 @@ gNBs =
|
||||
|
||||
tr_s_preference = "f1";
|
||||
|
||||
local_s_address = "192.168.71.150";
|
||||
local_s_address = "192.168.71.150";
|
||||
remote_s_address = "192.168.71.171";
|
||||
local_s_portd = 2153;
|
||||
remote_s_portd = 2153;
|
||||
local_s_portd = 2153;
|
||||
remote_s_portd = 2153;
|
||||
|
||||
# ------- SCTP definitions
|
||||
SCTP :
|
||||
@@ -41,7 +41,7 @@ gNBs =
|
||||
E1_INTERFACE =
|
||||
(
|
||||
{
|
||||
type = "cp";
|
||||
type = "cp";
|
||||
ipv4_cucp = "192.168.71.150";
|
||||
port_cucp = 38462;
|
||||
ipv4_cuup = "0.0.0.0"; # multiple CU-UPs
|
||||
@@ -75,8 +75,8 @@ security = {
|
||||
|
||||
log_config : {
|
||||
global_log_level = "info";
|
||||
pdcp_log_level = "info";
|
||||
rrc_log_level = "info";
|
||||
f1ap_log_level = "info";
|
||||
ngap_log_level = "info";
|
||||
pdcp_log_level = "info";
|
||||
rrc_log_level = "info";
|
||||
f1ap_log_level = "info";
|
||||
ngap_log_level = "info";
|
||||
};
|
||||
|
||||
@@ -197,15 +197,13 @@ RUs = (
|
||||
}
|
||||
);
|
||||
|
||||
rfsimulator = (
|
||||
{
|
||||
serveraddr = "server";
|
||||
rfsimulator: {
|
||||
serveraddr = "server";
|
||||
serverport = 4043;
|
||||
options = (); #("saviq"); or/and "chanmod"
|
||||
modelname = "AWGN";
|
||||
IQfile = "/tmp/rfsimulator.iqs";
|
||||
}
|
||||
);
|
||||
IQfile = "/tmp/rfsimulator.iqs"
|
||||
}
|
||||
|
||||
log_config: {
|
||||
global_log_level = "info";
|
||||
|
||||
@@ -23,6 +23,7 @@ gNBs =
|
||||
////////// Physical parameters:
|
||||
|
||||
min_rxtxtime = 2;
|
||||
do_CSIRS = 1;
|
||||
do_SRS = 1;
|
||||
|
||||
servingCellConfigCommon = (
|
||||
@@ -146,11 +147,7 @@ gNBs =
|
||||
);
|
||||
|
||||
first_active_bwp = 1;
|
||||
bwp_list = (
|
||||
{ scs = 1; bwpStart = 0; bwpSize = 106;},
|
||||
{ scs = 1; bwpStart = 0; bwpSize = 36;},
|
||||
{ scs = 1; bwpStart = 40; bwpSize = 50;}
|
||||
);
|
||||
bwp_list = ({ scs = 1; bwpStart = 0; bwpSize = 106;});
|
||||
|
||||
# ------- SCTP definitions
|
||||
SCTP :
|
||||
|
||||
@@ -27,15 +27,14 @@ RUs = ({
|
||||
eNB_instances = [0];
|
||||
});
|
||||
|
||||
rfsimulator = (
|
||||
rfsimulator :
|
||||
{
|
||||
serveraddr = "server";
|
||||
serverport = 4043;
|
||||
options = (); #("saviq"); or/and "chanmod"
|
||||
modelname = "AWGN";
|
||||
IQfile = "/tmp/rfsimulator.iqs";
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
log_config: {
|
||||
global_log_level = "info";
|
||||
|
||||
@@ -16,6 +16,8 @@ gNBs =
|
||||
nr_cellid = 12345678L;
|
||||
|
||||
////////// Physical parameters:
|
||||
|
||||
sib1_tda = 5;
|
||||
min_rxtxtime = 6;
|
||||
|
||||
servingCellConfigCommon = (
|
||||
|
||||
@@ -13,7 +13,16 @@ gNBs =
|
||||
|
||||
// Tracking area code, 0x0000 and 0xfffe are reserved values
|
||||
tracking_area_code = 1;
|
||||
plmn_list = ({ mcc = 208; mnc = 97; mnc_length = 2; snssaiList = ({ sst = 1; }) });
|
||||
plmn_list = ({
|
||||
mcc = 208;
|
||||
mnc = 97;
|
||||
mnc_length = 2;
|
||||
snssaiList = (
|
||||
{
|
||||
sst = 1;
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
nr_cellid = 12345678L;
|
||||
|
||||
@@ -23,7 +32,7 @@ gNBs =
|
||||
pdsch_AntennaPorts_N1 = 2;
|
||||
pusch_AntennaPorts = 2;
|
||||
do_CSIRS = 1;
|
||||
do_SRS = 1;
|
||||
do_SRS = 0;
|
||||
min_rxtxtime = 2;
|
||||
|
||||
servingCellConfigCommon = (
|
||||
@@ -146,7 +155,7 @@ gNBs =
|
||||
nrofUplinkSlots = 3; #1;
|
||||
nrofUplinkSymbols = 0;
|
||||
|
||||
ssPBCH_BlockPower = -15;
|
||||
ssPBCH_BlockPower = -25;
|
||||
}
|
||||
|
||||
);
|
||||
@@ -167,8 +176,8 @@ gNBs =
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.16.53";
|
||||
GNB_IPV4_ADDRESS_FOR_NGU = "172.21.16.53";
|
||||
GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.16.202";
|
||||
GNB_IPV4_ADDRESS_FOR_NGU = "172.21.16.202";
|
||||
GNB_PORT_FOR_S1U = 2152; # Spec 2152
|
||||
};
|
||||
|
||||
@@ -177,19 +186,19 @@ gNBs =
|
||||
|
||||
MACRLCs = (
|
||||
{
|
||||
num_cc = 1;
|
||||
remote_s_address = "127.0.0.1"; // pnf addr [!]
|
||||
local_s_address = "127.0.0.2"; // vnf addr
|
||||
local_s_portc = 50001; // vnf p5 port
|
||||
remote_s_portc = 50000; // pnf p5 port [!]
|
||||
local_s_portd = 50011; // vnf p7 port [!]
|
||||
remote_s_portd = 50010; // pnf p7 port [!]
|
||||
tr_s_preference = "aerial";
|
||||
tr_n_preference = "local_RRC";
|
||||
pusch_TargetSNRx10 = 280; # 150;
|
||||
pucch_TargetSNRx10 = 200; #200;
|
||||
dl_max_mcs = 28;
|
||||
ul_max_mcs = 28;
|
||||
num_cc = 1;
|
||||
remote_s_address = "127.0.0.1"; // pnf addr [!]
|
||||
local_s_address = "127.0.0.2"; // vnf addr
|
||||
local_s_portc = 50001; // vnf p5 port
|
||||
remote_s_portc = 50000; // pnf p5 port [!]
|
||||
local_s_portd = 50011; // vnf p7 port [!]
|
||||
remote_s_portd = 50010; // pnf p7 port [!]
|
||||
tr_s_preference = "aerial";
|
||||
tr_n_preference = "local_RRC";
|
||||
pusch_TargetSNRx10 = 200; # 150;
|
||||
pucch_TargetSNRx10 = 200; #200;
|
||||
dl_max_mcs = 28;
|
||||
ul_max_mcs = 28;
|
||||
}
|
||||
);
|
||||
|
||||
@@ -213,13 +222,13 @@ security = {
|
||||
|
||||
log_config :
|
||||
{
|
||||
global_log_level ="info";
|
||||
hw_log_level ="info";
|
||||
phy_log_level ="info";
|
||||
mac_log_level ="info";
|
||||
rlc_log_level ="info";
|
||||
pdcp_log_level ="info";
|
||||
rrc_log_level ="info";
|
||||
ngap_log_level ="debug";
|
||||
f1ap_log_level ="debug";
|
||||
global_log_level ="info";
|
||||
hw_log_level ="info";
|
||||
phy_log_level ="info";
|
||||
mac_log_level ="info";
|
||||
rlc_log_level ="info";
|
||||
pdcp_log_level ="info";
|
||||
rrc_log_level ="info";
|
||||
ngap_log_level ="debug";
|
||||
f1ap_log_level ="debug";
|
||||
};
|
||||
|
||||
@@ -24,9 +24,9 @@ gNBs =
|
||||
pdsch_AntennaPorts_N1 = 2;
|
||||
pusch_AntennaPorts = 2;
|
||||
do_CSIRS = 1;
|
||||
do_SRS = 1;
|
||||
do_SRS = 0;
|
||||
min_rxtxtime = 2;
|
||||
force_UL256qam_off = 1;
|
||||
|
||||
servingCellConfigCommon = (
|
||||
{
|
||||
#spCellConfigCommon
|
||||
@@ -168,8 +168,8 @@ gNBs =
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.16.53";
|
||||
GNB_IPV4_ADDRESS_FOR_NGU = "172.21.16.53";
|
||||
GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.16.202";
|
||||
GNB_IPV4_ADDRESS_FOR_NGU = "172.21.16.202";
|
||||
GNB_PORT_FOR_S1U = 2152; # Spec 2152
|
||||
};
|
||||
|
||||
@@ -187,7 +187,7 @@ MACRLCs = (
|
||||
remote_s_portd = 50010; // pnf p7 port [!]
|
||||
tr_s_preference = "aerial";
|
||||
tr_n_preference = "local_RRC";
|
||||
pusch_TargetSNRx10 = 260; # 150;
|
||||
pusch_TargetSNRx10 = 220; # 150;
|
||||
pucch_TargetSNRx10 = 200; #200;
|
||||
dl_max_mcs = 28;
|
||||
ul_max_mcs = 28;
|
||||
|
||||
@@ -191,11 +191,10 @@ RUs = (
|
||||
}
|
||||
);
|
||||
|
||||
rfsimulator = (
|
||||
{
|
||||
rfsimulator: {
|
||||
serveraddr = "server";
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
security = {
|
||||
# preferred ciphering algorithms
|
||||
|
||||
@@ -195,16 +195,14 @@ RUs = (
|
||||
max_pdschReferenceSignalPower = -27;
|
||||
max_rxgain = 50;
|
||||
eNB_instances = [0];
|
||||
sl_ahead = 3;
|
||||
sdr_addrs = "addr=192.168.10.2,second_addr=192.168.20.2";
|
||||
}
|
||||
);
|
||||
|
||||
rfsimulator = (
|
||||
{
|
||||
rfsimulator: {
|
||||
serveraddr = "server";
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
security = {
|
||||
# preferred ciphering algorithms
|
||||
|
||||
@@ -234,15 +234,14 @@ RUs = (
|
||||
}
|
||||
);
|
||||
|
||||
rfsimulator = (
|
||||
rfsimulator :
|
||||
{
|
||||
serveraddr = "server";
|
||||
serverport = 4043;
|
||||
options = ("chanmod"); #("saviq"); or/and "chanmod"
|
||||
prop_delay = 20;
|
||||
IQfile = "/tmp/rfsimulator.iqs";
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
channelmod = {
|
||||
max_chan=10;
|
||||
|
||||
@@ -242,15 +242,14 @@ RUs = (
|
||||
}
|
||||
);
|
||||
|
||||
rfsimulator = (
|
||||
rfsimulator :
|
||||
{
|
||||
serveraddr = "server";
|
||||
serverport = 4043;
|
||||
options = (); #("saviq"); or/and "chanmod"
|
||||
prop_delay = 238.74;
|
||||
IQfile = "/tmp/rfsimulator.iqs";
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
security = {
|
||||
# preferred ciphering algorithms
|
||||
|
||||
@@ -18,6 +18,8 @@ gNBs =
|
||||
tr_s_preference = "local_mac"
|
||||
|
||||
////////// Physical parameters:
|
||||
|
||||
sib1_tda = 15;
|
||||
min_rxtxtime = 6;
|
||||
|
||||
servingCellConfigCommon = (
|
||||
@@ -29,46 +31,46 @@ gNBs =
|
||||
# downlinkConfigCommon
|
||||
#frequencyInfoDL
|
||||
# this is pointA + 16 PRBs@120kHz SCS (same as initial BWP)
|
||||
absoluteFrequencySSB = 2078299;
|
||||
dl_frequencyBand = 257;
|
||||
absoluteFrequencySSB = 2071387;
|
||||
dl_frequencyBand = 261;
|
||||
# this is 27.900 GHz
|
||||
dl_absoluteFrequencyPointA = 2077963;
|
||||
dl_absoluteFrequencyPointA = 2071001;
|
||||
#scs-SpecificCarrierList
|
||||
dl_offstToCarrier = 0;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
dl_subcarrierSpacing = 3;
|
||||
dl_carrierBandwidth = 66;
|
||||
dl_carrierBandwidth = 32;
|
||||
#initialDownlinkBWP
|
||||
#genericParameters
|
||||
# this is RBstart=0,L=32 (275*(L-1))+RBstart
|
||||
initialDLBWPlocationAndBandwidth = 6349;
|
||||
initialDLBWPlocationAndBandwidth = 8525;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
initialDLBWPsubcarrierSpacing = 3;
|
||||
#pdcch-ConfigCommon
|
||||
initialDLBWPcontrolResourceSetZero = 4;
|
||||
initialDLBWPcontrolResourceSetZero = 1;
|
||||
initialDLBWPsearchSpaceZero = 0;
|
||||
|
||||
#uplinkConfigCommon
|
||||
#frequencyInfoUL
|
||||
ul_frequencyBand = 257;
|
||||
ul_frequencyBand = 261;
|
||||
#scs-SpecificCarrierList
|
||||
ul_offstToCarrier = 0;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
ul_subcarrierSpacing = 3;
|
||||
ul_carrierBandwidth = 66;
|
||||
ul_carrierBandwidth = 32;
|
||||
pMax = 20;
|
||||
#initialUplinkBWP
|
||||
#genericParameters
|
||||
initialULBWPlocationAndBandwidth = 6349;
|
||||
initialULBWPlocationAndBandwidth = 8525;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
initialULBWPsubcarrierSpacing = 3;
|
||||
#rach-ConfigCommon
|
||||
#rach-ConfigGeneric
|
||||
prach_ConfigurationIndex = 70;
|
||||
prach_ConfigurationIndex = 52;
|
||||
#prach_msg1_FDM
|
||||
#0 = one, 1=two, 2=four, 3=eight
|
||||
prach_msg1_FDM = 0;
|
||||
@@ -110,7 +112,7 @@ gNBs =
|
||||
hoppingId = 40;
|
||||
p0_nominal = -90;
|
||||
|
||||
ssb_PositionsInBurst_Bitmap = 85;
|
||||
ssb_PositionsInBurst_Bitmap = 1;
|
||||
|
||||
# ssb_periodicityServingCell
|
||||
# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1
|
||||
@@ -143,11 +145,6 @@ gNBs =
|
||||
|
||||
);
|
||||
|
||||
first_active_bwp = 1;
|
||||
bwp_list = (
|
||||
{ scs = 3; bwpStart = 0; bwpSize = 66;}
|
||||
);
|
||||
|
||||
# ------- SCTP definitions
|
||||
SCTP :
|
||||
{
|
||||
@@ -175,10 +172,10 @@ MACRLCs = ({
|
||||
tr_n_preference = "local_RRC";
|
||||
pusch_TargetSNRx10 = 200;
|
||||
pucch_TargetSNRx10 = 200;
|
||||
set_analog_beamforming = "lophy";
|
||||
set_analog_beamforming = 1;
|
||||
beam_duration = 1;
|
||||
beams_per_period = 1;
|
||||
beam_weights = [0, 1, 2, 3]; // 4 SSBs -> 4 analog beams
|
||||
beam_weights = [0]; // single SSB -> one analog beam
|
||||
});
|
||||
|
||||
L1s = (
|
||||
@@ -202,11 +199,9 @@ RUs = ({
|
||||
eNB_instances = [0];
|
||||
});
|
||||
|
||||
rfsimulator = (
|
||||
{
|
||||
rfsimulator: {
|
||||
serveraddr = "server";
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
security = {
|
||||
# preferred ciphering algorithms
|
||||
@@ -18,7 +18,7 @@ gNBs =
|
||||
////////// Physical parameters:
|
||||
|
||||
min_rxtxtime = 6;
|
||||
enable_sdap = 0;
|
||||
enable_sdap = 1;
|
||||
|
||||
servingCellConfigCommon = (
|
||||
{
|
||||
@@ -205,15 +205,14 @@ RUs = (
|
||||
);
|
||||
|
||||
|
||||
rfsimulator = (
|
||||
{
|
||||
rfsimulator :
|
||||
{
|
||||
serveraddr = "server";
|
||||
serverport = 4043;
|
||||
options = (); #("saviq"); or/and "chanmod"
|
||||
modelname = "AWGN";
|
||||
IQfile = "/tmp/rfsimulator.iqs";
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
security = {
|
||||
# preferred ciphering algorithms
|
||||
|
||||
@@ -1,266 +0,0 @@
|
||||
Active_gNBs = ( "gNB-OAI");
|
||||
# Asn1_verbosity, choice in: none, info, annoying
|
||||
Asn1_verbosity = "none";
|
||||
|
||||
gNBs =
|
||||
(
|
||||
{
|
||||
////////// Identification parameters:
|
||||
gNB_ID = 0xe00;
|
||||
gNB_name = "gNB-OAI";
|
||||
|
||||
// Tracking area code, 0x0000 and 0xfffe are reserved values
|
||||
tracking_area_code = 1;
|
||||
plmn_list = ({ mcc = 208; mnc = 99; mnc_length = 2; snssaiList = ( { sst = 1; }); });
|
||||
|
||||
nr_cellid = 1;
|
||||
|
||||
////////// Physical parameters:
|
||||
|
||||
pdsch_AntennaPorts_XP = 2;
|
||||
pdsch_AntennaPorts_N1 = 2;
|
||||
maxMIMO_layers = 4;
|
||||
pusch_AntennaPorts = 4;
|
||||
do_CSIRS = 0;
|
||||
do_SRS = 0;
|
||||
|
||||
servingCellConfigCommon = (
|
||||
{
|
||||
#spCellConfigCommon
|
||||
physCellId = 0;
|
||||
# downlinkConfigCommon
|
||||
#frequencyInfoDL
|
||||
# center frequency = 4049.76 MHz
|
||||
# selected SSB frequency = 4049.76 MHz
|
||||
absoluteFrequencySSB = 668640; #669984;
|
||||
dl_frequencyBand = 77;
|
||||
# frequency point A = 4000.62 MHz
|
||||
dl_absoluteFrequencyPointA = 666708;
|
||||
#scs-SpecificCarrierList
|
||||
dl_offstToCarrier = 0;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
dl_subcarrierSpacing = 1;
|
||||
dl_carrierBandwidth = 273;
|
||||
#initialDownlinkBWP
|
||||
#genericParameters
|
||||
initialDLBWPlocationAndBandwidth = 1099; #38.101-1 Table 5.3.2-1
|
||||
#
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
initialDLBWPsubcarrierSpacing = 1;
|
||||
#pdcch-ConfigCommon
|
||||
initialDLBWPcontrolResourceSetZero = 11;
|
||||
initialDLBWPsearchSpaceZero = 0;
|
||||
|
||||
#uplinkConfigCommon
|
||||
#frequencyInfoUL
|
||||
ul_frequencyBand = 77;
|
||||
#scs-SpecificCarrierList
|
||||
ul_offstToCarrier = 0;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
ul_subcarrierSpacing = 1;
|
||||
ul_carrierBandwidth = 273;
|
||||
pMax = 23;
|
||||
#initialUplinkBWP
|
||||
#genericParameters
|
||||
initialULBWPlocationAndBandwidth = 1099;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
initialULBWPsubcarrierSpacing = 1;
|
||||
#rach-ConfigCommon
|
||||
#rach-ConfigGeneric
|
||||
prach_ConfigurationIndex = 159;
|
||||
#prach_msg1_FDM
|
||||
#0 = one, 1=two, 2=four, 3=eight
|
||||
prach_msg1_FDM = 0;
|
||||
prach_msg1_FrequencyStart = 0;
|
||||
zeroCorrelationZoneConfig = 0;
|
||||
preambleReceivedTargetPower = -100;
|
||||
#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200)
|
||||
preambleTransMax = 7;
|
||||
#powerRampingStep
|
||||
# 0=dB0,1=dB2,2=dB4,3=dB6
|
||||
powerRampingStep = 2;
|
||||
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
|
||||
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
|
||||
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
|
||||
#one (0..15) 4,8,12,16,...60,64
|
||||
ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15;
|
||||
#ra_ContentionResolutionTimer
|
||||
#(0..7) 8,16,24,32,40,48,56,64
|
||||
ra_ContentionResolutionTimer = 7;
|
||||
rsrp_ThresholdSSB = 19;
|
||||
#prach-RootSequenceIndex_PR
|
||||
#1 = 839, 2 = 139
|
||||
prach_RootSequenceIndex_PR = 2;
|
||||
prach_RootSequenceIndex = 1;
|
||||
# SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex
|
||||
#
|
||||
msg1_SubcarrierSpacing = 1,
|
||||
# restrictedSetConfig
|
||||
# 0=unrestricted, 1=restricted type A, 2=restricted type B
|
||||
restrictedSetConfig = 0,
|
||||
|
||||
# this is the offset between the last PRACH preamble power and the Msg3 PUSCH, 2 times the field value in dB
|
||||
msg3_DeltaPreamble = 2;
|
||||
p0_NominalWithGrant = -100;
|
||||
|
||||
# pucch-ConfigCommon setup :
|
||||
# pucchGroupHopping
|
||||
# 0 = neither, 1= group hopping, 2=sequence hopping
|
||||
pucchGroupHopping = 0;
|
||||
hoppingId = 0;
|
||||
p0_nominal = -96;
|
||||
|
||||
ssb_PositionsInBurst_Bitmap = 0x1;
|
||||
|
||||
# ssb_periodicityServingCell
|
||||
# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1
|
||||
ssb_periodicityServingCell = 2;
|
||||
|
||||
# dmrs_TypeA_position
|
||||
# 0 = pos2, 1 = pos3
|
||||
dmrs_TypeA_Position = 0;
|
||||
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
subcarrierSpacing = 1;
|
||||
|
||||
|
||||
#tdd-UL-DL-ConfigurationCommon
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
referenceSubcarrierSpacing = 1;
|
||||
# pattern1
|
||||
# dl_UL_TransmissionPeriodicity
|
||||
# 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10
|
||||
dl_UL_TransmissionPeriodicity = 5;
|
||||
nrofDownlinkSlots = 3;
|
||||
nrofDownlinkSymbols = 6;
|
||||
nrofUplinkSlots = 1;
|
||||
nrofUplinkSymbols = 4;
|
||||
|
||||
ssPBCH_BlockPower = -11;
|
||||
}
|
||||
|
||||
);
|
||||
|
||||
|
||||
# ------- SCTP definitions
|
||||
SCTP :
|
||||
{
|
||||
# Number of streams to use in input/output
|
||||
SCTP_INSTREAMS = 2;
|
||||
SCTP_OUTSTREAMS = 2;
|
||||
};
|
||||
|
||||
|
||||
////////// AMF parameters:
|
||||
amf_ip_address = ({ ipv4 = "172.21.6.5"; });
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.16.209";
|
||||
GNB_IPV4_ADDRESS_FOR_NGU = "172.21.16.209";
|
||||
GNB_PORT_FOR_S1U = 2152; # Spec 2152
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
MACRLCs = (
|
||||
{
|
||||
num_cc = 1;
|
||||
tr_s_preference = "local_L1";
|
||||
tr_n_preference = "local_RRC";
|
||||
pusch_TargetSNRx10 = 220;
|
||||
pucch_TargetSNRx10 = 220;
|
||||
pusch_FailureThres = 100;
|
||||
}
|
||||
);
|
||||
|
||||
L1s = (
|
||||
{
|
||||
num_cc = 1;
|
||||
tr_n_preference = "local_mac";
|
||||
prach_dtx_threshold = 120
|
||||
pucch0_dtx_threshold = 80;
|
||||
pusch_dtx_threshold = -100;
|
||||
tx_amp_backoff_dB = 3;
|
||||
L1_rx_thread_core = 8;
|
||||
L1_tx_thread_core = 9;
|
||||
max_ldpc_iterations = 20;
|
||||
phase_compensation = 0; # needs to match O-RU configuration
|
||||
}
|
||||
);
|
||||
|
||||
RUs = (
|
||||
{
|
||||
local_rf = "no";
|
||||
nb_tx = 4;
|
||||
nb_rx = 4;
|
||||
att_tx = 0;
|
||||
att_rx = 0;
|
||||
bands = [77];
|
||||
max_pdschReferenceSignalPower = -27;
|
||||
max_rxgain = 75;
|
||||
sf_extension = 0;
|
||||
eNB_instances = [0];
|
||||
ru_thread_core = 10;
|
||||
sl_ahead = 5;
|
||||
tr_preference = "raw_if4p5"; # important: activate FHI7.2
|
||||
do_precoding = 0; # needs to match O-RU configuration
|
||||
}
|
||||
);
|
||||
|
||||
security = {
|
||||
# preferred ciphering algorithms
|
||||
# the first one of the list that an UE supports in chosen
|
||||
# valid values: nea0, nea1, nea2, nea3
|
||||
ciphering_algorithms = ( "nea0" );
|
||||
|
||||
# preferred integrity algorithms
|
||||
# the first one of the list that an UE supports in chosen
|
||||
# valid values: nia0, nia1, nia2, nia3
|
||||
integrity_algorithms = ( "nia2", "nia0" );
|
||||
|
||||
# setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter
|
||||
# what 'ciphering_algorithms' configures; same thing for 'drb_integrity'
|
||||
drb_ciphering = "yes";
|
||||
drb_integrity = "no";
|
||||
};
|
||||
|
||||
log_config :
|
||||
{
|
||||
global_log_level = "info";
|
||||
hw_log_level = "info";
|
||||
phy_log_level = "info";
|
||||
mac_log_level = "info";
|
||||
rlc_log_level = "info";
|
||||
pdcp_log_level = "info";
|
||||
rrc_log_level = "info";
|
||||
ngap_log_level = "info";
|
||||
f1ap_log_level = "info";
|
||||
};
|
||||
|
||||
fhi_72 = {
|
||||
dpdk_devices = ("0000:01:01.0");
|
||||
dpdk_iova_mode = "VA";
|
||||
system_core = 11;
|
||||
io_core = 12;
|
||||
worker_cores = (13);
|
||||
ru_addr = ("98:ae:71:04:83:e3");
|
||||
mtu = 9600;
|
||||
fh_config = ({
|
||||
T1a_cp_dl = (285, 470);
|
||||
T1a_cp_ul = (285, 429);
|
||||
T1a_up = (125, 350);
|
||||
Ta4 = (110, 180);
|
||||
ru_config = {
|
||||
iq_width = 9;
|
||||
iq_width_prach = 9;
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
@@ -251,7 +251,7 @@ fhi_72 = {
|
||||
io_core = 1;
|
||||
worker_cores = (2);
|
||||
ru_addr = ("98:ae:71:04:83:e3", "98:ae:71:04:83:e3");
|
||||
mtu = 9216;
|
||||
mtu = 9600;
|
||||
fh_config = ({
|
||||
T1a_cp_dl = (285, 470);
|
||||
T1a_cp_ul = (285, 429);
|
||||
|
||||
@@ -30,26 +30,26 @@ gNBs =
|
||||
# downlinkConfigCommon
|
||||
#frequencyInfoDL
|
||||
# this is 3610.56 MHz
|
||||
absoluteFrequencySSB = 679104;
|
||||
dl_frequencyBand = 77;
|
||||
absoluteFrequencySSB = 679104;
|
||||
dl_frequencyBand = 77;
|
||||
# this is 3599.94 MHz
|
||||
dl_absoluteFrequencyPointA = 678388;
|
||||
dl_absoluteFrequencyPointA = 678388;
|
||||
#scs-SpecificCarrierList
|
||||
dl_offstToCarrier = 0;
|
||||
dl_offstToCarrier = 0;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
dl_subcarrierSpacing = 1;
|
||||
dl_carrierBandwidth = 51;
|
||||
dl_subcarrierSpacing = 1;
|
||||
dl_carrierBandwidth = 51;
|
||||
#initialDownlinkBWP
|
||||
#genericParameters
|
||||
# this is RBstart=27,L=48 (275*(L-1))+RBstart
|
||||
initialDLBWPlocationAndBandwidth = 13750;
|
||||
initialDLBWPlocationAndBandwidth = 13750;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
initialDLBWPsubcarrierSpacing = 1;
|
||||
initialDLBWPsubcarrierSpacing = 1;
|
||||
#pdcch-ConfigCommon
|
||||
initialDLBWPcontrolResourceSetZero = 12;
|
||||
initialDLBWPsearchSpaceZero = 0;
|
||||
initialDLBWPcontrolResourceSetZero = 12;
|
||||
initialDLBWPsearchSpaceZero = 0;
|
||||
|
||||
#uplinkConfigCommon
|
||||
#frequencyInfoUL
|
||||
@@ -197,10 +197,10 @@ RUs = (
|
||||
att_rx = 0;
|
||||
bands = [77];
|
||||
max_pdschReferenceSignalPower = -27;
|
||||
max_rxgain = 114;
|
||||
max_rxgain = 114;
|
||||
eNB_instances = [0];
|
||||
clock_src = "external";
|
||||
time_src = "external";
|
||||
clock_src = "external";
|
||||
time_src = "external";
|
||||
}
|
||||
);
|
||||
|
||||
@@ -209,7 +209,7 @@ security = {
|
||||
# preferred ciphering algorithms
|
||||
# the first one of the list that an UE supports in chosen
|
||||
# valid values: nea0, nea1, nea2, nea3
|
||||
ciphering_algorithms = ( "nea2", "nea0" );
|
||||
ciphering_algorithms = ( "nea0" );
|
||||
|
||||
# preferred integrity algorithms
|
||||
# the first one of the list that an UE supports in chosen
|
||||
@@ -219,7 +219,7 @@ security = {
|
||||
# setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter
|
||||
# what 'ciphering_algorithms' configures; same thing for 'drb_integrity'
|
||||
drb_ciphering = "yes";
|
||||
drb_integrity = "yes";
|
||||
drb_integrity = "no";
|
||||
};
|
||||
|
||||
log_config :
|
||||
|
||||
@@ -208,11 +208,9 @@ RUs = (
|
||||
);
|
||||
|
||||
|
||||
rfsimulator = (
|
||||
{
|
||||
rfsimulator: {
|
||||
serveraddr = "server";
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
security = {
|
||||
# preferred ciphering algorithms
|
||||
|
||||
@@ -197,11 +197,9 @@ RUs = (
|
||||
}
|
||||
);
|
||||
|
||||
rfsimulator = (
|
||||
{
|
||||
rfsimulator: {
|
||||
serveraddr = "server";
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
security = {
|
||||
# preferred ciphering algorithms
|
||||
|
||||
@@ -18,6 +18,8 @@ gNBs =
|
||||
|
||||
////////// Physical parameters:
|
||||
|
||||
do_CSIRS = 0;
|
||||
do_SRS = 0;
|
||||
min_rxtxtime = 6;
|
||||
|
||||
servingCellConfigCommon = (
|
||||
@@ -204,15 +206,13 @@ RUs = ({
|
||||
});
|
||||
|
||||
|
||||
rfsimulator = (
|
||||
{
|
||||
rfsimulator: {
|
||||
serveraddr = "server";
|
||||
serverport = 4043;
|
||||
options = (); #("saviq"); or/and "chanmod"
|
||||
modelname = "AWGN";
|
||||
IQfile = "/tmp/rfsimulator.iqs"
|
||||
}
|
||||
);
|
||||
|
||||
security = {
|
||||
# preferred ciphering algorithms
|
||||
|
||||
@@ -1,257 +0,0 @@
|
||||
Active_gNBs = ( "gNB-OAI");
|
||||
# Asn1_verbosity, choice in: none, info, annoying
|
||||
Asn1_verbosity = "none";
|
||||
|
||||
gNBs =
|
||||
(
|
||||
{
|
||||
////////// Identification parameters:
|
||||
gNB_ID = 0xe00;
|
||||
gNB_name = "gNB-OAI";
|
||||
|
||||
// Tracking area code, 0x0000 and 0xfffe are reserved values
|
||||
tracking_area_code = 1;
|
||||
|
||||
plmn_list = ({mcc = 208; mnc = 97; mnc_length = 2;});
|
||||
|
||||
////////// Physical parameters:
|
||||
|
||||
min_rxtxtime = 6;
|
||||
|
||||
servingCellConfigCommon = (
|
||||
{
|
||||
#spCellConfigCommon
|
||||
|
||||
physCellId = 0;
|
||||
|
||||
# downlinkConfigCommon
|
||||
#frequencyInfoDL
|
||||
# this is 3300.60 MHz + 53*12*30e-3 MHz = 3319.68
|
||||
absoluteFrequencySSB = 621312;
|
||||
# this is 3300.60 MHz
|
||||
dl_absoluteFrequencyPointA = 620040;
|
||||
#scs-SpecificCarrierList
|
||||
dl_offstToCarrier = 0;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
dl_subcarrierSpacing = 1;
|
||||
dl_carrierBandwidth = 106;
|
||||
#initialDownlinkBWP
|
||||
#genericParameters
|
||||
# this is RBstart=0,L=106 (275*(L-1))+RBstart
|
||||
initialDLBWPlocationAndBandwidth = 28875;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
initialDLBWPsubcarrierSpacing = 1;
|
||||
#pdcch-ConfigCommon
|
||||
initialDLBWPcontrolResourceSetZero = 11;
|
||||
initialDLBWPsearchSpaceZero = 0;
|
||||
|
||||
#uplinkConfigCommon
|
||||
#frequencyInfoUL
|
||||
ul_frequencyBand = 78;
|
||||
#scs-SpecificCarrierList
|
||||
ul_offstToCarrier = 0;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
ul_subcarrierSpacing = 1;
|
||||
ul_carrierBandwidth = 106;
|
||||
pMax = 20;
|
||||
#initialUplinkBWP
|
||||
#genericParameters
|
||||
initialULBWPlocationAndBandwidth = 28875;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
initialULBWPsubcarrierSpacing = 1;
|
||||
#rach-ConfigCommon
|
||||
#rach-ConfigGeneric
|
||||
prach_ConfigurationIndex = 98;
|
||||
#prach_msg1_FDM
|
||||
#0 = one, 1=two, 2=four, 3=eight
|
||||
prach_msg1_FDM = 0;
|
||||
prach_msg1_FrequencyStart = 0;
|
||||
zeroCorrelationZoneConfig = 12;
|
||||
preambleReceivedTargetPower = -104;
|
||||
#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200)
|
||||
preambleTransMax = 6;
|
||||
#powerRampingStep
|
||||
# 0=dB0,1=dB2,2=dB4,3=dB6
|
||||
powerRampingStep = 1;
|
||||
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
|
||||
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
|
||||
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
|
||||
#one (0..15) 4,8,12,16,...60,64
|
||||
ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15;
|
||||
#ra_ContentionResolutionTimer
|
||||
#(0..7) 8,16,24,32,40,48,56,64
|
||||
ra_ContentionResolutionTimer = 7;
|
||||
rsrp_ThresholdSSB = 19;
|
||||
#prach-RootSequenceIndex_PR
|
||||
#1 = 839, 2 = 139
|
||||
prach_RootSequenceIndex_PR = 2;
|
||||
prach_RootSequenceIndex = 1;
|
||||
# SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex
|
||||
#
|
||||
msg1_SubcarrierSpacing = 1,
|
||||
# restrictedSetConfig
|
||||
# 0=unrestricted, 1=restricted type A, 2=restricted type B
|
||||
restrictedSetConfig = 0,
|
||||
|
||||
msg3_DeltaPreamble = 1;
|
||||
p0_NominalWithGrant =-90;
|
||||
|
||||
# pucch-ConfigCommon setup :
|
||||
# pucchGroupHopping
|
||||
# 0 = neither, 1= group hopping, 2=sequence hopping
|
||||
pucchGroupHopping = 0;
|
||||
hoppingId = 40;
|
||||
p0_nominal = -90;
|
||||
|
||||
ssb_PositionsInBurst_Bitmap = 1;
|
||||
|
||||
# ssb_periodicityServingCell
|
||||
# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spar e1
|
||||
ssb_periodicityServingCell = 2;
|
||||
|
||||
# dmrs_TypeA_position
|
||||
# 0 = pos2, 1 = pos3
|
||||
dmrs_TypeA_Position = 0;
|
||||
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
subcarrierSpacing = 1;
|
||||
|
||||
|
||||
#tdd-UL-DL-ConfigurationCommon
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
referenceSubcarrierSpacing = 1;
|
||||
# pattern1
|
||||
# dl_UL_TransmissionPeriodicity
|
||||
# 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10
|
||||
dl_UL_TransmissionPeriodicity = 6;
|
||||
nrofDownlinkSlots = 7;
|
||||
nrofDownlinkSymbols = 6;
|
||||
nrofUplinkSlots = 2;
|
||||
nrofUplinkSymbols = 4;
|
||||
|
||||
ssPBCH_BlockPower = -25;
|
||||
}
|
||||
|
||||
);
|
||||
|
||||
|
||||
# ------- SCTP definitions
|
||||
SCTP :
|
||||
{
|
||||
# Number of streams to use in input/output
|
||||
SCTP_INSTREAMS = 2;
|
||||
SCTP_OUTSTREAMS = 2;
|
||||
};
|
||||
|
||||
////////// AMF parameters:
|
||||
amf_ip_address = ({ ipv4 = "CI_MME_IP_ADDR"; });
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
|
||||
GNB_IPV4_ADDRESS_FOR_NG_AMF = "192.168.71.140";
|
||||
GNB_IPV4_ADDRESS_FOR_NGU = "192.168.71.140";
|
||||
GNB_PORT_FOR_S1U = 2152; # Spec 2152
|
||||
};
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
MACRLCs = (
|
||||
{
|
||||
num_cc = 1;
|
||||
tr_s_preference = "local_L1";
|
||||
tr_n_preference = "local_RRC";
|
||||
pusch_TargetSNRx10 = 200;
|
||||
pucch_TargetSNRx10 = 200;
|
||||
}
|
||||
);
|
||||
|
||||
prs_config = (
|
||||
{
|
||||
NumPRSResources = 1;
|
||||
PRSResourceSetPeriod = [20, 2];
|
||||
SymbolStart = [7];
|
||||
NumPRSSymbols = [6];
|
||||
NumRB = 106;
|
||||
RBOffset = 0;
|
||||
CombSize = 4;
|
||||
REOffset = [0];
|
||||
PRSResourceOffset = [0];
|
||||
PRSResourceRepetition = 1;
|
||||
PRSResourceTimeGap = 1;
|
||||
NPRS_ID = [0];
|
||||
MutingPattern1 = [];
|
||||
MutingPattern2 = [];
|
||||
MutingBitRepetition = 1;
|
||||
}
|
||||
);
|
||||
|
||||
L1s = (
|
||||
{
|
||||
num_cc = 1;
|
||||
tr_n_preference = "local_mac";
|
||||
prach_dtx_threshold = 120;
|
||||
}
|
||||
);
|
||||
|
||||
RUs = (
|
||||
{
|
||||
local_rf = "yes"
|
||||
nb_tx = 1
|
||||
nb_rx = 1
|
||||
att_tx = 0
|
||||
att_rx = 0;
|
||||
bands = [78];
|
||||
max_pdschReferenceSignalPower = -27;
|
||||
max_rxgain = 75;
|
||||
sf_extension = 0;
|
||||
eNB_instances = [0];
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
rfsimulator = (
|
||||
{
|
||||
serveraddr = "server";
|
||||
serverport = 4043;
|
||||
options = (); #("saviq"); or/and "chanmod"
|
||||
modelname = "AWGN";
|
||||
IQfile = "/tmp/rfsimulator.iqs";
|
||||
}
|
||||
);
|
||||
|
||||
security = {
|
||||
# preferred ciphering algorithms
|
||||
# the first one of the list that an UE supports in chosen
|
||||
# valid values: nea0, nea1, nea2, nea3
|
||||
ciphering_algorithms = ( "nea0" );
|
||||
|
||||
# preferred integrity algorithms
|
||||
# the first one of the list that an UE supports in chosen
|
||||
# valid values: nia0, nia1, nia2, nia3
|
||||
integrity_algorithms = ( "nia2", "nia0" );
|
||||
|
||||
# setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter
|
||||
# what 'ciphering_algorithms' configures; same thing for 'drb_integrity'
|
||||
drb_ciphering = "yes";
|
||||
drb_integrity = "no";
|
||||
};
|
||||
|
||||
log_config :
|
||||
{
|
||||
global_log_level = "info";
|
||||
hw_log_level = "info";
|
||||
phy_log_level = "info";
|
||||
mac_log_level = "info";
|
||||
rlc_log_level = "info";
|
||||
pdcp_log_level = "info";
|
||||
rrc_log_level = "info";
|
||||
f1ap_log_level = "debug";
|
||||
};
|
||||
@@ -63,7 +63,7 @@ gNBs:
|
||||
prach_ConfigurationIndex: 98
|
||||
#prach_msg1_FDM
|
||||
#0 = one, 1=two, 2=four, 3=eight
|
||||
prach_msg1_FDM: 1
|
||||
prach_msg1_FDM: 0
|
||||
prach_msg1_FrequencyStart: 0
|
||||
zeroCorrelationZoneConfig: 12
|
||||
preambleReceivedTargetPower: -104
|
||||
@@ -99,7 +99,7 @@ gNBs:
|
||||
pucchGroupHopping: 0
|
||||
hoppingId: 40
|
||||
p0_nominal: -90
|
||||
ssb_PositionsInBurst_Bitmap: 2
|
||||
ssb_PositionsInBurst_Bitmap: 1
|
||||
# ssb_periodicityServingCell
|
||||
# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1
|
||||
ssb_periodicityServingCell: 2
|
||||
@@ -146,7 +146,6 @@ MACRLCs:
|
||||
tr_n_preference: local_RRC
|
||||
pusch_TargetSNRx10: 200
|
||||
pucch_TargetSNRx10: 200
|
||||
stats_max_ue: 17
|
||||
|
||||
L1s:
|
||||
- num_cc: 1
|
||||
@@ -168,7 +167,7 @@ RUs:
|
||||
sdr_addrs: serial=XXXXXXX
|
||||
|
||||
rfsimulator:
|
||||
- serveraddr: server
|
||||
serveraddr: server
|
||||
|
||||
security:
|
||||
# preferred ciphering algorithms
|
||||
|
||||
@@ -1,209 +0,0 @@
|
||||
Active_gNBs:
|
||||
- gnb-rfsim
|
||||
# Asn1_verbosity, choice in: none, info, annoying
|
||||
Asn1_verbosity: none
|
||||
gNBs:
|
||||
##### Identification parameters:
|
||||
- gNB_ID: 0xe00
|
||||
gNB_name: gnb-rfsim
|
||||
tracking_area_code: 1
|
||||
plmn_list:
|
||||
- mcc: 208
|
||||
mnc: 99
|
||||
mnc_length: 2
|
||||
snssaiList:
|
||||
- sst: 1
|
||||
sd: 0xffffff
|
||||
nr_cellid: 12345678
|
||||
##### Physical parameters:
|
||||
min_rxtxtime: 6
|
||||
pusch_AntennaPorts: 2
|
||||
pdsch_AntennaPorts_XP: 2
|
||||
|
||||
servingCellConfigCommon:
|
||||
#spCellConfigCommon
|
||||
- physCellId: 0
|
||||
# downlinkConfigCommon
|
||||
#frequencyInfoDL
|
||||
# this is 3300.60 MHz + 53*12*30e-3 MHz = 3319.68
|
||||
absoluteFrequencySSB: 621312
|
||||
# this is 3300.60 MHz
|
||||
dl_absoluteFrequencyPointA: 620040
|
||||
#scs-SpecificCarrierList
|
||||
dl_offstToCarrier: 0
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
dl_subcarrierSpacing: 1
|
||||
dl_carrierBandwidth: 106
|
||||
#initialDownlinkBWP
|
||||
#genericParameters
|
||||
# this is RBstart=0,L=106 (275*(L-1))+RBstart
|
||||
initialDLBWPlocationAndBandwidth: 28875
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
initialDLBWPsubcarrierSpacing: 1
|
||||
#pdcch-ConfigCommon
|
||||
initialDLBWPcontrolResourceSetZero: 11
|
||||
initialDLBWPsearchSpaceZero: 0
|
||||
#uplinkConfigCommon
|
||||
#frequencyInfoUL
|
||||
ul_frequencyBand: 78
|
||||
#scs-SpecificCarrierList
|
||||
ul_offstToCarrier: 0
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
ul_subcarrierSpacing: 1
|
||||
ul_carrierBandwidth: 106
|
||||
pMax: 20
|
||||
#initialUplinkBWP
|
||||
#genericParameters
|
||||
initialULBWPlocationAndBandwidth: 28875
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
initialULBWPsubcarrierSpacing: 1
|
||||
#rach-ConfigCommon
|
||||
#rach-ConfigGeneric
|
||||
prach_ConfigurationIndex: 98
|
||||
#prach_msg1_FDM
|
||||
#0 = one, 1=two, 2=four, 3=eight
|
||||
prach_msg1_FDM: 0
|
||||
prach_msg1_FrequencyStart: 0
|
||||
zeroCorrelationZoneConfig: 12
|
||||
preambleReceivedTargetPower: -104
|
||||
#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200)
|
||||
preambleTransMax: 6
|
||||
#powerRampingStep
|
||||
# 0=dB0,1=dB2,2=dB4,3=dB6
|
||||
powerRampingStep: 1
|
||||
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
|
||||
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
|
||||
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR: 4
|
||||
#one (0..15) 4,8,12,16,...60,64
|
||||
ssb_perRACH_OccasionAndCB_PreamblesPerSSB: 15
|
||||
#ra_ContentionResolutionTimer
|
||||
#(0..7) 8,16,24,32,40,48,56,64
|
||||
ra_ContentionResolutionTimer: 7
|
||||
rsrp_ThresholdSSB: 19
|
||||
#prach-RootSequenceIndex_PR
|
||||
#1 = 839, 2 = 139
|
||||
prach_RootSequenceIndex_PR: 2
|
||||
prach_RootSequenceIndex: 1
|
||||
# SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex
|
||||
msg1_SubcarrierSpacing: 1
|
||||
# restrictedSetConfig
|
||||
# 0=unrestricted, 1=restricted type A, 2=restricted type B
|
||||
restrictedSetConfig: 0
|
||||
msg3_DeltaPreamble: 1
|
||||
p0_NominalWithGrant: -90
|
||||
|
||||
# pucch-ConfigCommon setup :
|
||||
# pucchGroupHopping
|
||||
# 0 = neither, 1= group hopping, 2=sequence hopping
|
||||
pucchGroupHopping: 0
|
||||
hoppingId: 40
|
||||
p0_nominal: -90
|
||||
ssb_PositionsInBurst_Bitmap: 1
|
||||
# ssb_periodicityServingCell
|
||||
# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1
|
||||
ssb_periodicityServingCell: 2
|
||||
|
||||
# dmrs_TypeA_position
|
||||
# 0 = pos2, 1 = pos3
|
||||
dmrs_TypeA_Position: 0
|
||||
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
subcarrierSpacing: 1
|
||||
|
||||
#tdd-UL-DL-ConfigurationCommon
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
referenceSubcarrierSpacing: 1
|
||||
|
||||
# pattern1
|
||||
# dl_UL_TransmissionPeriodicity
|
||||
# 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10
|
||||
dl_UL_TransmissionPeriodicity: 6
|
||||
nrofDownlinkSlots: 7
|
||||
nrofDownlinkSymbols: 6
|
||||
nrofUplinkSlots: 2
|
||||
nrofUplinkSymbols: 4
|
||||
ssPBCH_BlockPower: -25
|
||||
SCTP:
|
||||
SCTP_INSTREAMS: 2
|
||||
SCTP_OUTSTREAMS: 2
|
||||
|
||||
##### AMF parameters:
|
||||
amf_ip_address:
|
||||
- ipv4: 192.168.71.132
|
||||
|
||||
NETWORK_INTERFACES:
|
||||
GNB_IPV4_ADDRESS_FOR_NG_AMF: 192.168.71.140
|
||||
GNB_IPV4_ADDRESS_FOR_NGU: 192.168.71.140
|
||||
GNB_PORT_FOR_S1U: 2152 # Spec 2152
|
||||
|
||||
|
||||
MACRLCs:
|
||||
- num_cc: 1
|
||||
tr_s_preference: local_L1
|
||||
tr_n_preference: local_RRC
|
||||
pusch_TargetSNRx10: 200
|
||||
pucch_TargetSNRx10: 200
|
||||
|
||||
L1s:
|
||||
- num_cc: 1
|
||||
tr_n_preference: local_mac
|
||||
prach_dtx_threshold: 200
|
||||
# pucch0_dtx_threshold = 150;
|
||||
|
||||
RUs:
|
||||
- local_rf: yes
|
||||
nb_tx: 2
|
||||
nb_rx: 2
|
||||
att_tx: 0
|
||||
att_rx: 0
|
||||
bands: [78]
|
||||
max_pdschReferenceSignalPower: -27
|
||||
max_rxgain: 75
|
||||
eNB_instances: [0]
|
||||
sf_extension: 0
|
||||
|
||||
security:
|
||||
# preferred ciphering algorithms
|
||||
# the first one of the list that an UE supports in chosen
|
||||
# valid values: nea0, nea1, nea2, nea3
|
||||
ciphering_algorithms: [nea0]
|
||||
|
||||
# preferred integrity algorithms
|
||||
# the first one of the list that an UE supports in chosen
|
||||
# valid values: nia0, nia1, nia2, nia3
|
||||
integrity_algorithms: [nia2, nia0]
|
||||
|
||||
# setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter
|
||||
# what 'ciphering_algorithms' configures; same thing for 'drb_integrity'
|
||||
drb_ciphering: yes
|
||||
drb_integrity: no
|
||||
|
||||
log_config:
|
||||
global_log_level: info
|
||||
hw_log_level: info
|
||||
phy_log_level: info
|
||||
mac_log_level: info
|
||||
rlc_log_level: info
|
||||
pdcp_log_level: info
|
||||
rrc_log_level: info
|
||||
ngap_log_level: debug
|
||||
f1ap_log_level: debug
|
||||
|
||||
|
||||
channelmod:
|
||||
max_chan: 10
|
||||
modellist: DefaultChannelList
|
||||
DefaultChannelList:
|
||||
- model_name: server_tx_channel_model
|
||||
type: AWGN
|
||||
ploss_dB: 0
|
||||
noise_power_dB: -100
|
||||
forgetfact: 0
|
||||
offset: 0
|
||||
ds_tdl: 0
|
||||
@@ -16,6 +16,8 @@ gNBs =
|
||||
nr_cellid = 12345678L;
|
||||
|
||||
////////// Physical parameters:
|
||||
|
||||
sib1_tda = 15;
|
||||
min_rxtxtime = 6;
|
||||
|
||||
servingCellConfigCommon = (
|
||||
@@ -194,7 +196,6 @@ RUs = (
|
||||
att_tx = 0
|
||||
att_rx = 0;
|
||||
bands = [78];
|
||||
sl_ahead=3;
|
||||
max_pdschReferenceSignalPower = -27;
|
||||
max_rxgain = 114;
|
||||
sf_extension = 0;
|
||||
@@ -203,11 +204,10 @@ RUs = (
|
||||
}
|
||||
);
|
||||
|
||||
rfsimulator = (
|
||||
{
|
||||
rfsimulator: {
|
||||
serveraddr = "server";
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
security = {
|
||||
# preferred ciphering algorithms
|
||||
|
||||
@@ -23,6 +23,7 @@ gNBs =
|
||||
pusch_AntennaPorts = 4;
|
||||
do_CSIRS = 1;
|
||||
do_SRS = 0;
|
||||
sib1_tda = 15;
|
||||
# force_UL256qam_off = 1;
|
||||
|
||||
servingCellConfigCommon = (
|
||||
@@ -258,7 +259,7 @@ fhi_72 = {
|
||||
io_core = 1;
|
||||
worker_cores = (2);
|
||||
ru_addr = ("70:b3:d5:e1:5b:81", "70:b3:d5:e1:5b:81");
|
||||
mtu = 9216;
|
||||
mtu = 9600;
|
||||
fh_config = ({
|
||||
T1a_cp_dl = (419, 470);
|
||||
T1a_cp_ul = (285, 336);
|
||||
|
||||
@@ -203,15 +203,14 @@ RUs = (
|
||||
);
|
||||
|
||||
|
||||
rfsimulator = (
|
||||
rfsimulator :
|
||||
{
|
||||
serveraddr = "server";
|
||||
serverport = 4043;
|
||||
options = (); #("saviq"); or/and "chanmod"
|
||||
modelname = "AWGN";
|
||||
IQfile = "/tmp/rfsimulator.iqs";
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
security = {
|
||||
# preferred ciphering algorithms
|
||||
|
||||
@@ -21,6 +21,10 @@ gNBs =
|
||||
nr_cellid = 12345678L
|
||||
|
||||
////////// Physical parameters:
|
||||
pdsch_AntennaPorts_XP = 1;
|
||||
pusch_AntennaPorts = 1;
|
||||
do_CSIRS = 1;
|
||||
do_SRS = 0;
|
||||
uess_agg_levels = [2, 2, 2, 0, 0];
|
||||
|
||||
servingCellConfigCommon = (
|
||||
@@ -182,7 +186,6 @@ MACRLCs = (
|
||||
tr_n_preference = "local_RRC";
|
||||
pusch_TargetSNRx10 = 200;
|
||||
pucch_TargetSNRx10 = 200;
|
||||
stats_max_ue = 17;
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
rfsimulator = (
|
||||
{
|
||||
serveraddr = "127.0.0.1";
|
||||
}
|
||||
);
|
||||
@@ -42,13 +42,13 @@ nr_measurement_configuration = {
|
||||
A2 = {
|
||||
enable = 1;
|
||||
threshold = 110;
|
||||
time_to_trigger = 1;
|
||||
timeToTrigger = 1;
|
||||
};
|
||||
|
||||
A3 = ({
|
||||
physCellId = -1; #Default
|
||||
cell_id = -1; #Default
|
||||
offset = 10;
|
||||
hysteresis = 0;
|
||||
time_to_trigger = 1
|
||||
timeToTrigger = 1
|
||||
})
|
||||
};
|
||||
|
||||
@@ -57,19 +57,19 @@ nr_measurement_configuration = {
|
||||
A2 = {
|
||||
enable = 1;
|
||||
threshold = 60;
|
||||
time_to_trigger = 1;
|
||||
timeToTrigger = 1;
|
||||
};
|
||||
|
||||
A3 = ({
|
||||
physCellId = -1; #Default
|
||||
offset = 10;
|
||||
hysteresis = 0;
|
||||
time_to_trigger = 1
|
||||
timeToTrigger = 1
|
||||
}, {
|
||||
physCellId = 2;
|
||||
offset = 5;
|
||||
hysteresis = 1;
|
||||
time_to_trigger = 2
|
||||
timeToTrigger = 2
|
||||
})
|
||||
};
|
||||
|
||||
|
||||
@@ -12,7 +12,8 @@ uicc0 = {
|
||||
imsi = "208990100001100";
|
||||
key = "fec86ba6eb707ed08905757b1bb44b8f";
|
||||
opc= "C42449363BBAD02B66D16BC975D77CC1";
|
||||
pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; });
|
||||
dnn= "oai";
|
||||
nssai_sst=1;
|
||||
}
|
||||
|
||||
MACRLCs = (
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
PRSs =
|
||||
(
|
||||
{
|
||||
Active_gNBs = 1;
|
||||
prs_config0 = (
|
||||
{
|
||||
gNB_id = 0;
|
||||
NumPRSResources = 1;
|
||||
PRSResourceSetPeriod = [20, 2];
|
||||
SymbolStart = [7];
|
||||
NumPRSSymbols = [6];
|
||||
NumRB = 106;
|
||||
RBOffset = 0;
|
||||
CombSize = 4;
|
||||
REOffset = [0];
|
||||
PRSResourceOffset = [0];
|
||||
PRSResourceRepetition = 1;
|
||||
PRSResourceTimeGap = 1;
|
||||
NPRS_ID = [0];
|
||||
MutingPattern1 = [];
|
||||
MutingPattern2 = [];
|
||||
MutingBitRepetition = 1;
|
||||
}
|
||||
);
|
||||
|
||||
prs_config1 = (
|
||||
{
|
||||
gNB_id = 1;
|
||||
NumPRSResources = 1;
|
||||
PRSResourceSetPeriod = [20, 2];
|
||||
SymbolStart = [7];
|
||||
NumPRSSymbols = [6];
|
||||
NumRB = 106;
|
||||
RBOffset = 0;
|
||||
CombSize = 4;
|
||||
REOffset = [0];
|
||||
PRSResourceOffset = [1];
|
||||
PRSResourceRepetition = 1;
|
||||
PRSResourceTimeGap = 1;
|
||||
NPRS_ID = [1];
|
||||
MutingPattern1 = [];
|
||||
MutingPattern2 = [];
|
||||
MutingBitRepetition = 1;
|
||||
}
|
||||
);
|
||||
|
||||
prs_config2 = (
|
||||
{
|
||||
gNB_id = 2;
|
||||
NumPRSResources = 1;
|
||||
PRSResourceSetPeriod = [20, 2];
|
||||
SymbolStart = [7];
|
||||
NumPRSSymbols = [6];
|
||||
NumRB = 106;
|
||||
RBOffset = 0;
|
||||
CombSize = 4;
|
||||
REOffset = [0];
|
||||
PRSResourceOffset = [2];
|
||||
PRSResourceRepetition = 1;
|
||||
PRSResourceTimeGap = 1;
|
||||
NPRS_ID = [2];
|
||||
MutingPattern1 = [];
|
||||
MutingPattern2 = [];
|
||||
MutingBitRepetition = 1;
|
||||
}
|
||||
);
|
||||
|
||||
prs_config3 = (
|
||||
{
|
||||
gNB_id = 3;
|
||||
NumPRSResources = 1;
|
||||
PRSResourceSetPeriod = [20, 2];
|
||||
SymbolStart = [7];
|
||||
NumPRSSymbols = [6];
|
||||
NumRB = 106;
|
||||
RBOffset = 0;
|
||||
CombSize = 4;
|
||||
REOffset = [0];
|
||||
PRSResourceOffset = [3];
|
||||
PRSResourceRepetition = 1;
|
||||
PRSResourceTimeGap = 1;
|
||||
NPRS_ID = [3];
|
||||
MutingPattern1 = [];
|
||||
MutingPattern2 = [];
|
||||
MutingBitRepetition = 1;
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
rfsimulator = (
|
||||
{
|
||||
serveraddr = "127.0.0.1";
|
||||
}
|
||||
);
|
||||
@@ -1,17 +0,0 @@
|
||||
uicc0 = {
|
||||
imsi = "208990100001100";
|
||||
key = "fec86ba6eb707ed08905757b1bb44b8f";
|
||||
opc= "C42449363BBAD02B66D16BC975D77CC1";
|
||||
pdu_sessions = (
|
||||
{ id = 1; dnn = "oai"; nssai_sst = 1; },
|
||||
{ id = 2; dnn = "oai"; nssai_sst = 1; }
|
||||
)
|
||||
}
|
||||
|
||||
thread-pool = "-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1"
|
||||
|
||||
rfsimulator = (
|
||||
{
|
||||
serveraddr = "127.0.0.1";
|
||||
}
|
||||
);
|
||||
@@ -2,7 +2,8 @@ uicc0 = {
|
||||
imsi = "208990100001100";
|
||||
key = "fec86ba6eb707ed08905757b1bb44b8f";
|
||||
opc= "C42449363BBAD02B66D16BC975D77CC1";
|
||||
pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; });
|
||||
dnn= "oai";
|
||||
nssai_sst=1;
|
||||
}
|
||||
|
||||
position0 = {
|
||||
@@ -13,12 +14,6 @@ position0 = {
|
||||
|
||||
thread-pool = "-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1"
|
||||
|
||||
rfsimulator = (
|
||||
{
|
||||
serveraddr = "127.0.0.1";
|
||||
}
|
||||
);
|
||||
|
||||
#/* configuration for channel modelisation */
|
||||
#/* To be included in main config file when */
|
||||
#/* channel modelisation is used (rfsimulator with chanmod options enabled) */
|
||||
@@ -45,4 +40,4 @@ channelmod = {
|
||||
ds_tdl = 0;
|
||||
}
|
||||
);
|
||||
};
|
||||
};
|
||||
@@ -2,7 +2,8 @@ uicc0 = {
|
||||
imsi = "208990100001100";
|
||||
key = "fec86ba6eb707ed08905757b1bb44b8f";
|
||||
opc= "C42449363BBAD02B66D16BC975D77CC1";
|
||||
pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; });
|
||||
dnn= "oai";
|
||||
nssai_sst=1;
|
||||
}
|
||||
|
||||
position0 = {
|
||||
@@ -13,40 +14,6 @@ position0 = {
|
||||
|
||||
thread-pool = "-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1"
|
||||
|
||||
rfsimulator = (
|
||||
{
|
||||
prop_delay = 20;
|
||||
options = ("chanmod");
|
||||
}
|
||||
);
|
||||
|
||||
RUs = (
|
||||
{
|
||||
nb_tx = 1;
|
||||
nb_rx = 1;
|
||||
att_tx = 0;
|
||||
att_rx = 0;
|
||||
max_rxgain = 114;
|
||||
sdr_addrs = "type=x300";
|
||||
clock_src = "internal";
|
||||
time_src = "internal";
|
||||
# if_freq = 3700000000L;
|
||||
# if_offset = 1000000;
|
||||
}
|
||||
);
|
||||
|
||||
cells = (
|
||||
{
|
||||
ru_id = 0;
|
||||
band = 254;
|
||||
rf_freq = 2488400000L;
|
||||
rf_offset = -873500000L;
|
||||
numerology = 0;
|
||||
N_RB_DL = 25;
|
||||
ssb_start = 60;
|
||||
}
|
||||
);
|
||||
|
||||
#/* configuration for channel modelisation */
|
||||
#/* To be included in main config file when */
|
||||
#/* channel modelisation is used (rfsimulator with chanmod options enabled) */
|
||||
|
||||
@@ -2,15 +2,11 @@ uicc0:
|
||||
imsi: 208990100001100
|
||||
key: fec86ba6eb707ed08905757b1bb44b8f
|
||||
opc: C42449363BBAD02B66D16BC975D77CC1
|
||||
pdu_sessions:
|
||||
- dnn: oai
|
||||
nssai_sst: 1
|
||||
dnn: oai
|
||||
nssai_sst: 1
|
||||
|
||||
thread-pool: "-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1"
|
||||
|
||||
rfsimulator:
|
||||
- serveraddr: "127.0.0.1"
|
||||
|
||||
#/* configuration for channel modelisation */
|
||||
#/* To be included in main config file when */
|
||||
#/* channel modelisation is used (rfsimulator with chanmod options enabled) */
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
uicc0:
|
||||
imsi: 208990100001100
|
||||
key: fec86ba6eb707ed08905757b1bb44b8f
|
||||
opc: C42449363BBAD02B66D16BC975D77CC1
|
||||
pdu_sessions:
|
||||
- dnn: oai
|
||||
nssai_sst: 1
|
||||
|
||||
thread-pool: "-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1"
|
||||
|
||||
channelmod:
|
||||
max_chan: 10;
|
||||
modellist: DefaultChannelList
|
||||
DefaultChannelList:
|
||||
- model_name: client_tx_channel_model
|
||||
type: AWGN
|
||||
ploss_dB: 0
|
||||
noise_power_dB: -100
|
||||
forgetfact: 0
|
||||
offset: 0
|
||||
ds_tdl: 0
|
||||
@@ -2,7 +2,8 @@ uicc0 = {
|
||||
imsi = "208970100001127";
|
||||
key = "fec86ba6eb707ed08905757b1bb44b8f";
|
||||
opc= "c42449363bbad02b66d16bc975d77cc1";
|
||||
pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; });
|
||||
dnn= "oai";
|
||||
nssai_sst=1;
|
||||
}
|
||||
|
||||
thread-pool = "-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1"
|
||||
|
||||
@@ -12,7 +12,9 @@ uicc0 = {
|
||||
imsi = "208950000000031";
|
||||
key = "0c0a34601d4f07677303652c0462535b";
|
||||
opc= "63bfa50ee6523365ff14c1f45f88737d";
|
||||
pdu_sessions = ({ dnn = "oai"; nssai_sst = 222; nssai_sd = 123; });
|
||||
dnn= "oai";
|
||||
nssai_sst=222;
|
||||
nssai_sd=123;
|
||||
}
|
||||
|
||||
MACRLCs = (
|
||||
|
||||
@@ -12,7 +12,9 @@ uicc0 = {
|
||||
imsi = "2089900007487";
|
||||
key = "fec86ba6eb707ed08905757b1bb44b8f";
|
||||
opc= "C42449363BBAD02B66D16BC975D77CC1";
|
||||
pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; nssai_sd = 1; });
|
||||
dnn= "oai";
|
||||
nssai_sst=1;
|
||||
nssai_sd=1;
|
||||
}
|
||||
|
||||
MACRLCs = (
|
||||
|
||||
@@ -18,7 +18,7 @@ gNBs =
|
||||
////////// Physical parameters:
|
||||
|
||||
min_rxtxtime = 6;
|
||||
enable_sdap = 0;
|
||||
enable_sdap = 1;
|
||||
|
||||
servingCellConfigCommon = (
|
||||
{
|
||||
@@ -205,15 +205,14 @@ RUs = (
|
||||
);
|
||||
|
||||
|
||||
rfsimulator = (
|
||||
{
|
||||
rfsimulator :
|
||||
{
|
||||
serveraddr = "server";
|
||||
serverport = 4043;
|
||||
options = (); #("saviq"); or/and "chanmod"
|
||||
modelname = "AWGN";
|
||||
IQfile = "/tmp/rfsimulator.iqs";
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
security = {
|
||||
# preferred ciphering algorithms
|
||||
|
||||
@@ -17,6 +17,9 @@ gNBs =
|
||||
|
||||
////////// Physical parameters:
|
||||
|
||||
do_CSIRS = 0;
|
||||
do_SRS = 0;
|
||||
|
||||
servingCellConfigCommon = (
|
||||
{
|
||||
#spCellConfigCommon
|
||||
@@ -200,15 +203,14 @@ RUs = (
|
||||
);
|
||||
|
||||
|
||||
rfsimulator = (
|
||||
rfsimulator :
|
||||
{
|
||||
serveraddr = "server";
|
||||
serverport = 4043;
|
||||
options = (); #("saviq"); or/and "chanmod"
|
||||
modelname = "AWGN";
|
||||
IQfile = "/tmp/rfsimulator.iqs";
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
security = {
|
||||
# preferred ciphering algorithms
|
||||
|
||||
@@ -15,6 +15,7 @@ Ref :
|
||||
DLSCH encoding : 200.0
|
||||
L1 Rx processing : 530.0
|
||||
PUSCH inner-receiver : 360.0
|
||||
Schedule Response : 1.0
|
||||
DL & UL scheduling timing : 17.0
|
||||
UL Indication : 1.0
|
||||
Slot Indication : 13.0
|
||||
@@ -30,6 +31,7 @@ DeviationThreshold :
|
||||
DLSCH encoding : 0.25
|
||||
L1 Rx processing : 0.25
|
||||
PUSCH inner-receiver : 0.25
|
||||
Schedule Response : 1.00
|
||||
DL & UL scheduling timing : 0.25
|
||||
UL Indication : 1.00
|
||||
Slot Indication : 0.50
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
#this is a configuration file
|
||||
#used to build real time processing statistics
|
||||
#for 5G NR phy test (gNB terminate)
|
||||
Title : Processing Time (us) from datalog_rt_stats.4x4.fhi72.yaml
|
||||
ColNames :
|
||||
- Metric
|
||||
- Average; Max; Count
|
||||
- Average vs Reference Deviation (Reference Value; Acceptability Deviation Threshold)
|
||||
Ref :
|
||||
tx_fhaul : 40.2
|
||||
feptx_prec (per port, half_slot) : 12.3
|
||||
L1 Tx processing : 221.0
|
||||
DLSCH encoding : 141.0
|
||||
L1 Rx processing : 332.5
|
||||
UL segments decoding : 55.2
|
||||
UL Indication : 0.4
|
||||
Slot Indication : 14.3
|
||||
PUSCH inner-receiver : 421.4
|
||||
DeviationThreshold :
|
||||
tx_fhaul : 0.25
|
||||
feptx_prec (per port, half_slot) : 0.25
|
||||
L1 Tx processing : 0.25
|
||||
DLSCH encoding : 0.25
|
||||
L1 Rx processing : 0.25
|
||||
UL segments decoding : 0.25
|
||||
UL Indication : 1.00
|
||||
Slot Indication : 0.50
|
||||
PUSCH inner-receiver : 0.25
|
||||
@@ -15,6 +15,7 @@ Ref :
|
||||
DLSCH encoding : 110.0
|
||||
L1 Rx processing : 345.0
|
||||
PUSCH inner-receiver : 150.0
|
||||
Schedule Response : 1.0
|
||||
DL & UL scheduling timing : 5.0
|
||||
UL Indication : 1.0
|
||||
Slot Indication : 6.0
|
||||
@@ -30,6 +31,7 @@ DeviationThreshold :
|
||||
DLSCH encoding : 0.25
|
||||
L1 Rx processing : 0.25
|
||||
PUSCH inner-receiver : 0.25
|
||||
Schedule Response : 1.00
|
||||
DL & UL scheduling timing : 0.50
|
||||
UL Indication : 1.00
|
||||
Slot Indication : 0.50
|
||||
|
||||
@@ -15,6 +15,7 @@ Ref :
|
||||
DLSCH encoding : 230.0
|
||||
L1 Rx processing : 175.0
|
||||
PUSCH inner-receiver : 100.0
|
||||
Schedule Response : 3.0
|
||||
DL & UL scheduling timing : 11.0
|
||||
UL Indication : 3.0
|
||||
Slot Indication : 14.0
|
||||
@@ -27,6 +28,7 @@ DeviationThreshold :
|
||||
DLSCH encoding : 0.25
|
||||
L1 Rx processing : 0.25
|
||||
PUSCH inner-receiver : 0.25
|
||||
Schedule Response : 1.00
|
||||
DL & UL scheduling timing : 0.50
|
||||
UL Indication : 1.00
|
||||
Slot Indication : 0.25
|
||||
|
||||
@@ -15,6 +15,7 @@ Ref :
|
||||
DLSCH encoding : 140.0
|
||||
L1 Rx processing : 345.0
|
||||
PUSCH inner-receiver : 155.0
|
||||
Schedule Response : 1.0
|
||||
DL & UL scheduling timing : 8.0
|
||||
UL Indication : 3.0
|
||||
Slot Indication : 9.0
|
||||
@@ -30,6 +31,7 @@ DeviationThreshold :
|
||||
DLSCH encoding : 0.25
|
||||
L1 Rx processing : 0.25
|
||||
PUSCH inner-receiver : 0.25
|
||||
Schedule Response : 1.00
|
||||
DL & UL scheduling timing : 0.35
|
||||
UL Indication : 1.00
|
||||
Slot Indication : 0.35
|
||||
|
||||
@@ -15,6 +15,7 @@ Ref :
|
||||
DLSCH encoding : 90.0
|
||||
L1 Rx processing : 290.0
|
||||
PUSCH inner-receiver : 115.0
|
||||
Schedule Response : 1.0
|
||||
DL & UL scheduling timing : 4.0
|
||||
UL Indication : 2.0
|
||||
Slot Indication : 5.0
|
||||
@@ -30,6 +31,7 @@ DeviationThreshold :
|
||||
DLSCH encoding : 0.25
|
||||
L1 Rx processing : 0.25
|
||||
PUSCH inner-receiver : 0.25
|
||||
Schedule Response : 1.00
|
||||
DL & UL scheduling timing : 0.50
|
||||
UL Indication : 1.00
|
||||
Slot Indication : 0.50
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
#/*
|
||||
# * 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
|
||||
# */
|
||||
#---------------------------------------------------------------------
|
||||
#
|
||||
# Dockerfile for the Open-Air-Interface BUILD service
|
||||
# Valid for Ubuntu 24.04
|
||||
#
|
||||
#---------------------------------------------------------------------
|
||||
FROM nvidia/cuda:12.9.1-devel-ubuntu22.04 AS cuda-image
|
||||
FROM ran-base:develop AS ran-tests
|
||||
|
||||
RUN rm -Rf /oai-ran
|
||||
COPY --from=cuda-image /usr/local/cuda/ /usr/local/cuda/
|
||||
|
||||
# Set the LD_LIBRARY_PATH to ensure the system can find the copied libraries.
|
||||
# This is crucial for applications that use CUDA.
|
||||
ENV LD_LIBRARY_PATH=/usr/local/cuda/lib64:/usr/local/cuda/targets/sbsa-linux/lib
|
||||
ENV PATH=/usr/local/cuda/bin:$PATH
|
||||
ENV C_INCLUDE_PATH=/usr/local/cuda/include
|
||||
|
||||
WORKDIR /oai-ran
|
||||
COPY . .
|
||||
|
||||
WORKDIR /oai-ran/build
|
||||
RUN cmake -GNinja -DENABLE_PHYSIM_TESTS=ON -DENABLE_TESTS=ON \
|
||||
-DSANITIZE_UNDEFINED=OFF -DSANITIZE_ADDRESS=OFF \
|
||||
-DCMAKE_C_FLAGS=-Werror -DCMAKE_CXX_FLAGS=-Werror \
|
||||
-DPHYSIM_CHECK_FILES="ThresholdsCuda.cmake" \
|
||||
-DCUDA_ENABLE=ON \
|
||||
-DUSE_UNIFIED_MEMORY=ON \
|
||||
-DUSE_ATS_MEMORY=OFF \
|
||||
-DCMAKE_RUNTIME_OUTPUT_DIRECTORY=/oai-ran/cmake_targets/ran_build/build \
|
||||
.. && \
|
||||
ninja test_channel_scalability test_multipath test_noise
|
||||
@@ -1,52 +0,0 @@
|
||||
#/*
|
||||
# * 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
|
||||
# */
|
||||
#---------------------------------------------------------------------
|
||||
#
|
||||
# Dockerfile for the Open-Air-Interface BUILD service
|
||||
# Valid for Ubuntu 24.04
|
||||
#
|
||||
#---------------------------------------------------------------------
|
||||
FROM nvidia/cuda:12.9.1-devel-ubuntu22.04 AS cuda-image
|
||||
FROM ran-base:develop AS ran-tests
|
||||
|
||||
RUN rm -Rf /oai-ran
|
||||
COPY --from=cuda-image /usr/local/cuda/ /usr/local/cuda/
|
||||
|
||||
# Set the LD_LIBRARY_PATH to ensure the system can find the copied libraries.
|
||||
# This is crucial for applications that use CUDA.
|
||||
ENV LD_LIBRARY_PATH=/usr/local/cuda/lib64:/usr/local/cuda/targets/sbsa-linux/lib
|
||||
ENV PATH=/usr/local/cuda/bin:$PATH
|
||||
ENV C_INCLUDE_PATH=/usr/local/cuda/include
|
||||
|
||||
WORKDIR /oai-ran
|
||||
COPY . .
|
||||
|
||||
WORKDIR /oai-ran/build
|
||||
RUN cmake -GNinja -DENABLE_PHYSIM_TESTS=ON -DENABLE_TESTS=ON \
|
||||
-DSANITIZE_UNDEFINED=OFF -DSANITIZE_ADDRESS=OFF \
|
||||
-DCMAKE_C_FLAGS=-Werror -DCMAKE_CXX_FLAGS=-Werror \
|
||||
-DPHYSIM_CHECK_FILES="ThresholdsCuda.cmake" \
|
||||
-DCUDA_ENABLE=ON \
|
||||
-DUSE_UNIFIED_MEMORY=ON \
|
||||
-DUSE_ATS_MEMORY=OFF \
|
||||
-DCMAKE_RUNTIME_OUTPUT_DIRECTORY=/oai-ran/cmake_targets/ran_build/build \
|
||||
.. && \
|
||||
ninja nr_ulsim nr_dlsim
|
||||
@@ -44,4 +44,4 @@ RUN cmake -GNinja -DENABLE_PHYSIM_TESTS=ON \
|
||||
-DCMAKE_C_FLAGS=-Werror -DCMAKE_CXX_FLAGS=-Werror \
|
||||
-DPHYSIM_CHECK_FILES="ThresholdsGracehopper.cmake" \
|
||||
.. && \
|
||||
ninja ldpctest polartest smallblocktest nr_pbchsim nr_dlschsim nr_ulschsim nr_dlsim nr_ulsim nr_pucchsim nr_prachsim nr_psbchsim nr_srssim
|
||||
ninja ldpctest polartest smallblocktest nr_pbchsim nr_dlschsim nr_ulschsim nr_dlsim nr_ulsim nr_pucchsim nr_prachsim nr_psbchsim
|
||||
|
||||
@@ -58,10 +58,17 @@ import re # reg
|
||||
import time # sleep
|
||||
import os
|
||||
import subprocess
|
||||
import lxml.etree as ET
|
||||
import xml.etree.ElementTree as ET
|
||||
import logging
|
||||
import signal
|
||||
import traceback
|
||||
logging.basicConfig(
|
||||
level=logging.DEBUG,
|
||||
stream=sys.stdout,
|
||||
format="[%(asctime)s] %(levelname)8s: %(message)s"
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
#-----------------------------------------------------------
|
||||
@@ -78,7 +85,15 @@ def CheckClassValidity(xml_class_list,action,id):
|
||||
resp=True
|
||||
return resp
|
||||
|
||||
def ExecuteActionWithParam(action, ctx, node):
|
||||
#assigning parameters to object instance attributes (even if the attributes do not exist !!)
|
||||
def AssignParams(params_dict):
|
||||
|
||||
for key,value in params_dict.items():
|
||||
setattr(CiTestObj, key, value)
|
||||
setattr(RAN, key, value)
|
||||
setattr(HTML, key, value)
|
||||
|
||||
def ExecuteActionWithParam(action, ctx):
|
||||
global RAN
|
||||
global HTML
|
||||
global CONTAINERS
|
||||
@@ -87,11 +102,12 @@ def ExecuteActionWithParam(action, ctx, node):
|
||||
if action == 'Build_eNB' or action == 'Build_Image' or action == 'Build_Proxy' or action == "Build_Cluster_Image" or action == "Build_Run_Tests":
|
||||
RAN.Build_eNB_args=test.findtext('Build_eNB_args')
|
||||
CONTAINERS.imageKind=test.findtext('kind')
|
||||
node = test.findtext('node')
|
||||
proxy_commit = test.findtext('proxy_commit')
|
||||
if proxy_commit is not None:
|
||||
CONTAINERS.proxyCommit = proxy_commit
|
||||
if action == 'Build_eNB':
|
||||
success = cls_native.Native.Build(ctx, node, HTML, RAN.eNBSourceCodePath, RAN.Build_eNB_args)
|
||||
success = cls_native.Native.Build(ctx, node, HTML.testCase_id, HTML, RAN.eNBSourceCodePath, RAN.Build_eNB_args)
|
||||
elif action == 'Build_Image':
|
||||
success = CONTAINERS.BuildImage(ctx, node, HTML)
|
||||
elif action == 'Build_Proxy':
|
||||
@@ -102,52 +118,108 @@ def ExecuteActionWithParam(action, ctx, node):
|
||||
success = CONTAINERS.BuildRunTests(ctx, node, HTML)
|
||||
|
||||
elif action == 'Initialize_eNB':
|
||||
node = test.findtext('node')
|
||||
datalog_rt_stats_file=test.findtext('rt_stats_cfg')
|
||||
if datalog_rt_stats_file is None:
|
||||
RAN.datalog_rt_stats_file='datalog_rt_stats.default.yaml'
|
||||
else:
|
||||
RAN.datalog_rt_stats_file=datalog_rt_stats_file
|
||||
RAN.Initialize_eNB_args=test.findtext('Initialize_eNB_args')
|
||||
USRPIPAddress = test.findtext('USRP_IPAddress') or ''
|
||||
|
||||
#local variable air_interface
|
||||
air_interface = test.findtext('air_interface')
|
||||
if (air_interface is None) or (air_interface.lower() not in ['nr','lte']):
|
||||
RAN.air_interface = 'lte-softmodem'
|
||||
else:
|
||||
RAN.air_interface = air_interface.lower() +'-softmodem'
|
||||
|
||||
cmd_prefix = test.findtext('cmd_prefix')
|
||||
if cmd_prefix is not None: RAN.cmd_prefix = cmd_prefix
|
||||
success = RAN.InitializeeNB(ctx, node, HTML)
|
||||
|
||||
elif action == 'Terminate_eNB':
|
||||
services = []
|
||||
analysis = test.find("analysis")
|
||||
if analysis is not None:
|
||||
# services: multiple services to analyse, separated by whitespace
|
||||
services = analysis.findtext("services", default="").split()
|
||||
# service: individual services to analyze, in case they have whitespace
|
||||
services = services + [s.text for s in analysis.findall("service")]
|
||||
success = RAN.TerminateeNB(ctx, node, HTML, services)
|
||||
node = test.findtext('node')
|
||||
#retx checkers
|
||||
string_field = test.findtext('d_retx_th')
|
||||
if (string_field is not None):
|
||||
RAN.ran_checkers['d_retx_th'] = [float(x) for x in string_field.split(',')]
|
||||
string_field=test.findtext('u_retx_th')
|
||||
if (string_field is not None):
|
||||
RAN.ran_checkers['u_retx_th'] = [float(x) for x in string_field.split(',')]
|
||||
|
||||
#local variable air_interface
|
||||
air_interface = test.findtext('air_interface')
|
||||
if (air_interface is None) or (air_interface.lower() not in ['nr','lte']):
|
||||
RAN.air_interface = 'lte-softmodem'
|
||||
else:
|
||||
RAN.air_interface = air_interface.lower() +'-softmodem'
|
||||
success = RAN.TerminateeNB(ctx, node, HTML)
|
||||
|
||||
elif action == 'Initialize_UE' or action == 'Attach_UE' or action == 'Detach_UE' or action == 'Terminate_UE' or action == 'CheckStatusUE' or action == 'DataEnable_UE' or action == 'DataDisable_UE':
|
||||
CiTestObj.ue_ids = test.findtext('id').split(' ')
|
||||
if force_local:
|
||||
# Change all execution targets to localhost
|
||||
CiTestObj.nodes = ['localhost'] * len(CiTestObj.ue_ids)
|
||||
else:
|
||||
if test.findtext('nodes'):
|
||||
CiTestObj.nodes = test.findtext('nodes').split(' ')
|
||||
if len(CiTestObj.ue_ids) != len(CiTestObj.nodes):
|
||||
logging.error('Number of Nodes are not equal to the total number of UEs')
|
||||
sys.exit("Mismatch in number of Nodes and UIs")
|
||||
else:
|
||||
CiTestObj.nodes = [None] * len(CiTestObj.ue_ids)
|
||||
if action == 'Initialize_UE':
|
||||
success = CiTestObj.InitializeUE(node, HTML)
|
||||
success = CiTestObj.InitializeUE(HTML)
|
||||
elif action == 'Attach_UE':
|
||||
success = CiTestObj.AttachUE(node, HTML)
|
||||
success = CiTestObj.AttachUE(HTML)
|
||||
elif action == 'Detach_UE':
|
||||
success = CiTestObj.DetachUE(node, HTML)
|
||||
success = CiTestObj.DetachUE(HTML)
|
||||
elif action == 'Terminate_UE':
|
||||
success = CiTestObj.TerminateUE(ctx, node, HTML)
|
||||
success = CiTestObj.TerminateUE(ctx, HTML)
|
||||
elif action == 'CheckStatusUE':
|
||||
success = CiTestObj.CheckStatusUE(node, HTML)
|
||||
success = CiTestObj.CheckStatusUE(HTML)
|
||||
elif action == 'DataEnable_UE':
|
||||
success = CiTestObj.DataEnableUE(node, HTML)
|
||||
success = CiTestObj.DataEnableUE(HTML)
|
||||
elif action == 'DataDisable_UE':
|
||||
success = CiTestObj.DataDisableUE(node, HTML)
|
||||
success = CiTestObj.DataDisableUE(HTML)
|
||||
|
||||
elif action == 'Ping':
|
||||
CiTestObj.ping_args = test.findtext('ping_args')
|
||||
CiTestObj.ping_packetloss_threshold = test.findtext('ping_packetloss_threshold')
|
||||
CiTestObj.ue_ids = test.findtext('id').split(' ')
|
||||
CiTestObj.svr_id = test.findtext('svr_id')
|
||||
CiTestObj.svr_id = test.findtext('svr_id') or None
|
||||
if test.findtext('svr_node'):
|
||||
CiTestObj.svr_node = test.findtext('svr_node') if not force_local else 'localhost'
|
||||
if force_local:
|
||||
# Change all execution targets to localhost
|
||||
CiTestObj.nodes = ['localhost'] * len(CiTestObj.ue_ids)
|
||||
else:
|
||||
if test.findtext('nodes'):
|
||||
CiTestObj.nodes = test.findtext('nodes').split(' ')
|
||||
if len(CiTestObj.ue_ids) != len(CiTestObj.nodes):
|
||||
logging.error('Number of Nodes are not equal to the total number of UEs')
|
||||
sys.exit("Mismatch in number of Nodes and UIs")
|
||||
else:
|
||||
CiTestObj.nodes = [None] * len(CiTestObj.ue_ids)
|
||||
ping_rttavg_threshold = test.findtext('ping_rttavg_threshold') or ''
|
||||
success = CiTestObj.Ping(ctx, node, HTML)
|
||||
success = CiTestObj.Ping(ctx, HTML)
|
||||
|
||||
elif action == 'Iperf' or action == 'Iperf2_Unidir':
|
||||
CiTestObj.iperf_args = test.findtext('iperf_args')
|
||||
CiTestObj.ue_ids = test.findtext('id').split(' ')
|
||||
CiTestObj.svr_id = test.findtext('svr_id')
|
||||
CiTestObj.svr_id = test.findtext('svr_id') or None
|
||||
if force_local:
|
||||
# Change all execution targets to localhost
|
||||
CiTestObj.nodes = ['localhost'] * len(CiTestObj.ue_ids)
|
||||
else:
|
||||
if test.findtext('nodes'):
|
||||
CiTestObj.nodes = test.findtext('nodes').split(' ')
|
||||
if len(CiTestObj.ue_ids) != len(CiTestObj.nodes):
|
||||
logging.error('Number of Nodes are not equal to the total number of UEs')
|
||||
sys.exit("Mismatch in number of Nodes and UIs")
|
||||
else:
|
||||
CiTestObj.nodes = [None] * len(CiTestObj.ue_ids)
|
||||
if test.findtext('svr_node'):
|
||||
CiTestObj.svr_node = test.findtext('svr_node') if not force_local else 'localhost'
|
||||
CiTestObj.iperf_packetloss_threshold = test.findtext('iperf_packetloss_threshold')
|
||||
@@ -157,10 +229,14 @@ def ExecuteActionWithParam(action, ctx, node):
|
||||
if CiTestObj.iperf_profile != 'balanced' and CiTestObj.iperf_profile != 'unbalanced' and CiTestObj.iperf_profile != 'single-ue':
|
||||
logging.error(f'test-case has wrong profile {CiTestObj.iperf_profile}, forcing balanced')
|
||||
CiTestObj.iperf_profile = 'balanced'
|
||||
CiTestObj.iperf_options = test.findtext('iperf_options') or 'check'
|
||||
if CiTestObj.iperf_options != 'check' and CiTestObj.iperf_options != 'sink':
|
||||
logging.error('test-case has wrong option ' + CiTestObj.iperf_options)
|
||||
CiTestObj.iperf_options = 'check'
|
||||
if action == 'Iperf':
|
||||
success = CiTestObj.Iperf(ctx, node, HTML)
|
||||
success = CiTestObj.Iperf(ctx, HTML)
|
||||
elif action == 'Iperf2_Unidir':
|
||||
success = CiTestObj.Iperf2_Unidir(ctx, node, HTML)
|
||||
success = CiTestObj.Iperf2_Unidir(ctx, HTML)
|
||||
|
||||
elif action == 'IdleSleep':
|
||||
st = test.findtext('idle_sleep_time_in_sec') or "5"
|
||||
@@ -168,15 +244,17 @@ def ExecuteActionWithParam(action, ctx, node):
|
||||
|
||||
elif action == 'Deploy_Run_OC_PhySim':
|
||||
oc_release = test.findtext('oc_release')
|
||||
node = test.findtext('node') or None
|
||||
script = "scripts/oc-deploy-physims.sh"
|
||||
image_tag = cls_containerize.CreateTag(CLUSTER.ranCommitID, CLUSTER.ranBranch, CLUSTER.ranAllowMerge)
|
||||
options = f"oaicicd-core-for-ci-ran {oc_release} {image_tag} {CLUSTER.eNBSourceCodePath}"
|
||||
workdir = CLUSTER.eNBSourceCodePath
|
||||
success = cls_oaicitest.Deploy_Physim(ctx, HTML, node, workdir, script, options)
|
||||
|
||||
elif action == 'Build_Deploy_PhySim':
|
||||
elif action == 'Build_Deploy_Docker_PhySim' or action == 'Build_Deploy_Source_PhySim':
|
||||
node = test.findtext('node') or None
|
||||
ctest_opt = test.findtext('ctest-opt') or ''
|
||||
script = test.findtext('script')
|
||||
script = "scripts/docker-build-and-deploy-physims.sh" if action == 'Build_Deploy_Docker_PhySim' else 'scripts/source-deploy-physims.sh'
|
||||
options = f"{CONTAINERS.eNBSourceCodePath} {ctest_opt}"
|
||||
workdir = CONTAINERS.eNBSourceCodePath
|
||||
success = cls_oaicitest.Deploy_Physim(ctx, HTML, node, workdir, script, options)
|
||||
@@ -186,24 +264,22 @@ def ExecuteActionWithParam(action, ctx, node):
|
||||
core_op = getattr(cls_oaicitest.OaiCiTest, action)
|
||||
success = core_op(cn_id, ctx, HTML)
|
||||
|
||||
elif action == 'Deploy_Object' or action == 'Undeploy_Object' or action == "Create_Workspace" or action == "Stop_Object":
|
||||
elif action == 'Deploy_Object' or action == 'Undeploy_Object' or action == "Create_Workspace":
|
||||
node = test.findtext('node')
|
||||
CONTAINERS.yamlPath = test.findtext('yaml_path')
|
||||
string_field=test.findtext('d_retx_th')
|
||||
if (string_field is not None):
|
||||
CONTAINERS.ran_checkers['d_retx_th'] = [float(x) for x in string_field.split(',')]
|
||||
string_field=test.findtext('u_retx_th')
|
||||
if (string_field is not None):
|
||||
CONTAINERS.ran_checkers['u_retx_th'] = [float(x) for x in string_field.split(',')]
|
||||
CONTAINERS.services = test.findtext('services')
|
||||
CONTAINERS.num_attempts = int(test.findtext('num_attempts') or 1)
|
||||
CONTAINERS.deploymentTag = cls_containerize.CreateTag(CONTAINERS.ranCommitID, CONTAINERS.ranBranch, CONTAINERS.ranAllowMerge)
|
||||
if action == 'Deploy_Object':
|
||||
success = CONTAINERS.DeployObject(ctx, node, HTML)
|
||||
elif action == 'Stop_Object':
|
||||
success = CONTAINERS.StopObject(ctx, node, HTML)
|
||||
elif action == 'Undeploy_Object':
|
||||
analysis = test.find("analysis")
|
||||
services = []
|
||||
if analysis is not None:
|
||||
# services: multiple services to analyse, separated by whitespace
|
||||
services = analysis.findtext("services", default="").split()
|
||||
# service: individual services to analyze, in case they have whitespace
|
||||
services = services + [s.text for s in analysis.findall("service")]
|
||||
success = CONTAINERS.UndeployObject(ctx, node, HTML, services)
|
||||
success = CONTAINERS.UndeployObject(ctx, node, HTML, RAN)
|
||||
elif action == 'Create_Workspace':
|
||||
if force_local:
|
||||
# Do not create a working directory when running locally. Current repo directory will be used
|
||||
@@ -211,12 +287,15 @@ def ExecuteActionWithParam(action, ctx, node):
|
||||
success = CONTAINERS.Create_Workspace(node, HTML)
|
||||
|
||||
elif action == 'LicenceAndFormattingCheck':
|
||||
node = test.findtext('node')
|
||||
success = SCA.LicenceAndFormattingCheck(ctx, node, HTML)
|
||||
|
||||
elif action == 'Cppcheck_Analysis':
|
||||
node = test.findtext('node')
|
||||
success = SCA.CppCheckAnalysis(ctx, node, HTML)
|
||||
|
||||
elif action == 'Push_Local_Registry':
|
||||
node = test.findtext('node')
|
||||
tag_prefix = test.findtext('tag_prefix') or ""
|
||||
success = CONTAINERS.Push_Image_to_Local_Registry(node, HTML, tag_prefix)
|
||||
|
||||
@@ -224,6 +303,7 @@ def ExecuteActionWithParam(action, ctx, node):
|
||||
if force_local:
|
||||
# Do not pull or remove images when running locally. User is supposed to handle image creation & cleanup
|
||||
return True
|
||||
node = test.findtext('node')
|
||||
tag_prefix = test.findtext('tag_prefix') or ""
|
||||
images = test.findtext('images').split()
|
||||
# hack: for FlexRIC, we need to overwrite the tag to use
|
||||
@@ -236,52 +316,50 @@ def ExecuteActionWithParam(action, ctx, node):
|
||||
success = CONTAINERS.Clean_Test_Server_Images(HTML, node, images, tag=tag)
|
||||
|
||||
elif action == 'Custom_Command':
|
||||
node = test.findtext('node')
|
||||
if force_local:
|
||||
# Change all execution targets to localhost
|
||||
node = 'localhost'
|
||||
command = test.findtext('command')
|
||||
# Allow referencing repository workspace path in XML via %%workspace%%
|
||||
command = command.replace("%%workspace%%", CONTAINERS.eNBSourceCodePath)
|
||||
success = cls_oaicitest.Custom_Command(HTML, node, command)
|
||||
|
||||
elif action == 'Custom_Script':
|
||||
node = test.findtext('node')
|
||||
script = test.findtext('script')
|
||||
args = test.findtext('args')
|
||||
# Allow referencing repository workspace path in XML via %%workspace%%
|
||||
script = script.replace("%%workspace%%", CONTAINERS.eNBSourceCodePath)
|
||||
success = cls_oaicitest.Custom_Script(HTML, node, script, args)
|
||||
success = cls_oaicitest.Custom_Script(HTML, node, script)
|
||||
|
||||
elif action == 'Pull_Cluster_Image':
|
||||
tag_prefix = test.findtext('tag_prefix') or ""
|
||||
images = test.findtext('images').split()
|
||||
node = test.findtext('node')
|
||||
success = CLUSTER.PullClusterImage(HTML, node, images, tag_prefix=tag_prefix)
|
||||
|
||||
elif action == 'AnalyzeRTStats':
|
||||
yaml = test.findtext('stats_cfg')
|
||||
success = RAN.AnalyzeRTStats(HTML, node, ctx, yaml)
|
||||
|
||||
elif action == 'AnalyzeRTStats_Object':
|
||||
yaml = test.findtext('stats_cfg')
|
||||
success = CONTAINERS.AnalyzeRTStatsObject(HTML, node, ctx, yaml)
|
||||
|
||||
else:
|
||||
logging.warning(f"unknown action {action}, skip step")
|
||||
success = True # by default, we skip the step and print a warning
|
||||
|
||||
return success
|
||||
|
||||
test_runner_abort = False
|
||||
def receive_signal(signum, frame):
|
||||
global test_runner_abort
|
||||
if not test_runner_abort:
|
||||
logging.warning("received signal, canceling steps")
|
||||
logging.info("send signal again to exit immediately")
|
||||
test_runner_abort = True
|
||||
else:
|
||||
logging.warning("received signal again, exiting")
|
||||
sys.exit(1)
|
||||
#check if given test is in list
|
||||
#it is in list if one of the strings in 'list' is at the beginning of 'test'
|
||||
def test_in_list(test, list):
|
||||
for check in list:
|
||||
check=check.replace('+','')
|
||||
if (test.startswith(check)):
|
||||
return True
|
||||
return False
|
||||
|
||||
def ShowTestID(ctx, desc, file, line):
|
||||
def receive_signal(signum, frame):
|
||||
sys.exit(1)
|
||||
|
||||
def ShowTestID(ctx, desc):
|
||||
logging.info(f'\u001B[1m----------------------------------------\u001B[0m')
|
||||
logging.info(f'\u001B[1m Test #{ctx.test_idx} ({file}:{line}) \u001B[0m')
|
||||
logging.info(f'\u001B[1m {desc} \u001B[0m')
|
||||
logging.info(f'\u001B[1m Test ID: {ctx.test_id} (#{ctx.count}) \u001B[0m')
|
||||
logging.info(f'\u001B[1m {desc} \u001B[0m')
|
||||
logging.info(f'\u001B[1m----------------------------------------\u001B[0m')
|
||||
|
||||
#-----------------------------------------------------------
|
||||
@@ -321,13 +399,17 @@ CLUSTER = cls_cluster.Cluster()
|
||||
import args_parse
|
||||
# Force local execution, move all execution targets to localhost
|
||||
force_local = False
|
||||
mode, force_local, date_fmt = args_parse.ArgsParse(sys.argv,CiTestObj,RAN,HTML,CONTAINERS,HELP,SCA,CLUSTER)
|
||||
fmt = "%(levelname)8s: %(message)s"
|
||||
if date_fmt:
|
||||
fmt = "[%(asctime)s] %(levelname)s %(message)s"
|
||||
logging.basicConfig(level=logging.DEBUG, stream=sys.stdout, format=fmt, datefmt=date_fmt,)
|
||||
py_param_file_present, py_params, mode, force_local = args_parse.ArgsParse(sys.argv,CiTestObj,RAN,HTML,CONTAINERS,HELP,SCA,CLUSTER)
|
||||
|
||||
|
||||
|
||||
#-----------------------------------------------------------
|
||||
# TEMPORARY params management (UNUSED)
|
||||
#-----------------------------------------------------------
|
||||
#temporary solution for testing:
|
||||
if py_param_file_present == True:
|
||||
AssignParams(py_params)
|
||||
|
||||
#-----------------------------------------------------------
|
||||
# mode amd XML class (action) analysis
|
||||
#-----------------------------------------------------------
|
||||
@@ -344,7 +426,18 @@ elif re.match('^TerminateSPGW$', mode, re.IGNORECASE):
|
||||
elif re.match('^LogCollectBuild$', mode, re.IGNORECASE):
|
||||
logging.warning("Option LogCollectBuild ignored")
|
||||
elif re.match('^LogCollecteNB$', mode, re.IGNORECASE):
|
||||
logging.warning("Option LogCollecteNB ignored")
|
||||
if RAN.eNBSourceCodePath == '':
|
||||
HELP.GenericHelp(CONST.Version)
|
||||
sys.exit('Insufficient Parameter')
|
||||
if os.path.isdir('cmake_targets/log'):
|
||||
cmd = 'zip -r enb.log.' + RAN.BuildId + '.zip cmake_targets/log'
|
||||
logging.info(cmd)
|
||||
try:
|
||||
zipStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=60)
|
||||
except subprocess.CalledProcessError as e:
|
||||
logging.error("Command '{}' returned non-zero exit status {}.".format(e.cmd, e.returncode))
|
||||
logging.error("Error output:\n{}".format(e.output))
|
||||
sys.exit(0)
|
||||
elif re.match('^LogCollectHSS$', mode, re.IGNORECASE):
|
||||
logging.warning("Option LogCollectHSS ignored")
|
||||
elif re.match('^LogCollectMME$', mode, re.IGNORECASE):
|
||||
@@ -421,54 +514,90 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re
|
||||
xmlTree = ET.parse(xml_test_file)
|
||||
xmlRoot = xmlTree.getroot()
|
||||
|
||||
exclusion_tests=xmlRoot.findtext('TestCaseExclusionList',default='')
|
||||
requested_tests=xmlRoot.findtext('TestCaseRequestedList',default='')
|
||||
if (HTML.nbTestXMLfiles == 1):
|
||||
HTML.htmlTabRefs.append(xmlRoot.findtext('htmlTabRef',default='test-tab-0'))
|
||||
HTML.htmlTabNames.append(xmlRoot.findtext('htmlTabName',default='Test-0'))
|
||||
all_tests=xmlRoot.findall('testCase')
|
||||
|
||||
signal.signal(signal.SIGINT, receive_signal)
|
||||
exclusion_tests=exclusion_tests.split()
|
||||
requested_tests=requested_tests.split()
|
||||
|
||||
#check that exclusion tests are well formatted
|
||||
#(6 digits or less than 6 digits followed by +)
|
||||
for test in exclusion_tests:
|
||||
if (not re.match('^[0-9]{6}$', test) and
|
||||
not re.match('^[0-9]{1,5}\\+$', test)):
|
||||
logging.error('exclusion test is invalidly formatted: ' + test)
|
||||
sys.exit(1)
|
||||
else:
|
||||
logging.info(test)
|
||||
|
||||
#check that requested tests are well formatted
|
||||
#(6 digits or less than 6 digits followed by +)
|
||||
#be verbose
|
||||
for test in requested_tests:
|
||||
if (re.match('^[0-9]{6}$', test) or
|
||||
re.match('^[0-9]{1,5}\\+$', test)):
|
||||
logging.info('test group/case requested: ' + test)
|
||||
else:
|
||||
logging.error('requested test is invalidly formatted: ' + test)
|
||||
sys.exit(1)
|
||||
|
||||
#get the list of tests to be done
|
||||
todo_tests=[]
|
||||
for test in requested_tests:
|
||||
if (test_in_list(test, exclusion_tests)):
|
||||
logging.info('test will be skipped: ' + test)
|
||||
else:
|
||||
#logging.info('test will be run: ' + test)
|
||||
todo_tests.append(test)
|
||||
|
||||
signal.signal(signal.SIGUSR1, receive_signal)
|
||||
|
||||
HTML.CreateHtmlTabHeader()
|
||||
|
||||
task_set_succeeded = True
|
||||
HTML.startTime=int(round(time.time() * 1000))
|
||||
|
||||
for index, test in enumerate(all_tests, start=1):
|
||||
if test_runner_abort:
|
||||
task_set_succeeded = False
|
||||
test_case_idx = f"{index:06d}"
|
||||
ctx = TestCaseCtx(int(test_case_idx), logPath)
|
||||
HTML.testCaseIdx = test_case_idx
|
||||
desc = test.findtext('desc')
|
||||
node = test.findtext('node') if not force_local else 'localhost'
|
||||
always_exec = test.findtext('always_exec') in ['True', 'true', 'Yes', 'yes']
|
||||
may_fail = test.findtext('may_fail') in ['True', 'true', 'Yes', 'yes']
|
||||
HTML.desc = desc
|
||||
action = test.findtext('class')
|
||||
if not CheckClassValidity(xml_class_list, action, test_case_idx):
|
||||
task_set_succeeded = False
|
||||
continue
|
||||
file = os.path.basename(xml_test_file)
|
||||
line = test.find('class').sourceline
|
||||
ShowTestID(ctx, desc, file, line)
|
||||
if not task_set_succeeded and not always_exec:
|
||||
msg = f"skipping test due to prior error"
|
||||
logging.warning(msg)
|
||||
HTML.CreateHtmlTestRowQueue(msg, "SKIP", [])
|
||||
continue
|
||||
try:
|
||||
test_succeeded = ExecuteActionWithParam(action, ctx, node)
|
||||
if not test_succeeded and may_fail:
|
||||
logging.warning(f"test ID {test_case_idx} action {action} may or may not fail, proceeding despite error")
|
||||
elif not test_succeeded:
|
||||
logging.error(f"test ID {test_case_idx} action {action} failed ({test_succeeded}), skipping next tests")
|
||||
i = 0
|
||||
for test_case_id in todo_tests:
|
||||
for test in all_tests:
|
||||
id = test.get('id')
|
||||
if test_case_id != id:
|
||||
continue
|
||||
i += 1
|
||||
CiTestObj.testCase_id = id
|
||||
ctx = TestCaseCtx(i, int(id), logPath)
|
||||
HTML.testCase_id=CiTestObj.testCase_id
|
||||
desc = test.findtext('desc')
|
||||
always_exec = test.findtext('always_exec') in ['True', 'true', 'Yes', 'yes']
|
||||
may_fail = test.findtext('may_fail') in ['True', 'true', 'Yes', 'yes']
|
||||
HTML.desc = desc
|
||||
action = test.findtext('class')
|
||||
if (CheckClassValidity(xml_class_list, action, id) == False):
|
||||
task_set_succeeded = False
|
||||
except Exception as e:
|
||||
s = traceback.format_exc()
|
||||
logging.error(f'while running CI, an exception occurred:\n{s}')
|
||||
HTML.CreateHtmlTestRowQueue("N/A", 'KO', [f"CI test code encountered an exception:\n{s}"])
|
||||
task_set_succeeded = False
|
||||
continue
|
||||
continue
|
||||
ShowTestID(ctx, desc)
|
||||
if not task_set_succeeded and not always_exec:
|
||||
msg = f"skipping test due to prior error"
|
||||
logging.warning(msg)
|
||||
HTML.CreateHtmlTestRowQueue(msg, "SKIP", [])
|
||||
break
|
||||
try:
|
||||
test_succeeded = ExecuteActionWithParam(action, ctx)
|
||||
if not test_succeeded and may_fail:
|
||||
logging.warning(f"test ID {test_case_id} action {action} may or may not fail, proceeding despite error")
|
||||
elif not test_succeeded:
|
||||
logging.error(f"test ID {test_case_id} action {action} failed ({test_succeeded}), skipping next tests")
|
||||
task_set_succeeded = False
|
||||
except Exception as e:
|
||||
s = traceback.format_exc()
|
||||
logging.error(f'while running CI, an exception occurred:\n{s}')
|
||||
HTML.CreateHtmlTestRowQueue("N/A", 'KO', [f"CI test code encountered an exception:\n{s}"])
|
||||
task_set_succeeded = False
|
||||
break
|
||||
|
||||
if not task_set_succeeded:
|
||||
logging.error('\u001B[1;37;41mScenario failed\u001B[0m')
|
||||
|
||||
@@ -31,16 +31,21 @@
|
||||
#-----------------------------------------------------------
|
||||
# Import
|
||||
#-----------------------------------------------------------
|
||||
import sys # arg
|
||||
import re # reg
|
||||
import logging
|
||||
import os
|
||||
import time
|
||||
import yaml
|
||||
import cls_cmd
|
||||
|
||||
|
||||
#-----------------------------------------------------------
|
||||
# OAI Testing modules
|
||||
#-----------------------------------------------------------
|
||||
import cls_cmd
|
||||
import cls_analysis
|
||||
import helpreadme as HELP
|
||||
import constants as CONST
|
||||
from cls_ci_helper import archiveArtifact
|
||||
|
||||
#-----------------------------------------------------------
|
||||
@@ -58,9 +63,17 @@ class RANManagement():
|
||||
self.eNBSourceCodePath = ''
|
||||
self.Initialize_eNB_args = ''
|
||||
self.imageKind = ''
|
||||
self.air_interface = ''
|
||||
self.eNBOptions = ['', '', '']
|
||||
self.eNBmbmsEnables = [False, False, False]
|
||||
self.eNBstatuses = [-1, -1, -1]
|
||||
self.testCase_id = ''
|
||||
self.runtime_stats= ''
|
||||
self.datalog_rt_stats={}
|
||||
self.datalog_rt_stats_file='datalog_rt_stats.default.yaml'
|
||||
self.USRPIPAddress = ''
|
||||
#checkers from xml
|
||||
self.ran_checkers={}
|
||||
self.cmd_prefix = '' # prefix before {lte,nr}-softmodem
|
||||
self.node = ''
|
||||
self.command = ''
|
||||
@@ -75,6 +88,7 @@ class RANManagement():
|
||||
raise ValueError(f"{node=}")
|
||||
logging.debug('Starting eNB/gNB on server: ' + node)
|
||||
|
||||
self.testCase_id = HTML.testCase_id
|
||||
lSourcePath = self.eNBSourceCodePath
|
||||
cmd = cls_cmd.getConnection(node)
|
||||
|
||||
@@ -90,7 +104,7 @@ class RANManagement():
|
||||
|
||||
logfile = f'{lSourcePath}/cmake_targets/enb.log'
|
||||
cmd.cd(f"{lSourcePath}/cmake_targets/") # important: set wd so nrL1_stats.log etc are logged here
|
||||
cmd.run(f'sudo -E stdbuf -o0 {self.cmd_prefix} {lSourcePath}/cmake_targets/ran_build/build/nr-softmodem -O {lSourcePath}/{full_config_file} {extra_options} > {logfile} 2>&1 &')
|
||||
cmd.run(f'sudo -E stdbuf -o0 {self.cmd_prefix} {lSourcePath}/cmake_targets/ran_build/build/{self.air_interface} -O {lSourcePath}/{full_config_file} {extra_options} > {logfile} 2>&1 &')
|
||||
|
||||
if extra_options != '':
|
||||
self.eNBOptions = extra_options
|
||||
@@ -104,12 +118,12 @@ class RANManagement():
|
||||
enbDidSync = True
|
||||
break
|
||||
if not enbDidSync:
|
||||
cmd.run(f'sudo killall -9 nr-softmodem') # in case it did not stop automatically
|
||||
cmd.run(f'sudo killall -9 {self.air_interface}') # in case it did not stop automatically
|
||||
archiveArtifact(cmd, ctx, logfile)
|
||||
|
||||
cmd.close()
|
||||
|
||||
msg = f'{self.cmd_prefix} nr-softmodem -O {config_file} {extra_options}'
|
||||
msg = f'{self.cmd_prefix} {self.air_interface} -O {config_file} {extra_options}'
|
||||
if enbDidSync:
|
||||
logging.debug('\u001B[1m Initialize eNB/gNB Completed\u001B[0m')
|
||||
HTML.CreateHtmlTestRowQueue(msg, 'OK', [])
|
||||
@@ -119,7 +133,7 @@ class RANManagement():
|
||||
|
||||
return enbDidSync
|
||||
|
||||
def TerminateeNB(self, ctx, node, HTML, to_analyze):
|
||||
def TerminateeNB(self, ctx, node, HTML):
|
||||
logging.debug('Stopping eNB/gNB on server: ' + node)
|
||||
lSourcePath = self.eNBSourceCodePath
|
||||
cmd = cls_cmd.getConnection(node)
|
||||
@@ -134,13 +148,14 @@ class RANManagement():
|
||||
if result is not None:
|
||||
cmd.run('sudo -S killall --signal SIGKILL -r .*-softmodem')
|
||||
time.sleep(5)
|
||||
HTML.CreateHtmlTestRowQueue(node, 'OK', ['Undeployment successful'])
|
||||
|
||||
# see InitializeeNB()
|
||||
logfile = f'{lSourcePath}/cmake_targets/enb.log'
|
||||
logdir = os.path.dirname(logfile)
|
||||
|
||||
file = archiveArtifact(cmd, ctx, logfile)
|
||||
archiveArtifact(cmd, ctx, f"{logdir}/nrL1_stats.log")
|
||||
archiveArtifact(cmd, ctx, f"{logdir}/nrMAC_stats.log")
|
||||
cmd.close()
|
||||
if file is None:
|
||||
logging.debug('\u001B[1;37;41m Could not copy xNB logfile to analyze it! \u001B[0m')
|
||||
@@ -149,21 +164,633 @@ class RANManagement():
|
||||
return False
|
||||
|
||||
logging.debug('\u001B[1m Analyzing xNB logfile \u001B[0m ' + file)
|
||||
service_desc = {}
|
||||
service_desc["nr-softmodem"] = {'returncode': 0, 'logfile': file}
|
||||
success = cls_analysis.AnalyzeServices(HTML, service_desc, to_analyze)
|
||||
return success
|
||||
logStatus = self.AnalyzeLogFile_eNB(file, HTML, self.ran_checkers)
|
||||
if logStatus < 0:
|
||||
HTML.CreateHtmlTestRow('N/A', 'KO', logStatus)
|
||||
else:
|
||||
HTML.CreateHtmlTestRow(self.runtime_stats, 'OK', CONST.ALL_PROCESSES_OK)
|
||||
|
||||
def AnalyzeRTStats(self, HTML, node, ctx, thresholds):
|
||||
logging.info(f'Analyzing realtime stats from server: {node}')
|
||||
lSourcePath = self.eNBSourceCodePath
|
||||
#display rt stats for gNB only
|
||||
if len(self.datalog_rt_stats) != 0:
|
||||
HTML.CreateHtmlDataLogTable(self.datalog_rt_stats)
|
||||
|
||||
logdir = f'{lSourcePath}/cmake_targets'
|
||||
with cls_cmd.getConnection(node) as cmd:
|
||||
l1_file = archiveArtifact(cmd, ctx, f"{logdir}/nrL1_stats.log")
|
||||
mac_file = archiveArtifact(cmd, ctx, f"{logdir}/nrMAC_stats.log")
|
||||
return logStatus >= 0
|
||||
|
||||
logging.info(f"check against thresholds from {thresholds}")
|
||||
success, datalog_rt_stats = cls_analysis.Analysis.analyze_rt_stats(thresholds, l1_file, mac_file)
|
||||
HTML.CreateHtmlDataLogTable(datalog_rt_stats)
|
||||
return success
|
||||
def _analyzeUeRetx(self, rounds, checkers, regex):
|
||||
if len(rounds) == 0 or len(checkers) == 0:
|
||||
logging.warning(f'warning: rounds={rounds} checkers={checkers}')
|
||||
return []
|
||||
|
||||
perc = list(0 for i in checkers) # results in %
|
||||
stats = list(False for i in checkers) # status if succeeded
|
||||
tmp = re.match(regex, rounds)
|
||||
if tmp is None:
|
||||
logging.error('_analyzeUeRetx: did not match regex for DL retx analysis')
|
||||
return stats
|
||||
retx_data = [float(x) for x in tmp.groups()]
|
||||
for i in range(0, len(perc)):
|
||||
#case where numerator > denumerator with denum ==0 is disregarded, cannot hapen in principle, will lead to 0%
|
||||
perc[i] = 0 if (retx_data[i] == 0) else 100 * retx_data[i + 1] / retx_data[i]
|
||||
#treating % > 100 , % > requirement
|
||||
stats[i] = perc[i] <= 100 and perc[i] <= checkers[i]
|
||||
return stats
|
||||
|
||||
def AnalyzeLogFile_eNB(self, eNBlogFile, HTML, checkers={}):
|
||||
if (not os.path.isfile(eNBlogFile)):
|
||||
return -1
|
||||
enb_log_file = open(eNBlogFile, 'r')
|
||||
exitSignalReceived = False
|
||||
foundAssertion = False
|
||||
msgAssertion = ''
|
||||
msgLine = 0
|
||||
foundSegFault = False
|
||||
foundRealTimeIssue = False
|
||||
foundRealTimeIssue_cnt = 0
|
||||
rrcSetupComplete = 0
|
||||
rrcReleaseRequest = 0
|
||||
rrcReconfigRequest = 0
|
||||
rrcReconfigComplete = 0
|
||||
rrcReestablishRequest = 0
|
||||
rrcReestablishComplete = 0
|
||||
rrcReestablishReject = 0
|
||||
rlcDiscardBuffer = 0
|
||||
rachCanceledProcedure = 0
|
||||
uciStatMsgCount = 0
|
||||
pdcpFailure = 0
|
||||
ulschFailure = 0
|
||||
ulschAllocateCCEerror = 0
|
||||
uplinkSegmentsAborted = 0
|
||||
ulschReceiveOK = 0
|
||||
gnbRxTxWakeUpFailure = 0
|
||||
gnbTxWriteThreadEnabled = False
|
||||
cdrxActivationMessageCount = 0
|
||||
dropNotEnoughRBs = 0
|
||||
mbmsRequestMsg = 0
|
||||
htmleNBFailureMsg = ''
|
||||
isRRU = False
|
||||
isSlave = False
|
||||
slaveReceivesFrameResyncCmd = False
|
||||
X2HO_state = CONST.X2_HO_REQ_STATE__IDLE
|
||||
X2HO_inNbProcedures = 0
|
||||
X2HO_outNbProcedures = 0
|
||||
global_status = CONST.ALL_PROCESSES_OK
|
||||
# Runtime statistics
|
||||
runTime = ''
|
||||
userTime = ''
|
||||
systemTime = ''
|
||||
maxPhyMemUsage = ''
|
||||
nbContextSwitches = ''
|
||||
#NSA FR1 check
|
||||
NSA_RAPROC_PUSCH_check = 0
|
||||
#dlsch and ulsch statistics (dictionary)
|
||||
dlsch_ulsch_stats = {}
|
||||
#real time statistics (dictionary)
|
||||
real_time_stats = {}
|
||||
#count "problem receiving samples" msg
|
||||
pb_receiving_samples_cnt = 0
|
||||
#count "removing UE" msg
|
||||
removing_ue = 0
|
||||
#count"X2AP-PDU"
|
||||
x2ap_pdu = 0
|
||||
#gnb specific log markers
|
||||
gnb_markers ={'SgNBReleaseRequestAcknowledge': [],'FAILURE': [], 'scgFailureInformationNR-r15': [], 'SgNBReleaseRequest': [], 'Detected UL Failure on PUSCH':[]}
|
||||
nodeB_prefix_found = False
|
||||
RealTimeProcessingIssue = False
|
||||
retx_status = {}
|
||||
nrRrcRcfgComplete = 0
|
||||
harqFeedbackPast = 0
|
||||
showedByeMsg = False # last line is Bye. -> stopped properly
|
||||
|
||||
line_cnt=0 #log file line counter
|
||||
for line in enb_log_file.readlines():
|
||||
line_cnt+=1
|
||||
# Detection of eNB/gNB from a container log
|
||||
result = re.search('Starting eNB soft modem', str(line))
|
||||
if result is not None:
|
||||
nodeB_prefix_found = True
|
||||
nodeB_prefix = 'e'
|
||||
result = re.search('Starting gNB soft modem', str(line))
|
||||
if result is not None:
|
||||
nodeB_prefix_found = True
|
||||
nodeB_prefix = 'g'
|
||||
result = re.search('Run time:' ,str(line))
|
||||
# Runtime statistics
|
||||
result = re.search('Run time:' ,str(line))
|
||||
if result is not None:
|
||||
runTime = str(line).strip()
|
||||
if runTime != '':
|
||||
result = re.search('Time executing user inst', str(line))
|
||||
if result is not None:
|
||||
fields=line.split(':')
|
||||
userTime = 'userTime : ' + fields[1].replace('\n','')
|
||||
result = re.search('Time executing system inst', str(line))
|
||||
if result is not None:
|
||||
fields=line.split(':')
|
||||
systemTime = 'systemTime : ' + fields[1].replace('\n','')
|
||||
result = re.search('Max. Phy. memory usage:', str(line))
|
||||
if result is not None:
|
||||
fields=line.split(':')
|
||||
maxPhyMemUsage = 'maxPhyMemUsage : ' + fields[1].replace('\n','')
|
||||
result = re.search('Number of context switch.*process origin', str(line))
|
||||
if result is not None:
|
||||
fields=line.split(':')
|
||||
nbContextSwitches = 'nbContextSwitches : ' + fields[1].replace('\n','')
|
||||
if X2HO_state == CONST.X2_HO_REQ_STATE__IDLE:
|
||||
result = re.search('target eNB Receives X2 HO Req X2AP_HANDOVER_REQ', str(line))
|
||||
if result is not None:
|
||||
X2HO_state = CONST.X2_HO_REQ_STATE__TARGET_RECEIVES_REQ
|
||||
result = re.search('source eNB receives the X2 HO ACK X2AP_HANDOVER_REQ_ACK', str(line))
|
||||
if result is not None:
|
||||
X2HO_state = CONST.X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK
|
||||
if X2HO_state == CONST.X2_HO_REQ_STATE__TARGET_RECEIVES_REQ:
|
||||
result = re.search('Received LTE_RRCConnectionReconfigurationComplete from UE', str(line))
|
||||
if result is not None:
|
||||
X2HO_state = CONST.X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE
|
||||
if X2HO_state == CONST.X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE:
|
||||
result = re.search('issue rrc_eNB_send_PATH_SWITCH_REQ', str(line))
|
||||
if result is not None:
|
||||
X2HO_state = CONST.X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ
|
||||
if X2HO_state == CONST.X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ:
|
||||
result = re.search('received path switch ack S1AP_PATH_SWITCH_REQ_ACK', str(line))
|
||||
if result is not None:
|
||||
X2HO_state = CONST.X2_HO_REQ_STATE__IDLE
|
||||
X2HO_inNbProcedures += 1
|
||||
if X2HO_state == CONST.X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK:
|
||||
result = re.search('source eNB receives the X2 UE CONTEXT RELEASE X2AP_UE_CONTEXT_RELEASE', str(line))
|
||||
if result is not None:
|
||||
X2HO_state = CONST.X2_HO_REQ_STATE__IDLE
|
||||
X2HO_outNbProcedures += 1
|
||||
|
||||
if self.eNBOptions[0] != '':
|
||||
res1 = re.search('max_rxgain (?P<requested_option>[0-9]+)', self.eNBOptions[0])
|
||||
res2 = re.search('max_rxgain (?P<applied_option>[0-9]+)', str(line))
|
||||
if res1 is not None and res2 is not None:
|
||||
requested_option = int(res1.group('requested_option'))
|
||||
applied_option = int(res2.group('applied_option'))
|
||||
if requested_option == applied_option:
|
||||
htmleNBFailureMsg += '<span class="glyphicon glyphicon-ok-circle"></span> Command line option(s) correctly applied <span class="glyphicon glyphicon-arrow-right"></span> ' + self.eNBOptions[0] + '\n\n'
|
||||
else:
|
||||
htmleNBFailureMsg += '<span class="glyphicon glyphicon-ban-circle"></span> Command line option(s) NOT applied <span class="glyphicon glyphicon-arrow-right"></span> ' + self.eNBOptions[0] + '\n\n'
|
||||
result = re.search('Exiting OAI softmodem|Caught SIGTERM, shutting down', str(line))
|
||||
if result is not None:
|
||||
exitSignalReceived = True
|
||||
result = re.search('[Ss]egmentation [Ff]ault', str(line))
|
||||
if result is not None and not exitSignalReceived:
|
||||
foundSegFault = True
|
||||
result = re.search('[Cc]ore [dD]ump', str(line))
|
||||
if result is not None and not exitSignalReceived:
|
||||
foundSegFault = True
|
||||
result = re.search('[Aa]ssertion', str(line))
|
||||
if result is not None and not exitSignalReceived:
|
||||
foundAssertion = True
|
||||
result = re.search('LLL', str(line))
|
||||
if result is not None and not exitSignalReceived:
|
||||
foundRealTimeIssue = True
|
||||
foundRealTimeIssue_cnt += 1
|
||||
if foundAssertion and (msgLine < 3):
|
||||
msgLine += 1
|
||||
msgAssertion += str(line)
|
||||
result = re.search('Setting function for RU', str(line))
|
||||
if result is not None:
|
||||
isRRU = True
|
||||
if isRRU:
|
||||
result = re.search('RU 0 is_slave=yes', str(line))
|
||||
if result is not None:
|
||||
isSlave = True
|
||||
if isSlave:
|
||||
result = re.search('Received RRU_frame_resynch command', str(line))
|
||||
if result is not None:
|
||||
slaveReceivesFrameResyncCmd = True
|
||||
result = re.search('LTE_RRCConnectionSetupComplete from UE', str(line))
|
||||
if result is not None:
|
||||
rrcSetupComplete += 1
|
||||
result = re.search('Generate LTE_RRCConnectionRelease|Generate RRCConnectionRelease', str(line))
|
||||
if result is not None: rrcReleaseRequest += 1
|
||||
result = re.search('Generate LTE_RRCConnectionReconfiguration', str(line))
|
||||
if result is not None:
|
||||
rrcReconfigRequest += 1
|
||||
result = re.search('LTE_RRCConnectionReconfigurationComplete from UE rnti', str(line))
|
||||
if result is not None:
|
||||
rrcReconfigComplete += 1
|
||||
result = re.search('LTE_RRCConnectionReestablishmentRequest', str(line))
|
||||
if result is not None:
|
||||
rrcReestablishRequest += 1
|
||||
result = re.search('LTE_RRCConnectionReestablishmentComplete', str(line))
|
||||
if result is not None:
|
||||
rrcReestablishComplete += 1
|
||||
result = re.search('LTE_RRCConnectionReestablishmentReject', str(line))
|
||||
if result is not None:
|
||||
rrcReestablishReject += 1
|
||||
result = re.search('CDRX configuration activated after RRC Connection', str(line))
|
||||
if result is not None:
|
||||
cdrxActivationMessageCount += 1
|
||||
result = re.search('uci->stat', str(line))
|
||||
if result is not None:
|
||||
uciStatMsgCount += 1
|
||||
result = re.search('PDCP.*Out of Resources.*reason', str(line))
|
||||
if result is not None:
|
||||
pdcpFailure += 1
|
||||
result = re.search('could not wakeup gNB rxtx process', str(line))
|
||||
if result is not None:
|
||||
gnbRxTxWakeUpFailure += 1
|
||||
result = re.search('tx write thread ready', str(line))
|
||||
if result is not None:
|
||||
gnbTxWriteThreadEnabled = True
|
||||
result = re.search('ULSCH in error in round|ULSCH 0 in error', str(line))
|
||||
if result is not None:
|
||||
ulschFailure += 1
|
||||
result = re.search('ERROR ALLOCATING CCEs', str(line))
|
||||
if result is not None:
|
||||
ulschAllocateCCEerror += 1
|
||||
result = re.search('uplink segment error.*aborted [1-9] segments', str(line))
|
||||
if result is not None:
|
||||
uplinkSegmentsAborted += 1
|
||||
result = re.search('ULSCH received ok', str(line))
|
||||
if result is not None:
|
||||
ulschReceiveOK += 1
|
||||
result = re.search('BAD all_segments_received', str(line))
|
||||
if result is not None:
|
||||
rlcDiscardBuffer += 1
|
||||
result = re.search('Canceled RA procedure for UE rnti', str(line))
|
||||
if result is not None:
|
||||
rachCanceledProcedure += 1
|
||||
result = re.search('dropping, not enough RBs', str(line))
|
||||
if result is not None:
|
||||
dropNotEnoughRBs += 1
|
||||
if self.eNBmbmsEnables[0]:
|
||||
result = re.search('MBMS USER-PLANE.*Requesting.*bytes from RLC', str(line))
|
||||
if result is not None:
|
||||
mbmsRequestMsg += 1
|
||||
#FR1 NSA test : add new markers to make sure gNB is used
|
||||
result = re.search('\[gNB [0-9]+\]\[RAPROC\] PUSCH with TC_RNTI 0x[0-9a-fA-F]+ received correctly, adding UE MAC Context RNTI 0x[0-9a-fA-F]+', str(line))
|
||||
if result is not None:
|
||||
NSA_RAPROC_PUSCH_check = 1
|
||||
|
||||
# Collect information on UE DLSCH and ULSCH statistics
|
||||
keys = {'dlsch_rounds','ulsch_rounds'}
|
||||
for k in keys:
|
||||
result = re.search(k, line)
|
||||
if result is None:
|
||||
continue
|
||||
result = re.search('UE (?:RNTI )?([0-9a-f]{4})', line)
|
||||
if result is None:
|
||||
logging.error(f'did not find RNTI while matching key {k}')
|
||||
continue
|
||||
rnti = result.group(1)
|
||||
|
||||
#remove 1- all useless char before relevant info (ulsch or dlsch) 2- trailing char
|
||||
if not rnti in dlsch_ulsch_stats: dlsch_ulsch_stats[rnti] = {}
|
||||
dlsch_ulsch_stats[rnti][k]=re.sub(r'^.*\]\s+', r'' , line.rstrip())
|
||||
|
||||
result = re.search('Received NR_RRCReconfigurationComplete from UE', str(line))
|
||||
if result is not None:
|
||||
nrRrcRcfgComplete += 1
|
||||
result = re.search('HARQ feedback is in the past', str(line))
|
||||
if result is not None:
|
||||
harqFeedbackPast += 1
|
||||
|
||||
|
||||
#count "problem receiving samples" msg
|
||||
result = re.search('\[PHY\]\s+problem receiving samples', str(line))
|
||||
if result is not None:
|
||||
pb_receiving_samples_cnt += 1
|
||||
#count "Removing UE" msg
|
||||
result = re.search('\[MAC\]\s+Removing UE', str(line))
|
||||
if result is not None:
|
||||
removing_ue += 1
|
||||
#count "X2AP-PDU"
|
||||
result = re.search('X2AP-PDU', str(line))
|
||||
if result is not None:
|
||||
x2ap_pdu += 1
|
||||
#gnb markers logging
|
||||
for k in gnb_markers:
|
||||
result = re.search(k, line)
|
||||
if result is not None:
|
||||
gnb_markers[k].append(line_cnt)
|
||||
|
||||
# check whether e/gNB log finishes with "Bye." message
|
||||
showedByeMsg |= re.search(r'^Bye.\n', str(line), re.MULTILINE) is not None
|
||||
|
||||
enb_log_file.close()
|
||||
|
||||
|
||||
#the following part takes the *_stats.log files as source (not the stdout log file)
|
||||
|
||||
#the datalog config file has to be loaded
|
||||
datalog_rt_stats_file=self.datalog_rt_stats_file
|
||||
if (os.path.isfile(datalog_rt_stats_file)):
|
||||
yaml_file=datalog_rt_stats_file
|
||||
elif (os.path.isfile('ci-scripts/'+datalog_rt_stats_file)):
|
||||
yaml_file='ci-scripts/'+datalog_rt_stats_file
|
||||
else:
|
||||
logging.error("Datalog RT stats yaml file cannot be found")
|
||||
sys.exit("Datalog RT stats yaml file cannot be found")
|
||||
|
||||
with open(yaml_file,'r') as f:
|
||||
datalog_rt_stats = yaml.load(f,Loader=yaml.FullLoader)
|
||||
rt_keys = datalog_rt_stats['Ref'] #we use the keys from the Ref field
|
||||
|
||||
# nrL1_stats.log/nrMAC_stats.log should be in the same directory as main log file
|
||||
# currently the link is only implicit as below based on pattern matching
|
||||
# I will rework this to give the file explicitly
|
||||
l1_stats_fn = re.sub(r'-enb.log$', '-nrL1_stats.log', eNBlogFile)
|
||||
mac_stats_fn = re.sub(r'-enb.log$', '-nrMAC_stats.log', eNBlogFile)
|
||||
if os.path.isfile(l1_stats_fn) and os.path.isfile(mac_stats_fn):
|
||||
# don't use CI-nrL1_stats.log, as this will increase the processing time for
|
||||
# no reason, we just need the last occurence
|
||||
nrL1_stats = open(l1_stats_fn, 'r')
|
||||
nrMAC_stats = open(mac_stats_fn, 'r')
|
||||
for line in nrL1_stats.readlines():
|
||||
for k in rt_keys:
|
||||
result = re.search(k, line)
|
||||
if result is not None:
|
||||
#remove 1- all useless char before relevant info 2- trailing char
|
||||
tmp=re.match(rf'^.*?(\b{k}\b.*)',line.rstrip()) #from python 3.6 we can use literal string interpolation for the variable k, using rf' in the regex
|
||||
if tmp!=None:
|
||||
real_time_stats[k]=tmp.group(1)
|
||||
for line in nrMAC_stats.readlines():
|
||||
for k in rt_keys:
|
||||
result = re.search(k, line)
|
||||
if result is not None:
|
||||
#remove 1- all useless char before relevant info 2- trailing char
|
||||
tmp=re.match(rf'^.*?(\b{k}\b.*)',line.rstrip()) #from python 3.6 we can use literal string interpolation for the variable k, using rf' in the regex
|
||||
if tmp!=None:
|
||||
real_time_stats[k]=tmp.group(1)
|
||||
nrL1_stats.close()
|
||||
nrMAC_stats.close()
|
||||
else:
|
||||
logging.debug(f"NR Stats files for RT analysis not found: {l1_stats_fn}, {mac_stats_fn}")
|
||||
|
||||
#stdout log file and stat log files analysis completed
|
||||
logging.debug(' File analysis (stdout, stats) completed')
|
||||
|
||||
#post processing depending on the node type
|
||||
if not nodeB_prefix_found:
|
||||
if self.air_interface == 'lte-softmodem':
|
||||
nodeB_prefix = 'e'
|
||||
else:
|
||||
nodeB_prefix = 'g'
|
||||
|
||||
if nodeB_prefix == 'g':
|
||||
if ulschReceiveOK > 0:
|
||||
statMsg = nodeB_prefix + 'NB showed ' + str(ulschReceiveOK) + ' "ULSCH received ok" message(s)'
|
||||
logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m')
|
||||
htmleNBFailureMsg += statMsg + '\n'
|
||||
if gnbRxTxWakeUpFailure > 0:
|
||||
statMsg = nodeB_prefix + 'NB showed ' + str(gnbRxTxWakeUpFailure) + ' "could not wakeup gNB rxtx process" message(s)'
|
||||
logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m')
|
||||
htmleNBFailureMsg += statMsg + '\n'
|
||||
if gnbTxWriteThreadEnabled:
|
||||
statMsg = nodeB_prefix + 'NB ran with TX Write thread enabled'
|
||||
logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m')
|
||||
htmleNBFailureMsg += statMsg + '\n'
|
||||
if nrRrcRcfgComplete > 0:
|
||||
statMsg = nodeB_prefix + 'NB showed ' + str(nrRrcRcfgComplete) + ' "Received NR_RRCReconfigurationComplete from UE" message(s)'
|
||||
logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m')
|
||||
htmleNBFailureMsg += statMsg + '\n'
|
||||
if harqFeedbackPast > 0:
|
||||
statMsg = nodeB_prefix + 'NB showed ' + str(harqFeedbackPast) + ' "HARQ feedback is in the past" message(s)'
|
||||
logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m')
|
||||
htmleNBFailureMsg += statMsg + '\n'
|
||||
#FR1 NSA test : add new markers to make sure gNB is used
|
||||
if NSA_RAPROC_PUSCH_check:
|
||||
statMsg = '[RAPROC] PUSCH with TC_RNTI message check for ' + nodeB_prefix + 'NB : PASS '
|
||||
htmlMsg = statMsg+'\n'
|
||||
else:
|
||||
statMsg = '[RAPROC] PUSCH with TC_RNTI message check for ' + nodeB_prefix + 'NB : FAIL or not relevant'
|
||||
htmlMsg = statMsg+'\n'
|
||||
logging.debug(statMsg)
|
||||
htmleNBFailureMsg += htmlMsg
|
||||
#problem receiving samples log
|
||||
statMsg = '[PHY] problem receiving samples msg count = '+str(pb_receiving_samples_cnt)
|
||||
htmlMsg = statMsg+'\n'
|
||||
logging.debug(statMsg)
|
||||
htmleNBFailureMsg += htmlMsg
|
||||
#gnb markers
|
||||
statMsg = 'logfile line count = ' + str(line_cnt)
|
||||
htmlMsg = statMsg+'\n'
|
||||
logging.debug(statMsg)
|
||||
htmleNBFailureMsg += htmlMsg
|
||||
if len(gnb_markers['SgNBReleaseRequestAcknowledge'])!=0:
|
||||
statMsg = 'SgNBReleaseRequestAcknowledge = ' + str(len(gnb_markers['SgNBReleaseRequestAcknowledge'])) + ' occurences , starting line ' + str(gnb_markers['SgNBReleaseRequestAcknowledge'][0])
|
||||
else:
|
||||
statMsg = 'SgNBReleaseRequestAcknowledge = ' + str(len(gnb_markers['SgNBReleaseRequestAcknowledge'])) + ' occurences'
|
||||
htmlMsg = statMsg+'\n'
|
||||
logging.debug(statMsg)
|
||||
htmleNBFailureMsg += htmlMsg
|
||||
statMsg = 'FAILURE = ' + str(len(gnb_markers['FAILURE'])) + ' occurences'
|
||||
htmlMsg = statMsg+'\n'
|
||||
logging.debug(statMsg)
|
||||
htmleNBFailureMsg += htmlMsg
|
||||
statMsg = 'Detected UL Failure on PUSCH = ' + str(len(gnb_markers['Detected UL Failure on PUSCH'])) + ' occurences'
|
||||
htmlMsg = statMsg+'\n'
|
||||
logging.debug(statMsg)
|
||||
htmleNBFailureMsg += htmlMsg
|
||||
|
||||
#ulsch and dlsch statistics and checkers
|
||||
for ue in dlsch_ulsch_stats:
|
||||
dlulstat = dlsch_ulsch_stats[ue]
|
||||
#print statistics into html
|
||||
statMsg=''
|
||||
for key in dlulstat:
|
||||
statMsg += dlulstat[key] + '\n'
|
||||
logging.debug(dlulstat[key])
|
||||
htmleNBFailureMsg += statMsg
|
||||
|
||||
retx_status[ue] = {}
|
||||
dlcheckers = [] if 'd_retx_th' not in checkers else checkers['d_retx_th']
|
||||
retx_status[ue]['dl'] = self._analyzeUeRetx(dlulstat['dlsch_rounds'], dlcheckers, r'^.*dlsch_rounds\s+(\d+)\/(\d+)\/(\d+)\/(\d+),\s+dlsch_errors\s+(\d+)')
|
||||
ulcheckers = [] if 'u_retx_th' not in checkers else checkers['u_retx_th']
|
||||
retx_status[ue]['ul'] = self._analyzeUeRetx(dlulstat['ulsch_rounds'], ulcheckers, r'^.*ulsch_rounds\s+(\d+)\/(\d+)\/(\d+)\/(\d+),\s+ulsch_errors\s+(\d+)')
|
||||
|
||||
|
||||
#real time statistics
|
||||
datalog_rt_stats['Data']={}
|
||||
if len(real_time_stats)!=0: #check if dictionary is not empty
|
||||
for k in real_time_stats:
|
||||
tmp=re.match(r'^(?P<metric>.*):\s+(?P<avg>\d+\.\d+) us;\s+(?P<count>\d+);\s+(?P<max>\d+\.\d+) us;',real_time_stats[k])
|
||||
if tmp is not None:
|
||||
metric=tmp.group('metric')
|
||||
avg=float(tmp.group('avg'))
|
||||
max=float(tmp.group('max'))
|
||||
count=int(tmp.group('count'))
|
||||
datalog_rt_stats['Data'][metric]=["{:.0f}".format(avg),"{:.0f}".format(max),"{:d}".format(count),"{:.2f}".format(avg/datalog_rt_stats['Ref'][metric])]
|
||||
#once all metrics are collected, store the data as a class attribute to build a dedicated HTML table afterward
|
||||
self.datalog_rt_stats=datalog_rt_stats
|
||||
#check if there is a fail => will render the test as failed
|
||||
for k in datalog_rt_stats['Data']:
|
||||
valnorm = float(datalog_rt_stats['Data'][k][3])
|
||||
dev = datalog_rt_stats['DeviationThreshold'][k]
|
||||
if valnorm > 1.0 + dev or valnorm < 1.0 - dev: # condition for fail : avg/ref deviates by more than "deviation threshold"
|
||||
logging.debug(f'\u001B[1;30;43m normalized datalog_rt_stats metric {k}={valnorm} deviates by more than {dev}\u001B[0m')
|
||||
RealTimeProcessingIssue = True
|
||||
else:
|
||||
statMsg = 'No real time stats found in the log file\n'
|
||||
logging.debug('No real time stats found in the log file')
|
||||
htmleNBFailureMsg += statMsg
|
||||
|
||||
if not showedByeMsg:
|
||||
logging.debug('\u001B[1;37;41m ' + nodeB_prefix + 'NB did not show "Bye." message at end, it likely did not stop properly! \u001B[0m')
|
||||
htmleNBFailureMsg += 'No Bye. message found, did not stop properly\n'
|
||||
global_status = CONST.ENB_SHUTDOWN_NO_BYE
|
||||
else:
|
||||
logging.debug('"Bye." message found at end.')
|
||||
|
||||
else:
|
||||
#Removing UE log
|
||||
statMsg = '[MAC] Removing UE msg count = '+str(removing_ue)
|
||||
htmlMsg = statMsg+'\n'
|
||||
logging.debug(statMsg)
|
||||
htmleNBFailureMsg += htmlMsg
|
||||
#X2AP-PDU log
|
||||
statMsg = 'X2AP-PDU msg count = '+str(x2ap_pdu)
|
||||
htmlMsg = statMsg+'\n'
|
||||
logging.debug(statMsg)
|
||||
htmleNBFailureMsg += htmlMsg
|
||||
#nsa markers
|
||||
statMsg = 'logfile line count = ' + str(line_cnt)
|
||||
htmlMsg = statMsg+'\n'
|
||||
logging.debug(statMsg)
|
||||
htmleNBFailureMsg += htmlMsg
|
||||
if len(gnb_markers['SgNBReleaseRequest'])!=0:
|
||||
statMsg = 'SgNBReleaseRequest = ' + str(len(gnb_markers['SgNBReleaseRequest'])) + ' occurences , starting line ' + str(gnb_markers['SgNBReleaseRequest'][0])
|
||||
else:
|
||||
statMsg = 'SgNBReleaseRequest = ' + str(len(gnb_markers['SgNBReleaseRequest'])) + ' occurences'
|
||||
htmlMsg = statMsg+'\n'
|
||||
logging.debug(statMsg)
|
||||
htmleNBFailureMsg += htmlMsg
|
||||
statMsg = 'scgFailureInformationNR-r15 = ' + str(len(gnb_markers['scgFailureInformationNR-r15'])) + ' occurences'
|
||||
htmlMsg = statMsg+'\n'
|
||||
logging.debug(statMsg)
|
||||
htmleNBFailureMsg += htmlMsg
|
||||
|
||||
for ue in retx_status:
|
||||
msg = f"retransmissions for UE {ue}: DL {retx_status[ue]['dl']} UL {retx_status[ue]['ul']}"
|
||||
if False in retx_status[ue]['dl'] or False in retx_status[ue]['ul']:
|
||||
msg = 'Failure: ' + msg
|
||||
logging.error(f'\u001B[1;37;41m {msg}\u001B[0m')
|
||||
htmleNBFailureMsg += f'{msg}\n'
|
||||
global_status = CONST.ENB_RETX_ISSUE
|
||||
else:
|
||||
logging.debug(msg)
|
||||
|
||||
if RealTimeProcessingIssue:
|
||||
logging.debug('\u001B[1;37;41m ' + nodeB_prefix + 'NB ended with real time processing issue! \u001B[0m')
|
||||
htmleNBFailureMsg += 'Fail due to real time processing issue\n'
|
||||
global_status = CONST.ENB_REAL_TIME_PROCESSING_ISSUE
|
||||
if uciStatMsgCount > 0:
|
||||
statMsg = nodeB_prefix + 'NB showed ' + str(uciStatMsgCount) + ' "uci->stat" message(s)'
|
||||
logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m')
|
||||
htmleNBFailureMsg += statMsg + '\n'
|
||||
if pdcpFailure > 0:
|
||||
statMsg = nodeB_prefix + 'NB showed ' + str(pdcpFailure) + ' "PDCP Out of Resources" message(s)'
|
||||
logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m')
|
||||
htmleNBFailureMsg += statMsg + '\n'
|
||||
if ulschFailure > 0:
|
||||
statMsg = nodeB_prefix + 'NB showed ' + str(ulschFailure) + ' "ULSCH in error in round" message(s)'
|
||||
logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m')
|
||||
htmleNBFailureMsg += statMsg + '\n'
|
||||
if ulschAllocateCCEerror > 0:
|
||||
statMsg = nodeB_prefix + 'NB showed ' + str(ulschAllocateCCEerror) + ' "eNB_dlsch_ulsch_scheduler(); ERROR ALLOCATING CCEs" message(s)'
|
||||
logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m')
|
||||
htmleNBFailureMsg += statMsg + '\n'
|
||||
if uplinkSegmentsAborted > 0:
|
||||
statMsg = nodeB_prefix + 'NB showed ' + str(uplinkSegmentsAborted) + ' "uplink segment error 0/2, aborted * segments" message(s)'
|
||||
logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m')
|
||||
htmleNBFailureMsg += statMsg + '\n'
|
||||
if dropNotEnoughRBs > 0:
|
||||
statMsg = 'eNB showed ' + str(dropNotEnoughRBs) + ' "dropping, not enough RBs" message(s)'
|
||||
logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m')
|
||||
htmleNBFailureMsg += statMsg + '\n'
|
||||
if rrcSetupComplete > 0:
|
||||
rrcMsg = nodeB_prefix + 'NB completed ' + str(rrcSetupComplete) + ' RRC Connection Setup(s)'
|
||||
logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m')
|
||||
htmleNBFailureMsg += rrcMsg + '\n'
|
||||
rrcMsg = ' -- ' + str(rrcSetupComplete) + ' were completed'
|
||||
logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m')
|
||||
htmleNBFailureMsg += rrcMsg + '\n'
|
||||
if rrcReleaseRequest > 0:
|
||||
rrcMsg = nodeB_prefix + 'NB requested ' + str(rrcReleaseRequest) + ' RRC Connection Release(s)'
|
||||
logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m')
|
||||
htmleNBFailureMsg += rrcMsg + '\n'
|
||||
if rrcReconfigRequest > 0 or rrcReconfigComplete > 0:
|
||||
rrcMsg = nodeB_prefix + 'NB requested ' + str(rrcReconfigRequest) + ' RRC Connection Reconfiguration(s)'
|
||||
logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m')
|
||||
htmleNBFailureMsg += rrcMsg + '\n'
|
||||
rrcMsg = ' -- ' + str(rrcReconfigComplete) + ' were completed'
|
||||
logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m')
|
||||
htmleNBFailureMsg += rrcMsg + '\n'
|
||||
if rrcReestablishRequest > 0 or rrcReestablishComplete > 0 or rrcReestablishReject > 0:
|
||||
rrcMsg = nodeB_prefix + 'NB requested ' + str(rrcReestablishRequest) + ' RRC Connection Reestablishment(s)'
|
||||
logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m')
|
||||
htmleNBFailureMsg += rrcMsg + '\n'
|
||||
rrcMsg = ' -- ' + str(rrcReestablishComplete) + ' were completed'
|
||||
logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m')
|
||||
htmleNBFailureMsg += rrcMsg + '\n'
|
||||
rrcMsg = ' -- ' + str(rrcReestablishReject) + ' were rejected'
|
||||
logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m')
|
||||
htmleNBFailureMsg += rrcMsg + '\n'
|
||||
if self.eNBmbmsEnables[0]:
|
||||
if mbmsRequestMsg > 0:
|
||||
rrcMsg = 'eNB requested ' + str(mbmsRequestMsg) + ' times the RLC for MBMS USER-PLANE'
|
||||
logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m')
|
||||
htmleNBFailureMsg += rrcMsg + '\n'
|
||||
if X2HO_inNbProcedures > 0:
|
||||
rrcMsg = 'eNB completed ' + str(X2HO_inNbProcedures) + ' X2 Handover Connection procedure(s)'
|
||||
logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m')
|
||||
htmleNBFailureMsg += rrcMsg + '\n'
|
||||
if X2HO_outNbProcedures > 0:
|
||||
rrcMsg = 'eNB completed ' + str(X2HO_outNbProcedures) + ' X2 Handover Release procedure(s)'
|
||||
logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m')
|
||||
htmleNBFailureMsg += rrcMsg + '\n'
|
||||
if self.eNBOptions[0] != '':
|
||||
res1 = re.search('drx_Config_present prSetup', self.eNBOptions[0])
|
||||
if res1 is not None:
|
||||
if cdrxActivationMessageCount > 0:
|
||||
rrcMsg = 'eNB activated the CDRX Configuration for ' + str(cdrxActivationMessageCount) + ' time(s)'
|
||||
logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m')
|
||||
htmleNBFailureMsg += rrcMsg + '\n'
|
||||
else:
|
||||
rrcMsg = 'eNB did NOT ACTIVATE the CDRX Configuration'
|
||||
logging.debug('\u001B[1;37;43m ' + rrcMsg + ' \u001B[0m')
|
||||
htmleNBFailureMsg += rrcMsg + '\n'
|
||||
if rachCanceledProcedure > 0:
|
||||
rachMsg = nodeB_prefix + 'NB cancelled ' + str(rachCanceledProcedure) + ' RA procedure(s)'
|
||||
logging.debug('\u001B[1;30;43m ' + rachMsg + ' \u001B[0m')
|
||||
htmleNBFailureMsg += rachMsg + '\n'
|
||||
if isRRU:
|
||||
if isSlave:
|
||||
if slaveReceivesFrameResyncCmd:
|
||||
rruMsg = 'Slave RRU received the RRU_frame_resynch command from RAU'
|
||||
logging.debug('\u001B[1;30;43m ' + rruMsg + ' \u001B[0m')
|
||||
htmleNBFailureMsg += rruMsg + '\n'
|
||||
else:
|
||||
rruMsg = 'Slave RRU DID NOT receive the RRU_frame_resynch command from RAU'
|
||||
logging.debug('\u001B[1;37;41m ' + rruMsg + ' \u001B[0m')
|
||||
htmleNBFailureMsg += rruMsg + '\n'
|
||||
global_status = CONST.ENB_PROCESS_SLAVE_RRU_NOT_SYNCED
|
||||
if foundSegFault:
|
||||
logging.debug('\u001B[1;37;41m ' + nodeB_prefix + 'NB ended with a Segmentation Fault! \u001B[0m')
|
||||
global_status = CONST.ENB_PROCESS_SEG_FAULT
|
||||
if foundAssertion:
|
||||
logging.debug('\u001B[1;37;41m ' + nodeB_prefix + 'NB ended with an assertion! \u001B[0m')
|
||||
htmleNBFailureMsg += msgAssertion
|
||||
global_status = CONST.ENB_PROCESS_ASSERTION
|
||||
if foundRealTimeIssue:
|
||||
logging.debug('\u001B[1;37;41m ' + nodeB_prefix + 'NB faced real time issues! \u001B[0m')
|
||||
htmleNBFailureMsg += nodeB_prefix + 'NB faced real time issues! COUNT = '+ str(foundRealTimeIssue_cnt) +' lines\n'
|
||||
if rlcDiscardBuffer > 0:
|
||||
rlcMsg = nodeB_prefix + 'NB RLC discarded ' + str(rlcDiscardBuffer) + ' buffer(s)'
|
||||
logging.debug('\u001B[1;37;41m ' + rlcMsg + ' \u001B[0m')
|
||||
htmleNBFailureMsg += rlcMsg + '\n'
|
||||
global_status = CONST.ENB_PROCESS_REALTIME_ISSUE
|
||||
HTML.htmleNBFailureMsg=htmleNBFailureMsg
|
||||
# Runtime statistics for console output and HTML
|
||||
if runTime != '':
|
||||
logging.debug(runTime)
|
||||
logging.debug(userTime)
|
||||
logging.debug(systemTime)
|
||||
logging.debug(maxPhyMemUsage)
|
||||
logging.debug(nbContextSwitches)
|
||||
self.runtime_stats='<pre>'+runTime + '\n'+ userTime + '\n' + systemTime + '\n' + maxPhyMemUsage + '\n' + nbContextSwitches+'</pre>'
|
||||
return global_status
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
SHORT_COMMIT_SHA=$(git rev-parse --short=8 HEAD)
|
||||
COMMIT_SHA=$(git rev-parse HEAD)
|
||||
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
||||
@@ -12,8 +13,6 @@ if [ $# -eq 0 ]
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set -x
|
||||
|
||||
# The script assumes you've build the following images:
|
||||
#
|
||||
# docker build . -f docker/Dockerfile.gNB.ubuntu -t oai-gnb
|
||||
@@ -32,15 +31,15 @@ docker tag oai-nr-cuup oai-ci/oai-nr-cuup:develop-${SHORT_COMMIT_SHA}
|
||||
python3 main.py --mode=InitiateHtml --ranRepository=NONE --ranBranch=${CURRENT_BRANCH} \
|
||||
--ranCommitID=${COMMIT_SHA} --ranAllowMerge=false \
|
||||
--ranTargetBranch=NONE \
|
||||
--XMLTestFile=xml_files/${TESTCASE} --local --datefmt="%H:%M:%S"
|
||||
--XMLTestFile=xml_files/${TESTCASE} --local
|
||||
|
||||
python3 main.py --mode=TesteNB --ranRepository=NONE --ranBranch=${CURRENT_BRANCH} \
|
||||
--ranCommitID=${COMMIT_SHA} --ranAllowMerge=false \
|
||||
--ranTargetBranch=NONE \
|
||||
--eNBSourceCodePath=${REPO_PATH} \
|
||||
--XMLTestFile=${TESTCASE} --local --datefmt="%H:%M:%S"
|
||||
--XMLTestFile=${TESTCASE} --local
|
||||
RET=$?
|
||||
|
||||
python3 main.py --mode=FinalizeHtml --local --datefmt="%H:%M:%S"
|
||||
python3 main.py --mode=FinalizeHtml --local
|
||||
|
||||
exit ${RET}
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
function die() { echo $@; exit 1; }
|
||||
[ $# -ge 1 ] || die "usage: $0 <directory> [ctest-options]"
|
||||
|
||||
IMAGE=ran-channelsim:ci-temp
|
||||
CONTAINER=ran-channelsim
|
||||
function cleanup-docker() {
|
||||
docker stop ${CONTAINER}
|
||||
docker rm ${CONTAINER}
|
||||
docker rmi ${IMAGE}
|
||||
docker volume prune --force
|
||||
}
|
||||
trap cleanup-docker EXIT
|
||||
|
||||
set -x
|
||||
DIR=$1
|
||||
RESULT_DIR=${DIR}/
|
||||
shift
|
||||
CTEST_OPT=$@
|
||||
|
||||
# build channel simulator
|
||||
docker build --progress=plain --tag ${IMAGE} --file ${DIR}/ci-scripts/docker/Dockerfile.channelsim.ubuntu ${DIR} &>> ${RESULT_DIR}/channelsim_build_log.txt
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "build of channel simulator failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# get a JSON description of all tests to run
|
||||
docker run -a STDOUT --workdir /oai-ran/build/ --env LD_LIBRARY_PATH=/oai-ran/build/ --rm --name ${CONTAINER} ${IMAGE} ctest ${CTEST_OPT} --show-only=json-v1 &> ${RESULT_DIR}/desc-tests.json
|
||||
JSON_RES=$?
|
||||
|
||||
# run the actual tests: we don't suppy --rm as we have to copy the files
|
||||
# similar to unit tests, we can't mount the file where we write physims-5g-run.xml to
|
||||
# as it would write a file as root, but this script is run as a normal user
|
||||
docker run -a STDOUT --gpus all --workdir /oai-ran/build/ --env LD_LIBRARY_PATH=/oai-ran/build/ --name ${CONTAINER} ${IMAGE} ctest ${CTEST_OPT} --output-junit results-run.xml --test-output-size-passed 100000 --test-output-size-failed 100000 &>> ${RESULT_DIR}/channelsim_log.txt
|
||||
RUN_RES=$?
|
||||
docker cp ${CONTAINER}:/oai-ran/build/results-run.xml ${RESULT_DIR}/
|
||||
docker cp ${CONTAINER}:/oai-ran/build/Testing/Temporary/LastTestsFailed.log ${RESULT_DIR}/
|
||||
docker cp ${CONTAINER}:/oai-ran/build/Testing/Temporary/LastTest.log ${RESULT_DIR}/
|
||||
|
||||
# if both were successful, return 0
|
||||
# TODO not sure
|
||||
#[[ $JSON_RES -eq 0 && $RUN_RES -eq 0 ]] && exit 0
|
||||
|
||||
exit 0
|
||||
@@ -1,46 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
function die() { echo $@; exit 1; }
|
||||
[ $# -ge 1 ] || die "usage: $0 <directory> [ctest-options]"
|
||||
|
||||
IMAGE=ran-physimtests:ci-temp
|
||||
CONTAINER=ran-physimtests
|
||||
function cleanup-docker() {
|
||||
docker stop ${CONTAINER}
|
||||
docker rm ${CONTAINER}
|
||||
docker rmi ${IMAGE}
|
||||
docker volume prune --force
|
||||
}
|
||||
trap cleanup-docker EXIT
|
||||
|
||||
set -x
|
||||
DIR=$1
|
||||
RESULT_DIR=${DIR}/
|
||||
shift
|
||||
CTEST_OPT=$@
|
||||
|
||||
# build physims
|
||||
docker build --progress=plain --tag ${IMAGE} --file ${DIR}/ci-scripts/docker/Dockerfile.physim.cuda.ubuntu ${DIR} &>> ${RESULT_DIR}/physim_log.txt
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "build of physims failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# get a JSON description of all tests to run
|
||||
docker run -a STDOUT --workdir /oai-ran/build/ --env LD_LIBRARY_PATH=/oai-ran/build/ --rm --name ${CONTAINER} ${IMAGE} ctest ${CTEST_OPT} --show-only=json-v1 &> ${RESULT_DIR}/desc-tests.json
|
||||
JSON_RES=$?
|
||||
|
||||
# run the actual tests: we don't suppy --rm as we have to copy the files
|
||||
# similar to unit tests, we can't mount the file where we write physims-5g-run.xml to
|
||||
# as it would write a file as root, but this script is run as a normal user
|
||||
docker run -a STDOUT --gpus all --workdir /oai-ran/build/ --env LD_LIBRARY_PATH=/oai-ran/build/ --name ${CONTAINER} ${IMAGE} ctest ${CTEST_OPT} --output-junit results-run.xml --test-output-size-passed 100000 --test-output-size-failed 100000 &>> ${RESULT_DIR}/physim_log.txt
|
||||
RUN_RES=$?
|
||||
docker cp ${CONTAINER}:/oai-ran/build/results-run.xml ${RESULT_DIR}/
|
||||
docker cp ${CONTAINER}:/oai-ran/build/Testing/Temporary/LastTestsFailed.log ${RESULT_DIR}/
|
||||
docker cp ${CONTAINER}:/oai-ran/build/Testing/Temporary/LastTest.log ${RESULT_DIR}/
|
||||
|
||||
# if both were successful, return 0
|
||||
# TODO not sure
|
||||
#[[ $JSON_RES -eq 0 && $RUN_RES -eq 0 ]] && exit 0
|
||||
|
||||
exit 0
|
||||
@@ -1,89 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
[[ $# -lt 1 ]] && { echo "Usage: $0 <distance_in_meters...>"; exit 1; }
|
||||
DISTANCES=("$@")
|
||||
|
||||
IP=192.168.71.150
|
||||
PORT=8091
|
||||
NCAT_TIMEOUT=1 #s
|
||||
SLEEP_WAIT=4 #s
|
||||
MAX_RETRIES=3
|
||||
|
||||
set_and_verify_distance() {
|
||||
local distance=$1
|
||||
echo "Testing PRS ToA estimation for distance: $distance m"
|
||||
|
||||
# it seems that grep returns immediately with this syntax, but not echo | ncat | grep
|
||||
# so prefer this to receive new distance immediately. We use --idle to keep
|
||||
# ncat open for some additional time
|
||||
local setdist_resp="$(grep --max-count 1 new_offset <(echo rfsimu setdistance rfsimu_channel_enB0 $distance | ncat --idle ${NCAT_TIMEOUT} ${IP} ${PORT}))"
|
||||
echo "> response: ${setdist_resp}"
|
||||
|
||||
local gettoa_resp="$(echo "ciUE get_max_dl_toa" | ncat ${IP} ${PORT} | grep "UE max PRS DL ToA")"
|
||||
echo "> response: ${gettoa_resp}"
|
||||
|
||||
[[ -z "$setdist_resp" || -z "$gettoa_resp" ]] && return 1
|
||||
|
||||
# Extract ToA values
|
||||
[[ "$setdist_resp" =~ new_offset\ ([0-9]+) ]] && local set_toa="${BASH_REMATCH[1]}" || { echo "> Set ToA extraction failed for distance: $distance m"; return 1; }
|
||||
|
||||
[[ "$gettoa_resp" =~ UE\ max\ PRS\ DL\ ToA\ ([0-9]+) ]] && local est_toa="${BASH_REMATCH[1]}" || { echo "> Estimated ToA extraction failed for distance: $distance m"; return 1; }
|
||||
|
||||
# Compare extracted ToA values
|
||||
[[ $set_toa == $est_toa ]] && echo "PRS SUCCESS for distance: $distance m" || { echo "PRS FAILURE for distance: $distance m (Actual ToA=$set_toa, Estimated ToA=$est_toa)" ; return 1; }
|
||||
|
||||
}
|
||||
|
||||
test_distance() {
|
||||
local distance=$1 retries=0
|
||||
|
||||
# retry loop incase we didn't receive the response
|
||||
while (( retries < MAX_RETRIES )); do
|
||||
echo " Attempt $((retries + 1))/$MAX_RETRIES"
|
||||
|
||||
# Always reset to 0 m before testing target distance
|
||||
if ! set_and_verify_distance 0; then
|
||||
echo " Set distance 0 m failed during attempt $((retries + 1))"
|
||||
else
|
||||
sleep "$SLEEP_WAIT"
|
||||
# Now test the actual target distance
|
||||
if set_and_verify_distance "$distance"; then
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
((retries++))
|
||||
if (( retries < MAX_RETRIES )); then
|
||||
sleep "$SLEEP_WAIT"
|
||||
else
|
||||
echo " ERROR: No valid response after $MAX_RETRIES retries for distance: $distance m"
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
num_success=0
|
||||
num_fail=0
|
||||
|
||||
for d in "${DISTANCES[@]}"; do
|
||||
if test_distance "$d"; then
|
||||
((num_success++))
|
||||
else
|
||||
((num_fail++))
|
||||
fi
|
||||
sleep "$SLEEP_WAIT"
|
||||
done
|
||||
|
||||
# ---- Summary ----
|
||||
echo
|
||||
echo "==================== SUMMARY ===================="
|
||||
echo "Total tests run : ${#DISTANCES[@]}"
|
||||
echo "Successful tests: ${num_success}"
|
||||
echo "Failed tests : ${num_fail}"
|
||||
echo "================================================="
|
||||
|
||||
if [ $num_success -gt 0 ]; then
|
||||
exit 0
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
@@ -10,15 +10,12 @@ directory, i.e., `ci-scripts/`, and run
|
||||
|
||||
To run individual unit tests, start them like so:
|
||||
|
||||
python tests/analysis.py -v
|
||||
python tests/build.py -v
|
||||
python tests/cmd.py -v
|
||||
python tests/corenetwork.py -v
|
||||
python tests/deployment.py -v
|
||||
python tests/iperf-analysis.py -v
|
||||
python tests/log-analysis.py -v
|
||||
python tests/ping-iperf.py -v
|
||||
python tests/pull-clean-int-registry.py -v
|
||||
|
||||
The logs will indicate if all tests passed. `tests/deployment.py` requires
|
||||
these images to be present:
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
import sys
|
||||
import logging
|
||||
logging.basicConfig(
|
||||
level=logging.DEBUG,
|
||||
stream=sys.stdout,
|
||||
format="[%(asctime)s] %(levelname)8s: %(message)s"
|
||||
)
|
||||
import os
|
||||
import unittest
|
||||
import yaml
|
||||
|
||||
sys.path.append('./') # to find OAI imports below
|
||||
import cls_analysis
|
||||
import cls_oai_html
|
||||
import constants
|
||||
|
||||
class TestAnalysis(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.html = cls_oai_html.HTMLManagement()
|
||||
self.html.testCaseId = "000000"
|
||||
self.maxDiff = 10000 # to compare long files below
|
||||
|
||||
def test_gnb_phytest(self):
|
||||
rtsf = "datalog_rt_stats.100.2x2.yaml"
|
||||
l1f = "tests/analysis/gnb_phytest.success.nrL1.log"
|
||||
macf = "tests/analysis/gnb_phytest.success.nrMAC.log"
|
||||
status, s = cls_analysis.Analysis.analyze_rt_stats(rtsf, l1f, macf)
|
||||
self.assertTrue(status)
|
||||
self.assertEqual(s['Title'], "Processing Time (us) from datalog_rt_stats.100.2x2.yaml")
|
||||
self.assertEqual(s['ColNames'], ["Metric", "Average; Max; Count", "Average vs Reference Deviation (Reference Value; Acceptability Deviation Threshold)"])
|
||||
with open(rtsf, 'r') as f:
|
||||
rt_stats = yaml.load(f, Loader=yaml.FullLoader)
|
||||
# check that analyze_rt_stats() picked up all Ref/DeviationThreshold values from yaml file, e.g.
|
||||
# s['Ref']['L1 Tx processing'] == corresponding value in yaml
|
||||
# s['DeviationThreshold']['L1 Tx processing'] == corresponding value in yaml
|
||||
for k, v in rt_stats['Ref'].items():
|
||||
self.assertEqual(s['Ref'][k], v)
|
||||
for k, v in rt_stats['DeviationThreshold'].items():
|
||||
self.assertEqual(s['DeviationThreshold'][k], v)
|
||||
for k, v in s['Ref'].items():
|
||||
self.assertEqual(v, rt_stats['Ref'][k])
|
||||
for k, v in s['DeviationThreshold'].items():
|
||||
self.assertEqual(v, rt_stats['DeviationThreshold'][k])
|
||||
self.assertEqual(s['Data']['L1 Tx processing'], ['476', '872', '102933', '1.00'])
|
||||
self.assertEqual(s['Data']['DLSCH encoding'], ['216', '544', '77201', '1.08'])
|
||||
self.assertEqual(s['Data']['L1 Rx processing'], ['488', '868', '38598', '0.92'])
|
||||
self.assertEqual(s['Data']['UL Indication'], ['1', '10', '38598', '0.76'])
|
||||
self.assertEqual(s['Data']['Slot Indication'], ['18', '94', '128667', '1.38'])
|
||||
self.assertEqual(s['Data']['PUSCH inner-receiver'], ['307', '530', '25730', '0.85'])
|
||||
self.assertEqual(s['Data']['feprx'], ['169', '310', '38600', '1.12'])
|
||||
self.assertEqual(s['Data']['feptx_ofdm (per port, half_slot)'], ['56', '88', '102933', '0.98'])
|
||||
self.assertEqual(s['Data']['feptx_total'], ['148', '299', '102933', '1.00'])
|
||||
# TODO this one is not found, the CI does not recover this??
|
||||
#self.assertEqual(s['Data']['DL & UL scheduling timing'], ['17', '97', '159371', '1.14'])
|
||||
|
||||
def test_analze_services_no_service(self):
|
||||
service_desc = {} # nothing to analyze
|
||||
to_analyze = ["testserv"] # some service requested to be analyze that does not exist
|
||||
status = cls_analysis.AnalyzeServices(self.html, service_desc, to_analyze)
|
||||
self.assertFalse(status)
|
||||
|
||||
# TODO this does not work: we don't evaluate return codes yet
|
||||
#def test_analze_service_exit_nonnull(self):
|
||||
# service_desc = {}
|
||||
# service_desc["testserv"] = {'returncode': 129, 'logfile': 'tests/log-analysis/empty.log'}
|
||||
# to_analyze = ["testserv"] # some service requested to be analyze that does not exist
|
||||
# status = cls_analysis.AnalyzeServices(self.html, service_desc, to_analyze)
|
||||
# self.assertFalse(status)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,37 +0,0 @@
|
||||
Blacklisted PRBs 0/273
|
||||
-5.-6.-4.-4.-4.-6.-6.-6.-8.-6.-6.-4.-4.-4.-3.-6.-6.-11.-8.-8.-5.-4.-5.-4.-5.
|
||||
-6.-11.-11.-8.-8.-5.-5.-4.-4.-6.-8.-11.-11.-8.-8.-6.-5.-6.-6.-8.-11.-11.-11.-8.-6.
|
||||
-6.-6.-6.-11.-11.-11.-11.-11.-11.-6.-6.-6.-8.-3.-11.-11.-11.-8.-8.-6.-6.-6.-11.-11.-11.
|
||||
-11.-8.-6.-5.-6.-6.-8.-11.-11.-11.-6.-6.-5.-4.-4.-5.-8.-8.-8.-6.-5.-4.-3.-3.-4.
|
||||
-4.-6.-6.-5.-3.-3.-2.-2.-2.-3.-3.-4.-5.-5.-3.-2.-1.-1.-2.-5.-4.-4.-4.-3.-2.
|
||||
0.-1.-1.-1.-2.-2.-3.-2.-1. 0. 2.-11.13. 8. 7. 6. 5. 0. 0.-1. 0. 0. 0.-1.-3.
|
||||
-3.-3.-3.-1.-1.-1.-1.-1.-1.-2.-3.-1.-1.-1.-1.-2.-1.-3.-4.-5.-8.-6.-3.-3.-3.
|
||||
-3.-3.-5.-8.-8.-8.-6.-4.-4.-3.-4.-6.-6.-8.-8.-8.-6.-5.-6.-5.-6.-8.-11.-11.-11.
|
||||
-8.-5.-5.-8.-6.-6.-8.-11.-11.-11.-8.-6.-6.-6.-8.-11.-11.-11.-8.-8.-6.-6.-5.-5.-8.
|
||||
-11.-11.-8.-11.-6.-5.-5.-5.-5.-6.-11.-11.-8.-6.-3.-4.-5.-5.-6.-8.-6.-6.-5.-4.-4.
|
||||
-4.-5.-6.-6.-11.-8.-6.-4.-3.-4.-3.-4.-5.-6.-8.-6.-5.-4.-3.-4.-3.-6.-5.
|
||||
max_IO = 24 (137), min_I0 = 0 (17), avg_I0 = 11 dB(8.8.)
|
||||
PRACH I0 = 0.0 dB
|
||||
DLSCH RNTI 1234: current_Qm 6, current_RI 2, total_bytes TX -1130807110
|
||||
ULSCH RNTI 1234, 389: ulsch_power[0] 41,5 ulsch_noise_power[0] 7.8, sync_pos 0
|
||||
ulsch_power[1] 26.7, ulsch_noise_power[1] 7.8
|
||||
round_trials 6434(1.0e+00):6432(1.0e+00):6432(1.0e+00):6432, DTX 0, current_Qm 6, current_RI 1, total_bytes RX/SCHED 0/385630560
|
||||
L1 Tx job: 401.013 us; 128667; 895.809 us;
|
||||
L1 Rx job: 183.883 us; 128667; 980.814 us;
|
||||
L1 Tx processing: 476.247 us; 102933; 872.099 us;
|
||||
DLSCH encoding: 216.371 us; 77201; 544.272 us;
|
||||
DLSCH scrambling: 5.524 us; 77201; 19.192 us;
|
||||
DLSCH modulation: 21.137 us; 77201; 36.428 us;
|
||||
DLSCH resource mapping: 1.127 us; 1003613; 12.027 us;
|
||||
DLSCH precoding: 3.667 us; 1003613; 17.411 us;
|
||||
L1 Rx processing: 488.478 us; 38598; 867.672 us;
|
||||
UL segment deinterleaving: 5.063 us; 488870; 27.005 us;
|
||||
UL segment rate recovery: 11.554 us; 488870; 517.998 us;
|
||||
UL segments decoding: 134.035 us; 488870; 759.164 us;
|
||||
UL Indication: 0.763 us; 38598; 9.588 us;
|
||||
Slot Indication: 17.891 us; 128667; 94.446 us;
|
||||
PUSCH inner-receiver: 307.193 us; 25730; 529.580 us;
|
||||
feprx: 169.305 us; 38600; 310.489 us;
|
||||
feptx_ofdm (per port, half_slot): 56.093 us; 102933; 88.125 us;
|
||||
feptx_total: 147.889 us; 102933; 299.307 us;
|
||||
|
||||
@@ -17,7 +17,7 @@ import cls_cmd
|
||||
class TestBuild(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.html = cls_oai_html.HTMLManagement()
|
||||
self.html.testCaseIdx = "000000"
|
||||
self.html.testCase_id = "000000"
|
||||
self.cont = cls_containerize.Containerize()
|
||||
self._d = tempfile.mkdtemp()
|
||||
logging.warning(f"temporary directory: {self._d}")
|
||||
|
||||
@@ -16,6 +16,7 @@ import cls_oai_html
|
||||
import cls_oaicitest
|
||||
import cls_containerize
|
||||
from cls_ci_helper import TestCaseCtx
|
||||
import ran
|
||||
import cls_cmd
|
||||
|
||||
class TestDeploymentMethods(unittest.TestCase):
|
||||
@@ -38,6 +39,7 @@ class TestDeploymentMethods(unittest.TestCase):
|
||||
self.html.testCaseId = "000000"
|
||||
self.ci = cls_oaicitest.OaiCiTest()
|
||||
self.cont = cls_containerize.Containerize()
|
||||
self.ran = ran.RANManagement()
|
||||
self.cont.yamlPath = ''
|
||||
self.cont.ranAllowMerge = True
|
||||
self.cont.ranBranch = ''
|
||||
@@ -54,43 +56,16 @@ class TestDeploymentMethods(unittest.TestCase):
|
||||
self.cont.yamlPath = 'tests/simple-dep/'
|
||||
self.cont.deploymentTag = "noble"
|
||||
deploy = self.cont.DeployObject(self.ctx, self.node, self.html)
|
||||
undeploy = self.cont.UndeployObject(self.ctx, self.node, self.html, [])
|
||||
undeploy = self.cont.UndeployObject(self.ctx, self.node, self.html, self.ran)
|
||||
self.assertTrue(deploy)
|
||||
self.assertTrue(undeploy)
|
||||
|
||||
def test_stop_services(self):
|
||||
self.cont.yamlPath = 'tests/simple-undep/'
|
||||
self.cont.deploymentTag = "noble"
|
||||
# should deploy both testA and testB
|
||||
deploy = self.cont.DeployObject(self.ctx, self.node, self.html)
|
||||
# should fail (no such service)
|
||||
self.cont.services = "testC"
|
||||
stopC = self.cont.StopObject(self.ctx, self.node, self.html)
|
||||
# should stop testA
|
||||
self.cont.services = "testA"
|
||||
stopA = self.cont.StopObject(self.ctx, self.node, self.html)
|
||||
# should (re-)stop testA (no-op)
|
||||
self.cont.services = "testA"
|
||||
stopA2 = self.cont.StopObject(self.ctx, self.node, self.html)
|
||||
# should deploy testB
|
||||
self.cont.services = "testB"
|
||||
stopB = self.cont.StopObject(self.ctx, self.node, self.html)
|
||||
# should not undeploy anything (everything already stopped)
|
||||
self.cont.services = None
|
||||
undeployAll = self.cont.UndeployObject(self.ctx, self.node, self.html, [])
|
||||
self.assertTrue(deploy)
|
||||
self.assertFalse(stopC)
|
||||
self.assertTrue(stopA)
|
||||
self.assertTrue(stopA2)
|
||||
self.assertTrue(stopB)
|
||||
self.assertTrue(undeployAll)
|
||||
|
||||
def test_deployfails(self):
|
||||
# fails reliably
|
||||
old = self.cont.yamlPath
|
||||
self.cont.yamlPath = 'tests/simple-fail/'
|
||||
deploy = self.cont.DeployObject(self.ctx, self.node, self.html)
|
||||
self.cont.UndeployObject(self.ctx, self.node, self.html, [])
|
||||
self.cont.UndeployObject(self.ctx, self.node, self.html, self.ran)
|
||||
self.assertFalse(deploy)
|
||||
self.cont.yamlPath = old
|
||||
|
||||
@@ -99,7 +74,7 @@ class TestDeploymentMethods(unittest.TestCase):
|
||||
old = self.cont.yamlPath
|
||||
self.cont.yamlPath = 'tests/simple-fail-2svc/'
|
||||
deploy = self.cont.DeployObject(self.ctx, self.node, self.html)
|
||||
self.cont.UndeployObject(self.ctx, self.node, self.html, [])
|
||||
self.cont.UndeployObject(self.ctx, self.node, self.html, self.ran)
|
||||
self.assertFalse(deploy)
|
||||
self.cont.yamlPath = old
|
||||
|
||||
@@ -108,7 +83,7 @@ class TestDeploymentMethods(unittest.TestCase):
|
||||
self.cont.services = "oai-gnb"
|
||||
self.cont.deploymentTag = 'develop-12345678'
|
||||
deploy = self.cont.DeployObject(self.ctx, self.node, self.html)
|
||||
undeploy = self.cont.UndeployObject(self.ctx, self.node, self.html, [])
|
||||
undeploy = self.cont.UndeployObject(self.ctx, self.node, self.html, self.ran)
|
||||
self.assertTrue(deploy)
|
||||
self.assertTrue(undeploy)
|
||||
|
||||
@@ -117,7 +92,7 @@ class TestDeploymentMethods(unittest.TestCase):
|
||||
self.cont.services = "oai-gnb oai-nr-ue"
|
||||
self.cont.deploymentTag = 'develop-12345678'
|
||||
deploy = self.cont.DeployObject(self.ctx, self.node, self.html)
|
||||
undeploy = self.cont.UndeployObject(self.ctx, self.node, self.html, [])
|
||||
undeploy = self.cont.UndeployObject(self.ctx, self.node, self.html, self.ran)
|
||||
self.assertTrue(deploy)
|
||||
self.assertTrue(undeploy)
|
||||
|
||||
@@ -128,7 +103,7 @@ class TestDeploymentMethods(unittest.TestCase):
|
||||
deploy1 = self.cont.DeployObject(self.ctx, self.node, self.html)
|
||||
self.cont.services = "oai-nr-ue"
|
||||
deploy2 = self.cont.DeployObject(self.ctx, self.node, self.html)
|
||||
undeploy = self.cont.UndeployObject(self.ctx, self.node, self.html, [])
|
||||
undeploy = self.cont.UndeployObject(self.ctx, self.node, self.html, self.ran)
|
||||
self.assertTrue(deploy1)
|
||||
self.assertTrue(deploy2)
|
||||
self.assertTrue(undeploy)
|
||||
@@ -143,37 +118,5 @@ class TestDeploymentMethods(unittest.TestCase):
|
||||
cmd.run(f"rm -rf {self.cont.eNBSourceCodePath}")
|
||||
self.assertTrue(ws)
|
||||
|
||||
def test_undeploy_loganalysis(self):
|
||||
self.cont.yamlPath = 'yaml_files/5g_rfsimulator_tdd_dora'
|
||||
self.cont.services = "oai-gnb"
|
||||
self.cont.deploymentTag = 'develop-12345678'
|
||||
deploy = self.cont.DeployObject(self.ctx, self.node, self.html)
|
||||
analyze = ["oai-gnb"]
|
||||
undeploy = self.cont.UndeployObject(self.ctx, self.node, self.html, analyze)
|
||||
self.assertTrue(deploy)
|
||||
self.assertTrue(undeploy)
|
||||
|
||||
def test_undeploy_multi_loganalysis(self):
|
||||
self.cont.yamlPath = 'yaml_files/5g_rfsimulator_tdd_dora'
|
||||
self.cont.services = "oai-gnb"
|
||||
self.cont.deploymentTag = 'develop-12345678'
|
||||
deploy = self.cont.DeployObject(self.ctx, self.node, self.html)
|
||||
analyze = ["oai-gnb", "oai-gnb=ContainsString=NOTFOUND"]
|
||||
undeploy = self.cont.UndeployObject(self.ctx, self.node, self.html, analyze)
|
||||
self.assertTrue(deploy)
|
||||
self.assertFalse(undeploy)
|
||||
|
||||
# TODO this does not work: we don't evaluate return codes yet
|
||||
#def test_undeploy_rc_nonnull(self):
|
||||
# # fails reliably
|
||||
# old = self.cont.yamlPath
|
||||
# self.cont.yamlPath = 'tests/simple-fail/'
|
||||
# deploy = self.cont.DeployObject(self.ctx, self.node, self.html)
|
||||
# # should be false because wrong exit code
|
||||
# undeploy = self.cont.UndeployObject(self.ctx, self.node, self.html, ["test"])
|
||||
# self.assertFalse(deploy)
|
||||
# self.assertFalse(undeploy)
|
||||
# self.cont.yamlPath = old
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
import sys
|
||||
import logging
|
||||
logging.basicConfig(
|
||||
level=logging.DEBUG,
|
||||
stream=sys.stdout,
|
||||
format="[%(asctime)s] %(levelname)8s: %(message)s"
|
||||
)
|
||||
import os
|
||||
import unittest
|
||||
|
||||
sys.path.append('./') # to find OAI imports below
|
||||
import cls_loganalysis
|
||||
|
||||
class TestLogAnalysis(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.maxDiff = None
|
||||
|
||||
#def test_no_file(self):
|
||||
# f = "/total/fantasy/path/file.log"
|
||||
# result, _ = cls_loganalysis.Default.run(f, None)
|
||||
# self.assertFalse(result)
|
||||
|
||||
def test_no_error(self):
|
||||
f = "tests/log-analysis/empty.log"
|
||||
result, _ = cls_loganalysis.Default.run(f, None)
|
||||
self.assertTrue(result)
|
||||
|
||||
def test_retx_check_good(self):
|
||||
f = "tests/log-analysis/retx-check-good.log"
|
||||
opt = "dl=1,0,0,0;ul=1,0,0,0"
|
||||
result, log = cls_loganalysis.RetxCheck.run(f, opt)
|
||||
expected = """UE f40a: dlsch_rounds 86/0/0/0, dlsch_errors 0, pucch0_DTX 0, BLER 0.00052 MCS (0) 0 CCE fail 3
|
||||
UE f40a: ulsch_rounds 518/0/0/0, ulsch_errors 0, ulsch_DTX 0, BLER 0.00000 MCS (0) 0 (Qm 2 deltaMCS 0 dB) NPRB 5 SNR 51.0 dB CCE fail 0"""
|
||||
self.assertTrue(result)
|
||||
self.assertEqual(log, expected)
|
||||
|
||||
def test_retx_check_good_single_val(self):
|
||||
f = "tests/log-analysis/retx-check-good.log"
|
||||
opt = "1,0,0,0"
|
||||
result, log = cls_loganalysis.RetxCheck.run(f, opt)
|
||||
expected = """UE f40a: dlsch_rounds 86/0/0/0, dlsch_errors 0, pucch0_DTX 0, BLER 0.00052 MCS (0) 0 CCE fail 3
|
||||
UE f40a: ulsch_rounds 518/0/0/0, ulsch_errors 0, ulsch_DTX 0, BLER 0.00000 MCS (0) 0 (Qm 2 deltaMCS 0 dB) NPRB 5 SNR 51.0 dB CCE fail 0"""
|
||||
self.assertTrue(result)
|
||||
self.assertEqual(log, expected)
|
||||
|
||||
def test_retx_check_good_ul_only(self):
|
||||
f = "tests/log-analysis/retx-check-good.log"
|
||||
opt = "ul=1,0,0,0"
|
||||
result, log = cls_loganalysis.RetxCheck.run(f, opt)
|
||||
expected = """UE f40a: dlsch_rounds 86/0/0/0, dlsch_errors 0, pucch0_DTX 0, BLER 0.00052 MCS (0) 0 CCE fail 3
|
||||
UE f40a: ulsch_rounds 518/0/0/0, ulsch_errors 0, ulsch_DTX 0, BLER 0.00000 MCS (0) 0 (Qm 2 deltaMCS 0 dB) NPRB 5 SNR 51.0 dB CCE fail 0"""
|
||||
self.assertTrue(result)
|
||||
self.assertEqual(log, expected)
|
||||
|
||||
def test_retx_check_bad(self):
|
||||
f = "tests/log-analysis/retx-check-bad.log"
|
||||
opt = "dl=10,100,100,100;ul=10,100,100,100"
|
||||
result, log = cls_loganalysis.RetxCheck.run(f, opt)
|
||||
expected = """UE a491: dlsch_rounds 13/1/0/0, dlsch_errors 0, pucch0_DTX 0, BLER 0.11000 MCS (0) 0 CCE fail 0
|
||||
UE a491: ulsch_rounds 23/1/0/0, ulsch_errors 0, ulsch_DTX 1, BLER 0.08447 MCS (0) 0 (Qm 2 deltaMCS 0 dB) NPRB 5 SNR 34.0 dB CCE fail 0
|
||||
UE bf9b: dlsch_rounds 370/368/368/368, dlsch_errors 368, pucch0_DTX 1377, BLER 1.00000 MCS (0) 0 CCE fail 64
|
||||
UE bf9b: ulsch_rounds 150/148/147/147, ulsch_errors 147, ulsch_DTX 589, BLER 1.00000 MCS (0) 0 (Qm 2 deltaMCS 0 dB) NPRB 104 SNR 38.0 dB CCE fail 0
|
||||
!!! Failure: UE bf9b: retx rounds DL [1] UL [1] exceeded threshold
|
||||
UE 257a: dlsch_rounds 68071/142/14/0, dlsch_errors 0, pucch0_DTX 10, BLER 0.00427 MCS (1) 25 CCE fail 0
|
||||
UE 257a: ulsch_rounds 41777/2863/10/0, ulsch_errors 0, ulsch_DTX 17, BLER 0.11456 MCS (1) 10 (Qm 4 deltaMCS 0 dB) NPRB 5 SNR 29.0 dB CCE fail 0"""
|
||||
self.assertFalse(result)
|
||||
self.assertEqual(log, expected)
|
||||
|
||||
def test_retx_check_dl_only_bad(self):
|
||||
f = "tests/log-analysis/retx-check-bad.log"
|
||||
opt = "dl=10,80,100,100"
|
||||
result, log = cls_loganalysis.RetxCheck.run(f, opt)
|
||||
expected = """UE a491: dlsch_rounds 13/1/0/0, dlsch_errors 0, pucch0_DTX 0, BLER 0.11000 MCS (0) 0 CCE fail 0
|
||||
UE a491: ulsch_rounds 23/1/0/0, ulsch_errors 0, ulsch_DTX 1, BLER 0.08447 MCS (0) 0 (Qm 2 deltaMCS 0 dB) NPRB 5 SNR 34.0 dB CCE fail 0
|
||||
UE bf9b: dlsch_rounds 370/368/368/368, dlsch_errors 368, pucch0_DTX 1377, BLER 1.00000 MCS (0) 0 CCE fail 64
|
||||
UE bf9b: ulsch_rounds 150/148/147/147, ulsch_errors 147, ulsch_DTX 589, BLER 1.00000 MCS (0) 0 (Qm 2 deltaMCS 0 dB) NPRB 104 SNR 38.0 dB CCE fail 0
|
||||
!!! Failure: UE bf9b: retx rounds DL [1, 2] exceeded threshold
|
||||
UE 257a: dlsch_rounds 68071/142/14/0, dlsch_errors 0, pucch0_DTX 10, BLER 0.00427 MCS (1) 25 CCE fail 0
|
||||
UE 257a: ulsch_rounds 41777/2863/10/0, ulsch_errors 0, ulsch_DTX 17, BLER 0.11456 MCS (1) 10 (Qm 4 deltaMCS 0 dB) NPRB 5 SNR 29.0 dB CCE fail 0"""
|
||||
self.assertFalse(result)
|
||||
self.assertEqual(log, expected)
|
||||
|
||||
def test_retx_check_ul_bad(self):
|
||||
f = "tests/log-analysis/retx-check-bad.log"
|
||||
opt = "dl=100,100,100,100;ul=10,100,100,100"
|
||||
result, log = cls_loganalysis.RetxCheck.run(f, opt)
|
||||
expected = """UE a491: dlsch_rounds 13/1/0/0, dlsch_errors 0, pucch0_DTX 0, BLER 0.11000 MCS (0) 0 CCE fail 0
|
||||
UE a491: ulsch_rounds 23/1/0/0, ulsch_errors 0, ulsch_DTX 1, BLER 0.08447 MCS (0) 0 (Qm 2 deltaMCS 0 dB) NPRB 5 SNR 34.0 dB CCE fail 0
|
||||
UE bf9b: dlsch_rounds 370/368/368/368, dlsch_errors 368, pucch0_DTX 1377, BLER 1.00000 MCS (0) 0 CCE fail 64
|
||||
UE bf9b: ulsch_rounds 150/148/147/147, ulsch_errors 147, ulsch_DTX 589, BLER 1.00000 MCS (0) 0 (Qm 2 deltaMCS 0 dB) NPRB 104 SNR 38.0 dB CCE fail 0
|
||||
!!! Failure: UE bf9b: retx rounds UL [1] exceeded threshold
|
||||
UE 257a: dlsch_rounds 68071/142/14/0, dlsch_errors 0, pucch0_DTX 10, BLER 0.00427 MCS (1) 25 CCE fail 0
|
||||
UE 257a: ulsch_rounds 41777/2863/10/0, ulsch_errors 0, ulsch_DTX 17, BLER 0.11456 MCS (1) 10 (Qm 4 deltaMCS 0 dB) NPRB 5 SNR 29.0 dB CCE fail 0"""
|
||||
self.assertFalse(result)
|
||||
self.assertEqual(log, expected)
|
||||
|
||||
def test_last_line_contains_false(self):
|
||||
f = "tests/log-analysis/arbitrary.log"
|
||||
opt = "Bye."
|
||||
result, log = cls_loganalysis.LastLineContains.run(f, opt)
|
||||
expected = f"could not find '{opt}' in last line"
|
||||
self.assertFalse(result)
|
||||
self.assertEqual(log, expected)
|
||||
|
||||
def test_last_line_contains_false(self):
|
||||
f = "tests/log-analysis/arbitrary.log"
|
||||
opt = "got sync"
|
||||
result, log = cls_loganalysis.LastLineContains.run(f, opt)
|
||||
expected = ""
|
||||
self.assertTrue(result)
|
||||
self.assertEqual(log, expected)
|
||||
|
||||
def test_ends_no_bye(self):
|
||||
f = "tests/log-analysis/arbitrary.log"
|
||||
opt = None
|
||||
result, log = cls_loganalysis.EndsWithBye.run(f, opt)
|
||||
expected = "No Bye. message found, did not stop properly"
|
||||
self.assertFalse(result)
|
||||
self.assertEqual(log, expected)
|
||||
|
||||
def test_ends_with_bye(self):
|
||||
f = "tests/log-analysis/with-bye.log"
|
||||
opt = None
|
||||
result, log = cls_loganalysis.EndsWithBye.run(f, opt)
|
||||
expected = ""
|
||||
self.assertTrue(result)
|
||||
self.assertEqual(log, expected)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user