Compare commits

..

160 Commits

Author SHA1 Message Date
Qizhi Pan
d37e64829b try to merge the encoder branch, but bug exist 2025-08-24 01:03:19 +08:00
Qizhi Pan
3ea2cd8b21 change naming 2025-08-23 09:56:04 +08:00
Qizhi Pan
403b6ec572 clean up version organization a bit -G for grace hopper support, -P for general GPU 2025-08-22 16:54:25 +08:00
Qizhi Pan
e8dd817392 GPU memory version should be finnished 2025-08-20 19:45:03 +08:00
Raymond Knopp
32248a6628 use ldpc shared lib for sizes other than 384 or 384 with less than 9 segments 2025-08-19 16:23:27 +00:00
Qizhi Pan
7ff4813a3d Inter stream problem fixed 2025-08-19 16:15:46 +08:00
Qizhi Pan
360435912d Inter stream problem fixed 2025-08-19 15:44:43 +08:00
Qizhi Pan
6d78852ac0 Add prefetch, the inter stream problem still exists 2025-08-19 15:26:50 +08:00
Qizhi Pan
2ac916a847 Add prefetch, now the performance is quite stable 2025-08-19 14:53:22 +08:00
Qizhi Pan
e1d754322c Modify LDPC decoder to use GPU memory instead of GH200 direct memory 2025-08-19 13:55:24 +08:00
Qizhi Pan
ae492731af half added, try to merge the encoder 2025-08-16 13:29:24 +08:00
Raymond Knopp
9c77c7e513 added check for new tconcat timer 2025-08-15 16:23:46 +00:00
Raymond Knp
bdc8e1efa1 more optimization of segement concatenation at output of encoder 2025-08-15 16:41:09 +02:00
Raymond Knopp
b51697c2c1 128-bit NEON optimizations for input and output data formatting 2025-08-15 09:15:56 +00:00
Raymond Knopp
a3adab8312 added missing file for cuda encoder 2025-08-08 15:34:21 +00:00
Raymond Knopp
e4d3520648 add ldpc_encoder32.c. Cleanup of commented code in cuda encoder host functions 2025-08-08 15:32:59 +00:00
Raymond Knopp
3420c2df41 interleaver optimization 2025-08-08 08:27:36 +00:00
Raymond Knopp
7831e52798 handling of multiple 32-bit segment groups, segment interleaving/deinterleaving optimization 2025-08-07 16:45:48 +00:00
Qizhi Pan
701fd5a755 update encoder 2025-08-07 23:20:26 +08:00
Qizhi Pan
28dcbb49f8 Merge branch 'ldpc_decoder_cuda' of https://gitlab.eurecom.fr/oai/openairinterface5g into ldpc_decoder_cuda 2025-07-31 08:39:47 +00:00
Qizhi Pan
42931472a5 version v1 with parallel bug 2025-07-31 08:34:34 +00:00
Qizhi Pan
55a4a0632a version v1 with parallel bug 2025-07-29 19:28:23 +00:00
Qizhi Pan
5305698b78 Parallel version basically done. Not stable performance 2025-07-28 14:58:10 +00:00
Aida Teshome Teressa
c4f8bb6cd0 CUDA stream version almost done, need to fix the parallerl collision and high SNR error 2025-07-26 14:43:02 +00:00
Aida Teshome Teressa
ca968bbf8f building cuda streaming now 2025-07-23 09:15:25 +00:00
Aida Teshome Teressa
b5b3e53a70 one scheduler done, now working on multiple streams 2025-07-22 14:25:01 +00:00
Aida Teshome Teressa
980b29415b One big scheculer works but not equivalent BLER performance, need to improved 2025-07-22 09:38:02 +00:00
Aida Teshome Teressa
8fb4cbedd7 -P option added, runs in CUDA stream, need debug 2025-07-21 14:06:48 +00:00
Aida Teshome Teressa
00ac9f0469 Now the parity check is on GPU now 2025-07-17 11:20:35 +00:00
panq from NVIDIA H200
2b6781a017 Bn to Cn is now on GPU too, only the parity check need to work on 2025-07-15 18:13:12 +00:00
panq from NVIDIA H200
03e3fc8b1f cn2bnProcBuf is now in the CnProc part 2025-07-14 12:50:54 +00:00
panq from NVIDIA H200
def1f3ac38 slight agjustment 2025-07-08 13:12:56 +00:00
panq from NVIDIA H200
e478d2ab28 Bn_Proc done 2025-07-08 09:15:35 +00:00
panq from NVIDIA H200
7624903bce change cn_proc to a big kernel 2025-07-02 12:59:36 +00:00
panq from NVIDIA H200
61b48a8e6b add some profiling 2025-06-27 10:10:00 +00:00
Raymond Knopp
b0cf5e4b27 generator for single-worker 2025-06-14 14:43:26 +00:00
panq from NVIDIA H200
838bbdf7db add option for lower version gpu(need cudaMalloc; need cudastream); make the code more readable; some debug traces remaining 2025-06-11 15:01:42 +00:00
panq
c2856440ae not use mem_manage 2025-06-10 11:36:07 +02:00
panq
39399f1a0c use mem_manage 2025-06-10 11:35:42 +02:00
panq
2f091764d2 use mem_manage 2025-06-10 11:31:34 +02:00
panq
af1a5d59a2 dump first output 2025-06-10 11:17:54 +02:00
panq
069463a3d5 128 dump 2025-06-10 11:14:11 +02:00
panq
e46f16ae60 use unified memory, no memcpy 2025-06-10 11:11:01 +02:00
panq
4200f98fcf use unified memory, no memcpy 2025-06-10 11:09:57 +02:00
panq
8d6279a9f8 use unified memory 2025-06-10 11:05:45 +02:00
panq
699ba0932a use unified memory 2025-06-10 11:03:09 +02:00
panq
9989516b6b use unified memory 2025-06-10 10:58:19 +02:00
panq
9247017f06 use unified memory 2025-06-10 10:51:55 +02:00
panq
ad6df4870a testing 2025-06-10 10:48:22 +02:00
panq
1422e7b5ad remove memcpy 2025-06-10 10:41:50 +02:00
panq
050c0e061d remove memcpy 2025-06-10 10:40:22 +02:00
panq
f8752d1485 remove memcpy 2025-06-10 10:39:10 +02:00
panq
83f4c6ea17 remove memcpy 2025-06-10 10:37:22 +02:00
panq
7244a33dc6 works properly version 2025-06-10 10:34:57 +02:00
panq
c123a0499b works properly version 2025-06-10 10:32:29 +02:00
panq
00a2dda48b debug 2025-06-10 10:26:14 +02:00
panq
205e92071a debug 2025-06-10 10:22:41 +02:00
panq
ce6225bd1f debug 2025-06-10 10:11:31 +02:00
panq
9a74fb2b47 debug 2025-06-10 10:07:51 +02:00
panq
8223e61ec1 debug 2025-06-10 10:04:53 +02:00
panq
78d93ff335 debug 2025-06-10 10:03:18 +02:00
panq
ff551fb902 debug 2025-06-10 09:54:07 +02:00
panq from NVIDIA H200
dcb668593a dump data 2025-06-10 07:45:28 +00:00
panq
08a6979191 debug 2025-06-10 09:41:22 +02:00
panq
712e8bbc9f debug 2025-06-10 09:40:08 +02:00
panq
e3b652b8ff debug 2025-06-10 09:25:31 +02:00
panq
6e2b6dd2f4 debug 2025-06-10 09:22:05 +02:00
panq
321bc27b67 debug 2025-06-10 09:18:23 +02:00
panq
695e4e6044 debug 2025-06-10 09:07:54 +02:00
panq
ad09d09ea0 debug 2025-06-10 08:48:10 +02:00
panq
5c4b1cc0be debug 2025-06-10 08:46:46 +02:00
panq
0bfd05ee35 debug 2025-06-10 08:29:27 +02:00
panq
0f81225abc debug 2025-06-10 08:25:36 +02:00
panq
307413ce24 debug 2025-06-10 08:19:58 +02:00
panq
de92c277b5 debug 2025-06-10 00:29:06 +02:00
panq
fc130034f5 debug 2025-06-10 00:25:53 +02:00
panq
1e73d9fa17 debug 2025-06-09 23:58:10 +02:00
panq
714707bbe3 debug 2025-06-09 23:51:28 +02:00
panq
147dc8998f debug 2025-06-09 23:47:30 +02:00
panq
3b2359dc0d debug 2025-06-09 23:34:50 +02:00
panq
17db765c19 Merge branch 'ldpc_decoder_cuda' of https://gitlab.eurecom.fr/oai/openairinterface5g into ldpc_decoder_cuda 2025-06-09 23:18:56 +02:00
panq
299a6167ab debug 2025-06-09 23:18:48 +02:00
panq from NVIDIA H200
9c8f25448a dump data 2025-06-09 20:55:58 +00:00
panq
d824a5deef debug 2025-06-09 22:53:25 +02:00
panq
b12d46b7d6 debug 2025-06-09 22:43:18 +02:00
panq
ba61b16dc6 debug 2025-06-09 22:39:17 +02:00
panq
64e1704c2a Merge branch 'ldpc_decoder_cuda' of https://gitlab.eurecom.fr/oai/openairinterface5g into ldpc_decoder_cuda 2025-06-09 22:31:52 +02:00
panq
38422eff50 debug 2025-06-09 22:31:42 +02:00
panq from NVIDIA H200
75e707b893 dump data 2025-06-09 20:26:35 +00:00
panq
28856b9f6a debug 2025-06-09 22:20:21 +02:00
panq
c740ba54a5 debug 2025-06-09 22:13:33 +02:00
panq
baa5843cc6 debug 2025-06-09 22:11:28 +02:00
panq
d52c5dcae1 debug 2025-06-09 21:59:05 +02:00
panq
010f5e4b04 debug 2025-06-09 21:56:24 +02:00
panq
52a6da8b85 debug 2025-06-09 21:55:21 +02:00
panq
94dbe1f946 Merge branch 'ldpc_decoder_cuda' of https://gitlab.eurecom.fr/oai/openairinterface5g into ldpc_decoder_cuda 2025-06-09 21:24:29 +02:00
panq
215365ca87 for debug 2025-06-09 21:24:16 +02:00
panq from NVIDIA H200
11414c35b0 dump data 2025-06-09 13:52:39 +00:00
panq
aedd4a9a69 debug 2025-06-09 15:48:20 +02:00
panq
6d76d2d889 debug 2025-06-09 15:31:50 +02:00
panq from NVIDIA H200
8e1e40a13d dump date 2025-06-09 13:22:17 +00:00
panq
6988f7015e debug 2025-06-09 15:20:00 +02:00
panq
efbc20b6ff debug 2025-06-09 15:18:00 +02:00
panq
df38dff948 debug 2025-06-09 15:05:27 +02:00
panq
085a9b2c0a Merge branch 'ldpc_decoder_cuda' of https://gitlab.eurecom.fr/oai/openairinterface5g into ldpc_decoder_cuda 2025-06-09 15:02:06 +02:00
panq
ccf529ad3d debug 2025-06-09 15:01:59 +02:00
panq from NVIDIA H200
84af1bbf7c dump data 2025-06-09 12:55:12 +00:00
panq
f575917922 debug 2025-06-09 14:53:54 +02:00
panq
e92d6a85f9 Merge branch 'ldpc_decoder_cuda' of https://gitlab.eurecom.fr/oai/openairinterface5g into ldpc_decoder_cuda 2025-06-09 14:52:36 +02:00
panq
6ac7a5d23d debug 2025-06-09 14:52:29 +02:00
panq from NVIDIA H200
f86edbc6dc dump data 2025-06-09 12:14:35 +00:00
panq
49a25f33fb debug 2025-06-09 14:13:17 +02:00
panq
4a948dad5a Merge branch 'ldpc_decoder_cuda' of https://gitlab.eurecom.fr/oai/openairinterface5g into ldpc_decoder_cuda 2025-06-09 14:10:37 +02:00
panq
c8e6c05b3f debug 2025-06-09 14:10:25 +02:00
panq from NVIDIA H200
4f2e735f5b dump data 2025-06-09 11:57:15 +00:00
panq
8160dd3f0d debug 2025-06-09 13:55:38 +02:00
panq from NVIDIA H200
2fc3cdf2b8 dump data 2025-06-09 11:51:30 +00:00
panq
6c97af2bae Merge branch 'ldpc_decoder_cuda' of https://gitlab.eurecom.fr/oai/openairinterface5g into ldpc_decoder_cuda 2025-06-09 13:48:30 +02:00
panq
77d361aa21 debug 2025-06-09 13:48:18 +02:00
panq from NVIDIA H200
f63dac6e76 dump data 2025-06-08 13:48:49 +00:00
panq
de64521228 change address 2025-06-08 15:46:55 +02:00
panq
8e6d8a1c4f change address 2025-06-08 15:36:13 +02:00
panq
7d63abd14c change address 2025-06-08 15:32:34 +02:00
panq
1a0c3764a4 change address 2025-06-08 15:28:19 +02:00
panq
79c03ae4b5 fix lut 2025-06-08 13:49:00 +02:00
panq
264b522fd2 check input 2025-06-08 13:05:10 +02:00
panq
7da4543ca8 check input 2025-06-08 12:58:18 +02:00
panq
f69b11bd0f check input 2025-06-08 12:54:36 +02:00
panq from NVIDIA H200
0e188111b1 check dump file 2025-06-08 10:31:58 +00:00
panq
12c5b054f5 debugging 2025-06-08 12:29:10 +02:00
panq
65d5cc8ac0 debugging 2025-06-08 12:24:10 +02:00
panq
7a76b6adb9 debugging 2025-06-08 12:19:42 +02:00
panq
a41a3a7bbe debugging 2025-06-08 12:16:55 +02:00
panq
fc72657bf5 fix lut 2025-06-08 12:07:36 +02:00
panq
e0a97a23be fix lut 2025-06-08 12:03:39 +02:00
panq
20725355c8 fix lut 2025-06-08 12:01:55 +02:00
panq
1f6a943c63 fix lut 2025-06-08 12:00:13 +02:00
panq
4376de5e13 Merge branch 'ldpc_decoder_cuda' of https://gitlab.eurecom.fr/oai/openairinterface5g into ldpc_decoder_cuda 2025-06-08 11:55:25 +02:00
panq
128eccf84b fix lut 2025-06-08 11:54:04 +02:00
panq from NVIDIA H200
898be9efb7 debug 2025-06-08 09:00:03 +00:00
panq
a806f7d847 debug 2025-06-08 10:49:14 +02:00
panq from NVIDIA H200
0e3aa00687 debug 2025-06-08 08:38:51 +00:00
panq from NVIDIA H200
02a9023d26 dump data 2025-06-08 08:02:46 +00:00
panq from NVIDIA H200
e5022f03db check dump result 2025-06-08 07:08:22 +00:00
panq from NVIDIA H200
b97a0a8ed0 kernel launch successfully but input is not correct. Fixing it 2025-06-07 20:15:41 +00:00
panq from NVIDIA H200
b8b0ae1808 debugging, cn_Proc can run but not corecctly functionning 2025-06-07 12:00:28 +00:00
panq from NVIDIA H200
b417019711 two dummy file for debug 2025-06-06 10:03:21 +00:00
panq from NVIDIA H200
23ce9c98e2 add no stream version 2025-06-06 08:04:58 +00:00
Raymond Knopp
4ac89e6d46 removed ldpc_encoder generated file 2025-06-05 07:33:59 +00:00
Qizhi Pan
32a800bbd2 Merge branch 'ldpc_encoder_test' into 'ldpc_decoder_cuda'
LDPC cuda cn_Proc parts successfully work in the ldpctest

See merge request oai/openairinterface5g!3469
2025-06-05 07:33:07 +00:00
panq from NVIDIA H200
949115e4f0 cuda_decoder first test succeed 2025-06-04 17:33:32 +00:00
panq from NVIDIA H200
a06ad04366 encoder works so far 2025-06-04 14:31:36 +00:00
Raymond Knopp
1c8f88bbb8 added ifdef for unified CPU/GPU memory configuration (e.g. Gracehopper). 2025-06-01 21:22:34 +00:00
Raymond Knopp
2ad88ae0f3 initial implementation of 32-segment interleaved LDPC encoder for NVidia GPU (CUDA). functionally correct and integrated in existing CUDA library. Works only BG1 Zc 384. Integrated into ldpctest 2025-06-01 10:34:20 +00:00
Raymond Knopp
b6a67635ee change to CODING/CMakeLists.txt 2025-05-30 13:01:45 +00:00
Raymond Knopp
3cf8f6344c added initial CUDA implementation (and code generator) for ldpc encoder 2025-05-30 12:56:44 +00:00
panq from NVIDIA H200
050a231b55 cuda version nrLDPC_cn_Proc_BG1.cu 2025-05-29 12:44:52 +00:00
panq from NVIDIA H200
17c4d20042 first commit 2025-05-29 12:29:39 +00:00
Raymond Knopp
6856460923 added entry LDPC encoder routines for CUDA parity check implementation. Limited to BG1 Zc=384 for now. Also, left unoptimized interleaving of input for 32-bit. Will do after with SIMD bit-interleaving. 2025-05-27 21:19:42 +00:00
Raymond Knopp
9a76f26b91 added first version of generator for CUDA LDPC encoder code 2025-05-27 13:31:38 +00:00
1705 changed files with 92880 additions and 148453 deletions

View File

@@ -62,7 +62,6 @@ ForEachMacros:
- BOOST_FOREACH - BOOST_FOREACH
- RB_FOREACH - RB_FOREACH
- UE_iterator - UE_iterator
- FOR_EACH_SEQ_ARR
IncludeBlocks: Preserve IncludeBlocks: Preserve
IncludeCategories: IncludeCategories:
- Regex: '^<ext/.*\.h>' - Regex: '^<ext/.*\.h>'

9
.gitignore vendored
View File

@@ -5,6 +5,7 @@
cmake_targets/log/ cmake_targets/log/
cmake_targets/*/build/ cmake_targets/*/build/
cmake_targets/ran_build/ cmake_targets/ran_build/
cmake_targets/nas_sim_tools/build/
log/ log/
lte_build_oai/ lte_build_oai/
@@ -20,14 +21,6 @@ GRTAGS
GTAGS GTAGS
tags tags
# Package conffiles
tools/packages/oai-lte/conffiles
tools/packages/oai-nr/conffiles
tools/packages/liboai-common/conffiles
tools/packages/liboai-usrp/conffiles
# others # others
nfapi_nr_interface_scf nfapi_nr_interface_scf
*.log *.log

View File

@@ -1,117 +1,5 @@
# RELEASE NOTES: # # 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):
- Preliminary support for RedCap UEs
- Support for NTN LEO scenarios including SIB19 and channel emulation (see
doc/RUNMODEM.md)
- VRTSIM: new shared memory realtime radio (see develop/radio/vrtsim/README.md)
- Support for TDD pattern 2
- Support for long PRACH
- Support for SIB2
- Add unit tests using ctest (see doc/UnitTests.md)
Stability and bug fixes:
- Improve various procedures (e.g., RRC reestablishment, RRC Reject, ...)
- Add improvements for ImScope
- Bugfixes in the entire stack (e.g., #803, #805, #810, #812, #818, #852, #878,
#884, #890, #895, #901, #907, #932, #939 ...)
- Documentation updates
- And many other small fixes, like memory leaks, crashes, ...
RAN changes (gNB/CU/CU-CP/CU-UP/DU/DU-high/DU-low):
- Stability and performance improvements when running with 4-layer DL MIMO
- Stability and performance improvements when running with 2-layer UL MIMO
- Interoperability testing with Metanoia Jura and Foxconn RUs
- Support of O-RAN 7.2 M-plane (Start-up procedure including configuration
management, see also doc/ORAN_FHI7.2_Tutorial.md)
- Upgrade OSC FHI (xran) from E to F release
- Refactoring of LDPC interface and performance improvements
- Support for nFAPI in all scenarios for FR1 (see doc/nfapi.md)
- Support at least 32 UEs concurrently
- Improve robustness when running in split modes (F1, E1)
- Add basic support for beam management in FR2
- Add support for O1 on DU (see also https://gitlab.eurecom.fr/oai/o1-adapter)
- E2 agent: Support for multiple E2SM-RC report service styles
nrUE changes:
- Refactoring of threading towards better code and performance
- Add or rework various procedures (e.g., RA with C-RNTI, Going to Idle, RA, ...)
- Refactor and extend NAS implementation (e.g., Service Request, Registration
Request, Service Acept, Service Reject, ...)
- Support for continuous frequency offset compensation
- Reduce minimum RX-to-TX time to 3
Regression:
- Multiple BWPs do not work reliably on gNB; use tag 2025.w17
## [v2.2.0](https://gitlab.eurecom.fr/oai/openairinterface5g/-/tags/v2.2.0) -> November 2024. ## ## [v2.2.0](https://gitlab.eurecom.fr/oai/openairinterface5g/-/tags/v2.2.0) -> November 2024. ##
General 5G improvements (both gNB and UE): General 5G improvements (both gNB and UE):

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,7 @@
<a href="https://releases.ubuntu.com/22.04/"><img src="https://img.shields.io/badge/OS-Ubuntu22-Green" alt="Supported OS Ubuntu 22"></a> <a href="https://releases.ubuntu.com/22.04/"><img src="https://img.shields.io/badge/OS-Ubuntu22-Green" alt="Supported OS Ubuntu 22"></a>
<a href="https://releases.ubuntu.com/24.04/"><img src="https://img.shields.io/badge/OS-Ubuntu24-Green" alt="Supported OS Ubuntu 24"></a> <a href="https://releases.ubuntu.com/24.04/"><img src="https://img.shields.io/badge/OS-Ubuntu24-Green" alt="Supported OS Ubuntu 24"></a>
<a href="https://www.redhat.com/en/technologies/linux-platforms/enterprise-linux"><img src="https://img.shields.io/badge/OS-RHEL9-Green" alt="Supported OS RHEL9"></a> <a href="https://www.redhat.com/en/technologies/linux-platforms/enterprise-linux"><img src="https://img.shields.io/badge/OS-RHEL9-Green" alt="Supported OS RHEL9"></a>
<a href="https://getfedora.org/en/workstation/"><img src="https://img.shields.io/badge/OS-Fedore41-Green" alt="Supported OS Fedora 43"></a> <a href="https://getfedora.org/en/workstation/"><img src="https://img.shields.io/badge/OS-Fedore41-Green" alt="Supported OS Fedora 41"></a>
</p> </p>
<p align="center"> <p align="center">

233
ci-scripts/Jenkinsfile vendored
View File

@@ -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}"
}
}
}
}
}
}
}

View File

@@ -35,8 +35,6 @@ def gitCommitAuthorEmailAddr
// list of failing stages // list of failing stages
def failingStages = "" def failingStages = ""
OAI_Registry = "gracehopper3-oai.sboai.cs.eurecom.fr"
pipeline { pipeline {
agent { agent {
label nodeExecutor label nodeExecutor
@@ -177,28 +175,6 @@ pipeline {
} }
} }
} }
stage ("Ubuntu-Jetson-Image-Builder") {
steps {
script {
triggerSlaveJob ('RAN-Ubuntu-Jetson-Image-Builder', 'Ubuntu-Jetson-Image-Builder')
}
}
post {
always {
script {
// Using a unique variable name for each test stage to avoid overwriting on a global variable
// due to parallel-time concurrency
ubuntuJetsonBuildStatus = finalizeSlaveJob('RAN-Ubuntu-Jetson-Image-Builder')
}
}
failure {
script {
currentBuild.result = 'FAILURE'
failingStages += ubuntuJetsonBuildStatus
}
}
}
}
stage ("RHEL-Cluster-Image-Builder") { stage ("RHEL-Cluster-Image-Builder") {
steps { steps {
script { script {
@@ -267,24 +243,6 @@ pipeline {
} }
} }
} }
stage ("DockerHub-Push") {
when { expression {doBuild && "PUSH".equals(env.gitlabActionType)} }
steps {
script {
catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') {
triggerSlaveJob ('RAN-DockerHub-Push', 'DockerHub-Push')
}
}
}
post {
failure {
script {
echo "Push to Docker-Hub KO"
failingStages += '\n * RAN-DockerHub-Push'
}
}
}
}
stage ("Image Test Processes") { stage ("Image Test Processes") {
when { expression {doBuild} } when { expression {doBuild} }
parallel { parallel {
@@ -311,52 +269,6 @@ pipeline {
} }
} }
} }
stage ("PhySim-GraceHopper-5G") {
when { expression {do5Gtest || do5GUeTest} }
steps {
script {
triggerSlaveJob ('RAN-PhySim-GraceHopper-5G', 'PhySim-GraceHopper-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
physimGH5GStatus = finalizeSlaveJob('RAN-PhySim-GraceHopper-5G')
}
}
failure {
script {
currentBuild.result = 'FAILURE'
failingStages += physimGH5GStatus
}
}
}
}
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") { stage ("PhySim-Cluster-4G") {
when { expression {do4Gtest} } when { expression {do4Gtest} }
steps { steps {
@@ -403,29 +315,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") { stage ("RF-Sim-Test-5G") {
when { expression {do5Gtest || do5GUeTest} } when { expression {do5Gtest || do5GUeTest} }
steps { steps {
@@ -726,11 +615,11 @@ pipeline {
} }
} }
} }
stage ("SA-Multi-Antenna-CN5G") { stage ("SA-2x2-Module-CN5G") {
when { expression {do5Gtest} } when { expression {do5Gtest} }
steps { steps {
script { script {
triggerSlaveJob ('RAN-SA-Multi-Antenna-CN5G', 'SA-Multi-Antenna-CN5G') triggerSlaveJob ('RAN-SA-2x2-Module-CN5G', 'SA-2x2-Module-CN5G')
} }
} }
post { post {
@@ -738,13 +627,13 @@ pipeline {
script { script {
// Using a unique variable name for each test stage to avoid overwriting on a global variable // Using a unique variable name for each test stage to avoid overwriting on a global variable
// due to parallel-time concurrency // due to parallel-time concurrency
saMultiAntennaStatus = finalizeSlaveJob('RAN-SA-Multi-Antenna-CN5G') saTDD2x2Status = finalizeSlaveJob('RAN-SA-2x2-Module-CN5G')
} }
} }
failure { failure {
script { script {
currentBuild.result = 'FAILURE' currentBuild.result = 'FAILURE'
failingStages += saMultiAntennaStatus failingStages += saTDD2x2Status
} }
} }
} }
@@ -772,52 +661,6 @@ pipeline {
} }
} }
} }
stage ("SA-Handover-CN5G") {
when { expression {do5Gtest} }
steps {
script {
triggerSlaveJob ('RAN-SA-Handover-CN5G', 'SA-Handover-CN5G')
}
}
post {
always {
script {
// Using a unique variable name for each test stage to avoid overwriting on a global variable
// due to parallel-time concurrency
saHandoverStatus = finalizeSlaveJob('RAN-SA-Handover-CN5G')
}
}
failure {
script {
currentBuild.result = 'FAILURE'
failingStages += saHandoverStatus
}
}
}
}
stage ("SA-AERIAL-OAIUE-CN5G") {
when { expression {do5Gtest || do5GUeTest} }
steps {
script {
triggerSlaveJob ('RAN-SA-AERIAL-OAIUE-CN5G', 'SA-AERIAL-OAIUE-CN5G')
}
}
post {
always {
script {
// Using a unique variable name for each test stage to avoid overwriting on a global variable
// due to parallel-time concurrency
saAERIALOAIUEStatus = finalizeSlaveJob('RAN-SA-AERIAL-OAIUE-CN5G')
}
}
failure {
script {
currentBuild.result = 'FAILURE'
failingStages += saAERIALOAIUEStatus
}
}
}
}
stage ("SA-OAIUE-CN5G") { stage ("SA-OAIUE-CN5G") {
when { expression {do5Gtest || do5GUeTest} } when { expression {do5Gtest || do5GUeTest} }
steps { steps {
@@ -843,6 +686,23 @@ pipeline {
} }
} }
} }
stage ("DockerHub-Push") {
when { expression {doBuild && "PUSH".equals(env.gitlabActionType)} }
steps {
script {
triggerSlaveJob ('RAN-DockerHub-Push', 'DockerHub-Push')
}
}
post {
failure {
script {
echo "Push to Docker-Hub KO"
currentBuild.result = 'FAILURE'
failingStages += '\n * RAN-DockerHub-Push'
}
}
}
}
} }
post { post {
success { success {
@@ -906,11 +766,11 @@ def triggerCN5GSlaveJob (jobName, gitlabStatusName) {
shortenShaOne = sh returnStdout: true, script: 'git log -1 --pretty=format:"%h" --abbrev=8 ' + env.gitlabMergeRequestLastCommit shortenShaOne = sh returnStdout: true, script: 'git log -1 --pretty=format:"%h" --abbrev=8 ' + env.gitlabMergeRequestLastCommit
shortenShaOne = shortenShaOne.trim() shortenShaOne = shortenShaOne.trim()
branchName = env.gitlabSourceBranch.replaceAll("/", "-").trim() branchName = env.gitlabSourceBranch.replaceAll("/", "-").trim()
fullRanTag = OAI_Registry + '/oai-gnb:' + env.gitlabSourceBranch + '-' + shortenShaOne fullRanTag = 'porcepix.sboai.cs.eurecom.fr/oai-gnb:' + env.gitlabSourceBranch + '-' + shortenShaOne
} else { } else {
shortenShaOne = sh returnStdout: true, script: 'git log -1 --pretty=format:"%h" --abbrev=8 ' + env.GIT_COMMIT shortenShaOne = sh returnStdout: true, script: 'git log -1 --pretty=format:"%h" --abbrev=8 ' + env.GIT_COMMIT
shortenShaOne = shortenShaOne.trim() shortenShaOne = shortenShaOne.trim()
fullRanTag = OAI_Registry + '/oai-gnb:develop-' + shortenShaOne fullRanTag = 'porcepix.sboai.cs.eurecom.fr/oai-gnb:develop-' + shortenShaOne
} }
// Workaround for the "cancelled" GitLab pipeline notification // Workaround for the "cancelled" GitLab pipeline notification
// The slave job is triggered with the propagate false so the following commands are executed // The slave job is triggered with the propagate false so the following commands are executed
@@ -975,13 +835,11 @@ def finalizeSlaveJob(jobName) {
selector: lastCompleted()) selector: lastCompleted())
if (fileExists(fileName)) { if (fileExists(fileName)) {
sh "sed -i -e 's#TEMPLATE_BUILD_TIME#${JOB_TIMESTAMP}#' ${fileName}" sh "sed -i -e 's#TEMPLATE_BUILD_TIME#${JOB_TIMESTAMP}#' ${fileName}"
} else { archiveArtifacts artifacts: fileName
sh "echo \"could not copy results from ${jobName}, please check pipeline ${BUILD_URL}\" > ${fileName}" // BUILD_URL is like http://server:port/jenkins/job/foo/15/
// no need to add a prefixed '/'
artifactUrl += 'artifact/' + fileName
} }
archiveArtifacts artifacts: fileName
// BUILD_URL is like http://server:port/jenkins/job/foo/15/
// no need to add a prefixed '/'
artifactUrl += 'artifact/' + fileName
} }
artifactUrl = "\n * [${jobName}](${artifactUrl})" artifactUrl = "\n * [${jobName}](${artifactUrl})"
return artifactUrl return artifactUrl

View File

@@ -0,0 +1,237 @@
#!/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_IPAddress == null) {
echo "no eNB_IPAddress given"
allParametersPresent = false
}
if (params.eNB_SourceCodePath == null) {
echo "no eNB_SourceCodePath given"
allParametersPresent = false
}
if (params.eNB_Credentials == null) {
echo "no eNB_Credentials 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.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password'],
[$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 --eNBIPAddress=${params.eNB_IPAddress} --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --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} --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password}"
}
}
}
}
}
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"
}
}
}
}
}
}
}

240
ci-scripts/Jenkinsfile-nrue Normal file
View File

@@ -0,0 +1,240 @@
#!/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_IPAddress == null) {
allParametersPresent = false
}
if (params.eNB_SourceCodePath == null) {
allParametersPresent = false
}
if (params.eNB_Credentials == null) {
allParametersPresent = false
}
if (params.eNB1_IPAddress == null) {
allParametersPresent = false
}
if (params.eNB1_SourceCodePath == null) {
allParametersPresent = false
}
if (params.eNB1_Credentials == 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.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password'],
[$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB1_Credentials}", usernameVariable: 'eNB1_Username', passwordVariable: 'eNB1_Password'],
[$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 --eNBIPAddress=${params.eNB_IPAddress} --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath} --XMLTestFile=${xmlFile} --OCUserName=${OC_Username} --OCPassword=${OC_Password} --OCProjectName=${OC_ProjectName} --eNB1IPAddress=${params.eNB1_IPAddress} --eNB1UserName=${eNB1_Username} --eNB1Password=${eNB1_Password} --eNB1SourceCodePath=${params.eNB1_SourceCodePath}"
}
} catch (Exception e) {
currentBuild.result = 'FAILURE'
buildStageStatus = false
}
}
}
sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus} --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password}"
}
}
}
}
}
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"
}
}
}
}
}
}
}

View File

@@ -0,0 +1,231 @@
#!/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_IPAddress == null) {
allParametersPresent = false
}
if (params.eNB_SourceCodePath == null) {
allParametersPresent = false
}
if (params.eNB_Credentials == 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.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password'],
[$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 --eNBIPAddress=${params.eNB_IPAddress} --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --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} --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password}"
}
}
}
}
}
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"
}
}
}
}
}
}
}

View File

@@ -31,9 +31,6 @@ if (params.LockResources != null && params.LockResources.trim().length() > 0)
// Docker Hub account to push to // Docker Hub account to push to
def DH_Account = "oaisoftwarealliance" def DH_Account = "oaisoftwarealliance"
// internal registry to use
def OAI_Registry = "gracehopper3-oai.sboai.cs.eurecom.fr"
pipeline { pipeline {
agent { agent {
label nodeExecutor label nodeExecutor
@@ -82,22 +79,14 @@ pipeline {
def listOfImages = ["oai-enb", "oai-gnb", "oai-lte-ue", "oai-nr-ue", "oai-nr-cuup", "oai-gnb-fhi72"] def listOfImages = ["oai-enb", "oai-gnb", "oai-lte-ue", "oai-nr-ue", "oai-nr-cuup", "oai-gnb-fhi72"]
// Logging in on both registries // Logging in on both registries
sh "docker login -u ${DH_Username} -p ${DH_Password} > /dev/null 2>&1" sh "docker login -u ${DH_Username} -p ${DH_Password} > /dev/null 2>&1"
sh "docker login -u oaicicd -p oaicicd ${OAI_Registry} > /dev/null 2>&1" sh "docker login -u oaicicd -p oaicicd porcepix.sboai.cs.eurecom.fr > /dev/null 2>&1"
listOfImages.eachWithIndex { item, iindex -> listOfImages.eachWithIndex { item, iindex ->
if (["oai-gnb", "oai-nr-ue", "oai-nr-cuup"].contains(item)) { sh "docker pull --quiet porcepix.sboai.cs.eurecom.fr/${item}:develop-${WEEK_SHA}"
// For images built on AMD64 and ARMv8 Jetson sh "docker image tag porcepix.sboai.cs.eurecom.fr/${item}:develop-${WEEK_SHA} ${DH_Account}/${item}:develop"
echo "Pushing image '${item}' for both AMD64 and ARM64 architectures with tags: ${WEEK_TAG} and develop" sh "docker image tag porcepix.sboai.cs.eurecom.fr/${item}:develop-${WEEK_SHA} ${DH_Account}/${item}:${WEEK_TAG}"
sh "docker rmi ${DH_Account}/${item}:${WEEK_TAG} ${DH_Account}/${item}:develop || true" sh "docker push --quiet ${DH_Account}/${item}:${WEEK_TAG}"
sh "docker buildx imagetools create --tag ${DH_Account}/${item}:${WEEK_TAG} ${OAI_Registry}/${item}:armv8_develop-${WEEK_SHA} ${OAI_Registry}/${item}:develop-${WEEK_SHA}" sh "docker push --quiet ${DH_Account}/${item}:develop"
sh "docker buildx imagetools create --tag ${DH_Account}/${item}:develop ${OAI_Registry}/${item}:armv8_develop-${WEEK_SHA} ${OAI_Registry}/${item}:develop-${WEEK_SHA}" sh "docker rmi ${DH_Account}/${item}:${WEEK_TAG} ${DH_Account}/${item}:develop porcepix.sboai.cs.eurecom.fr/${item}:develop-${WEEK_SHA}"
} else {
sh "docker pull --quiet ${OAI_Registry}/${item}:develop-${WEEK_SHA}"
sh "docker image tag ${OAI_Registry}/${item}:develop-${WEEK_SHA} ${DH_Account}/${item}:develop"
sh "docker image tag ${OAI_Registry}/${item}:develop-${WEEK_SHA} ${DH_Account}/${item}:${WEEK_TAG}"
sh "docker push --quiet ${DH_Account}/${item}:develop"
sh "docker push --quiet ${DH_Account}/${item}:${WEEK_TAG}"
}
sh "docker rmi ${DH_Account}/${item}:${WEEK_TAG} ${DH_Account}/${item}:develop ${OAI_Registry}/${item}:develop-${WEEK_SHA} || true"
} }
// Proxy is not following the same pattern. // Proxy is not following the same pattern.
sh "docker image tag proxy:develop ${DH_Account}/proxy:develop" sh "docker image tag proxy:develop ${DH_Account}/proxy:develop"
@@ -106,7 +95,7 @@ pipeline {
sh "docker push --quiet ${DH_Account}/proxy:${WEEK_TAG}" sh "docker push --quiet ${DH_Account}/proxy:${WEEK_TAG}"
sh "docker rmi ${DH_Account}/proxy:develop ${DH_Account}/proxy:${WEEK_TAG}" sh "docker rmi ${DH_Account}/proxy:develop ${DH_Account}/proxy:${WEEK_TAG}"
// Logging out on both registries // Logging out on both registries
sh "docker logout ${OAI_Registry} > /dev/null 2>&1" sh "docker logout porcepix.sboai.cs.eurecom.fr > /dev/null 2>&1"
sh "docker logout > /dev/null 2>&1" sh "docker logout > /dev/null 2>&1"
} }
} }
@@ -116,7 +105,7 @@ pipeline {
post { post {
always { always {
script { script {
sh "docker logout ${OAI_Registry} > /dev/null 2>&1" sh "docker logout porcepix.sboai.cs.eurecom.fr > /dev/null 2>&1"
sh "docker logout > /dev/null 2>&1" sh "docker logout > /dev/null 2>&1"
echo "End of Registry Push" echo "End of Registry Push"
} }

View File

@@ -0,0 +1,292 @@
#!/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_IPAddress == null) {
allParametersPresent = false
}
if (params.eNB_SourceCodePath == null) {
allParametersPresent = false
}
if (params.eNB_Credentials == 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"
}
}
}
withCredentials([
[$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_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} --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath} --XMLTestFile=${xmlFile}"
}
} catch (Exception e) {
currentBuild.result = 'FAILURE'
buildStageStatus = false
}
}
}
sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus} --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password}"
}
}
}
}
}
stage ("Terminate") {
parallel {
stage('Terminate eNB') {
steps {
echo '\u2705 \u001B[32mTerminate eNB\u001B[0m'
withCredentials([
[$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password']
]) {
sh "python3 ci-scripts/main.py --mode=TerminateeNB --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password}"
}
}
post {
success {
script {
termStatusArray[termENB] = true
}
}
}
}
}
}
stage('Log Collection') {
parallel {
stage('Log Collection (eNB - Build)') {
steps {
withCredentials([
[$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password']
]) {
echo '\u2705 \u001B[32mLog Collection (eNB - Build)\u001B[0m'
sh "python3 ci-scripts/main.py --mode=LogCollectBuild --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath}"
echo '\u2705 \u001B[32mLog Transfer (eNB - Build)\u001B[0m'
sh "sshpass -p \'${eNB_Password}\' scp -o 'StrictHostKeyChecking no' -o 'ConnectTimeout 10' ${eNB_Username}@${params.eNB_IPAddress}:${eNB_SourceCodePath}/cmake_targets/build.log.zip ./build.log.${env.BUILD_ID}.zip || true"
}
script {
if(fileExists("build.log.${env.BUILD_ID}.zip")) {
archiveArtifacts "build.log.${env.BUILD_ID}.zip"
}
}
}
}
stage('Log Collection (eNB - Run)') {
steps {
withCredentials([
[$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password']
]) {
echo '\u2705 \u001B[32mLog Collection (eNB - Run)\u001B[0m'
sh "python3 ci-scripts/main.py --mode=LogCollecteNB --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath} --BuildId=${env.BUILD_ID}"
echo '\u2705 \u001B[32mLog Transfer (eNB - Run)\u001B[0m'
sh "sshpass -p \'${eNB_Password}\' scp -o 'StrictHostKeyChecking no' -o 'ConnectTimeout 10' ${eNB_Username}@${params.eNB_IPAddress}:${eNB_SourceCodePath}/cmake_targets/enb.log.zip ./enb.log.${env.BUILD_ID}.zip || true"
}
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]) {
withCredentials([
[$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password']
]) {
sh "python3 ci-scripts/main.py --mode=TerminateeNB --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password}"
}
}
}
}
}
}

View File

@@ -0,0 +1,286 @@
#!/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
}
// 1st eNB parameters
if (params.eNB_IPAddress == null) {
allParametersPresent = false
}
if (params.eNB_SourceCodePath == null) {
allParametersPresent = false
}
if (params.eNB_Credentials == null) {
allParametersPresent = false
}
// 2nd eNB parameters
if (params.eNB1_IPAddress == null) {
allParametersPresent = false
}
if (params.eNB1_SourceCodePath == null) {
allParametersPresent = false
}
if (params.eNB1_Credentials == null) {
allParametersPresent = false
}
// 3rd eNB parameters
if (params.eNB2_IPAddress == null) {
allParametersPresent = false
}
if (params.eNB2_SourceCodePath == null) {
allParametersPresent = false
}
if (params.eNB2_Credentials == 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"
}
}
}
withCredentials([
[$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password'],
[$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB1_Credentials}", usernameVariable: 'eNB1_Username', passwordVariable: 'eNB1_Password'],
[$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB2_Credentials}", usernameVariable: 'eNB2_Username', passwordVariable: 'eNB2_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} --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath} --eNB1IPAddress=${params.eNB1_IPAddress} --eNB1UserName=${eNB1_Username} --eNB1Password=${eNB1_Password} --eNB1SourceCodePath=${params.eNB1_SourceCodePath} --eNB2IPAddress=${params.eNB2_IPAddress} --eNB2UserName=${eNB2_Username} --eNB2Password=${eNB2_Password} --eNB2SourceCodePath=${params.eNB2_SourceCodePath} --XMLTestFile=${xmlFile}"
}
} catch (Exception e) {
currentBuild.result = 'FAILURE'
buildStageStatus = false
}
}
}
sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus} --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password}"
}
}
}
}
}
stage ("Terminate") {
parallel {
stage('Terminate eNB') {
steps {
echo '\u2705 \u001B[32mTerminate eNB\u001B[0m'
withCredentials([
[$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password']
]) {
sh "python3 ci-scripts/main.py --mode=TerminateeNB --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password}"
}
}
}
}
}
stage('Log Collection') {
parallel {
stage('Log Collection (eNB - Build)') {
steps {
withCredentials([
[$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password']
]) {
echo '\u2705 \u001B[32mLog Collection (eNB - Build)\u001B[0m'
sh "python3 ci-scripts/main.py --mode=LogCollectBuild --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath}"
echo '\u2705 \u001B[32mLog Transfer (eNB - Build)\u001B[0m'
sh "sshpass -p \'${eNB_Password}\' scp -o 'StrictHostKeyChecking no' -o 'ConnectTimeout 10' ${eNB_Username}@${params.eNB_IPAddress}:${eNB_SourceCodePath}/cmake_targets/build.log.zip ./build.log.${env.BUILD_ID}.zip || true"
}
script {
if(fileExists("build.log.${env.BUILD_ID}.zip")) {
archiveArtifacts "build.log.${env.BUILD_ID}.zip"
}
}
}
}
stage('Log Collection (eNB - Run)') {
steps {
withCredentials([
[$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password']
]) {
echo '\u2705 \u001B[32mLog Collection (eNB - Run)\u001B[0m'
sh "python3 ci-scripts/main.py --mode=LogCollecteNB --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath} --BuildId=${env.BUILD_ID}"
echo '\u2705 \u001B[32mLog Transfer (eNB - Run)\u001B[0m'
sh "sshpass -p \'${eNB_Password}\' scp -o 'StrictHostKeyChecking no' -o 'ConnectTimeout 10' ${eNB_Username}@${params.eNB_IPAddress}:${eNB_SourceCodePath}/cmake_targets/enb.log.zip ./enb.log.${env.BUILD_ID}.zip || true"
}
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"
}
}
}
}
}
}
}

View File

@@ -0,0 +1,274 @@
#!/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
}
// 1st eNB parameters
if (params.eNB_IPAddress == null) {
allParametersPresent = false
}
if (params.eNB_SourceCodePath == null) {
allParametersPresent = false
}
if (params.eNB_Credentials == null) {
allParametersPresent = false
}
// 2nd eNB parameters
if (params.eNB1_IPAddress == null) {
allParametersPresent = false
}
if (params.eNB1_SourceCodePath == null) {
allParametersPresent = false
}
if (params.eNB1_Credentials == null) {
allParametersPresent = false
}
// 3rd eNB parameters
if (params.eNB2_IPAddress == null) {
allParametersPresent = false
}
if (params.eNB2_SourceCodePath == null) {
allParametersPresent = false
}
if (params.eNB2_Credentials == 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"
}
}
}
withCredentials([
[$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password'],
[$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB1_Credentials}", usernameVariable: 'eNB1_Username', passwordVariable: 'eNB1_Password'],
[$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB2_Credentials}", usernameVariable: 'eNB2_Username', passwordVariable: 'eNB2_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} --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath} --eNB1IPAddress=${params.eNB1_IPAddress} --eNB1UserName=${eNB1_Username} --eNB1Password=${eNB1_Password} --eNB1SourceCodePath=${params.eNB1_SourceCodePath} --eNB2IPAddress=${params.eNB2_IPAddress} --eNB2UserName=${eNB2_Username} --eNB2Password=${eNB2_Password} --eNB2SourceCodePath=${params.eNB2_SourceCodePath} --XMLTestFile=${xmlFile}"
}
} catch (Exception e) {
currentBuild.result = 'FAILURE'
buildStageStatus = false
}
}
}
sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus} --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password}"
}
}
}
}
}
stage('Log Collection') {
parallel {
stage('Log Collection (eNB - Build)') {
steps {
withCredentials([
[$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password']
]) {
echo '\u2705 \u001B[32mLog Collection (eNB - Build)\u001B[0m'
sh "python3 ci-scripts/main.py --mode=LogCollectBuild --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath}"
echo '\u2705 \u001B[32mLog Transfer (eNB - Build)\u001B[0m'
sh "sshpass -p \'${eNB_Password}\' scp -o 'StrictHostKeyChecking no' -o 'ConnectTimeout 10' ${eNB_Username}@${params.eNB_IPAddress}:${eNB_SourceCodePath}/cmake_targets/build.log.zip ./build.log.${env.BUILD_ID}.zip || true"
}
script {
if(fileExists("build.log.${env.BUILD_ID}.zip")) {
archiveArtifacts "build.log.${env.BUILD_ID}.zip"
}
}
}
}
stage('Log Collection (eNB - Run)') {
steps {
withCredentials([
[$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password']
]) {
echo '\u2705 \u001B[32mLog Collection (eNB - Run)\u001B[0m'
sh "python3 ci-scripts/main.py --mode=LogCollecteNB --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath} --BuildId=${env.BUILD_ID}"
echo '\u2705 \u001B[32mLog Transfer (eNB - Run)\u001B[0m'
sh "sshpass -p \'${eNB_Password}\' scp -o 'StrictHostKeyChecking no' -o 'ConnectTimeout 10' ${eNB_Username}@${params.eNB_IPAddress}:${eNB_SourceCodePath}/cmake_targets/enb.log.zip ./enb.log.${env.BUILD_ID}.zip || true"
}
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"
}
}
}
}
}
}
}

View File

@@ -0,0 +1,303 @@
#!/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_IPAddress == null) {
allParametersPresent = false
}
if (params.eNB_SourceCodePath == null) {
allParametersPresent = false
}
if (params.eNB_Credentials == 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"
}
}
}
withCredentials([
[$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password'],
]) {
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} --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath} --XMLTestFile=${xmlFile}"
}
} catch (Exception e) {
currentBuild.result = 'FAILURE'
buildStageStatus = false
}
}
}
sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus} --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password}"
}
}
}
}
}
stage ("Terminate") {
parallel {
stage('Terminate eNB') {
steps {
echo '\u2705 \u001B[32mTerminate eNB\u001B[0m'
withCredentials([
[$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password']
]) {
sh "python3 ci-scripts/main.py --mode=TerminateeNB --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password}"
}
}
post {
success {
script {
termStatusArray[termENB] = true
}
}
}
}
}
}
stage('Log Collection') {
parallel {
stage('Log Collection (eNB - Build)') {
steps {
withCredentials([
[$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password']
]) {
echo '\u2705 \u001B[32mLog Collection (eNB - Build)\u001B[0m'
sh "python3 ci-scripts/main.py --mode=LogCollectBuild --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath}"
echo '\u2705 \u001B[32mLog Transfer (eNB - Build)\u001B[0m'
sh "sshpass -p \'${eNB_Password}\' scp -o 'StrictHostKeyChecking no' -o 'ConnectTimeout 10' ${eNB_Username}@${params.eNB_IPAddress}:${eNB_SourceCodePath}/cmake_targets/build.log.zip ./build.log.${env.BUILD_ID}.zip || true"
}
script {
if(fileExists("build.log.${env.BUILD_ID}.zip")) {
archiveArtifacts "build.log.${env.BUILD_ID}.zip"
}
}
}
}
stage('Log Collection (eNB - Run)') {
steps {
withCredentials([
[$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password']
]) {
echo '\u2705 \u001B[32mLog Collection (eNB - Run)\u001B[0m'
sh "python3 ci-scripts/main.py --mode=LogCollecteNB --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath} --BuildId=${env.BUILD_ID}"
echo '\u2705 \u001B[32mLog Transfer (eNB - Run)\u001B[0m'
sh "sshpass -p \'${eNB_Password}\' scp -o 'StrictHostKeyChecking no' -o 'ConnectTimeout 10' ${eNB_Username}@${params.eNB_IPAddress}:${eNB_SourceCodePath}/cmake_targets/enb.log.zip ./enb.log.${env.BUILD_ID}.zip || true"
}
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]) {
withCredentials([
[$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password']
]) {
sh "python3 ci-scripts/main.py --mode=TerminateeNB --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password}"
}
}
}
}
}
}

View File

@@ -1,60 +0,0 @@
This document outlines how to use the OAI CI framework and gives a quickstart.
[[_TOC_]]
# Quickstart
There is a script `main.py` that
- reads scenario files from XML
- executes the steps (e.g., deployment of CN/gNB/UE, attach, ping, ...)
To simplify, a script `run_locally.sh` can be used to run a single scenario
locally. First, download images for gNB&UE (we assume you already downloaded
the CN) and tag them "latest", which is expected by `run_locally.sh`:
docker pull oaisoftwarealliance/oai-gnb:develop
docker tag oaisoftwarealliance/oai-gnb:develop oai-gnb
docker pull oaisoftwarealliance/oai-nr-ue:develop
docker tag oaisoftwarealliance/oai-nr-ue:develop oai-nr-ue
Now, run the scenario:
cd ~/openairinterface5g/ci-scripts/
./run_locally.sh xml_files/container_5g_rfsim_simple.xml
Output should look like
```
[2025-08-07 18:07:49,631] INFO: ----------------------------------------
[2025-08-07 18:07:49,631] INFO: Creating HTML header
[2025-08-07 18:07:49,631] INFO: ----------------------------------------
[2025-08-07 18:07:49,766] INFO: ----------------------------------------
[2025-08-07 18:07:49,767] INFO: Starting Scenario: xml_files/container_5g_rfsim_simple.xml
[2025-08-07 18:07:49,767] INFO: ----------------------------------------
[2025-08-07 18:07:49,767] INFO: placing all artifacts for this run in /home/richie/oai/cmake_targets/log/container_5g_rfsim_simple.xml.d/
[...]
[2025-08-07 18:07:49,771] INFO: ----------------------------------------
[2025-08-07 18:07:49,771] INFO: Test ID: 1 (#1)
[2025-08-07 18:07:49,771] INFO: Deploy OAI 5G CoreNetwork
[2025-08-07 18:07:49,771] INFO: ----------------------------------------
```
it will run an end-to-end test, connecting one UE to the gNB, and ping, before
undeploying. As shown, logs will be under
`/home/richie/oai/cmake_targets/log/container_5g_rfsim_simple.xml.d/`. The
python code also produces an HTML report in `ci-scripts/test_results.html`.
# Running with local changes
In order to run the tests as above, with local changes, please [build images
locally](../docker/README.md).
It is not yet possible to override an existing image with changes made locally
to a source file and run it directly through the CI framework. However, it is
possible to override an existing image with local changes, and run the scenario
manually following the console logs steps provided above. This is described in
the [5G RFsimulator
README](yaml_files/5g_rfsimulator/README.md#6-running-with-local-changes).

View File

@@ -33,6 +33,7 @@
#----------------------------------------------------------- #-----------------------------------------------------------
import sys # arg import sys # arg
import re # reg import re # reg
import yaml
import constants as CONST import constants as CONST
#----------------------------------------------------------- #-----------------------------------------------------------
@@ -42,8 +43,11 @@ import constants as CONST
def ArgsParse(argvs,CiTestObj,RAN,HTML,CONTAINERS,HELP,SCA,CLUSTER): def ArgsParse(argvs,CiTestObj,RAN,HTML,CONTAINERS,HELP,SCA,CLUSTER):
py_param_file_present = False
py_params={}
force_local = False force_local = False
date_fmt = None
while len(argvs) > 1: while len(argvs) > 1:
myArgv = argvs.pop(1) # 0th is this file's name myArgv = argvs.pop(1) # 0th is this file's name
@@ -55,10 +59,18 @@ def ArgsParse(argvs,CiTestObj,RAN,HTML,CONTAINERS,HELP,SCA,CLUSTER):
force_local = True force_local = True
#--apply=<filename> as parameters file, to replace inline parameters
elif re.match(r'^\-\-Apply=(.+)$', myArgv, re.IGNORECASE):
matchReg = re.match(r'^\-\-Apply=(.+)$', myArgv, re.IGNORECASE)
py_params_file = matchReg.group(1)
with open(py_params_file,'r') as file:
# The FullLoader parameter handles the conversion from YAML
# scalar values to Python dictionary format
py_params = yaml.load(file,Loader=yaml.FullLoader)
py_param_file_present = True #to be removed once validated
#AssignParams(py_params) #to be uncommented once validated
#consider inline parameters #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): elif re.match(r'^\-\-mode=(.+)$', myArgv, re.IGNORECASE):
matchReg = re.match(r'^\-\-mode=(.+)$', myArgv, re.IGNORECASE) matchReg = re.match(r'^\-\-mode=(.+)$', myArgv, re.IGNORECASE)
mode = matchReg.group(1) mode = matchReg.group(1)
@@ -120,11 +132,50 @@ def ArgsParse(argvs,CiTestObj,RAN,HTML,CONTAINERS,HELP,SCA,CLUSTER):
SCA.ranTargetBranch=matchReg.group(1) SCA.ranTargetBranch=matchReg.group(1)
CLUSTER.ranTargetBranch=matchReg.group(1) CLUSTER.ranTargetBranch=matchReg.group(1)
elif re.match(r'^\-\-eNBIPAddress=(.+)$|^\-\-eNB[1-2]IPAddress=(.+)$', myArgv, re.IGNORECASE): elif re.match(r'^\-\-eNBIPAddress=(.+)$|^\-\-eNB[1-2]IPAddress=(.+)$', myArgv, re.IGNORECASE):
print("parameters --eNB*IPAddress ignored") if re.match(r'^\-\-eNBIPAddress=(.+)$', myArgv, re.IGNORECASE):
matchReg = re.match(r'^\-\-eNBIPAddress=(.+)$', myArgv, re.IGNORECASE)
RAN.eNBIPAddress=matchReg.group(1)
CONTAINERS.eNBIPAddress=matchReg.group(1)
SCA.eNBIPAddress=matchReg.group(1)
CLUSTER.eNBIPAddress=matchReg.group(1)
elif re.match(r'^\-\-eNB1IPAddress=(.+)$', myArgv, re.IGNORECASE):
matchReg = re.match(r'^\-\-eNB1IPAddress=(.+)$', myArgv, re.IGNORECASE)
RAN.eNB1IPAddress=matchReg.group(1)
CONTAINERS.eNB1IPAddress=matchReg.group(1)
elif re.match(r'^\-\-eNB2IPAddress=(.+)$', myArgv, re.IGNORECASE):
matchReg = re.match(r'^\-\-eNB2IPAddress=(.+)$', myArgv, re.IGNORECASE)
RAN.eNB2IPAddress=matchReg.group(1)
CONTAINERS.eNB2IPAddress=matchReg.group(1)
elif re.match(r'^\-\-eNBUserName=(.+)$|^\-\-eNB[1-2]UserName=(.+)$', myArgv, re.IGNORECASE): elif re.match(r'^\-\-eNBUserName=(.+)$|^\-\-eNB[1-2]UserName=(.+)$', myArgv, re.IGNORECASE):
print("parameters --eNB*UserName ignored") if re.match(r'^\-\-eNBUserName=(.+)$', myArgv, re.IGNORECASE):
matchReg = re.match(r'^\-\-eNBUserName=(.+)$', myArgv, re.IGNORECASE)
RAN.eNBUserName=matchReg.group(1)
CONTAINERS.eNBUserName=matchReg.group(1)
SCA.eNBUserName=matchReg.group(1)
CLUSTER.eNBUserName=matchReg.group(1)
elif re.match(r'^\-\-eNB1UserName=(.+)$', myArgv, re.IGNORECASE):
matchReg = re.match(r'^\-\-eNB1UserName=(.+)$', myArgv, re.IGNORECASE)
RAN.eNB1UserName=matchReg.group(1)
CONTAINERS.eNB1UserName=matchReg.group(1)
elif re.match(r'^\-\-eNB2UserName=(.+)$', myArgv, re.IGNORECASE):
matchReg = re.match(r'^\-\-eNB2UserName=(.+)$', myArgv, re.IGNORECASE)
RAN.eNB2UserName=matchReg.group(1)
CONTAINERS.eNB2UserName=matchReg.group(1)
elif re.match(r'^\-\-eNBPassword=(.+)$|^\-\-eNB[1-2]Password=(.+)$', myArgv, re.IGNORECASE): elif re.match(r'^\-\-eNBPassword=(.+)$|^\-\-eNB[1-2]Password=(.+)$', myArgv, re.IGNORECASE):
print("parameter --eNB*Password ignored") if re.match(r'^\-\-eNBPassword=(.+)$', myArgv, re.IGNORECASE):
matchReg = re.match(r'^\-\-eNBPassword=(.+)$', myArgv, re.IGNORECASE)
RAN.eNBPassword=matchReg.group(1)
CONTAINERS.eNBPassword=matchReg.group(1)
SCA.eNBPassword=matchReg.group(1)
CLUSTER.eNBPassword=matchReg.group(1)
elif re.match(r'^\-\-eNB1Password=(.+)$', myArgv, re.IGNORECASE):
matchReg = re.match(r'^\-\-eNB1Password=(.+)$', myArgv, re.IGNORECASE)
RAN.eNB1Password=matchReg.group(1)
CONTAINERS.eNB1Password=matchReg.group(1)
elif re.match(r'^\-\-eNB2Password=(.+)$', myArgv, re.IGNORECASE):
matchReg = re.match(r'^\-\-eNB2Password=(.+)$', myArgv, re.IGNORECASE)
RAN.eNB2Password=matchReg.group(1)
CONTAINERS.eNB2Password=matchReg.group(1)
elif re.match(r'^\-\-eNBSourceCodePath=(.+)$|^\-\-eNB[1-2]SourceCodePath=(.+)$', myArgv, re.IGNORECASE): elif re.match(r'^\-\-eNBSourceCodePath=(.+)$|^\-\-eNB[1-2]SourceCodePath=(.+)$', myArgv, re.IGNORECASE):
if re.match(r'^\-\-eNBSourceCodePath=(.+)$', myArgv, re.IGNORECASE): if re.match(r'^\-\-eNBSourceCodePath=(.+)$', myArgv, re.IGNORECASE):
matchReg = re.match(r'^\-\-eNBSourceCodePath=(.+)$', myArgv, re.IGNORECASE) matchReg = re.match(r'^\-\-eNBSourceCodePath=(.+)$', myArgv, re.IGNORECASE)
@@ -133,14 +184,26 @@ def ArgsParse(argvs,CiTestObj,RAN,HTML,CONTAINERS,HELP,SCA,CLUSTER):
SCA.eNBSourceCodePath=matchReg.group(1) SCA.eNBSourceCodePath=matchReg.group(1)
CLUSTER.eNBSourceCodePath=matchReg.group(1) CLUSTER.eNBSourceCodePath=matchReg.group(1)
elif re.match(r'^\-\-eNB1SourceCodePath=(.+)$', myArgv, re.IGNORECASE): elif re.match(r'^\-\-eNB1SourceCodePath=(.+)$', myArgv, re.IGNORECASE):
print("parameter --eNB1SourceCodePath ignored") matchReg = re.match(r'^\-\-eNB1SourceCodePath=(.+)$', myArgv, re.IGNORECASE)
RAN.eNB1SourceCodePath=matchReg.group(1)
CONTAINERS.eNB1SourceCodePath=matchReg.group(1)
elif re.match(r'^\-\-eNB2SourceCodePath=(.+)$', myArgv, re.IGNORECASE): elif re.match(r'^\-\-eNB2SourceCodePath=(.+)$', myArgv, re.IGNORECASE):
print("parameter --eNB2SourceCodePath ignored") matchReg = re.match(r'^\-\-eNB2SourceCodePath=(.+)$', myArgv, re.IGNORECASE)
RAN.eNB2SourceCodePath=matchReg.group(1)
CONTAINERS.eNB2SourceCodePath=matchReg.group(1)
elif re.match(r'^\-\-XMLTestFile=(.+)$', myArgv, re.IGNORECASE): elif re.match(r'^\-\-XMLTestFile=(.+)$', myArgv, re.IGNORECASE):
matchReg = re.match(r'^\-\-XMLTestFile=(.+)$', myArgv, re.IGNORECASE) matchReg = re.match(r'^\-\-XMLTestFile=(.+)$', myArgv, re.IGNORECASE)
CiTestObj.testXMLfiles.append(matchReg.group(1)) CiTestObj.testXMLfiles.append(matchReg.group(1))
HTML.testXMLfiles.append(matchReg.group(1)) HTML.testXMLfiles.append(matchReg.group(1))
HTML.nbTestXMLfiles=HTML.nbTestXMLfiles+1 HTML.nbTestXMLfiles=HTML.nbTestXMLfiles+1
elif re.match(r'^\-\-UEIPAddress=(.+)$', myArgv, re.IGNORECASE): # cleanup
print("parameter --UEIPAddress ignored")
elif re.match(r'^\-\-UEUserName=(.+)$', myArgv, re.IGNORECASE):
print("parameter --UEUserName ignored")
elif re.match(r'^\-\-UEPassword=(.+)$', myArgv, re.IGNORECASE):
print("parameter --UEPassword ignored")
elif re.match(r'^\-\-UESourceCodePath=(.+)$', myArgv, re.IGNORECASE):
print("parameter --UESourceCodePath ignored")
elif re.match(r'^\-\-finalStatus=(.+)$', myArgv, re.IGNORECASE): elif re.match(r'^\-\-finalStatus=(.+)$', myArgv, re.IGNORECASE):
matchReg = re.match(r'^\-\-finalStatus=(.+)$', myArgv, re.IGNORECASE) matchReg = re.match(r'^\-\-finalStatus=(.+)$', myArgv, re.IGNORECASE)
finalStatus = matchReg.group(1) finalStatus = matchReg.group(1)
@@ -161,6 +224,9 @@ def ArgsParse(argvs,CiTestObj,RAN,HTML,CONTAINERS,HELP,SCA,CLUSTER):
elif re.match(r'^\-\-OCRegistry=(.+)$', myArgv, re.IGNORECASE): elif re.match(r'^\-\-OCRegistry=(.+)$', myArgv, re.IGNORECASE):
matchReg = re.match(r'^\-\-OCRegistry=(.+)$', myArgv, re.IGNORECASE) matchReg = re.match(r'^\-\-OCRegistry=(.+)$', myArgv, re.IGNORECASE)
CLUSTER.OCRegistry = matchReg.group(1) 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): elif re.match(r'^\-\-FlexRicTag=(.+)$', myArgv, re.IGNORECASE):
matchReg = re.match(r'^\-\-FlexRicTag=(.+)$', myArgv, re.IGNORECASE) matchReg = re.match(r'^\-\-FlexRicTag=(.+)$', myArgv, re.IGNORECASE)
CONTAINERS.flexricTag = matchReg.group(1) CONTAINERS.flexricTag = matchReg.group(1)
@@ -168,4 +234,4 @@ def ArgsParse(argvs,CiTestObj,RAN,HTML,CONTAINERS,HELP,SCA,CLUSTER):
HELP.GenericHelp(CONST.Version) HELP.GenericHelp(CONST.Version)
sys.exit('Invalid Parameter: ' + myArgv) sys.exit('Invalid Parameter: ' + myArgv)
return mode, force_local, date_fmt return py_param_file_present, py_params, mode, force_local

View File

@@ -5,16 +5,16 @@
{ {
#define N_ANTENNA_DL 1 #define N_ANTENNA_DL 1
#define N_ANTENNA_UL 1 #define N_ANTENNA_UL 1
#define DL_ARFCN 627360 #define DL_ARFCN 631296
#define TDD 1 #define TDD 1
log_options: "all.level=debug,all.max_size=0,nas.level=debug,nas.max_size=1,rrc.level=debug,rrc.max_size=1", log_options: "all.level=warn,all.max_size=0,nas.level=debug,nas.max_size=1,rrc.level=debug,rrc.max_size=1",
log_filename: "/tmp/ue.log", log_filename: "/tmp/ue.log",
/* Enable remote API and Web interface */ /* Enable remote API and Web interface */
com_addr: "0.0.0.0:9002", com_addr: "0.0.0.0:9002",
include "rf_driver/config.cfg", include "rf_driver_20/1chan.cfg",
/* If true, allow the simulation of several UEs at the same time and /* If true, allow the simulation of several UEs at the same time and
allow dynamic UE creation from remote API */ allow dynamic UE creation from remote API */
@@ -22,6 +22,7 @@ allow dynamic UE creation from remote API */
cell_groups: [{ cell_groups: [{
group_type: "nr", group_type: "nr",
multi_ue: true, multi_ue: true,
ldpc_max_its:8,
cells: [{ cells: [{
rf_port: 0, rf_port: 0,
bandwidth: 20, bandwidth: 20,
@@ -46,7 +47,7 @@ allow dynamic UE creation from remote API */
"sim_algo":"milenage", "sim_algo":"milenage",
"op": "1006020f0a478bf6b699f15c062e42b3", "op": "1006020f0a478bf6b699f15c062e42b3",
as_release: 17, as_release: 15,
ue_category: "nr", ue_category: "nr",
apn:"oai", apn:"oai",
attach_pdn_type:"ipv4", attach_pdn_type:"ipv4",
@@ -61,9 +62,8 @@ allow dynamic UE creation from remote API */
"sim_algo":"milenage", "sim_algo":"milenage",
"op": "1006020f0a478bf6b699f15c062e42b3", "op": "1006020f0a478bf6b699f15c062e42b3",
as_release: 17, as_release: 15,
ue_category: "nr", ue_category: "nr",
redcap: "redcap",
apn:"oai", apn:"oai",
attach_pdn_type:"ipv4", attach_pdn_type:"ipv4",
default_nssai: [ { sst: 1, }, ], default_nssai: [ { sst: 1, }, ],
@@ -77,7 +77,7 @@ allow dynamic UE creation from remote API */
"sim_algo":"milenage", "sim_algo":"milenage",
"op": "1006020f0a478bf6b699f15c062e42b3", "op": "1006020f0a478bf6b699f15c062e42b3",
as_release: 17, as_release: 15,
ue_category: "nr", ue_category: "nr",
apn:"oai", apn:"oai",
attach_pdn_type:"ipv4", attach_pdn_type:"ipv4",
@@ -92,7 +92,7 @@ allow dynamic UE creation from remote API */
"sim_algo":"milenage", "sim_algo":"milenage",
"op": "1006020f0a478bf6b699f15c062e42b3", "op": "1006020f0a478bf6b699f15c062e42b3",
as_release: 17, as_release: 15,
ue_category: "nr", ue_category: "nr",
apn:"oai", apn:"oai",
attach_pdn_type:"ipv4", attach_pdn_type:"ipv4",
@@ -107,9 +107,8 @@ allow dynamic UE creation from remote API */
"sim_algo":"milenage", "sim_algo":"milenage",
"op": "1006020f0a478bf6b699f15c062e42b3", "op": "1006020f0a478bf6b699f15c062e42b3",
as_release: 17, as_release: 15,
ue_category: "nr", ue_category: "nr",
redcap: "redcap",
apn:"oai", apn:"oai",
attach_pdn_type:"ipv4", attach_pdn_type:"ipv4",
default_nssai: [ { sst: 1, }, ], default_nssai: [ { sst: 1, }, ],
@@ -123,9 +122,8 @@ allow dynamic UE creation from remote API */
"sim_algo":"milenage", "sim_algo":"milenage",
"op": "1006020f0a478bf6b699f15c062e42b3", "op": "1006020f0a478bf6b699f15c062e42b3",
as_release: 17, as_release: 15,
ue_category: "nr", ue_category: "nr",
redcap: "redcap",
apn:"oai", apn:"oai",
attach_pdn_type:"ipv4", attach_pdn_type:"ipv4",
default_nssai: [ { sst: 1, }, ], default_nssai: [ { sst: 1, }, ],
@@ -139,7 +137,7 @@ allow dynamic UE creation from remote API */
"sim_algo":"milenage", "sim_algo":"milenage",
"op": "1006020f0a478bf6b699f15c062e42b3", "op": "1006020f0a478bf6b699f15c062e42b3",
as_release: 17, as_release: 15,
ue_category: "nr", ue_category: "nr",
apn:"oai", apn:"oai",
attach_pdn_type:"ipv4", attach_pdn_type:"ipv4",
@@ -154,7 +152,7 @@ allow dynamic UE creation from remote API */
"sim_algo":"milenage", "sim_algo":"milenage",
"op": "1006020f0a478bf6b699f15c062e42b3", "op": "1006020f0a478bf6b699f15c062e42b3",
as_release: 17, as_release: 15,
ue_category: "nr", ue_category: "nr",
apn:"oai", apn:"oai",
attach_pdn_type:"ipv4", attach_pdn_type:"ipv4",
@@ -169,7 +167,7 @@ allow dynamic UE creation from remote API */
"sim_algo":"milenage", "sim_algo":"milenage",
"op": "1006020f0a478bf6b699f15c062e42b3", "op": "1006020f0a478bf6b699f15c062e42b3",
as_release: 17, as_release: 15,
ue_category: "nr", ue_category: "nr",
apn:"oai", apn:"oai",
attach_pdn_type:"ipv4", attach_pdn_type:"ipv4",
@@ -184,9 +182,8 @@ allow dynamic UE creation from remote API */
"sim_algo":"milenage", "sim_algo":"milenage",
"op": "1006020f0a478bf6b699f15c062e42b3", "op": "1006020f0a478bf6b699f15c062e42b3",
as_release: 17, as_release: 15,
ue_category: "nr", ue_category: "nr",
redcap: "redcap",
apn:"oai", apn:"oai",
attach_pdn_type:"ipv4", attach_pdn_type:"ipv4",
default_nssai: [ { sst: 1, }, ], default_nssai: [ { sst: 1, }, ],
@@ -200,9 +197,8 @@ allow dynamic UE creation from remote API */
"sim_algo":"milenage", "sim_algo":"milenage",
"op": "1006020f0a478bf6b699f15c062e42b3", "op": "1006020f0a478bf6b699f15c062e42b3",
as_release: 17, as_release: 15,
ue_category: "nr", ue_category: "nr",
redcap: "redcap",
apn:"oai", apn:"oai",
attach_pdn_type:"ipv4", attach_pdn_type:"ipv4",
default_nssai: [ { sst: 1, }, ], default_nssai: [ { sst: 1, }, ],
@@ -216,9 +212,8 @@ allow dynamic UE creation from remote API */
"sim_algo":"milenage", "sim_algo":"milenage",
"op": "1006020f0a478bf6b699f15c062e42b3", "op": "1006020f0a478bf6b699f15c062e42b3",
as_release: 17, as_release: 15,
ue_category: "nr", ue_category: "nr",
redcap: "redcap",
apn:"oai", apn:"oai",
attach_pdn_type:"ipv4", attach_pdn_type:"ipv4",
default_nssai: [ { sst: 1, }, ], default_nssai: [ { sst: 1, }, ],
@@ -232,7 +227,7 @@ allow dynamic UE creation from remote API */
"sim_algo":"milenage", "sim_algo":"milenage",
"op": "1006020f0a478bf6b699f15c062e42b3", "op": "1006020f0a478bf6b699f15c062e42b3",
as_release: 17, as_release: 15,
ue_category: "nr", ue_category: "nr",
apn:"oai", apn:"oai",
attach_pdn_type:"ipv4", attach_pdn_type:"ipv4",
@@ -247,7 +242,7 @@ allow dynamic UE creation from remote API */
"sim_algo":"milenage", "sim_algo":"milenage",
"op": "1006020f0a478bf6b699f15c062e42b3", "op": "1006020f0a478bf6b699f15c062e42b3",
as_release: 17, as_release: 15,
ue_category: "nr", ue_category: "nr",
apn:"oai", apn:"oai",
attach_pdn_type:"ipv4", attach_pdn_type:"ipv4",
@@ -262,9 +257,8 @@ allow dynamic UE creation from remote API */
"sim_algo":"milenage", "sim_algo":"milenage",
"op": "1006020f0a478bf6b699f15c062e42b3", "op": "1006020f0a478bf6b699f15c062e42b3",
as_release: 17, as_release: 15,
ue_category: "nr", ue_category: "nr",
redcap: "redcap",
apn:"oai", apn:"oai",
attach_pdn_type:"ipv4", attach_pdn_type:"ipv4",
default_nssai: [ { sst: 1, }, ], default_nssai: [ { sst: 1, }, ],
@@ -278,9 +272,8 @@ allow dynamic UE creation from remote API */
"sim_algo":"milenage", "sim_algo":"milenage",
"op": "1006020f0a478bf6b699f15c062e42b3", "op": "1006020f0a478bf6b699f15c062e42b3",
as_release: 17, as_release: 15,
ue_category: "nr", ue_category: "nr",
redcap: "redcap",
apn:"oai", apn:"oai",
attach_pdn_type:"ipv4", attach_pdn_type:"ipv4",
default_nssai: [ { sst: 1, }, ], default_nssai: [ { sst: 1, }, ],

View File

@@ -1,47 +0,0 @@
/* Parameters for SDR device version 2023-06-10
* Copyright (C) 2015-2023 Amarisoft
*/
#if !defined(N_CELL)
#define N_CELL 1
#endif
#if N_ANTENNA_DL <= 2
#define N_CHAN N_CELL
#else
#define N_CHAN 2*N_CELL
#endif
rf_driver: {
name: "sdr",
/* list of devices. 'dev0' is always the master. */
#if N_CHAN == 1
args: "dev0=/dev/sdr0",
#elif N_CHAN == 2
args: "dev0=/dev/sdr0,dev1=/dev/sdr1",
#elif N_CHAN == 3
args: "dev0=/dev/sdr0,dev1=/dev/sdr1,dev2=/dev/sdr2",
#elif N_CHAN == 4
args: "dev0=/dev/sdr0,dev1=/dev/sdr1,dev2=/dev/sdr2,dev3=/dev/sdr3",
#elif N_CHAN == 6
args: "dev0=/dev/sdr0,dev1=/dev/sdr1,dev2=/dev/sdr2,dev3=/dev/sdr3,dev4=/dev/sdr4,dev5=/dev/sdr5",
#else
args: "",
#endif
/* synchronisation source: internal, gps, external (default = internal) */
// sync: "gps",
//rx_antenna:"rx", // force to use the RX connector in TDD as RX antenna
/* PCIe jitter. decrease it to reduce latency */
fifo_tx_time: 50,
//rx_latency: 30,
},
#if 0
tx_pad_duration:300,
#endif
tx_gain: 75.0, /* TX gain (in dB) */
rx_gain: 52.0, /* RX gain (in dB) */

View File

@@ -1,175 +0,0 @@
#!/usr/bin/env python3
import argparse
import logging
import itertools
import usb.core
import usb.util
import sys
import time
logging.basicConfig(
level=logging.DEBUG,
stream=sys.stdout,
format="%(message)s"
)
# helper class parsing command line options for channels and attenuators
class ValidateChAtt(argparse.Action):
def _parse_channels(s):
if len(s.split("-")) == 2:
s, e = [int(x) for x in s.split("-")]
chs = [x for x in range(s, e+1)]
if len(chs) == 0:
raise Exception(f"empty range")
elif len(s.split(",")) > 1:
chs = [int(x) for x in s.split(",")]
elif s.isdigit():
chs = [int(s)]
else:
raise Exception(f"could not parse channel expression")
for c in chs:
if not 1 <= c <= 4:
raise Exception(f"channel number must be within [1,4], but have {c}")
return chs
def __call__(self, parse, args, values, option_string=None):
ch, att = values
try:
chs = ValidateChAtt._parse_channels(ch)
except Exception as e:
parse.exit(1, f"while parsing channel expression {ch}: {e}\n")
if not att.isdigit():
parse.exit(1, f'expected number for attenuation, but got {att}\n')
if not 0 <= int(att) <= 63:
parse.exit(1, f'attenuation must be within [0,63], but is {att}\n')
opts = getattr(args, self.dest) or {}
for c in chs:
opts[c] = int(att)
setattr(args, self.dest, opts)
def _parse_args() -> argparse.Namespace:
epilog = '''
[CHs] can have the following forms:
(1) single channel number w (within [1-4])
(2) a range of channels in the form x-y (x <= y)
(3) a list of channels in the form a,b,c
[ATT] must be within [0,63] (dB)
--set and --reach are mutually exclusive
Examples:
- reset all channels to 0: -s 1-4 0
- set channels 3 and 4 to attenuation 60: -s 3,4 60
- perform attenuation sweep during 10s, reaching ch. 1+2 to 60: -r 1,2 60 -d 10
'''
parser = argparse.ArgumentParser(description='Mini-Circuit RC*DAT attenuator controller',
epilog=epilog,
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument('--info', '-i', action='store_true', default=False,
help='Get Infos for all connected Mini-Circuits RC*DAT',)
parser.add_argument('--set', '-s', nargs=2, metavar=("[CHs]","[ATT]"),
action=ValidateChAtt, help="Set a fixed attenuation ATT on channels CHs")
parser.add_argument('--reach', '-r', nargs=2, metavar=("[CHs]","[ATT]"),
action=ValidateChAtt, help="Perform an \"attenuation sweep\": reach attenuation ATT on channels CHs")
parser.add_argument('--duration', '-d', action='store', type=float, default=5.0,
help='DURATION for attenuation sweep to --reach given attenuation (Default: 5)',)
parser.add_argument('--progress', '-p', action='store_true', default=False,
help='If provided, will show progress during attenuation sweep',)
return parser.parse_args()
def _exec(dev, cmd):
dev.write(1, cmd)
ans = dev.read(0x81,64)
# take from ans(wer) while valid bytes
sn = itertools.takewhile(lambda x: x < 255 and x > 0, ans)
# turn bytes into characters and accumulate into string
return "".join(map(chr, sn))
def devId(dev):
return f"{dev.idVendor:04x}:{dev.idProduct:04x}"
def _info(dev):
ident = devId(dev)
SerialN = _exec(dev, "*:SN?")
ModelN = _exec(dev, "*:MN?")
Fw = _exec(dev, "*:FIRMWARE?")
logging.info(f'{ident}: model is {ModelN}')
logging.info(f'{ident}: serial number is {SerialN}')
logging.info(f'{ident}: FW version is {Fw}')
def _get_attenuation(dev):
ident = devId(dev)
att = _exec(dev, "*:ATT?")
# remove leading "*" and split by channels
return [float(n) for n in att[1:].split(" ")]
def _set_attenuation(dev, ch_att):
ident = devId(dev)
for ch, att in ch_att:
#logging.debug(f"{ident}: Set attenuation channel {ch}: {att} dB")
att = round(4 * att) / 4 # round to closest 0.25dB
resp = _exec(dev, f"*:CHAN:{ch}:SETATT:{att};" )
def _continuous_set_attenuation(dev, ch_att_end, duration, show_progress=False, step_duration=0.25):
ident = devId(dev)
current = _get_attenuation(dev)
steps = duration / step_duration
ch_att_step = [(ch, (att_end - current[ch - 1]) / steps) for ch, att_end in ch_att_end]
logging.info(f"{ident}: sweep attenuation during {duration} s in {steps} steps: increments {ch_att_step}")
for i in range(1, int(steps)+1):
next_att = [(ch, current[ch - 1] + i * att_step) for ch, att_step in ch_att_step]
_set_attenuation(dev, next_att)
if show_progress:
logging.debug(f"{ident}: attenuation for channel(s): {next_att}")
time.sleep(step_duration)
_set_attenuation(dev, ch_att_end)
def _get_usb_devs(idVendor, idProduct):
devs = []
for dev in usb.core.find(idVendor=idVendor, idProduct=idProduct, find_all=True):
for configuration in dev:
for interface in configuration:
ifnum = interface.bInterfaceNumber
if not dev.is_kernel_driver_active(ifnum):
continue
try:
dev.detach_kernel_driver(ifnum)
except e:
pass
devs.append(dev)
return devs
if __name__ == '__main__':
# Parse the arguments
args = _parse_args()
if args.set and args.reach:
logging.error("--set and --reach are mutually exclusive")
sys.exit(1)
# 20ce:0023 is Mini-Circuit RC*DAT device
devs = _get_usb_devs(idVendor=0x20ce, idProduct=0x0023)
if len(devs) == 0:
logging.error('no Mini-Circuits RC*DAT device detected')
sys.exit(-1)
if len(devs) > 1:
logging.error('more than one Mini-Circuits RC*DAT device detected')
sys.exit(-1)
dev = devs[0]
if args.info:
_info(dev)
if args.set:
_set_attenuation(dev, [(k,v) for k,v in args.set.items()])
if args.reach:
_continuous_set_attenuation(dev, [(k,v) for k,v in args.reach.items()], args.duration, args.progress)
ident = devId(dev)
for i, a in enumerate(_get_attenuation(dev)):
logging.info(f"{ident}: Attenuation channel {i+1}: {a} dB")
sys.exit(0)

View File

@@ -5,20 +5,10 @@ idefix:
AttachScript: sudo python3 ci_ctl_qtel.py /dev/ttyUSB2 wup AttachScript: sudo python3 ci_ctl_qtel.py /dev/ttyUSB2 wup
DetachScript: sudo python3 ci_ctl_qtel.py /dev/ttyUSB2 detach DetachScript: sudo python3 ci_ctl_qtel.py /dev/ttyUSB2 detach
NetworkScript: ip a show dev wwan0 NetworkScript: ip a show dev wwan0
#Tracing:
# Start: 'sudo rm -f ci_qlog/*; nohup sudo -b QLog/QLog -s ci_qlog -f NR5G.cfg &'
# Stop: 'sudo killall QLog'
# Collect: 'sudo mv ci_qlog/* %%log_dir%%/'
IF: wwan0
MTU: 1500
raspix:
Host: raspix
AttachScript: sudo /opt/mbim_scripts/start_quectel_mbim.sh
DetachScript: sudo /opt/mbim_scripts/stop_quectel_mbim.sh
NetworkScript: ip a show dev wwan0
IF: wwan0 IF: wwan0
MTU: 1500 MTU: 1500
Trace: True
LogStore: /media/usb-drive/ci_qlogs
up2: up2:
Host: up2 Host: up2
@@ -56,6 +46,7 @@ adb_ue_1:
NetworkScript: adb -s R3CM40LZPHT shell "ip address show | grep rmnet_data0" NetworkScript: adb -s R3CM40LZPHT shell "ip address show | grep rmnet_data0"
CmdPrefix: adb -s R3CM40LZPHT shell CmdPrefix: adb -s R3CM40LZPHT shell
MTU: 1500 MTU: 1500
LogStore: /media/usb-drive/ci_adb_1-logs
adb_ue_2: adb_ue_2:
Host: nano Host: nano
InitScript: /home/oaicicd/ci_ctl_adb.sh initialize 5200c00db4413517 InitScript: /home/oaicicd/ci_ctl_adb.sh initialize 5200c00db4413517
@@ -68,14 +59,15 @@ adb_ue_2:
NetworkScript: adb -s 5200c00db4413517 shell "ip address show | grep rmnet" NetworkScript: adb -s 5200c00db4413517 shell "ip address show | grep rmnet"
CmdPrefix: adb -s 5200c00db4413517 shell CmdPrefix: adb -s 5200c00db4413517 shell
MTU: 1500 MTU: 1500
LogStore: /media/usb-drive/ci_adb_2-logs
oc-cn5g: oc-cn5g:
Host: avra Host: avra
NetworkScript: echo "inet 172.21.6.102" NetworkScript: echo "inet 172.21.6.102"
RunIperf3Server: False RunIperf3Server: False
Deploy: "! scripts/oc-cn5g-deploy.sh /opt/oai-cn5g-fed-develop-2025-jun oaicicd-core-for-ci-ran" Deploy: "! scripts/oc-cn5g-deploy.sh /opt/oai-cn5g-fed-develop-2025-jan oaicicd-core-for-ci-ran"
Undeploy: "! scripts/oc-cn5g-undeploy.sh /opt/oai-cn5g-fed-develop-2025-jun oaicicd-core-for-ci-ran" Undeploy: "! scripts/oc-cn5g-undeploy.sh /opt/oai-cn5g-fed-develop-2025-jan oaicicd-core-for-ci-ran"
LogCollect: "! scripts/oc-cn5g-logcollect.sh /opt/oai-cn5g-fed-develop-2025-jun oaicicd-core-for-ci-ran %%log_dir%%" LogCollect: "! scripts/oc-cn5g-logcollect.sh /opt/oai-cn5g-fed-develop-2025-jan oaicicd-core-for-ci-ran %%log_dir%%"
oc-cn5g-20897: oc-cn5g-20897:
Host: cacofonix Host: cacofonix
@@ -85,14 +77,6 @@ oc-cn5g-20897:
Undeploy: "! scripts/oc-cn5g-undeploy.sh /opt/oai-cn5g-fed-develop-2025-jan oaicicd-core-for-fhi72" Undeploy: "! scripts/oc-cn5g-undeploy.sh /opt/oai-cn5g-fed-develop-2025-jan oaicicd-core-for-fhi72"
LogCollect: "! scripts/oc-cn5g-logcollect.sh /opt/oai-cn5g-fed-develop-2025-jan oaicicd-core-for-fhi72 %%log_dir%%" LogCollect: "! scripts/oc-cn5g-logcollect.sh /opt/oai-cn5g-fed-develop-2025-jan oaicicd-core-for-fhi72 %%log_dir%%"
oc-cn5g-00103-ho:
Host: groot
NetworkScript: echo "inet 172.21.6.111"
RunIperf3Server: False
Deploy: "! scripts/oc-cn5g-deploy.sh /opt/oai-cn5g-fed-develop-2025-jan oaicicd-core-for-ho"
Undeploy: "! scripts/oc-cn5g-undeploy.sh /opt/oai-cn5g-fed-develop-2025-jan oaicicd-core-for-ho"
LogCollect: "! scripts/oc-cn5g-logcollect.sh /opt/oai-cn5g-fed-develop-2025-jan oaicicd-core-for-ho %%log_dir%%"
oc-cn5g-20897-aerial: oc-cn5g-20897-aerial:
Host: gracehopper1-oai Host: gracehopper1-oai
NetworkScript: echo "inet 172.21.6.105" NetworkScript: echo "inet 172.21.6.105"
@@ -101,20 +85,12 @@ oc-cn5g-20897-aerial:
Undeploy: "! scripts/oc-cn5g-undeploy.sh /opt/oai-cn5g-fed-develop-2025-jan oaicicd-core-for-nvidia-aerial" Undeploy: "! scripts/oc-cn5g-undeploy.sh /opt/oai-cn5g-fed-develop-2025-jan oaicicd-core-for-nvidia-aerial"
LogCollect: "! scripts/oc-cn5g-logcollect.sh /opt/oai-cn5g-fed-develop-2025-jan oaicicd-core-for-nvidia-aerial %%log_dir%%" LogCollect: "! scripts/oc-cn5g-logcollect.sh /opt/oai-cn5g-fed-develop-2025-jan oaicicd-core-for-nvidia-aerial %%log_dir%%"
oc-cn5g-00104:
Host: gracehopper1-oai
NetworkScript: echo "inet 172.21.6.105"
RunIperf3Server: False
Deploy: "! scripts/oc-cn5g-deploy.sh /opt/oai-cn5g-fed-develop-00104 oaicicd-core-for-nvidia-aerial"
Undeploy: "! scripts/oc-cn5g-undeploy.sh /opt/oai-cn5g-fed-develop-00104 oaicicd-core-for-nvidia-aerial"
LogCollect: "! scripts/oc-cn5g-logcollect.sh /opt/oai-cn5g-fed-develop-00104 oaicicd-core-for-nvidia-aerial %%log_dir%%"
matix-cn5g: matix-cn5g:
Host: matix Host: matix
NetworkScript: docker exec prod-trf-gen ip a show dev eth0 NetworkScript: docker exec prod-trf-gen ip a show dev eth0
RunIperf3Server: False RunIperf3Server: False
Deploy: "cd /opt/oai-cn5g-fed-v2-jun-2025/docker-compose && python3 ./core-network.py --type start-basic" Deploy: "cd /opt/oai-cn5g-fed-v2/docker-compose && python3 ./core-network.py --type start-basic"
Undeploy: "cd /opt/oai-cn5g-fed-v2-jun-2025/docker-compose && python3 ./core-network.py --type stop-basic" Undeploy: "cd /opt/oai-cn5g-fed-v2/docker-compose && python3 ./core-network.py --type stop-basic"
LogCollect: LogCollect:
- "docker logs oai-smf > %%log_dir%%/oai-smf.log" - "docker logs oai-smf > %%log_dir%%/oai-smf.log"
- "docker logs oai-amf > %%log_dir%%/oai-amf.log" - "docker logs oai-amf > %%log_dir%%/oai-amf.log"
@@ -171,131 +147,125 @@ ltebox-nepes:
amarisoft_ue: amarisoft_ue:
Host: amariue Host: amariue
InitScript: /root/lteue-linux-2025-03-15/lteue /root/oaicicd/ran_sa_aw2s_asue_20MHz_redcap/aw2s-multi-00102-20.cfg & InitScript: /root/lteue-linux-2023-10-27/ue/lteue /root/oaicicd/ran_sa_aw2s_asue/aw2s-multi-00102-20.cfg &
TermScript: /root/lteue-linux-2025-03-15/ws.js -t 10 127.0.0.1:9002 '{"message":"quit"}' || killall -KILL lteue-avx2 TermScript: /root/2023-10-27/libs/ws.js -t 10 127.0.0.1:9002 '{"message":"quit"}' || killall -KILL lteue-avx2
NetworkScript: ip netns exec ue1 ip a show dev pdn0
#Tracing:
# Start: '' # nothing to be done
# Stop: '' # nothing to be done
# Collect: 'cp /tmp/ue.log %%log_dir%%'
amarisoft_ue_2x2: amarisoft_ue_2x2:
Host: amariue Host: amariue
InitScript: /root/lteue-linux-2025-03-15/lteue /root/oaicicd/ran_sa_aw2s_asue_20MHz_2x2/aw2s-multi-00102-2x2-v2.cfg & InitScript: /root/lteue-linux-2023-10-27/ue/lteue /root/oaicicd/ran_sa_aw2s_asue_2x2/aw2s-multi-00102-2x2-v2.cfg &
TermScript: /root/lteue-linux-2025-03-15/ws.js -t 10 127.0.0.1:9002 '{"message":"quit"}' || killall -KILL lteue-avx2 TermScript: /root/2023-10-27/libs/ws.js -t 10 127.0.0.1:9002 '{"message":"quit"}' || killall -KILL lteue-avx2
NetworkScript: ip netns exec ue1 ip a show dev pdn0
amarisoft_ue_fhi72: amarisoft_ue_fhi72:
Host: amariue Host: amariue
InitScript: /root/lteue-linux-2025-03-15/lteue /root/oaicicd/ran_sa_fhi72_asue_2x2_benetel550/fhi72-multi-20897-2x2.cfg & InitScript: /root/lteue-linux-2023-10-27/ue/lteue /root/oaicicd/ran_sa_fhi72_asue_2x2_benetel550/fhi72-multi-20897-2x2.cfg &
TermScript: /root/lteue-linux-2025-03-15/ws.js -t 10 127.0.0.1:9002 '{"message":"quit"}' || killall -KILL lteue-avx2 TermScript: /root/2023-10-27/libs/ws.js -t 10 127.0.0.1:9002 '{"message":"quit"}' || killall -KILL lteue-avx2
amarisoft_ue_1: amarisoft_ue_1:
Host: amariue Host: amariue
AttachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":1}' AttachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":1}'
DetachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":1}' DetachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":1}'
NetworkScript: ip netns exec ue1 ip a show dev pdn0 NetworkScript: ip netns exec ue1 ip a show dev pdn0
CmdPrefix: ip netns exec ue1 CmdPrefix: ip netns exec ue1
MTU: 1500 MTU: 1500
amarisoft_ue_2: amarisoft_ue_2:
Host: amariue Host: amariue
AttachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":2}' AttachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":2}'
DetachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":2}' DetachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":2}'
NetworkScript: ip netns exec ue2 ip a show dev pdn0 NetworkScript: ip netns exec ue2 ip a show dev pdn0
CmdPrefix: ip netns exec ue2 CmdPrefix: ip netns exec ue2
MTU: 1500 MTU: 1500
amarisoft_ue_3: amarisoft_ue_3:
Host: amariue Host: amariue
AttachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":3}' AttachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":3}'
DetachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":3}' DetachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":3}'
NetworkScript: ip netns exec ue3 ip a show dev pdn0 NetworkScript: ip netns exec ue3 ip a show dev pdn0
CmdPrefix: ip netns exec ue3 CmdPrefix: ip netns exec ue3
MTU: 1500 MTU: 1500
amarisoft_ue_4: amarisoft_ue_4:
Host: amariue Host: amariue
AttachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":4}' AttachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":4}'
DetachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":4}' DetachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":4}'
NetworkScript: ip netns exec ue4 ip a show dev pdn0 NetworkScript: ip netns exec ue4 ip a show dev pdn0
CmdPrefix: ip netns exec ue4 CmdPrefix: ip netns exec ue4
MTU: 1500 MTU: 1500
amarisoft_ue_5: amarisoft_ue_5:
Host: amariue Host: amariue
AttachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":5}' AttachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":5}'
DetachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":5}' DetachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":5}'
NetworkScript: ip netns exec ue5 ip a show dev pdn0 NetworkScript: ip netns exec ue5 ip a show dev pdn0
CmdPrefix: ip netns exec ue5 CmdPrefix: ip netns exec ue5
MTU: 1500 MTU: 1500
amarisoft_ue_6: amarisoft_ue_6:
Host: amariue Host: amariue
AttachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":6}' AttachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":6}'
DetachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":6}' DetachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":6}'
NetworkScript: ip netns exec ue6 ip a show dev pdn0 NetworkScript: ip netns exec ue6 ip a show dev pdn0
CmdPrefix: ip netns exec ue6 CmdPrefix: ip netns exec ue6
MTU: 1500 MTU: 1500
amarisoft_ue_7: amarisoft_ue_7:
Host: amariue Host: amariue
AttachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":7}' AttachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":7}'
DetachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":7}' DetachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":7}'
NetworkScript: ip netns exec ue7 ip a show dev pdn0 NetworkScript: ip netns exec ue7 ip a show dev pdn0
CmdPrefix: ip netns exec ue7 CmdPrefix: ip netns exec ue7
MTU: 1500 MTU: 1500
amarisoft_ue_8: amarisoft_ue_8:
Host: amariue Host: amariue
AttachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":8}' AttachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":8}'
DetachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":8}' DetachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":8}'
NetworkScript: ip netns exec ue8 ip a show dev pdn0 NetworkScript: ip netns exec ue8 ip a show dev pdn0
CmdPrefix: ip netns exec ue8 CmdPrefix: ip netns exec ue8
MTU: 1500 MTU: 1500
amarisoft_ue_9: amarisoft_ue_9:
Host: amariue Host: amariue
AttachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":9}' AttachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":9}'
DetachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":9}' DetachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":9}'
NetworkScript: ip netns exec ue9 ip a show dev pdn0 NetworkScript: ip netns exec ue9 ip a show dev pdn0
CmdPrefix: ip netns exec ue9 CmdPrefix: ip netns exec ue9
MTU: 1500 MTU: 1500
amarisoft_ue_10: amarisoft_ue_10:
Host: amariue Host: amariue
AttachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":10}' AttachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":10}'
DetachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":10}' DetachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":10}'
NetworkScript: ip netns exec ue10 ip a show dev pdn0 NetworkScript: ip netns exec ue10 ip a show dev pdn0
CmdPrefix: ip netns exec ue10 CmdPrefix: ip netns exec ue10
MTU: 1500 MTU: 1500
amarisoft_ue_11: amarisoft_ue_11:
Host: amariue Host: amariue
AttachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":11}' AttachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":11}'
DetachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":11}' DetachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":11}'
NetworkScript: ip netns exec ue11 ip a show dev pdn0 NetworkScript: ip netns exec ue11 ip a show dev pdn0
CmdPrefix: ip netns exec ue11 CmdPrefix: ip netns exec ue11
MTU: 1500 MTU: 1500
amarisoft_ue_12: amarisoft_ue_12:
Host: amariue Host: amariue
AttachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":12}' AttachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":12}'
DetachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":12}' DetachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":12}'
NetworkScript: ip netns exec ue12 ip a show dev pdn0 NetworkScript: ip netns exec ue12 ip a show dev pdn0
CmdPrefix: ip netns exec ue12 CmdPrefix: ip netns exec ue12
MTU: 1500 MTU: 1500
amarisoft_ue_13: amarisoft_ue_13:
Host: amariue Host: amariue
AttachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":13}' AttachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":13}'
DetachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":13}' DetachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":13}'
NetworkScript: ip netns exec ue13 ip a show dev pdn0 NetworkScript: ip netns exec ue13 ip a show dev pdn0
CmdPrefix: ip netns exec ue13 CmdPrefix: ip netns exec ue13
MTU: 1500 MTU: 1500
amarisoft_ue_14: amarisoft_ue_14:
Host: amariue Host: amariue
AttachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":14}' AttachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":14}'
DetachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":14}' DetachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":14}'
NetworkScript: ip netns exec ue14 ip a show dev pdn0 NetworkScript: ip netns exec ue14 ip a show dev pdn0
CmdPrefix: ip netns exec ue14 CmdPrefix: ip netns exec ue14
MTU: 1500 MTU: 1500
amarisoft_ue_15: amarisoft_ue_15:
Host: amariue Host: amariue
AttachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":15}' AttachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":15}'
DetachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":15}' DetachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":15}'
NetworkScript: ip netns exec ue15 ip a show dev pdn0 NetworkScript: ip netns exec ue15 ip a show dev pdn0
CmdPrefix: ip netns exec ue15 CmdPrefix: ip netns exec ue15
MTU: 1500 MTU: 1500
amarisoft_ue_16: amarisoft_ue_16:
Host: amariue Host: amariue
AttachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":16}' AttachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":16}'
DetachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":16}' DetachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":16}'
NetworkScript: ip netns exec ue16 ip a show dev pdn0 NetworkScript: ip netns exec ue16 ip a show dev pdn0
CmdPrefix: ip netns exec ue16 CmdPrefix: ip netns exec ue16
MTU: 1500 MTU: 1500
@@ -308,14 +278,6 @@ oai_ue_caracal:
IF: oaitun_ue1 IF: oaitun_ue1
MTU: 1500 MTU: 1500
oai_ue_jetson2:
Host: jetson2-oai
AttachScript: 'docker start oai-nr-ue'
DetachScript: 'docker stop oai-nr-ue'
NetworkScript: ip a show dev oaitun_ue1
IF: oaitun_ue1
MTU: 1500
lte_oai_ue_carabe: lte_oai_ue_carabe:
Host: carabe Host: carabe
NetworkScript: docker exec lte-b200-ue-fdd-10Mhz-tm1 ip a show dev oaitun_ue1 NetworkScript: docker exec lte-b200-ue-fdd-10Mhz-tm1 ip a show dev oaitun_ue1
@@ -337,15 +299,6 @@ rfsim5g_ue:
AttachScript: docker start rfsim5g-oai-nr-ue AttachScript: docker start rfsim5g-oai-nr-ue
DetachScript: docker stop rfsim5g-oai-nr-ue DetachScript: docker stop rfsim5g-oai-nr-ue
MTU: 1500 MTU: 1500
# for tests with second PDU session ID 2, needs to match requested PDU session name
rfsim5g_ue_pdu_2:
Host: "%%current_host%%"
NetworkScript: docker exec rfsim5g-oai-nr-ue ip a show dev oaitun_ue1p2
CmdPrefix: docker exec rfsim5g-oai-nr-ue
IF: oaitun_ue1p2
AttachScript: docker start rfsim5g-oai-nr-ue
DetachScript: docker stop rfsim5g-oai-nr-ue
MTU: 1500
rfsim5g_ue2: rfsim5g_ue2:
Host: "%%current_host%%" Host: "%%current_host%%"
@@ -487,93 +440,3 @@ l2sim4g_ext_dn:
Host: "%%current_host%%" Host: "%%current_host%%"
NetworkScript: docker exec l2sim4g-trf-gen ip a show dev eth0 NetworkScript: docker exec l2sim4g-trf-gen ip a show dev eth0
CmdPrefix: docker exec l2sim4g-trf-gen CmdPrefix: docker exec l2sim4g-trf-gen
rfsim5g_multiue1:
Host: "%%current_host%%"
NetworkScript: docker exec rfsim5g-oai-nr-ue ip a show dev oaitun_ue1
CmdPrefix: docker exec rfsim5g-oai-nr-ue
IF: oaitun_ue1
AttachScript: docker start rfsim5g-oai-nr-ue
DetachScript: docker stop rfsim5g-oai-nr-ue
MTU: 1500
rfsim5g_multiue2:
Host: "%%current_host%%"
NetworkScript: docker exec rfsim5g-oai-nr-ue ip a show dev oaitun_ue2
CmdPrefix: docker exec rfsim5g-oai-nr-ue
IF: oaitun_ue2
AttachScript: true
DetachScript: true
MTU: 1500
rfsim5g_multiue3:
Host: "%%current_host%%"
NetworkScript: docker exec rfsim5g-oai-nr-ue ip a show dev oaitun_ue3
CmdPrefix: docker exec rfsim5g-oai-nr-ue
IF: oaitun_ue3
AttachScript: "true"
DetachScript: "true"
MTU: 1500
rfsim5g_multiue4:
Host: "%%current_host%%"
NetworkScript: docker exec rfsim5g-oai-nr-ue ip a show dev oaitun_ue4
CmdPrefix: docker exec rfsim5g-oai-nr-ue
IF: oaitun_ue4
AttachScript: "true"
DetachScript: "true"
MTU: 1500
rfsim5g_multiue5:
Host: "%%current_host%%"
NetworkScript: docker exec rfsim5g-oai-nr-ue ip a show dev oaitun_ue5
CmdPrefix: docker exec rfsim5g-oai-nr-ue
IF: oaitun_ue5
AttachScript: "true"
DetachScript: "true"
MTU: 1500
rfsim5g_multiue6:
Host: "%%current_host%%"
NetworkScript: docker exec rfsim5g-oai-nr-ue ip a show dev oaitun_ue6
CmdPrefix: docker exec rfsim5g-oai-nr-ue
IF: oaitun_ue6
AttachScript: "true"
DetachScript: "true"
MTU: 1500
rfsim5g_multiue7:
Host: "%%current_host%%"
NetworkScript: docker exec rfsim5g-oai-nr-ue ip a show dev oaitun_ue7
CmdPrefix: docker exec rfsim5g-oai-nr-ue
IF: oaitun_ue7
AttachScript: "true"
DetachScript: "true"
MTU: 1500
rfsim5g_multiue8:
Host: "%%current_host%%"
NetworkScript: docker exec rfsim5g-oai-nr-ue ip a show dev oaitun_ue8
CmdPrefix: docker exec rfsim5g-oai-nr-ue
IF: oaitun_ue8
AttachScript: "true"
DetachScript: "true"
MTU: 1500
rfsim5g_multiue9:
Host: "%%current_host%%"
NetworkScript: docker exec rfsim5g-oai-nr-ue ip a show dev oaitun_ue9
CmdPrefix: docker exec rfsim5g-oai-nr-ue
IF: oaitun_ue9
AttachScript: "true"
DetachScript: "true"
MTU: 1500
rfsim5g_multiue10:
Host: "%%current_host%%"
NetworkScript: docker exec rfsim5g-oai-nr-ue ip a show dev oaitun_ue10
CmdPrefix: docker exec rfsim5g-oai-nr-ue
IF: oaitun_ue10
AttachScript: "true"
DetachScript: "true"
MTU: 1500

View File

@@ -22,35 +22,69 @@
import re import re
import os import os
import logging
import yaml
import signal
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
import json import json
import importlib, inspect # Define the mapping of physim_test values to search patterns
PHYSIM_PATTERN_MAPPING = {
'nr_ulsim': [
r'(Total PHY proc rx)\s+(\d+\.\d+)\s+us', # Pattern for RX PHY processing time
r'(ULSCH total decoding time)\s+(\d+\.\d+)\s+us', # Pattern for ULSCH decoding time
],
'nr_dlsim': [
r'(PHY proc tx)\s+(\d+\.\d+)\s+us', # Pattern for TX PHY processing time
r'(DLSCH encoding time)\s+(\d+\.\d+)\s+us', # Pattern for DLSCH encoding time
],
'ldpctest': [
r'(Encoding time mean):\s+(\d+\.\d+)\s+us', # Pattern for encoding time mean
r'(Decoding time mean):\s+(\d+\.\d+)\s+us', # Pattern for decoding time mean
],
}
# Define test conditions based on the simulation type
PHYSIM_TEST_CONDITION = {
'nr_ulsim': 'test OK', # For nr_ulsim, check if 'test OK' is present
'nr_dlsim': 'test OK', # For nr_dlsim, check if 'test OK' is present
'ldpctest': None, # No condition for ldpctest, just process the patterns
}
class Analysis(): class Analysis():
def _get_test_description(properties): def analyze_physim(log, physim_test, options, threshold):
env_vars = None search_patterns = PHYSIM_PATTERN_MAPPING.get(physim_test)
for p in properties: test_condition = PHYSIM_TEST_CONDITION.get(physim_test)
if p["name"] == "ENVIRONMENT": success = False
env_vars = p["value"] # save for later if no custom property msg = ''
if p["name"] == "TEST_DESCRIPTION":
return p["value"]
# if we came till here, it means there is no custom test property
# saved in JSON. See if we have a description in environment variables
if not env_vars:
return "<none>"
for ev in env_vars:
name, value = ev.split("=", 1)
if name == "TEST_DESCRIPTION":
return value
return "<none>"
def analyze_physim(result_junit, details_json, logPath): try:
with open(log, 'r') as f:
log_content = f.read()
except FileNotFoundError as e:
msg = f'{log} file not found, exception: {e}'
return False, msg
except Exception as e:
msg = f'Error while parsing log file {log}: exception: {e}'
return False, msg
if test_condition and test_condition not in log_content:
msg = f"Test did not succeed, '{test_condition}' not found in log file {log}."
return False, msg
time1_match = re.search(search_patterns[0], log_content)
time2_match = re.search(search_patterns[1], log_content)
if not(time1_match and time2_match):
msg = f"Processing time not found in log file {log}."
return False, msg
success = float(time2_match.group(2)) < float(threshold)
if success:
msg = f'{time1_match.group(1)}: {time1_match.group(2)} us\n{time2_match.group(1)}: {time2_match.group(2)} us'
else:
msg = f'{time1_match.group(1)}: {time1_match.group(2)} us\n{time2_match.group(1)}: {time2_match.group(2)} us exceeds a limit of {threshold} us'
return success,msg
def analyze_oc_physim(result_junit, details_json):
try: try:
tree = ET.parse(result_junit) tree = ET.parse(result_junit)
root = tree.getroot() root = tree.getroot()
@@ -82,7 +116,7 @@ class Analysis():
for test in root: # for each test for test in root: # for each test
test_name = test.attrib["name"] test_name = test.attrib["name"]
test_exec = json_test_desc[test_name]["properties"][1]["value"][0] test_exec = json_test_desc[test_name]["properties"][1]["value"][0]
desc = Analysis._get_test_description(json_test_desc[test_name]["properties"]) desc = json_test_desc[test_name]["properties"][1]["value"][1]
# get runtime and checks # get runtime and checks
test_check = test.attrib["status"] == "run" test_check = test.attrib["status"] == "run"
time = round(float(test.attrib["time"]), 1) time = round(float(test.attrib["time"]), 1)
@@ -90,21 +124,18 @@ class Analysis():
output = test.findtext("system-out") output = test.findtext("system-out")
output_check = "exceeds the threshold" not in output output_check = "exceeds the threshold" not in output
# collect logs # collect logs
log_dir = f'{logPath}/{test_exec}' log_dir = f'../cmake_targets/log/{test_exec}'
os.makedirs(log_dir, exist_ok=True) os.makedirs(log_dir, exist_ok=True)
with open(f'{log_dir}/{test_name}.log', 'w') as f: with open(f'{log_dir}/{test_name}.log', 'w') as f:
f.write(output) f.write(output)
# prepare result and info # prepare result and info
info = f"Runtime: {f'{time:.3f}'[:5]} s"
resultstr = 'PASS' if (test_check and time_check and output_check) else 'FAIL' resultstr = 'PASS' if (test_check and time_check and output_check) else 'FAIL'
info = f"{test_name}.log: test {resultstr}"
for l in output.splitlines():
if l.startswith("CHECK "):
info += f"\n{l}"
if test_check: if test_check:
if not output_check: if not output_check:
info += "\nTest log exceeds maximal allowed length 100 kB" info += " Test log exceeds maximal allowed length 100 kB"
if not time_check: if not time_check:
info += "\nTest exceeds 150s" info += " Test exceeds 150s"
if not (time_check and output_check): if not (time_check and output_check):
nb_failed += 1 # time threshold/output length error, not counted for by ctest as of now nb_failed += 1 # time threshold/output length error, not counted for by ctest as of now
test_result[test_name] = [desc, info, resultstr] test_result[test_name] = [desc, info, resultstr]
@@ -114,134 +145,3 @@ class Analysis():
test_summary['Nbpass'] = nb_tests - nb_failed test_summary['Nbpass'] = nb_tests - nb_failed
test_summary['Nbfail'] = nb_failed test_summary['Nbfail'] = nb_failed
return nb_failed == 0, test_summary, test_result 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

View File

@@ -1,43 +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 os
from typing import NamedTuple
import logging
class TestCaseCtx(NamedTuple):
test_idx: int
logPath: str
def Default(logPath):
return TestCaseCtx(112233, logPath)
def baseFilename(self):
# typically, the test ID is of form 001234 (6 digits)
return f"{self.logPath}/{self.test_idx:06d}"
def archiveArtifact(cmd, ctx, remote_path):
base = os.path.basename(remote_path)
local = f"{ctx.baseFilename()}-{base}"
logging.info(f"Archive artifact '{local}'")
success = cmd.copyin(remote_path, local)
if success:
cmd.run(f'rm {remote_path}', silent=True)
return local if success else None

View File

@@ -34,11 +34,11 @@ import time
import os import os
import cls_oai_html import cls_oai_html
import cls_analysis
import constants as CONST import constants as CONST
import helpreadme as HELP import helpreadme as HELP
import cls_containerize import cls_containerize
import cls_cmd import cls_cmd
from cls_ci_helper import archiveArtifact
IMAGE_REGISTRY_SERVICE_NAME = "image-registry.openshift-image-registry.svc" IMAGE_REGISTRY_SERVICE_NAME = "image-registry.openshift-image-registry.svc"
NAMESPACE = "oaicicd-ran" NAMESPACE = "oaicicd-ran"
@@ -68,7 +68,9 @@ def OC_logout(cmd):
class Cluster: class Cluster:
def __init__(self): def __init__(self):
self.eNBIPAddress = ""
self.eNBSourceCodePath = "" self.eNBSourceCodePath = ""
self.forcedWorkspaceCleanup = False
self.OCUserName = "" self.OCUserName = ""
self.OCPassword = "" self.OCPassword = ""
self.OCProjectName = "" self.OCProjectName = ""
@@ -162,8 +164,27 @@ class Cluster:
return -1 return -1
return int(result.group("size")) return int(result.group("size"))
def _deploy_pod(self, filename, timeout = 120):
ret = self.cmd.run(f'oc create -f {filename}')
result = re.search(r'pod/(?P<pod>[a-zA-Z0-9_\-]+) created', ret.stdout)
if result is None:
logging.error(f'could not deploy pod: {ret.stdout}')
return None
pod = result.group("pod")
logging.debug(f'checking if pod {pod} is in Running state')
ret = self.cmd.run(f'oc wait --for=condition=ready pod {pod} --timeout={timeout}s', silent=True)
if ret.returncode == 0:
return pod
logging.error(f'pod {pod} did not reach Running state')
self._undeploy_pod(filename)
return None
def _undeploy_pod(self, filename):
self.cmd.run(f'oc delete -f {filename}')
def PullClusterImage(self, HTML, node, images, tag_prefix): def PullClusterImage(self, HTML, node, images, tag_prefix):
logging.debug(f'Pull OC image {images} to server {node}') logging.debug(f'Pull OC image {images} to server {node}')
self.testCase_id = HTML.testCase_id
with cls_cmd.getConnection(node) as cmd: with cls_cmd.getConnection(node) as cmd:
succeeded = OC_login(cmd, self.OCUserName, self.OCPassword, CI_OC_RAN_NAMESPACE) succeeded = OC_login(cmd, self.OCUserName, self.OCPassword, CI_OC_RAN_NAMESPACE)
if not succeeded: if not succeeded:
@@ -186,17 +207,13 @@ class Cluster:
HTML.CreateHtmlTestRowQueue(param, 'KO', [msg]) HTML.CreateHtmlTestRowQueue(param, 'KO', [msg])
return success return success
def _retrieveOCLog(self, ctx, job, lSourcePath, image): def BuildClusterImage(self, HTML):
fn = f'{lSourcePath}/cmake_targets/log/{image}.log'
self.cmd.run(f'oc logs {job} &> {fn}')
return (image, archiveArtifact(self.cmd, ctx, fn))
def BuildClusterImage(self, ctx, node, HTML):
if self.ranRepository == '' or self.ranBranch == '' or self.ranCommitID == '': if self.ranRepository == '' or self.ranBranch == '' or self.ranCommitID == '':
HELP.GenericHelp(CONST.Version) HELP.GenericHelp(CONST.Version)
raise ValueError(f'Insufficient Parameter: ranRepository {self.ranRepository} ranBranch {ranBranch} ranCommitID {self.ranCommitID}') raise ValueError(f'Insufficient Parameter: ranRepository {self.ranRepository} ranBranch {ranBranch} ranCommitID {self.ranCommitID}')
lIpAddr = self.eNBIPAddress
lSourcePath = self.eNBSourceCodePath lSourcePath = self.eNBSourceCodePath
if node == '' or lSourcePath == '': if lIpAddr == '' or lSourcePath == '':
raise ValueError('Insufficient Parameter: eNBSourceCodePath missing') raise ValueError('Insufficient Parameter: eNBSourceCodePath missing')
ocUserName = self.OCUserName ocUserName = self.OCUserName
ocPassword = self.OCPassword ocPassword = self.OCPassword
@@ -207,8 +224,10 @@ class Cluster:
if self.OCRegistry.startswith("http") or self.OCRegistry.endswith("/"): if self.OCRegistry.startswith("http") or self.OCRegistry.endswith("/"):
raise ValueError(f'ocRegistry {self.OCRegistry} should not start with http:// or https:// and not end on a slash /') raise ValueError(f'ocRegistry {self.OCRegistry} should not start with http:// or https:// and not end on a slash /')
logging.debug(f'Building on cluster triggered from server: {node}') logging.debug(f'Building on cluster triggered from server: {lIpAddr}')
self.cmd = cls_cmd.RemoteCmd(node) self.cmd = cls_cmd.RemoteCmd(lIpAddr)
self.testCase_id = HTML.testCase_id
# Workaround for some servers, we need to erase completely the workspace # Workaround for some servers, we need to erase completely the workspace
self.cmd.cd(lSourcePath) self.cmd.cd(lSourcePath)
@@ -261,45 +280,124 @@ class Cluster:
self._recreate_entitlements() self._recreate_entitlements()
status = True # flag to abandon compiling if any image fails status = True # flag to abandon compiling if any image fails
log_files = [] attemptedImages = []
build_metrics = f"{lSourcePath}/cmake_targets/log/build-metrics.log"
if forceBaseImageBuild: if forceBaseImageBuild:
self._recreate_is_tag('ran-base', baseTag, 'openshift/ran-base-is.yaml') self._recreate_is_tag('ran-base', baseTag, 'openshift/ran-base-is.yaml')
self._recreate_bc('ran-base', baseTag, 'openshift/ran-base-bc.yaml') self._recreate_bc('ran-base', baseTag, 'openshift/ran-base-bc.yaml')
ranbase_job = self._start_build('ran-base') ranbase_job = self._start_build('ran-base')
attemptedImages += ['ran-base']
status = ranbase_job is not None and self._wait_build_end([ranbase_job], 1000) status = ranbase_job is not None and self._wait_build_end([ranbase_job], 1000)
if not status: logging.error('failure during build of ran-base') if not status: logging.error('failure during build of ran-base')
log_files.append(self._retrieveOCLog(ctx, ranbase_job, lSourcePath, 'ran-base')) self.cmd.run(f'oc logs {ranbase_job} &> cmake_targets/log/ran-base.log') # cannot use cmd.run because of redirect
# recover logs by mounting image
self._retag_image_statement('ran-base', 'ran-base', baseTag, 'openshift/ran-base-log-retrieval.yaml')
pod = self._deploy_pod('openshift/ran-base-log-retrieval.yaml')
if pod is not None:
self.cmd.run(f'mkdir -p cmake_targets/log/ran-base')
self.cmd.run(f'oc rsync {pod}:/oai-ran/cmake_targets/log/ cmake_targets/log/ran-base')
self._undeploy_pod('openshift/ran-base-log-retrieval.yaml')
else:
status = False
if status:
self._recreate_is_tag('oai-physim', imageTag, 'openshift/oai-physim-is.yaml')
self._recreate_bc('oai-physim', imageTag, 'openshift/oai-physim-bc.yaml')
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.phySim.rhel9')
physim_job = self._start_build('oai-physim')
attemptedImages += ['oai-physim']
self._recreate_is_tag('ran-build', imageTag, 'openshift/ran-build-is.yaml')
self._recreate_bc('ran-build', imageTag, 'openshift/ran-build-bc.yaml')
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.build.rhel9')
ranbuild_job = self._start_build('ran-build')
attemptedImages += ['ran-build']
self._recreate_is_tag('oai-clang', imageTag, 'openshift/oai-clang-is.yaml')
self._recreate_bc('oai-clang', imageTag, 'openshift/oai-clang-bc.yaml')
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.clang.rhel9')
clang_job = self._start_build('oai-clang')
attemptedImages += ['oai-clang']
wait = ranbuild_job is not None and physim_job is not None and clang_job is not None and self._wait_build_end([ranbuild_job, physim_job, clang_job], 1200)
if not wait: logging.error('error during build of ranbuild_job or physim_job or clang_job')
status = status and wait
self.cmd.run(f'oc logs {ranbuild_job} &> cmake_targets/log/ran-build.log')
self.cmd.run(f'oc logs {physim_job} &> cmake_targets/log/oai-physim.log')
self.cmd.run(f'oc logs {clang_job} &> cmake_targets/log/oai-clang.log')
self.cmd.run(f'oc get pods.metrics.k8s.io &>> cmake_targets/log/build-metrics.log')
if status:
self._recreate_is_tag('oai-enb', imageTag, 'openshift/oai-enb-is.yaml')
self._recreate_bc('oai-enb', imageTag, 'openshift/oai-enb-bc.yaml')
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.eNB.rhel9')
self._retag_image_statement('ran-build', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-build', imageTag, 'docker/Dockerfile.eNB.rhel9')
enb_job = self._start_build('oai-enb')
attemptedImages += ['oai-enb']
self._recreate_is_tag('oai-gnb', imageTag, 'openshift/oai-gnb-is.yaml')
self._recreate_bc('oai-gnb', imageTag, 'openshift/oai-gnb-bc.yaml')
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.gNB.rhel9')
self._retag_image_statement('ran-build', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-build', imageTag, 'docker/Dockerfile.gNB.rhel9')
gnb_job = self._start_build('oai-gnb')
attemptedImages += ['oai-gnb']
self._recreate_is_tag('oai-gnb-aw2s', imageTag, 'openshift/oai-gnb-aw2s-is.yaml')
self._recreate_bc('oai-gnb-aw2s', imageTag, 'openshift/oai-gnb-aw2s-bc.yaml')
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.gNB.aw2s.rhel9')
self._retag_image_statement('ran-build', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-build', imageTag, 'docker/Dockerfile.gNB.aw2s.rhel9')
gnb_aw2s_job = self._start_build('oai-gnb-aw2s')
attemptedImages += ['oai-gnb-aw2s']
wait = enb_job is not None and gnb_job is not None and gnb_aw2s_job is not None and self._wait_build_end([enb_job, gnb_job, gnb_aw2s_job], 800)
if not wait: logging.error('error during build of eNB/gNB')
status = status and wait
# recover logs
self.cmd.run(f'oc logs {enb_job} &> cmake_targets/log/oai-enb.log')
self.cmd.run(f'oc logs {gnb_job} &> cmake_targets/log/oai-gnb.log')
self.cmd.run(f'oc logs {gnb_aw2s_job} &> cmake_targets/log/oai-gnb-aw2s.log')
self._recreate_is_tag('oai-nr-cuup', imageTag, 'openshift/oai-nr-cuup-is.yaml')
self._recreate_bc('oai-nr-cuup', imageTag, 'openshift/oai-nr-cuup-bc.yaml')
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.nr-cuup.rhel9')
self._retag_image_statement('ran-build', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-build', imageTag, 'docker/Dockerfile.nr-cuup.rhel9')
nr_cuup_job = self._start_build('oai-nr-cuup')
attemptedImages += ['oai-nr-cuup']
self._recreate_is_tag('oai-lte-ue', imageTag, 'openshift/oai-lte-ue-is.yaml')
self._recreate_bc('oai-lte-ue', imageTag, 'openshift/oai-lte-ue-bc.yaml')
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.lteUE.rhel9')
self._retag_image_statement('ran-build', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-build', imageTag, 'docker/Dockerfile.lteUE.rhel9')
lteue_job = self._start_build('oai-lte-ue')
attemptedImages += ['oai-lte-ue']
self._recreate_is_tag('oai-nr-ue', imageTag, 'openshift/oai-nr-ue-is.yaml')
self._recreate_bc('oai-nr-ue', imageTag, 'openshift/oai-nr-ue-bc.yaml')
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.nrUE.rhel9')
self._retag_image_statement('ran-build', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-build', imageTag, 'docker/Dockerfile.nrUE.rhel9')
nrue_job = self._start_build('oai-nr-ue')
attemptedImages += ['oai-nr-ue']
wait = nr_cuup_job is not None and lteue_job is not None and nrue_job is not None and self._wait_build_end([nr_cuup_job, lteue_job, nrue_job], 800)
if not wait: logging.error('error during build of nr-cuup/lteUE/nrUE')
status = status and wait
# recover logs
self.cmd.run(f'oc logs {nr_cuup_job} &> cmake_targets/log/oai-nr-cuup.log')
self.cmd.run(f'oc logs {lteue_job} &> cmake_targets/log/oai-lte-ue.log')
self.cmd.run(f'oc logs {nrue_job} &> cmake_targets/log/oai-nr-ue.log')
self.cmd.run(f'oc get pods.metrics.k8s.io &>> cmake_targets/log/build-metrics.log')
if status: if status:
self._recreate_is_tag('ran-build-fhi72', imageTag, 'openshift/ran-build-fhi72-is.yaml') self._recreate_is_tag('ran-build-fhi72', imageTag, 'openshift/ran-build-fhi72-is.yaml')
self._recreate_bc('ran-build-fhi72', imageTag, 'openshift/ran-build-fhi72-bc.yaml') self._recreate_bc('ran-build-fhi72', imageTag, 'openshift/ran-build-fhi72-bc.yaml')
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.build.fhi72.rhel9') self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.build.fhi72.rhel9')
ranbuildfhi72_job = self._start_build('ran-build-fhi72') ranbuildfhi72_job = self._start_build('ran-build-fhi72')
attemptedImages += ['ran-build-fhi72']
self._recreate_is_tag('oai-physim', imageTag, 'openshift/oai-physim-is.yaml') wait = ranbuildfhi72_job is not None and self._wait_build_end([ranbuildfhi72_job], 1200)
self._recreate_bc('oai-physim', imageTag, 'openshift/oai-physim-bc.yaml') if not wait: logging.error('error during build of ranbuildfhi72_job')
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.phySim.rhel9')
physim_job = self._start_build('oai-physim')
self._recreate_is_tag('ran-build', imageTag, 'openshift/ran-build-is.yaml')
self._recreate_bc('ran-build', imageTag, 'openshift/ran-build-bc.yaml')
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.build.rhel9')
ranbuild_job = self._start_build('ran-build')
self._recreate_is_tag('oai-clang', imageTag, 'openshift/oai-clang-is.yaml')
self._recreate_bc('oai-clang', imageTag, 'openshift/oai-clang-bc.yaml')
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.clang.rhel9')
clang_job = self._start_build('oai-clang')
wait = ranbuildfhi72_job is not None and ranbuild_job is not None and physim_job is not None and clang_job is not None and self._wait_build_end([ranbuildfhi72_job, ranbuild_job, physim_job, clang_job], 1200)
if not wait: logging.error('error during build of ranbuildfhi72_job or ranbuild_job or physim_job or clang_job')
status = status and wait status = status and wait
log_files.append(self._retrieveOCLog(ctx, ranbuildfhi72_job, lSourcePath, 'ran-build-fhi72')) self.cmd.run(f'oc logs {ranbuildfhi72_job} &> cmake_targets/log/ran-build-fhi72.log')
log_files.append(self._retrieveOCLog(ctx, ranbuild_job, lSourcePath, 'ran-build')) self.cmd.run(f'oc get pods.metrics.k8s.io &>> cmake_targets/log/build-metrics.log')
log_files.append(self._retrieveOCLog(ctx, physim_job, lSourcePath, 'oai-physim'))
log_files.append(self._retrieveOCLog(ctx, clang_job, lSourcePath, 'oai-clang'))
self.cmd.run(f'oc get pods.metrics.k8s.io &>> {build_metrics}')
if status: if status:
self._recreate_is_tag('oai-gnb-fhi72', imageTag, 'openshift/oai-gnb-fhi72-is.yaml') self._recreate_is_tag('oai-gnb-fhi72', imageTag, 'openshift/oai-gnb-fhi72-is.yaml')
@@ -307,65 +405,19 @@ class Cluster:
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.gNB.fhi72.rhel9') self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.gNB.fhi72.rhel9')
self._retag_image_statement('ran-build-fhi72', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-build-fhi72', imageTag, 'docker/Dockerfile.gNB.fhi72.rhel9') self._retag_image_statement('ran-build-fhi72', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-build-fhi72', imageTag, 'docker/Dockerfile.gNB.fhi72.rhel9')
gnb_fhi72_job = self._start_build('oai-gnb-fhi72') gnb_fhi72_job = self._start_build('oai-gnb-fhi72')
attemptedImages += ['oai-gnb-fhi72']
self._recreate_is_tag('oai-enb', imageTag, 'openshift/oai-enb-is.yaml') wait = gnb_fhi72_job is not None and self._wait_build_end([gnb_fhi72_job], 600)
self._recreate_bc('oai-enb', imageTag, 'openshift/oai-enb-bc.yaml') if not wait: logging.error('error during build of gNB-fhi72')
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.eNB.rhel9')
self._retag_image_statement('ran-build', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-build', imageTag, 'docker/Dockerfile.eNB.rhel9')
enb_job = self._start_build('oai-enb')
self._recreate_is_tag('oai-gnb', imageTag, 'openshift/oai-gnb-is.yaml')
self._recreate_bc('oai-gnb', imageTag, 'openshift/oai-gnb-bc.yaml')
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.gNB.rhel9')
self._retag_image_statement('ran-build', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-build', imageTag, 'docker/Dockerfile.gNB.rhel9')
gnb_job = self._start_build('oai-gnb')
self._recreate_is_tag('oai-gnb-aw2s', imageTag, 'openshift/oai-gnb-aw2s-is.yaml')
self._recreate_bc('oai-gnb-aw2s', imageTag, 'openshift/oai-gnb-aw2s-bc.yaml')
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.gNB.aw2s.rhel9')
self._retag_image_statement('ran-build', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-build', imageTag, 'docker/Dockerfile.gNB.aw2s.rhel9')
gnb_aw2s_job = self._start_build('oai-gnb-aw2s')
wait = gnb_fhi72_job is not None and enb_job is not None and gnb_job is not None and gnb_aw2s_job is not None and self._wait_build_end([gnb_fhi72_job, enb_job, gnb_job, gnb_aw2s_job], 800)
if not wait: logging.error('error during build of eNB/gNB')
status = status and wait status = status and wait
# recover logs # recover logs
log_files.append(self._retrieveOCLog(ctx, gnb_fhi72_job, lSourcePath, 'oai-gnb-fhi72')) self.cmd.run(f'oc logs {gnb_fhi72_job} &> cmake_targets/log/oai-gnb-fhi72.log')
log_files.append(self._retrieveOCLog(ctx, enb_job, lSourcePath, 'oai-enb')) self.cmd.run(f'oc get pods.metrics.k8s.io &>> cmake_targets/log/build-metrics.log')
log_files.append(self._retrieveOCLog(ctx, gnb_job, lSourcePath, 'oai-gnb'))
log_files.append(self._retrieveOCLog(ctx, gnb_aw2s_job, lSourcePath, 'oai-gnb-aw2s'))
self.cmd.run(f'oc get pods.metrics.k8s.io &>> {build_metrics}')
self._recreate_is_tag('oai-nr-cuup', imageTag, 'openshift/oai-nr-cuup-is.yaml')
self._recreate_bc('oai-nr-cuup', imageTag, 'openshift/oai-nr-cuup-bc.yaml')
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.nr-cuup.rhel9')
self._retag_image_statement('ran-build', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-build', imageTag, 'docker/Dockerfile.nr-cuup.rhel9')
nr_cuup_job = self._start_build('oai-nr-cuup')
self._recreate_is_tag('oai-lte-ue', imageTag, 'openshift/oai-lte-ue-is.yaml')
self._recreate_bc('oai-lte-ue', imageTag, 'openshift/oai-lte-ue-bc.yaml')
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.lteUE.rhel9')
self._retag_image_statement('ran-build', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-build', imageTag, 'docker/Dockerfile.lteUE.rhel9')
lteue_job = self._start_build('oai-lte-ue')
self._recreate_is_tag('oai-nr-ue', imageTag, 'openshift/oai-nr-ue-is.yaml')
self._recreate_bc('oai-nr-ue', imageTag, 'openshift/oai-nr-ue-bc.yaml')
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.nrUE.rhel9')
self._retag_image_statement('ran-build', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-build', imageTag, 'docker/Dockerfile.nrUE.rhel9')
nrue_job = self._start_build('oai-nr-ue')
wait = nr_cuup_job is not None and lteue_job is not None and nrue_job is not None and self._wait_build_end([nr_cuup_job, lteue_job, nrue_job], 800)
if not wait: logging.error('error during build of nr-cuup/lteUE/nrUE')
status = status and wait
# recover logs
log_files.append(self._retrieveOCLog(ctx, nr_cuup_job, lSourcePath, 'oai-nr-cuup'))
log_files.append(self._retrieveOCLog(ctx, lteue_job, lSourcePath, 'oai-lte-ue'))
log_files.append(self._retrieveOCLog(ctx, nrue_job, lSourcePath, 'oai-nr-ue'))
self.cmd.run(f'oc get pods.metrics.k8s.io &>> {build_metrics}')
# split and analyze logs # split and analyze logs
imageSize = {} imageSize = {}
for image, _ in log_files: for image in attemptedImages:
self.cmd.run(f'mkdir -p cmake_targets/log/{image}')
tag = imageTag if image != 'ran-base' else baseTag tag = imageTag if image != 'ran-base' else baseTag
size = self._get_image_size(image, tag) size = self._get_image_size(image, tag)
if size <= 0: if size <= 0:
@@ -376,14 +428,12 @@ class Cluster:
imageSize[image] = f'{sizeMb:.1f} Mbytes (uncompressed: ~{sizeMb*2.5:.1f} Mbytes)' imageSize[image] = f'{sizeMb:.1f} Mbytes (uncompressed: ~{sizeMb*2.5:.1f} Mbytes)'
logging.info(f'\u001B[1m{image} size is {imageSize[image]}\u001B[0m') logging.info(f'\u001B[1m{image} size is {imageSize[image]}\u001B[0m')
archiveArtifact(self.cmd, ctx, build_metrics) grep_exp = r"\|".join(attemptedImages)
logfile = f'{lSourcePath}/cmake_targets/log/image_registry.log' self.cmd.run(f'oc get images | grep -e \'{grep_exp}\' &> cmake_targets/log/image_registry.log');
grep_exp = r"\|".join([i for i,f in log_files]) self.cmd.run(f'for pod in $(oc get pods | tail -n +2 | awk \'{{print $1}}\'); do oc get pod $pod -o json &>> cmake_targets/log/build_pod_summary.log; done')
self.cmd.run(f'oc get images | grep -e \'{grep_exp}\' &> {logfile}');
archiveArtifact(self.cmd, ctx, logfile) build_log_name = f'build_log_{self.testCase_id}'
logfile = f'{lSourcePath}/cmake_targets/log/build_pod_summary.log' cls_containerize.CopyLogsToExecutor(self.cmd, lSourcePath, build_log_name)
self.cmd.run(f'for pod in $(oc get pods | tail -n +2 | awk \'{{print $1}}\'); do oc get pod $pod -o json &>> {logfile}; done')
archiveArtifact(self.cmd, ctx, logfile)
self.cmd.run('for pod in $(oc get pods | tail -n +2 | awk \'{print $1}\'); do oc delete pod ${pod}; done') self.cmd.run('for pod in $(oc get pods | tail -n +2 | awk \'{print $1}\'); do oc delete pod ${pod}; done')
@@ -392,24 +442,55 @@ class Cluster:
self.cmd.close() self.cmd.close()
# Analyze the logs # Analyze the logs
collectInfo = {} collectInfo = cls_containerize.AnalyzeBuildLogs(build_log_name, attemptedImages, status)
for image, lf in log_files: for img in collectInfo:
imgStatus, errors = cls_containerize.AnalyzeBuildLogs(image, lf) for f in collectInfo[img]:
info = f"Analysis of {os.path.basename(lf)}: {imgStatus=}, size {imageSize[image]}, {len(errors)} errors" status = status and collectInfo[img][f]['status']
msg = "\n".join([info] + errors) if not status:
HTML.CreateHtmlTestRowQueue(image, 'OK' if imgStatus else 'KO', [msg]) logging.debug(collectInfo)
status = status and imgStatus
if status: if status:
logging.info('\u001B[1m Building OAI Image(s) Pass\u001B[0m') logging.info('\u001B[1m Building OAI Image(s) Pass\u001B[0m')
HTML.CreateHtmlTestRow('all', 'OK', CONST.ALL_PROCESSES_OK)
else: else:
logging.error('\u001B[1m Building OAI Images Failed\u001B[0m') logging.error('\u001B[1m Building OAI Images Failed\u001B[0m')
HTML.CreateHtmlTestRow('all', 'KO', CONST.ALL_PROCESSES_OK)
# TODO fix groovy script, remove the following. HTML.CreateHtmlNextTabHeaderTestRow(collectInfo, imageSize)
# 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}/')
return status return status
def deploy_oc_physim(self, HTML, oc_release, svr_id):
if self.ranRepository == '' or self.ranBranch == '' or self.ranCommitID == '':
HELP.GenericHelp(CONST.Version)
raise ValueError(f'Insufficient Parameter: ranRepository {self.ranRepository} ranBranch {self.ranBranch} ranCommitID {self.ranCommitID}')
image_tag = cls_containerize.CreateTag(self.ranCommitID, self.ranBranch, self.ranAllowMerge)
logging.debug(f'Running physims from server: {svr_id}')
script = "scripts/oc-deploy-physims.sh"
options = f"oaicicd-core-for-ci-ran {oc_release} {image_tag} {self.eNBSourceCodePath}"
ret = cls_cmd.runScript(svr_id, script, 600, options)
logging.debug(f'"{script}" finished with code {ret.returncode}, output:\n{ret.stdout}')
log_dir = f'{os.getcwd()}/../cmake_targets/log'
os.makedirs(log_dir, exist_ok=True)
result_junit = f'{oc_release}-run.xml'
details_json = f'{oc_release}-tests.json'
with cls_cmd.getConnection(svr_id) as ssh:
ssh.copyin(src=f'{self.eNBSourceCodePath}/ci-scripts/{details_json}', tgt=f'{log_dir}/{details_json}')
ssh.copyin(src=f'{self.eNBSourceCodePath}/ci-scripts/{result_junit}', tgt=f'{log_dir}/{result_junit}')
ssh.copyin(src=f'{self.eNBSourceCodePath}/ci-scripts/physim_log.txt', tgt=f'{log_dir}/physim_log.txt')
ssh.copyin(src=f'{self.eNBSourceCodePath}/ci-scripts/physim_pods_summary.txt', tgt=f'{log_dir}/physim_pods_summary.txt')
ssh.copyin(src=f'{self.eNBSourceCodePath}/ci-scripts/LastTestsFailed.log', tgt=f'{log_dir}/LastTestsFailed.log')
test_status, test_summary, test_result = cls_analysis.Analysis.analyze_oc_physim(f'{log_dir}/{result_junit}', f'{log_dir}/{details_json}')
if test_summary:
if test_status:
HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK)
HTML.CreateHtmlTestRowPhySimTestResult(test_summary, test_result)
logging.info('\u001B[1m Physical Simulator Pass\u001B[0m')
else:
HTML.CreateHtmlTestRow('Some test(s) failed!', 'KO', CONST.OC_PHYSIM_DEPLOY_FAIL)
HTML.CreateHtmlTestRowPhySimTestResult(test_summary, test_result)
logging.error('\u001B[1m Physical Simulator Fail\u001B[0m')
else:
HTML.CreateHtmlTestRowQueue('Physical simulator failed', 'KO', [test_result])
logging.error('\u001B[1m Physical Simulator Fail\u001B[0m')
return test_status

View File

@@ -45,6 +45,12 @@ def getConnection(host, d=None):
else: else:
return RemoteCmd(host, d=d) return RemoteCmd(host, d=d)
def runScript(host, path, timeout, parameters=None, redirect=None, silent=False):
if is_local(host):
return LocalCmd.exec_script(path, timeout, parameters, redirect, silent)
else:
return RemoteCmd.exec_script(host, path, timeout, parameters, redirect, silent)
# provides a partial interface for the legacy SSHconnection class (getBefore(), command()) # provides a partial interface for the legacy SSHconnection class (getBefore(), command())
class Cmd(metaclass=abc.ABCMeta): class Cmd(metaclass=abc.ABCMeta):
def cd(self, d, silent=False): def cd(self, d, silent=False):
@@ -105,12 +111,12 @@ class LocalCmd(Cmd):
logging.debug(f'Working dir is {self.cwd}') logging.debug(f'Working dir is {self.cwd}')
self.cp = sp.CompletedProcess(args='', returncode=0, stdout='') self.cp = sp.CompletedProcess(args='', returncode=0, stdout='')
def exec_script(self, path, timeout, parameters=None, redirect=None, silent=False): def exec_script(path, timeout, parameters=None, redirect=None, silent=False):
if redirect and not redirect.startswith("/"): if redirect and not redirect.startswith("/"):
raise ValueError(f"redirect must be absolute, but is {redirect}") raise ValueError(f"redirect must be absolute, but is {redirect}")
c = f"{path} {parameters}" if parameters else path c = f"{path} {parameters}" if parameters else path
if not redirect: if not redirect:
ret = sp.run(c, shell=True, cwd=self.cwd, timeout=timeout, stdout=sp.PIPE, stderr=sp.STDOUT) ret = sp.run(c, shell=True, timeout=timeout, stdout=sp.PIPE, stderr=sp.STDOUT)
ret.stdout = ret.stdout.decode('utf-8').strip() ret.stdout = ret.stdout.decode('utf-8').strip()
else: else:
with open(redirect, "w") as f: with open(redirect, "w") as f:
@@ -232,15 +238,18 @@ class RemoteCmd(Cmd):
cfg['sock'] = paramiko.ProxyCommand(ucfg['proxycommand']) cfg['sock'] = paramiko.ProxyCommand(ucfg['proxycommand'])
return cfg return cfg
def exec_script(self, path, timeout, parameters=None, redirect=None, silent=False): def exec_script(host, path, timeout, parameters=None, redirect=None, silent=False):
if redirect and not redirect.startswith("/"): if redirect and not redirect.startswith("/"):
raise ValueError(f"redirect must be absolute, but is {redirect}") raise ValueError(f"redirect must be absolute, but is {redirect}")
p = parameters if parameters else "" p = parameters if parameters else ""
r = f"> {redirect}" if redirect else "" r = f"> {redirect}" if redirect else ""
if not silent: if not silent:
logging.debug(f"local> ssh {self.hostname} bash -s {p} < {path} {r}") logging.debug(f"local> ssh {host} bash -s {p} < {path} {r} # {path} from localhost")
client = RemoteCmd._ssh_init()
cfg = RemoteCmd._lookup_ssh_config(host)
client.connect(**cfg)
bash_opt = 'BASH_XTRACEFD=1' # write bash set -x output to stdout, see bash(1) bash_opt = 'BASH_XTRACEFD=1' # write bash set -x output to stdout, see bash(1)
stdin, stdout, stderr = self.client.exec_command(f"{bash_opt} bash -s {p} {r}", timeout=timeout) stdin, stdout, stderr = client.exec_command(f"{bash_opt} bash -s {p} {r}", timeout=timeout)
# open() the file f at path, read() it and write() it into the stdin of the bash -s cmd # open() the file f at path, read() it and write() it into the stdin of the bash -s cmd
with open(path) as f: with open(path) as f:
stdin.write(f.read()) stdin.write(f.read())
@@ -250,6 +259,7 @@ class RemoteCmd(Cmd):
if redirect: cmd += f" &> {redirect}" if redirect: cmd += f" &> {redirect}"
ret = sp.CompletedProcess(args=cmd, returncode=stdout.channel.recv_exit_status(), stdout=stdout.read(size=None) + stderr.read(size=None)) ret = sp.CompletedProcess(args=cmd, returncode=stdout.channel.recv_exit_status(), stdout=stdout.read(size=None) + stderr.read(size=None))
ret.stdout = ret.stdout.decode('utf-8').strip() ret.stdout = ret.stdout.decode('utf-8').strip()
client.close()
return ret return ret
def run(self, line, timeout=300, silent=False, reportNonZero=True): def run(self, line, timeout=300, silent=False, reportNonZero=True):

View File

@@ -31,24 +31,27 @@
#----------------------------------------------------------- #-----------------------------------------------------------
# Import # Import
#----------------------------------------------------------- #-----------------------------------------------------------
import sys # arg
import re # reg import re # reg
import logging import logging
import os import os
import shutil
import time
from zipfile import ZipFile
#----------------------------------------------------------- #-----------------------------------------------------------
# OAI Testing modules # OAI Testing modules
#----------------------------------------------------------- #-----------------------------------------------------------
import cls_cmd import cls_cmd
import helpreadme as HELP
import constants as CONST import constants as CONST
import cls_analysis import cls_oaicitest
from cls_ci_helper import archiveArtifact
#----------------------------------------------------------- #-----------------------------------------------------------
# Helper functions used here and in other classes # Helper functions used here and in other classes
# (e.g., cls_cluster.py) # (e.g., cls_cluster.py)
#----------------------------------------------------------- #-----------------------------------------------------------
IMAGES = ['oai-enb', 'oai-lte-ru', 'oai-lte-ue', 'oai-gnb', 'oai-nr-cuup', 'oai-gnb-aw2s', 'oai-nr-ue', 'oai-enb-asan', 'oai-gnb-asan', 'oai-lte-ue-asan', 'oai-nr-ue-asan', 'oai-nr-cuup-asan', 'oai-gnb-aerial', 'oai-gnb-fhi72'] IMAGES = ['oai-enb', 'oai-lte-ru', 'oai-lte-ue', 'oai-gnb', 'oai-nr-cuup', 'oai-gnb-aw2s', 'oai-nr-ue', 'oai-enb-asan', 'oai-gnb-asan', 'oai-lte-ue-asan', 'oai-nr-ue-asan', 'oai-nr-cuup-asan', 'oai-gnb-aerial', 'oai-gnb-fhi72']
DEFAULT_REGISTRY = "gracehopper3-oai.sboai.cs.eurecom.fr"
def CreateWorkspace(host, sourcePath, ranRepository, ranCommitID, ranTargetBranch, ranAllowMerge): def CreateWorkspace(host, sourcePath, ranRepository, ranCommitID, ranTargetBranch, ranAllowMerge):
if ranCommitID == '': if ranCommitID == '':
@@ -62,8 +65,7 @@ def CreateWorkspace(host, sourcePath, ranRepository, ranCommitID, ranTargetBranc
ranTargetBranch = 'develop' ranTargetBranch = 'develop'
options += f" {ranTargetBranch}" options += f" {ranTargetBranch}"
logging.info(f'execute "{script}" with options "{options}" on node {host}') logging.info(f'execute "{script}" with options "{options}" on node {host}')
with cls_cmd.getConnection(host) as c: ret = cls_cmd.runScript(host, script, 90, options)
ret = c.exec_script(script, 90, options)
logging.debug(f'"{script}" finished with code {ret.returncode}, output:\n{ret.stdout}') logging.debug(f'"{script}" finished with code {ret.returncode}, output:\n{ret.stdout}')
return ret.returncode == 0 return ret.returncode == 0
@@ -79,25 +81,69 @@ def CreateTag(ranCommitID, ranBranch, ranAllowMerge):
tagToUse = f'develop-{shortCommit}' tagToUse = f'develop-{shortCommit}'
return tagToUse return tagToUse
def AnalyzeBuildLogs(image, lf): def CopyLogsToExecutor(cmd, sourcePath, log_name):
committed = False cmd.cd(f'{sourcePath}/cmake_targets')
tagged = False cmd.run(f'rm -f {log_name}.zip')
errors = [] cmd.run(f'mkdir -p {log_name}')
with open(lf, mode='r') as inputfile: cmd.run(f'mv log/* {log_name}')
for line in inputfile: cmd.run(f'zip -r -qq {log_name}.zip {log_name}')
lineHasTag = re.search(f'Successfully tagged {image}:', str(line)) is not None
lineHasTag2 = re.search(f'naming to docker.io/library/{image}:', str(line)) is not None # copy zip to executor for analysis
tagged = tagged or lineHasTag or lineHasTag2 if (os.path.isfile(f'./{log_name}.zip')):
# the OpenShift Cluster builder prepends image registry URL os.remove(f'./{log_name}.zip')
lineHasCommit = re.search(r'COMMIT [a-zA-Z0-9\.:/\-]*' + image, str(line)) is not None if (os.path.isdir(f'./{log_name}')):
committed = committed or lineHasCommit shutil.rmtree(f'./{log_name}')
if re.search(r'error:|Errors|ERROR', line): cmd.copyin(src=f'{sourcePath}/cmake_targets/{log_name}.zip', tgt=f'{os.getcwd()}/{log_name}.zip')
errors.append(f"=> {line.strip()}") cmd.run(f'rm -f {log_name}.zip')
status = (committed or tagged) and len(errors) == 0 ZipFile(f'{log_name}.zip').extractall('.')
logging.info(f"Analyzing {image}, file {lf}: {status=}, {len(errors)} errors")
for e in errors: def AnalyzeBuildLogs(buildRoot, images, globalStatus):
logging.info(e) collectInfo = {}
return status, errors for image in images:
files = {}
file_list = [f for f in os.listdir(f'{buildRoot}/{image}') if os.path.isfile(os.path.join(f'{buildRoot}/{image}', f)) and f.endswith('.txt')]
# Analyze the "sub-logs" of every target image
for fil in file_list:
errorandwarnings = {}
warningsNo = 0
errorsNo = 0
with open(f'{buildRoot}/{image}/{fil}', mode='r') as inputfile:
for line in inputfile:
result = re.search(' ERROR ', str(line))
if result is not None:
errorsNo += 1
result = re.search(' error:', str(line))
if result is not None:
errorsNo += 1
result = re.search(' WARNING ', str(line))
if result is not None:
warningsNo += 1
result = re.search(' warning:', str(line))
if result is not None:
warningsNo += 1
errorandwarnings['errors'] = errorsNo
errorandwarnings['warnings'] = warningsNo
errorandwarnings['status'] = globalStatus
files[fil] = errorandwarnings
# Analyze the target image
if os.path.isfile(f'{buildRoot}/{image}.log'):
errorandwarnings = {}
committed = False
tagged = False
with open(f'{buildRoot}/{image}.log', mode='r') as inputfile:
for line in inputfile:
lineHasTag = re.search(f'Successfully tagged {image}:', str(line)) is not None
lineHasTag2 = re.search(f'naming to docker.io/library/{image}:', str(line)) is not None
tagged = tagged or lineHasTag or lineHasTag2
# the OpenShift Cluster builder prepends image registry URL
lineHasCommit = re.search(f'COMMIT [a-zA-Z0-9\.:/\-]*{image}', str(line)) is not None
committed = committed or lineHasCommit
errorandwarnings['errors'] = 0 if committed or tagged else 1
errorandwarnings['warnings'] = 0
errorandwarnings['status'] = committed or tagged
files['Target Image Creation'] = errorandwarnings
collectInfo[image] = files
return collectInfo
def GetImageName(ssh, svcName, file): def GetImageName(ssh, svcName, file):
ret = ssh.run(f"docker compose -f {file} config --format json {svcName} | jq -r '.services.\"{svcName}\".image'", silent=True) ret = ssh.run(f"docker compose -f {file} config --format json {svcName} | jq -r '.services.\"{svcName}\".image'", silent=True)
@@ -106,6 +152,19 @@ def GetImageName(ssh, svcName, file):
else: else:
return ret.stdout.strip() return ret.stdout.strip()
def GetServiceHealth(ssh, svcName, file):
if svcName is None:
return False, f"Service {svcName} not found in {file}"
image = GetImageName(ssh, svcName, file)
if 'db_init' in svcName or 'db-init' in svcName: # exits with 0, there cannot be healthy
return True, f"Service {svcName} healthy, image {image}"
for _ in range(8):
result = ssh.run(f"docker compose -f {file} ps --format json {svcName} | jq -r 'if type==\"array\" then .[0].Health else .Health end'", silent=True)
if result.stdout == 'healthy':
return True, f"Service {svcName} healthy, image {image}"
time.sleep(5)
return False, f"Failed to deploy: service {svcName}"
def ExistEnvFilePrint(ssh, wd, prompt='env vars in existing'): def ExistEnvFilePrint(ssh, wd, prompt='env vars in existing'):
ret = ssh.run(f'cat {wd}/.env', silent=True, reportNonZero=False) ret = ssh.run(f'cat {wd}/.env', silent=True, reportNonZero=False)
if ret.returncode != 0: if ret.returncode != 0:
@@ -116,7 +175,7 @@ def ExistEnvFilePrint(ssh, wd, prompt='env vars in existing'):
def WriteEnvFile(ssh, services, wd, tag, flexric_tag): def WriteEnvFile(ssh, services, wd, tag, flexric_tag):
ret = ssh.run(f'cat {wd}/.env', silent=True, reportNonZero=False) 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} envs = {"REGISTRY":registry, "TAG": tag, "FLEXRIC_TAG": flexric_tag}
if ret.returncode == 0: # it exists, we have to update if ret.returncode == 0: # it exists, we have to update
# transforms env file to dictionary # transforms env file to dictionary
@@ -131,8 +190,7 @@ def WriteEnvFile(ssh, services, wd, tag, flexric_tag):
# or -asan images. We need to detect which kind we did pull. # or -asan images. We need to detect which kind we did pull.
fullImageName = GetImageName(ssh, svc, f"{wd}/docker-compose.y*ml") fullImageName = GetImageName(ssh, svc, f"{wd}/docker-compose.y*ml")
image = fullImageName.split("/")[-1].split(":")[0] 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) ret = ssh.run(f'docker image inspect {checkimg}', reportNonZero=False)
if ret.returncode == 0: if ret.returncode == 0:
logging.info(f"detected pulled image {checkimg}") logging.info(f"detected pulled image {checkimg}")
@@ -157,31 +215,69 @@ def GetServices(ssh, requested, file):
else: else:
return requested return requested
def CopyinServiceLog(ssh, lSourcePath, svcName, wd_yaml, ctx): def CopyinServiceLog(ssh, lSourcePath, yaml, svcName, wd_yaml, filename):
remote_filename = f"{lSourcePath}/cmake_targets/log/{svcName}.logs" remote_filename = f"{lSourcePath}/cmake_targets/log/{filename}"
ssh.run(f'docker compose -f {wd_yaml} logs {svcName} --no-log-prefix &> {remote_filename}') ssh.run(f'docker compose -f {wd_yaml} logs {svcName} --no-log-prefix &> {remote_filename}')
return archiveArtifact(ssh, ctx, remote_filename) local_dir = f"{os.getcwd()}/../cmake_targets/log/{yaml}"
local_filename = f"{local_dir}/{filename}"
return ssh.copyin(remote_filename, local_filename)
def GetDeployedServices(ssh, file): def GetRunningServices(ssh, file):
ret = ssh.run(f'docker compose -f {file} config --services') ret = ssh.run(f'docker compose -f {file} config --services')
if ret.returncode != 0: if ret.returncode != 0:
logging.error("could not get services")
return None return None
allServices = ret.stdout.splitlines() allServices = ret.stdout.splitlines()
deployed_services = [] running_services = []
for s in allServices: for s in allServices:
# outputs the hash if the container has been deployed (but might be stopped) # outputs the hash if the container is running
ret = ssh.run(f'docker compose -f {file} ps --all --quiet -- {s}', silent=True) ret = ssh.run(f'docker compose -f {file} ps --all --quiet -- {s}')
if ret.returncode != 0: if ret.returncode != 0:
# error: should not happen as we iterate over docker-provided service list logging.info(f"service {s}: {ret.stdout}")
logging.error(f"service {s}: {ret.stdout}")
elif ret.stdout == "": elif ret.stdout == "":
logging.info(f"service {s} not deployed") logging.warning(f"could not retrieve information for service {s}")
else: else:
c = ret.stdout c = ret.stdout
logging.info(f'service {s} with container id {c}') logging.debug(f'running service {s} with container id {c}')
deployed_services.append((s, c)) running_services.append((s, c))
return deployed_services logging.info(f'stopping services: {running_services}')
return running_services
def CheckLogs(self, yaml, service_name, HTML, RAN):
logPath = f'{os.getcwd()}/../cmake_targets/log/{yaml}'
filename = f'{logPath}/{service_name}-{HTML.testCase_id}.log'
success = True
if (any(sub in service_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 for service {service_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 service_name == 'nv-cubb':
msg = 'Undeploy PNF/Nvidia CUBB'
HTML.CreateHtmlTestRow(msg, 'OK', CONST.ALL_PROCESSES_OK)
elif (any(sub in service_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 for service {service_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 to analyze log for service name {service_name}')
HTML.CreateHtmlTestRowQueue(f"service {service_name}", 'OK', ["no analysis function"])
logging.debug(f"log check: service {service_name} passed analysis {success}")
return success
#----------------------------------------------------------- #-----------------------------------------------------------
# Class Declaration # Class Declaration
@@ -195,18 +291,48 @@ class Containerize():
self.ranAllowMerge = False self.ranAllowMerge = False
self.ranCommitID = '' self.ranCommitID = ''
self.ranTargetBranch = '' self.ranTargetBranch = ''
self.eNBIPAddress = ''
self.eNBUserName = ''
self.eNBPassword = ''
self.eNBSourceCodePath = '' self.eNBSourceCodePath = ''
self.eNB1IPAddress = ''
self.eNB1UserName = ''
self.eNB1Password = ''
self.eNB1SourceCodePath = ''
self.eNB2IPAddress = ''
self.eNB2UserName = ''
self.eNB2Password = ''
self.eNB2SourceCodePath = ''
self.forcedWorkspaceCleanup = False
self.imageKind = '' self.imageKind = ''
self.proxyCommit = None self.proxyCommit = None
self.yamlPath = '' self.eNB_instance = 0
self.services = '' self.eNB_serverId = ['', '', '']
self.yamlPath = ['', '', '']
self.services = ['', '', '']
self.deploymentTag = '' self.deploymentTag = ''
self.eNB_logFile = ['', '', '']
self.testCase_id = ''
self.cli = '' self.cli = ''
self.cliBuildOptions = '' self.cliBuildOptions = ''
self.dockerfileprefix = '' self.dockerfileprefix = ''
self.host = '' self.host = ''
self.deployedContainers = []
self.tsharkStarted = False
self.pingContName = ''
self.pingOptions = ''
self.pingLossThreshold = ''
self.svrContName = ''
self.svrOptions = ''
self.cliContName = ''
self.cliOptions = ''
self.imageToCopy = ''
#checkers from xml
self.ran_checkers={}
self.num_attempts = 1 self.num_attempts = 1
self.flexricTag = '' self.flexricTag = ''
@@ -215,11 +341,25 @@ class Containerize():
# Container management functions # Container management functions
#----------------------------------------------------------- #-----------------------------------------------------------
def BuildImage(self, ctx, node, HTML): def GetCredentials(self, server_id):
lSourcePath = self.eNBSourceCodePath if server_id == '0':
logging.debug('Building on server: ' + node) ip, path = self.eNBIPAddress, self.eNBSourceCodePath
cmd = cls_cmd.getConnection(node) elif server_id == '1':
log_files = [] ip, path = self.eNB1IPAddress, self.eNB1SourceCodePath
elif server_id == '2':
ip, path = self.eNB2IPAddress, self.eNB2SourceCodePath
else:
raise ValueError(f"unknown server ID '{server_id}'")
if ip == '' or path == '':
HELP.GenericHelp(CONST.Version)
raise ValueError(f'Insufficient Parameter: IP/node {ip}, path {path}')
return (ip, path)
def BuildImage(self, HTML):
svr = self.eNB_serverId[self.eNB_instance]
lIpAddr, lSourcePath = self.GetCredentials(svr)
logging.debug('Building on server: ' + lIpAddr)
cmd = cls_cmd.getConnection(lIpAddr)
# Checking the hostname to get adapted on cli and dockerfileprefixes # Checking the hostname to get adapted on cli and dockerfileprefixes
cmd.run('hostnamectl') cmd.run('hostnamectl')
@@ -227,7 +367,7 @@ class Containerize():
self.host = result.group(0) self.host = result.group(0)
if self.host == 'Ubuntu': if self.host == 'Ubuntu':
self.cli = 'docker' self.cli = 'docker'
self.dockerfileprefix = '.ubuntu' self.dockerfileprefix = '.ubuntu22'
self.cliBuildOptions = '' self.cliBuildOptions = ''
elif self.host == 'Red Hat': elif self.host == 'Red Hat':
self.cli = 'sudo podman' self.cli = 'sudo podman'
@@ -243,7 +383,7 @@ class Containerize():
result = re.search('gNB', self.imageKind) result = re.search('gNB', self.imageKind)
if result is not None: if result is not None:
imageNames.append(('oai-gnb', 'gNB', 'oai-gnb', '')) imageNames.append(('oai-gnb', 'gNB', 'oai-gnb', ''))
result = re.search('x86', self.imageKind) result = re.search('all', self.imageKind)
if result is not None: if result is not None:
imageNames.append(('oai-enb', 'eNB', 'oai-enb', '')) imageNames.append(('oai-enb', 'eNB', 'oai-enb', ''))
imageNames.append(('oai-gnb', 'gNB', 'oai-gnb', '')) imageNames.append(('oai-gnb', 'gNB', 'oai-gnb', ''))
@@ -254,6 +394,7 @@ class Containerize():
imageNames.append(('oai-physim', 'phySim', 'oai-physim', '')) imageNames.append(('oai-physim', 'phySim', 'oai-physim', ''))
if self.host == 'Ubuntu': if self.host == 'Ubuntu':
imageNames.append(('oai-lte-ru', 'lteRU', 'oai-lte-ru', '')) 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 # Building again the 5G images with Address Sanitizer
imageNames.append(('ran-build', 'build', 'ran-build-asan', '--build-arg "BUILD_OPTION=--sanitize"')) 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"')) imageNames.append(('oai-enb', 'eNB', 'oai-enb-asan', '--build-arg "BUILD_OPTION=--sanitize"'))
@@ -263,23 +404,18 @@ class Containerize():
imageNames.append(('oai-nr-cuup', 'nr-cuup', 'oai-nr-cuup-asan', '--build-arg "BUILD_OPTION=--sanitize"')) 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(('ran-build-fhi72', 'build.fhi72', 'ran-build-fhi72', ''))
imageNames.append(('oai-gnb', 'gNB.fhi72', 'oai-gnb-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) result = re.search('build_cross_arm64', self.imageKind)
if result is not None: if result is not None:
self.dockerfileprefix = '.ubuntu.cross-arm64' self.dockerfileprefix = '.ubuntu22.cross-arm64'
result = re.search('native_armv9', self.imageKind) result = re.search('native_arm', self.imageKind)
if result is not None: if result is not None:
imageNames.append(('oai-gnb', 'gNB', 'oai-gnb', '')) imageNames.append(('oai-gnb', 'gNB', 'oai-gnb', ''))
imageNames.append(('ran-build-fhi72', 'build.fhi72.native_arm', 'ran-build-fhi72', '')) imageNames.append(('ran-build-fhi72', 'build.fhi72.native_arm', 'ran-build-fhi72', ''))
imageNames.append(('oai-nr-cuup', 'nr-cuup', 'oai-nr-cuup', '')) imageNames.append(('oai-nr-cuup', 'nr-cuup', 'oai-nr-cuup', ''))
imageNames.append(('oai-nr-ue', 'nrUE', 'oai-nr-ue', '')) imageNames.append(('oai-nr-ue', 'nrUE', 'oai-nr-ue', ''))
imageNames.append(('oai-gnb-aerial', 'gNB.aerial', 'oai-gnb-aerial', '')) imageNames.append(('oai-gnb-aerial', 'gNB.aerial', 'oai-gnb-aerial', ''))
result = re.search('native_armv8', self.imageKind)
if result is not None:
imageNames.append(('oai-gnb', 'gNB', 'oai-gnb', ''))
imageNames.append(('oai-nr-cuup', 'nr-cuup', 'oai-nr-cuup', ''))
imageNames.append(('oai-nr-ue', 'nrUE', 'oai-nr-ue', ''))
self.testCase_id = HTML.testCase_id
cmd.cd(lSourcePath) cmd.cd(lSourcePath)
# if asterix, copy the entitlement and subscription manager configurations # if asterix, copy the entitlement and subscription manager configurations
if self.host == 'Red Hat': if self.host == 'Red Hat':
@@ -309,21 +445,13 @@ class Containerize():
# Let's remove any previous run artifacts if still there # Let's remove any previous run artifacts if still there
cmd.run(f"{self.cli} image prune --force") cmd.run(f"{self.cli} image prune --force")
for image,pattern,name,option in imageNames: for image,pattern,name,option in imageNames:
cmd.run(f"{self.cli} image rm {name}:{imageTag}", reportNonZero=False) cmd.run(f"{self.cli} image rm {name}:{imageTag}")
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) # Build the base image only on Push Events (not on Merge Requests)
# On when the base image docker file is being modified. # On when the base image docker file is being modified.
if forceBaseImageBuild: if forceBaseImageBuild:
cmd.run(f"{self.cli} image rm {baseImage}:{baseTag}") cmd.run(f"{self.cli} image rm {baseImage}:{baseTag}")
logfile = f'{lSourcePath}/cmake_targets/log/ran-base.docker.log' cmd.run(f"{self.cli} build {self.cliBuildOptions} --target {baseImage} --tag {baseImage}:{baseTag} --file docker/Dockerfile.base{self.dockerfileprefix} . &> cmake_targets/log/ran-base.log", timeout=1600)
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)
t = ("ran-base", archiveArtifact(cmd, ctx, logfile))
log_files.append(t)
# First verify if the base image was properly created. # First verify if the base image was properly created.
ret = cmd.run(f"{self.cli} image inspect --format=\'Size = {{{{.Size}}}} bytes\' {baseImage}:{baseTag}") ret = cmd.run(f"{self.cli} image inspect --format=\'Size = {{{{.Size}}}} bytes\' {baseImage}:{baseTag}")
allImagesSize = {} allImagesSize = {}
@@ -335,9 +463,10 @@ class Containerize():
cmd.close() cmd.close()
logging.error('\u001B[1m Building OAI Images Failed\u001B[0m') logging.error('\u001B[1m Building OAI Images Failed\u001B[0m')
HTML.CreateHtmlTestRow(self.imageKind, 'KO', CONST.ALL_PROCESSES_OK) HTML.CreateHtmlTestRow(self.imageKind, 'KO', CONST.ALL_PROCESSES_OK)
HTML.CreateHtmlTabFooter(False)
return False return False
else: else:
result = re.search(r'Size *= *(?P<size>[0-9\-]+) *bytes', cmd.getBefore()) result = re.search('Size *= *(?P<size>[0-9\-]+) *bytes', cmd.getBefore())
if result is not None: if result is not None:
size = float(result.group("size")) / 1000000 size = float(result.group("size")) / 1000000
imageSizeStr = f'{size:.1f}' imageSizeStr = f'{size:.1f}'
@@ -346,9 +475,17 @@ class Containerize():
else: else:
logging.debug('ran-base size is unknown') logging.debug('ran-base size is unknown')
# Recover build logs, for the moment only possible when build is successful
cmd.run(f"{self.cli} create --name test {baseImage}:{baseTag}")
cmd.run("mkdir -p cmake_targets/log/ran-base")
cmd.run(f"{self.cli} cp test:/oai-ran/cmake_targets/log/. cmake_targets/log/ran-base")
cmd.run(f"{self.cli} rm -f test")
# Build the target image(s) # Build the target image(s)
status = True status = True
attemptedImages = ['ran-base']
for image,pattern,name,option in imageNames: for image,pattern,name,option in imageNames:
attemptedImages += [name]
# the archived Dockerfiles have "ran-base:latest" as base image # the archived Dockerfiles have "ran-base:latest" as base image
# we need to update them with proper tag # we need to update them with proper tag
cmd.run(f'git checkout -- docker/Dockerfile.{pattern}{self.dockerfileprefix}') cmd.run(f'git checkout -- docker/Dockerfile.{pattern}{self.dockerfileprefix}')
@@ -356,20 +493,21 @@ class Containerize():
# target images should use the proper ran-build image # target images should use the proper ran-build image
if image != 'ran-build' and "-asan" in name: 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}') 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}') cmd.run(f'sed -i -e "s#ran-build-fhi72:latest#ran-build-fhi72:{imageTag}#" docker/Dockerfile.{pattern}{self.dockerfileprefix}')
elif image != 'ran-build': elif image != 'ran-build':
cmd.run(f'sed -i -e "s#ran-build:latest#ran-build:{imageTag}#" docker/Dockerfile.{pattern}{self.dockerfileprefix}') cmd.run(f'sed -i -e "s#ran-build:latest#ran-build:{imageTag}#" docker/Dockerfile.{pattern}{self.dockerfileprefix}')
if image == 'oai-gnb-aerial': 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.*.tar.gz .')
logfile = f'{lSourcePath}/cmake_targets/log/{name}.docker.log' ret = cmd.run(f'{self.cli} build {self.cliBuildOptions} --target {image} --tag {name}:{imageTag} --file docker/Dockerfile.{pattern}{self.dockerfileprefix} {option} . > cmake_targets/log/{name}.log 2>&1', timeout=1200)
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': if image == 'oai-gnb-aerial':
cmd.run('rm -f nvipc_src.2026.01.07.tar.gz') cmd.run('rm -f nvipc_src.*.tar.gz')
if image == 'ran-build' and ret.returncode == 0:
cmd.run(f"docker run --name test-log -d {name}:{imageTag} /bin/true")
cmd.run(f"docker cp test-log:/oai-ran/cmake_targets/log/ cmake_targets/log/{name}/")
cmd.run(f"docker rm -f test-log")
else:
cmd.run(f"mkdir -p cmake_targets/log/{name}")
# check the status of the build # check the status of the build
ret = cmd.run(f"{self.cli} image inspect --format=\'Size = {{{{.Size}}}} bytes\' {name}:{imageTag}") ret = cmd.run(f"{self.cli} image inspect --format=\'Size = {{{{.Size}}}} bytes\' {name}:{imageTag}")
if ret.returncode != 0: if ret.returncode != 0:
@@ -380,7 +518,7 @@ class Containerize():
allImagesSize[name] = 'N/A -- Build Failed' allImagesSize[name] = 'N/A -- Build Failed'
break break
else: else:
result = re.search(r'Size *= *(?P<size>[0-9\-]+) *bytes', cmd.getBefore()) result = re.search('Size *= *(?P<size>[0-9\-]+) *bytes', cmd.getBefore())
if result is not None: if result is not None:
size = float(result.group("size")) / 1000000 # convert to MB size = float(result.group("size")) / 1000000 # convert to MB
imageSizeStr = f'{size:.1f}' imageSizeStr = f'{size:.1f}'
@@ -391,7 +529,7 @@ class Containerize():
allImagesSize[name] = 'unknown' allImagesSize[name] = 'unknown'
# Now pruning dangling images in between target builds # Now pruning dangling images in between target builds
cmd.run(f"{self.cli} image prune --force") cmd.run(f"{self.cli} image prune --force")
cmd.run(f'docker logout {DEFAULT_REGISTRY}')
# Remove all intermediate build images and clean up # 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} image rm ran-build:{imageTag} ran-build-asan:{imageTag} ran-build-fhi72:{imageTag} || true")
cmd.run(f"{self.cli} volume prune --force") cmd.run(f"{self.cli} volume prune --force")
@@ -403,27 +541,33 @@ class Containerize():
logging.debug(cmd.run("df -h").stdout) logging.debug(cmd.run("df -h").stdout)
logging.debug(cmd.run("docker system df").stdout) logging.debug(cmd.run("docker system df").stdout)
# create a zip with all logs
build_log_name = f'build_log_{self.testCase_id}'
CopyLogsToExecutor(cmd, lSourcePath, build_log_name)
cmd.close() cmd.close()
# Analyze the logs # Analyze the logs
for name, lf in log_files: collectInfo = AnalyzeBuildLogs(build_log_name, attemptedImages, status)
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)
HTML.CreateHtmlTestRowQueue(name, 'OK' if imgStatus else 'KO', [msg])
status = status and imgStatus
if status: if status:
logging.info('\u001B[1m Building OAI Image(s) Pass\u001B[0m') logging.info('\u001B[1m Building OAI Image(s) Pass\u001B[0m')
HTML.CreateHtmlTestRow(self.imageKind, 'OK', CONST.ALL_PROCESSES_OK)
HTML.CreateHtmlNextTabHeaderTestRow(collectInfo, allImagesSize)
return True
else: else:
logging.error('\u001B[1m Building OAI Images Failed\u001B[0m') logging.error('\u001B[1m Building OAI Images Failed\u001B[0m')
return status HTML.CreateHtmlTestRow(self.imageKind, 'KO', CONST.ALL_PROCESSES_OK)
HTML.CreateHtmlNextTabHeaderTestRow(collectInfo, allImagesSize)
HTML.CreateHtmlTabFooter(False)
return False
def BuildProxy(self, ctx, node, HTML): def BuildProxy(self, HTML):
lSourcePath = self.eNBSourceCodePath svr = self.eNB_serverId[self.eNB_instance]
logging.debug('Building on server: ' + node) lIpAddr, lSourcePath = self.GetCredentials(svr)
ssh = cls_cmd.getConnection(node) logging.debug('Building on server: ' + lIpAddr)
ssh = cls_cmd.getConnection(lIpAddr)
self.testCase_id = HTML.testCase_id
oldRanCommidID = self.ranCommitID oldRanCommidID = self.ranCommitID
oldRanRepository = self.ranRepository oldRanRepository = self.ranRepository
oldRanAllowMerge = self.ranAllowMerge oldRanAllowMerge = self.ranAllowMerge
@@ -445,14 +589,19 @@ class Containerize():
buildProxy = ret.returncode != 0 # if no image, build new proxy buildProxy = ret.returncode != 0 # if no image, build new proxy
if buildProxy: if buildProxy:
ssh.run(f'rm -Rf {lSourcePath}') ssh.run(f'rm -Rf {lSourcePath}')
success = CreateWorkspace(node, lSourcePath, self.ranRepository, self.ranCommitID, self.ranTargetBranch, self.ranAllowMerge) success = CreateWorkspace(lIpAddr, lSourcePath, self.ranRepository, self.ranCommitID, self.ranTargetBranch, self.ranAllowMerge)
if not success: if not success:
raise Exception("could not clone proxy repository") raise Exception("could not clone proxy repository")
fullpath = f'{lSourcePath}/proxy_build.log' filename = f'build_log_{self.testCase_id}'
fullpath = f'{lSourcePath}/{filename}'
ssh.run(f'docker build --target oai-lte-multi-ue-proxy --tag proxy:{tag} --file {lSourcePath}/docker/Dockerfile.ubuntu18.04 {lSourcePath} > {fullpath} 2>&1') ssh.run(f'docker build --target oai-lte-multi-ue-proxy --tag proxy:{tag} --file {lSourcePath}/docker/Dockerfile.ubuntu18.04 {lSourcePath} > {fullpath} 2>&1')
archiveArtifact(ssh, ctx, fullpath) ssh.run(f'zip -r -qq {fullpath}.zip {fullpath}')
local_file = f"{os.getcwd()}/../cmake_targets/log/{filename}.zip"
ssh.copyin(f'{fullpath}.zip', local_file)
# don't delete such that we might recover the zips
#ssh.run(f'rm -f {fullpath}.zip')
ssh.run('docker image prune --force') ssh.run('docker image prune --force')
ret = ssh.run(f'docker image inspect --format=\'Size = {{{{.Size}}}} bytes\' proxy:{tag}') ret = ssh.run(f'docker image inspect --format=\'Size = {{{{.Size}}}} bytes\' proxy:{tag}')
@@ -460,6 +609,7 @@ class Containerize():
logging.error('\u001B[1m Build of L2sim proxy failed\u001B[0m') logging.error('\u001B[1m Build of L2sim proxy failed\u001B[0m')
ssh.close() ssh.close()
HTML.CreateHtmlTestRow('commit ' + tag, 'KO', CONST.ALL_PROCESSES_OK) HTML.CreateHtmlTestRow('commit ' + tag, 'KO', CONST.ALL_PROCESSES_OK)
HTML.CreateHtmlTabFooter(False)
return False return False
else: else:
logging.debug('L2sim proxy image for tag ' + tag + ' already exists, skipping build') logging.debug('L2sim proxy image for tag ' + tag + ' already exists, skipping build')
@@ -480,8 +630,18 @@ class Containerize():
self.ranAllowMerge = oldRanAllowMerge self.ranAllowMerge = oldRanAllowMerge
self.ranTargetBranch = oldRanTargetBranch self.ranTargetBranch = oldRanTargetBranch
# we do not analyze the logs (we assume the proxy builds fine at this stage),
# but need to have the following information to correctly display the HTML
files = {}
errorandwarnings = {}
errorandwarnings['errors'] = 0
errorandwarnings['warnings'] = 0
errorandwarnings['status'] = True
files['Target Image Creation'] = errorandwarnings
collectInfo = {}
collectInfo['proxy'] = files
ret = ssh.run(f'docker image inspect --format=\'Size = {{{{.Size}}}} bytes\' proxy:{tag}') ret = ssh.run(f'docker image inspect --format=\'Size = {{{{.Size}}}} bytes\' proxy:{tag}')
result = re.search(r'Size *= *(?P<size>[0-9\-]+) *bytes', ret.stdout) result = re.search('Size *= *(?P<size>[0-9\-]+) *bytes', ret.stdout)
# Cleaning any created tmp volume # Cleaning any created tmp volume
ssh.run('docker volume prune --force') ssh.run('docker volume prune --force')
ssh.close() ssh.close()
@@ -493,18 +653,21 @@ class Containerize():
allImagesSize['proxy'] = str(round(imageSize,1)) + ' Mbytes' allImagesSize['proxy'] = str(round(imageSize,1)) + ' Mbytes'
logging.info('\u001B[1m Building L2sim Proxy Image Pass\u001B[0m') logging.info('\u001B[1m Building L2sim Proxy Image Pass\u001B[0m')
HTML.CreateHtmlTestRow('commit ' + tag, 'OK', CONST.ALL_PROCESSES_OK) HTML.CreateHtmlTestRow('commit ' + tag, 'OK', CONST.ALL_PROCESSES_OK)
HTML.CreateHtmlNextTabHeaderTestRow(collectInfo, allImagesSize)
return True return True
else: else:
logging.error('proxy size is unknown') logging.error('proxy size is unknown')
allImagesSize['proxy'] = 'unknown' allImagesSize['proxy'] = 'unknown'
logging.error('\u001B[1m Build of L2sim proxy failed\u001B[0m') logging.error('\u001B[1m Build of L2sim proxy failed\u001B[0m')
HTML.CreateHtmlTestRow('commit ' + tag, 'KO', CONST.ALL_PROCESSES_OK) HTML.CreateHtmlTestRow('commit ' + tag, 'KO', CONST.ALL_PROCESSES_OK)
HTML.CreateHtmlTabFooter(False)
return False return False
def BuildRunTests(self, ctx, node, HTML): def BuildRunTests(self, HTML):
lSourcePath = self.eNBSourceCodePath svr = self.eNB_serverId[self.eNB_instance]
logging.debug('Building on server: ' + node) lIpAddr, lSourcePath = self.GetCredentials(svr)
cmd = cls_cmd.RemoteCmd(node) logging.debug('Building on server: ' + lIpAddr)
cmd = cls_cmd.RemoteCmd(lIpAddr)
cmd.cd(lSourcePath) cmd.cd(lSourcePath)
ret = cmd.run('hostnamectl') ret = cmd.run('hostnamectl')
@@ -515,6 +678,10 @@ class Containerize():
raise Exception("Can build unit tests only on Ubuntu server") raise Exception("Can build unit tests only on Ubuntu server")
logging.debug('running on Ubuntu as expected') logging.debug('running on Ubuntu as expected')
if self.forcedWorkspaceCleanup:
cmd.run(f'sudo -S rm -Rf {lSourcePath}')
self.testCase_id = HTML.testCase_id
# check that ran-base image exists as we expect it # check that ran-base image exists as we expect it
baseImage = 'ran-base' baseImage = 'ran-base'
baseTag = 'develop' baseTag = 'develop'
@@ -527,45 +694,44 @@ class Containerize():
ret = cmd.run(f"docker image inspect --format=\'Size = {{{{.Size}}}} bytes\' {baseImage}:{baseTag}") ret = cmd.run(f"docker image inspect --format=\'Size = {{{{.Size}}}} bytes\' {baseImage}:{baseTag}")
if ret.returncode != 0: if ret.returncode != 0:
logging.error(f'No {baseImage} image present, cannot build tests') 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)
HTML.CreateHtmlTabFooter(False)
return False return False
# build ran-unittests image # build ran-unittests image
dockerfile = "ci-scripts/docker/Dockerfile.unittest.ubuntu" dockerfile = "ci-scripts/docker/Dockerfile.unittest.ubuntu22"
logfile = f'{lSourcePath}/cmake_targets/log/unittest-build.log' ret = cmd.run(f'docker build --progress=plain --tag ran-unittests:{baseTag} --file {dockerfile} . &> {lSourcePath}/cmake_targets/log/unittest-build.log')
ret = cmd.run(f'docker build --progress=plain --tag ran-unittests:{baseTag} --file {dockerfile} . &> {logfile}')
archiveArtifact(cmd, ctx, logfile)
if ret.returncode != 0: if ret.returncode != 0:
build_log_name = f'build_log_{self.testCase_id}'
CopyLogsToExecutor(cmd, lSourcePath, build_log_name)
logging.error(f'Cannot build unit tests') logging.error(f'Cannot build unit tests')
HTML.CreateHtmlTestRow("Unit test build failed", 'KO', [dockerfile]) HTML.CreateHtmlTestRow("Unit test build failed", 'KO', [dockerfile])
HTML.CreateHtmlTabFooter(False)
return False return False
HTML.CreateHtmlTestRowQueue("Build unit tests", 'OK', [dockerfile]) HTML.CreateHtmlTestRowQueue("Build unit tests", 'OK', [dockerfile])
# it worked, build and execute tests, and close connection # it worked, build and execute tests, and close connection
# I would like to run it with --rm and mount the ctest result directory to avoid 'docker cp' ret = cmd.run(f'docker run -a STDOUT --workdir /oai-ran/build/ --env LD_LIBRARY_PATH=/oai-ran/build/ --rm ran-unittests:{baseTag} ctest --output-on-failure --no-label-summary -j$(nproc)')
# below, but then permissions are messed up and we can't remove the directory without sudo cmd.run(f'docker rmi ran-unittests:{baseTag}')
# making the next pipeline fail build_log_name = f'build_log_{self.testCase_id}'
ret = cmd.run(f'docker run -a STDOUT --workdir /oai-ran/build/ --env LD_LIBRARY_PATH=/oai-ran/build/ --name ran-unittests ran-unittests:{baseTag} ctest --no-label-summary -j$(nproc)') CopyLogsToExecutor(cmd, lSourcePath, build_log_name)
cmd.run('docker cp ran-unittests:/oai-ran/build/Testing/Temporary/LastTest.log .')
archiveArtifact(cmd, ctx, f'{lSourcePath}/LastTest.log')
cmd.run('docker cp ran-unittests:/oai-ran/build/Testing/Temporary/LastTestsFailed.log .')
archiveArtifact(cmd, ctx, f'{lSourcePath}/LastTestsFailed.log')
cmd.run('docker rm ran-unittests')
cmd.close() cmd.close()
if ret.returncode == 0: if ret.returncode == 0:
HTML.CreateHtmlTestRowQueue('Unit tests succeeded', 'OK', [ret.stdout]) HTML.CreateHtmlTestRowQueue('Unit tests succeeded', 'OK', [ret.stdout])
HTML.CreateHtmlTabFooter(True)
return True return True
else: else:
HTML.CreateHtmlTestRowQueue('Unit tests failed (see also doc/UnitTests.md)', 'KO', [ret.stdout]) HTML.CreateHtmlTestRowQueue('Unit tests failed (see also doc/UnitTests.md)', 'KO', [ret.stdout])
HTML.CreateHtmlTabFooter(False)
return False return False
def Push_Image_to_Local_Registry(self, node, HTML, tag_prefix=""): def Push_Image_to_Local_Registry(self, HTML, svr_id, tag_prefix=""):
lSourcePath = self.eNBSourceCodePath lIpAddr, lSourcePath = self.GetCredentials(svr_id)
logging.debug('Pushing images to server: ' + node) logging.debug('Pushing images to server: ' + lIpAddr)
ssh = cls_cmd.getConnection(node) ssh = cls_cmd.getConnection(lIpAddr)
imagePrefix = DEFAULT_REGISTRY imagePrefix = 'porcepix.sboai.cs.eurecom.fr'
ret = ssh.run(f'docker login -u oaicicd -p oaicicd {imagePrefix}') ret = ssh.run(f'docker login -u oaicicd -p oaicicd {imagePrefix}')
if ret.returncode != 0: if ret.returncode != 0:
msg = 'Could not log into local registry' msg = 'Could not log into local registry'
@@ -636,26 +802,28 @@ class Containerize():
msg = "Pulled Images:\n" + '\n'.join(pulled_images) msg = "Pulled Images:\n" + '\n'.join(pulled_images)
return True, msg return True, msg
def Pull_Image_from_Registry(self, HTML, node, images, tag=None, tag_prefix="", registry=DEFAULT_REGISTRY, username="oaicicd", password="oaicicd"): def Pull_Image_from_Registry(self, HTML, svr_id, images, tag=None, tag_prefix="", registry="porcepix.sboai.cs.eurecom.fr", username="oaicicd", password="oaicicd"):
logging.debug(f'\u001B[1m Pulling image(s) on server: {node}\u001B[0m') lIpAddr, lSourcePath = self.GetCredentials(svr_id)
logging.debug('\u001B[1m Pulling image(s) on server: ' + lIpAddr + '\u001B[0m')
if not tag: if not tag:
tag = CreateTag(self.ranCommitID, self.ranBranch, self.ranAllowMerge) tag = CreateTag(self.ranCommitID, self.ranBranch, self.ranAllowMerge)
with cls_cmd.getConnection(node) as cmd: with cls_cmd.getConnection(lIpAddr) as cmd:
success, msg = Containerize.Pull_Image(cmd, images, tag, tag_prefix, registry, username, password) success, msg = Containerize.Pull_Image(cmd, images, tag, tag_prefix, registry, username, password)
param = f"on node {node}" param = f"on node {lIpAddr}"
if success: if success:
HTML.CreateHtmlTestRowQueue(param, 'OK', [msg]) HTML.CreateHtmlTestRowQueue(param, 'OK', [msg])
else: else:
HTML.CreateHtmlTestRowQueue(param, 'KO', [msg]) HTML.CreateHtmlTestRowQueue(param, 'KO', [msg])
return success return success
def Clean_Test_Server_Images(self, HTML, node, images, tag=None): def Clean_Test_Server_Images(self, HTML, svr_id, images, tag=None):
logging.debug(f'\u001B[1m Cleaning image(s) from server: {node}\u001B[0m') lIpAddr, lSourcePath = self.GetCredentials(svr_id)
logging.debug(f'\u001B[1m Cleaning image(s) from server: {lIpAddr}\u001B[0m')
if not tag: if not tag:
tag = CreateTag(self.ranCommitID, self.ranBranch, self.ranAllowMerge) tag = CreateTag(self.ranCommitID, self.ranBranch, self.ranAllowMerge)
status = True status = True
with cls_cmd.getConnection(node) as myCmd: with cls_cmd.getConnection(lIpAddr) as myCmd:
removed_images = [] removed_images = []
for image in images: for image in images:
fullImage = f"oai-ci/{image}:{tag}" fullImage = f"oai-ci/{image}:{tag}"
@@ -666,145 +834,102 @@ class Containerize():
msg = "Removed Images:\n" + '\n'.join(removed_images) msg = "Removed Images:\n" + '\n'.join(removed_images)
s = 'OK' if status else 'KO' s = 'OK' if status else 'KO'
param = f"on node {node}" param = f"on node {lIpAddr}"
HTML.CreateHtmlTestRowQueue(param, s, [msg]) HTML.CreateHtmlTestRowQueue(param, s, [msg])
return status return status
def Create_Workspace(self, node, HTML): def Create_Workspace(self,HTML):
lSourcePath = self.eNBSourceCodePath svr = self.eNB_serverId[self.eNB_instance]
success = CreateWorkspace(node, lSourcePath, self.ranRepository, self.ranCommitID, self.ranTargetBranch, self.ranAllowMerge) lIpAddr, lSourcePath = self.GetCredentials(svr)
success = CreateWorkspace(lIpAddr, lSourcePath, self.ranRepository, self.ranCommitID, self.ranTargetBranch, self.ranAllowMerge)
if success: if success:
HTML.CreateHtmlTestRowQueue('N/A', 'OK', [f"created workspace {lSourcePath}"]) HTML.CreateHtmlTestRowQueue('N/A', 'OK', [f"created workspace {lSourcePath}"])
else: else:
HTML.CreateHtmlTestRowQueue('N/A', 'KO', ["cannot create workspace"]) HTML.CreateHtmlTestRowQueue('N/A', 'KO', ["cannot create workspace"])
return success return success
def DeployObject(self, ctx, node, HTML): def DeployObject(self, HTML):
svr = self.eNB_serverId[self.eNB_instance]
num_attempts = self.num_attempts num_attempts = self.num_attempts
lSourcePath = self.eNBSourceCodePath lIpAddr, lSourcePath = self.GetCredentials(svr)
yaml = self.yamlPath.strip('/') logging.debug(f'Deploying OAI Object on server: {lIpAddr}')
yaml = self.yamlPath[self.eNB_instance].strip('/')
# creating the log folder by default
local_dir = f"{os.getcwd()}/../cmake_targets/log/{yaml.split('/')[-1]}"
os.system(f'mkdir -p {local_dir}')
wd = f'{lSourcePath}/{yaml}' wd = f'{lSourcePath}/{yaml}'
wd_yaml = f'{wd}/docker-compose.y*ml' wd_yaml = f'{wd}/docker-compose.y*ml'
with cls_cmd.getConnection(node) as ssh: yaml_dir = yaml.split('/')[-1]
services = GetServices(ssh, self.services, wd_yaml) with cls_cmd.getConnection(lIpAddr) as ssh:
services = GetServices(ssh, self.services[self.eNB_instance], wd_yaml)
if services == [] or services == ' ' or services == None: if services == [] or services == ' ' or services == None:
msg = 'Cannot determine services to start' msg = 'Cannot determine services to start'
logging.error(msg) logging.error(msg)
HTML.CreateHtmlTestRowQueue('N/A', 'KO', [msg]) HTML.CreateHtmlTestRowQueue('N/A', 'KO', [msg])
return False return False
logging.info(f'\u001B[1mDeploying object(s) "{services}" on server {node}\u001B[0m')
ExistEnvFilePrint(ssh, wd) ExistEnvFilePrint(ssh, wd)
WriteEnvFile(ssh, services, wd, self.deploymentTag, self.flexricTag) WriteEnvFile(ssh, services, wd, self.deploymentTag, self.flexricTag)
if num_attempts <= 0: if num_attempts <= 0:
raise ValueError(f'Invalid value for num_attempts: {num_attempts}, must be greater than 0') raise ValueError(f'Invalid value for num_attempts: {num_attempts}, must be greater than 0')
for attempt in range(num_attempts): for attempt in range(num_attempts):
imagesInfo = []
healthInfo = []
logging.info(f'will start services {services}') logging.info(f'will start services {services}')
status = ssh.run(f'docker compose -f {wd_yaml} up -d --wait --wait-timeout 60 -- {services}') status = ssh.run(f'docker compose -f {wd_yaml} up -d -- {services}')
info = ssh.run(f"docker compose -f {wd_yaml} ps --all --format=\'table {{{{.Service}}}} [{{{{.Image}}}}] {{{{.Status}}}}\' -- {services} | column -t") if status.returncode != 0:
deployed = status.returncode == 0
if not deployed:
msg = f'cannot deploy services {services}: {status.stdout}' msg = f'cannot deploy services {services}: {status.stdout}'
logging.error(msg) logging.error(msg)
else: HTML.CreateHtmlTestRowQueue('N/A', 'NOK', [msg])
return False
for svc in services.split():
health, msg = GetServiceHealth(ssh, svc, f'{wd_yaml}')
logging.info(msg)
imagesInfo.append(msg)
healthInfo.append(health)
deployed = all(healthInfo)
if deployed:
break break
if (attempt < num_attempts - 1): elif (attempt < num_attempts - 1):
warning_msg = (f'Failed to deploy on attempt {attempt}, restart services {services}') warning_msg = f'Restart services {services}'
logging.warning(warning_msg) logging.warning(warning_msg)
HTML.CreateHtmlTestRowQueue('N/A', 'NOK', [warning_msg]) imagesInfo.append(warning_msg)
HTML.CreateHtmlTestRowQueue('N/A', 'NOK', ['\n'.join(imagesInfo)])
for svc in services.split(): for svc in services.split():
CopyinServiceLog(ssh, lSourcePath, svc, wd_yaml, ctx) CopyinServiceLog(ssh, lSourcePath, yaml_dir, svc, wd_yaml, f'{svc}-{HTML.testCase_id}-attempt{attempt}.log')
ssh.run(f'docker compose -f {wd_yaml} down -- {services}') ssh.run(f'docker compose -f {wd_yaml} down -- {services}')
imagesInfo = info.stdout.splitlines()[1:]
logging.debug(f'{info.stdout.splitlines()[1:]}')
if deployed: if deployed:
HTML.CreateHtmlTestRowQueue(self.services, 'OK', ['\n'.join(imagesInfo)]) HTML.CreateHtmlTestRowQueue('N/A', 'OK', ['\n'.join(imagesInfo)])
logging.info('\u001B[1m Deploying objects Pass\u001B[0m')
else: else:
HTML.CreateHtmlTestRowQueue(self.services, 'KO', ['\n'.join(imagesInfo)]) HTML.CreateHtmlTestRowQueue('N/A', 'KO', ['\n'.join(imagesInfo)])
logging.error('\u001B[1m Deploying objects Failed\u001B[0m')
return deployed return deployed
def StopObject(self, ctx, node, HTML): def UndeployObject(self, HTML, RAN):
lSourcePath = self.eNBSourceCodePath svr = self.eNB_serverId[self.eNB_instance]
if not self.services: lIpAddr, lSourcePath = self.GetCredentials(svr)
raise ValueError(f'no services provided') logging.debug(f'\u001B[1m Undeploying OAI Object from server: {lIpAddr}\u001B[0m')
logging.info(f'\u001B[1m Stopping objects "{self.services}" from server: {node}\u001B[0m') yaml = self.yamlPath[self.eNB_instance].strip('/')
reqServices = self.services.split()
yaml = self.yamlPath.strip('/')
wd = f'{lSourcePath}/{yaml}' wd = f'{lSourcePath}/{yaml}'
wd_yaml = f'{wd}/docker-compose.y*ml' yaml_dir = yaml.split('/')[-1]
with cls_cmd.getConnection(node) as ssh: with cls_cmd.getConnection(lIpAddr) as ssh:
ExistEnvFilePrint(ssh, wd) ExistEnvFilePrint(ssh, wd)
services = [s for s, _ in GetDeployedServices(ssh, wd_yaml)] services = GetRunningServices(ssh, f"{wd}/docker-compose.y*ml")
success = [] copyin_res = None
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')
if services is not None: if services is not None:
service_desc = {} all_serv = " ".join([s for s, _ in services])
for s, c in services: ssh.run(f'docker compose -f {wd}/docker-compose.y*ml stop -- {all_serv}')
ret = ssh.run(f'docker inspect {c} --format="{{{{.State.ExitCode}}}}"') copyin_res = all(CopyinServiceLog(ssh, lSourcePath, yaml_dir, s, f"{wd}/docker-compose.y*ml", f'{s}-{HTML.testCase_id}.log') for s, c in services)
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}
else: else:
logging.warning('could not identify services to stop => no log file') logging.warning('could not identify services to stop => no log file')
ssh.run(f'docker compose -f {wd_yaml} down -v') ssh.run(f'docker compose -f {wd}/docker-compose.y*ml down -v')
HTML.CreateHtmlTestRowQueue(node, 'OK', ['Undeployment successful'])
ssh.run(f'rm {wd}/.env') ssh.run(f'rm {wd}/.env')
if not all_logs: if not copyin_res:
HTML.CreateHtmlTestRowQueue('N/A', 'KO', ['Could not copy logfile(s)']) HTML.CreateHtmlTestRowQueue('N/A', 'KO', ['Could not copy logfile(s)'])
logging.error(f"could not copy all files: {all_logs=} {services=}") return False
success = False
else: else:
success = cls_analysis.AnalyzeServices(HTML, service_desc, to_analyze) log_results = [CheckLogs(self, yaml_dir, s, HTML, RAN) for s, _ in services]
success = all(log_results)
if success: if success:
logging.info('\u001B[1m Undeploying objects Pass\u001B[0m') logging.info('\u001B[1m Undeploying OAI Object Pass\u001B[0m')
else: else:
logging.error('\u001B[1m Undeploying objects Failed\u001B[0m') logging.error('\u001B[1m Undeploying OAI Object 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)
return success return success

View File

@@ -29,7 +29,6 @@ import yaml
import re import re
import cls_cmd import cls_cmd
from cls_ci_helper import archiveArtifact
def listify(s): def listify(s):
if s is None: if s is None:
@@ -77,8 +76,7 @@ class CoreNetwork:
words = line[1:].strip().split(" ") words = line[1:].strip().split(" ")
script_name = words[0] script_name = words[0]
options = " ".join(words[1:]) options = " ".join(words[1:])
with cls_cmd.getConnection(host) as c: ret = cls_cmd.runScript(host, script_name, 300, parameters=options, silent=silent)
ret = c.exec_script(script_name, 300, parameters=options, silent=silent)
return ret return ret
def _command(self, cmd_list, must_succeed=False, silent=False): def _command(self, cmd_list, must_succeed=False, silent=False):
@@ -116,7 +114,8 @@ class CoreNetwork:
logging.info(f'deployed core network {self}, pingable IP address {ip}') logging.info(f'deployed core network {self}, pingable IP address {ip}')
return True, output return True, output
def _collect_logs(self, ctx): def _collect_logs(self, log_dir):
logging.info(f'collecting logs into (local) {log_dir}')
remote_dir = "/tmp/cn-undeploy-logs" remote_dir = "/tmp/cn-undeploy-logs"
with cls_cmd.getConnection(self._host) as c: with cls_cmd.getConnection(self._host) as c:
# create a directory for log collection # create a directory for log collection
@@ -135,17 +134,18 @@ class CoreNetwork:
logging.error("cannot enumerate log files") logging.error("cannot enumerate log files")
return [] return []
log_files = [] log_files = []
# copy them to the executor one by one # copy them to the executor one by one, and store in log_dir
for f in ret.stdout.split("\n"): for f in ret.stdout.split("\n"):
name = archiveArtifact(c, ctx, f) l = f.replace(remote_dir, log_dir)
log_files.append(name) c.copyin(f, l)
log_files.append(l)
c.run(f'rm -rf {remote_dir}') c.run(f'rm -rf {remote_dir}')
return log_files return log_files
def undeploy(self, ctx=None): def undeploy(self, log_dir=None):
log_files = [] log_files = []
if ctx is not None: if log_dir is not None:
log_files = self._collect_logs(ctx) log_files = self._collect_logs(log_dir)
else: else:
logging.warning("no directory for log collection specified, cannot retrieve core network logs") logging.warning("no directory for log collection specified, cannot retrieve core network logs")
logging.info(f'undeploy core network {self}') logging.info(f'undeploy core network {self}')

View File

@@ -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)

View File

@@ -32,7 +32,6 @@ import re
import yaml import yaml
import cls_cmd import cls_cmd
from cls_ci_helper import archiveArtifact
class Module_UE: class Module_UE:
@@ -60,31 +59,26 @@ class Module_UE:
} }
self.interface = m.get('IF') self.interface = m.get('IF')
self.MTU = m.get('MTU') self.MTU = m.get('MTU')
self.trace = m.get('trace') == True
self.logStore = m.get('LogStore')
self.cmd_prefix = m.get('CmdPrefix') self.cmd_prefix = m.get('CmdPrefix')
logging.info(f'initialized UE {self} from {filename}') logging.info(f'initialized UE {self} from {filename}')
t = m.get('Tracing')
self.trace = t is not None
if self.trace:
if t.get('Start') is None or t.get('Stop') is None or t.get('Collect')is None :
raise ValueError("need to have Start/Stop/Collect for tracing")
self.cmd_dict["traceStart"] = t.get('Start')
self.cmd_dict["traceStop"] = t.get('Stop')
self._logCollect = t.get('Collect')
if "%%log_dir%%" not in self._logCollect:
raise ValueError(f"(At least one) LogCollect expression for {module_name} must contain \"%%log_dir%%\"")
def __str__(self): def __str__(self):
return f"{self.module_name}@{self.host}" return f"{self.module_name}@{self.host} [IP: {self.getIP()}]"
def __repr__(self): def __repr__(self):
return self.__str__() return self.__str__()
def _command(self, cmd, silent=False, reportNonZero=True): def _command(self, cmd, silent = False):
if cmd is None: if cmd is None:
raise Exception("no command provided") raise Exception("no command provided")
with cls_cmd.getConnection(self.host) as c: if self.host == "" or self.host == "localhost":
response = c.run(cmd, silent=silent, reportNonZero=reportNonZero) c = cls_cmd.LocalCmd()
else:
c = cls_cmd.RemoteCmd(self.host)
response = c.run(cmd, silent=silent)
c.close()
return response return response
#-----------------$ #-----------------$
@@ -92,40 +86,40 @@ class Module_UE:
#-----------------$ #-----------------$
def initialize(self): def initialize(self):
if self.trace:
raise Exception("UE tracing not implemented yet")
self._enableTrace()
# we first terminate to make sure the UE has been stopped # we first terminate to make sure the UE has been stopped
if self.cmd_dict["detach"]: if self.cmd_dict["detach"]:
self._command(self.cmd_dict["detach"], silent=True) self._command(self.cmd_dict["detach"], silent=True)
self._command(self.cmd_dict["terminate"], silent=True) self._command(self.cmd_dict["terminate"], silent=True)
ret = self._command(self.cmd_dict["initialize"]) ret = self._command(self.cmd_dict["initialize"])
logging.info(f'For command: {ret.args} | return output: {ret.stdout} | Code: {ret.returncode}') logging.info(f'For command: {ret.args} | return output: {ret.stdout} | Code: {ret.returncode}')
if self.trace:
self._enableTrace()
# Here each UE returns differently for the successful initialization, requires check based on UE # Here each UE returns differently for the successful initialization, requires check based on UE
return ret.returncode == 0 return ret.returncode == 0
def terminate(self, ctx=None): def terminate(self):
self._command(self.cmd_dict["terminate"]) self._command(self.cmd_dict["terminate"])
if self.trace and ctx is not None: if self.trace:
raise Exception("UE tracing not implemented yet")
self._disableTrace() self._disableTrace()
return self._collectTrace(ctx) return self._logCollect()
return None return None
def attach(self, attach_tries = 3, attach_timeout = 40): def attach(self, attach_tries = 4, attach_timeout = 60):
ip = None ip = None
while attach_tries > 0: while attach_tries > 0:
self._command(self.cmd_dict["attach"]) self._command(self.cmd_dict["attach"])
timeout = attach_timeout timeout = attach_timeout
logging.debug("Waiting for IP address to be assigned") logging.debug("Waiting for IP address to be assigned")
ip = self.getIP(silent=False, reportNonZero=True)
while timeout > 0 and not ip: while timeout > 0 and not ip:
time.sleep(1) time.sleep(5)
timeout -= 1 timeout -= 5
ip = self.getIP(silent=True, reportNonZero=False) ip = self.getIP()
if ip: if ip:
break break
logging.warning(f"UE did not receive IP address after {attach_timeout} s, detaching") logging.warning(f"UE did not receive IP address after {attach_timeout} s, detaching")
attach_timeout += 20
attach_tries -= 1 attach_tries -= 1
self._command(self.cmd_dict["detach"]) self._command(self.cmd_dict["detach"])
time.sleep(5) time.sleep(5)
@@ -166,8 +160,8 @@ class Module_UE:
logging.error(message) logging.error(message)
return False return False
def getIP(self, silent=True, reportNonZero=True): def getIP(self):
output = self._command(self.cmd_dict["getNetwork"], silent=silent, reportNonZero=reportNonZero) output = self._command(self.cmd_dict["getNetwork"], silent=True)
result = re.search(r'inet (?P<ip>[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)', output.stdout) result = re.search(r'inet (?P<ip>[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)', output.stdout)
if result and result.group('ip'): if result and result.group('ip'):
ip = result.group('ip') ip = result.group('ip')
@@ -197,33 +191,10 @@ class Module_UE:
return self.cmd_prefix if self.cmd_prefix else "" return self.cmd_prefix if self.cmd_prefix else ""
def _enableTrace(self): def _enableTrace(self):
logging.info(f'UE {self}: start UE tracing') raise Exception("not implemented")
self._command(self.cmd_dict["traceStart"])
def _disableTrace(self): def _disableTrace(self):
logging.info(f'UE {self}: stop UE tracing') raise Exception("not implemented")
self._command(self.cmd_dict["traceStop"])
def _collectTrace(self, ctx): def _logCollect(self):
remote_dir = "/tmp/ue-trace-logs" raise Exception("not implemented")
with cls_cmd.getConnection(self.host) as c:
# create a directory for log collection
c.run(f'rm -rf {remote_dir}')
ret = c.run(f'mkdir {remote_dir}')
if ret.returncode != 0:
logging.error("cannot create directory for log collection")
return []
log_cmd = self._logCollect.replace('%%log_dir%%', remote_dir)
self._command(log_cmd)
# enumerate collected files
ret = c.run(f'ls {remote_dir}/*')
if ret.returncode != 0:
logging.error("cannot enumerate log files")
return []
log_files = []
# copy them to the executor one by one, and store in log_dir
for f in ret.stdout.split("\n"):
name = archiveArtifact(c, ctx, f)
log_files.append(name)
c.run(f'rm -rf {remote_dir}')
return log_files

View File

@@ -28,23 +28,26 @@ import cls_cmd
import cls_oai_html import cls_oai_html
import cls_analysis import cls_analysis
import constants as CONST import constants as CONST
from cls_ci_helper import archiveArtifact
DPDK_PATH = '/opt/dpdk-t2-22.11.0' LOG_PATH_PHYSIM = 'phy_sim_logs'
class Native(): class Native():
def Build(ctx, node, HTML, directory, options): def Build(test_case, HTML, host, directory, options):
logging.debug(f'Building on server: {node}') logging.debug(f'Building on server: {host}')
HTML.testCase_id = test_case
with cls_cmd.getConnection(node) as ssh: with cls_cmd.getConnection(host) as ssh:
base = f"{directory}/cmake_targets" base = f"{directory}/cmake_targets"
ret = ssh.run(f"C_INCLUDE_PATH={DPDK_PATH}/include/ PKG_CONFIG_PATH={DPDK_PATH}/lib64/pkgconfig/ {base}/build_oai {options} > {base}/build_oai.log", timeout=900) ret = ssh.run(f"{base}/build_oai {options} > {base}/log/build_oai.log", timeout=900)
success = ret.returncode == 0 success = ret.returncode == 0
logs = ssh.run(f"cat {base}/build_oai.log", silent=True) logs = ssh.run(f"cat {base}/log/build_oai.log", silent=True)
logging.debug(f"build finished with code {ret.returncode}") logging.debug(f"build finished with code {ret.returncode}, output:\n{logs.stdout}")
archiveArtifact(ssh, ctx, f'{base}/build_oai.log') # create log directory, and copy build logs
target = f"{base}/build_log_{test_case}/"
ssh.run(f"mkdir -p {target}")
ssh.run(f"mv {base}/log/* {target}")
# check if build artifacts are there # check if build artifacts are there
# NOTE: build_oai should fail with exit code if it could not build, but it does not # NOTE: build_oai should fail with exit code if it could not build, but it does not
@@ -63,3 +66,19 @@ class Native():
logging.error('\u001B[1m Building OAI Failed\u001B[0m') logging.error('\u001B[1m Building OAI Failed\u001B[0m')
HTML.CreateHtmlTestRow(options, 'KO', CONST.ALL_PROCESSES_OK) HTML.CreateHtmlTestRow(options, 'KO', CONST.ALL_PROCESSES_OK)
return success return success
def Run_Physim(HTML, host, directory, options, physim_test, threshold):
logging.debug(f'Runnin {physim_test} on server: {host}')
workSpacePath = f'{directory}/cmake_targets'
os.system(f'mkdir -p ./{LOG_PATH_PHYSIM}')
runLogFile=f'physim_{HTML.testCase_id}.log'
with cls_cmd.getConnection(host) as cmd:
cmd.run(f'sudo {workSpacePath}/ran_build/build/{physim_test} {options} >> {workSpacePath}/{runLogFile}')
cmd.copyin(src=f'{workSpacePath}/{runLogFile}', tgt=f'{LOG_PATH_PHYSIM}/{runLogFile}')
success, msg = cls_analysis.Analysis.analyze_physim(f'{LOG_PATH_PHYSIM}/{runLogFile}', physim_test, options, threshold)
if success:
HTML.CreateHtmlTestRowQueue(options, 'OK', [msg])
else:
logging.error(msg)
HTML.CreateHtmlTestRowQueue(options, 'KO', [msg])
return success

View File

@@ -67,9 +67,19 @@ class HTMLManagement():
self.htmlUEFailureMsg = '' self.htmlUEFailureMsg = ''
self.startTime = int(round(time.time() * 1000)) self.startTime = int(round(time.time() * 1000))
self.testCaseIdx = '' self.testCase_id = ''
self.desc = '' self.desc = ''
self.OsVersion = ['', '']
self.KernelVersion = ['', '']
self.UhdVersion = ['', '']
self.UsrpBoard = ['', '']
self.CpuNb = ['', '']
self.CpuModel = ['', '']
self.CpuMHz = ['', '']
#----------------------------------------------------------- #-----------------------------------------------------------
# HTML structure creation functions # HTML structure creation functions
#----------------------------------------------------------- #-----------------------------------------------------------
@@ -191,7 +201,7 @@ class HTMLManagement():
self.htmlFile.write(' <table class="table" border = "1">\n') self.htmlFile.write(' <table class="table" border = "1">\n')
self.htmlFile.write(' <tr bgcolor = "#33CCFF" >\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%">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 Desc</th>\n')
self.htmlFile.write(' <th>Test Options</th>\n') self.htmlFile.write(' <th>Test Options</th>\n')
self.htmlFile.write(' <th style="width:5%">Test Status</th>\n') self.htmlFile.write(' <th style="width:5%">Test Status</th>\n')
@@ -214,11 +224,12 @@ class HTMLManagement():
self.htmlFile.write(' </table>\n') self.htmlFile.write(' </table>\n')
self.htmlFile.write(' </div>\n') self.htmlFile.write(' </div>\n')
self.htmlFile.close() self.htmlFile.close()
time.sleep(1)
if passStatus: if passStatus:
cmd = "sed -i -e 's/__STATE_" + self.htmlTabNames[0] + "__//' test_results.html" cmd = "sed -i -e 's/__STATE_" + self.htmlTabNames[0] + "__//' test_results.html"
subprocess.run(cmd, shell=True) subprocess.run(cmd, shell=True)
else: 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) subprocess.run(cmd, shell=True)
self.htmlFooterCreated = False self.htmlFooterCreated = False
@@ -247,7 +258,7 @@ class HTMLManagement():
self.htmlFile.write(' </tr>\n') self.htmlFile.write(' </tr>\n')
self.htmlFile.write(' </table>\n') self.htmlFile.write(' </table>\n')
self.htmlFile.write(' <p></p>\n') self.htmlFile.write(' <p></p>\n')
self.htmlFile.write(' <div class="well well-lg">End of Test Report -- Copyright <span class="glyphicon glyphicon-copyright-mark"></span> 2025 <a href="http://www.openairinterface.org/">OpenAirInterface</a>. All Rights Reserved.</div>\n') self.htmlFile.write(' <div class="well well-lg">End of Test Report -- Copyright <span class="glyphicon glyphicon-copyright-mark"></span> 2018 <a href="http://www.openairinterface.org/">OpenAirInterface</a>. All Rights Reserved.</div>\n')
self.htmlFile.write('</div></body>\n') self.htmlFile.write('</div></body>\n')
self.htmlFile.write('</html>\n') self.htmlFile.write('</html>\n')
self.htmlFile.close() self.htmlFile.close()
@@ -259,7 +270,7 @@ class HTMLManagement():
currentTime = int(round(time.time() * 1000)) - self.startTime currentTime = int(round(time.time() * 1000)) - self.startTime
self.htmlFile.write(' <tr>\n') self.htmlFile.write(' <tr>\n')
self.htmlFile.write(' <td bgcolor = "lightcyan" >' + format(currentTime / 1000, '.1f') + '</td>\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>' + self.desc + '</td>\n')
self.htmlFile.write(' <td>' + str(options) + '</td>\n') self.htmlFile.write(' <td>' + str(options) + '</td>\n')
if (str(status) == 'OK'): if (str(status) == 'OK'):
@@ -332,6 +343,58 @@ class HTMLManagement():
self.htmlFile.write(' </tr>\n') self.htmlFile.write(' </tr>\n')
self.htmlFile.close() self.htmlFile.close()
def CreateHtmlNextTabHeaderTestRow(self, collectInfo, allImagesSize, machine='eNB'):
if (self.htmlFooterCreated or (not self.htmlHeaderCreated)):
return
self.htmlFile = open('test_results.html', 'a')
if bool(collectInfo) == False:
self.htmlFile.write(' <tr bgcolor = "red" >\n')
self.htmlFile.write(' <td colspan="6"><b> ----IMAGES BUILDING FAILED - Unable to recover the image logs ---- </b></td>\n')
self.htmlFile.write(' </tr>\n')
else:
for image in collectInfo:
files = collectInfo[image]
# TabHeader for image logs on built shared and target images
if allImagesSize[image].count('unknown') > 0:
self.htmlFile.write(' <tr bgcolor = "orange" >\n')
elif allImagesSize[image].count('Build Failed') > 0:
self.htmlFile.write(' <tr bgcolor = "red" >\n')
else:
self.htmlFile.write(' <tr bgcolor = "#F0F0F0" >\n')
self.htmlFile.write(' <td colspan="6"><b> ---- ' + image + ' IMAGE STATUS ----> Size ' + allImagesSize[image] + ' </b></td>\n')
self.htmlFile.write(' </tr>\n')
self.htmlFile.write(' <tr bgcolor = "#33CCFF" >\n')
self.htmlFile.write(' <th colspan="2">Element</th>\n')
self.htmlFile.write(' <th>Nb Errors</th>\n')
self.htmlFile.write(' <th>Nb Warnings</th>\n')
self.htmlFile.write(' <th colspan="2">Status</th>\n')
self.htmlFile.write(' </tr>\n')
for fil in files:
parameters = files[fil]
# TestRow for image logs on built shared and target images
self.htmlFile.write(' <tr>\n')
self.htmlFile.write(' <td colspan="2" bgcolor = "lightcyan" >' + fil + ' </td>\n')
if (parameters['errors'] == 0):
self.htmlFile.write(' <td bgcolor = "green" >' + str(parameters['errors']) + '</td>\n')
else:
self.htmlFile.write(' <td bgcolor = "red" >' + str(parameters['errors']) + '</td>\n')
if (parameters['errors'] > 0):
self.htmlFile.write(' <td bgcolor = "red" >' + str(parameters['warnings']) + '</td>\n')
elif (parameters['warnings'] == 0):
self.htmlFile.write(' <td bgcolor = "green" >' + str(parameters['warnings']) + '</td>\n')
else:
self.htmlFile.write(' <td bgcolor = "orange" >' + str(parameters['warnings']) + '</td>\n')
if (parameters['errors'] == 0) and (parameters['warnings'] == 0):
self.htmlFile.write(' <th colspan="2" bgcolor = "green" ><font color="white">OK </font></th>\n')
elif (parameters['errors'] == 0):
self.htmlFile.write(' <th colspan="2" bgcolor = "orange" ><font color="white">OK </font></th>\n')
else:
self.htmlFile.write(' <th colspan="2" bgcolor = "red" > NOT OK </th>\n')
self.htmlFile.write(' </tr>\n')
self.htmlFile.close()
#for the moment it is limited to 4 columns, to be made generic later #for the moment it is limited to 4 columns, to be made generic later
def CreateHtmlDataLogTable(self, DataLog): def CreateHtmlDataLogTable(self, DataLog):
if (self.htmlFooterCreated or (not self.htmlHeaderCreated)): if (self.htmlFooterCreated or (not self.htmlHeaderCreated)):
@@ -374,7 +437,7 @@ class HTMLManagement():
addOrangeBK = False addOrangeBK = False
self.htmlFile.write(' <tr>\n') self.htmlFile.write(' <tr>\n')
self.htmlFile.write(' <td bgcolor = "lightcyan" >' + format(currentTime / 1000, '.1f') + '</td>\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>' + self.desc + '</td>\n')
self.htmlFile.write(' <td>' + str(options) + '</td>\n') self.htmlFile.write(' <td>' + str(options) + '</td>\n')
if (str(status) == 'OK'): if (str(status) == 'OK'):
@@ -533,6 +596,6 @@ class HTMLManagement():
self.htmlFile.write(' <td bgcolor = "green" ><font color="white"><b>' + value[2] + '</b></font></td>\n') self.htmlFile.write(' <td bgcolor = "green" ><font color="white"><b>' + value[2] + '</b></font></td>\n')
else: else:
self.htmlFile.write(' <td bgcolor = "red" ><font color="white"><b>' + value[2] + '</b></font></td>\n') self.htmlFile.write(' <td bgcolor = "red" ><font color="white"><b>' + value[2] + '</b></font></td>\n')
self.htmlFile.write(f' <td colspan="2" bgcolor = "lightcyan"><pre style="display: inline flow-root list-item; margin: 0 3px 0 3px; min-width: 24em;">{value[1]}</pre></td>\n') self.htmlFile.write(' <td bgcolor = "lightcyan">' + value[1] + '</td>\n')
self.htmlFile.close() self.htmlFile.close()

View File

@@ -32,6 +32,7 @@
#----------------------------------------------------------- #-----------------------------------------------------------
# Import Libs # Import Libs
#----------------------------------------------------------- #-----------------------------------------------------------
import sys # arg
import re # reg import re # reg
import time # sleep import time # sleep
import os import os
@@ -40,13 +41,12 @@ import concurrent.futures
import json import json
#import our libs #import our libs
import helpreadme as HELP
import constants as CONST import constants as CONST
import cls_module import cls_module
import cls_corenetwork import cls_corenetwork
import cls_analysis
import cls_cmd import cls_cmd
from cls_ci_helper import archiveArtifact
#----------------------------------------------------------- #-----------------------------------------------------------
# Helper functions used here and in other classes # Helper functions used here and in other classes
@@ -83,29 +83,6 @@ def Iperf_ComputeTime(args):
raise Exception('Iperf time not found!') raise Exception('Iperf time not found!')
return int(result.group('iperf_time')) return int(result.group('iperf_time'))
def convert_to_mbps(value, magnitude):
value = float(value)
if magnitude == 'K' or magnitude == 'k':
return value / 1000
elif magnitude == 'M':
return value
elif magnitude == 'G':
return value * 1000
else:
return value
def extract_iperf_data(res):
if not res:
return None
bitrate_val = res.group('bitrate')
magnitude = res.group('magnitude')
return {
'bitrate_mbps': convert_to_mbps(bitrate_val, magnitude),
'jitter': res.group('jitter'),
'packetloss': res.group('packetloss'),
'bitrate_disp': f'{float(bitrate_val):.2f} {magnitude}bps'
}
def Iperf_analyzeV3TCPJson(filename, iperf_tcp_rate_target): def Iperf_analyzeV3TCPJson(filename, iperf_tcp_rate_target):
try: try:
with open(filename) as f: with open(filename) as f:
@@ -153,36 +130,53 @@ def Iperf_analyzeV3BIDIRJson(filename):
return (True, msg) return (True, msg)
def Iperf_analyzeV3UDP(filename, iperf_bitrate_threshold, iperf_packetloss_threshold, target_bitrate): def Iperf_analyzeV3UDP(filename, iperf_bitrate_threshold, iperf_packetloss_threshold, target_bitrate):
if not os.path.isfile(filename): if (not os.path.isfile(filename)):
return (False, 'Iperf3 UDP: Log file not present') return (False, 'Iperf3 UDP: Log file not present')
if os.path.getsize(filename) == 0: if (os.path.getsize(filename)==0):
return (False, 'Iperf3 UDP: Log file is empty') return (False, 'Iperf3 UDP: Log file is empty')
sender_bitrate = None
sender_data = None receiver_bitrate = None
receiver_data = None
with open(filename, 'r') as server_file: with open(filename, 'r') as server_file:
for line in server_file: for line in server_file.readlines():
res_sender = re.search(r'(?P<bitrate>[0-9\.]+)\s+(?P<magnitude>[kKMG]?)bits\/sec\s+(?P<jitter>[0-9\.]+\s+ms)\s+(?P<lostPack>-?\d+)/(?P<sentPack>-?\d+)\s+\((?P<packetloss>[0-9\.eE\-\+]+).*?\s+(sender)', line) res_sender = re.search(r'(?P<bitrate>[0-9\.]+)\s+(?P<unit>[KMG]?bits\/sec)\s+(?P<jitter>[0-9\.]+\s+ms)\s+(?P<lostPack>-?\d+)/(?P<sentPack>-?\d+) \((?P<lost>[0-9\.]+).*?\s+(sender)', line)
res_receiver = re.search(r'(?P<bitrate>[0-9\.]+)\s+(?P<magnitude>[kKMG]?)bits\/sec\s+(?P<jitter>[0-9\.]+\s+ms)\s+(?P<lostPack>-?\d+)/(?P<receivedPack>-?\d+)\s+\((?P<packetloss>[0-9\.eE\-\+]+)%\).*?(receiver)', line) res_receiver = re.search(r'(?P<bitrate>[0-9\.]+)\s+(?P<unit>[KMG]?bits\/sec)\s+(?P<jitter>[0-9\.]+\s+ms)\s+(?P<lostPack>-?\d+)/(?P<receivedPack>-?\d+)\s+\((?P<lost>[0-9\.]+)%\).*?(receiver)', line)
if res_sender: if res_sender is not None:
sender_data = extract_iperf_data(res_sender) sender_bitrate = res_sender.group('bitrate')
if res_receiver: sender_unit = res_sender.group('unit')
receiver_data = extract_iperf_data(res_receiver) sender_jitter = res_sender.group('jitter')
if not sender_data or not receiver_data: sender_lostPack = res_sender.group('lostPack')
return (False, 'Could not analyze iperf report') sender_sentPack = res_sender.group('sentPack')
sender_packetloss = res_sender.group('lost')
if res_receiver is not None:
receiver_bitrate = res_receiver.group('bitrate')
receiver_unit = res_receiver.group('unit')
receiver_jitter = res_receiver.group('jitter')
receiver_lostPack = res_receiver.group('lostPack')
receiver_receivedPack = res_receiver.group('receivedPack')
receiver_packetloss = res_receiver.group('lost')
br_perf = 100 * receiver_data['bitrate_mbps'] / float(target_bitrate) if receiver_bitrate is not None and sender_bitrate is not None:
br_perf_str = f'{br_perf:.2f}%' if sender_unit == 'Kbits/sec':
req_msg = f"Sender Bitrate : {sender_data['bitrate_disp']}" sender_bitrate = float(sender_bitrate) / 1000
bir_msg = f"Receiver Bitrate: {receiver_data['bitrate_disp']} ({br_perf_str})" if receiver_unit == 'Kbits/sec':
jit_msg = f"Jitter : {receiver_data['jitter']}" receiver_bitrate = float(receiver_bitrate) / 1000
pal_msg = f"Packet Loss : {receiver_data['packetloss']}%" br_perf = 100 * float(receiver_bitrate) / float(target_bitrate)
if br_perf < float(iperf_bitrate_threshold): br_perf = '%.2f ' % br_perf
bir_msg += f' (too low! < {iperf_bitrate_threshold}%)' sender_bitrate = '%.2f ' % float(sender_bitrate)
if float(receiver_data['packetloss']) > float(iperf_packetloss_threshold): receiver_bitrate = '%.2f ' % float(receiver_bitrate)
pal_msg += f' (too high! > {iperf_packetloss_threshold}%)' req_msg = f'Sender Bitrate : {sender_bitrate} Mbps'
result = br_perf >= float(iperf_bitrate_threshold) and float(receiver_data['packetloss']) <= float(iperf_packetloss_threshold) bir_msg = f'Receiver Bitrate: {receiver_bitrate} Mbps'
return (result, f'{req_msg}\n{bir_msg}\n{jit_msg}\n{pal_msg}') brl_msg = f'{br_perf}%'
jit_msg = f'Jitter : {receiver_jitter}'
pal_msg = f'Packet Loss : {receiver_packetloss} %'
if float(br_perf) < float(iperf_bitrate_threshold):
brl_msg = f'too low! < {iperf_bitrate_threshold}%'
if float(receiver_packetloss) > float(iperf_packetloss_threshold):
pal_msg += f' (too high! > {iperf_packetloss_threshold}%)'
result = float(br_perf) >= float(iperf_bitrate_threshold) and float(receiver_packetloss) <= float(iperf_packetloss_threshold)
return (result, f'{req_msg}\n{bir_msg} ({brl_msg})\n{jit_msg}\n{pal_msg}')
else:
return (False, 'Could not analyze iperf report')
def Iperf_analyzeV2UDP(server_filename, iperf_bitrate_threshold, iperf_packetloss_threshold, target_bitrate): def Iperf_analyzeV2UDP(server_filename, iperf_bitrate_threshold, iperf_packetloss_threshold, target_bitrate):
result = None result = None
@@ -196,9 +190,12 @@ def Iperf_analyzeV2UDP(server_filename, iperf_bitrate_threshold, iperf_packetlos
result = re.search(statusTemplate, str(line)) or result result = re.search(statusTemplate, str(line)) or result
if result is None: if result is None:
return (False, 'Could not parse server report!') return (False, 'Could not parse server report!')
bitrate_val = float(result.group('bitrate')) bitrate = float(result.group('bitrate'))
magnitude = result.group('magnitude') magn = result.group('magnitude')
bitrate = convert_to_mbps(bitrate_val, magnitude) if magn == "k" or magn == "K":
bitrate /= 1000
elif magn == "G": # we assume bitrate in Mbps, therefore it must be G now
bitrate *= 1000
jitter = float(result.group('jitter')) jitter = float(result.group('jitter'))
packetloss = float(result.group('packetloss')) packetloss = float(result.group('packetloss'))
br_perf = float(bitrate)/float(target_bitrate) * 100 br_perf = float(bitrate)/float(target_bitrate) * 100
@@ -216,7 +213,7 @@ def Iperf_analyzeV2UDP(server_filename, iperf_bitrate_threshold, iperf_packetlos
pal_msg += f' (too high! >{iperf_packetloss_threshold}%)' pal_msg += f' (too high! >{iperf_packetloss_threshold}%)'
return (result, f'{req_msg}\n{bir_msg}\n{brl_msg}\n{jit_msg}\n{pal_msg}') return (result, f'{req_msg}\n{bir_msg}\n{brl_msg}\n{jit_msg}\n{pal_msg}')
def Custom_Command(HTML, node, command): def Custom_Command(HTML, node, command, command_fail):
logging.info(f"Executing custom command on {node}") logging.info(f"Executing custom command on {node}")
cmd = cls_cmd.getConnection(node) cmd = cls_cmd.getConnection(node)
ret = cmd.run(command) ret = cmd.run(command)
@@ -224,59 +221,35 @@ def Custom_Command(HTML, node, command):
logging.debug(f"Custom_Command: {command} on node: {node} - {'OK, command succeeded' if ret.returncode == 0 else f'Error, return code: {ret.returncode}'}") logging.debug(f"Custom_Command: {command} on node: {node} - {'OK, command succeeded' if ret.returncode == 0 else f'Error, return code: {ret.returncode}'}")
status = 'OK' status = 'OK'
message = [] message = []
if ret.returncode != 0: if ret.returncode != 0 and not command_fail:
message = [ret.stdout]
logging.warning(f'Custom_Command output: {message}')
status = 'Warning'
if ret.returncode != 0 and command_fail:
message = [ret.stdout] message = [ret.stdout]
logging.error(f'Custom_Command failed: output: {message}') logging.error(f'Custom_Command failed: output: {message}')
status = 'KO' status = 'KO'
HTML.CreateHtmlTestRowQueue(command, status, message) HTML.CreateHtmlTestRowQueue(command, status, message)
return status == 'OK' or status == 'Warning' return status == 'OK' or status == 'Warning'
def Custom_Script(HTML, node, script, args): def Custom_Script(HTML, node, script, command_fail):
logging.info(f"Executing custom script on {node}") logging.info(f"Executing custom script on {node}")
with cls_cmd.getConnection(node) as c: ret = cls_cmd.runScript(node, script, 90)
ret = c.exec_script(script, 90, args)
logging.debug(f"Custom_Script: {script} on node: {node} - return code {ret.returncode}, output:\n{ret.stdout}") logging.debug(f"Custom_Script: {script} on node: {node} - return code {ret.returncode}, output:\n{ret.stdout}")
status = 'OK' status = 'OK'
message = [ret.stdout] message = [ret.stdout]
if ret.returncode != 0: if ret.returncode != 0 and not command_fail:
status = 'Warning'
if ret.returncode != 0 and command_fail:
status = 'KO' status = 'KO'
HTML.CreateHtmlTestRowQueue(script, status, message) HTML.CreateHtmlTestRowQueue(script, status, message)
return status == 'OK' or status == 'Warning' return status == 'OK' or status == 'Warning'
def IdleSleep(HTML, idle_sleep_time): def IdleSleep(HTML, idle_sleep_time):
logging.debug(f"sleep for {idle_sleep_time} seconds")
time.sleep(idle_sleep_time) time.sleep(idle_sleep_time)
HTML.CreateHtmlTestRow(f"{idle_sleep_time} sec", 'OK', CONST.ALL_PROCESSES_OK) HTML.CreateHtmlTestRow(f"{idle_sleep_time} sec", 'OK', CONST.ALL_PROCESSES_OK)
return True return True
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)
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:
details_json = archiveArtifact(ssh, ctx, f'{workdir}/desc-tests.json')
result_junit = archiveArtifact(ssh, ctx, f'{workdir}/results-run.xml')
archiveArtifact(ssh, ctx, f'{workdir}/physim_log.txt')
archiveArtifact(ssh, ctx, f'{workdir}/LastTestsFailed.log')
archiveArtifact(ssh, ctx, f'{workdir}/LastTest.log')
test_status, test_summary, test_result = cls_analysis.Analysis.analyze_physim(result_junit, details_json, ctx.logPath)
if test_summary:
if test_status:
HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK)
HTML.CreateHtmlTestRowPhySimTestResult(test_summary, test_result)
logging.info('\u001B[1m Physical Simulator Pass\u001B[0m')
else:
HTML.CreateHtmlTestRowQueue('At least one physical simulator test failed!', 'KO', ["See below for details"])
HTML.CreateHtmlTestRowPhySimTestResult(test_summary, test_result)
logging.error('\u001B[1m Physical Simulator Fail\u001B[0m')
else:
HTML.CreateHtmlTestRowQueue('Physical simulator failed', 'KO', [test_result])
logging.error('\u001B[1m Physical Simulator Fail\u001B[0m')
return test_status
#----------------------------------------------------------- #-----------------------------------------------------------
# OaiCiTest Class Definition # OaiCiTest Class Definition
#----------------------------------------------------------- #-----------------------------------------------------------
@@ -289,7 +262,9 @@ class OaiCiTest():
self.ranAllowMerge = False self.ranAllowMerge = False
self.ranTargetBranch = '' self.ranTargetBranch = ''
self.testCase_id = ''
self.testXMLfiles = [] self.testXMLfiles = []
self.desc = ''
self.ping_args = '' self.ping_args = ''
self.ping_packetloss_threshold = '' self.ping_packetloss_threshold = ''
self.ping_rttavg_threshold ='' self.ping_rttavg_threshold =''
@@ -297,15 +272,18 @@ class OaiCiTest():
self.iperf_packetloss_threshold = '' self.iperf_packetloss_threshold = ''
self.iperf_bitrate_threshold = '' self.iperf_bitrate_threshold = ''
self.iperf_profile = '' self.iperf_profile = ''
self.iperf_options = ''
self.iperf_tcp_rate_target = '' self.iperf_tcp_rate_target = ''
self.finalStatus = False self.finalStatus = False
self.air_interface=''
self.ue_ids = [] self.ue_ids = []
self.nodes = []
self.svr_node = None self.svr_node = None
self.svr_id = None self.svr_id = None
self.cmd_prefix = '' # prefix before {lte,nr}-uesoftmodem self.cmd_prefix = '' # prefix before {lte,nr}-uesoftmodem
def InitializeUE(self, node, HTML): def InitializeUE(self, HTML):
ues = [cls_module.Module_UE(n.strip(), node) for n in self.ue_ids] ues = [cls_module.Module_UE(n.strip()) for n in self.ue_ids]
messages = [] messages = []
with concurrent.futures.ThreadPoolExecutor(max_workers=64) as executor: with concurrent.futures.ThreadPoolExecutor(max_workers=64) as executor:
futures = [executor.submit(ue.initialize) for ue in ues] futures = [executor.submit(ue.initialize) for ue in ues]
@@ -316,8 +294,8 @@ class OaiCiTest():
HTML.CreateHtmlTestRowQueue('N/A', 'OK', messages) HTML.CreateHtmlTestRowQueue('N/A', 'OK', messages)
return True return True
def AttachUE(self, node, HTML): def AttachUE(self, HTML):
ues = [cls_module.Module_UE(ue_id, node) for ue_id in self.ue_ids] 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: with concurrent.futures.ThreadPoolExecutor(max_workers=64) as executor:
futures = [executor.submit(ue.attach) for ue in ues] futures = [executor.submit(ue.attach) for ue in ues]
attached = [f.result() for f in futures] attached = [f.result() for f in futures]
@@ -332,8 +310,8 @@ class OaiCiTest():
HTML.CreateHtmlTestRowQueue('N/A', 'KO', ["Could not retrieve UE IP address(es) or MTU(s) wrong!"]) HTML.CreateHtmlTestRowQueue('N/A', 'KO', ["Could not retrieve UE IP address(es) or MTU(s) wrong!"])
return success return success
def DetachUE(self, node, HTML): def DetachUE(self, HTML):
ues = [cls_module.Module_UE(ue_id, node) for ue_id in self.ue_ids] 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: with concurrent.futures.ThreadPoolExecutor(max_workers=64) as executor:
futures = [executor.submit(ue.detach) for ue in ues] futures = [executor.submit(ue.detach) for ue in ues]
[f.result() for f in futures] [f.result() for f in futures]
@@ -341,8 +319,8 @@ class OaiCiTest():
HTML.CreateHtmlTestRowQueue('NA', 'OK', messages) HTML.CreateHtmlTestRowQueue('NA', 'OK', messages)
return True return True
def DataDisableUE(self, node, HTML): def DataDisableUE(self, HTML):
ues = [cls_module.Module_UE(n.strip(), node) for n in self.ue_ids] ues = [cls_module.Module_UE(n.strip()) for n in self.ue_ids]
with concurrent.futures.ThreadPoolExecutor(max_workers=64) as executor: with concurrent.futures.ThreadPoolExecutor(max_workers=64) as executor:
futures = [executor.submit(ue.dataDisable) for ue in ues] futures = [executor.submit(ue.dataDisable) for ue in ues]
status = [f.result() for f in futures] status = [f.result() for f in futures]
@@ -355,8 +333,8 @@ class OaiCiTest():
HTML.CreateHtmlTestRowQueue('N/A', 'KO', ["Could not disable UE data!"]) HTML.CreateHtmlTestRowQueue('N/A', 'KO', ["Could not disable UE data!"])
return success return success
def DataEnableUE(self, node, HTML): def DataEnableUE(self, HTML):
ues = [cls_module.Module_UE(n.strip(), node) for n in self.ue_ids] ues = [cls_module.Module_UE(n.strip()) for n in self.ue_ids]
logging.debug(f'disabling data for UEs {ues}') logging.debug(f'disabling data for UEs {ues}')
with concurrent.futures.ThreadPoolExecutor(max_workers=64) as executor: with concurrent.futures.ThreadPoolExecutor(max_workers=64) as executor:
futures = [executor.submit(ue.dataEnable) for ue in ues] futures = [executor.submit(ue.dataEnable) for ue in ues]
@@ -370,8 +348,8 @@ class OaiCiTest():
HTML.CreateHtmlTestRowQueue('N/A', 'KO', ["Could not enable UE data!"]) HTML.CreateHtmlTestRowQueue('N/A', 'KO', ["Could not enable UE data!"])
return success return success
def CheckStatusUE(self, node, HTML): def CheckStatusUE(self,HTML):
ues = [cls_module.Module_UE(n.strip(), node) for n in self.ue_ids] ues = [cls_module.Module_UE(n.strip()) for n in self.ue_ids]
logging.debug(f'checking status of UEs {ues}') logging.debug(f'checking status of UEs {ues}')
messages = [] messages = []
with concurrent.futures.ThreadPoolExecutor(max_workers=64) as executor: with concurrent.futures.ThreadPoolExecutor(max_workers=64) as executor:
@@ -380,7 +358,7 @@ class OaiCiTest():
HTML.CreateHtmlTestRowQueue('NA', 'OK', messages) HTML.CreateHtmlTestRowQueue('NA', 'OK', messages)
return True return True
def Ping_common(self, ctx, cn, ue): def Ping_common(self, cn, ue, logPath):
ping_status = 0 ping_status = 0
ueIP = ue.getIP() ueIP = ue.getIP()
if not ueIP: if not ueIP:
@@ -388,12 +366,13 @@ class OaiCiTest():
svrIP = cn.getIP() svrIP = cn.getIP()
if not svrIP: if not svrIP:
return (False, f"CN {cn.getName()} has no IP address") return (False, f"CN {cn.getName()} has no IP address")
ping_log_file = f'/tmp/ping_{ue.getName()}.log' ping_log_file = f'ping_{self.testCase_id}_{ue.getName()}.log'
ping_time = re.findall(r"-c *(\d+)",str(self.ping_args)) ping_time = re.findall(r"-c *(\d+)",str(self.ping_args))
local_ping_log_file = f'{logPath}/{ping_log_file}'
if re.search('%cn_ip%', self.ping_args) or re.search(r'[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+', self.ping_args): if re.search('%cn_ip%', self.ping_args) or re.search(r'[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+', self.ping_args):
raise Exception(f"ping_args should not have IP address: {self.ping_args}") raise Exception(f"ping_args should not have IP address: {self.ping_args}")
interface = f'-I {ue.getIFName()}' if ue.getIFName() else '' interface = f'-I {ue.getIFName()}' if ue.getIFName() else ''
ping_cmd = f'{ue.getCmdPrefix()} ping {interface} {self.ping_args} {svrIP} 2>&1 | tee {ping_log_file}' ping_cmd = f'{ue.getCmdPrefix()} ping {interface} {self.ping_args} {svrIP} 2>&1 | tee /tmp/{ping_log_file}'
cmd = cls_cmd.getConnection(ue.getHost()) cmd = cls_cmd.getConnection(ue.getHost())
response = cmd.run(ping_cmd, timeout=int(ping_time[0])*1.5) response = cmd.run(ping_cmd, timeout=int(ping_time[0])*1.5)
ue_header = f'UE {ue.getName()} ({ueIP})' ue_header = f'UE {ue.getName()} ({ueIP})'
@@ -401,7 +380,8 @@ class OaiCiTest():
message = ue_header + ': ping crashed: TIMEOUT?' message = ue_header + ': ping crashed: TIMEOUT?'
return (False, message) return (False, message)
local_ping_log_file = archiveArtifact(cmd, ctx, ping_log_file) #copy the ping log file to have it locally for analysis (ping stats)
cmd.copyin(src=f'/tmp/{ping_log_file}', tgt=local_ping_log_file)
cmd.close() cmd.close()
with open(local_ping_log_file, 'r') as f: with open(local_ping_log_file, 'r') as f:
@@ -441,13 +421,18 @@ class OaiCiTest():
return (True, message) return (True, message)
def Ping(self, ctx, node, HTML, infra_file="ci_infra.yaml"): def Ping(self, HTML, CONTAINERS, infra_file="ci_infra.yaml"):
if self.ue_ids == [] or self.svr_id == None: if self.ue_ids == [] or self.svr_id == None:
raise Exception("no module names in self.ue_ids or/and self.svr_id provided") 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] # Creating destination log folder if needed on the python executor workspace
with cls_cmd.getConnection('localhost') as local:
ymlPath = CONTAINERS.yamlPath[0].split('/')
logPath = f'{os.getcwd()}/../cmake_targets/log/{ymlPath[-1]}'
local.run(f'mkdir -p {logPath}', silent=True)
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) cn = cls_corenetwork.CoreNetwork(self.svr_id, self.svr_node, filename=infra_file)
with concurrent.futures.ThreadPoolExecutor(max_workers=64) as executor: with concurrent.futures.ThreadPoolExecutor(max_workers=64) as executor:
futures = [executor.submit(self.Ping_common, ctx, cn, ue) for ue in ues] futures = [executor.submit(self.Ping_common, cn, ue, logPath) for ue in ues]
results = [f.result() for f in futures] results = [f.result() for f in futures]
# each result in results is a tuple, first member goes to successes, second to messages # each result in results is a tuple, first member goes to successes, second to messages
successes, messages = map(list, zip(*results)) successes, messages = map(list, zip(*results))
@@ -468,7 +453,7 @@ class OaiCiTest():
HTML.CreateHtmlTestRowQueue(self.ping_args, 'KO', messages) HTML.CreateHtmlTestRowQueue(self.ping_args, 'KO', messages)
return success return success
def Iperf_Module(self, ctx, cn, ue, idx, ue_num): def Iperf_Module(self, cn, ue, idx, ue_num, logPath):
ueIP = ue.getIP() ueIP = ue.getIP()
if not ueIP: if not ueIP:
return (False, f"UE {ue.getName()} has no IP address") return (False, f"UE {ue.getName()} has no IP address")
@@ -481,7 +466,7 @@ class OaiCiTest():
serverReport = "" serverReport = ""
udpIperf = re.search('-u', iperf_opt) is not None udpIperf = re.search('-u', iperf_opt) is not None
bidirIperf = re.search('--bidir', iperf_opt) is not None bidirIperf = re.search('--bidir', iperf_opt) is not None
client_filename = f'/tmp/iperf_client_{ue.getName()}.log' client_filename = f'iperf_client_{self.testCase_id}_{ue.getName()}.log'
if udpIperf: if udpIperf:
target_bitrate, iperf_opt = Iperf_ComputeModifiedBW(idx, ue_num, self.iperf_profile, self.iperf_args) target_bitrate, iperf_opt = Iperf_ComputeModifiedBW(idx, ue_num, self.iperf_profile, self.iperf_args)
# note: for UDP testing we don't want to use json report - reports 0 Mbps received bitrate # note: for UDP testing we don't want to use json report - reports 0 Mbps received bitrate
@@ -496,16 +481,14 @@ class OaiCiTest():
port = 5002 + idx port = 5002 + idx
# note: some core setups start an iperf3 server automatically, indicated in ci_infra by runIperf3Server: False` # note: some core setups start an iperf3 server automatically, indicated in ci_infra by runIperf3Server: False`
t = iperf_time * 2.5 t = iperf_time * 2.5
cmd_ue.run(f'rm {client_filename}', reportNonZero=False, silent=True) cmd_ue.run(f'rm /tmp/{client_filename}', reportNonZero=False, silent=True)
if cn.runIperf3Server(): 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_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) cmd_ue.run(f'{ue.getCmdPrefix()} timeout -vk3 {t} {iperf_ue} -B {ueIP} -c {svrIP} -p {port} {iperf_opt} {jsonReport} {serverReport} -O 5 >> /tmp/{client_filename}', timeout=t)
dest_filename = archiveArtifact(cmd_ue, ctx, client_filename) # note: copy iperf3 log to the current directory for log analysis and log collection
dest_filename = f'{logPath}/{client_filename}'
cmd_ue.copyin(f'/tmp/{client_filename}', dest_filename)
cmd_ue.run(f'rm /tmp/{client_filename}', reportNonZero=False, silent=True)
if udpIperf: if udpIperf:
status, msg = Iperf_analyzeV3UDP(dest_filename, self.iperf_bitrate_threshold, self.iperf_packetloss_threshold, target_bitrate) status, msg = Iperf_analyzeV3UDP(dest_filename, self.iperf_bitrate_threshold, self.iperf_packetloss_threshold, target_bitrate)
elif bidirIperf: elif bidirIperf:
@@ -515,15 +498,20 @@ class OaiCiTest():
return (status, f'{ue_header}\n{msg}') return (status, f'{ue_header}\n{msg}')
def Iperf(self, ctx, node, HTML, infra_file="ci_infra.yaml"): def Iperf(self, HTML, CONTAINERS, 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}"') 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: if self.ue_ids == [] or self.svr_id == None:
raise Exception("no module names in self.ue_ids or/and self.svr_id provided") 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] # create log directory on executor node
with cls_cmd.getConnection('localhost') as local:
ymlPath = CONTAINERS.yamlPath[0].split('/')
logPath = f'{os.getcwd()}/../cmake_targets/log/{ymlPath[-1]}'
local.run(f'mkdir -p {logPath}', silent=True)
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) cn = cls_corenetwork.CoreNetwork(self.svr_id, self.svr_node, filename=infra_file)
with concurrent.futures.ThreadPoolExecutor(max_workers=64) as executor: 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)] futures = [executor.submit(self.Iperf_Module, cn, ue, i, len(ues), logPath) for i, ue in enumerate(ues)]
results = [f.result() for f in futures] results = [f.result() for f in futures]
# each result in results is a tuple, first member goes to successes, second to messages # each result in results is a tuple, first member goes to successes, second to messages
successes, messages = map(list, zip(*results)) successes, messages = map(list, zip(*results))
@@ -544,10 +532,10 @@ class OaiCiTest():
HTML.CreateHtmlTestRowQueue(self.iperf_args, 'KO', messages) HTML.CreateHtmlTestRowQueue(self.iperf_args, 'KO', messages)
return success return success
def Iperf2_Unidir(self, ctx, node, HTML, infra_file="ci_infra.yaml"): def Iperf2_Unidir(self, HTML, CONTAINERS, infra_file="ci_infra.yaml"):
if self.ue_ids == [] or self.svr_id == None or len(self.ue_ids) != 1: 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") 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) cn = cls_corenetwork.CoreNetwork(self.svr_id, self.svr_node, filename=infra_file)
ueIP = ue.getIP() ueIP = ue.getIP()
if not ueIP: if not ueIP:
@@ -555,17 +543,23 @@ class OaiCiTest():
svrIP = cn.getIP() svrIP = cn.getIP()
if not svrIP: if not svrIP:
return False return False
server_filename = f'/tmp/iperf_server_{ue.getName()}.log' server_filename = f'iperf_server_{self.testCase_id}_{ue.getName()}.log'
ymlPath = CONTAINERS.yamlPath[0].split('/')
logPath = f'{os.getcwd()}/../cmake_targets/log/{ymlPath[-1]}'
iperf_time = Iperf_ComputeTime(self.iperf_args) iperf_time = Iperf_ComputeTime(self.iperf_args)
target_bitrate, iperf_opt = Iperf_ComputeModifiedBW(0, 1, self.iperf_profile, self.iperf_args) target_bitrate, iperf_opt = Iperf_ComputeModifiedBW(0, 1, self.iperf_profile, self.iperf_args)
t = iperf_time*2.5 t = iperf_time*2.5
with cls_cmd.getConnection('localhost') as local:
local.run(f'mkdir -p {logPath}')
with cls_cmd.getConnection(ue.getHost()) as cmd_ue, cls_cmd.getConnection(cn.getHost()) as cmd_svr: with cls_cmd.getConnection(ue.getHost()) as cmd_ue, cls_cmd.getConnection(cn.getHost()) as cmd_svr:
cmd_ue.run(f'rm {server_filename}', reportNonZero=False) cmd_ue.run(f'rm /tmp/{server_filename}', reportNonZero=False)
cmd_ue.run(f'{ue.getCmdPrefix()} timeout -vk3 {t} iperf -B {ueIP} -s -u -i1 >> {server_filename} &', timeout=t) cmd_ue.run(f'{ue.getCmdPrefix()} timeout -vk3 {t} iperf -B {ueIP} -s -u -i1 >> /tmp/{server_filename} &', timeout=t)
cmd_svr.run(f'{cn.getCmdPrefix()} timeout -vk3 {t} iperf -c {ueIP} -B {svrIP} {iperf_opt} -i1 >> /dev/null', timeout=t) cmd_svr.run(f'{cn.getCmdPrefix()} timeout -vk3 {t} iperf -c {ueIP} -B {svrIP} {iperf_opt} -i1 >> /dev/null', timeout=t)
localPath = f'{os.getcwd()}' localPath = f'{os.getcwd()}'
local = archiveArtifact(cmd_ue, ctx, server_filename) # note: copy iperf2 log to the directory for log collection
success, msg = Iperf_analyzeV2UDP(local, self.iperf_bitrate_threshold, self.iperf_packetloss_threshold, target_bitrate) cmd_ue.copyin(f'/tmp/{server_filename}', f'{logPath}/{server_filename}')
cmd_ue.run(f'rm /tmp/{server_filename}', reportNonZero=False)
success, msg = Iperf_analyzeV2UDP(f'{logPath}/{server_filename}', self.iperf_bitrate_threshold, self.iperf_packetloss_threshold, target_bitrate)
ue_header = f'UE {ue.getName()} ({ueIP})' ue_header = f'UE {ue.getName()} ({ueIP})'
logging.info(f'\u001B[1;37;45m iperf result for {ue_header}\u001B[0m') logging.info(f'\u001B[1;37;45m iperf result for {ue_header}\u001B[0m')
for l in msg.split('\n'): for l in msg.split('\n'):
@@ -576,17 +570,288 @@ class OaiCiTest():
HTML.CreateHtmlTestRowQueue(self.iperf_args, 'KO', [f'{ue_header}\n{msg}']) HTML.CreateHtmlTestRowQueue(self.iperf_args, 'KO', [f'{ue_header}\n{msg}'])
return success return success
def TerminateUE(self, ctx, node, HTML): def AnalyzeLogFile_UE(self, UElogFile,HTML,RAN):
ues = [cls_module.Module_UE(n.strip(), node) for n in self.ue_ids] 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, HTML):
ues = [cls_module.Module_UE(n.strip()) for n in self.ue_ids]
with concurrent.futures.ThreadPoolExecutor(max_workers=64) as executor: with concurrent.futures.ThreadPoolExecutor(max_workers=64) as executor:
futures = [executor.submit(ue.terminate, ctx) for ue in ues] futures = [executor.submit(ue.terminate) for ue in ues]
archives = [f.result() for f in futures] archives = [f.result() for f in futures]
archive_info = [f'Log at: {a}' if a else 'No log available' for a in archives] archive_info = [f'Log at: {a}' if a else 'No log available' for a in archives]
messages = [f"UE {ue.getName()}: {log}" for (ue, log) in zip(ues, archive_info)] messages = [f"UE {ue.getName()}: {log}" for (ue, log) in zip(ues, archive_info)]
HTML.CreateHtmlTestRowQueue(f'N/A', 'OK', messages) HTML.CreateHtmlTestRowQueue(f'N/A', 'OK', messages)
return True return True
def DeployCoreNetwork(cn_id, ctx, HTML): def DeployCoreNetwork(cn_id, HTML):
core_name = cn_id.strip() core_name = cn_id.strip()
cn = cls_corenetwork.CoreNetwork(core_name) cn = cls_corenetwork.CoreNetwork(core_name)
success, output = cn.deploy() success, output = cn.deploy()
@@ -600,11 +865,41 @@ class OaiCiTest():
HTML.CreateHtmlTestRowQueue(core_name, 'KO', [msg]) HTML.CreateHtmlTestRowQueue(core_name, 'KO', [msg])
return success return success
def UndeployCoreNetwork(cn_id, ctx, HTML): def UndeployCoreNetwork(cn_id, HTML):
# Ping, Iperf, DeployObject put logs into a path based on YAML. We
# can't do this here (because there is no yaml), so hardcode a path for
# "cn_logs" for the moment
logPath = f'{os.getcwd()}/../cmake_targets/log/cn_logs'
with cls_cmd.getConnection('localhost') as local:
local.run(f'mkdir -p {logPath}', silent=True)
core_name = cn_id.strip() core_name = cn_id.strip()
cn = cls_corenetwork.CoreNetwork(core_name) cn = cls_corenetwork.CoreNetwork(core_name)
logs, output = cn.undeploy(ctx=ctx) logs, output = cn.undeploy(log_dir=logPath)
logging.info(f"undeployed core network {core_name}, logs {logs}, output:\n{output}") logging.info(f"undeployed core network {core_name}, logs {logs}, output:\n{output}")
message = "Log files:\n" + "\n".join([os.path.basename(l) for l in logs]) message = "Log files: " + ", ".join([os.path.basename(l) for l in logs])
HTML.CreateHtmlTestRowQueue(core_name, 'OK', [message]) HTML.CreateHtmlTestRowQueue(core_name, 'OK', [message])
return True return True
def LogCollectBuild(self,RAN):
# Some pipelines are using "none" IP / Credentials
# In that case, just forget about it
if RAN.eNBIPAddress == 'none':
sys.exit(0)
if (RAN.eNBIPAddress != '' and RAN.eNBUserName != '' and RAN.eNBPassword != ''):
IPAddress = RAN.eNBIPAddress
UserName = RAN.eNBUserName
Password = RAN.eNBPassword
SourceCodePath = RAN.eNBSourceCodePath
else:
sys.exit('Insufficient Parameter')
with cls_cmd.getConnection(IPAddress) as cmd:
d = f'{SourceCodePath}/cmake_targets'
cmd.run(f'rm -f {d}/build.log.zip')
cmd.run(f'cd {d} && zip -r build.log.zip build_log_*/*')
def ShowTestID(self):
logging.info(f'\u001B[1m----------------------------------------\u001B[0m')
logging.info(f'\u001B[1m Test ID: {self.testCase_id} \u001B[0m')
logging.info(f'\u001B[1m {self.desc} \u001B[0m')
logging.info(f'\u001B[1m----------------------------------------\u001B[0m')

View File

@@ -43,7 +43,6 @@ from pathlib import Path
import helpreadme as HELP import helpreadme as HELP
import constants as CONST import constants as CONST
import cls_cmd import cls_cmd
from cls_ci_helper import archiveArtifact
#----------------------------------------------------------- #-----------------------------------------------------------
# Class Declaration # Class Declaration
@@ -76,27 +75,35 @@ class StaticCodeAnalysis():
self.ranAllowMerge = False self.ranAllowMerge = False
self.ranCommitID = '' self.ranCommitID = ''
self.ranTargetBranch = '' self.ranTargetBranch = ''
self.eNBIPAddress = ''
self.eNBUserName = ''
self.eNBPassword = ''
self.eNBSourceCodePath = '' self.eNBSourceCodePath = ''
def CppCheckAnalysis(self, ctx, node, HTML): def CppCheckAnalysis(self, HTML):
if self.ranRepository == '' or self.ranBranch == '' or self.ranCommitID == '': if self.ranRepository == '' or self.ranBranch == '' or self.ranCommitID == '':
HELP.GenericHelp(CONST.Version) HELP.GenericHelp(CONST.Version)
sys.exit('Insufficient Parameter') sys.exit('Insufficient Parameter')
lIpAddr = self.eNBIPAddress
lUserName = self.eNBUserName
lPassWord = self.eNBPassword
lSourcePath = self.eNBSourceCodePath lSourcePath = self.eNBSourceCodePath
if not lSourcePath or not node: if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '':
raise ValueError(f"{lSourcePath=} {node=}") HELP.GenericHelp(CONST.Version)
logging.debug('Building on server: ' + node) sys.exit('Insufficient Parameter')
cmd = cls_cmd.getConnection(node) logging.debug('Building on server: ' + lIpAddr)
cmd = cls_cmd.getConnection(lIpAddr)
self.testCase_id = HTML.testCase_id
# on RedHat/CentOS .git extension is mandatory # 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: if result is not None:
full_ran_repo_name = self.ranRepository.replace('git/', 'git') full_ran_repo_name = self.ranRepository.replace('git/', 'git')
else: else:
full_ran_repo_name = self.ranRepository + '.git' full_ran_repo_name = self.ranRepository + '.git'
cmd.cd(lSourcePath) cmd.cd(lSourcePath)
logDir = f'{lSourcePath}/cmake_targets/log' logDir = f'{lSourcePath}/cmake_targets/build_log_{self.testCase_id}'
cmd.run(f'mkdir -p {logDir}') cmd.run(f'mkdir -p {logDir}')
cmd.run('docker image rm oai-cppcheck:bionic oai-cppcheck:focal') cmd.run('docker image rm oai-cppcheck:bionic oai-cppcheck:focal')
cmd.run(f'sed -e "s@xenial@bionic@" {lSourcePath}/ci-scripts/docker/Dockerfile.cppcheck.xenial > {lSourcePath}/ci-scripts/docker/Dockerfile.cppcheck.bionic') cmd.run(f'sed -e "s@xenial@bionic@" {lSourcePath}/ci-scripts/docker/Dockerfile.cppcheck.xenial > {lSourcePath}/ci-scripts/docker/Dockerfile.cppcheck.bionic')
@@ -105,23 +112,33 @@ class StaticCodeAnalysis():
cmd.run(f'docker build --tag oai-cppcheck:focal --file {lSourcePath}/ci-scripts/docker/Dockerfile.cppcheck.focal . > {logDir}/cppcheck-focal.txt 2>&1') cmd.run(f'docker build --tag oai-cppcheck:focal --file {lSourcePath}/ci-scripts/docker/Dockerfile.cppcheck.focal . > {logDir}/cppcheck-focal.txt 2>&1')
cmd.run('docker image rm oai-cppcheck:bionic oai-cppcheck:focal') cmd.run('docker image rm oai-cppcheck:bionic oai-cppcheck:focal')
bionic = archiveArtifact(cmd, ctx, f'{logDir}/cppcheck-bionic.txt') # Analyzing the logs
focal = archiveArtifact(cmd, ctx, f'{logDir}/cppcheck-focal.txt') cmd.copyin(f'{logDir}/cppcheck-bionic.txt', 'cppcheck-bionic.txt')
cmd.copyin(f'{logDir}/cppcheck-focal.txt', 'cppcheck-focal.txt')
cmd.close() cmd.close()
CCR = CppCheckResults() CCR = CppCheckResults()
CCR_ref = CppCheckResults() CCR_ref = CppCheckResults()
vId = 0 vId = 0
for variant in CCR.variants: for variant in CCR.variants:
filename = ctx.baseFilename() + '-cppcheck-'+ variant + '.txt' refAvailable = False
logging.info(f"will check file '{filename}'") if self.ranAllowMerge:
if not os.path.isfile(filename): refFolder = str(Path.home()) + '/cppcheck-references'
raise FileNotFoundError(f"{filename} is not a file") if (os.path.isfile(refFolder + '/cppcheck-'+ variant + '.txt')):
else: refAvailable = True
with open(refFolder + '/cppcheck-'+ variant + '.txt', 'r') as refFile:
for line in refFile:
ret = re.search(' (?P<nb_errors>[0-9\.]+) errors', str(line))
if ret is not None:
CCR_ref.nbErrors[vId] = int(ret.group('nb_errors'))
ret = re.search(' (?P<nb_warnings>[0-9\.]+) warnings', str(line))
if ret is not None:
CCR_ref.nbWarnings[vId] = int(ret.group('nb_warnings'))
if (os.path.isfile('./cppcheck-'+ variant + '.txt')):
xmlStart = False xmlStart = False
with open(filename, 'r') as logfile: with open('./cppcheck-'+ variant + '.txt', 'r') as logfile:
for line in 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: if ret is not None:
CCR.versions[vId] = ret.group('version') CCR.versions[vId] = ret.group('version')
if re.search('RUN cat cmake_targets/log/cppcheck.xml', str(line)) is not None: if re.search('RUN cat cmake_targets/log/cppcheck.xml', str(line)) is not None:
@@ -168,6 +185,26 @@ class StaticCodeAnalysis():
vMsg += ' Wrong Scanf Nb Args: ' + str(CCR.nbWrongScanfArg[vId]) + '\n' vMsg += ' Wrong Scanf Nb Args: ' + str(CCR.nbWrongScanfArg[vId]) + '\n'
for vLine in vMsg.split('\n'): for vLine in vMsg.split('\n'):
logging.debug(vLine) logging.debug(vLine)
if self.ranAllowMerge and refAvailable:
if CCR_ref.nbErrors[vId] == CCR.nbErrors[vId]:
logging.debug(' No change in number of errors')
elif CCR_ref.nbErrors[vId] > CCR.nbErrors[vId]:
logging.debug(' Good! Decrease in number of errors')
else:
logging.debug(' Bad! increase in number of errors')
if CCR_ref.nbWarnings[vId] == CCR.nbWarnings[vId]:
logging.debug(' No change in number of warnings')
elif CCR_ref.nbWarnings[vId] > CCR.nbWarnings[vId]:
logging.debug(' Good! Decrease in number of warnings')
else:
logging.debug(' Bad! increase in number of warnings')
# Create new reference file
if not self.ranAllowMerge:
refFolder = str(Path.home()) + '/cppcheck-references'
if not os.path.isdir(refFolder):
os.mkdir(refFolder)
with open(refFolder + '/cppcheck-'+ variant + '.txt', 'w') as refFile:
refFile.write(vMsg)
vId += 1 vId += 1
HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK)
@@ -176,16 +213,22 @@ class StaticCodeAnalysis():
return True return True
def LicenceAndFormattingCheck(self, ctx, node, HTML): def LicenceAndFormattingCheck(self, HTML):
# Workspace is no longer recreated from scratch. # Workspace is no longer recreated from scratch.
# It implies that this method shall be called last within a build pipeline # It implies that this method shall be called last within a build pipeline
# where workspace is already created # where workspace is already created
lIpAddr = self.eNBIPAddress
lUserName = self.eNBUserName
lPassWord = self.eNBPassword
lSourcePath = self.eNBSourceCodePath lSourcePath = self.eNBSourceCodePath
if not node or not lSourcePath: if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '':
raise ValueError(f"{lSourcePath=} {node=}") HELP.GenericHelp(CONST.Version)
logging.debug('Building on server: ' + node) sys.exit('Insufficient Parameter')
cmd = cls_cmd.getConnection(node) logging.debug('Building on server: ' + lIpAddr)
cmd = cls_cmd.getConnection(lIpAddr)
self.testCase_id = HTML.testCase_id
check_options = '' check_options = ''
if self.ranAllowMerge: if self.ranAllowMerge:
check_options = f'--build-arg MERGE_REQUEST=true --build-arg SRC_BRANCH={self.ranBranch}' check_options = f'--build-arg MERGE_REQUEST=true --build-arg SRC_BRANCH={self.ranBranch}'
@@ -195,20 +238,21 @@ class StaticCodeAnalysis():
else: else:
check_options += f' --build-arg TARGET_BRANCH={self.ranTargetBranch}' check_options += f' --build-arg TARGET_BRANCH={self.ranTargetBranch}'
logDir = f'{lSourcePath}/cmake_targets/log/' logDir = f'{lSourcePath}/cmake_targets/build_log_{self.testCase_id}'
cmd.run(f'mkdir -p {logDir}') cmd.run(f'mkdir -p {logDir}')
cmd.run('docker image rm oai-formatting-check:latest') cmd.run('docker image rm oai-formatting-check:latest')
cmd.run(f'docker build --target oai-formatting-check --tag oai-formatting-check:latest {check_options} --file {lSourcePath}/ci-scripts/docker/Dockerfile.formatting.ubuntu {lSourcePath} > {logDir}/oai-formatting-check.txt 2>&1') cmd.run(f'docker build --target oai-formatting-check --tag oai-formatting-check:latest {check_options} --file {lSourcePath}/ci-scripts/docker/Dockerfile.formatting.bionic {lSourcePath} > {logDir}/oai-formatting-check.txt 2>&1')
cmd.run('docker image rm oai-formatting-check:latest') cmd.run('docker image rm oai-formatting-check:latest')
cmd.run('docker image prune --force') cmd.run('docker image prune --force')
cmd.run('docker volume prune --force') cmd.run('docker volume prune --force')
file = archiveArtifact(cmd, ctx, f'{logDir}/oai-formatting-check.txt') # Analyzing the logs
cmd.copyin(f'{logDir}/oai-formatting-check.txt', 'oai-formatting-check.txt')
cmd.close() cmd.close()
finalStatus = 0 finalStatus = 0
if (os.path.isfile(file)): if (os.path.isfile('./oai-formatting-check.txt')):
analyzed = False analyzed = False
nbFilesNotFormatted = 0 nbFilesNotFormatted = 0
listFiles = False listFiles = False
@@ -219,7 +263,7 @@ class StaticCodeAnalysis():
gnuGplLicenceFiles = [] gnuGplLicenceFiles = []
suspectLicence = False suspectLicence = False
suspectLicenceFiles = [] suspectLicenceFiles = []
with open(file, 'r') as logfile: with open('./oai-formatting-check.txt', 'r') as logfile:
for line in logfile: for line in logfile:
ret = re.search('./ci-scripts/checkCodingFormattingRules.sh', str(line)) ret = re.search('./ci-scripts/checkCodingFormattingRules.sh', str(line))
if ret is not None: if ret is not None:

View File

@@ -200,11 +200,9 @@ RUs = (
} }
); );
rfsimulator = ( rfsimulator: {
{
serveraddr = "server"; serveraddr = "server";
} };
);
THREAD_STRUCT = ( THREAD_STRUCT = (
{ {

View File

@@ -233,11 +233,9 @@ RUs =
} }
); );
rfsimulator = ( rfsimulator: {
{
serveraddr = "server"; serveraddr = "server";
} };
);
THREAD_STRUCT = THREAD_STRUCT =
( (

View File

@@ -233,11 +233,9 @@ RUs =
} }
); );
rfsimulator = ( rfsimulator: {
{
serveraddr = "server"; serveraddr = "server";
} };
);
THREAD_STRUCT = THREAD_STRUCT =
( (

View File

@@ -233,11 +233,9 @@ RUs =
} }
); );
rfsimulator = ( rfsimulator: {
{
serveraddr = "server"; serveraddr = "server";
} };
);
THREAD_STRUCT = THREAD_STRUCT =
( (

View File

@@ -233,11 +233,9 @@ RUs =
} }
); );
rfsimulator = ( rfsimulator: {
{
serveraddr = "server"; serveraddr = "server";
} };
);
THREAD_STRUCT = THREAD_STRUCT =
( (

View File

@@ -362,11 +362,9 @@ RUs = (
} }
); );
rfsimulator = ( rfsimulator: {
{
serveraddr = "server"; serveraddr = "server";
} };
);
THREAD_STRUCT = ( THREAD_STRUCT = (
{ {

View File

@@ -15,7 +15,7 @@ gNBs =
// Tracking area code, 0x0000 and 0xfffe are reserved values // Tracking area code, 0x0000 and 0xfffe are reserved values
tracking_area_code = 1; tracking_area_code = 1;
plmn_list = ({ mcc = 208; mnc = 99; mnc_length = 2; snssaiList = ({ sst = 1, sd = 0xffffff }) }); plmn_list = ({ mcc = 208; mnc = 99; mnc_length = 2; snssaiList = ({ sst = 1, sd = 0xffffff }) });
@include "neighbour-config.conf"
nr_cellid = 12345678L; nr_cellid = 12345678L;
@@ -23,7 +23,9 @@ gNBs =
local_s_address = "192.168.71.150"; local_s_address = "192.168.71.150";
remote_s_address = "192.168.71.171"; remote_s_address = "192.168.71.171";
local_s_portc = 501;
local_s_portd = 2153; local_s_portd = 2153;
remote_s_portc = 500;
remote_s_portd = 2153; remote_s_portd = 2153;
# ------- SCTP definitions # ------- SCTP definitions

View File

@@ -23,7 +23,9 @@ gNBs =
local_s_address = "127.0.0.4"; local_s_address = "127.0.0.4";
remote_s_address = "127.0.0.5"; remote_s_address = "127.0.0.5";
local_s_portc = 501;
local_s_portd = 2153; local_s_portd = 2153;
remote_s_portc = 500;
remote_s_portd = 2153; remote_s_portd = 2153;
# ------- SCTP definitions # ------- SCTP definitions

View File

@@ -1,76 +0,0 @@
Active_gNBs = ( "CU-OAI");
# Asn1_verbosity, choice in: none, info, annoying
Asn1_verbosity = "none";
gNBs =
(
{
////////// Identification parameters:
gNB_ID = 0xe88;
# cell_type = "CELL_MACRO_GNB";
gNB_name = "CU-OAI";
// Tracking area code, 0x0000 and 0xfffe are reserved values
tracking_area_code = 1;
plmn_list = ({ mcc = 001; mnc = 03; mnc_length = 2; snssaiList = ({ sst = 1 }) });
@include "neighbour-config-ho.conf"
nr_cellid = 12345678L;
tr_s_preference = "f1";
local_s_address = "172.21.19.98";
remote_s_address = "0.0.0.0";
local_s_portd = 2153;
remote_s_portd = 2154;
# ------- 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.109"; });
NETWORK_INTERFACES :
{
GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.19.98/22";
GNB_IPV4_ADDRESS_FOR_NGU = "172.21.19.98/22";
GNB_PORT_FOR_S1U = 2152; # Spec 2152
};
}
);
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" );
# 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 = "yes";
};
log_config :
{
global_log_level ="info";
pdcp_log_level ="info";
rrc_log_level ="info";
f1ap_log_level ="info";
ngap_log_level ="info";
};

View File

@@ -1,82 +0,0 @@
Active_gNBs = ( "cu-cp-0");
# Asn1_verbosity, choice in: none, info, annoying
Asn1_verbosity = "none";
gNBs =
(
{
////////// Identification parameters:
gNB_ID = 0xe00;
# cell_type = "CELL_MACRO_GNB";
gNB_name = "cu-cp-0";
// 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, sd = 0xffffff }) });
@include "neighbour-config.conf"
nr_cellid = 12345678L;
tr_s_preference = "f1";
local_s_address = "192.168.71.150";
remote_s_address = "192.168.71.171";
local_s_portd = 2153;
remote_s_portd = 2153;
# ------- SCTP definitions
SCTP :
{
# Number of streams to use in input/output
SCTP_INSTREAMS = 2;
SCTP_OUTSTREAMS = 2;
};
////////// AMF parameters:
amf_ip_address = ({ ipv4 = "192.168.71.132"; });
E1_INTERFACE =
(
{
type = "cp";
ipv4_cucp = "192.168.71.150";
port_cucp = 38462;
ipv4_cuup = "0.0.0.0"; # multiple CU-UPs
port_cuup = 38462;
}
)
NETWORK_INTERFACES :
{
GNB_IPV4_ADDRESS_FOR_NG_AMF = "192.168.71.150";
};
}
);
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";
pdcp_log_level = "info";
rrc_log_level = "info";
f1ap_log_level = "info";
ngap_log_level = "info";
};

View File

@@ -23,7 +23,9 @@ gNBs =
local_s_address = "192.168.71.150"; local_s_address = "192.168.71.150";
remote_s_address = "0.0.0.0"; # multiple DUs remote_s_address = "0.0.0.0"; # multiple DUs
local_s_portc = 501;
local_s_portd = 2152; local_s_portd = 2152;
remote_s_portc = 500;
remote_s_portd = 2152; remote_s_portd = 2152;
# ------- SCTP definitions # ------- SCTP definitions

View File

@@ -23,7 +23,9 @@ gNBs =
local_s_address = "127.0.0.4"; local_s_address = "127.0.0.4";
remote_s_address = "127.0.0.5"; remote_s_address = "127.0.0.5";
local_s_portc = 501;
local_s_portd = 2153; local_s_portd = 2153;
remote_s_portc = 500;
remote_s_portd = 2153; remote_s_portd = 2153;
# ------- SCTP definitions # ------- SCTP definitions
@@ -56,14 +58,6 @@ gNBs =
} }
); );
pdcp = {
drb = {
sn_size = "len18bits"
t_reordering = "ms100"
discard_timer = "infinity"
}
}
security = { security = {
# preferred ciphering algorithms # preferred ciphering algorithms
# the first one of the list that an UE supports in chosen # the first one of the list that an UE supports in chosen

View File

@@ -22,7 +22,9 @@ gNBs =
local_s_address = "192.168.72.161"; local_s_address = "192.168.72.161";
remote_s_address = "192.168.72.171"; remote_s_address = "192.168.72.171";
local_s_portc = 501;
local_s_portd = 2153; local_s_portd = 2153;
remote_s_portc = 500;
remote_s_portd = 2153; remote_s_portd = 2153;
# ------- SCTP definitions # ------- SCTP definitions

View File

@@ -22,7 +22,9 @@ gNBs =
local_s_address = "127.0.0.6"; local_s_address = "127.0.0.6";
remote_s_address = "127.0.0.5"; remote_s_address = "127.0.0.5";
local_s_portc = 501;
local_s_portd = 2153; local_s_portd = 2153;
remote_s_portc = 500;
remote_s_portd = 2153; remote_s_portd = 2153;
# ------- SCTP definitions # ------- SCTP definitions

View File

@@ -86,6 +86,9 @@ gNBs =
#powerRampingStep #powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6 # 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 1; powerRampingStep = 1;
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 4;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
@@ -160,7 +163,9 @@ MACRLCs = (
tr_n_preference = "f1"; tr_n_preference = "f1";
local_n_address = "127.0.0.5"; local_n_address = "127.0.0.5";
remote_n_address = "127.0.0.4"; remote_n_address = "127.0.0.4";
local_n_portc = 500;
local_n_portd = 2153; local_n_portd = 2153;
remote_n_portc = 501;
remote_n_portd = 2153; remote_n_portd = 2153;
pusch_TargetSNRx10 = 200; pusch_TargetSNRx10 = 200;
pucch_TargetSNRx10 = 200; pucch_TargetSNRx10 = 200;

View File

@@ -84,6 +84,9 @@ gNBs =
#powerRampingStep #powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6 # 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 1; powerRampingStep = 1;
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 4;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
@@ -165,7 +168,9 @@ MACRLCs = (
tr_n_preference = "f1"; tr_n_preference = "f1";
local_n_address = "192.168.71.171"; local_n_address = "192.168.71.171";
remote_n_address = "192.168.71.150"; remote_n_address = "192.168.71.150";
local_n_portc = 500;
local_n_portd = 2153; local_n_portd = 2153;
remote_n_portc = 501;
remote_n_portd = 2153; remote_n_portd = 2153;
pusch_TargetSNRx10 = 200; pusch_TargetSNRx10 = 200;
pucch_TargetSNRx10 = 200; pucch_TargetSNRx10 = 200;
@@ -197,15 +202,13 @@ RUs = (
} }
); );
rfsimulator = ( rfsimulator: {
{ serveraddr = "server";
serveraddr = "server";
serverport = 4043; serverport = 4043;
options = (); #("saviq"); or/and "chanmod" options = (); #("saviq"); or/and "chanmod"
modelname = "AWGN"; modelname = "AWGN";
IQfile = "/tmp/rfsimulator.iqs"; IQfile = "/tmp/rfsimulator.iqs"
} }
);
log_config: { log_config: {
global_log_level = "info"; global_log_level = "info";

View File

@@ -23,6 +23,7 @@ gNBs =
////////// Physical parameters: ////////// Physical parameters:
min_rxtxtime = 2; min_rxtxtime = 2;
do_CSIRS = 1;
do_SRS = 1; do_SRS = 1;
servingCellConfigCommon = ( servingCellConfigCommon = (
@@ -33,9 +34,11 @@ gNBs =
# downlinkConfigCommon # downlinkConfigCommon
#frequencyInfoDL #frequencyInfoDL
absoluteFrequencySSB = 641280; # GSCN: 7929, Freq: 3619.200 MHz # this is 3600 MHz + 43 PRBs@30kHz SCS (same as initial BWP)
absoluteFrequencySSB = 641280;
dl_frequencyBand = 78; dl_frequencyBand = 78;
dl_absoluteFrequencyPointA = 640752; # 3611.280 MHz # this is 3600 MHz
dl_absoluteFrequencyPointA = 640008;
#scs-SpecificCarrierList #scs-SpecificCarrierList
dl_offstToCarrier = 0; dl_offstToCarrier = 0;
# subcarrierSpacing # subcarrierSpacing
@@ -44,12 +47,13 @@ gNBs =
dl_carrierBandwidth = 106; dl_carrierBandwidth = 106;
#initialDownlinkBWP #initialDownlinkBWP
#genericParameters #genericParameters
initialDLBWPlocationAndBandwidth = 13750; # RBstart=0, L=51 (275*(L-1))+RBstart # this is RBstart=27,L=48 (275*(L-1))+RBstart
initialDLBWPlocationAndBandwidth = 28875; # 6366 12925 12956 28875 12952
# subcarrierSpacing # subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
initialDLBWPsubcarrierSpacing = 1; initialDLBWPsubcarrierSpacing = 1;
#pdcch-ConfigCommon #pdcch-ConfigCommon
initialDLBWPcontrolResourceSetZero = 10; initialDLBWPcontrolResourceSetZero = 12;
initialDLBWPsearchSpaceZero = 0; initialDLBWPsearchSpaceZero = 0;
#uplinkConfigCommon #uplinkConfigCommon
@@ -64,7 +68,7 @@ gNBs =
pMax = 20; pMax = 20;
#initialUplinkBWP #initialUplinkBWP
#genericParameters #genericParameters
initialULBWPlocationAndBandwidth = 13750; # RBstart=0, L=51 (275*(L-1))+RBstart initialULBWPlocationAndBandwidth = 28875;
# subcarrierSpacing # subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
initialULBWPsubcarrierSpacing = 1; initialULBWPsubcarrierSpacing = 1;
@@ -82,6 +86,9 @@ gNBs =
#powerRampingStep #powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6 # 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 1; powerRampingStep = 1;
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 4;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
@@ -134,23 +141,17 @@ gNBs =
# pattern1 # pattern1
# dl_UL_TransmissionPeriodicity # dl_UL_TransmissionPeriodicity
# 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10 # 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10
dl_UL_TransmissionPeriodicity = 5; dl_UL_TransmissionPeriodicity = 6;
nrofDownlinkSlots = 3; nrofDownlinkSlots = 7;
nrofDownlinkSymbols = 10; nrofDownlinkSymbols = 6;
nrofUplinkSlots = 1; nrofUplinkSlots = 2;
nrofUplinkSymbols = 2; nrofUplinkSymbols = 4;
ssPBCH_BlockPower = -25; ssPBCH_BlockPower = -25;
} }
); );
first_active_bwp = 1;
bwp_list = (
{ scs = 1; bwpStart = 0; bwpSize = 106;},
{ scs = 1; bwpStart = 0; bwpSize = 36;},
{ scs = 1; bwpStart = 40; bwpSize = 50;}
);
# ------- SCTP definitions # ------- SCTP definitions
SCTP : SCTP :
@@ -162,31 +163,6 @@ gNBs =
} }
); );
rlc = {
srb = {
t_poll_retransmit = "ms45"
t_reassembly = "ms25"
t_status_prohibit = "ms0"
poll_pdu = "infinity"
poll_byte = "infinity"
max_retx_threshold = "t8"
sn_field_length = "size12"
}
drb_am = {
t_poll_retransmit = "ms45"
t_reassembly = "ms15"
t_status_prohibit = "ms15"
poll_pdu = "p64"
poll_byte = "kB500"
max_retx_threshold = "t32"
sn_field_length = "size18"
}
drb_um = {
t_reassembly = "ms15"
sn_field_length = "size12"
}
}
MACRLCs = ( MACRLCs = (
{ {
num_cc = 1; num_cc = 1;
@@ -194,7 +170,9 @@ MACRLCs = (
tr_n_preference = "f1"; tr_n_preference = "f1";
local_n_address = "127.0.0.5"; local_n_address = "127.0.0.5";
remote_n_address = "127.0.0.4"; remote_n_address = "127.0.0.4";
local_n_portc = 500;
local_n_portd = 2153; local_n_portd = 2153;
remote_n_portc = 501;
remote_n_portd = 2153; remote_n_portd = 2153;
pusch_TargetSNRx10 = 200; pusch_TargetSNRx10 = 200;
pucch_TargetSNRx10 = 200; pucch_TargetSNRx10 = 200;

View File

@@ -1,210 +0,0 @@
Active_gNBs = ( "DU0-OAI");
# Asn1_verbosity, choice in: none, info, annoying
Asn1_verbosity = "none";
gNBs =
(
{
////////// Identification parameters:
gNB_ID = 0xe88;
gNB_DU_ID = 0xe00;
gNB_name = "DU0-OAI";
// Tracking area code, 0x0000 and 0xfffe are reserved values
tracking_area_code = 1 ;
plmn_list = ({ mcc = 001; mnc = 03; mnc_length = 2; snssaiList = ({ sst = 1; }) });
nr_cellid = 12345678L;
////////// Physical parameters:
servingCellConfigCommon = (
{
#spCellConfigCommon
physCellId = 0;
# downlinkConfigCommon
#frequencyInfoDL
# 4186.56 MHz
absoluteFrequencySSB = 679104;
dl_frequencyBand = 77;
# 4175.82 MHz
dl_absoluteFrequencyPointA = 678388;
#scs-SpecificCarrierList
dl_offstToCarrier = 0;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
dl_subcarrierSpacing = 1;
dl_carrierBandwidth = 51;
#initialDownlinkBWP
#genericParameters
# this is RBstart=27,L=48 (275*(L-1))+RBstart
initialDLBWPlocationAndBandwidth = 13750;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
initialDLBWPsubcarrierSpacing = 1;
#pdcch-ConfigCommon
initialDLBWPcontrolResourceSetZero = 12;
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 = 51;
pMax = 20;
#initialUplinkBWP
#genericParameters
initialULBWPlocationAndBandwidth = 13750;
# 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 = 13;
preambleReceivedTargetPower = -96;
#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 = 14;
#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 definitions
SCTP :
{
# Number of streams to use in input/output
SCTP_INSTREAMS = 2;
SCTP_OUTSTREAMS = 2;
};
}
);
MACRLCs = (
{
num_cc = 1;
tr_s_preference = "local_L1";
tr_n_preference = "f1";
local_n_address = "172.21.19.98";
remote_n_address = "172.21.19.98";
local_n_portd = 2154;
remote_n_portd = 2153;
pusch_TargetSNRx10 = 200;
pucch_TargetSNRx10 = 230;
# ul_prbblack_SNR_threshold = 10;
}
);
L1s = (
{
num_cc = 1;
tr_n_preference = "local_mac";
prach_dtx_threshold = 100;
pucch0_dtx_threshold = 10;
max_ldpc_iterations = 20;
ofdm_offset_divisor = 8; #set this to UINT_MAX for offset 0
}
);
RUs = (
{
local_rf = "yes"
nb_tx = 1
nb_rx = 1
att_tx = 0;
att_rx = 0;
sl_ahead = 3;
bands = [77];
max_pdschReferenceSignalPower = -27;
max_rxgain = 114;
eNB_instances = [0];
# USRP is connected to an Octoclock in order to establish synchroniation with other USRPs
clock_src = "external";
time_src = "external";
}
);
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 ="info";
};

View File

@@ -1,210 +0,0 @@
Active_gNBs = ( "DU1-OAI");
# Asn1_verbosity, choice in: none, info, annoying
Asn1_verbosity = "none";
gNBs =
(
{
////////// Identification parameters:
gNB_ID = 0xe88;
gNB_DU_ID = 0xe01;
gNB_name = "DU1-OAI";
// Tracking area code, 0x0000 and 0xfffe are reserved values
tracking_area_code = 1 ;
plmn_list = ({ mcc = 001; mnc = 03; mnc_length = 2; snssaiList = ({ sst = 1; }) });
nr_cellid = 11111111L;
////////// Physical parameters:
servingCellConfigCommon = (
{
#spCellConfigCommon
physCellId = 1;
# downlinkConfigCommon
#frequencyInfoDL
# 4186.56 MHz
absoluteFrequencySSB = 679104;
dl_frequencyBand = 77;
# 4175.82 MHz
dl_absoluteFrequencyPointA = 678388;
#scs-SpecificCarrierList
dl_offstToCarrier = 0;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
dl_subcarrierSpacing = 1;
dl_carrierBandwidth = 51;
#initialDownlinkBWP
#genericParameters
# this is RBstart=27,L=48 (275*(L-1))+RBstart
initialDLBWPlocationAndBandwidth = 13750;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
initialDLBWPsubcarrierSpacing = 1;
#pdcch-ConfigCommon
initialDLBWPcontrolResourceSetZero = 12;
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 = 51;
pMax = 20;
#initialUplinkBWP
#genericParameters
initialULBWPlocationAndBandwidth = 13750;
# 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 = 13;
preambleReceivedTargetPower = -96;
#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 = 14;
#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 = 2;
# 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 definitions
SCTP :
{
# Number of streams to use in input/output
SCTP_INSTREAMS = 2;
SCTP_OUTSTREAMS = 2;
};
}
);
MACRLCs = (
{
num_cc = 1;
tr_s_preference = "local_L1";
tr_n_preference = "f1";
local_n_address = "172.21.19.99";
remote_n_address = "172.21.19.98";
local_n_portd = 2154;
remote_n_portd = 2153;
pusch_TargetSNRx10 = 200;
pucch_TargetSNRx10 = 230;
# ul_prbblack_SNR_threshold = 10;
}
);
L1s = (
{
num_cc = 1;
tr_n_preference = "local_mac";
prach_dtx_threshold = 100;
pucch0_dtx_threshold = 10;
max_ldpc_iterations = 20;
ofdm_offset_divisor = 8; #set this to UINT_MAX for offset 0
}
);
RUs = (
{
local_rf = "yes"
nb_tx = 1
nb_rx = 1
att_tx = 0;
att_rx = 0;
sl_ahead = 3;
bands = [77];
max_pdschReferenceSignalPower = -27;
max_rxgain = 114;
eNB_instances = [0];
# USRP is connected to an Octoclock in order to establish synchroniation with other USRPs
clock_src = "external";
time_src = "external";
}
);
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 ="info";
};

View File

@@ -27,15 +27,14 @@ RUs = ({
eNB_instances = [0]; eNB_instances = [0];
}); });
rfsimulator = ( rfsimulator :
{ {
serveraddr = "server"; serveraddr = "server";
serverport = 4043; serverport = 4043;
options = (); #("saviq"); or/and "chanmod" options = (); #("saviq"); or/and "chanmod"
modelname = "AWGN"; modelname = "AWGN";
IQfile = "/tmp/rfsimulator.iqs"; IQfile = "/tmp/rfsimulator.iqs";
} };
);
log_config: { log_config: {
global_log_level = "info"; global_log_level = "info";

View File

@@ -16,6 +16,8 @@ gNBs =
nr_cellid = 12345678L; nr_cellid = 12345678L;
////////// Physical parameters: ////////// Physical parameters:
sib1_tda = 5;
min_rxtxtime = 6; min_rxtxtime = 6;
servingCellConfigCommon = ( servingCellConfigCommon = (

View File

@@ -85,6 +85,9 @@ gNBs =
#powerRampingStep #powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6 # 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 1; powerRampingStep = 1;
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 5;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;

View File

@@ -13,7 +13,16 @@ gNBs =
// Tracking area code, 0x0000 and 0xfffe are reserved values // Tracking area code, 0x0000 and 0xfffe are reserved values
tracking_area_code = 1; 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; nr_cellid = 12345678L;
@@ -23,7 +32,7 @@ gNBs =
pdsch_AntennaPorts_N1 = 2; pdsch_AntennaPorts_N1 = 2;
pusch_AntennaPorts = 2; pusch_AntennaPorts = 2;
do_CSIRS = 1; do_CSIRS = 1;
do_SRS = 1; do_SRS = 0;
min_rxtxtime = 2; min_rxtxtime = 2;
servingCellConfigCommon = ( servingCellConfigCommon = (
@@ -34,12 +43,19 @@ gNBs =
# downlinkConfigCommon # downlinkConfigCommon
#frequencyInfoDL #frequencyInfoDL
# center frequency = 3350.01 MHz # this is 3300.24 + 134*12*30e3 = 3348.48 MHz (5G NR GSCN: 7741)
# selected SSB frequency = 3349.92 MHz absoluteFrequencySSB = 649920;
absoluteFrequencySSB = 623328; #652860; #should be 649920
#647520;
#647540;
#649920;
#650208;
#647540;
dl_frequencyBand = 78; dl_frequencyBand = 78;
# frequency point A = 3300.87 MHz # this is 3300.24 MHz
dl_absoluteFrequencyPointA = 620058; dl_absoluteFrequencyPointA = 646724;
#649104;
#646724;
#scs-SpecificCarrierList #scs-SpecificCarrierList
dl_offstToCarrier = 0; dl_offstToCarrier = 0;
# subcarrierSpacing # subcarrierSpacing
@@ -88,6 +104,9 @@ gNBs =
#powerRampingStep #powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6 # 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 1; powerRampingStep = 1;
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 5;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
@@ -146,7 +165,7 @@ gNBs =
nrofUplinkSlots = 3; #1; nrofUplinkSlots = 3; #1;
nrofUplinkSymbols = 0; nrofUplinkSymbols = 0;
ssPBCH_BlockPower = -15; ssPBCH_BlockPower = -25;
} }
); );
@@ -167,8 +186,8 @@ gNBs =
NETWORK_INTERFACES : NETWORK_INTERFACES :
{ {
GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.16.53"; GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.16.202";
GNB_IPV4_ADDRESS_FOR_NGU = "172.21.16.53"; GNB_IPV4_ADDRESS_FOR_NGU = "172.21.16.202";
GNB_PORT_FOR_S1U = 2152; # Spec 2152 GNB_PORT_FOR_S1U = 2152; # Spec 2152
}; };
@@ -177,19 +196,20 @@ gNBs =
MACRLCs = ( MACRLCs = (
{ {
num_cc = 1; num_cc = 1;
remote_s_address = "127.0.0.1"; // pnf addr [!] remote_s_address = "127.0.0.1"; // pnf addr [!]
local_s_address = "127.0.0.2"; // vnf addr local_s_address = "127.0.0.2"; // vnf addr
local_s_portc = 50001; // vnf p5 port local_s_portc = 50001; // vnf p5 port
remote_s_portc = 50000; // pnf p5 port [!] remote_s_portc = 50000; // pnf p5 port [!]
local_s_portd = 50011; // vnf p7 port [!] local_s_portd = 50011; // vnf p7 port [!]
remote_s_portd = 50010; // pnf p7 port [!] remote_s_portd = 50010; // pnf p7 port [!]
tr_s_preference = "aerial"; tr_s_preference = "aerial";
tr_n_preference = "local_RRC"; tr_n_preference = "local_RRC";
pusch_TargetSNRx10 = 280; # 150; pusch_TargetSNRx10 = 200; # 150;
pucch_TargetSNRx10 = 200; #200; pucch_TargetSNRx10 = 200; #200;
dl_max_mcs = 28; ulsch_max_frame_inactivity = 10;
ul_max_mcs = 28; dl_max_mcs = 28;
ul_max_mcs = 28;
} }
); );
@@ -213,13 +233,13 @@ security = {
log_config : log_config :
{ {
global_log_level ="info"; global_log_level ="info";
hw_log_level ="info"; hw_log_level ="info";
phy_log_level ="info"; phy_log_level ="info";
mac_log_level ="info"; mac_log_level ="info";
rlc_log_level ="info"; rlc_log_level ="info";
pdcp_log_level ="info"; pdcp_log_level ="info";
rrc_log_level ="info"; rrc_log_level ="info";
ngap_log_level ="debug"; ngap_log_level ="debug";
f1ap_log_level ="debug"; f1ap_log_level ="debug";
}; };

View File

@@ -1,227 +0,0 @@
Active_gNBs = ( "gNB-OAI");
# Asn1_verbosity, choice in: none, info, annoying
Asn1_verbosity = "none";
nfapi = "AERIAL";
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; snssaiList = ({ sst = 1; }); });
nr_cellid = 12345678L;
uess_agg_levels = [0,6,0,0,0];
////////// Physical parameters:
pdsch_AntennaPorts_XP = 2;
pdsch_AntennaPorts_N1 = 2;
pusch_AntennaPorts = 2;
do_CSIRS = 1;
do_SRS = 1;
min_rxtxtime = 2;
force_UL256qam_off = 1;
servingCellConfigCommon = (
{
#spCellConfigCommon
physCellId = 0;
# downlinkConfigCommon
#frequencyInfoDL
# center frequency = 3350.01 MHz
# selected SSB frequency = 3349.92 MHz
absoluteFrequencySSB = 623328;
dl_frequencyBand = 78;
# frequency point A = 3300.87 MHz
dl_absoluteFrequencyPointA = 620058;
#scs-SpecificCarrierList
dl_offstToCarrier = 0;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
dl_subcarrierSpacing = 1;
dl_carrierBandwidth = 273;
#initialDownlinkBWP
#genericParameters
# this is RBstart=0,L=162 (275*(275-L+1))+(274-RBstart))
initialDLBWPlocationAndBandwidth = 1099;
#
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
initialDLBWPsubcarrierSpacing = 1;
#pdcch-ConfigCommon
initialDLBWPcontrolResourceSetZero = 12;
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 = 273;
pMax = 20;
#initialUplinkBWP
#genericParameters
initialULBWPlocationAndBandwidth = 1099;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
initialULBWPsubcarrierSpacing = 1;
#rach-ConfigCommon
#rach-ConfigGeneric
prach_ConfigurationIndex = 159;# testMAC 158; OAI gNB 98
#prach_msg1_FDM
#0 = one, 1=two, 2=four, 3=eight
prach_msg1_FDM = 0;
prach_msg1_FrequencyStart = 0;
zeroCorrelationZoneConfig = 12;
preambleReceivedTargetPower = -96;
#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 = 5;
nrofDownlinkSlots = 1;
nrofDownlinkSymbols = 10;
nrofUplinkSlots = 3;
nrofUplinkSymbols = 0;
ssPBCH_BlockPower = -10;
}
);
# ------- 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.103"; });
NETWORK_INTERFACES :
{
GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.16.53";
GNB_IPV4_ADDRESS_FOR_NGU = "172.21.16.53";
GNB_PORT_FOR_S1U = 2152; # Spec 2152
};
}
);
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 = 260; # 150;
pucch_TargetSNRx10 = 200; #200;
dl_max_mcs = 28;
ul_max_mcs = 28;
ul_min_mcs = 16;
}
);
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";
};

View File

@@ -1,226 +0,0 @@
Active_gNBs = ( "gNB-OAI");
# Asn1_verbosity, choice in: none, info, annoying
Asn1_verbosity = "none";
nfapi = "AERIAL";
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 = 001; mnc = 04; mnc_length = 2; snssaiList = ({sst = 1;});});
nr_cellid = 12345678L;
////////// Physical parameters:
pdsch_AntennaPorts_XP = 2;
pdsch_AntennaPorts_N1 = 2;
pusch_AntennaPorts = 2;
do_CSIRS = 0;
do_SRS = 0;
min_rxtxtime = 6;
servingCellConfigCommon = (
{
#spCellConfigCommon
physCellId = 0;
# downlinkConfigCommon
#frequencyInfoDL
# center frequency = 3350.01 MHz
# selected SSB frequency = 3349.92 MHz
absoluteFrequencySSB = 623328;
dl_frequencyBand = 78;
# frequency point A = 3300.87 MHz
dl_absoluteFrequencyPointA = 622398;
#scs-SpecificCarrierList
dl_offstToCarrier = 0;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
dl_subcarrierSpacing = 1;
dl_carrierBandwidth = 78;
#initialDownlinkBWP
#genericParameters
# this is RBstart=0,L=162 (275*(275-L+1))+(274-RBstart))
initialDLBWPlocationAndBandwidth = 21175;
#
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
initialDLBWPsubcarrierSpacing = 1;
#pdcch-ConfigCommon
initialDLBWPcontrolResourceSetZero = 12;
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 = 78;
pMax = 20;
#initialUplinkBWP
#genericParameters
initialULBWPlocationAndBandwidth = 21175;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
initialULBWPsubcarrierSpacing = 1;
#rach-ConfigCommon
#rach-ConfigGeneric
prach_ConfigurationIndex = 148;# testMAC 158; OAI gNB 98
#prach_msg1_FDM
#0 = one, 1=two, 2=four, 3=eight
prach_msg1_FDM = 0;
prach_msg1_FrequencyStart = 0;
zeroCorrelationZoneConfig = 12;
preambleReceivedTargetPower = -96;
#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; #5;
nrofDownlinkSlots = 6; #3;
nrofDownlinkSymbols = 10; #6;
nrofUplinkSlots = 3; #1;
nrofUplinkSymbols = 0;
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 = "172.21.6.103"; });
NETWORK_INTERFACES :
{
GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.16.53";
GNB_IPV4_ADDRESS_FOR_NGU = "172.21.16.53";
GNB_PORT_FOR_S1U = 2152; # Spec 2152
};
}
);
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 = 180; # 150;
pucch_TargetSNRx10 = 180; #200;
ulsch_max_frame_inactivity = 10;
dl_max_mcs = 28;
ul_max_mcs = 28;
}
);
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";
}

View File

@@ -84,6 +84,9 @@ gNBs =
#powerRampingStep #powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6 # 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 1; powerRampingStep = 1;
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 4;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
@@ -191,11 +194,10 @@ RUs = (
} }
); );
rfsimulator = ( rfsimulator: {
{
serveraddr = "server"; serveraddr = "server";
} };
);
security = { security = {
# preferred ciphering algorithms # preferred ciphering algorithms

View File

@@ -83,6 +83,9 @@ gNBs =
#powerRampingStep #powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6 # 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 1; powerRampingStep = 1;
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 5;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
@@ -195,16 +198,14 @@ RUs = (
max_pdschReferenceSignalPower = -27; max_pdschReferenceSignalPower = -27;
max_rxgain = 50; max_rxgain = 50;
eNB_instances = [0]; eNB_instances = [0];
sl_ahead = 3;
sdr_addrs = "addr=192.168.10.2,second_addr=192.168.20.2"; sdr_addrs = "addr=192.168.10.2,second_addr=192.168.20.2";
} }
); );
rfsimulator = ( rfsimulator: {
{
serveraddr = "server"; serveraddr = "server";
} };
);
security = { security = {
# preferred ciphering algorithms # preferred ciphering algorithms

View File

@@ -31,11 +31,11 @@ gNBs =
# downlinkConfigCommon # downlinkConfigCommon
#frequencyInfoDL #frequencyInfoDL
# this is 4412.64 MHz # this is 3319.68 MHz
absoluteFrequencySSB = 694176; absoluteFrequencySSB = 621312;
dl_frequencyBand = 79; dl_frequencyBand = 78;
# this is 4400.94 MHz # this is 3300.6 MHz
dl_absoluteFrequencyPointA = 693396; dl_absoluteFrequencyPointA = 620040;
#scs-SpecificCarrierList #scs-SpecificCarrierList
dl_offstToCarrier = 0; dl_offstToCarrier = 0;
# subcarrierSpacing # subcarrierSpacing
@@ -55,7 +55,7 @@ gNBs =
#uplinkConfigCommon #uplinkConfigCommon
#frequencyInfoUL #frequencyInfoUL
ul_frequencyBand = 79; ul_frequencyBand = 78;
#scs-SpecificCarrierList #scs-SpecificCarrierList
ul_offstToCarrier = 0; ul_offstToCarrier = 0;
# subcarrierSpacing # subcarrierSpacing
@@ -83,6 +83,9 @@ gNBs =
#powerRampingStep #powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6 # 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 1; powerRampingStep = 1;
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 4;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;

View File

@@ -31,11 +31,11 @@ gNBs =
# downlinkConfigCommon # downlinkConfigCommon
#frequencyInfoDL #frequencyInfoDL
# this is 4435.68 MHz # this is 3600 MHz + 43 PRBs@30kHz SCS (same as initial BWP)
absoluteFrequencySSB = 695712; absoluteFrequencySSB = 621312;
dl_frequencyBand = 79; dl_frequencyBand = 78;
# this is 4400.94 MHz # this is 3600 MHz
dl_absoluteFrequencyPointA = 693396; dl_absoluteFrequencyPointA = 620040;
#scs-SpecificCarrierList #scs-SpecificCarrierList
dl_offstToCarrier = 0; dl_offstToCarrier = 0;
# subcarrierSpacing # subcarrierSpacing
@@ -55,7 +55,7 @@ gNBs =
#uplinkConfigCommon #uplinkConfigCommon
#frequencyInfoUL #frequencyInfoUL
ul_frequencyBand = 79; ul_frequencyBand = 78;
#scs-SpecificCarrierList #scs-SpecificCarrierList
ul_offstToCarrier = 0; ul_offstToCarrier = 0;
# subcarrierSpacing # subcarrierSpacing
@@ -83,6 +83,9 @@ gNBs =
#powerRampingStep #powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6 # 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 1; powerRampingStep = 1;
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 4;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;

View File

@@ -33,11 +33,11 @@ gNBs =
# downlinkConfigCommon # downlinkConfigCommon
#frequencyInfoDL #frequencyInfoDL
# this is 4458.72 MHz # this is 3600 MHz + 43 PRBs@30kHz SCS (same as initial BWP)
absoluteFrequencySSB = 697248; absoluteFrequencySSB = 621312;
dl_frequencyBand = 79; dl_frequencyBand = 78;
# this is 4400.94 MHz # this is 3600 MHz
dl_absoluteFrequencyPointA = 693396; dl_absoluteFrequencyPointA = 620040;
#scs-SpecificCarrierList #scs-SpecificCarrierList
dl_offstToCarrier = 0; dl_offstToCarrier = 0;
# subcarrierSpacing # subcarrierSpacing
@@ -57,7 +57,7 @@ gNBs =
#uplinkConfigCommon #uplinkConfigCommon
#frequencyInfoUL #frequencyInfoUL
ul_frequencyBand = 79; ul_frequencyBand = 78;
#scs-SpecificCarrierList #scs-SpecificCarrierList
ul_offstToCarrier = 0; ul_offstToCarrier = 0;
# subcarrierSpacing # subcarrierSpacing
@@ -85,6 +85,9 @@ gNBs =
#powerRampingStep #powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6 # 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 1; powerRampingStep = 1;
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 4;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;

View File

@@ -78,6 +78,9 @@ gNBs =
#powerRampingStep #powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6 # 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 1; powerRampingStep = 1;
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 5;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
@@ -166,10 +169,10 @@ gNBs =
NETWORK_INTERFACES : NETWORK_INTERFACES :
{ {
GNB_IPV4_ADDRESS_FOR_S1_MME = "172.21.16.109"; GNB_IPV4_ADDRESS_FOR_S1_MME = "192.168.68.194";
GNB_IPV4_ADDRESS_FOR_S1U = "172.21.16.109"; GNB_IPV4_ADDRESS_FOR_S1U = "192.168.68.194";
GNB_PORT_FOR_S1U = 2152; # Spec 2152 GNB_PORT_FOR_S1U = 2152; # Spec 2152
GNB_IPV4_ADDRESS_FOR_X2C = "172.21.16.109"; GNB_IPV4_ADDRESS_FOR_X2C = "192.168.68.194";
GNB_PORT_FOR_X2C = 36422; # Spec 36422 GNB_PORT_FOR_X2C = 36422; # Spec 36422
}; };

View File

@@ -83,6 +83,9 @@ gNBs =
#powerRampingStep #powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6 # 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 1; powerRampingStep = 1;
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 5;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;

View File

@@ -16,6 +16,7 @@ gNBs =
////////// Physical parameters: ////////// Physical parameters:
sib1_tda = 5;
min_rxtxtime = 6; min_rxtxtime = 6;
num_dlharq = 32; num_dlharq = 32;
num_ulharq = 32; num_ulharq = 32;
@@ -84,6 +85,9 @@ gNBs =
#powerRampingStep #powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6 # 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 1; powerRampingStep = 1;
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 4;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
@@ -146,8 +150,6 @@ gNBs =
#ext2 #ext2
#ntn_Config_r17 #ntn_Config_r17
# This can be of values {s5, s10, s15, s20, s25, s30, s35, s40, s45, s50, s55, s60, s120, s180, s240, s900}
ntn-UlSyncValidityDuration-r17 = 5;
cellSpecificKoffset_r17 = 40; cellSpecificKoffset_r17 = 40;
ta-Common-r17 = 4627000; # 18.84 ms ta-Common-r17 = 4627000; # 18.84 ms
ta-CommonDrift-r17 = -230000; # -46 µs/s ta-CommonDrift-r17 = -230000; # -46 µs/s
@@ -198,6 +200,7 @@ MACRLCs = (
num_cc = 1; num_cc = 1;
tr_s_preference = "local_L1"; tr_s_preference = "local_L1";
tr_n_preference = "local_RRC"; tr_n_preference = "local_RRC";
# ulsch_max_frame_inactivity = 0;
pusch_TargetSNRx10 = 150; pusch_TargetSNRx10 = 150;
pucch_TargetSNRx10 = 200; pucch_TargetSNRx10 = 200;
dl_max_mcs = 9; dl_max_mcs = 9;
@@ -234,15 +237,14 @@ RUs = (
} }
); );
rfsimulator = ( rfsimulator :
{ {
serveraddr = "server"; serveraddr = "server";
serverport = 4043; serverport = 4043;
options = ("chanmod"); #("saviq"); or/and "chanmod" options = ("chanmod"); #("saviq"); or/and "chanmod"
prop_delay = 20; prop_delay = 20;
IQfile = "/tmp/rfsimulator.iqs"; IQfile = "/tmp/rfsimulator.iqs";
} };
);
channelmod = { channelmod = {
max_chan=10; max_chan=10;

View File

@@ -16,7 +16,7 @@ gNBs =
////////// Physical parameters: ////////// Physical parameters:
CSI_report_type = "ssb_sinr"; sib1_tda = 5;
min_rxtxtime = 6; min_rxtxtime = 6;
disable_harq = 1; disable_harq = 1;
cu_sibs = [2]; cu_sibs = [2];
@@ -84,6 +84,9 @@ gNBs =
#powerRampingStep #powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6 # 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 1; powerRampingStep = 1;
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 4;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
@@ -146,8 +149,6 @@ gNBs =
#ext2 #ext2
#ntn_Config_r17 #ntn_Config_r17
# This can be of values {s5, s10, s15, s20, s25, s30, s35, s40, s45, s50, s55, s60, s120, s180, s240, s900}
ntn-UlSyncValidityDuration-r17 = 240;
cellSpecificKoffset_r17 = 478; cellSpecificKoffset_r17 = 478;
ta-Common-r17 = 58629666; # 238.74 ms ta-Common-r17 = 58629666; # 238.74 ms
positionX-r17 = 0; positionX-r17 = 0;
@@ -192,20 +193,12 @@ gNBs =
} }
); );
rlc = {
srb = {
t_poll_retransmit = "ms2000"
}
drb_am = {
t_poll_retransmit = "ms2000"
}
}
MACRLCs = ( MACRLCs = (
{ {
num_cc = 1; num_cc = 1;
tr_s_preference = "local_L1"; tr_s_preference = "local_L1";
tr_n_preference = "local_RRC"; tr_n_preference = "local_RRC";
# ulsch_max_frame_inactivity = 0;
pusch_TargetSNRx10 = 150; pusch_TargetSNRx10 = 150;
pucch_TargetSNRx10 = 200; pucch_TargetSNRx10 = 200;
dl_max_mcs = 9; dl_max_mcs = 9;
@@ -242,15 +235,14 @@ RUs = (
} }
); );
rfsimulator = ( rfsimulator :
{ {
serveraddr = "server"; serveraddr = "server";
serverport = 4043; serverport = 4043;
options = (); #("saviq"); or/and "chanmod" options = (); #("saviq"); or/and "chanmod"
prop_delay = 238.74; prop_delay = 238.74;
IQfile = "/tmp/rfsimulator.iqs"; IQfile = "/tmp/rfsimulator.iqs";
} };
);
security = { security = {
# preferred ciphering algorithms # preferred ciphering algorithms

View File

@@ -18,7 +18,10 @@ gNBs =
tr_s_preference = "local_mac" tr_s_preference = "local_mac"
////////// Physical parameters: ////////// Physical parameters:
sib1_tda = 15;
min_rxtxtime = 6; min_rxtxtime = 6;
beam_weights = [0]; // single SSB -> one analog beam
servingCellConfigCommon = ( servingCellConfigCommon = (
{ {
@@ -29,40 +32,40 @@ gNBs =
# downlinkConfigCommon # downlinkConfigCommon
#frequencyInfoDL #frequencyInfoDL
# this is pointA + 16 PRBs@120kHz SCS (same as initial BWP) # this is pointA + 16 PRBs@120kHz SCS (same as initial BWP)
absoluteFrequencySSB = 2078299; absoluteFrequencySSB = 2071387;
dl_frequencyBand = 257; dl_frequencyBand = 261;
# this is 27.900 GHz # this is 27.900 GHz
dl_absoluteFrequencyPointA = 2077963; dl_absoluteFrequencyPointA = 2071001;
#scs-SpecificCarrierList #scs-SpecificCarrierList
dl_offstToCarrier = 0; dl_offstToCarrier = 0;
# subcarrierSpacing # subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
dl_subcarrierSpacing = 3; dl_subcarrierSpacing = 3;
dl_carrierBandwidth = 66; dl_carrierBandwidth = 32;
#initialDownlinkBWP #initialDownlinkBWP
#genericParameters #genericParameters
# this is RBstart=0,L=32 (275*(L-1))+RBstart # this is RBstart=0,L=32 (275*(L-1))+RBstart
initialDLBWPlocationAndBandwidth = 6349; initialDLBWPlocationAndBandwidth = 8525;
# subcarrierSpacing # subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
initialDLBWPsubcarrierSpacing = 3; initialDLBWPsubcarrierSpacing = 3;
#pdcch-ConfigCommon #pdcch-ConfigCommon
initialDLBWPcontrolResourceSetZero = 4; initialDLBWPcontrolResourceSetZero = 1;
initialDLBWPsearchSpaceZero = 0; initialDLBWPsearchSpaceZero = 0;
#uplinkConfigCommon #uplinkConfigCommon
#frequencyInfoUL #frequencyInfoUL
ul_frequencyBand = 257; ul_frequencyBand = 261;
#scs-SpecificCarrierList #scs-SpecificCarrierList
ul_offstToCarrier = 0; ul_offstToCarrier = 0;
# subcarrierSpacing # subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
ul_subcarrierSpacing = 3; ul_subcarrierSpacing = 3;
ul_carrierBandwidth = 66; ul_carrierBandwidth = 32;
pMax = 20; pMax = 20;
#initialUplinkBWP #initialUplinkBWP
#genericParameters #genericParameters
initialULBWPlocationAndBandwidth = 6349; initialULBWPlocationAndBandwidth = 8525;
# subcarrierSpacing # subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
initialULBWPsubcarrierSpacing = 3; initialULBWPsubcarrierSpacing = 3;
@@ -80,6 +83,9 @@ gNBs =
#powerRampingStep #powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6 # 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 1; powerRampingStep = 1;
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 5;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
@@ -143,11 +149,6 @@ gNBs =
); );
first_active_bwp = 1;
bwp_list = (
{ scs = 3; bwpStart = 0; bwpSize = 66;}
);
# ------- SCTP definitions # ------- SCTP definitions
SCTP : SCTP :
{ {
@@ -175,10 +176,9 @@ MACRLCs = ({
tr_n_preference = "local_RRC"; tr_n_preference = "local_RRC";
pusch_TargetSNRx10 = 200; pusch_TargetSNRx10 = 200;
pucch_TargetSNRx10 = 200; pucch_TargetSNRx10 = 200;
set_analog_beamforming = "lophy"; set_analog_beamforming = 1;
beam_duration = 1; beam_duration = 1;
beams_per_period = 1; beams_per_period = 1;
beam_weights = [0]; // single SSB -> one analog beam
}); });
L1s = ( L1s = (
@@ -202,11 +202,9 @@ RUs = ({
eNB_instances = [0]; eNB_instances = [0];
}); });
rfsimulator = ( rfsimulator: {
{
serveraddr = "server"; serveraddr = "server";
} };
);
security = { security = {
# preferred ciphering algorithms # preferred ciphering algorithms

View File

@@ -18,7 +18,7 @@ gNBs =
////////// Physical parameters: ////////// Physical parameters:
min_rxtxtime = 6; min_rxtxtime = 6;
enable_sdap = 0; enable_sdap = 1;
servingCellConfigCommon = ( servingCellConfigCommon = (
{ {
@@ -81,6 +81,9 @@ gNBs =
#powerRampingStep #powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6 # 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 1; powerRampingStep = 1;
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 4;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
@@ -205,15 +208,14 @@ RUs = (
); );
rfsimulator = ( rfsimulator :
{ {
serveraddr = "server"; serveraddr = "server";
serverport = 4043; serverport = 4043;
options = (); #("saviq"); or/and "chanmod" options = (); #("saviq"); or/and "chanmod"
modelname = "AWGN"; modelname = "AWGN";
IQfile = "/tmp/rfsimulator.iqs"; IQfile = "/tmp/rfsimulator.iqs";
} };
);
security = { security = {
# preferred ciphering algorithms # preferred ciphering algorithms

View File

@@ -24,7 +24,6 @@ gNBs =
pusch_AntennaPorts = 2; pusch_AntennaPorts = 2;
do_CSIRS = 1; do_CSIRS = 1;
do_SRS = 1; do_SRS = 1;
uess_agg_levels = [4,2,0,0,0];
servingCellConfigCommon = ( servingCellConfigCommon = (
{ {
@@ -87,6 +86,9 @@ gNBs =
#powerRampingStep #powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6 # 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 1; powerRampingStep = 1;
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 4;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
@@ -140,9 +142,9 @@ gNBs =
# dl_UL_TransmissionPeriodicity # dl_UL_TransmissionPeriodicity
# 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10 # 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10
dl_UL_TransmissionPeriodicity = 5; dl_UL_TransmissionPeriodicity = 5;
nrofDownlinkSlots = 1; nrofDownlinkSlots = 2;
nrofDownlinkSymbols = 6; nrofDownlinkSymbols = 6;
nrofUplinkSlots = 3; nrofUplinkSlots = 2;
nrofUplinkSymbols = 4; nrofUplinkSymbols = 4;
ssPBCH_BlockPower = -20; ssPBCH_BlockPower = -20;
@@ -179,12 +181,11 @@ MACRLCs = (
num_cc = 1; num_cc = 1;
tr_s_preference = "local_L1"; tr_s_preference = "local_L1";
tr_n_preference = "local_RRC"; tr_n_preference = "local_RRC";
pusch_TargetSNRx10 = 320; pusch_TargetSNRx10 = 300;
pucch_TargetSNRx10 = 320; pucch_TargetSNRx10 = 300;
ulsch_max_frame_inactivity = 0;
pusch_FailureThres = 100; pusch_FailureThres = 100;
ul_max_mcs = 28; ul_max_mcs = 28;
ul_bler_target_upper = 0.20;
ul_bler_target_lower = 0.10;
} }
); );

View File

@@ -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;
};
});
};

View File

@@ -84,6 +84,9 @@ gNBs =
#powerRampingStep #powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6 # 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 2; powerRampingStep = 2;
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 5;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
@@ -251,7 +254,7 @@ fhi_72 = {
io_core = 1; io_core = 1;
worker_cores = (2); worker_cores = (2);
ru_addr = ("98:ae:71:04:83:e3", "98:ae:71:04:83:e3"); ru_addr = ("98:ae:71:04:83:e3", "98:ae:71:04:83:e3");
mtu = 9216; mtu = 9600;
fh_config = ({ fh_config = ({
T1a_cp_dl = (285, 470); T1a_cp_dl = (285, 470);
T1a_cp_ul = (285, 429); T1a_cp_ul = (285, 429);

View File

@@ -79,6 +79,9 @@ gNBs =
#powerRampingStep #powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6 # 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 1; powerRampingStep = 1;
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 5;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
@@ -106,7 +109,8 @@ gNBs =
pucchGroupHopping = 0; pucchGroupHopping = 0;
hoppingId = 40; hoppingId = 40;
p0_nominal = -90; p0_nominal = -90;
# ssb_PositionsInBurs_BitmapPR
# 1=short, 2=medium, 3=long
ssb_PositionsInBurst_Bitmap = 1; ssb_PositionsInBurst_Bitmap = 1;
# ssb_periodicityServingCell # ssb_periodicityServingCell
# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1 # 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1
@@ -192,6 +196,8 @@ RUs = (
eNB_instances = [0]; eNB_instances = [0];
ru_thread_core = 6; ru_thread_core = 6;
sl_ahead = 10; #5; sl_ahead = 10; #5;
##beamforming 1x2 matrix: 1 layer x 2 antennas
bf_weights = [0x00007fff, 0x0000,0x00007fff, 0x0000];
tr_preference = "raw_if4p5"; # important: activate FHI7.2 tr_preference = "raw_if4p5"; # important: activate FHI7.2
do_precoding = 0; # needs to match O-RU configuration do_precoding = 0; # needs to match O-RU configuration
} }

View File

@@ -86,6 +86,9 @@ gNBs = (
# powerRampingStep # powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6 # 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 1; powerRampingStep = 1;
# ra_ReponseWindow
# 1,2,4,8,10,20,40,80
ra_ResponseWindow = 4;
# ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR # ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
# 1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen # 1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
@@ -175,6 +178,7 @@ MACRLCs = (
pusch_TargetSNRx10 = 270; pusch_TargetSNRx10 = 270;
pucch_TargetSNRx10 = 270; pucch_TargetSNRx10 = 270;
pusch_FailureThres = 1000; pusch_FailureThres = 1000;
ulsch_max_frame_inactivity = 0;
ul_max_mcs = 25; ul_max_mcs = 25;
} }
); );
@@ -209,7 +213,7 @@ security = {
# preferred ciphering algorithms # preferred ciphering algorithms
# the first one of the list that an UE supports in chosen # the first one of the list that an UE supports in chosen
# valid values: nea0, nea1, nea2, nea3 # valid values: nea0, nea1, nea2, nea3
ciphering_algorithms = ( "nea2", "nea0" ); ciphering_algorithms = ( "nea0" );
# preferred integrity algorithms # preferred integrity algorithms
# the first one of the list that an UE supports in chosen # the first one of the list that an UE supports in chosen
@@ -219,7 +223,7 @@ security = {
# setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter
# what 'ciphering_algorithms' configures; same thing for 'drb_integrity' # what 'ciphering_algorithms' configures; same thing for 'drb_integrity'
drb_ciphering = "yes"; drb_ciphering = "yes";
drb_integrity = "yes"; drb_integrity = "no";
}; };
log_config : log_config :

View File

@@ -1,237 +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 = 001; mnc = 03; mnc_length = 2; snssaiList = ({ sst = 1, sd = 0xffffff }) });
// Include neighbour configuration for N2 handover
@include "neighbour-config-ho.conf"
nr_cellid = 12345678L;
////////// Physical parameters:
servingCellConfigCommon = (
{
#spCellConfigCommon
physCellId = 0;
# downlinkConfigCommon
#frequencyInfoDL
# this is 3610.56 MHz
absoluteFrequencySSB = 679104;
dl_frequencyBand = 77;
# this is 3599.94 MHz
dl_absoluteFrequencyPointA = 678388;
#scs-SpecificCarrierList
dl_offstToCarrier = 0;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
dl_subcarrierSpacing = 1;
dl_carrierBandwidth = 51;
#initialDownlinkBWP
#genericParameters
# this is RBstart=27,L=48 (275*(L-1))+RBstart
initialDLBWPlocationAndBandwidth = 13750;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
initialDLBWPsubcarrierSpacing = 1;
#pdcch-ConfigCommon
initialDLBWPcontrolResourceSetZero = 12;
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 = 51;
pMax = 20;
#initialUplinkBWP
#genericParameters
initialULBWPlocationAndBandwidth = 13750;
# 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 = 13;
preambleReceivedTargetPower = -96;
#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 = 14;
#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 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.109"; });
NETWORK_INTERFACES :
{
GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.19.98";
GNB_IPV4_ADDRESS_FOR_NGU = "172.21.19.98";
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;
ul_prbblack_SNR_threshold = 10;
}
);
L1s = (
{
num_cc = 1;
tr_n_preference = "local_mac";
prach_dtx_threshold = 120;
pucch0_dtx_threshold = 100;
ofdm_offset_divisor = 8; #set this to UINT_MAX for offset 0
}
);
RUs = (
{
local_rf = "yes"
nb_tx = 1
nb_rx = 1
att_tx = 0;
att_rx = 0;
bands = [77];
max_pdschReferenceSignalPower = -27;
max_rxgain = 114;
eNB_instances = [0];
clock_src = "external";
time_src = "external";
}
);
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" );
# 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 = "yes";
};
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";
};

View File

@@ -35,8 +35,8 @@ gNBs =
# downlinkConfigCommon # downlinkConfigCommon
#frequencyInfoDL #frequencyInfoDL
dl_frequencyBand = 78; dl_frequencyBand = 78;
absoluteFrequencySSB = 628320; absoluteFrequencySSB = 634080;
dl_absoluteFrequencyPointA = 627062; dl_absoluteFrequencyPointA = 632808;
#scs-SpecificCarrierList #scs-SpecificCarrierList
dl_offstToCarrier = 0; dl_offstToCarrier = 0;
# subcarrierSpacing # subcarrierSpacing
@@ -84,6 +84,9 @@ gNBs =
#powerRampingStep #powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6 # 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 1; powerRampingStep = 1;
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 4;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
@@ -112,7 +115,7 @@ gNBs =
# 0 = neither, 1= group hopping, 2=sequence hopping # 0 = neither, 1= group hopping, 2=sequence hopping
pucchGroupHopping = 0; pucchGroupHopping = 0;
hoppingId = 40; hoppingId = 40;
p0_nominal = -80; p0_nominal = -70;
ssb_PositionsInBurst_Bitmap = 1; ssb_PositionsInBurst_Bitmap = 1;
@@ -175,7 +178,7 @@ MACRLCs = (
num_cc = 1; num_cc = 1;
tr_s_preference = "local_L1"; tr_s_preference = "local_L1";
tr_n_preference = "local_RRC"; tr_n_preference = "local_RRC";
pusch_TargetSNRx10 = 150; pusch_TargetSNRx10 = 180;
pucch_TargetSNRx10 = 200; pucch_TargetSNRx10 = 200;
} }
); );
@@ -184,7 +187,7 @@ L1s = (
{ {
num_cc = 1; num_cc = 1;
tr_n_preference = "local_mac"; tr_n_preference = "local_mac";
prach_dtx_threshold = 150; prach_dtx_threshold = 120;
#pucch0_dtx_threshold = 150; #pucch0_dtx_threshold = 150;
} }
); );
@@ -194,11 +197,11 @@ RUs = (
local_rf = "yes"; local_rf = "yes";
nb_tx = 1; nb_tx = 1;
nb_rx = 1; nb_rx = 1;
att_tx = 10; att_tx = 0;
att_rx = 0; att_rx = 0;
bands = [78]; bands = [78];
max_pdschReferenceSignalPower = -27; max_pdschReferenceSignalPower = -27;
max_rxgain = 70; max_rxgain = 65;
eNB_instances = [0]; eNB_instances = [0];
sf_extension = 0 sf_extension = 0
sdr_addrs = "addr=192.168.80.52,clock_source=internal,time_source=internal" sdr_addrs = "addr=192.168.80.52,clock_source=internal,time_source=internal"
@@ -209,7 +212,7 @@ security = {
# preferred ciphering algorithms # preferred ciphering algorithms
# the first one of the list that an UE supports in chosen # the first one of the list that an UE supports in chosen
# valid values: nea0, nea1, nea2, nea3 # valid values: nea0, nea1, nea2, nea3
ciphering_algorithms = ( "nea2", "nea0" ); ciphering_algorithms = ( "nea0" );
# preferred integrity algorithms # preferred integrity algorithms
# the first one of the list that an UE supports in chosen # the first one of the list that an UE supports in chosen
@@ -219,7 +222,7 @@ security = {
# setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter
# what 'ciphering_algorithms' configures; same thing for 'drb_integrity' # what 'ciphering_algorithms' configures; same thing for 'drb_integrity'
drb_ciphering = "yes"; drb_ciphering = "yes";
drb_integrity = "yes"; drb_integrity = "no";
}; };
log_config : log_config :

View File

@@ -86,6 +86,9 @@ gNBs =
#powerRampingStep #powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6 # 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 1; powerRampingStep = 1;
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 5;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
@@ -208,11 +211,9 @@ RUs = (
); );
rfsimulator = ( rfsimulator: {
{
serveraddr = "server"; serveraddr = "server";
} };
);
security = { security = {
# preferred ciphering algorithms # preferred ciphering algorithms

View File

@@ -80,6 +80,9 @@ gNBs =
#powerRampingStep #powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6 # 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 1; powerRampingStep = 1;
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 4;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
@@ -197,11 +200,9 @@ RUs = (
} }
); );
rfsimulator = ( rfsimulator: {
{
serveraddr = "server"; serveraddr = "server";
} };
);
security = { security = {
# preferred ciphering algorithms # preferred ciphering algorithms

View File

@@ -18,6 +18,8 @@ gNBs =
////////// Physical parameters: ////////// Physical parameters:
do_CSIRS = 0;
do_SRS = 0;
min_rxtxtime = 6; min_rxtxtime = 6;
servingCellConfigCommon = ( servingCellConfigCommon = (
@@ -80,6 +82,9 @@ gNBs =
#powerRampingStep #powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6 # 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 1; powerRampingStep = 1;
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 4;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
@@ -143,10 +148,64 @@ gNBs =
); );
first_active_bwp = 1; # Dedicated Serving Cell Configuration
bwp_list = ({ scs = 1; bwpStart = 0; bwpSize = 106;}, servingCellConfigDedicated = ({
{ scs = 1; bwpStart = 0; bwpSize = 51;}, # BWP-Downlink
{ scs = 1; bwpStart = 0; bwpSize = 24;}); # BWP 1 Configuration
dl_bwp-Id_1 = 1;
dl_bwp1_locationAndBandwidth = 28875; // RBstart=0, L=106 (40 MHz BW)
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
dl_bwp1_subcarrierSpacing = 1;
# BWP 2 Configuration
dl_bwp-Id_2 = 2;
dl_bwp2_locationAndBandwidth = 13750; // RBstart=0, L=51 (20 MHz BW)
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
dl_bwp2_subcarrierSpacing = 1;
# BWP 3 Configuration
dl_bwp-Id_3 = 3;
dl_bwp3_locationAndBandwidth = 6325; // RBstart=0, L=24 (10 MHz BW)
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
dl_bwp3_subcarrierSpacing = 1;
firstActiveDownlinkBWP-Id = 1; #BWP-Id
defaultDownlinkBWP-Id = 1; #BWP-Id
# bwp-InactivityTimer ENUMERATED {ms2, ms3, ms4, ms5, ms6, ms8, ms10, ms20, ms30,
# ms40,ms50, ms60, ms80,ms100, ms200,ms300, ms500,
# ms750, ms1280, ms1920, ms2560, spare10, spare9, spare8,
# spare7, spare6, spare5, spare4, spare3, spare2, spare1 }
# UplinkConfig
# BWP-Uplink
# BWP 1 Configuration
ul_bwp-Id_1 = 1;
ul_bwp1_locationAndBandwidth = 28875; // RBstart=0, L=106 (40 MHz BW)
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
ul_bwp1_subcarrierSpacing = 1;
# BWP 2 Configuration
ul_bwp-Id_2 = 2;
ul_bwp2_locationAndBandwidth = 13750; // RBstart=0, L=51 (20 MHz BW)
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
ul_bwp2_subcarrierSpacing = 1;
# BWP 3 Configuration
ul_bwp-Id_3 = 3;
ul_bwp3_locationAndBandwidth = 6325; // RBstart=0, L=24 (10 MHz BW)
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
ul_bwp3_subcarrierSpacing = 1;
firstActiveUplinkBWP-Id = 1; #BWP-Id
}
);
# ------- SCTP definitions # ------- SCTP definitions
@@ -177,6 +236,7 @@ MACRLCs = (
tr_n_preference = "local_RRC"; tr_n_preference = "local_RRC";
pusch_TargetSNRx10 = 250; pusch_TargetSNRx10 = 250;
pucch_TargetSNRx10 = 200; pucch_TargetSNRx10 = 200;
ulsch_max_frame_inactivity = 0;
} }
); );
@@ -204,15 +264,13 @@ RUs = ({
}); });
rfsimulator = ( rfsimulator: {
{
serveraddr = "server"; serveraddr = "server";
serverport = 4043; serverport = 4043;
options = (); #("saviq"); or/and "chanmod" options = (); #("saviq"); or/and "chanmod"
modelname = "AWGN"; modelname = "AWGN";
IQfile = "/tmp/rfsimulator.iqs" IQfile = "/tmp/rfsimulator.iqs"
} }
);
security = { security = {
# preferred ciphering algorithms # preferred ciphering algorithms

View File

@@ -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";
};

View File

@@ -63,7 +63,7 @@ gNBs:
prach_ConfigurationIndex: 98 prach_ConfigurationIndex: 98
#prach_msg1_FDM #prach_msg1_FDM
#0 = one, 1=two, 2=four, 3=eight #0 = one, 1=two, 2=four, 3=eight
prach_msg1_FDM: 1 prach_msg1_FDM: 0
prach_msg1_FrequencyStart: 0 prach_msg1_FrequencyStart: 0
zeroCorrelationZoneConfig: 12 zeroCorrelationZoneConfig: 12
preambleReceivedTargetPower: -104 preambleReceivedTargetPower: -104
@@ -72,6 +72,9 @@ gNBs:
#powerRampingStep #powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6 # 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep: 1 powerRampingStep: 1
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow: 5
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR: 4 ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR: 4
@@ -99,7 +102,7 @@ gNBs:
pucchGroupHopping: 0 pucchGroupHopping: 0
hoppingId: 40 hoppingId: 40
p0_nominal: -90 p0_nominal: -90
ssb_PositionsInBurst_Bitmap: 2 ssb_PositionsInBurst_Bitmap: 1
# ssb_periodicityServingCell # ssb_periodicityServingCell
# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1 # 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1
ssb_periodicityServingCell: 2 ssb_periodicityServingCell: 2
@@ -146,7 +149,6 @@ MACRLCs:
tr_n_preference: local_RRC tr_n_preference: local_RRC
pusch_TargetSNRx10: 200 pusch_TargetSNRx10: 200
pucch_TargetSNRx10: 200 pucch_TargetSNRx10: 200
stats_max_ue: 17
L1s: L1s:
- num_cc: 1 - num_cc: 1
@@ -168,7 +170,7 @@ RUs:
sdr_addrs: serial=XXXXXXX sdr_addrs: serial=XXXXXXX
rfsimulator: rfsimulator:
- serveraddr: server serveraddr: server
security: security:
# preferred ciphering algorithms # preferred ciphering algorithms

View File

@@ -85,6 +85,9 @@ gNBs =
#powerRampingStep #powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6 # 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 1; powerRampingStep = 1;
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 4;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;

View File

@@ -78,6 +78,9 @@ gNBs =
#powerRampingStep #powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6 # 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 1; powerRampingStep = 1;
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 4;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;

View File

@@ -98,6 +98,9 @@ gNBs =
#powerRampingStep #powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6 # 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 1; powerRampingStep = 1;
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 4;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;

View File

@@ -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

View File

@@ -99,6 +99,9 @@ gNBs =
#powerRampingStep #powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6 # 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 1; powerRampingStep = 1;
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 4;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;

View File

@@ -16,6 +16,8 @@ gNBs =
nr_cellid = 12345678L; nr_cellid = 12345678L;
////////// Physical parameters: ////////// Physical parameters:
sib1_tda = 15;
min_rxtxtime = 6; min_rxtxtime = 6;
servingCellConfigCommon = ( servingCellConfigCommon = (
@@ -78,6 +80,9 @@ gNBs =
#powerRampingStep #powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6 # 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 1; powerRampingStep = 1;
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 5;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
@@ -194,7 +199,6 @@ RUs = (
att_tx = 0 att_tx = 0
att_rx = 0; att_rx = 0;
bands = [78]; bands = [78];
sl_ahead=3;
max_pdschReferenceSignalPower = -27; max_pdschReferenceSignalPower = -27;
max_rxgain = 114; max_rxgain = 114;
sf_extension = 0; sf_extension = 0;
@@ -203,11 +207,10 @@ RUs = (
} }
); );
rfsimulator = ( rfsimulator: {
{
serveraddr = "server"; serveraddr = "server";
} };
);
security = { security = {
# preferred ciphering algorithms # preferred ciphering algorithms

View File

@@ -23,6 +23,7 @@ gNBs =
pusch_AntennaPorts = 4; pusch_AntennaPorts = 4;
do_CSIRS = 1; do_CSIRS = 1;
do_SRS = 0; do_SRS = 0;
sib1_tda = 15;
# force_UL256qam_off = 1; # force_UL256qam_off = 1;
servingCellConfigCommon = ( servingCellConfigCommon = (
@@ -86,6 +87,9 @@ gNBs =
#powerRampingStep #powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6 # 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 1; powerRampingStep = 1;
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 5;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
@@ -258,7 +262,7 @@ fhi_72 = {
io_core = 1; io_core = 1;
worker_cores = (2); worker_cores = (2);
ru_addr = ("70:b3:d5:e1:5b:81", "70:b3:d5:e1:5b:81"); ru_addr = ("70:b3:d5:e1:5b:81", "70:b3:d5:e1:5b:81");
mtu = 9216; mtu = 9600;
fh_config = ({ fh_config = ({
T1a_cp_dl = (419, 470); T1a_cp_dl = (419, 470);
T1a_cp_ul = (285, 336); T1a_cp_ul = (285, 336);

View File

@@ -83,6 +83,9 @@ gNBs =
#powerRampingStep #powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6 # 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 1; powerRampingStep = 1;
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 5;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
@@ -182,7 +185,6 @@ L1s = (
num_cc = 1; num_cc = 1;
tr_n_preference = "local_mac"; tr_n_preference = "local_mac";
prach_dtx_threshold = 120; prach_dtx_threshold = 120;
tx_amp_backoff_dB = 30;
} }
); );
@@ -203,15 +205,14 @@ RUs = (
); );
rfsimulator = ( rfsimulator :
{ {
serveraddr = "server"; serveraddr = "server";
serverport = 4043; serverport = 4043;
options = (); #("saviq"); or/and "chanmod" options = (); #("saviq"); or/and "chanmod"
modelname = "AWGN"; modelname = "AWGN";
IQfile = "/tmp/rfsimulator.iqs"; IQfile = "/tmp/rfsimulator.iqs";
} };
);
security = { security = {
# preferred ciphering algorithms # preferred ciphering algorithms

View File

@@ -87,6 +87,9 @@ gNBs =
#powerRampingStep #powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6 # 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 1; powerRampingStep = 1;
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 4;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;

View File

@@ -21,7 +21,10 @@ gNBs =
nr_cellid = 12345678L nr_cellid = 12345678L
////////// Physical parameters: ////////// Physical parameters:
uess_agg_levels = [2, 2, 2, 0, 0]; pdsch_AntennaPorts_XP = 1;
pusch_AntennaPorts = 1;
do_CSIRS = 1;
do_SRS = 0;
servingCellConfigCommon = ( servingCellConfigCommon = (
{ {
@@ -31,11 +34,11 @@ gNBs =
# downlinkConfigCommon # downlinkConfigCommon
#frequencyInfoDL #frequencyInfoDL
# this is 3410.400 MHz # this is 3469.44 MHz => 301 REs from PointA 25 PRBs + 1 RE
absoluteFrequencySSB = 627360; absoluteFrequencySSB = 631296;
dl_frequencyBand = 78; dl_frequencyBand = 78;
# this is 3401.220 MHz # this is 3469.44 - (51*12*30e-3/2) = 3460.26 MHz
dl_absoluteFrequencyPointA = 626748; dl_absoluteFrequencyPointA = 630684;
#scs-SpecificCarrierList #scs-SpecificCarrierList
dl_offstToCarrier = 0; dl_offstToCarrier = 0;
# subcarrierSpacing # subcarrierSpacing
@@ -84,6 +87,9 @@ gNBs =
#powerRampingStep #powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6 # 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 1; powerRampingStep = 1;
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 4;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
@@ -147,11 +153,6 @@ gNBs =
); );
RedCap: {
cellBarredRedCap1Rx_r17 = 1;
cellBarredRedCap2Rx_r17 = 1;
intraFreqReselectionRedCap_r17 = 0;
}
# ------- SCTP definitions # ------- SCTP definitions
SCTP : SCTP :
@@ -182,7 +183,6 @@ MACRLCs = (
tr_n_preference = "local_RRC"; tr_n_preference = "local_RRC";
pusch_TargetSNRx10 = 200; pusch_TargetSNRx10 = 200;
pucch_TargetSNRx10 = 200; pucch_TargetSNRx10 = 200;
stats_max_ue = 17;
} }
); );

View File

@@ -78,6 +78,9 @@ gNBs =
#powerRampingStep #powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6 # 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 1; powerRampingStep = 1;
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 4;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;

View File

@@ -1,5 +0,0 @@
rfsimulator = (
{
serveraddr = "127.0.0.1";
}
);

View File

@@ -1,54 +0,0 @@
neighbour_list = (
{
nr_cellid = 12345678;
neighbour_cell_configuration = (
{
gNB_ID = 0xe01;
nr_cellid = 11111111;
physical_cellId = 1;
absoluteFrequencySSB = 679104;
subcarrierSpacing = 1; #30 KHz
band = 77;
plmn = { mcc = 001; mnc = 03; mnc_length = 2};
tracking_area_code = 1;
}
)
},
{
nr_cellid = 11111111;
neighbour_cell_configuration = (
{
gNB_ID = 0xe00;
nr_cellid = 12345678;
physical_cellId = 0;
absoluteFrequencySSB = 679104;
subcarrierSpacing = 1; #30 KHz
band = 77;
plmn = { mcc = 001; mnc = 03; mnc_length = 2};
tracking_area_code = 1;
}
)
}
);
nr_measurement_configuration = {
Periodical = {
enable = 1;
includeBeamMeasurements = 1;
maxNrofRS_IndexesToReport = 4;
};
A2 = {
enable = 1;
threshold = 110;
time_to_trigger = 1;
};
A3 = ({
physCellId = -1; #Default
offset = 10;
hysteresis = 0;
time_to_trigger = 1
})
};

View File

@@ -1,51 +1,52 @@
############################################################
# gNB-to-gNB neighbour list + measurement configuration #
# for the 2-cell rfsim setup (gNB_ID 0xe00 & 0xb00) #
############################################################
neighbour_list = ( neighbour_list = (
##########################################################
# Entry USED BY gNB_ID = 0xe00 (nr_cellid = 1) #
##########################################################
{ {
nr_cellid = 0; # Serving cell of gNB 0xe00 nr_cellid = 1;
neighbour_cell_configuration = ( neighbour_cell_configuration = (
{ {
gNB_ID = 0xb00; gNB_ID = 0xb00;
nr_cellid = 1; # Cell served by gNB 0xb00 nr_cellid = 2;
physical_cellId = 1; physical_cellId = 0x002;
absoluteFrequencySSB= 621312; absoluteFrequencySSB = 641280 ;
subcarrierSpacing = 1; # 30 kHz subcarrierSpacing = 1; #30 KHz
band = 78; plmn = { mcc = 216; mnc = 03; mnc_length = 2};
plmn = { mcc = 208; mnc = 99; mnc_length = 2 }; tracking_area_code = 2;
tracking_area_code = 1; },
{
gNB_ID = 0xa00;
nr_cellid = 3;
physical_cellId = 0x003;
absoluteFrequencySSB = 641280 ;
subcarrierSpacing = 1; #30 KHz
plmn = { mcc = 999; mnc = 99; mnc_length = 2};
tracking_area_code = 3;
},
{
gNB_ID = 0xc00;
nr_cellid = 4;
physical_cellId = 0x004;
absoluteFrequencySSB = 641280 ;
subcarrierSpacing = 1; #30 KHz
plmn = { mcc = 999; mnc = 99; mnc_length = 2};
tracking_area_code = 4;
} }
); )
}, },
##########################################################
# Entry USED BY gNB_ID = 0xb00 (nr_cellid = 2) #
##########################################################
{ {
nr_cellid = 1; # Serving cell of gNB 0xb00 nr_cellid = 2;
neighbour_cell_configuration = ( neighbour_cell_configuration = (
{ {
gNB_ID = 0xe00; gNB_ID = 0xe00;
nr_cellid = 0; # Cell served by gNB 0xe00 nr_cellid = 1;
physical_cellId = 0; physical_cellId = 0x000;
absoluteFrequencySSB= 641280; absoluteFrequencySSB = 641280 ;
subcarrierSpacing = 1; # 30 kHz subcarrierSpacing = 1; #30 KHz
band = 78; plmn = { mcc = 001; mnc = 01; mnc_length = 2};
plmn = { mcc = 208; mnc = 99; mnc_length = 2 }; tracking_area_code = 1;
tracking_area_code = 1;
} }
); )
} }
); );
############################################################
# Common NR measurement-event configuration #
############################################################
nr_measurement_configuration = { nr_measurement_configuration = {
Periodical = { Periodical = {
@@ -57,19 +58,19 @@ nr_measurement_configuration = {
A2 = { A2 = {
enable = 1; enable = 1;
threshold = 60; threshold = 60;
time_to_trigger = 1; timeToTrigger = 1;
}; };
A3 = ({ A3 = ({
physCellId = -1; #Default physCellId = -1; #Default
offset = 10; offset = 10;
hysteresis = 0; hysteresis = 0;
time_to_trigger = 1 timeToTrigger = 1
}, { }, {
physCellId = 2; physCellId = 2;
offset = 5; offset = 5;
hysteresis = 1; hysteresis = 1;
time_to_trigger = 2 timeToTrigger = 2
}) })
}; };

View File

@@ -12,7 +12,9 @@ uicc0 = {
imsi = "208990100001100"; imsi = "208990100001100";
key = "fec86ba6eb707ed08905757b1bb44b8f"; key = "fec86ba6eb707ed08905757b1bb44b8f";
opc= "C42449363BBAD02B66D16BC975D77CC1"; opc= "C42449363BBAD02B66D16BC975D77CC1";
pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; }); dnn= "oai";
nssai_sst=1;
nssai_sd=16777215;
} }
MACRLCs = ( MACRLCs = (

View File

@@ -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";
}
);

View File

@@ -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";
}
);

Some files were not shown because too many files have changed in this diff Show More