From cffdac04459a26a3a5a37116f9150ffe4d97e16b Mon Sep 17 00:00:00 2001 From: hardy Date: Fri, 26 Mar 2021 10:53:42 +0100 Subject: [PATCH 01/25] adding module support, primary test/debug --- ci-scripts/build_fr1_template.yaml | 8 +- ci-scripts/ci_ueinfra.yaml | 30 ++++ ci-scripts/cls_ci_ueinfra.py | 57 +++++++ ci-scripts/cls_module_ue.py | 113 ++++++++++++++ ci-scripts/cls_oaicitest.py | 242 ++++++++++++++++++++++------- ci-scripts/main.py | 34 +++- ci-scripts/ran.py | 1 - 7 files changed, 417 insertions(+), 68 deletions(-) create mode 100644 ci-scripts/ci_ueinfra.yaml create mode 100644 ci-scripts/cls_ci_ueinfra.py create mode 100644 ci-scripts/cls_module_ue.py diff --git a/ci-scripts/build_fr1_template.yaml b/ci-scripts/build_fr1_template.yaml index 2a8f9cc6a0..02e49bc4b5 100755 --- a/ci-scripts/build_fr1_template.yaml +++ b/ci-scripts/build_fr1_template.yaml @@ -1,15 +1,15 @@ ranRepository : https://gitlab.eurecom.fr/oai/openairinterface5g.git -ranBranch : BRANCH_NAME -ranCommitID : COMMIT_ID -ranAllowMerge : 'true' +ranBranch : integration_2021_wk13_a +ranCommitID : 104aa7eed5d6702c1b9da663414079ef698da206 +ranAllowMerge : 'yes' ranTargetBranch : develop steps: - InitiateHtml,none - TesteNB,xml_files/fr1_multi_node_build.xml - TesteNB,xml_files/fr1_epc_start.xml - - TesteNB,xml_files/fr1_ran_ue_base.xml #ue toggle, nodes initialize, ue toggle, ping, nodes terminate + - TesteNB,xml_files/fr1_nsa_base_next.xml #ue toggle, nodes initialize, ue toggle, ping, nodes terminate - TesteNB,xml_files/fr1_epc_closure.xml diff --git a/ci-scripts/ci_ueinfra.yaml b/ci-scripts/ci_ueinfra.yaml new file mode 100644 index 0000000000..8ea75f9a85 --- /dev/null +++ b/ci-scripts/ci_ueinfra.yaml @@ -0,0 +1,30 @@ +idefix: + ID: idefix + State : enabled + Kind : quectel + Process : quectel-CM + WakeupScript : ci_qtel.py + UENetwork : wwan0 + HostIPAddress : 192.168.18.188 + HostUsername : oaicicd + HostPassword : oaicicd + HostSourceCodePath : none +dummy1: + ID: dummy1 + Kind : simcom + State : disabled + Process : quectel-cm + HostIPAddress : 192.168.18.187 + HostUsername : oaicicd + HostPassword : oaicicd + HostSourceCodePath : none +dummy2: + ID: dummy2 + Kind : cots + State : disabled + Process : quectel-cm + HostIPAddress : 192.168.18.186 + HostUsername : oaicicd + HostPassword : oaicicd + HostSourceCodePath : none + diff --git a/ci-scripts/cls_ci_ueinfra.py b/ci-scripts/cls_ci_ueinfra.py new file mode 100644 index 0000000000..0326a92a4f --- /dev/null +++ b/ci-scripts/cls_ci_ueinfra.py @@ -0,0 +1,57 @@ +# * 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 +# */ +#--------------------------------------------------------------------- +# +# Required Python Version +# Python 3.x +# +#--------------------------------------------------------------------- + +#to use isfile +import os +import sys +import logging +#to create a SSH object locally in the methods +import sshconnection +#time.sleep +import time +#to load ue infrastructure dictionary +import yaml + +class InfraUE: + def __init__(self): + self.ci_ue_infra ={} + + +#-----------------$ +#PUBLIC Methods$ +#-----------------$ + + #This method reads the yaml file describing the multi-UE infrastructure + #and stores the infra permanently in the related class attribute self.ci_ue_infra + def Get_UE_Infra(self,ue_infra_filename): + f_yaml=ue_infra_filename + with open(f_yaml,'r') as file: + logging.debug('Loading UE infrastructure from file '+f_yaml) + #load it permanently in the class attribute + self.ci_ue_infra = yaml.load(file,Loader=yaml.FullLoader) + + + diff --git a/ci-scripts/cls_module_ue.py b/ci-scripts/cls_module_ue.py new file mode 100644 index 0000000000..87902deaff --- /dev/null +++ b/ci-scripts/cls_module_ue.py @@ -0,0 +1,113 @@ +# * 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 +# */ +#--------------------------------------------------------------------- +# +# Required Python Version +# Python 3.x +# +#--------------------------------------------------------------------- + +#to use isfile +import os +import sys +import logging +#to create a SSH object locally in the methods +import sshconnection +#time.sleep +import time + + +import re +import subprocess + + + +class Module_UE: +# ID: idefix +# State : enabled +# Kind : quectel +# Process : quectel-cm +# WakeupScript : ci_qtel.py +# UENetwork : wwan0 +# HostIPAddress : 192.168.18.188 +# HostUsername : oaicicd +# HostPassword : oaicicd +# HostSourceCodePath : none + + def __init__(self,Module): + #create attributes as in the Module dictionary + for k, v in Module.items(): + setattr(self, k, v) + self.UEIPAddress = "" + + + + +#-----------------$ +#PUBLIC Methods$ +#-----------------$ + + #this method checks if the specified Process is running on the server hosting the module + def CheckIsModule(self): + HOST=self.HostIPAddress + COMMAND="ps aux | grep " + self.Process + " | grep -v grep " + logging.debug(COMMAND) + ssh = subprocess.Popen(["ssh", "%s" % HOST, COMMAND],shell=False,stdout=subprocess.PIPE,stderr=subprocess.PIPE) + result = ssh.stdout.readlines() + if len(result)!=0: + logging.debug(self.Process + " process found") + return True + else: + logging.debug(self.Process + " process NOT found") + return False + + #this method wakes up the module by calling the specified python script + def WakeUp(self): + mySSH = sshconnection.SSHConnection() + mySSH.open(self.HostIPAddress, self.HostUsername, self.HostPassword) + mySSH.command('echo ' + self.HostPassword + ' | sudo -S python3 ' + self.WakeupScript + ' ','\$',5) + time.sleep(5) + logging.debug("Module wake-up") + mySSH.close() + + #this method retrieves the Module IP address (not the Host IP address) + def GetModuleIPAddress(self): + HOST=self.HostIPAddress + COMMAND="ip a show dev " + self.UENetwork + " | grep inet | grep " + self.UENetwork + ssh = subprocess.Popen(["ssh", "%s" % HOST, COMMAND],shell=False,stdout=subprocess.PIPE,stderr=subprocess.PIPE) + response = ssh.stdout.readlines() + if len(response)!=0: + result = re.search('inet (?P[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)', response[0].decode("utf-8") ) + if result is not None: + if result.group('moduleipaddress') is not None: + self.UEIPAddress = result.group('moduleipaddress') + logging.debug('\u001B[1mUE Module IP Address is ' + self.UEIPAddress + '\u001B[0m') + else: + logging.debug('\u001B[1;37;41m Module IP Address Not Found! \u001B[0m') + else: + logging.debug('\u001B[1;37;41m Module IP Address Not Found! \u001B[0m') + else: + logging.debug('\u001B[1;37;41m Module IP Address Not Found! \u001B[0m') + + + + + + diff --git a/ci-scripts/cls_oaicitest.py b/ci-scripts/cls_oaicitest.py index 7da829b7f7..a8a467153b 100644 --- a/ci-scripts/cls_oaicitest.py +++ b/ci-scripts/cls_oaicitest.py @@ -54,7 +54,8 @@ import helpreadme as HELP import constants as CONST import sshconnection - +import cls_module_ue +import cls_ci_ueinfra #class defining the multi Ue infrastrucure #----------------------------------------------------------- @@ -129,6 +130,7 @@ class OaiCiTest(): self.iperf_packetloss_threshold = '' self.iperf_profile = '' self.iperf_options = '' + self.iperf_direction = '' self.nbMaxUEtoAttach = -1 self.UEDevices = [] self.UEDevicesStatus = [] @@ -157,6 +159,7 @@ class OaiCiTest(): self.clean_repository = True self.air_interface='' self.expectedNbOfConnectedUEs = 0 + self.ue_id = '' #used for module identification def BuildOAIUE(self,HTML): @@ -364,29 +367,39 @@ class OaiCiTest(): except: os.kill(os.getppid(),signal.SIGUSR1) - def InitializeUE(self,HTML,COTS_UE): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - HELP.GenericHelp(CONST.Version) - sys.exit('Insufficient Parameter') - multi_jobs = [] - i = 0 - for device_id in self.UEDevices: - p = Process(target = self.InitializeUE_common, args = (device_id,i,COTS_UE,)) - p.daemon = True - p.start() - multi_jobs.append(p) - i += 1 - for job in multi_jobs: - job.join() - HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) - - - + def InitializeUE(self,HTML,COTS_UE, InfraUE): + if self.ue_id=='':#no ID specified, then it is a COTS controlled by ADB + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + HELP.GenericHelp(CONST.Version) + sys.exit('Insufficient Parameter') + multi_jobs = [] + i = 0 + for device_id in self.UEDevices: + p = Process(target = self.InitializeUE_common, args = (device_id,i,COTS_UE,)) + p.daemon = True + p.start() + multi_jobs.append(p) + i += 1 + for job in multi_jobs: + job.join() + HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) + else: #if an ID is specified, it is a module from the yaml infrastructure file + #RH + Module_UE = cls_module_ue.Module_UE(InfraUE.ci_ue_infra[self.ue_id]) + is_module=Module_UE.CheckIsModule() + if is_module: + Module_UE.WakeUp() + Module_UE.GetModuleIPAddress() + HTML.CreateHtmlTestRow(Module_UE.UEIPAddress, 'OK', CONST.ALL_PROCESSES_OK) + self.UEIPAddresses.append(Module_UE.UEIPAddress) + logging.debug(self.UEIPAddresses) def InitializeOAIUE(self,HTML,RAN,EPC,COTS_UE): if self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '' or self.UESourceCodePath == '': HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') + + if self.air_interface == 'lte-uesoftmodem': result = re.search('--no-L2-connect', str(self.Initialize_OAI_UE_args)) if result is None: @@ -1437,14 +1450,20 @@ class OaiCiTest(): statusQueue.put(message) lock.release() - def Ping_common(self, lock, UE_IPAddress, device_id, statusQueue,EPC): + def Ping_common(self, lock, UE_IPAddress, device_id, statusQueue,EPC, InfraUE): try: SSH = sshconnection.SSHConnection() # Launch ping on the EPC side (true for ltebox and old open-air-cn) # But for OAI-Rel14-CUPS, we launch from python executor launchFromEpc = True + launchFromModule = False if re.match('OAI-Rel14-CUPS', EPC.Type, re.IGNORECASE): launchFromEpc = False + #if module, ping from module to EPC + if self.ue_id!='': + launchFromEpc = False + launchfromModule = True + ping_time = re.findall("-c (\d+)",str(self.ping_args)) if launchFromEpc: @@ -1462,21 +1481,36 @@ class OaiCiTest(): #copy the ping log file to have it locally for analysis (ping stats) SSH.copyin(EPC.IPAddress, EPC.UserName, EPC.Password, EPC.SourceCodePath + '/scripts/ping_' + self.testCase_id + '_' + device_id + '.log', '.') else: - #ping log file is on the python executor - cmd = 'ping ' + self.ping_args + ' ' + UE_IPAddress + ' 2>&1 > ping_' + self.testCase_id + '_' + device_id + '.log' - message = cmd + '\n' - logging.debug(cmd) - ret = subprocess.run(cmd, shell=True) - ping_status = ret.returncode - #copy the ping log file to an other folder for log collection (source and destination are EPC) - SSH.copyout(EPC.IPAddress, EPC.UserName, EPC.Password, 'ping_' + self.testCase_id + '_' + device_id + '.log', EPC.SourceCodePath + '/scripts') - #copy the ping log file to have it locally for analysis (ping stats) - logging.debug(EPC.SourceCodePath + 'ping_' + self.testCase_id + '_' + device_id + '.log') - SSH.copyin(EPC.IPAddress, EPC.UserName, EPC.Password, EPC.SourceCodePath +'/scripts/ping_' + self.testCase_id + '_' + device_id + '.log', '.') + if launchfromModule == False: + #ping log file is on the python executor + cmd = 'ping ' + self.ping_args + ' ' + UE_IPAddress + ' 2>&1 > ping_' + self.testCase_id + '_' + device_id + '.log' + message = cmd + '\n' + logging.debug(cmd) + ret = subprocess.run(cmd, shell=True) + ping_status = ret.returncode + #copy the ping log file to an other folder for log collection (source and destination are EPC) + SSH.copyout(EPC.IPAddress, EPC.UserName, EPC.Password, 'ping_' + self.testCase_id + '_' + device_id + '.log', EPC.SourceCodePath + '/scripts') + #copy the ping log file to have it locally for analysis (ping stats) + logging.debug(EPC.SourceCodePath + 'ping_' + self.testCase_id + '_' + device_id + '.log') + SSH.copyin(EPC.IPAddress, EPC.UserName, EPC.Password, EPC.SourceCodePath +'/scripts/ping_' + self.testCase_id + '_' + device_id + '.log', '.') + + SSH.open(EPC.IPAddress, EPC.UserName, EPC.Password) + #cat is executed on EPC + SSH.command('cat ' + EPC.SourceCodePath + '/scripts/ping_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + else: #launch from Module + Module_UE = cls_module_ue.Module_UE(InfraUE.ci_ue_infra[self.ue_id]) + + SSH.open(Module_UE.HostIPAddress, Module_UE.HostUsername, Module_UE.HostPassword) + cmd = 'ping -I ' + UE_IPAddress + ' ' + self.ping_args + ' ' + EPC.IPAddress + ' 2>&1 > ping_' + self.testCase_id + '_' + self.ue_id + '.log' + SSH.command(cmd,'\$',int(ping_time[0])*1.5) + logging.debug(cmd) + #copy the ping log file to have it locally for analysis (ping stats) + SSH.copyin(Module_UE.HostIPAddress, Module_UE.HostUsername, Module_UE.HostPassword, 'ping_' + self.testCase_id + '_' + self.ue_id + '.log', '.') + + #cat is executed locally + SSH.command('cat ping_' + self.testCase_id + '_' + self.ue_id + '.log', '\$', 5) + ping_status=0 - SSH.open(EPC.IPAddress, EPC.UserName, EPC.Password) - #cat is executed on EPC - SSH.command('cat ' + EPC.SourceCodePath + '/scripts/ping_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) # TIMEOUT CASE if ping_status < 0: message = 'Ping with UE (' + str(UE_IPAddress) + ') crashed due to TIMEOUT!' @@ -1660,7 +1694,7 @@ class OaiCiTest(): except: os.kill(os.getppid(),signal.SIGUSR1) - def Ping(self,HTML,RAN,EPC,COTS_UE): + def Ping(self,HTML,RAN,EPC,COTS_UE, InfraUE): result = re.search('noS1', str(RAN.Initialize_eNB_args)) if result is not None: self.PingNoS1(HTML,RAN,EPC,COTS_UE) @@ -1678,18 +1712,29 @@ class OaiCiTest(): HTML.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC) return - ueIpStatus = self.GetAllUEIPAddresses() - if (ueIpStatus < 0): - HTML.CreateHtmlTestRow(self.ping_args, 'KO', CONST.UE_IP_ADDRESS_ISSUE) - self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC) - return + + if self.ue_id=="": + ueIpStatus = self.GetAllUEIPAddresses() + if (ueIpStatus < 0): + HTML.CreateHtmlTestRow(self.ping_args, 'KO', CONST.UE_IP_ADDRESS_ISSUE) + self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC) + return + else: + Module_UE = cls_module_ue.Module_UE(InfraUE.ci_ue_infra[self.ue_id]) + Module_UE.GetModuleIPAddress() + if Module_UE.UEIPAddress not in self.UEIPAddresses: + self.UEIPAddresses.append(Module_UE.UEIPAddress) + logging.debug(self.UEIPAddresses) multi_jobs = [] i = 0 lock = Lock() status_queue = SimpleQueue() for UE_IPAddress in self.UEIPAddresses: - device_id = self.UEDevices[i] - p = Process(target = self.Ping_common, args = (lock,UE_IPAddress,device_id,status_queue,EPC,)) + if self.ue_id=="": + device_id = self.UEDevices[i] + else: + device_id = "" + p = Process(target = self.Ping_common, args = (lock,UE_IPAddress,device_id,status_queue,EPC,InfraUE,)) p.daemon = True p.start() multi_jobs.append(p) @@ -1864,8 +1909,8 @@ class OaiCiTest(): else: return -2 - def Iperf_analyzeV2Server(self, lock, UE_IPAddress, device_id, statusQueue, iperf_real_options): - if (not os.path.isfile('iperf_server_' + self.testCase_id + '_' + device_id + '.log')): + def Iperf_analyzeV2Server(self, lock, UE_IPAddress, device_id, statusQueue, iperf_real_options, filename,type): + if (not os.path.isfile(filename)): self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, 'Could not analyze from server log') return # Computing the requested bandwidth in float @@ -1890,14 +1935,18 @@ class OaiCiTest(): req_bandwidth = '%.1f Gbits/sec' % req_bw req_bw = req_bw * 1000000000 - server_file = open('iperf_server_' + self.testCase_id + '_' + device_id + '.log', 'r') + server_file = open(filename, 'r') br_sum = 0.0 ji_sum = 0.0 pl_sum = 0 ps_sum = 0 row_idx = 0 for line in server_file.readlines(): - result = re.search('(?P[0-9\.]+ [KMG]bits\/sec) +(?P[0-9\.]+ ms) +(?P[0-9]+)/ +(?P[0-9]+)', str(line)) + if type==0: + result = re.search('(?P[0-9\.]+ [KMG]bits\/sec) +(?P[0-9\.]+ ms) +(?P[0-9]+)/ +(?P[0-9]+)', str(line)) + else: + result = re.search('^.+ +(?P[0-9\.]+ [KMG]bits\/sec) +(?P[0-9\.]+ ms) +(?P[0-9]+)\/(?P[0-9]+)', str(line)) + if result is not None: bitrate = result.group('bitrate') jitter = result.group('jitter') @@ -2127,13 +2176,65 @@ class OaiCiTest(): SSH.command('docker cp prod-trf-gen:/iperf-2.0.5/iperf_server_' + self.testCase_id + '_' + device_id + '.log ' + EPC.SourceCodePath + '/scripts', '\$', 5) SSH.close() SSH.copyin(EPC.IPAddress, EPC.UserName, EPC.Password, EPC.SourceCodePath+ '/scripts/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') - self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, modified_options) + filename='iperf_server_' + self.testCase_id + '_' + device_id + '.log' + self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, modified_options,filename,0) # in case of OAI-UE if (device_id == 'OAI-UE'): SSH.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/iperf_' + self.testCase_id + '_' + device_id + '.log', '.') SSH.copyout(EPC.IPAddress, EPC.UserName, EPC.Password, 'iperf_' + self.testCase_id + '_' + device_id + '.log', EPC.SourceCodePath + '/scripts') - def Iperf_common(self, lock, UE_IPAddress, device_id, idx, ue_num, statusQueue,EPC): + + def Iperf_Module(self, lock, UE_IPAddress, device_id, idx, ue_num, statusQueue,EPC, InfraUE): + SSH = sshconnection.SSHConnection() + iperf_time = self.Iperf_ComputeTime() + if self.iperf_direction=="DL": + logging.debug("Iperf for Module in DL mode detected") + #server side UE + Module_UE = cls_module_ue.Module_UE(InfraUE.ci_ue_infra[self.ue_id]) + SSH.open(Module_UE.HostIPAddress, Module_UE.HostUsername, Module_UE.HostPassword) + cmd = 'echo $USER; nohup iperf -s -B ' + UE_IPAddress + ' -u 2>&1 > iperf_server_' + self.testCase_id + '_' + self.ue_id + '.log' + SSH.command(cmd,'\$',5) + logging.debug(cmd) + #client side EPC + SSH.open(EPC.IPAddress, EPC.UserName, EPC.Password) + cmd = 'iperf -c ' + UE_IPAddress + ' ' + self.iperf_args + ' 2>&1 > iperf_client_' + self.testCase_id + '_' + self.ue_id + '.log' + SSH.command(cmd,'\$',int(iperf_time)*5.0) + logging.debug(cmd) + + #copy the 2 resulting files locally + SSH.copyin(Module_UE.HostIPAddress, Module_UE.HostUsername, Module_UE.HostPassword, 'iperf_server_' + self.testCase_id + '_' + self.ue_id + '.log', '.') + SSH.copyin(EPC.IPAddress, EPC.UserName, EPC.Password, 'iperf_client_' + self.testCase_id + '_' + self.ue_id + '.log', '.') + #send for analysis + filename='iperf_server_' + self.testCase_id + '_' + self.ue_id + '.log' + self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, self.iperf_args,filename,1) + + elif self.iperf_direction=="UL": + logging.debug("Iperf for Module in UL mode detected") + #server side UE + Module_UE = cls_module_ue.Module_UE(InfraUE.ci_ue_infra[self.ue_id]) + SSH.open(Module_UE.UEHostIPAddr, Module_UE.UEHostUserName, Module_UE.UEHostPassWord) + cmd = 'echo $USER; nohup iperf -s -B ' + UE_IPAddress + ' -u 2>&1 > iperf_server_' + self.testCase_id + '_' + self.ue_id + '.log' + SSH.command(cmd,'\$',5) + logging.debug(cmd) + #client side EPC + SSH.open(EPC.IPAddress, EPC.UserName, EPC.Password) + cmd = 'iperf -c ' + UE_IPAddress + ' ' + self.iperf_args + ' 2>&1 > iperf_client_' + self.testCase_id + '_' + self.ue_id + '.log' + SSH.command(cmd,'\$',int(iperf_time)*5.0) + logging.debug(cmd) + + #copy the 2 resulting files locally + SSH.copyin(Module_UE.UEHostIPAddr, Module_UE.UEHostUserName, Module_UE.UEHostPassWord, 'iperf_server_' + self.testCase_id + '_' + self.ue_id + '.log', '.') + SSH.copyin(EPC.IPAddress, EPC.UserName, EPC.Password, 'iperf_client_' + self.testCase_id + '_' + self.ue_id + '.log', '.') + #send for analysis + filename='iperf_server_' + self.testCase_id + '_' + self.ue_id + '.log' + self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, self.iperf_args,filename,1) + else : + logging.debug("Incorrect or missing IPERF direction in XML") + + SSH.close() + return + + def Iperf_common(self, lock, UE_IPAddress, device_id, idx, ue_num, statusQueue,EPC, InfraUE): try: SSH = sshconnection.SSHConnection() # Single-UE profile -- iperf only on one UE @@ -2229,8 +2330,13 @@ class OaiCiTest(): # Launch the IPERF client on the EPC side for DL (true for ltebox and old open-air-cn # But for OAI-Rel14-CUPS, we launch from python executor launchFromEpc = True + launchFromModule = False if re.match('OAI-Rel14-CUPS', EPC.Type, re.IGNORECASE): launchFromEpc = False + #if module + if self.ue_id!='' and self.iperf : + launchFromEpc = False + launchfromModule = True # When using a docker-based deployment, IPERF client shall be launched from trf container launchFromTrfContainer = False if re.match('OAI-Rel14-Docker', EPC.Type, re.IGNORECASE): @@ -2334,7 +2440,8 @@ class OaiCiTest(): subprocess.run(cmd, shell=True) except: pass - self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, modified_options) + filename='iperf_server_' + self.testCase_id + '_' + device_id + '.log' + self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, modified_options,filename,0) # in case of OAI UE: if (device_id == 'OAI-UE'): @@ -2422,7 +2529,8 @@ class OaiCiTest(): if (os.path.isfile('iperf_server_' + self.testCase_id + '.log')): os.remove('iperf_server_' + self.testCase_id + '.log') SSH.copyin(iServerIPAddr, iServerUser, iServerPasswd, '/tmp/tmp_iperf_server_' + self.testCase_id + '.log', 'iperf_server_' + self.testCase_id + '_OAI-UE.log') - self.Iperf_analyzeV2Server(lock, '10.0.1.2', 'OAI-UE', status_queue, modified_options) + filename='iperf_server_' + self.testCase_id + '_' + device_id + '.log' + self.Iperf_analyzeV2Server(lock, '10.0.1.2', 'OAI-UE', status_queue, modified_options,filename,0) # copying on the EPC server for logCollection if (clientStatus == -1): @@ -2457,7 +2565,7 @@ class OaiCiTest(): HTML.CreateHtmlTestRowQueue(self.iperf_args, 'KO', len(self.UEDevices), html_queue) self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC) - def Iperf(self,HTML,RAN,EPC,COTS_UE): + def Iperf(self,HTML,RAN,EPC,COTS_UE, InfraUE): result = re.search('noS1', str(RAN.Initialize_eNB_args)) if result is not None: self.IperfNoS1(HTML,RAN,EPC,COTS_UE) @@ -2477,11 +2585,26 @@ class OaiCiTest(): return ueIpStatus = self.GetAllUEIPAddresses() if (ueIpStatus < 0): - logging.debug('going here') HTML.CreateHtmlTestRow(self.iperf_args, 'KO', CONST.UE_IP_ADDRESS_ISSUE) self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC) return + + if self.ue_id=="": + ueIpStatus = self.GetAllUEIPAddresses() + if (ueIpStatus < 0): + HTML.CreateHtmlTestRow(self.iperf_args, 'KO', CONST.UE_IP_ADDRESS_ISSUE) + self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC) + return + else: + Module_UE = cls_module_ue.Module_UE(InfraUE.ci_ue_infra[self.ue_id]) + Module_UE.GetModuleIPAddress() + if Module_UE.UEIPAddress not in self.UEIPAddresses: + self.UEIPAddresses.append(Module_UE.UEIPAddress) + + + + self.dummyIperfVersion = '2.0.10' #cmd = 'iperf --version' #logging.debug(cmd + '\n') @@ -2498,13 +2621,18 @@ class OaiCiTest(): ue_num = len(self.UEIPAddresses) lock = Lock() status_queue = SimpleQueue() + logging.debug(self.UEIPAddresses) for UE_IPAddress in self.UEIPAddresses: device_id = self.UEDevices[i] - p = Process(target = self.Iperf_common, args = (lock,UE_IPAddress,device_id,i,ue_num,status_queue,EPC,)) - p.daemon = True - p.start() - multi_jobs.append(p) - i = i + 1 + #special quick and dirty treatment for modules, iperf to be restructured + if self.ue_id!="": + p = Process(target = self.Iperf_Module ,args = (lock, UE_IPAddress, device_id, i, ue_num, status_queue, EPC, InfraUE,)) + else: + p = Process(target = self.Iperf_common, args = (lock, UE_IPAddress, device_id, i, ue_num, status_queue, EPC, InfraUE,)) + p.daemon = True + p.start() + multi_jobs.append(p) + i = i + 1 for job in multi_jobs: job.join() diff --git a/ci-scripts/main.py b/ci-scripts/main.py index 3094197c54..d6bfe3c7c9 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -40,9 +40,9 @@ import constants as CONST import cls_oaicitest #main class for OAI CI test framework import cls_physim #class PhySim for physical simulators build and test -import cls_cots_ue #class CotsUe for Airplane mode control +import cls_cots_ue #class CotsUe for Airplane mode control of various mobile phones import cls_containerize #class Containerize for all container-based operations on RAN/UE objects - +import cls_ci_ueinfra #class defining the multi Ue infrastrucure import sshconnection import epc @@ -192,6 +192,14 @@ def GetParametersFromXML(action): else : RAN.air_interface[RAN.eNB_instance] = 'ocp-enb' + elif action == 'Initialize_UE': + ue_id = test.findtext('id') + if (ue_id is None): + CiTestObj.ue_id = "" + else: + CiTestObj.ue_id = ue_id + + elif action == 'Attach_UE': nbMaxUEtoAttach = test.findtext('nbMaxUEtoAttach') if (nbMaxUEtoAttach is None): @@ -252,9 +260,20 @@ def GetParametersFromXML(action): elif (action == 'Ping') or (action == 'Ping_CatM_module'): CiTestObj.ping_args = test.findtext('ping_args') CiTestObj.ping_packetloss_threshold = test.findtext('ping_packetloss_threshold') + ue_id = test.findtext('id') + if (ue_id is None): + CiTestObj.ue_id = "" + else: + CiTestObj.ue_id = ue_id elif action == 'Iperf': CiTestObj.iperf_args = test.findtext('iperf_args') + ue_id = test.findtext('id') + if (ue_id is None): + CiTestObj.ue_id = "" + else: + CiTestObj.ue_id = ue_id + CiTestObj.iperf_direction = test.findtext('direction')#used for modules only CiTestObj.iperf_packetloss_threshold = test.findtext('iperf_packetloss_threshold') CiTestObj.iperf_profile = test.findtext('iperf_profile') if (CiTestObj.iperf_profile is None): @@ -368,6 +387,10 @@ with open(yaml_file,'r') as f: xml_class_list = yaml.load(f,Loader=yaml.FullLoader) +InfraUE=cls_ci_ueinfra.InfraUE() #initialize UE infrastructure class +InfraUE.Get_UE_Infra("ci_ueinfra.yaml") #read the UE infra, filename is hardcoded and unique for the moment but should be passed as parameter from the test suite + + mode = '' @@ -382,7 +405,6 @@ CONTAINERS = cls_containerize.Containerize() ldpc=cls_physim.PhySim() #create an instance for LDPC test using GPU or CPU build - #----------------------------------------------------------- # Parsing Command Line Arguments #----------------------------------------------------------- @@ -671,7 +693,7 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re elif action == 'Terminate_eNB': RAN.TerminateeNB(HTML, EPC) elif action == 'Initialize_UE': - CiTestObj.InitializeUE(HTML,COTS_UE) + CiTestObj.InitializeUE(HTML,COTS_UE, InfraUE) elif action == 'Terminate_UE': CiTestObj.TerminateUE(HTML,COTS_UE) elif action == 'Attach_UE': @@ -701,9 +723,9 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re elif action == 'Ping_CatM_module': CiTestObj.PingCatM(HTML,RAN,EPC,COTS_UE,EPC) elif action == 'Ping': - CiTestObj.Ping(HTML,RAN,EPC,COTS_UE) + CiTestObj.Ping(HTML,RAN,EPC,COTS_UE, InfraUE) elif action == 'Iperf': - CiTestObj.Iperf(HTML,RAN,EPC,COTS_UE) + CiTestObj.Iperf(HTML,RAN,EPC,COTS_UE, InfraUE) elif action == 'Reboot_UE': CiTestObj.RebootUE(HTML,RAN,EPC) elif action == 'Initialize_HSS': diff --git a/ci-scripts/ran.py b/ci-scripts/ran.py index 783adb98e6..5bac3846c9 100644 --- a/ci-scripts/ran.py +++ b/ci-scripts/ran.py @@ -239,7 +239,6 @@ class RANManagement(): while (count > 0) and buildOAIprocess: mySSH.command('ps aux | grep --color=never build_ | grep -v grep', '\$', 6) result = re.search('build_oai', mySSH.getBefore()) - print(result) if result is None: buildOAIprocess = False else: From 31bc110de07bdf69f443c8af0b8b6bd5f0b43782 Mon Sep 17 00:00:00 2001 From: hardy Date: Sun, 4 Apr 2021 10:53:28 +0200 Subject: [PATCH 02/25] a bit of re factoring --- ci-scripts/cls_oaicitest.py | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/ci-scripts/cls_oaicitest.py b/ci-scripts/cls_oaicitest.py index a8a467153b..62b2784faa 100644 --- a/ci-scripts/cls_oaicitest.py +++ b/ci-scripts/cls_oaicitest.py @@ -1450,7 +1450,7 @@ class OaiCiTest(): statusQueue.put(message) lock.release() - def Ping_common(self, lock, UE_IPAddress, device_id, statusQueue,EPC, InfraUE): + def Ping_common(self, lock, UE_IPAddress, device_id, statusQueue,EPC, Module_UE): try: SSH = sshconnection.SSHConnection() # Launch ping on the EPC side (true for ltebox and old open-air-cn) @@ -1498,8 +1498,6 @@ class OaiCiTest(): #cat is executed on EPC SSH.command('cat ' + EPC.SourceCodePath + '/scripts/ping_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) else: #launch from Module - Module_UE = cls_module_ue.Module_UE(InfraUE.ci_ue_infra[self.ue_id]) - SSH.open(Module_UE.HostIPAddress, Module_UE.HostUsername, Module_UE.HostPassword) cmd = 'ping -I ' + UE_IPAddress + ' ' + self.ping_args + ' ' + EPC.IPAddress + ' 2>&1 > ping_' + self.testCase_id + '_' + self.ue_id + '.log' SSH.command(cmd,'\$',int(ping_time[0])*1.5) @@ -1734,7 +1732,7 @@ class OaiCiTest(): device_id = self.UEDevices[i] else: device_id = "" - p = Process(target = self.Ping_common, args = (lock,UE_IPAddress,device_id,status_queue,EPC,InfraUE,)) + p = Process(target = self.Ping_common, args = (lock,UE_IPAddress,device_id,status_queue,EPC,Module_UE,)) p.daemon = True p.start() multi_jobs.append(p) @@ -2184,13 +2182,12 @@ class OaiCiTest(): SSH.copyout(EPC.IPAddress, EPC.UserName, EPC.Password, 'iperf_' + self.testCase_id + '_' + device_id + '.log', EPC.SourceCodePath + '/scripts') - def Iperf_Module(self, lock, UE_IPAddress, device_id, idx, ue_num, statusQueue,EPC, InfraUE): + def Iperf_Module(self, lock, UE_IPAddress, device_id, idx, ue_num, statusQueue,EPC, Module_UE): SSH = sshconnection.SSHConnection() iperf_time = self.Iperf_ComputeTime() if self.iperf_direction=="DL": logging.debug("Iperf for Module in DL mode detected") #server side UE - Module_UE = cls_module_ue.Module_UE(InfraUE.ci_ue_infra[self.ue_id]) SSH.open(Module_UE.HostIPAddress, Module_UE.HostUsername, Module_UE.HostPassword) cmd = 'echo $USER; nohup iperf -s -B ' + UE_IPAddress + ' -u 2>&1 > iperf_server_' + self.testCase_id + '_' + self.ue_id + '.log' SSH.command(cmd,'\$',5) @@ -2210,31 +2207,30 @@ class OaiCiTest(): elif self.iperf_direction=="UL": logging.debug("Iperf for Module in UL mode detected") - #server side UE - Module_UE = cls_module_ue.Module_UE(InfraUE.ci_ue_infra[self.ue_id]) - SSH.open(Module_UE.UEHostIPAddr, Module_UE.UEHostUserName, Module_UE.UEHostPassWord) - cmd = 'echo $USER; nohup iperf -s -B ' + UE_IPAddress + ' -u 2>&1 > iperf_server_' + self.testCase_id + '_' + self.ue_id + '.log' + #server side EPC + SSH.open(EPC.IPAddress, EPC.UserName, EPC.Password) + cmd = 'iperf -s -u 2>&1 > iperf_server_' + self.testCase_id + '_' + self.ue_id + '.log' SSH.command(cmd,'\$',5) logging.debug(cmd) - #client side EPC - SSH.open(EPC.IPAddress, EPC.UserName, EPC.Password) - cmd = 'iperf -c ' + UE_IPAddress + ' ' + self.iperf_args + ' 2>&1 > iperf_client_' + self.testCase_id + '_' + self.ue_id + '.log' + #client side UE + SSH.open(Module_UE.HostIPAddress, Module_UE.HostUsername, Module_UE.HostPassword) + cmd = 'echo $USER; nohup iperf -B ' + UE_IPAddress + ' ' + '-c ' + EPC.IPAddress + ' ' + self.iperf_args + ' 2>&1 > iperf_client_' + self.testCase_id + '_' + self.ue_id + '.log' SSH.command(cmd,'\$',int(iperf_time)*5.0) logging.debug(cmd) #copy the 2 resulting files locally - SSH.copyin(Module_UE.UEHostIPAddr, Module_UE.UEHostUserName, Module_UE.UEHostPassWord, 'iperf_server_' + self.testCase_id + '_' + self.ue_id + '.log', '.') + SSH.copyin(Module_UE.HostIPAddress, Module_UE.UEHostUsername, Module_UE.UEHostPassword, 'iperf_server_' + self.testCase_id + '_' + self.ue_id + '.log', '.') SSH.copyin(EPC.IPAddress, EPC.UserName, EPC.Password, 'iperf_client_' + self.testCase_id + '_' + self.ue_id + '.log', '.') #send for analysis - filename='iperf_server_' + self.testCase_id + '_' + self.ue_id + '.log' - self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, self.iperf_args,filename,1) + filename='iperf_client_' + self.testCase_id + '_' + self.ue_id + '.log' + self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, self.iperf_args,filename,0) else : logging.debug("Incorrect or missing IPERF direction in XML") SSH.close() return - def Iperf_common(self, lock, UE_IPAddress, device_id, idx, ue_num, statusQueue,EPC, InfraUE): + def Iperf_common(self, lock, UE_IPAddress, device_id, idx, ue_num, statusQueue,EPC): try: SSH = sshconnection.SSHConnection() # Single-UE profile -- iperf only on one UE @@ -2626,9 +2622,9 @@ class OaiCiTest(): device_id = self.UEDevices[i] #special quick and dirty treatment for modules, iperf to be restructured if self.ue_id!="": - p = Process(target = self.Iperf_Module ,args = (lock, UE_IPAddress, device_id, i, ue_num, status_queue, EPC, InfraUE,)) + p = Process(target = self.Iperf_Module ,args = (lock, UE_IPAddress, device_id, i, ue_num, status_queue, EPC, Module_UE,)) else: - p = Process(target = self.Iperf_common, args = (lock, UE_IPAddress, device_id, i, ue_num, status_queue, EPC, InfraUE,)) + p = Process(target = self.Iperf_common, args = (lock, UE_IPAddress, device_id, i, ue_num, status_queue, EPC, )) p.daemon = True p.start() multi_jobs.append(p) From ea89cfa1a180bf0bf3070200800a95e32ad59462 Mon Sep 17 00:00:00 2001 From: Remi Hardy Date: Sun, 4 Apr 2021 15:28:49 +0200 Subject: [PATCH 03/25] iperf UL and DL working ok --- ci-scripts/cls_oaicitest.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ci-scripts/cls_oaicitest.py b/ci-scripts/cls_oaicitest.py index 62b2784faa..1cd435e723 100644 --- a/ci-scripts/cls_oaicitest.py +++ b/ci-scripts/cls_oaicitest.py @@ -2209,21 +2209,21 @@ class OaiCiTest(): logging.debug("Iperf for Module in UL mode detected") #server side EPC SSH.open(EPC.IPAddress, EPC.UserName, EPC.Password) - cmd = 'iperf -s -u 2>&1 > iperf_server_' + self.testCase_id + '_' + self.ue_id + '.log' + cmd = 'echo $USER; nohup iperf -s -u 2>&1 > iperf_server_' + self.testCase_id + '_' + self.ue_id + '.log' SSH.command(cmd,'\$',5) logging.debug(cmd) #client side UE SSH.open(Module_UE.HostIPAddress, Module_UE.HostUsername, Module_UE.HostPassword) - cmd = 'echo $USER; nohup iperf -B ' + UE_IPAddress + ' ' + '-c ' + EPC.IPAddress + ' ' + self.iperf_args + ' 2>&1 > iperf_client_' + self.testCase_id + '_' + self.ue_id + '.log' + cmd = 'iperf -B ' + UE_IPAddress + ' ' + '-c ' + EPC.IPAddress + ' ' + self.iperf_args + ' > iperf_client_' + self.testCase_id + '_' + self.ue_id + '.log' SSH.command(cmd,'\$',int(iperf_time)*5.0) logging.debug(cmd) #copy the 2 resulting files locally - SSH.copyin(Module_UE.HostIPAddress, Module_UE.UEHostUsername, Module_UE.UEHostPassword, 'iperf_server_' + self.testCase_id + '_' + self.ue_id + '.log', '.') + SSH.copyin(Module_UE.HostIPAddress, Module_UE.HostUsername, Module_UE.HostPassword, 'iperf_server_' + self.testCase_id + '_' + self.ue_id + '.log', '.') SSH.copyin(EPC.IPAddress, EPC.UserName, EPC.Password, 'iperf_client_' + self.testCase_id + '_' + self.ue_id + '.log', '.') #send for analysis - filename='iperf_client_' + self.testCase_id + '_' + self.ue_id + '.log' - self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, self.iperf_args,filename,0) + filename='iperf_server_' + self.testCase_id + '_' + self.ue_id + '.log' + self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, self.iperf_args,filename,1) else : logging.debug("Incorrect or missing IPERF direction in XML") From 41cb06546fedc1b7a126507c3209a3111751abc9 Mon Sep 17 00:00:00 2001 From: Remi Hardy Date: Sun, 4 Apr 2021 15:36:34 +0200 Subject: [PATCH 04/25] fix UE name in html for iperf --- ci-scripts/cls_oaicitest.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ci-scripts/cls_oaicitest.py b/ci-scripts/cls_oaicitest.py index 1cd435e723..99252da20c 100644 --- a/ci-scripts/cls_oaicitest.py +++ b/ci-scripts/cls_oaicitest.py @@ -2622,6 +2622,7 @@ class OaiCiTest(): device_id = self.UEDevices[i] #special quick and dirty treatment for modules, iperf to be restructured if self.ue_id!="": + device_id = Module_UE.ID + "-" + Module_UE.Kind p = Process(target = self.Iperf_Module ,args = (lock, UE_IPAddress, device_id, i, ue_num, status_queue, EPC, Module_UE,)) else: p = Process(target = self.Iperf_common, args = (lock, UE_IPAddress, device_id, i, ue_num, status_queue, EPC, )) From 69451ed33fceeaebf65b89d4ed84ad04a907b9ad Mon Sep 17 00:00:00 2001 From: Remi Hardy Date: Sun, 4 Apr 2021 15:54:57 +0200 Subject: [PATCH 05/25] fix UE name in html for ping --- ci-scripts/cls_oaicitest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-scripts/cls_oaicitest.py b/ci-scripts/cls_oaicitest.py index 99252da20c..7e27a41a0a 100644 --- a/ci-scripts/cls_oaicitest.py +++ b/ci-scripts/cls_oaicitest.py @@ -1731,7 +1731,7 @@ class OaiCiTest(): if self.ue_id=="": device_id = self.UEDevices[i] else: - device_id = "" + device_id = Module_UE.ID + "-" + Module_UE.Kind p = Process(target = self.Ping_common, args = (lock,UE_IPAddress,device_id,status_queue,EPC,Module_UE,)) p.daemon = True p.start() From 5a3dc09fdb1426317694469ca2c9a14b327285f4 Mon Sep 17 00:00:00 2001 From: hardy Date: Sun, 4 Apr 2021 21:27:28 +0200 Subject: [PATCH 06/25] fixes for other CI pipelines --- ci-scripts/ci_ueinfra.yaml | 11 ++--------- ci-scripts/cls_oaicitest.py | 1 + ci-scripts/main.py | 12 +++++++++++- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/ci-scripts/ci_ueinfra.yaml b/ci-scripts/ci_ueinfra.yaml index 8ea75f9a85..15ca6b3859 100644 --- a/ci-scripts/ci_ueinfra.yaml +++ b/ci-scripts/ci_ueinfra.yaml @@ -9,15 +9,8 @@ idefix: HostUsername : oaicicd HostPassword : oaicicd HostSourceCodePath : none -dummy1: - ID: dummy1 - Kind : simcom - State : disabled - Process : quectel-cm - HostIPAddress : 192.168.18.187 - HostUsername : oaicicd - HostPassword : oaicicd - HostSourceCodePath : none +dummy: + ID: dummy dummy2: ID: dummy2 Kind : cots diff --git a/ci-scripts/cls_oaicitest.py b/ci-scripts/cls_oaicitest.py index 7e27a41a0a..f4f30c5d18 100644 --- a/ci-scripts/cls_oaicitest.py +++ b/ci-scripts/cls_oaicitest.py @@ -1712,6 +1712,7 @@ class OaiCiTest(): return if self.ue_id=="": + Module_UE = cls_module_ue.Module_UE(InfraUE.ci_ue_infra['dummy']) #RH, temporary, we need a dummy Module_UE object to pass to Ping_common ueIpStatus = self.GetAllUEIPAddresses() if (ueIpStatus < 0): HTML.CreateHtmlTestRow(self.ping_args, 'KO', CONST.UE_IP_ADDRESS_ISSUE) diff --git a/ci-scripts/main.py b/ci-scripts/main.py index d6bfe3c7c9..0c0c76dc09 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -387,8 +387,18 @@ with open(yaml_file,'r') as f: xml_class_list = yaml.load(f,Loader=yaml.FullLoader) + +#loading UE infrastructure from yaml +ue_infra_file='ci_ueinfra.yaml' +if (os.path.isfile(ue_infra_file)): + yaml_file=ue_infra_file +elif (os.path.isfile('ci-scripts/'+ue_infra_file)): + yaml_file='ci-scripts/'+ue_infra_file +else: + logging.error("UE infrastructure yaml file cannot be found") + sys.exit("UE infrastructure file cannot be found") InfraUE=cls_ci_ueinfra.InfraUE() #initialize UE infrastructure class -InfraUE.Get_UE_Infra("ci_ueinfra.yaml") #read the UE infra, filename is hardcoded and unique for the moment but should be passed as parameter from the test suite +InfraUE.Get_UE_Infra(yaml_file) #read the UE infra, filename is hardcoded and unique for the moment but should be passed as parameter from the test suite From c1be8be1bc392b5a4f774c50c8138e61c309e43d Mon Sep 17 00:00:00 2001 From: hardy Date: Mon, 5 Apr 2021 11:14:53 +0200 Subject: [PATCH 07/25] new nsa testcase for quectel --- ci-scripts/xml_files/fr1_nsa_quectel.xml | 139 +++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 ci-scripts/xml_files/fr1_nsa_quectel.xml diff --git a/ci-scripts/xml_files/fr1_nsa_quectel.xml b/ci-scripts/xml_files/fr1_nsa_quectel.xml new file mode 100644 index 0000000000..a1604af7b3 --- /dev/null +++ b/ci-scripts/xml_files/fr1_nsa_quectel.xml @@ -0,0 +1,139 @@ + + + TEST-NSA-FR1-TM1 + NSA QUECTEL + tasks + + 030000 + 040000 + 000001 + 010000 + 000001 + 050000 + 050001 + 000001 + 070000 + 000001 + 070001 + 000001 + 080001 + 080000 + + + + + + Initialize_UE + Initialize Quectel + idefix + + + + + Detach_UE + Detach UE + idefix + + + + + Initialize_eNB + Initialize eNB + -O ci-scripts/conf_files/enb.band7.tm1.fr1.25PRB.usrpb210.conf + 0 + 0 + lte + + + + + Initialize_eNB + Initialize gNB + -O ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpb210.conf -E + 1 + 1 + nr + + + + IdleSleep + Sleep + 10 + + + + Ping + Ping: 20pings in 20sec + idefix + -c 20 + 50 + + + + Ping + Ping: 100pings in 20sec + idefix + -c 100 -i 0.2 + 50 + + + + Iperf + iperf (DL/20Mbps/UDP)(20 sec)(single-ue profile) + -u -b 20M -t 20 -i 1 + DL + idefix + 50 + single-ue + + + + Iperf + iperf (UL/3Mbps/UDP)(20 sec)(single-ue profile) + -u -b 3M -t 20 -i 1 + UL + idefix + 50 + single-ue + + + + + Terminate_eNB + Terminate eNB + 0 + 0 + lte + + + + Terminate_eNB + Terminate gNB + 1 + 1 + nr + + + + From 53e624e4c2386d59ceffc1e065edf0367d450cf1 Mon Sep 17 00:00:00 2001 From: hardy Date: Mon, 5 Apr 2021 12:25:50 +0200 Subject: [PATCH 08/25] improving module control scripts, to be tested --- ci-scripts/ci_ctl_qtel.py | 63 ++++++++++++++++++++++++++++++++++++++ ci-scripts/ci_ueinfra.yaml | 3 +- 2 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 ci-scripts/ci_ctl_qtel.py diff --git a/ci-scripts/ci_ctl_qtel.py b/ci-scripts/ci_ctl_qtel.py new file mode 100644 index 0000000000..1813c1daab --- /dev/null +++ b/ci-scripts/ci_ctl_qtel.py @@ -0,0 +1,63 @@ +# * 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 +# */ +#--------------------------------------------------------------------- +# +# Required Python Version +# Python 3.x +# +#--------------------------------------------------------------------- + + + +import sys +import time +import serial + + +class qtel_ctl: + def __init__(self, usb_port_at): + self.QUECTEL_USB_PORT_AT = usb_port_at #'/dev/ttyUSB2' + self.modem = serial.Serial(self.QUECTEL_USB_PORT_AT, timeout=1) + self.cmd_dict= {"wup": self.wup;"detach":self.detach} + + def __set_modem_state(self,ser,state): + self.__send_command(ser,"AT+CFUN={}\r".format(state)) + + def __send_command(self,ser,com): + if ser.inWaiting() > 0: + ser.flushInput() + ser.write(com.encode()) + + + def wup(self): + self.__set_modem_state(modem,0) + time.sleep(3) + self.__set_modem_state(modem,1) + + def detach(self): + self.__set_modem_state(modem,0) + + + + +if __name__ == "__main__": + command = sys.argv[2] + Module=qtel_ctl(sys.argv[1]) + Module.cmd_dict[command]() diff --git a/ci-scripts/ci_ueinfra.yaml b/ci-scripts/ci_ueinfra.yaml index 15ca6b3859..e62943e683 100644 --- a/ci-scripts/ci_ueinfra.yaml +++ b/ci-scripts/ci_ueinfra.yaml @@ -3,7 +3,8 @@ idefix: State : enabled Kind : quectel Process : quectel-CM - WakeupScript : ci_qtel.py + WakeupScript : ci_ctl_qtel.py /dev/ttyUSB2 wup + DetachScript : ci_ctl_qtel.py /dev/ttyUSB2 detach UENetwork : wwan0 HostIPAddress : 192.168.18.188 HostUsername : oaicicd From 31726d685f0aa83494e4410376eb74c5e96a08ac Mon Sep 17 00:00:00 2001 From: Remi Hardy Date: Mon, 5 Apr 2021 19:58:54 +0200 Subject: [PATCH 09/25] fixing qtel control --- ci-scripts/ci_ctl_qtel.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ci-scripts/ci_ctl_qtel.py b/ci-scripts/ci_ctl_qtel.py index 1813c1daab..b9e61c1687 100644 --- a/ci-scripts/ci_ctl_qtel.py +++ b/ci-scripts/ci_ctl_qtel.py @@ -35,7 +35,7 @@ class qtel_ctl: def __init__(self, usb_port_at): self.QUECTEL_USB_PORT_AT = usb_port_at #'/dev/ttyUSB2' self.modem = serial.Serial(self.QUECTEL_USB_PORT_AT, timeout=1) - self.cmd_dict= {"wup": self.wup;"detach":self.detach} + self.cmd_dict= {"wup": self.wup,"detach":self.detach} def __set_modem_state(self,ser,state): self.__send_command(ser,"AT+CFUN={}\r".format(state)) @@ -47,12 +47,12 @@ class qtel_ctl: def wup(self): - self.__set_modem_state(modem,0) + self.__set_modem_state(self.modem,0) time.sleep(3) - self.__set_modem_state(modem,1) + self.__set_modem_state(self.modem,1) def detach(self): - self.__set_modem_state(modem,0) + self.__set_modem_state(self.modem,0) From 7878f8af6ed0bf2baa6ebdf3c61013cbe793dd87 Mon Sep 17 00:00:00 2001 From: Remi Hardy Date: Mon, 5 Apr 2021 20:14:38 +0200 Subject: [PATCH 10/25] adding some inline doc/comments to ci_ctl_qtel.py --- ci-scripts/ci_ctl_qtel.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/ci-scripts/ci_ctl_qtel.py b/ci-scripts/ci_ctl_qtel.py index b9e61c1687..1030b54616 100644 --- a/ci-scripts/ci_ctl_qtel.py +++ b/ci-scripts/ci_ctl_qtel.py @@ -32,10 +32,13 @@ import serial class qtel_ctl: + #--------------- + #private methods + #--------------- def __init__(self, usb_port_at): - self.QUECTEL_USB_PORT_AT = usb_port_at #'/dev/ttyUSB2' + self.QUECTEL_USB_PORT_AT = usb_port_at #ex : '/dev/ttyUSB2' self.modem = serial.Serial(self.QUECTEL_USB_PORT_AT, timeout=1) - self.cmd_dict= {"wup": self.wup,"detach":self.detach} + self.cmd_dict= {"wup": self.wup,"detach":self.detach}#dictionary of function pointers def __set_modem_state(self,ser,state): self.__send_command(ser,"AT+CFUN={}\r".format(state)) @@ -45,19 +48,24 @@ class qtel_ctl: ser.flushInput() ser.write(com.encode()) - - def wup(self): + #-------------- + #public methods + #-------------- + def wup(self):#sending AT+CFUN=0, then AT+CFUN=1 self.__set_modem_state(self.modem,0) time.sleep(3) self.__set_modem_state(self.modem,1) - def detach(self): + def detach(self):#sending AT+CFUN=0 self.__set_modem_state(self.modem,0) if __name__ == "__main__": + #argv[1] : usb port + #argv[2] : qtel command (see function pointers dict "wup", "detach" etc ...) command = sys.argv[2] Module=qtel_ctl(sys.argv[1]) + #calling the function to be applied Module.cmd_dict[command]() From 87a5e40edad615e305c4ad96998332d1c517af57 Mon Sep 17 00:00:00 2001 From: hardy Date: Wed, 7 Apr 2021 14:03:45 +0200 Subject: [PATCH 11/25] fix CI issue (removing code that should have been deleted) --- ci-scripts/cls_oaicitest.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/ci-scripts/cls_oaicitest.py b/ci-scripts/cls_oaicitest.py index f4f30c5d18..c0492f10f2 100644 --- a/ci-scripts/cls_oaicitest.py +++ b/ci-scripts/cls_oaicitest.py @@ -2580,20 +2580,14 @@ class OaiCiTest(): HTML.CreateHtmlTestRow(self.iperf_args, 'KO', pStatus) self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC) return - ueIpStatus = self.GetAllUEIPAddresses() - if (ueIpStatus < 0): - HTML.CreateHtmlTestRow(self.iperf_args, 'KO', CONST.UE_IP_ADDRESS_ISSUE) - self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC) - return - - if self.ue_id=="": + if self.ue_id=="":#is not a module, follow legacy code ueIpStatus = self.GetAllUEIPAddresses() if (ueIpStatus < 0): HTML.CreateHtmlTestRow(self.iperf_args, 'KO', CONST.UE_IP_ADDRESS_ISSUE) self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC) return - else: + else: #is a module Module_UE = cls_module_ue.Module_UE(InfraUE.ci_ue_infra[self.ue_id]) Module_UE.GetModuleIPAddress() if Module_UE.UEIPAddress not in self.UEIPAddresses: From d727eebaf51da2bab2f1963679754d0d2dab5352 Mon Sep 17 00:00:00 2001 From: hardy Date: Wed, 7 Apr 2021 20:30:42 +0200 Subject: [PATCH 12/25] fix incorrect indentation that makes the CI fail for multiple UEs --- ci-scripts/cls_oaicitest.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/ci-scripts/cls_oaicitest.py b/ci-scripts/cls_oaicitest.py index c0492f10f2..3e90fd6eb7 100644 --- a/ci-scripts/cls_oaicitest.py +++ b/ci-scripts/cls_oaicitest.py @@ -2615,16 +2615,16 @@ class OaiCiTest(): logging.debug(self.UEIPAddresses) for UE_IPAddress in self.UEIPAddresses: device_id = self.UEDevices[i] - #special quick and dirty treatment for modules, iperf to be restructured - if self.ue_id!="": - device_id = Module_UE.ID + "-" + Module_UE.Kind - p = Process(target = self.Iperf_Module ,args = (lock, UE_IPAddress, device_id, i, ue_num, status_queue, EPC, Module_UE,)) - else: - p = Process(target = self.Iperf_common, args = (lock, UE_IPAddress, device_id, i, ue_num, status_queue, EPC, )) - p.daemon = True - p.start() - multi_jobs.append(p) - i = i + 1 + #special quick and dirty treatment for modules, iperf to be restructured + if self.ue_id!="": #is module + device_id = Module_UE.ID + "-" + Module_UE.Kind + p = Process(target = self.Iperf_Module ,args = (lock, UE_IPAddress, device_id, i, ue_num, status_queue, EPC, Module_UE,)) + else: #legacy code + p = Process(target = self.Iperf_common, args = (lock, UE_IPAddress, device_id, i, ue_num, status_queue, EPC, )) + p.daemon = True + p.start() + multi_jobs.append(p) + i = i + 1 for job in multi_jobs: job.join() From 8def7528182cc8c6e537dceed54e4bd114153a1a Mon Sep 17 00:00:00 2001 From: hardy Date: Mon, 12 Apr 2021 10:18:10 +0200 Subject: [PATCH 13/25] adding module UE detach, to be tested --- ci-scripts/cls_module_ue.py | 10 +++ ci-scripts/cls_oaicitest.py | 121 +++++++++++++++++++----------------- ci-scripts/main.py | 6 ++ 3 files changed, 81 insertions(+), 56 deletions(-) diff --git a/ci-scripts/cls_module_ue.py b/ci-scripts/cls_module_ue.py index 87902deaff..6aa4265571 100644 --- a/ci-scripts/cls_module_ue.py +++ b/ci-scripts/cls_module_ue.py @@ -78,6 +78,7 @@ class Module_UE: logging.debug(self.Process + " process NOT found") return False + #Wakeup/Detach can probably be improved with encapsulation of the command such def Command(self, command) #this method wakes up the module by calling the specified python script def WakeUp(self): mySSH = sshconnection.SSHConnection() @@ -87,6 +88,15 @@ class Module_UE: logging.debug("Module wake-up") mySSH.close() + #this method detaches the module by calling the specified python script + def Detach(self): + mySSH = sshconnection.SSHConnection() + mySSH.open(self.HostIPAddress, self.HostUsername, self.HostPassword) + mySSH.command('echo ' + self.HostPassword + ' | sudo -S python3 ' + self.DetachScript + ' ','\$',5) + time.sleep(5) + logging.debug("Module detach") + mySSH.close() + #this method retrieves the Module IP address (not the Host IP address) def GetModuleIPAddress(self): HOST=self.HostIPAddress diff --git a/ci-scripts/cls_oaicitest.py b/ci-scripts/cls_oaicitest.py index 3e90fd6eb7..9bcfa458ba 100644 --- a/ci-scripts/cls_oaicitest.py +++ b/ci-scripts/cls_oaicitest.py @@ -392,7 +392,7 @@ class OaiCiTest(): Module_UE.GetModuleIPAddress() HTML.CreateHtmlTestRow(Module_UE.UEIPAddress, 'OK', CONST.ALL_PROCESSES_OK) self.UEIPAddresses.append(Module_UE.UEIPAddress) - logging.debug(self.UEIPAddresses) + logging.debug('UEs IP addresses : '+ self.UEIPAddresses) def InitializeOAIUE(self,HTML,RAN,EPC,COTS_UE): if self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '' or self.UESourceCodePath == '': @@ -957,31 +957,32 @@ class OaiCiTest(): except: os.kill(os.getppid(),signal.SIGUSR1) - def AttachUE(self,HTML,RAN,EPC,COTS_UE): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - HELP.GenericHelp(CONST.Version) - sys.exit('Insufficient Parameter') - check_eNB = True - check_OAI_UE = False - pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE,RAN,EPC) - if (pStatus < 0): - HTML.CreateHtmlTestRow('N/A', 'KO', pStatus) - self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC) - return - multi_jobs = [] - status_queue = SimpleQueue() - lock = Lock() - nb_ue_to_connect = 0 - for device_id in self.UEDevices: - if (self.nbMaxUEtoAttach == -1) or (nb_ue_to_connect < self.nbMaxUEtoAttach): - self.UEDevicesStatus[nb_ue_to_connect] = CONST.UE_STATUS_ATTACHING - p = Process(target = self.AttachUE_common, args = (device_id, status_queue, lock,nb_ue_to_connect,COTS_UE,)) - p.daemon = True - p.start() - multi_jobs.append(p) - nb_ue_to_connect = nb_ue_to_connect + 1 - for job in multi_jobs: - job.join() + def AttachUE(self,HTML,RAN,EPC,COTS_UE,InfraUE): + if self.ue_id=='':#no ID specified, then it is a COTS controlled by ADB + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + HELP.GenericHelp(CONST.Version) + sys.exit('Insufficient Parameter') + check_eNB = True + check_OAI_UE = False + pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE,RAN,EPC) + if (pStatus < 0): + HTML.CreateHtmlTestRow('N/A', 'KO', pStatus) + self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC) + return + multi_jobs = [] + status_queue = SimpleQueue() + lock = Lock() + nb_ue_to_connect = 0 + for device_id in self.UEDevices: + if (self.nbMaxUEtoAttach == -1) or (nb_ue_to_connect < self.nbMaxUEtoAttach): + self.UEDevicesStatus[nb_ue_to_connect] = CONST.UE_STATUS_ATTACHING + p = Process(target = self.AttachUE_common, args = (device_id, status_queue, lock,nb_ue_to_connect,COTS_UE,)) + p.daemon = True + p.start() + multi_jobs.append(p) + nb_ue_to_connect = nb_ue_to_connect + 1 + for job in multi_jobs: + job.join() if (status_queue.empty()): HTML.CreateHtmlTestRow('N/A', 'KO', CONST.ALL_PROCESSES_OK) @@ -1039,36 +1040,44 @@ class OaiCiTest(): os.kill(os.getppid(),signal.SIGUSR1) def DetachUE(self,HTML,RAN,EPC,COTS_UE): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - HELP.GenericHelp(CONST.Version) - sys.exit('Insufficient Parameter') - check_eNB = True - check_OAI_UE = False - pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE,RAN,EPC) - if (pStatus < 0): - HTML.CreateHtmlTestRow('N/A', 'KO', pStatus) - self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC) - return - multi_jobs = [] - cnt = 0 - for device_id in self.UEDevices: - self.UEDevicesStatus[cnt] = CONST.UE_STATUS_DETACHING - p = Process(target = self.DetachUE_common, args = (device_id,cnt,COTS_UE,)) - p.daemon = True - p.start() - multi_jobs.append(p) - cnt += 1 - for job in multi_jobs: - job.join() - HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) - result = re.search('T_stdout', str(RAN.Initialize_eNB_args)) - if result is not None: - logging.debug('Waiting 5 seconds to fill up record file') - time.sleep(5) - cnt = 0 - while cnt < len(self.UEDevices): - self.UEDevicesStatus[cnt] = CONST.UE_STATUS_DETACHED - cnt += 1 + if self.ue_id=='':#no ID specified, then it is a COTS controlled by ADB + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + HELP.GenericHelp(CONST.Version) + sys.exit('Insufficient Parameter') + check_eNB = True + check_OAI_UE = False + pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE,RAN,EPC) + if (pStatus < 0): + HTML.CreateHtmlTestRow('N/A', 'KO', pStatus) + self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC) + return + multi_jobs = [] + cnt = 0 + for device_id in self.UEDevices: + self.UEDevicesStatus[cnt] = CONST.UE_STATUS_DETACHING + p = Process(target = self.DetachUE_common, args = (device_id,cnt,COTS_UE,)) + p.daemon = True + p.start() + multi_jobs.append(p) + cnt += 1 + for job in multi_jobs: + job.join() + HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) + result = re.search('T_stdout', str(RAN.Initialize_eNB_args)) + if result is not None: + logging.debug('Waiting 5 seconds to fill up record file') + time.sleep(5) + cnt = 0 + while cnt < len(self.UEDevices): + self.UEDevicesStatus[cnt] = CONST.UE_STATUS_DETACHED + cnt += 1 + else:#if an ID is specified, it is a module from the yaml infrastructure file + Module_UE = cls_module_ue.Module_UE(InfraUE.ci_ue_infra[self.ue_id]) + is_module=Module_UE.CheckIsModule() + if is_module: + Module_UE.Detach() + Module_UE.GetModuleIPAddress() + HTML.CreateHtmlTestRow(Module_UE.UEIPAddress, 'OK', CONST.ALL_PROCESSES_OK) def RebootUE_common(self, device_id): try: diff --git a/ci-scripts/main.py b/ci-scripts/main.py index 1d6f81c820..5a26e3a5ed 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -200,6 +200,12 @@ def GetParametersFromXML(action): else: CiTestObj.ue_id = ue_id + elif action == 'Detach_UE': + ue_id = test.findtext('id') + if (ue_id is None): + CiTestObj.ue_id = "" + else: + CiTestObj.ue_id = ue_id elif action == 'Attach_UE': nbMaxUEtoAttach = test.findtext('nbMaxUEtoAttach') From b6daabc2b5c9f5e84a3622bd438f61c8a20dd1e8 Mon Sep 17 00:00:00 2001 From: hardy Date: Tue, 13 Apr 2021 21:19:54 +0200 Subject: [PATCH 14/25] tentative to improve Module control encapsulation --- ci-scripts/ci_ueinfra.yaml | 5 +- ci-scripts/cls_module_ue.py | 73 +++++++++++++++--------- ci-scripts/cls_oaicitest.py | 12 ++-- ci-scripts/main.py | 2 +- ci-scripts/xml_files/fr1_nsa_quectel.xml | 53 ++++++++++------- 5 files changed, 87 insertions(+), 58 deletions(-) diff --git a/ci-scripts/ci_ueinfra.yaml b/ci-scripts/ci_ueinfra.yaml index e62943e683..1ca913072c 100644 --- a/ci-scripts/ci_ueinfra.yaml +++ b/ci-scripts/ci_ueinfra.yaml @@ -2,9 +2,12 @@ idefix: ID: idefix State : enabled Kind : quectel - Process : quectel-CM + Process : + Name : quectel-CM + Cmd : /home/oaicicd/quectel-CM/quectel-CM -s oai.ipv4 -4 WakeupScript : ci_ctl_qtel.py /dev/ttyUSB2 wup DetachScript : ci_ctl_qtel.py /dev/ttyUSB2 detach + PLMN : 22201 UENetwork : wwan0 HostIPAddress : 192.168.18.188 HostUsername : oaicicd diff --git a/ci-scripts/cls_module_ue.py b/ci-scripts/cls_module_ue.py index 6aa4265571..4586be33e8 100644 --- a/ci-scripts/cls_module_ue.py +++ b/ci-scripts/cls_module_ue.py @@ -56,7 +56,8 @@ class Module_UE: for k, v in Module.items(): setattr(self, k, v) self.UEIPAddress = "" - + #dictionary linking command names and related module scripts + self.cmd_dict= {"wup": self.WakeupScript,"detach":self.DetachScript}#dictionary of function scripts @@ -65,56 +66,72 @@ class Module_UE: #-----------------$ #this method checks if the specified Process is running on the server hosting the module - def CheckIsModule(self): + #if not it will be started + def CheckCMProcess(self): HOST=self.HostIPAddress - COMMAND="ps aux | grep " + self.Process + " | grep -v grep " + COMMAND="ps aux | grep " + self.Process['Name'] + " | grep -v grep " logging.debug(COMMAND) ssh = subprocess.Popen(["ssh", "%s" % HOST, COMMAND],shell=False,stdout=subprocess.PIPE,stderr=subprocess.PIPE) result = ssh.stdout.readlines() if len(result)!=0: - logging.debug(self.Process + " process found") + logging.debug(self.Process['Name'] + " process found") return True - else: - logging.debug(self.Process + " process NOT found") - return False + else:#start process and check again + logging.debug(self.Process['Name'] + " process NOT found") + #starting the process + logging.debug('Starting ' + self.Process['Name']) + mySSH = sshconnection.SSHConnection() + mySSH.open(self.HostIPAddress, self.HostUsername, self.HostPassword) + mySSH.command('echo ' + self.HostPassword + ' | sudo -S ' + self.Process['Cmd'] + ' &','\$',5) + mySSH.close() + #checking the process + HOST=self.HostIPAddress + COMMAND="ps aux | grep " + self.Process['Name'] + " | grep -v grep " + logging.debug(COMMAND) + ssh = subprocess.Popen(["ssh", "%s" % HOST, COMMAND],shell=False,stdout=subprocess.PIPE,stderr=subprocess.PIPE) + result = ssh.stdout.readlines() + if len(result)!=0: + logging.debug(self.Process['Name'] + " process found") + return True + else: + logging.debug(self.Process['Name'] + " process NOT found") + return False - #Wakeup/Detach can probably be improved with encapsulation of the command such def Command(self, command) - #this method wakes up the module by calling the specified python script - def WakeUp(self): + #Generic command function, using function pointers dictionary + def Command(self,cmd): mySSH = sshconnection.SSHConnection() mySSH.open(self.HostIPAddress, self.HostUsername, self.HostPassword) - mySSH.command('echo ' + self.HostPassword + ' | sudo -S python3 ' + self.WakeupScript + ' ','\$',5) + mySSH.command('echo ' + self.HostPassword + ' | sudo -S python3 ' + self.cmd_dict[cmd],'\$',5) time.sleep(5) - logging.debug("Module wake-up") + logging.debug("Module "+ cmd) mySSH.close() - #this method detaches the module by calling the specified python script - def Detach(self): - mySSH = sshconnection.SSHConnection() - mySSH.open(self.HostIPAddress, self.HostUsername, self.HostPassword) - mySSH.command('echo ' + self.HostPassword + ' | sudo -S python3 ' + self.DetachScript + ' ','\$',5) - time.sleep(5) - logging.debug("Module detach") - mySSH.close() #this method retrieves the Module IP address (not the Host IP address) def GetModuleIPAddress(self): HOST=self.HostIPAddress - COMMAND="ip a show dev " + self.UENetwork + " | grep inet | grep " + self.UENetwork - ssh = subprocess.Popen(["ssh", "%s" % HOST, COMMAND],shell=False,stdout=subprocess.PIPE,stderr=subprocess.PIPE) - response = ssh.stdout.readlines() - if len(response)!=0: + response= [] + tentative = 10 + while (len(response)==0) and (tentative>0): + COMMAND="ip a show dev " + self.UENetwork + " | grep inet | grep " + self.UENetwork + logging.debug(COMMAND) + ssh = subprocess.Popen(["ssh", "%s" % HOST, COMMAND],shell=False,stdout=subprocess.PIPE,stderr=subprocess.PIPE) + response = ssh.stdout.readlines() + tentative-=1 + time.sleep(10) + if (tentative==0) and (len(response)==0): + logging.debug('\u001B[1;37;41m Module IP Address Not Found! Time expired \u001B[0m') + return -1 + else: #check response result = re.search('inet (?P[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)', response[0].decode("utf-8") ) if result is not None: if result.group('moduleipaddress') is not None: self.UEIPAddress = result.group('moduleipaddress') logging.debug('\u001B[1mUE Module IP Address is ' + self.UEIPAddress + '\u001B[0m') + return 0 else: logging.debug('\u001B[1;37;41m Module IP Address Not Found! \u001B[0m') - else: - logging.debug('\u001B[1;37;41m Module IP Address Not Found! \u001B[0m') - else: - logging.debug('\u001B[1;37;41m Module IP Address Not Found! \u001B[0m') + return -1 diff --git a/ci-scripts/cls_oaicitest.py b/ci-scripts/cls_oaicitest.py index 9bcfa458ba..06cc814a11 100644 --- a/ci-scripts/cls_oaicitest.py +++ b/ci-scripts/cls_oaicitest.py @@ -386,13 +386,13 @@ class OaiCiTest(): else: #if an ID is specified, it is a module from the yaml infrastructure file #RH Module_UE = cls_module_ue.Module_UE(InfraUE.ci_ue_infra[self.ue_id]) - is_module=Module_UE.CheckIsModule() + is_module=Module_UE.CheckCMProcess() if is_module: - Module_UE.WakeUp() + Module_UE.Command("wup") Module_UE.GetModuleIPAddress() HTML.CreateHtmlTestRow(Module_UE.UEIPAddress, 'OK', CONST.ALL_PROCESSES_OK) self.UEIPAddresses.append(Module_UE.UEIPAddress) - logging.debug('UEs IP addresses : '+ self.UEIPAddresses) + logging.debug('UE IP addresss : '+ Module_UE.UEIPAddress) def InitializeOAIUE(self,HTML,RAN,EPC,COTS_UE): if self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '' or self.UESourceCodePath == '': @@ -1039,7 +1039,7 @@ class OaiCiTest(): except: os.kill(os.getppid(),signal.SIGUSR1) - def DetachUE(self,HTML,RAN,EPC,COTS_UE): + def DetachUE(self,HTML,RAN,EPC,COTS_UE,InfraUE): if self.ue_id=='':#no ID specified, then it is a COTS controlled by ADB if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': HELP.GenericHelp(CONST.Version) @@ -1073,9 +1073,9 @@ class OaiCiTest(): cnt += 1 else:#if an ID is specified, it is a module from the yaml infrastructure file Module_UE = cls_module_ue.Module_UE(InfraUE.ci_ue_infra[self.ue_id]) - is_module=Module_UE.CheckIsModule() + is_module=Module_UE.CheckCMProcess() if is_module: - Module_UE.Detach() + Module_UE.Command("detach") Module_UE.GetModuleIPAddress() HTML.CreateHtmlTestRow(Module_UE.UEIPAddress, 'OK', CONST.ALL_PROCESSES_OK) diff --git a/ci-scripts/main.py b/ci-scripts/main.py index 5a26e3a5ed..2396a73d92 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -717,7 +717,7 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re elif action == 'Attach_UE': CiTestObj.AttachUE(HTML,RAN,EPC,COTS_UE) elif action == 'Detach_UE': - CiTestObj.DetachUE(HTML,RAN,EPC,COTS_UE) + CiTestObj.DetachUE(HTML,RAN,EPC,COTS_UE,InfraUE) elif action == 'DataDisable_UE': CiTestObj.DataDisableUE(HTML) elif action == 'DataEnable_UE': diff --git a/ci-scripts/xml_files/fr1_nsa_quectel.xml b/ci-scripts/xml_files/fr1_nsa_quectel.xml index a1604af7b3..e1e19cbbf8 100644 --- a/ci-scripts/xml_files/fr1_nsa_quectel.xml +++ b/ci-scripts/xml_files/fr1_nsa_quectel.xml @@ -29,7 +29,7 @@ 040000 000001 010000 - 000001 + 000002 050000 050001 000001 @@ -37,6 +37,8 @@ 000001 070001 000001 + 010002 + 000001 080001 080000 @@ -46,14 +48,14 @@ Initialize_UE Initialize Quectel - idefix + idefix Detach_UE Detach UE - idefix + idefix @@ -64,13 +66,13 @@ 0 0 lte - + Initialize_eNB Initialize gNB - -O ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpb210.conf -E + -O ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpn310.conf -q 1 1 nr @@ -79,9 +81,16 @@ IdleSleep Sleep - 10 + 5 + + IdleSleep + Sleep + 30 + + + Ping Ping: 20pings in 20sec @@ -98,25 +107,25 @@ 50 - - Iperf - iperf (DL/20Mbps/UDP)(20 sec)(single-ue profile) - -u -b 20M -t 20 -i 1 + + Iperf + iperf (DL/20Mbps/UDP)(20 sec)(single-ue profile) + -u -b 20M -t 20 -i 1 DL - idefix - 50 - single-ue - + idefix + 50 + single-ue + - - Iperf - iperf (UL/3Mbps/UDP)(20 sec)(single-ue profile) - -u -b 3M -t 20 -i 1 + + Iperf + iperf (UL/3Mbps/UDP)(20 sec)(single-ue profile) + -u -b 3M -t 20 -i 1 UL - idefix - 50 - single-ue - + idefix + 50 + single-ue + From a8bbd77087c4e9dd2e0107813f16b0cdde2ce160 Mon Sep 17 00:00:00 2001 From: hardy Date: Tue, 27 Apr 2021 15:29:34 +0200 Subject: [PATCH 15/25] fixing auto termination --- ci-scripts/cls_module_ue.py | 4 +++- ci-scripts/cls_oaicitest.py | 24 ++++++++++++++---------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/ci-scripts/cls_module_ue.py b/ci-scripts/cls_module_ue.py index 4586be33e8..2df7b2e8b8 100644 --- a/ci-scripts/cls_module_ue.py +++ b/ci-scripts/cls_module_ue.py @@ -132,7 +132,9 @@ class Module_UE: else: logging.debug('\u001B[1;37;41m Module IP Address Not Found! \u001B[0m') return -1 - + else: + logging.debug('\u001B[1;37;41m Module IP Address Not Found! \u001B[0m') + return -1 diff --git a/ci-scripts/cls_oaicitest.py b/ci-scripts/cls_oaicitest.py index 06cc814a11..cbb09287bd 100644 --- a/ci-scripts/cls_oaicitest.py +++ b/ci-scripts/cls_oaicitest.py @@ -389,10 +389,16 @@ class OaiCiTest(): is_module=Module_UE.CheckCMProcess() if is_module: Module_UE.Command("wup") - Module_UE.GetModuleIPAddress() - HTML.CreateHtmlTestRow(Module_UE.UEIPAddress, 'OK', CONST.ALL_PROCESSES_OK) - self.UEIPAddresses.append(Module_UE.UEIPAddress) - logging.debug('UE IP addresss : '+ Module_UE.UEIPAddress) + status=Module_UE.GetModuleIPAddress() + if status==0: + HTML.CreateHtmlTestRow(Module_UE.UEIPAddress, 'OK', CONST.ALL_PROCESSES_OK) + self.UEIPAddresses.append(Module_UE.UEIPAddress) + logging.debug('UE IP addresss : '+ Module_UE.UEIPAddress) + else: #status==-1 failed to retrieve IP address + HTML.CreateHtmlTestRow('N/A', 'KO', CONST.UE_IP_ADDRESS_ISSUE) + self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC) + return + def InitializeOAIUE(self,HTML,RAN,EPC,COTS_UE): if self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '' or self.UESourceCodePath == '': @@ -957,7 +963,7 @@ class OaiCiTest(): except: os.kill(os.getppid(),signal.SIGUSR1) - def AttachUE(self,HTML,RAN,EPC,COTS_UE,InfraUE): + def AttachUE(self,HTML,RAN,EPC,COTS_UE): if self.ue_id=='':#no ID specified, then it is a COTS controlled by ADB if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': HELP.GenericHelp(CONST.Version) @@ -1073,11 +1079,9 @@ class OaiCiTest(): cnt += 1 else:#if an ID is specified, it is a module from the yaml infrastructure file Module_UE = cls_module_ue.Module_UE(InfraUE.ci_ue_infra[self.ue_id]) - is_module=Module_UE.CheckCMProcess() - if is_module: - Module_UE.Command("detach") - Module_UE.GetModuleIPAddress() - HTML.CreateHtmlTestRow(Module_UE.UEIPAddress, 'OK', CONST.ALL_PROCESSES_OK) + Module_UE.Command("detach") + + def RebootUE_common(self, device_id): try: From bad3e98301385e3a86aaa539f0bd05c2621f04ef Mon Sep 17 00:00:00 2001 From: hardy Date: Wed, 28 Apr 2021 13:45:34 +0200 Subject: [PATCH 16/25] need to update dummy UE for CI --- ci-scripts/ci_ueinfra.yaml | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/ci-scripts/ci_ueinfra.yaml b/ci-scripts/ci_ueinfra.yaml index 1ca913072c..1b39891382 100644 --- a/ci-scripts/ci_ueinfra.yaml +++ b/ci-scripts/ci_ueinfra.yaml @@ -14,14 +14,19 @@ idefix: HostPassword : oaicicd HostSourceCodePath : none dummy: - ID: dummy -dummy2: - ID: dummy2 - Kind : cots - State : disabled - Process : quectel-cm - HostIPAddress : 192.168.18.186 + ID: '' + State : '' + Kind : '' + Process : + Name : '' + Cmd : '' + WakeupScript : '' + DetachScript : '' + PLMN : 22201 + UENetwork : wwan0 + HostIPAddress : 192.168.18.188 HostUsername : oaicicd HostPassword : oaicicd HostSourceCodePath : none + From 6b45eb8210a352032fba4ab9e8196869299c5ca1 Mon Sep 17 00:00:00 2001 From: hardy Date: Wed, 28 Apr 2021 22:25:08 +0200 Subject: [PATCH 17/25] update of the AT-based module control for automation --- ci-scripts/ci_ctl_qtel.py | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/ci-scripts/ci_ctl_qtel.py b/ci-scripts/ci_ctl_qtel.py index 1030b54616..3785d7ee89 100644 --- a/ci-scripts/ci_ctl_qtel.py +++ b/ci-scripts/ci_ctl_qtel.py @@ -24,6 +24,9 @@ # #--------------------------------------------------------------------- +#usage example: +#sudo python3 ci_ctl_qtel.py /dev/ttyUSB2 wup +#sudo python3 ci_ctl_qtel.py /dev/ttyUSB2 detach import sys @@ -44,28 +47,40 @@ class qtel_ctl: self.__send_command(ser,"AT+CFUN={}\r".format(state)) def __send_command(self,ser,com): - if ser.inWaiting() > 0: - ser.flushInput() ser.write(com.encode()) + time.sleep(0.1) + ret=[] + while ser.inWaiting()>0: + print("waiting") + msg=ser.readline() + msg=msg.decode("utf-8") + msg=msg.replace("\r","") + msg=msg.replace("\n","") + print(msg) + if msg!="": + ret.append(msg) + else: + print("msg empty") + return ret #-------------- #public methods #-------------- def wup(self):#sending AT+CFUN=0, then AT+CFUN=1 - self.__set_modem_state(self.modem,0) + self.__set_modem_state(self.modem,'0') time.sleep(3) - self.__set_modem_state(self.modem,1) + self.__set_modem_state(self.modem,'1') def detach(self):#sending AT+CFUN=0 - self.__set_modem_state(self.modem,0) + self.__set_modem_state(self.modem,'0') if __name__ == "__main__": - #argv[1] : usb port - #argv[2] : qtel command (see function pointers dict "wup", "detach" etc ...) + #argv[1] : usb port + #argv[2] : qtel command (see function pointers dict "wup", "detach" etc ...) command = sys.argv[2] Module=qtel_ctl(sys.argv[1]) - #calling the function to be applied + #calling the function to be applied Module.cmd_dict[command]() From 9d50c5ea0247bbafc13cde6b6732923cb7acdbb1 Mon Sep 17 00:00:00 2001 From: Remi Hardy Date: Thu, 29 Apr 2021 11:38:03 +0200 Subject: [PATCH 18/25] update of ci nsa and benetel jenkins pipelines --- ci-scripts/Jenkinsfile-trig-nsa | 4 +- ...a_base_ref.xml => benetel_nsa_quectel.xml} | 69 ++++++++----------- ci-scripts/xml_files/fr1_nsa_quectel.xml | 16 ++--- 3 files changed, 38 insertions(+), 51 deletions(-) rename ci-scripts/xml_files/{fr1_nsa_base_ref.xml => benetel_nsa_quectel.xml} (74%) diff --git a/ci-scripts/Jenkinsfile-trig-nsa b/ci-scripts/Jenkinsfile-trig-nsa index 3dd5ce3b50..5ace29d866 100644 --- a/ci-scripts/Jenkinsfile-trig-nsa +++ b/ci-scripts/Jenkinsfile-trig-nsa @@ -37,7 +37,7 @@ pipeline { steps { script { //retrieve MR that are opened nd with tag READY_TO_BE_MERGED - MR_LIST= sh returnStdout: true, script: 'curl --silent "https://gitlab.eurecom.fr/api/v4/projects/oai%2Fopenairinterface5g/merge_requests?state=opened&per_page=100&labels=READY_TO_BE_MERGED" | jq ".[].iid" || true ' + MR_LIST= sh returnStdout: true, script: 'curl --silent "https://gitlab.eurecom.fr/api/v4/projects/oai%2Fopenairinterface5g/merge_requests?state=opened&per_page=100&milestone=REVIEW_COMPLETED_AND_APPROVED" | jq ".[].iid" || true ' echo "List of selected MR:\n${MR_LIST}" def MR_ARRAY = MR_LIST.split('\n') //for every selected MR, retrieve the branch name and the latest commit @@ -48,7 +48,7 @@ pipeline { COMMIT_ID=COMMIT_ID.trim() echo "Testing NSA on : ${MR} ${SRC_BRANCH} ${COMMIT_ID}" //calling NSA sub job - build job: "RAN-CI-NSA-B210", wait : false, propagate : false, parameters: [ + build job: "RAN-CI-NSA-B210-N310-ModuleUE", wait : false, propagate : false, parameters: [ string(name: 'eNB_MR', value: String.valueOf(MR)), string(name: 'eNB_Branch', value: String.valueOf(SRC_BRANCH)), string(name: 'eNB_CommitID', value: String.valueOf(COMMIT_ID)), diff --git a/ci-scripts/xml_files/fr1_nsa_base_ref.xml b/ci-scripts/xml_files/benetel_nsa_quectel.xml similarity index 74% rename from ci-scripts/xml_files/fr1_nsa_base_ref.xml rename to ci-scripts/xml_files/benetel_nsa_quectel.xml index fd47db10b2..d505d0e190 100644 --- a/ci-scripts/xml_files/fr1_nsa_base_ref.xml +++ b/ci-scripts/xml_files/benetel_nsa_quectel.xml @@ -22,64 +22,57 @@ --> TEST-NSA-FR1-TM1 - NSA FULL + NSA Ping DL UL with QUECTEL tasks - 010000 030000 040000 - 010001 + 000002 + 010000 000001 050000 050001 000001 - 060000 - 060001 - 000001 070000 + 000001 + 070001 + 000001 010002 000001 080001 080000 - 010003 + Initialize_UE - Initialize UE + Initialize Quectel + idefix - - Terminate_UE - Terminate UE - - - - Attach_UE - Attach UE - Detach_UE Detach UE + idefix Initialize_eNB Initialize eNB - -O ci-scripts/conf_files/enb.band7.tm1.fr1.25PRB.usrpb210.conf + -O ci-scripts/conf_files/benetel-4g.conf 0 0 lte - + Initialize_eNB Initialize gNB - -O ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpb210.conf -E + -O ci-scripts/conf_files/benetel-5g.conf -q 1 1 nr @@ -88,12 +81,20 @@ IdleSleep Sleep - 20 + 10 + + IdleSleep + Sleep + 30 + + + Ping Ping: 20pings in 20sec + idefix -c 20 50 @@ -101,32 +102,17 @@ Ping Ping: 100pings in 20sec + idefix -c 100 -i 0.2 50 - - - Iperf - iperf (DL/3Mbps/UDP)(20 sec)(single-ue profile) - -u -b 3M -t 20 -i 1 - 50 - single-ue - - - - Iperf - iperf (UL/1Mbps/UDP)(20 sec)(single-ue profile) - -u -b 1M -t 20 -i 1 -R - 50 - single-ue - - - Iperf iperf (DL/20Mbps/UDP)(20 sec)(single-ue profile) -u -b 20M -t 20 -i 1 + DL + idefix 50 single-ue @@ -134,13 +120,14 @@ Iperf iperf (UL/3Mbps/UDP)(20 sec)(single-ue profile) - -u -b 3M -t 20 -i 1 -R + -u -b 3M -t 20 -i 1 + UL + idefix 50 single-ue - Terminate_eNB Terminate eNB diff --git a/ci-scripts/xml_files/fr1_nsa_quectel.xml b/ci-scripts/xml_files/fr1_nsa_quectel.xml index e1e19cbbf8..67480ebb81 100644 --- a/ci-scripts/xml_files/fr1_nsa_quectel.xml +++ b/ci-scripts/xml_files/fr1_nsa_quectel.xml @@ -22,14 +22,14 @@ --> TEST-NSA-FR1-TM1 - NSA QUECTEL + NSA Ping DL UL with QUECTEL tasks 030000 040000 - 000001 - 010000 000002 + 010000 + 000001 050000 050001 000001 @@ -81,7 +81,7 @@ IdleSleep Sleep - 5 + 10 @@ -109,8 +109,8 @@ Iperf - iperf (DL/20Mbps/UDP)(20 sec)(single-ue profile) - -u -b 20M -t 20 -i 1 + iperf (DL/20Mbps/UDP)(60 sec)(single-ue profile) + -u -b 20M -t 60 -i 1 DL idefix 50 @@ -119,8 +119,8 @@ Iperf - iperf (UL/3Mbps/UDP)(20 sec)(single-ue profile) - -u -b 3M -t 20 -i 1 + iperf (UL/3Mbps/UDP)(60 sec)(single-ue profile) + -u -b 3M -t 60 -i 1 UL idefix 50 From 9581b5cce29e92a1ed0e3e62a4405da03ac2dbf2 Mon Sep 17 00:00:00 2001 From: Remi Hardy Date: Thu, 29 Apr 2021 14:01:53 +0200 Subject: [PATCH 19/25] adding conf file for n310 --- .../gnb.band78.tm1.fr1.106PRB.usrpn310.conf | 305 ++++++++++++++++++ 1 file changed, 305 insertions(+) create mode 100644 ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpn310.conf diff --git a/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpn310.conf b/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpn310.conf new file mode 100644 index 0000000000..809203f672 --- /dev/null +++ b/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpn310.conf @@ -0,0 +1,305 @@ +Active_gNBs = ( "gNB-Eurecom-5GNRBox"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + + +gNBs = +( + { + ////////// Identification parameters: + gNB_ID = 0xe00; + + cell_type = "CELL_MACRO_GNB"; + gNB_name = "gNB-Eurecom-5GNRBox"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 1; + plmn_list = ({mcc = 222; mnc = 01; mnc_length = 2;}); + + tr_s_preference = "local_mac" + + ////////// Physical parameters: + + ssb_SubcarrierOffset = 31; //0; + pdsch_AntennaPorts = 1; + pusch_AntennaPorts = 1; + pusch_TargetSNRx10 = 200; + pucch_TargetSNRx10 = 200; + + + servingCellConfigCommon = ( + { + #spCellConfigCommon + + physCellId = 0; + +# downlinkConfigCommon + #frequencyInfoDL + # this is 3600 MHz + 84 PRBs@30kHz SCS (same as initial BWP) + absoluteFrequencySSB = 641272; //641032; #641968; 641968=start of ssb at 3600MHz + 82 RBs 641032=center of SSB at center of cell + dl_frequencyBand = 78; + # this is 3600 MHz + dl_absoluteFrequencyPointA = 640000; + #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=84,L=13 (275*(L-1))+RBstart + initialDLBWPlocationAndBandwidth = 6368; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialDLBWPsubcarrierSpacing = 1; + #pdcch-ConfigCommon + initialDLBWPcontrolResourceSetZero = 0; + initialDLBWPsearchSpaceZero = 0; + #pdsch-ConfigCommon + #pdschTimeDomainAllocationList (up to 16 entries) + initialDLBWPk0_0 = 0; + #initialULBWPmappingType + #0=typeA,1=typeB + initialDLBWPmappingType_0 = 0; + #this is SS=1,L=13 + initialDLBWPstartSymbolAndLength_0 = 40; + + initialDLBWPk0_1 = 0; + initialDLBWPmappingType_1 = 0; + #this is SS=2,L=12 + initialDLBWPstartSymbolAndLength_1 = 53; + + initialDLBWPk0_2 = 0; + initialDLBWPmappingType_2 = 0; + #this is SS=1,L=12 + initialDLBWPstartSymbolAndLength_2 = 54; + + initialDLBWPk0_3 = 0; + initialDLBWPmappingType_3 = 0; + #this is SS=1,L=4 //5 (4 is for 43, 5 is for 57) + initialDLBWPstartSymbolAndLength_3 = 57; //43; //57; + #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 = 6368; +# 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 = -100; +#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 = 5; +#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; +#oneHalf (0..15) 4,8,12,16,...60,64 + ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 14; //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, + # pusch-ConfigCommon (up to 16 elements) + initialULBWPk2_0 = 2; + initialULBWPmappingType_0 = 1 + # this is SS=0 L=11 + initialULBWPstartSymbolAndLength_0 = 55; + + initialULBWPk2_1 = 2; + initialULBWPmappingType_1 = 1; + # this is SS=0 L=12 + initialULBWPstartSymbolAndLength_1 = 69; + + initialULBWPk2_2 = 7; + initialULBWPmappingType_2 = 1; + # this is SS=10 L=4 + initialULBWPstartSymbolAndLength_2 = 52; + + 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_PositionsInBurs_BitmapPR +# 1=short, 2=medium, 3=long + ssb_PositionsInBurst_PR = 2; + ssb_PositionsInBurst_Bitmap = 1; #0x80; + +# 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; //8; //7; + nrofDownlinkSymbols = 6; //0; //6; + nrofUplinkSlots = 2; + nrofUplinkSymbols = 4; //0; //4; + + ssPBCH_BlockPower = -25; + } + + ); + + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + + ////////// MME parameters: + mme_ip_address = ( { ipv4 = "CI_MME_IP_ADDR"; + ipv6 = "192:168:30::17"; + port = 36412 ; + active = "yes"; + preference = "ipv4"; + } + ); + + ///X2 + enable_x2 = "yes"; + t_reloc_prep = 1000; /* unit: millisecond */ + tx2_reloc_overall = 2000; /* unit: millisecond */ + t_dc_prep = 1000; /* unit: millisecond */ + t_dc_overall = 2000; /* unit: millisecond */ + target_enb_x2_ip_address = ( + { ipv4 = "CI_FR1_CTL_ENB_IP_ADDR"; + ipv6 = "192:168:30::17"; + preference = "ipv4"; + } + ); + + NETWORK_INTERFACES : + { + + GNB_INTERFACE_NAME_FOR_S1_MME = "eth0"; + GNB_IPV4_ADDRESS_FOR_S1_MME = "CI_GNB_IP_ADDR"; + GNB_INTERFACE_NAME_FOR_S1U = "eth0"; + GNB_IPV4_ADDRESS_FOR_S1U = "CI_GNB_IP_ADDR"; + GNB_PORT_FOR_S1U = 2152; # Spec 2152 + GNB_IPV4_ADDRESS_FOR_X2C = "CI_GNB_IP_ADDR"; + GNB_PORT_FOR_X2C = 36422; # Spec 36422 + }; + } +); + +MACRLCs = ( + { + num_cc = 1; + tr_s_preference = "local_L1"; + tr_n_preference = "local_RRC"; + } +); + +L1s = ( + { + num_cc = 1; + tr_n_preference = "local_mac"; + pusch_proc_threads = 6; + } +); + +RUs = ( + { + local_rf = "yes" + nb_tx = 1 + nb_rx = 1 + att_tx = 0 + att_rx = 0; + bands = [7]; + max_pdschReferenceSignalPower = -27; + max_rxgain = 75; #114 + eNB_instances = [0]; + sdr_addrs = "addr=192.168.80.50" + clock_src = "internal" + + } +); + +THREAD_STRUCT = ( + { + #three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT" + parallel_config = "PARALLEL_RU_L1_TRX_SPLIT"; + //parallel_config = "PARALLEL_SINGLE_THREAD"; + #two option for worker "WORKER_DISABLE" or "WORKER_ENABLE" + worker_config = "WORKER_ENABLE"; + } +); + + log_config : + { + global_log_level ="info"; + global_log_verbosity ="medium"; + hw_log_level ="info"; + hw_log_verbosity ="medium"; + phy_log_level ="info"; + phy_log_verbosity ="medium"; + mac_log_level ="info"; + mac_log_verbosity ="high"; + rlc_log_level ="info"; + rlc_log_verbosity ="medium"; + pdcp_log_level ="info"; + pdcp_log_verbosity ="medium"; + rrc_log_level ="info"; + rrc_log_verbosity ="medium"; + }; + +uicc: { +opc = "testopc"; +}; From 7d03c14ecec0acd3191d6154fdf4e433db49801a Mon Sep 17 00:00:00 2001 From: Remi Hardy Date: Fri, 30 Apr 2021 15:04:11 +0200 Subject: [PATCH 20/25] logging fix -> pass --- ci-scripts/cls_oaicitest.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ci-scripts/cls_oaicitest.py b/ci-scripts/cls_oaicitest.py index cbb09287bd..73f5613dfc 100644 --- a/ci-scripts/cls_oaicitest.py +++ b/ci-scripts/cls_oaicitest.py @@ -1514,7 +1514,6 @@ class OaiCiTest(): SSH.open(Module_UE.HostIPAddress, Module_UE.HostUsername, Module_UE.HostPassword) cmd = 'ping -I ' + UE_IPAddress + ' ' + self.ping_args + ' ' + EPC.IPAddress + ' 2>&1 > ping_' + self.testCase_id + '_' + self.ue_id + '.log' SSH.command(cmd,'\$',int(ping_time[0])*1.5) - logging.debug(cmd) #copy the ping log file to have it locally for analysis (ping stats) SSH.copyin(Module_UE.HostIPAddress, Module_UE.HostUsername, Module_UE.HostPassword, 'ping_' + self.testCase_id + '_' + self.ue_id + '.log', '.') @@ -2205,12 +2204,10 @@ class OaiCiTest(): SSH.open(Module_UE.HostIPAddress, Module_UE.HostUsername, Module_UE.HostPassword) cmd = 'echo $USER; nohup iperf -s -B ' + UE_IPAddress + ' -u 2>&1 > iperf_server_' + self.testCase_id + '_' + self.ue_id + '.log' SSH.command(cmd,'\$',5) - logging.debug(cmd) #client side EPC SSH.open(EPC.IPAddress, EPC.UserName, EPC.Password) cmd = 'iperf -c ' + UE_IPAddress + ' ' + self.iperf_args + ' 2>&1 > iperf_client_' + self.testCase_id + '_' + self.ue_id + '.log' SSH.command(cmd,'\$',int(iperf_time)*5.0) - logging.debug(cmd) #copy the 2 resulting files locally SSH.copyin(Module_UE.HostIPAddress, Module_UE.HostUsername, Module_UE.HostPassword, 'iperf_server_' + self.testCase_id + '_' + self.ue_id + '.log', '.') @@ -2225,12 +2222,10 @@ class OaiCiTest(): SSH.open(EPC.IPAddress, EPC.UserName, EPC.Password) cmd = 'echo $USER; nohup iperf -s -u 2>&1 > iperf_server_' + self.testCase_id + '_' + self.ue_id + '.log' SSH.command(cmd,'\$',5) - logging.debug(cmd) #client side UE SSH.open(Module_UE.HostIPAddress, Module_UE.HostUsername, Module_UE.HostPassword) cmd = 'iperf -B ' + UE_IPAddress + ' ' + '-c ' + EPC.IPAddress + ' ' + self.iperf_args + ' > iperf_client_' + self.testCase_id + '_' + self.ue_id + '.log' SSH.command(cmd,'\$',int(iperf_time)*5.0) - logging.debug(cmd) #copy the 2 resulting files locally SSH.copyin(Module_UE.HostIPAddress, Module_UE.HostUsername, Module_UE.HostPassword, 'iperf_server_' + self.testCase_id + '_' + self.ue_id + '.log', '.') From 4b23e6a7bfcc0b1fc8feda397f940c1cf7ad00ae Mon Sep 17 00:00:00 2001 From: Remi Hardy Date: Fri, 30 Apr 2021 15:45:39 +0200 Subject: [PATCH 21/25] adding HTML row for detach --- ci-scripts/cls_oaicitest.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ci-scripts/cls_oaicitest.py b/ci-scripts/cls_oaicitest.py index 73f5613dfc..8674710ceb 100644 --- a/ci-scripts/cls_oaicitest.py +++ b/ci-scripts/cls_oaicitest.py @@ -1080,6 +1080,7 @@ class OaiCiTest(): else:#if an ID is specified, it is a module from the yaml infrastructure file Module_UE = cls_module_ue.Module_UE(InfraUE.ci_ue_infra[self.ue_id]) Module_UE.Command("detach") + HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) @@ -1956,7 +1957,7 @@ class OaiCiTest(): if type==0: result = re.search('(?P[0-9\.]+ [KMG]bits\/sec) +(?P[0-9\.]+ ms) +(?P[0-9]+)/ +(?P[0-9]+)', str(line)) else: - result = re.search('^.+ +(?P[0-9\.]+ [KMG]bits\/sec) +(?P[0-9\.]+ ms) +(?P[0-9]+)\/(?P[0-9]+)', str(line)) + result = re.search('^\[ 3\].+ +(?P[0-9\.]+ [KMG]bits\/sec) +(?P[0-9\.]+ ms) +(?P[0-9]+)\/(?P[0-9]+)', str(line)) if result is not None: bitrate = result.group('bitrate') From 1d07f2559508d595f765a4a1dd32f42df71a3263 Mon Sep 17 00:00:00 2001 From: Remi Hardy Date: Mon, 3 May 2021 11:42:51 +0200 Subject: [PATCH 22/25] update ssPBCH_BlockPower in conf file for N310 --- ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpn310.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpn310.conf b/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpn310.conf index 809203f672..e6e0c5c0f8 100644 --- a/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpn310.conf +++ b/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpn310.conf @@ -188,7 +188,7 @@ gNBs = nrofUplinkSlots = 2; nrofUplinkSymbols = 4; //0; //4; - ssPBCH_BlockPower = -25; + ssPBCH_BlockPower = -15; } ); From 4ae5ac690c254a366ed08ccad144de9de2685818 Mon Sep 17 00:00:00 2001 From: hardy Date: Mon, 3 May 2021 13:19:35 +0200 Subject: [PATCH 23/25] missing parameter in InitializeUE --- ci-scripts/cls_oaicitest.py | 2 +- ci-scripts/main.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ci-scripts/cls_oaicitest.py b/ci-scripts/cls_oaicitest.py index 8674710ceb..7b75cf82c5 100644 --- a/ci-scripts/cls_oaicitest.py +++ b/ci-scripts/cls_oaicitest.py @@ -367,7 +367,7 @@ class OaiCiTest(): except: os.kill(os.getppid(),signal.SIGUSR1) - def InitializeUE(self,HTML,COTS_UE, InfraUE): + def InitializeUE(self,HTML,RAN,EPC, COTS_UE, InfraUE): if self.ue_id=='':#no ID specified, then it is a COTS controlled by ADB if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': HELP.GenericHelp(CONST.Version) diff --git a/ci-scripts/main.py b/ci-scripts/main.py index 2396a73d92..47e1265985 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -711,7 +711,7 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re elif action == 'Terminate_eNB': RAN.TerminateeNB(HTML, EPC) elif action == 'Initialize_UE': - CiTestObj.InitializeUE(HTML,COTS_UE, InfraUE) + CiTestObj.InitializeUE(HTML,RAN, EPC, COTS_UE, InfraUE) elif action == 'Terminate_UE': CiTestObj.TerminateUE(HTML,COTS_UE) elif action == 'Attach_UE': From e0960c35d3e393c5ef83bc73a86c757564fb628f Mon Sep 17 00:00:00 2001 From: hardy Date: Tue, 4 May 2021 08:37:30 +0200 Subject: [PATCH 24/25] removed in code comments --- ci-scripts/cls_module_ue.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/ci-scripts/cls_module_ue.py b/ci-scripts/cls_module_ue.py index 2df7b2e8b8..a94af5bcda 100644 --- a/ci-scripts/cls_module_ue.py +++ b/ci-scripts/cls_module_ue.py @@ -40,16 +40,6 @@ import subprocess class Module_UE: -# ID: idefix -# State : enabled -# Kind : quectel -# Process : quectel-cm -# WakeupScript : ci_qtel.py -# UENetwork : wwan0 -# HostIPAddress : 192.168.18.188 -# HostUsername : oaicicd -# HostPassword : oaicicd -# HostSourceCodePath : none def __init__(self,Module): #create attributes as in the Module dictionary From f5a76d7983fea8ad74f4dc952e99b4a3fbd0ed6b Mon Sep 17 00:00:00 2001 From: hardy Date: Thu, 6 May 2021 23:41:15 +0200 Subject: [PATCH 25/25] fix test retry due to N310 init issue --- ci-scripts/xml_files/benetel_nsa_quectel.xml | 1 + ci-scripts/xml_files/fr1_nsa_quectel.xml | 1 + 2 files changed, 2 insertions(+) diff --git a/ci-scripts/xml_files/benetel_nsa_quectel.xml b/ci-scripts/xml_files/benetel_nsa_quectel.xml index d505d0e190..7130180753 100644 --- a/ci-scripts/xml_files/benetel_nsa_quectel.xml +++ b/ci-scripts/xml_files/benetel_nsa_quectel.xml @@ -24,6 +24,7 @@ TEST-NSA-FR1-TM1 NSA Ping DL UL with QUECTEL tasks + 3 030000 040000 diff --git a/ci-scripts/xml_files/fr1_nsa_quectel.xml b/ci-scripts/xml_files/fr1_nsa_quectel.xml index 67480ebb81..c48aa70739 100644 --- a/ci-scripts/xml_files/fr1_nsa_quectel.xml +++ b/ci-scripts/xml_files/fr1_nsa_quectel.xml @@ -24,6 +24,7 @@ TEST-NSA-FR1-TM1 NSA Ping DL UL with QUECTEL tasks + 3 030000 040000