diff --git a/ci-scripts/Jenkinsfile-GitLab-Container b/ci-scripts/Jenkinsfile-GitLab-Container
index 8d52bc9f8e..c066333eaa 100644
--- a/ci-scripts/Jenkinsfile-GitLab-Container
+++ b/ci-scripts/Jenkinsfile-GitLab-Container
@@ -464,6 +464,26 @@ pipeline {
}
}
}
+ stage ("SA-OAIUE-CN5G") {
+ when { expression {do5Gtest} }
+ steps {
+ script {
+ triggerCN5GSlaveJob ('RAN-SA-OAIUE-CN5G', 'RAN-SA-OAIUE-CN5G')
+ }
+ }
+ post {
+ always {
+ script {
+ finalizeSlaveJob('RAN-SA-OAIUE-CN5G')
+ }
+ }
+ failure {
+ script {
+ currentBuild.result = 'FAILURE'
+ }
+ }
+ }
+ }
}
}
stage ("DockerHub-Push") {
diff --git a/ci-scripts/Jenkinsfile-nrue b/ci-scripts/Jenkinsfile-nrue
new file mode 100644
index 0000000000..ab5fe0747d
--- /dev/null
+++ b/ci-scripts/Jenkinsfile-nrue
@@ -0,0 +1,242 @@
+#!/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 ('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.EPC_IPAddress == null) {
+ allParametersPresent = false
+ }
+ if (params.EPC_Type == null) {
+ allParametersPresent = false
+ }
+ if (params.EPC_SourceCodePath == null) {
+ allParametersPresent = false
+ }
+ if (params.EPC_Credentials == null) {
+ allParametersPresent = false
+ }
+ 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}"
+ }
+ }
+ }
+ 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.EPC_Credentials}", usernameVariable: 'EPC_Username', passwordVariable: 'EPC_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 {
+ 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} --EPCIPAddress=${params.EPC_IPAddress} --EPCType=${params.EPC_Type} --EPCUserName=${EPC_Username} --EPCPassword=${EPC_Password} --EPCSourceCodePath=${params.EPC_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"
+ 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_logs_CN.zip")){
+ sh "mv test_logs_CN.zip test_logs_CN_${env.BUILD_ID}.zip"
+ archiveArtifacts artifacts: "test_logs_CN_${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: ${BUILD_ID}#' -e 's#TEMPLATE_STAGE_NAME#${testStageName}#' test_results-${JOB_NAME}.html"
+ archiveArtifacts artifacts: "test_results-${env.JOB_NAME}.html"
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/ci-scripts/ci_ueinfra.yaml b/ci-scripts/ci_ueinfra.yaml
index 2aa3952fcb..daedf496f7 100644
--- a/ci-scripts/ci_ueinfra.yaml
+++ b/ci-scripts/ci_ueinfra.yaml
@@ -122,10 +122,13 @@ amarisoft_ue_10:
CmdPrefix: ip netns exec ue10
MTU: 1500
-oai_ue_obelix:
- Host: obelix
+oai_ue_caracal:
+ Host: caracal
+ AttachScript: 'docker start oai-nr-ue'
+ DetachScript: 'docker stop oai-nr-ue'
NetworkScript: ip a show dev oaitun_ue1
IF: oaitun_ue1
+ MTU: 1500
rfsim5g_gnb_nos1:
Host: localhost
diff --git a/ci-scripts/cls_cluster.py b/ci-scripts/cls_cluster.py
index 56c60f7551..24b0c8902e 100644
--- a/ci-scripts/cls_cluster.py
+++ b/ci-scripts/cls_cluster.py
@@ -82,6 +82,7 @@ class Cluster:
self.ranTargetBranch = ""
self.cmd = None
self.imageToPull = ''
+ self.testSvrId = None
def _recreate_entitlements(self):
# recreating entitlements, don't care if deletion fails
@@ -195,12 +196,13 @@ class Cluster:
self.cmd.run(f'oc delete -f {filename}')
def PullClusterImage(self, HTML, RAN):
+ if self.testSvrId == None: self.testSvrId = self.eNBIPAddress
if self.imageToPull == '':
HELP.GenericHelp(CONST.Version)
- HELP.EPCSrvHelp(self.imageToPull)
- sys.exit('Insufficient eNB Parameters')
+ sys.exit('Insufficient Parameter')
+ logging.debug(f'Pull OC image {self.imageToPull} to server {self.testSvrId}')
self.testCase_id = HTML.testCase_id
- cmd = cls_cmd.getConnection(self.eNBIPAddress)
+ cmd = cls_cmd.getConnection(self.testSvrId)
succeeded = OC_login(cmd, self.OCUserName, self.OCPassword, CI_OC_RAN_NAMESPACE)
if not succeeded:
logging.error('\u001B[1m OC Cluster Login Failed\u001B[0m')
diff --git a/ci-scripts/cls_containerize.py b/ci-scripts/cls_containerize.py
index 813b14ce22..3f034e9b73 100644
--- a/ci-scripts/cls_containerize.py
+++ b/ci-scripts/cls_containerize.py
@@ -52,7 +52,7 @@ import cls_cmd
import sshconnection as SSH
import helpreadme as HELP
import constants as CONST
-
+import cls_oaicitest
#-----------------------------------------------------------
# Helper functions used here and in other classes
# (e.g., cls_cluster.py)
@@ -838,7 +838,7 @@ class Containerize():
mySSH.command('cd ' + lSourcePath + '/' + self.yamlPath[self.eNB_instance], '\$', 5)
mySSH.command('cp docker-compose.y*ml ci-docker-compose.yml', '\$', 5)
- imagesList = ['oai-enb', 'oai-gnb', 'oai-nr-cuup', 'oai-gnb-aw2s']
+ imagesList = ['oai-enb', 'oai-gnb', 'oai-nr-cuup', 'oai-gnb-aw2s', 'oai-nr-ue']
for image in imagesList:
imageTag = ImageTagToUse(image, self.ranCommitID, self.ranBranch, self.ranAllowMerge)
mySSH.command(f'sed -i -e "s#image: {image}:latest#image: oai-ci/{imageTag}#" ci-docker-compose.yml', '\$', 2)
@@ -877,6 +877,7 @@ class Containerize():
else:
time.sleep(10)
cnt += 1
+
mySSH.command('docker inspect --format="ImageUsed: {{.Config.Image}}" ' + containerName, '\$', 5)
for stdoutLine in mySSH.getBefore().split('\n'):
if stdoutLine.count('ImageUsed: oai-ci'):
@@ -903,7 +904,7 @@ class Containerize():
cnt = 0
while (cnt < 20):
mySSH.command('docker logs ' + containerName + ' | egrep --text --color=never -i "wait|sync|Starting"', '\$', 30)
- result = re.search('got sync|Starting F1AP at CU', mySSH.getBefore())
+ result = re.search('got sync|Starting F1AP at CU|Got sync', mySSH.getBefore())
if result is None:
time.sleep(6)
cnt += 1
@@ -993,7 +994,6 @@ class Containerize():
mySSH.command('docker volume prune --force', '\$', 20)
mySSH.close()
-
# Analyzing log file!
files = ','.join([f'{s}-{HTML.testCase_id}' for s in services])
if len(services) > 1:
@@ -1005,6 +1005,16 @@ class Containerize():
HTML.htmleNBFailureMsg='Could not copy logfile to analyze it!'
HTML.CreateHtmlTestRow('N/A', 'KO', CONST.ENB_PROCESS_NOLOGFILE_TO_ANALYZE)
self.exitStatus = 1
+ # use function for UE log analysis, when oai-nr-ue container is used
+ elif 'oai-nr-ue' in services:
+ self.exitStatus == 0
+ logging.debug('\u001B[1m Analyzing UE logfile ' + filename + ' \u001B[0m')
+ logStatus = cls_oaicitest.OaiCiTest().AnalyzeLogFile_UE(f'{filename}', HTML, RAN)
+ if (logStatus < 0):
+ fullStatus = False
+ HTML.CreateHtmlTestRow('UE log Analysis', 'KO', logStatus)
+ else:
+ HTML.CreateHtmlTestRow('UE log Analysis', 'OK', CONST.ALL_PROCESSES_OK)
else:
for svcName in services:
filename = f'{svcName}-{HTML.testCase_id}.log'
diff --git a/ci-scripts/cls_oaicitest.py b/ci-scripts/cls_oaicitest.py
index 97eaed8ba5..4d0d4d8f17 100644
--- a/ci-scripts/cls_oaicitest.py
+++ b/ci-scripts/cls_oaicitest.py
@@ -1059,7 +1059,7 @@ class OaiCiTest():
cmd = cls_cmd.getConnection(ue.getHost())
cmd.run(f'rm /tmp/{server_filename}', reportNonZero=False)
port = f'{5002+idx}'
- cmd.run(f'{ue.getCmdPrefix()} iperf3 -c {cn_target_ip} -p {port} {iperf_opt} --get-server-output &> /tmp/{server_filename}', timeout=iperf_time*1.5)
+ cmd.run(f'{ue.getCmdPrefix()} iperf3 -B {ue.getIP()} -c {cn_target_ip} -p {port} {iperf_opt} --get-server-output &> /tmp/{server_filename}', timeout=iperf_time*1.5)
cmd.copyin(f'/tmp/{server_filename}', server_filename)
cmd.close()
if udpIperf:
diff --git a/ci-scripts/conf_files/gnb.sa.band78.106prb.n310.7ds2u.conf b/ci-scripts/conf_files/gnb.sa.band78.106prb.n310.7ds2u.conf
new file mode 100644
index 0000000000..a1e66c7ade
--- /dev/null
+++ b/ci-scripts/conf_files/gnb.sa.band78.106prb.n310.7ds2u.conf
@@ -0,0 +1,261 @@
+Active_gNBs = ( "gNB-OAI");
+# Asn1_verbosity, choice in: none, info, annoying
+Asn1_verbosity = "none";
+
+gNBs =
+(
+ {
+ ////////// Identification parameters:
+ gNB_CU_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
+
+ ////////// Physical parameters:
+
+ min_rxtxtime = 5;
+ do_SRS = 0;
+ force_256qam_off = 1;
+ pdsch_AntennaPorts_N1 = 1;
+ pdsch_AntennaPorts_XP = 1;
+ pusch_AntennaPorts = 1;
+
+
+ pdcch_ConfigSIB1 = (
+ {
+ controlResourceSetZero = 12;
+ searchSpaceZero = 0;
+ }
+ );
+
+ servingCellConfigCommon = (
+ {
+ #spCellConfigCommon
+
+ physCellId = 0;
+
+# downlinkConfigCommon
+ #frequencyInfoDL
+ dl_frequencyBand = 78;
+ absoluteFrequencySSB = 634080;
+ dl_absoluteFrequencyPointA = 632808;
+ #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 = 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 = 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 = -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;
+#ra_ReponseWindow
+#1,2,4,8,10,20,40,80
+ ra_ResponseWindow = 4;
+#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 = 3;
+#oneHalf (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 = -70;
+# ssb_PositionsInBurs_BitmapPR
+# 1=short, 2=medium, 3=long
+ ssb_PositionsInBurst_PR = 2;
+ 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 = "172.21.6.100";
+ ipv6 = "192:168:30::17";
+ active = "yes";
+ preference = "ipv4";
+ }
+ );
+
+ NETWORK_INTERFACES :
+ {
+
+ GNB_INTERFACE_NAME_FOR_NG_AMF = "eno33np0";
+ GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.16.124/22";
+ GNB_INTERFACE_NAME_FOR_NGU = "eno33np0";
+ GNB_IPV4_ADDRESS_FOR_NGU = "172.21.16.124/22";
+ GNB_PORT_FOR_S1U = 2152; # Spec 2152
+ };
+
+ }
+);
+
+MACRLCs = (
+{
+ num_cc = 1;
+ tr_s_preference = "local_L1";
+ tr_n_preference = "local_RRC";
+ pusch_TargetSNRx10 = 180;
+ pucch_TargetSNRx10 = 200;
+ ulsch_max_frame_inactivity = 1;
+ ul_max_mcs = 16;
+}
+);
+
+L1s = (
+{
+ num_cc = 1;
+ tr_n_preference = "local_mac";
+ prach_dtx_threshold = 120;
+ #pucch0_dtx_threshold = 150;
+}
+);
+
+RUs = (
+{
+ local_rf = "yes";
+ nb_tx = 1;
+ nb_rx = 1;
+ att_tx = 0;
+ att_rx = 0;
+ bands = [78];
+ max_pdschReferenceSignalPower = -27;
+ max_rxgain = 75;
+ eNB_instances = [0];
+ ##beamforming 1x2 matrix: 1 layer x 2 antennas
+ bf_weights = [0x00007fff, 0x0000];
+ sf_extension = 0
+ sdr_addrs = "addr=192.168.80.52,clock_source=internal,time_source=internal"
+}
+);
+
+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";
+ gtpu_log_level ="info";
+};
+
diff --git a/ci-scripts/main.py b/ci-scripts/main.py
index 898dfca6d8..613b6238f5 100644
--- a/ci-scripts/main.py
+++ b/ci-scripts/main.py
@@ -420,10 +420,12 @@ def GetParametersFromXML(action):
RAN.command = test.findtext('command')
RAN.command_fail = test.findtext('command_fail') in ['True', 'true', 'Yes', 'yes']
elif action == 'Pull_Cluster_Image':
- # CLUSTER.imageToPull.clear()
string_field = test.findtext('images_to_pull')
if (string_field is not None):
CLUSTER.imageToPull = string_field.split()
+ string_field = test.findtext('test_svr_id')
+ if (string_field is not None):
+ CLUSTER.testSvrId = string_field
else:
logging.warning(f"unknown action {action} from option-parsing point-of-view")
diff --git a/ci-scripts/xml_files/container_sa_n310_nrue.xml b/ci-scripts/xml_files/container_sa_n310_nrue.xml
new file mode 100644
index 0000000000..309b2860f7
--- /dev/null
+++ b/ci-scripts/xml_files/container_sa_n310_nrue.xml
@@ -0,0 +1,146 @@
+
+
+ TEST-5G-NRUE
+ 40 MHz TDD SA
+ tasks
+ 1
+
+ 010000 010001
+ 020000 020001
+ 000001
+ 001000
+ 002000
+ 000100
+ 000200
+ 040001 040000
+
+
+
+
+ Pull_Cluster_Image
+ Pull Images from Cluster
+ oai-gnb
+ avra
+
+
+
+ Pull_Cluster_Image
+ Pull Images from Cluster
+ oai-nr-ue
+ caracal
+
+
+
+ Custom_Command
+ Reboot USRP N310
+ avra
+ ssh root@192.168.80.52 reboot ; sleep 45
+
+
+
+ Custom_Command
+ Reboot USRP N310
+ caracal
+ ssh root@192.168.20.2 reboot ; sleep 45
+
+
+
+ Deploy_Object
+ Deploy gNB (TDD/Band78/40MHz/N310) in a container
+ ci-scripts/yaml_files/5g_sa_n310_gnb
+ 0
+ 0
+
+
+
+ Deploy_Object
+ Deploy nrUE (TDD/Band78/40MHz/N310) in a container
+ ci-scripts/yaml_files/5g_sa_n310_nrue
+ 1
+ 1
+
+
+
+ Attach_UE
+ Attach OAIUE
+ oai_ue_caracal
+
+
+
+ Iperf
+ iperf (DL/20Mbps/UDP)(30 sec)(single-ue profile)
+ -u -b 20M -t 30 -i 1 -R
+ IPERF3
+ oai_ue_caracal
+ 25
+ 80
+
+
+
+ Iperf
+ iperf (UL/5Mbps/UDP)(30 sec)(single-ue profile)
+ -u -b 5M -t 30 -i 1
+ IPERF3
+ oai_ue_caracal
+ 25
+ 80
+
+
+
+ Ping
+ Ping: 20pings in 20sec
+ oai_ue_caracal
+ -c 20
+ 1
+ 25
+
+
+
+ Ping
+ Ping: 100pings in 20sec
+ oai_ue_caracal
+ -c 100 -i 0.2
+ 1
+ 30
+
+
+
+ Undeploy_Object
+ Undeploy gNB
+ ci-scripts/yaml_files/5g_sa_n310_gnb
+ 0
+ 0
+ 20,100,100,100
+ 20,100,100,100
+
+
+
+ Undeploy_Object
+ Undeploy nr UE
+ ci-scripts/yaml_files/5g_sa_n310_nrue
+ 1
+ 1
+
+
+
diff --git a/ci-scripts/xml_files/container_sa_n310_nrue_cleanup.xml b/ci-scripts/xml_files/container_sa_n310_nrue_cleanup.xml
new file mode 100644
index 0000000000..0bac1e010b
--- /dev/null
+++ b/ci-scripts/xml_files/container_sa_n310_nrue_cleanup.xml
@@ -0,0 +1,46 @@
+
+
+ test-aw2s-cleanup
+ CleanUp of test servers
+ trash
+
+ 111111
+ 222222
+
+
+
+
+ Clean_Test_Server_Images
+ Clean Test Images on Test Server
+ 0
+
+
+
+ Clean_Test_Server_Images
+ Clean Test Images on Test Server
+ 1
+
+
+
+
diff --git a/ci-scripts/yaml_files/5g_sa_n310_gnb/docker-compose.yml b/ci-scripts/yaml_files/5g_sa_n310_gnb/docker-compose.yml
new file mode 100644
index 0000000000..30cef6b62b
--- /dev/null
+++ b/ci-scripts/yaml_files/5g_sa_n310_gnb/docker-compose.yml
@@ -0,0 +1,17 @@
+version: '3.8'
+services:
+ oai-gnb:
+ image: oai-gnb:latest
+ privileged: true
+ network_mode: "host"
+ container_name: oai-gnb
+ environment:
+ TZ: Europe/Paris
+ USE_ADDITIONAL_OPTIONS: --sa --tune-offset 20000000 --log_config.global_log_options level,nocolor,time
+ volumes:
+ - ../../conf_files/gnb.sa.band78.106prb.n310.7ds2u.conf:/opt/oai-gnb/etc/gnb.conf
+ healthcheck:
+ test: /bin/bash -c "pgrep nr-softmodem"
+ interval: 10s
+ timeout: 5s
+ retries: 5
diff --git a/ci-scripts/yaml_files/5g_sa_n310_nrue/docker-compose.yml b/ci-scripts/yaml_files/5g_sa_n310_nrue/docker-compose.yml
new file mode 100644
index 0000000000..038ea51532
--- /dev/null
+++ b/ci-scripts/yaml_files/5g_sa_n310_nrue/docker-compose.yml
@@ -0,0 +1,18 @@
+version: '3.8'
+services:
+ oai-nr-ue:
+ image: oai-nr-ue:latest
+ privileged: true
+ network_mode: host
+ container_name: oai-nr-ue
+ #entrypoint: /bin/bash -c "sleep infinity"
+ environment:
+ TZ: Europe/Paris
+ USE_ADDITIONAL_OPTIONS: --usrp-args type=n3xx,name=ni-n3xx-31641B9,addr=192.168.20.2 -r 106 --numerology 1 --band 78 -C 3511200000 --sa --ue-fo-compensation --ue-rxgain 65 --tune-offset 20000000 --log_config.global_log_options level,nocolor,time --uicc0.imsi 208970000000111 --uicc0.nssai_sd 16777215
+ volumes:
+ - ../../conf_files/ue.sa.conf:/opt/oai-nr-ue/etc/nr-ue.conf
+ healthcheck:
+ test: /bin/bash -c "pgrep nr-uesoftmodem"
+ interval: 10s
+ timeout: 5s
+ retries: 5
diff --git a/doc/TESTBenches.md b/doc/TESTBenches.md
index 300d9cd56a..35aebfe1aa 100644
--- a/doc/TESTBenches.md
+++ b/doc/TESTBenches.md
@@ -61,6 +61,14 @@ Note: The available resources, and their current usage, is indicated here:
[PDF version](testbenches_doc_resources/5g-aw2s-bench.pdf) | [LaTeX/TikZ version](testbenches_doc_resources/5g-aw2s-bench.tex) if you want to modify to reflect your setup
+### 5G UE OTA Testbench
+
+**Purpose**: Over-the-air 5G tests with OAI UE
+
+
+
+[PDF version](testbenches_doc_resources/5g-nrue-bench.pdf) | [LaTeX/TikZ version](testbenches_doc_resources/5g-nrue-bench.tex) if you want to modify to reflect your setup
+
### 4G Testbench(es)
**Purpose**: 4G/LTE testbenches
@@ -121,6 +129,9 @@ Webhook
- [RAN-SA-B200-Module-SABOX-Container](https://jenkins-oai.eurecom.fr/job/RAN-SA-B200-Module-SABOX-Container/)
- ofqot + B200, idefix + Quectel, nepes w/ sabox
- basic SA test (20 MHz TDD), F1, reestablishment, ...
+- [RAN-SA-OAIUE-CN5G](https://jenkins-oai.eurecom.fr/job/RAN-SA-OAIUE-CN5G/)
+ - 5G-NR SA test setup: gNB on avra(RHEL9.2) + N310, OAIUE on caracal(RHEL9.1) + N310, OAI CN5G
+ - OpenShift cluster for CN deployment and container images for gNB and UE deployment
- [RAN-Ubuntu18-Image-Builder](https://jenkins-oai.eurecom.fr/job/RAN-Ubuntu18-Image-Builder/)
- obelix: Ubuntu 20 image build using docker (Note: builds U20 images while pipeline is named U18!)
@@ -134,9 +145,6 @@ Webhook
- [RAN-SA-Module-CN5G](https://jenkins-oai.eurecom.fr/view/RAN/job/RAN-SA-Module-CN5G/)
- asterix + N310 (gNB), nrmodule2 + Quectel, porcepix w/ OAI 5GC
- NR 2x2 (standalone)
-- [RAN-SA-OAIUE-N310-X300-CN5G](https://jenkins-oai.eurecom.fr/job/RAN-SA-OAIUE-N310-X300-CN5G/)
- - asterix + N310 (gNB), obelix + N310 or X300 (5G UE), porcepix w/ OAI 5GC
- - OTA test with OAIUE using both N310 and X300
- [RAN-SA-AmariS-CN5G](https://jenkins-oai.eurecom.fr/view/RAN/job/RAN-SA-AmariS-CN5G/)
- asterix + N310, amariue (1x UE), porcepix w/ OAI 5GC
- Amarisoft UE simulator: expected to be increased to more UEs
diff --git a/doc/testbenches_doc_resources/5g-nrue-bench.pdf b/doc/testbenches_doc_resources/5g-nrue-bench.pdf
new file mode 100644
index 0000000000..7e461807c1
Binary files /dev/null and b/doc/testbenches_doc_resources/5g-nrue-bench.pdf differ
diff --git a/doc/testbenches_doc_resources/5g-nrue-bench.png b/doc/testbenches_doc_resources/5g-nrue-bench.png
new file mode 100644
index 0000000000..c167591592
Binary files /dev/null and b/doc/testbenches_doc_resources/5g-nrue-bench.png differ
diff --git a/doc/testbenches_doc_resources/5g-nrue-bench.tex b/doc/testbenches_doc_resources/5g-nrue-bench.tex
new file mode 100644
index 0000000000..c180929767
--- /dev/null
+++ b/doc/testbenches_doc_resources/5g-nrue-bench.tex
@@ -0,0 +1,36 @@
+\documentclass{standalone}
+
+\usepackage{tikz}
+\usetikzlibrary{backgrounds, positioning, shapes.symbols}
+\usepackage{helvet}
+\renewcommand*{\rmdefault}{\sfdefault}
+
+\begin{document}
+\begin{tikzpicture}
+ [
+ font=\footnotesize,
+ faraday/.style={minimum size=3cm, draw, dashed},
+ duplexer/.style={draw,fill=white},
+ ]
+
+ \node[label=above:avra] (avra)
+ {\includegraphics[width=1.2cm]{server}};
+ \node[right=0.5cm of avra, label=above:USRP N310] (n310gnb)
+ {\includegraphics[width=1.2cm]{n310}} edge (avra);
+ \node[right=.2cm of n310gnb, duplexer] (b78o) {n78} edge (n310gnb);
+ \node[right=0.5cm of b78o] (ant1)
+ {\includegraphics[width=0.3cm]{antenna}} edge (b78o);
+ \node[left=0.5cm of avra] (oc)
+ {\includegraphics[width=1.2cm]{openshift}} edge (avra);
+
+ \node[right=7cm of n310gnb, label=above:caracal] (caracal)
+ {\includegraphics[width=1.2cm]{server}};
+ \node[left=0.5cm of caracal, label=above:USRP N310] (n310ue)
+ {\includegraphics[width=1.2cm]{n310}} edge (caracal);
+ \node[left=.2cm of n310ue, duplexer] (b78a) {n78} edge (n310ue);
+ \node[left=0.5cm of b78a] (ant2)
+ {\includegraphics[width=0.3cm]{antenna}} edge (b78a);
+
+
+\end{tikzpicture}
+\end{document}
diff --git a/doc/testbenches_doc_resources/openshift.png b/doc/testbenches_doc_resources/openshift.png
new file mode 100644
index 0000000000..4be8884b9d
Binary files /dev/null and b/doc/testbenches_doc_resources/openshift.png differ