[a-zA-Z0-9\_]+)', mySSH.getBefore())
if result is not None:
svcName = result.group('svc_name')
- mySSH.command('docker-compose --file ci-docker-compose.yml up -d ' + svcName, '\$', 2)
+ mySSH.command('docker-compose --file ci-docker-compose.yml up -d ' + svcName, '\$', 10)
# Checking Status
mySSH.command('docker-compose --file ci-docker-compose.yml config', '\$', 5)
@@ -459,7 +515,7 @@ class Containerize():
time.sleep(5)
cnt = 0
while (cnt < 3):
- mySSH.command('docker inspect --format=\'{{.State.Health.Status}}\' ' + containerName, '\$', 5)
+ mySSH.command('docker inspect --format="{{.State.Health.Status}}" ' + containerName, '\$', 5)
unhealthyNb = mySSH.getBefore().count('unhealthy')
healthyNb = mySSH.getBefore().count('healthy') - unhealthyNb
startingNb = mySSH.getBefore().count('starting')
@@ -528,12 +584,9 @@ class Containerize():
time.sleep(5)
mySSH.command('docker logs ' + containerName + ' > ' + lSourcePath + '/cmake_targets/' + self.eNB_logFile[self.eNB_instance], '\$', 30)
mySSH.command('docker rm -f ' + containerName, '\$', 30)
+ # Forcing the down now to remove the networks and any artifacts
+ mySSH.command('docker-compose --file ci-docker-compose.yml down', '\$', 5)
- # Putting the CPUs back in a idle state, we do that only on a few servers
- mySSH.command('hostname', '\$', 5)
- result = re.search('obelix|asterix', mySSH.getBefore())
- if result is not None:
- mySSH.command('if command -v cpupower &> /dev/null; then echo ' + lPassWord + ' | sudo -S cpupower idle-set -E; fi', '\$', 5)
mySSH.close()
# Analyzing log file!
@@ -841,3 +894,114 @@ class Containerize():
else:
self.exitStatus = 1
HTML.CreateHtmlTestRowQueue(self.cliOptions, 'KO', 1, html_queue)
+
+ def CheckAndAddRoute(self, svrName, ipAddr, userName, password):
+ logging.debug('Checking IP routing on ' + svrName)
+ mySSH = SSH.SSHConnection()
+ if svrName == 'porcepix':
+ mySSH.open(ipAddr, userName, password)
+ # Check if route to asterix gnb exists
+ mySSH.command('ip route | grep --colour=never "192.168.68.64/26"', '\$', 10)
+ result = re.search('192.168.18.194', mySSH.getBefore())
+ if result is None:
+ mySSH.command('echo ' + password + ' | sudo -S ip route add 192.168.68.64/26 via 192.168.18.194 dev eno1', '\$', 10)
+ # Check if route to obelix enb exists
+ mySSH.command('ip route | grep --colour=never "192.168.68.128/26"', '\$', 10)
+ result = re.search('192.168.18.193', mySSH.getBefore())
+ if result is None:
+ mySSH.command('echo ' + password + ' | sudo -S ip route add 192.168.68.128/26 via 192.168.18.193 dev eno1', '\$', 10)
+ # Check if route to nepes gnb exists
+ mySSH.command('ip route | grep --colour=never "192.168.68.192/26"', '\$', 10)
+ result = re.search('192.168.18.209', mySSH.getBefore())
+ if result is None:
+ mySSH.command('echo ' + password + ' | sudo -S ip route add 192.168.68.192/26 via 192.168.18.209 dev eno1', '\$', 10)
+ # Check if forwarding is enabled
+ mySSH.command('sysctl net.ipv4.conf.all.forwarding', '\$', 10)
+ result = re.search('net.ipv4.conf.all.forwarding = 1', mySSH.getBefore())
+ if result is None:
+ mySSH.command('echo ' + password + ' | sudo -S sysctl net.ipv4.conf.all.forwarding=1', '\$', 10)
+ # Check if iptables forwarding is accepted
+ mySSH.command('echo ' + password + ' | sudo -S iptables -L', '\$', 10)
+ result = re.search('Chain FORWARD .*policy ACCEPT', mySSH.getBefore())
+ if result is None:
+ mySSH.command('echo ' + password + ' | sudo -S iptables -P FORWARD ACCEPT', '\$', 10)
+ mySSH.close()
+ if svrName == 'asterix':
+ mySSH.open(ipAddr, userName, password)
+ # Check if route to porcepix epc exists
+ mySSH.command('ip route | grep --colour=never "192.168.61.192/26"', '\$', 10)
+ result = re.search('192.168.18.210', mySSH.getBefore())
+ if result is None:
+ mySSH.command('echo ' + password + ' | sudo -S ip route add 192.168.61.192/26 via 192.168.18.210 dev em1', '\$', 10)
+ # Check if route to porcepix cn5g exists
+ mySSH.command('ip route | grep --colour=never "192.168.70.128/26"', '\$', 10)
+ result = re.search('192.168.18.210', mySSH.getBefore())
+ if result is None:
+ mySSH.command('echo ' + password + ' | sudo -S ip route add 192.168.70.128/26 via 192.168.18.210 dev em1', '\$', 10)
+ # Check if X2 route to obelix enb exists
+ mySSH.command('ip route | grep --colour=never "192.168.68.128/26"', '\$', 10)
+ result = re.search('192.168.18.193', mySSH.getBefore())
+ if result is None:
+ mySSH.command('echo ' + password + ' | sudo -S ip route add 192.168.68.128/26 via 192.168.18.193 dev em1', '\$', 10)
+ # Check if forwarding is enabled
+ mySSH.command('sysctl net.ipv4.conf.all.forwarding', '\$', 10)
+ result = re.search('net.ipv4.conf.all.forwarding = 1', mySSH.getBefore())
+ if result is None:
+ mySSH.command('echo ' + password + ' | sudo -S sysctl net.ipv4.conf.all.forwarding=1', '\$', 10)
+ # Check if iptables forwarding is accepted
+ mySSH.command('echo ' + password + ' | sudo -S iptables -L', '\$', 10)
+ result = re.search('Chain FORWARD .*policy ACCEPT', mySSH.getBefore())
+ if result is None:
+ mySSH.command('echo ' + password + ' | sudo -S iptables -P FORWARD ACCEPT', '\$', 10)
+ mySSH.close()
+ if svrName == 'obelix':
+ mySSH.open(ipAddr, userName, password)
+ # Check if route to porcepix epc exists
+ mySSH.command('ip route | grep --colour=never "192.168.61.192/26"', '\$', 10)
+ result = re.search('192.168.18.210', mySSH.getBefore())
+ if result is None:
+ mySSH.command('echo ' + password + ' | sudo -S ip route add 192.168.61.192/26 via 192.168.18.210 dev eno1', '\$', 10)
+ # Check if X2 route to asterix gnb exists
+ mySSH.command('ip route | grep --colour=never "192.168.68.64/26"', '\$', 10)
+ result = re.search('192.168.18.194', mySSH.getBefore())
+ if result is None:
+ mySSH.command('echo ' + password + ' | sudo -S ip route add 192.168.68.64/26 via 192.168.18.194 dev eno1', '\$', 10)
+ # Check if X2 route to nepes gnb exists
+ mySSH.command('ip route | grep --colour=never "192.168.68.192/26"', '\$', 10)
+ result = re.search('192.168.18.209', mySSH.getBefore())
+ if result is None:
+ mySSH.command('echo ' + password + ' | sudo -S ip route add 192.168.68.192/26 via 192.168.18.209 dev eno1', '\$', 10)
+ # Check if forwarding is enabled
+ mySSH.command('sysctl net.ipv4.conf.all.forwarding', '\$', 10)
+ result = re.search('net.ipv4.conf.all.forwarding = 1', mySSH.getBefore())
+ if result is None:
+ mySSH.command('echo ' + password + ' | sudo -S sysctl net.ipv4.conf.all.forwarding=1', '\$', 10)
+ # Check if iptables forwarding is accepted
+ mySSH.command('echo ' + password + ' | sudo -S iptables -L', '\$', 10)
+ result = re.search('Chain FORWARD .*policy ACCEPT', mySSH.getBefore())
+ if result is None:
+ mySSH.command('echo ' + password + ' | sudo -S iptables -P FORWARD ACCEPT', '\$', 10)
+ mySSH.close()
+ if svrName == 'nepes':
+ mySSH.open(ipAddr, userName, password)
+ # Check if route to porcepix epc exists
+ mySSH.command('ip route | grep --colour=never "192.168.61.192/26"', '\$', 10)
+ result = re.search('192.168.18.210', mySSH.getBefore())
+ if result is None:
+ mySSH.command('echo ' + password + ' | sudo -S ip route add 192.168.61.192/26 via 192.168.18.210 dev enp0s31f6', '\$', 10)
+ # Check if X2 route to obelix enb exists
+ mySSH.command('ip route | grep --colour=never "192.168.68.128/26"', '\$', 10)
+ result = re.search('192.168.18.193', mySSH.getBefore())
+ if result is None:
+ mySSH.command('echo ' + password + ' | sudo -S ip route add 192.168.68.128/26 via 192.168.18.193 dev enp0s31f6', '\$', 10)
+ # Check if forwarding is enabled
+ mySSH.command('sysctl net.ipv4.conf.all.forwarding', '\$', 10)
+ result = re.search('net.ipv4.conf.all.forwarding = 1', mySSH.getBefore())
+ if result is None:
+ mySSH.command('echo ' + password + ' | sudo -S sysctl net.ipv4.conf.all.forwarding=1', '\$', 10)
+ # Check if iptables forwarding is accepted
+ mySSH.command('echo ' + password + ' | sudo -S iptables -L', '\$', 10)
+ result = re.search('Chain FORWARD .*policy ACCEPT', mySSH.getBefore())
+ if result is None:
+ mySSH.command('echo ' + password + ' | sudo -S iptables -P FORWARD ACCEPT', '\$', 10)
+ mySSH.close()
diff --git a/ci-scripts/cls_module_ue.py b/ci-scripts/cls_module_ue.py
index 74ae9c207e..e006eb6aae 100644
--- a/ci-scripts/cls_module_ue.py
+++ b/ci-scripts/cls_module_ue.py
@@ -63,7 +63,7 @@ class Module_UE:
#if not it will be started
def CheckCMProcess(self,CNType):
HOST=self.HostUsername+'@'+self.HostIPAddress
- COMMAND="ps aux | grep " + self.Process['Name'] + " | grep -v grep "
+ COMMAND="ps aux | grep --colour=never " + 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()
@@ -81,7 +81,7 @@ class Module_UE:
#checking the process
time.sleep(5)
HOST=self.HostUsername+'@'+self.HostIPAddress
- COMMAND="ps aux | grep " + self.Process['Name'] + " | grep -v grep "
+ COMMAND="ps aux | grep --colour=never " + 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()
@@ -108,7 +108,7 @@ class Module_UE:
response= []
tentative = 3
while (len(response)==0) and (tentative>0):
- COMMAND="ip a show dev " + self.UENetwork + " | grep inet | grep " + self.UENetwork
+ COMMAND="ip a show dev " + self.UENetwork + " | grep --colour=never 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()
@@ -136,7 +136,7 @@ class Module_UE:
response= []
tentative = 3
while (len(response)==0) and (tentative>0):
- COMMAND="ip a show dev " + self.UENetwork + " | grep mtu"
+ COMMAND="ip a show dev " + self.UENetwork + " | grep --colour=never mtu"
logging.debug(COMMAND)
ssh = subprocess.Popen(["ssh", "%s" % HOST, COMMAND],shell=False,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
response = ssh.stdout.readlines()
diff --git a/ci-scripts/cls_oaicitest.py b/ci-scripts/cls_oaicitest.py
index 92a4e8637e..ab7d249f7e 100644
--- a/ci-scripts/cls_oaicitest.py
+++ b/ci-scripts/cls_oaicitest.py
@@ -192,16 +192,16 @@ class OaiCiTest():
result = re.search('LAST_BUILD_INFO', SSH.getBefore())
if result is not None:
mismatch = False
- SSH.command('grep SRC_COMMIT LAST_BUILD_INFO.txt', '\$', 2)
+ SSH.command('grep --colour=never SRC_COMMIT LAST_BUILD_INFO.txt', '\$', 2)
result = re.search(self.ranCommitID, SSH.getBefore())
if result is None:
mismatch = True
- SSH.command('grep MERGED_W_TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2)
+ SSH.command('grep --colour=never MERGED_W_TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2)
if self.ranAllowMerge:
result = re.search('YES', SSH.getBefore())
if result is None:
mismatch = True
- SSH.command('grep TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2)
+ SSH.command('grep --colour=never TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2)
if self.ranTargetBranch == '':
result = re.search('develop', SSH.getBefore())
else:
@@ -451,13 +451,13 @@ class OaiCiTest():
SSH = sshconnection.SSHConnection()
SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword)
# b2xx_fx3_utils reset procedure
- SSH.command('echo ' + self.UEPassword + ' | sudo -S uhd_find_devices', '\$', 90)
+ SSH.command('echo ' + self.UEPassword + ' | sudo -S uhd_find_devices', '\$', 180)
result = re.search('type: b200', SSH.getBefore())
if result is not None:
logging.debug('Found a B2xx device --> resetting it')
SSH.command('echo ' + self.UEPassword + ' | sudo -S b2xx_fx3_utils --reset-device', '\$', 10)
# Reloading FGPA bin firmware
- SSH.command('echo ' + self.UEPassword + ' | sudo -S uhd_find_devices', '\$', 90)
+ SSH.command('echo ' + self.UEPassword + ' | sudo -S uhd_find_devices', '\$', 180)
result = re.search('type: n3xx', str(SSH.getBefore()))
if result is not None:
logging.debug('Found a N3xx device --> resetting it')
@@ -660,7 +660,7 @@ class OaiCiTest():
SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword)
count = 0
while count < 5:
- SSH.command('echo ' + self.ADBPassword + ' | sudo -S lsof | grep ttyUSB0', '\$', 10)
+ SSH.command('echo ' + self.ADBPassword + ' | sudo -S lsof | grep --colour=never ttyUSB0', '\$', 10)
result = re.search('picocom', SSH.getBefore())
if result is None:
count = 10
@@ -1328,7 +1328,7 @@ class OaiCiTest():
SSH = sshconnection.SSHConnection()
SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword)
if self.ADBCentralized:
- SSH.command('lsusb | egrep "Future Technology Devices International, Ltd FT2232C" | sed -e "s#:.*##" -e "s# #_#g"', '\$', 15)
+ SSH.command('lsusb | egrep --colour=never "Future Technology Devices International, Ltd FT2232C" | sed -e "s#:.*##" -e "s# #_#g"', '\$', 15)
#self.CatMDevices = re.findall("\\\\r\\\\n([A-Za-z0-9_]+)",SSH.getBefore())
self.CatMDevices = re.findall("\\\\r\\\\n([A-Za-z0-9_]+)",SSH.getBefore())
else:
@@ -1583,7 +1583,7 @@ class OaiCiTest():
if re.match('OAI-Rel14-Docker', EPC.Type, re.IGNORECASE):
Target = EPC.MmeIPAddress
elif re.match('OAICN5G', EPC.Type, re.IGNORECASE):
- Target = '8.8.8.8'
+ Target = EPC.MmeIPAddress
else:
Target = EPC.IPAddress
#ping from module NIC rather than IP address to make sure round trip is over the air
@@ -2325,7 +2325,7 @@ class OaiCiTest():
server_filename = 'iperf_server_' + self.testCase_id + '_' + self.ue_id + '.log'
SSH.command('docker exec -it prod-trf-gen /bin/bash -c "killall --signal SIGKILL iperf"', '\$', 5)
iperf_cmd = 'echo $USER; nohup bin/iperf -s -u 2>&1 > ' + server_filename
- cmd = 'docker exec -it prod-trf-gen /bin/bash -c \"' + iperf_cmd + '\"'
+ cmd = 'docker exec -d prod-trf-gen /bin/bash -c \"' + iperf_cmd + '\"'
SSH.command(cmd,'\$',5)
SSH.close()
@@ -3601,7 +3601,7 @@ class OaiCiTest():
UhdVersion = result.group('uhd_version')
logging.debug('UHD Version is: ' + UhdVersion)
HTML.UhdVersion[idx]=UhdVersion
- SSH.command('echo ' + Password + ' | sudo -S uhd_find_devices', '\$', 90)
+ SSH.command('echo ' + Password + ' | sudo -S uhd_find_devices', '\$', 180)
usrp_boards = re.findall('product: ([0-9A-Za-z]+)\\\\r\\\\n', SSH.getBefore())
count = 0
for board in usrp_boards:
diff --git a/ci-scripts/cls_physim1.py b/ci-scripts/cls_physim1.py
index 131aa01c4c..2052d98c2c 100644
--- a/ci-scripts/cls_physim1.py
+++ b/ci-scripts/cls_physim1.py
@@ -140,7 +140,7 @@ class PhySim:
logging.debug('oai-physim size is unknown')
# logging to OC Cluster and then switch to corresponding project
- mySSH.command(f'oc login -u {ocUserName} -p {ocPassword}', '\$', 6)
+ mySSH.command(f'oc login -u {ocUserName} -p {ocPassword}', '\$', 30)
if mySSH.getBefore().count('Login successful.') == 0:
logging.error('\u001B[1m OC Cluster Login Failed\u001B[0m')
mySSH.close()
@@ -149,7 +149,7 @@ class PhySim:
return
else:
logging.debug('\u001B[1m Login to OC Cluster Successfully\u001B[0m')
- mySSH.command(f'oc project {ocProjectName}', '\$', 6)
+ mySSH.command(f'oc project {ocProjectName}', '\$', 30)
if mySSH.getBefore().count(f'Already on project "{ocProjectName}"') == 0 and mySSH.getBefore().count(f'Now using project "{self.OCProjectName}"') == 0:
logging.error(f'\u001B[1m Unable to access OC project {ocProjectName}\u001B[0m')
mySSH.close()
@@ -160,7 +160,7 @@ class PhySim:
logging.debug(f'\u001B[1m Now using project {ocProjectName}\u001B[0m')
# Tag the image and push to the OC cluster
- mySSH.command('oc whoami -t | sudo podman login -u ' + ocUserName + ' --password-stdin https://default-route-openshift-image-registry.apps.5glab.nsa.eurecom.fr/ --tls-verify=false', '\$', 6)
+ mySSH.command('oc whoami -t | sudo podman login -u ' + ocUserName + ' --password-stdin https://default-route-openshift-image-registry.apps.5glab.nsa.eurecom.fr/ --tls-verify=false', '\$', 30)
if mySSH.getBefore().count('Login Succeeded!') == 0:
logging.error('\u001B[1m Podman Login to OC Cluster Registry Failed\u001B[0m')
mySSH.close()
@@ -170,7 +170,7 @@ class PhySim:
else:
logging.debug('\u001B[1m Podman Login to OC Cluster Registry Successfully\u001B[0m')
time.sleep(2)
- mySSH.command('oc create -f openshift/oai-physim-image-stream.yml', '\$', 6)
+ mySSH.command('oc create -f openshift/oai-physim-image-stream.yml', '\$', 30)
if mySSH.getBefore().count('(AlreadyExists):') == 0 and mySSH.getBefore().count('created') == 0:
logging.error(f'\u001B[1m Image Stream "oai-physim" Creation Failed on OC Cluster {ocProjectName}\u001B[0m')
mySSH.close()
@@ -180,9 +180,9 @@ class PhySim:
else:
logging.debug(f'\u001B[1m Image Stream "oai-physim" created on OC project {ocProjectName}\u001B[0m')
time.sleep(2)
- mySSH.command(f'sudo podman tag oai-physim:{imageTag} default-route-openshift-image-registry.apps.5glab.nsa.eurecom.fr/{self.OCProjectName}/oai-physim:{imageTag}', '\$', 6)
+ mySSH.command(f'sudo podman tag oai-physim:{imageTag} default-route-openshift-image-registry.apps.5glab.nsa.eurecom.fr/{self.OCProjectName}/oai-physim:{imageTag}', '\$', 30)
time.sleep(2)
- mySSH.command(f'sudo podman push default-route-openshift-image-registry.apps.5glab.nsa.eurecom.fr/{self.OCProjectName}/oai-physim:{imageTag} --tls-verify=false', '\$', 30)
+ mySSH.command(f'sudo podman push default-route-openshift-image-registry.apps.5glab.nsa.eurecom.fr/{self.OCProjectName}/oai-physim:{imageTag} --tls-verify=false', '\$', 180)
if mySSH.getBefore().count('Storing signatures') == 0:
logging.error('\u001B[1m Image "oai-physim" push to OC Cluster Registry Failed\u001B[0m')
mySSH.close()
@@ -195,18 +195,18 @@ class PhySim:
# Using helm charts deployment
time.sleep(5)
mySSH.command(f'sed -i -e "s#TAG#{imageTag}#g" ./charts/physims/values.yaml', '\$', 6)
- mySSH.command('helm install physim ./charts/physims/ | tee -a cmake_targets/log/physim_helm_summary.txt 2>&1', '\$', 6)
+ mySSH.command('helm install physim ./charts/physims/ | tee -a cmake_targets/log/physim_helm_summary.txt 2>&1', '\$', 30)
if mySSH.getBefore().count('STATUS: deployed') == 0:
logging.error('\u001B[1m Deploying PhySim Failed using helm chart on OC Cluster\u001B[0m')
- mySSH.command('helm uninstall physim >> cmake_targets/log/physim_helm_summary.txt 2>&1', '\$', 6)
+ mySSH.command('helm uninstall physim >> cmake_targets/log/physim_helm_summary.txt 2>&1', '\$', 30)
isFinished1 = False
while(isFinished1 == False):
time.sleep(20)
mySSH.command('oc get pods -l app.kubernetes.io/instance=physim', '\$', 6, resync=True)
if re.search('No resources found', mySSH.getBefore()):
isFinished1 = True
- mySSH.command(f'sudo podman rmi default-route-openshift-image-registry.apps.5glab.nsa.eurecom.fr/{self.OCProjectName}/oai-physim:{imageTag}', '\$', 6)
- mySSH.command('oc delete is oai-physim', '\$', 6)
+ mySSH.command(f'sudo podman rmi default-route-openshift-image-registry.apps.5glab.nsa.eurecom.fr/{self.OCProjectName}/oai-physim:{imageTag}', '\$', 30)
+ mySSH.command('oc delete is oai-physim', '\$', 30)
mySSH.close()
self.AnalyzeLogFile_phySim(HTML)
RAN.prematureExit = True
@@ -217,7 +217,7 @@ class PhySim:
count = 0
while(count < 2 and isRunning == False):
time.sleep(60)
- mySSH.command('oc get pods -o wide -l app.kubernetes.io/instance=physim | tee -a cmake_targets/log/physim_pods_summary.txt', '\$', 6, resync=True)
+ mySSH.command('oc get pods -o wide -l app.kubernetes.io/instance=physim | tee -a cmake_targets/log/physim_pods_summary.txt', '\$', 30, resync=True)
if mySSH.getBefore().count('Running') == 12:
logging.debug('\u001B[1m Running the physim test Scenarios\u001B[0m')
isRunning = True
diff --git a/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.2x2.usrpn310.conf b/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.2x2.usrpn310.conf
index c889ba2b89..0e8466e2df 100644
--- a/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.2x2.usrpn310.conf
+++ b/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.2x2.usrpn310.conf
@@ -255,7 +255,7 @@ MACRLCs = (
tr_n_preference = "local_RRC";
# pusch_TargetSNRx10 = 200;
# pucch_TargetSNRx10 = 150;
- ulsch_max_slots_inactivity=20;
+ ulsch_max_frame_inactivity = 1;
}
);
diff --git a/ci-scripts/epc.py b/ci-scripts/epc.py
index 8376e07fd5..fdf77ba007 100644
--- a/ci-scripts/epc.py
+++ b/ci-scripts/epc.py
@@ -53,7 +53,7 @@ import constants as CONST
class EPCManagement():
def __init__(self):
-
+
self.IPAddress = ''
self.UserName = ''
self.Password = ''
@@ -62,7 +62,6 @@ class EPCManagement():
self.PcapFileName = ''
self.testCase_id = ''
self.MmeIPAddress = ''
- self.AmfIPAddress = ''
self.containerPrefix = 'prod'
self.mmeConfFile = 'mme.conf'
self.yamlPath = ''
@@ -228,6 +227,7 @@ class EPCManagement():
sys.exit('Insufficient EPC Parameters')
mySSH = SSH.SSHConnection()
mySSH.open(self.IPAddress, self.UserName, self.Password)
+ html_cell = '\n'
if re.match('ltebox', self.Type, re.IGNORECASE):
logging.debug('Using the SABOX simulated HSS')
mySSH.command('if [ -d ' + self.SourceCodePath + '/scripts ]; then echo ' + self.Password + ' | sudo -S rm -Rf ' + self.SourceCodePath + '/scripts ; fi', '\$', 5)
@@ -238,16 +238,48 @@ class EPCManagement():
logging.debug('Using the sabox')
mySSH.command('cd /opt/ltebox/tools', '\$', 5)
mySSH.command('echo ' + self.Password + ' | sudo -S ./start_sabox', '\$', 5)
+ html_cell += 'N/A\n'
elif re.match('OAICN5G', self.Type, re.IGNORECASE):
logging.debug('Starting OAI CN5G')
mySSH.command('if [ -d ' + self.SourceCodePath + '/scripts ]; then echo ' + self.Password + ' | sudo -S rm -Rf ' + self.SourceCodePath + '/scripts ; fi', '\$', 5)
mySSH.command('mkdir -p ' + self.SourceCodePath + '/scripts', '\$', 5)
mySSH.command('cd /opt/oai-cn5g-fed/docker-compose', '\$', 5)
mySSH.command('./core-network.sh start nrf spgwu', '\$', 60)
+ time.sleep(2)
+ mySSH.command('docker-compose -p 5gcn ps -a', '\$', 60)
+ if mySSH.getBefore().count('Up (healthy)') != 6:
+ logging.error('Not all container healthy')
+ else:
+ logging.debug('OK')
+ mySSH.command('docker-compose config | grep --colour=never image', '\$', 10)
+ listOfImages = mySSH.getBefore()
+ for imageLine in listOfImages.split('\\r\\n'):
+ res1 = re.search('image: (?P[a-zA-Z0-9\-]+):(?P[a-zA-Z0-9\-]+)', str(imageLine))
+ res2 = re.search('mysql', str(imageLine))
+ if res1 is not None and res2 is None:
+ html_cell += res1.group('name') + ':' + res1.group('tag') + ' '
+ nbChars = len(res1.group('name')) + len(res1.group('tag')) + 2
+ while (nbChars < 32):
+ html_cell += ' '
+ nbChars += 1
+ mySSH.command('docker image inspect --format="Size = {{.Size}} bytes" ' + res1.group('name') + ':' + res1.group('tag'), '\$', 10)
+ res3 = re.search('Size *= *(?P[0-9\-]*) *bytes', mySSH.getBefore())
+ if res3 is not None:
+ imageSize = int(res3.group('size'))
+ imageSize = int(imageSize/(1024*1024))
+ html_cell += str(imageSize) + ' MBytes '
+ mySSH.command('docker image inspect --format="Date = {{.Created}}" ' + res1.group('name') + ':' + res1.group('tag'), '\$', 10)
+ res4 = re.search('Date *= *(?P[0-9\-]*)T', mySSH.getBefore())
+ if res4 is not None:
+ html_cell += '(' + res4.group('date') + ')'
+ html_cell += '\n'
else:
logging.error('This option should not occur!')
+ html_cell += ''
mySSH.close()
- HTML.CreateHtmlTestRow(self.Type, 'OK', CONST.ALL_PROCESSES_OK)
+ html_queue = SimpleQueue()
+ html_queue.put(html_cell)
+ HTML.CreateHtmlTestRowQueue(self.Type, 'OK', 1, html_queue)
def SetAmfIPAddress(self):
# Not an error if we don't need an 5GCN
@@ -371,7 +403,7 @@ class EPCManagement():
elif re.match('OAI-Rel14-CUPS', self.Type, re.IGNORECASE):
mySSH.command('echo ' + self.Password + ' | sudo -S killall --signal SIGINT oai_hss || true', '\$', 5)
time.sleep(2)
- mySSH.command('stdbuf -o0 ps -aux | grep hss | grep -v grep', '\$', 5)
+ mySSH.command('stdbuf -o0 ps -aux | grep --colour=never hss | grep -v grep', '\$', 5)
result = re.search('oai_hss -j', mySSH.getBefore())
if result is not None:
mySSH.command('echo ' + self.Password + ' | sudo -S killall --signal SIGKILL oai_hss || true', '\$', 5)
@@ -379,7 +411,7 @@ class EPCManagement():
elif re.match('OAI', self.Type, re.IGNORECASE):
mySSH.command('echo ' + self.Password + ' | sudo -S killall --signal SIGINT run_hss oai_hss || true', '\$', 5)
time.sleep(2)
- mySSH.command('stdbuf -o0 ps -aux | grep hss | grep -v grep', '\$', 5)
+ mySSH.command('stdbuf -o0 ps -aux | grep --colour=never hss | grep -v grep', '\$', 5)
result = re.search('\/bin\/bash .\/run_', mySSH.getBefore())
if result is not None:
mySSH.command('echo ' + self.Password + ' | sudo -S killall --signal SIGKILL run_hss oai_hss || true', '\$', 5)
@@ -465,6 +497,7 @@ class EPCManagement():
def Terminate5GCN(self, HTML):
mySSH = SSH.SSHConnection()
mySSH.open(self.IPAddress, self.UserName, self.Password)
+ message = ''
if re.match('ltebox', self.Type, re.IGNORECASE):
logging.debug('Terminating SA BOX')
mySSH.command('cd /opt/ltebox/tools', '\$', 5)
@@ -475,15 +508,31 @@ class EPCManagement():
time.sleep(1)
mySSH.command('echo ' + self.Password + ' | sudo -S screen -S simulated_5g_hss -X quit', '\$', 5)
elif re.match('OAICN5G', self.Type, re.IGNORECASE):
- self.LogCollectOAICN5G()
+ logging.debug('OAI CN5G Collecting Log files to workspace')
+ mySSH.command('echo ' + self.Password + ' | sudo rm -rf ' + self.SourceCodePath + '/logs', '\$', 5)
+ mySSH.command('mkdir ' + self.SourceCodePath + '/logs','\$', 5)
+ containers_list=['oai-smf','oai-spgwu','oai-amf','oai-nrf']
+ for c in containers_list:
+ mySSH.command('docker logs ' + c + ' > ' + self.SourceCodePath + '/logs/' + c + '.log', '\$', 5)
+
logging.debug('Terminating OAI CN5G')
mySSH.command('cd /opt/oai-cn5g-fed/docker-compose', '\$', 5)
- mySSH.command('docker-compose down', '\$', 5)
mySSH.command('./core-network.sh stop nrf spgwu', '\$', 60)
+ time.sleep(2)
+ mySSH.command('tshark -r /tmp/oai-cn5g.pcap | egrep --colour=never "Tracking area update" ','\$', 30)
+ result = re.search('Tracking area update request', mySSH.getBefore())
+ if result is not None:
+ message = 'UE requested ' + str(mySSH.getBefore().count('Tracking area update request')) + 'Tracking area update request(s)'
+ else:
+ message = 'No Tracking area update request'
+ logging.debug(message)
else:
logging.error('This should not happen!')
mySSH.close()
- HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK)
+ html_queue = SimpleQueue()
+ html_cell = '' + message + '
'
+ html_queue.put(html_cell)
+ HTML.CreateHtmlTestRowQueue(self.Type, 'OK', 1, html_queue)
def DeployEpc(self, HTML):
logging.debug('Trying to deploy')
@@ -529,6 +578,10 @@ class EPCManagement():
mySSH.copyout(self.IPAddress, self.UserName, self.Password, './' + self.yamlPath + '/mme_fd.sprint.conf', self.SourceCodePath + '/scripts')
mySSH.copyout(self.IPAddress, self.UserName, self.Password, './' + self.yamlPath + '/redis_extern.conf', self.SourceCodePath + '/scripts')
mySSH.command('chmod a+x ' + self.SourceCodePath + '/scripts/entrypoint.sh', '\$', 5)
+ else:
+ mySSH.copyout(self.IPAddress, self.UserName, self.Password, './' + self.yamlPath + '/entrypoint.sh', self.SourceCodePath + '/scripts')
+ mySSH.copyout(self.IPAddress, self.UserName, self.Password, './' + self.yamlPath + '/mme.conf', self.SourceCodePath + '/scripts')
+ mySSH.command('chmod 775 entrypoint.sh', '\$', 60)
mySSH.command('wget --quiet --tries=3 --retry-connrefused https://raw.githubusercontent.com/OPENAIRINTERFACE/openair-hss/develop/src/hss_rel14/db/oai_db.cql', '\$', 30)
mySSH.command('docker-compose down', '\$', 60)
mySSH.command('docker-compose up -d db_init', '\$', 60)
@@ -572,6 +625,30 @@ class EPCManagement():
listOfContainers += ' prod-trf-gen'
expectedHealthyContainers += 1
+ mySSH.command('docker-compose config | grep --colour=never image', '\$', 10)
+ html_cell = '\n'
+ listOfImages = mySSH.getBefore()
+ for imageLine in listOfImages.split('\\r\\n'):
+ res1 = re.search('image: (?P[a-zA-Z0-9\-]+):(?P[a-zA-Z0-9\-]+)', str(imageLine))
+ res2 = re.search('cassandra|redis', str(imageLine))
+ if res1 is not None and res2 is None:
+ html_cell += res1.group('name') + ':' + res1.group('tag') + ' '
+ nbChars = len(res1.group('name')) + len(res1.group('tag')) + 2
+ while (nbChars < 32):
+ html_cell += ' '
+ nbChars += 1
+ mySSH.command('docker image inspect --format="Size = {{.Size}} bytes" ' + res1.group('name') + ':' + res1.group('tag'), '\$', 10)
+ res3 = re.search('Size *= *(?P[0-9\-]*) *bytes', mySSH.getBefore())
+ if res3 is not None:
+ imageSize = int(res3.group('size'))
+ imageSize = int(imageSize/(1024*1024))
+ html_cell += str(imageSize) + ' MBytes '
+ mySSH.command('docker image inspect --format="Date = {{.Created}}" ' + res1.group('name') + ':' + res1.group('tag'), '\$', 10)
+ res4 = re.search('Date *= *(?P[0-9\-]*)T', mySSH.getBefore())
+ if res4 is not None:
+ html_cell += '(' + res4.group('date') + ')'
+ html_cell += '\n'
+ html_cell += ''
# Checking if all are healthy
cnt = 0
while (cnt < 3):
@@ -587,6 +664,8 @@ class EPCManagement():
logging.debug(' -- ' + str(healthyNb) + ' healthy container(s)')
logging.debug(' -- ' + str(unhealthyNb) + ' unhealthy container(s)')
logging.debug(' -- ' + str(startingNb) + ' still starting container(s)')
+ html_queue = SimpleQueue()
+ html_queue.put(html_cell)
if healthyNb == expectedHealthyContainers:
mySSH.command('docker exec -d prod-oai-hss /bin/bash -c "nohup tshark -i any -f \'port 9042 or port 3868\' -w /tmp/hss_check_run.pcap 2>&1 > /dev/null"', '\$', 5)
if self.isMagmaUsed:
@@ -598,11 +677,11 @@ class EPCManagement():
mySSH.command('docker exec -d prod-oai-spgwu-tiny /bin/bash -c "nohup tshark -i any -f \'port 8805\' -w /tmp/spgwu_check_run.pcap 2>&1 > /dev/null"', '\$', 10)
mySSH.close()
logging.debug('Deployment OK')
- HTML.CreateHtmlTestRow(self.Type, 'OK', CONST.ALL_PROCESSES_OK)
+ HTML.CreateHtmlTestRowQueue(self.Type, 'OK', 1, html_queue)
else:
mySSH.close()
logging.debug('Deployment went wrong')
- HTML.CreateHtmlTestRow(self.Type, 'KO', CONST.INVALID_PARAMETER)
+ HTML.CreateHtmlTestRowQueue(self.Type, 'KO', 1, html_queue)
def UndeployEpc(self, HTML):
logging.debug('Trying to undeploy')
@@ -639,6 +718,13 @@ class EPCManagement():
mySSH.command('docker cp prod-magma-mme:/tmp/mme_check_run.pcap mme_' + self.testCase_id + '.pcap', '\$', 60)
else:
mySSH.command('docker cp prod-oai-mme:/tmp/mme_check_run.pcap mme_' + self.testCase_id + '.pcap', '\$', 60)
+ mySSH.command('tshark -r mme_' + self.testCase_id + '.pcap | egrep --colour=never "Tracking area update"', '\$', 60)
+ result = re.search('Tracking area update request', mySSH.getBefore())
+ if result is not None:
+ message = 'UE requested ' + str(mySSH.getBefore().count('Tracking area update request')) + 'Tracking area update request(s)'
+ else:
+ message = 'No Tracking area update request'
+ logging.debug(message)
mySSH.command('docker cp prod-oai-spgwc:/tmp/spgwc_check_run.pcap spgwc_' + self.testCase_id + '.pcap', '\$', 60)
mySSH.command('docker cp prod-oai-spgwu-tiny:/tmp/spgwu_check_run.pcap spgwu_' + self.testCase_id + '.pcap', '\$', 60)
# Remove all
@@ -665,12 +751,15 @@ class EPCManagement():
mySSH.command('docker inspect --format=\'{{.Name}}\' prod-oai-public-net prod-oai-private-net', '\$', 10)
noMoreNetworkNb = mySSH.getBefore().count('No such object')
mySSH.close()
+ html_queue = SimpleQueue()
+ html_cell = '' + message + '
'
+ html_queue.put(html_cell)
if noMoreContainerNb == nbContainers and noMoreNetworkNb == 2:
logging.debug('Undeployment OK')
- HTML.CreateHtmlTestRow(self.Type, 'OK', CONST.ALL_PROCESSES_OK)
+ HTML.CreateHtmlTestRowQueue(self.Type, 'OK', 1, html_queue)
else:
logging.debug('Undeployment went wrong')
- HTML.CreateHtmlTestRow(self.Type, 'KO', CONST.INVALID_PARAMETER)
+ HTML.CreateHtmlTestRowQueu(self.Type, 'KO', 1, html_queue)
def LogCollectHSS(self):
mySSH = SSH.SSHConnection()
@@ -689,6 +778,8 @@ class EPCManagement():
mySSH.command('docker cp ' + self.containerPrefix + '-oai-hss:/openair-hss/hss_check_run.log .', '\$', 60)
mySSH.command('docker cp ' + self.containerPrefix + '-oai-hss:/tmp/hss_check_run.pcap .', '\$', 60)
mySSH.command('zip hss.log.zip hss_check_run.*', '\$', 60)
+ elif re.match('OAICN5G', self.Type, re.IGNORECASE):
+ logging.debug('LogCollect is bypassed for that variant')
elif re.match('OAI', self.Type, re.IGNORECASE) or re.match('OAI-Rel14-CUPS', self.Type, re.IGNORECASE):
mySSH.command('zip hss.log.zip hss*.log', '\$', 60)
mySSH.command('echo ' + self.Password + ' | sudo -S rm hss*.log', '\$', 5)
@@ -719,6 +810,11 @@ class EPCManagement():
mySSH.command('docker cp ' + self.containerPrefix + '-oai-mme:/openair-mme/mme_check_run.log .', '\$', 60)
mySSH.command('docker cp ' + self.containerPrefix + '-oai-mme:/tmp/mme_check_run.pcap .', '\$', 60)
mySSH.command('zip mme.log.zip mme_check_run.*', '\$', 60)
+ elif re.match('OAICN5G', self.Type, re.IGNORECASE):
+ mySSH.command('cd ' + self.SourceCodePath + '/logs','\$', 5)
+ mySSH.command('cp -f /tmp/oai-cn5g.pcap .','\$', 30)
+ mySSH.command('zip mme.log.zip oai-amf.log oai-nrf.log oai-cn5g.pcap','\$', 30)
+ mySSH.command('mv mme.log.zip ' + self.SourceCodePath + '/scripts','\$', 30)
elif re.match('OAI', self.Type, re.IGNORECASE) or re.match('OAI-Rel14-CUPS', self.Type, re.IGNORECASE):
mySSH.command('zip mme.log.zip mme*.log', '\$', 60)
mySSH.command('echo ' + self.Password + ' | sudo -S rm mme*.log', '\$', 5)
@@ -748,6 +844,10 @@ class EPCManagement():
mySSH.command('docker cp ' + self.containerPrefix + '-oai-spgwc:/tmp/spgwc_check_run.pcap .', '\$', 60)
mySSH.command('docker cp ' + self.containerPrefix + '-oai-spgwu-tiny:/tmp/spgwu_check_run.pcap .', '\$', 60)
mySSH.command('zip spgw.log.zip spgw*_check_run.*', '\$', 60)
+ elif re.match('OAICN5G', self.Type, re.IGNORECASE):
+ mySSH.command('cd ' + self.SourceCodePath + '/logs','\$', 5)
+ mySSH.command('zip spgw.log.zip oai-smf.log oai-spgwu.log','\$', 30)
+ mySSH.command('mv spgw.log.zip ' + self.SourceCodePath + '/scripts','\$', 30)
elif re.match('OAI', self.Type, re.IGNORECASE) or re.match('OAI-Rel14-CUPS', self.Type, re.IGNORECASE):
mySSH.command('zip spgw.log.zip spgw*.log', '\$', 60)
mySSH.command('echo ' + self.Password + ' | sudo -S rm spgw*.log', '\$', 5)
@@ -757,17 +857,3 @@ class EPCManagement():
else:
logging.error('This option should not occur!')
mySSH.close()
-
- def LogCollectOAICN5G(self):
- mySSH = SSH.SSHConnection()
- mySSH.open(self.IPAddress, self.UserName, self.Password)
- logging.debug('OAI CN5G Collecting Log files to workspace')
- mySSH.command('echo ' + self.Password + ' | sudo rm -rf ' + self.SourceCodePath + '/logs', '\$', 5)
- mySSH.command('mkdir ' + self.SourceCodePath + '/logs','\$', 5)
- containers_list=['oai-smf','oai-spgwu','oai-amf','oai-nrf']
- for c in containers_list:
- mySSH.command('docker logs ' + c + ' > ' + self.SourceCodePath + '/logs/' + c + '.log', '\$', 5)
- mySSH.command('cd ' + self.SourceCodePath + '/logs', '\$', 5)
- mySSH.command('zip oai-cn5g.log.zip *.log', '\$', 60)
- mySSH.close()
-
diff --git a/ci-scripts/main.py b/ci-scripts/main.py
index 9923d515a4..409647e216 100644
--- a/ci-scripts/main.py
+++ b/ci-scripts/main.py
@@ -410,6 +410,17 @@ def GetParametersFromXML(action):
if (string_field is not None):
CONTAINERS.cliOptions = string_field
+ elif action == 'Copy_Image_to_Test':
+ string_field = test.findtext('image_name')
+ if (string_field is not None):
+ CONTAINERS.imageToCopy = string_field
+ string_field = test.findtext('registry_svr_id')
+ if (string_field is not None):
+ CONTAINERS.registrySvrId = string_field
+ string_field = test.findtext('test_svr_id')
+ if (string_field is not None):
+ CONTAINERS.testSvrId = string_field
+
else: # ie action == 'Run_PhySim':
ldpc.runargs = test.findtext('physim_run_args')
@@ -734,6 +745,22 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re
HTML.SethtmlUEConnected(len(CiTestObj.UEDevices) + len(CiTestObj.CatMDevices))
HTML.CreateHtmlTabHeader()
+ # On CI bench w/ containers, we need to validate if IP routes are set
+ if EPC.IPAddress == '192.168.18.210':
+ CONTAINERS.CheckAndAddRoute('porcepix', EPC.IPAddress, EPC.UserName, EPC.Password)
+ if CONTAINERS.eNBIPAddress == '192.168.18.194':
+ CONTAINERS.CheckAndAddRoute('asterix', CONTAINERS.eNBIPAddress, CONTAINERS.eNBUserName, CONTAINERS.eNBPassword)
+ if CONTAINERS.eNB1IPAddress == '192.168.18.194':
+ CONTAINERS.CheckAndAddRoute('asterix', CONTAINERS.eNB1IPAddress, CONTAINERS.eNB1UserName, CONTAINERS.eNB1Password)
+ if CONTAINERS.eNBIPAddress == '192.168.18.193':
+ CONTAINERS.CheckAndAddRoute('obelix', CONTAINERS.eNBIPAddress, CONTAINERS.eNBUserName, CONTAINERS.eNBPassword)
+ if CONTAINERS.eNB1IPAddress == '192.168.18.193':
+ CONTAINERS.CheckAndAddRoute('obelix', CONTAINERS.eNB1IPAddress, CONTAINERS.eNB1UserName, CONTAINERS.eNB1Password)
+ if CONTAINERS.eNBIPAddress == '192.168.18.209':
+ CONTAINERS.CheckAndAddRoute('nepes', CONTAINERS.eNBIPAddress, CONTAINERS.eNBUserName, CONTAINERS.eNBPassword)
+ if CONTAINERS.eNB1IPAddress == '192.168.18.209':
+ CONTAINERS.CheckAndAddRoute('nepes', CONTAINERS.eNB1IPAddress, CONTAINERS.eNB1UserName, CONTAINERS.eNB1Password)
+
CiTestObj.FailReportCnt = 0
RAN.prematureExit=True
HTML.startTime=int(round(time.time() * 1000))
@@ -853,6 +880,8 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re
HTML=ldpc.Run_PhySim(HTML,CONST,id)
elif action == 'Build_Image':
CONTAINERS.BuildImage(HTML)
+ elif action == 'Copy_Image_to_Test':
+ CONTAINERS.Copy_Image_to_Test_Server(HTML)
elif action == 'Deploy_Object':
CONTAINERS.DeployObject(HTML, EPC)
elif action == 'Undeploy_Object':
diff --git a/ci-scripts/ran.py b/ci-scripts/ran.py
index 9acb1de34e..74f13d031b 100644
--- a/ci-scripts/ran.py
+++ b/ci-scripts/ran.py
@@ -165,16 +165,16 @@ class RANManagement():
result = re.search('LAST_BUILD_INFO', mySSH.getBefore())
if result is not None:
mismatch = False
- mySSH.command('grep SRC_COMMIT LAST_BUILD_INFO.txt', '\$', 2)
+ mySSH.command('grep --colour=never SRC_COMMIT LAST_BUILD_INFO.txt', '\$', 2)
result = re.search(self.ranCommitID, mySSH.getBefore())
if result is None:
mismatch = True
- mySSH.command('grep MERGED_W_TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2)
+ mySSH.command('grep --colour=never MERGED_W_TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2)
if (self.ranAllowMerge):
result = re.search('YES', mySSH.getBefore())
if result is None:
mismatch = True
- mySSH.command('grep TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2)
+ mySSH.command('grep --colour=never TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2)
if self.ranTargetBranch == '':
result = re.search('develop', mySSH.getBefore())
else:
@@ -423,13 +423,13 @@ class RANManagement():
# do not reset board twice in IF4.5 case
result = re.search('^rru|^enb|^du.band', str(config_file))
if result is not None:
- mySSH.command('echo ' + lPassWord + ' | sudo -S uhd_find_devices', '\$', 90)
+ mySSH.command('echo ' + lPassWord + ' | sudo -S uhd_find_devices', '\$', 180)
result = re.search('type: b200', mySSH.getBefore())
if result is not None:
logging.debug('Found a B2xx device --> resetting it')
mySSH.command('echo ' + lPassWord + ' | sudo -S b2xx_fx3_utils --reset-device', '\$', 10)
# Reloading FGPA bin firmware
- mySSH.command('echo ' + lPassWord + ' | sudo -S uhd_find_devices', '\$', 90)
+ mySSH.command('echo ' + lPassWord + ' | sudo -S uhd_find_devices', '\$', 180)
# Make a copy and adapt to EPC / eNB IP addresses
mySSH.command('cp ' + full_config_file + ' ' + ci_full_config_file, '\$', 5)
localMmeIpAddr = EPC.MmeIPAddress
@@ -446,7 +446,7 @@ class RANManagement():
else:
mySSH.command('sed -i -e \'s/FLEXRAN_ENABLED.*;/FLEXRAN_ENABLED = "no";/\' ' + ci_full_config_file, '\$', 2);
self.eNBmbmsEnables[int(self.eNB_instance)] = False
- mySSH.command('grep enable_enb_m2 ' + ci_full_config_file, '\$', 2);
+ mySSH.command('grep --colour=never enable_enb_m2 ' + ci_full_config_file, '\$', 2);
result = re.search('yes', mySSH.getBefore())
if result is not None:
self.eNBmbmsEnables[int(self.eNB_instance)] = True
@@ -593,8 +593,12 @@ class RANManagement():
lPassWord = self.eNBPassword
mySSH = SSH.SSHConnection()
mySSH.open(lIpAddr, lUserName, lPassWord)
- mySSH.command('stdbuf -o0 ps -aux | grep --color=never ' + self.air_interface[self.eNB_instance] + ' | grep -v grep', '\$', 5)
- result = re.search(self.air_interface[self.eNB_instance], mySSH.getBefore())
+ if self.air_interface[self.eNB_instance] == '':
+ pattern = 'softmodem'
+ else:
+ pattern = self.air_interface[self.eNB_instance]
+ mySSH.command('stdbuf -o0 ps -aux | grep --color=never ' + pattern + ' | grep -v grep', '\$', 5)
+ result = re.search(pattern, mySSH.getBefore())
if result is None:
logging.debug('\u001B[1;37;41m eNB Process Not Found! \u001B[0m')
status_queue.put(CONST.ENB_PROCESS_FAILED)
@@ -734,8 +738,8 @@ class RANManagement():
mySSH.command('echo ' + self.eNBPassword + ' | sudo -S mv /tmp/enb_*.pcap .','\$',20)
mySSH.command('echo ' + self.eNBPassword + ' | sudo -S mv /tmp/gnb_*.pcap .','\$',20)
mySSH.command('echo ' + self.eNBPassword + ' | sudo -S rm -f enb.log.zip', '\$', 5)
- mySSH.command('echo ' + self.eNBPassword + ' | sudo -S zip enb.log.zip enb*.log core* enb_*record.raw enb_*.pcap gnb_*.pcap enb_*txt physim_*.log *stats.log *monitor.pickle *monitor.png', '\$', 60)
- mySSH.command('echo ' + self.eNBPassword + ' | sudo -S rm enb*.log core* enb_*record.raw enb_*.pcap gnb_*.pcap enb_*txt physim_*.log *stats.log *.pickle *.png', '\$', 5)
+ mySSH.command('echo ' + self.eNBPassword + ' | sudo -S zip enb.log.zip enb*.log core* enb_*record.raw enb_*.pcap gnb_*.pcap enb_*txt physim_*.log *stats.log *monitor.pickle *monitor*.png', '\$', 60)
+ mySSH.command('echo ' + self.eNBPassword + ' | sudo -S rm enb*.log core* enb_*record.raw enb_*.pcap gnb_*.pcap enb_*txt physim_*.log *stats.log *monitor.pickle *monitor*.png', '\$', 5)
mySSH.close()
def AnalyzeLogFile_eNB(self, eNBlogFile, HTML):
@@ -792,23 +796,11 @@ class RANManagement():
pb_receiving_samples_cnt = 0
#count "removing UE" msg
removing_ue = 0
+ #count"X2AP-PDU"
+ x2ap_pdu = 0
#NSA specific log markers
nsa_markers ={'SgNBReleaseRequestAcknowledge': [],'FAILURE': [], 'scgFailureInformationNR-r15': [], 'SgNBReleaseRequest': []}
- #the datalog config file has to be loaded
- datalog_rt_stats_file='datalog_rt_stats.yaml'
- if (os.path.isfile(datalog_rt_stats_file)):
- yaml_file=datalog_rt_stats_file
- elif (os.path.isfile('ci-scripts/'+datalog_rt_stats_file)):
- yaml_file='ci-scripts/'+datalog_rt_stats_file
- else:
- logging.error("Datalog RT stats yaml file cannot be found")
- sys.exit("Datalog RT stats yaml file cannot be found")
-
- with open(yaml_file,'r') as f:
- datalog_rt_stats = yaml.load(f,Loader=yaml.FullLoader)
- rt_keys = datalog_rt_stats['Ref'] #we use the keys from the Ref field
-
line_cnt=0 #log file line counter
for line in enb_log_file.readlines():
line_cnt+=1
@@ -975,15 +967,7 @@ class RANManagement():
if result is not None:
#remove 1- all useless char before relevant info (ulsch or dlsch) 2- trailing char
dlsch_ulsch_stats[k]=re.sub(r'^.*\]\s+', r'' , line.rstrip())
- #real time statistics for gNB
- for k in rt_keys:
- result = re.search(k, line)
- if result is not None:
- #remove 1- all useless char before relevant info 2- trailing char
- line=line.replace('[0m','')
- tmp=re.match(rf'^.*?(\b{k}\b.*)',line.rstrip()) #from python 3.6 we can use literal string interpolation for the variable k, using rf' in the regex
- if tmp!=None: #with ULULULUULULULLLL at the head of the line, we skip it
- real_time_stats[k]=tmp.group(1)
+
#count "problem receiving samples" msg
result = re.search('\[PHY\]\s+problem receiving samples', str(line))
@@ -993,7 +977,10 @@ class RANManagement():
result = re.search('\[MAC\]\s+Removing UE', str(line))
if result is not None:
removing_ue += 1
-
+ #count "X2AP-PDU"
+ result = re.search('X2AP-PDU', str(line))
+ if result is not None:
+ x2ap_pdu += 1
#nsa markers logging
for k in nsa_markers:
result = re.search(k, line)
@@ -1001,7 +988,55 @@ class RANManagement():
nsa_markers[k].append(line_cnt)
enb_log_file.close()
- logging.debug(' File analysis completed')
+
+
+ #the following part takes the *_stats.log files as source (not the stdout log file)
+
+ #the datalog config file has to be loaded
+ datalog_rt_stats_file='datalog_rt_stats.yaml'
+ if (os.path.isfile(datalog_rt_stats_file)):
+ yaml_file=datalog_rt_stats_file
+ elif (os.path.isfile('ci-scripts/'+datalog_rt_stats_file)):
+ yaml_file='ci-scripts/'+datalog_rt_stats_file
+ else:
+ logging.error("Datalog RT stats yaml file cannot be found")
+ sys.exit("Datalog RT stats yaml file cannot be found")
+
+ with open(yaml_file,'r') as f:
+ datalog_rt_stats = yaml.load(f,Loader=yaml.FullLoader)
+ rt_keys = datalog_rt_stats['Ref'] #we use the keys from the Ref field
+
+ if (os.path.isfile('./nrL1_stats.log')) and (os.path.isfile('./nrL1_stats.log')):
+ stat_files_present=True
+ else:
+ stat_files_present=False
+ logging.debug("NR Stats files for RT analysis not found")
+ if stat_files_present:
+ nrL1_stats = open('./nrL1_stats.log', 'r')
+ nrMAC_stats = open('./nrMAC_stats.log', 'r')
+ for line in nrL1_stats.readlines():
+ for k in rt_keys:
+ result = re.search(k, line)
+ if result is not None:
+ #remove 1- all useless char before relevant info 2- trailing char
+ tmp=re.match(rf'^.*?(\b{k}\b.*)',line.rstrip()) #from python 3.6 we can use literal string interpolation for the variable k, using rf' in the regex
+ if tmp!=None:
+ real_time_stats[k]=tmp.group(1)
+ for line in nrMAC_stats.readlines():
+ for k in rt_keys:
+ result = re.search(k, line)
+ if result is not None:
+ #remove 1- all useless char before relevant info 2- trailing char
+ tmp=re.match(rf'^.*?(\b{k}\b.*)',line.rstrip()) #from python 3.6 we can use literal string interpolation for the variable k, using rf' in the regex
+ if tmp!=None:
+ real_time_stats[k]=tmp.group(1)
+ nrL1_stats.close()
+ nrMAC_stats.close()
+
+ #stdout log file and stat log files analysis completed
+ logging.debug(' File analysis (stdout, stats) completed')
+
+ #post processing depending on the node type
if (self.air_interface[self.eNB_instance] == 'lte-softmodem') or (self.air_interface[self.eNB_instance] == 'ocp-enb'):
nodeB_prefix = 'e'
else:
@@ -1087,6 +1122,11 @@ class RANManagement():
htmlMsg = statMsg+'\n'
logging.debug(statMsg)
htmleNBFailureMsg += htmlMsg
+ #X2AP-PDU log
+ statMsg = 'X2AP-PDU msg count = '+str(x2ap_pdu)
+ htmlMsg = statMsg+'\n'
+ logging.debug(statMsg)
+ htmleNBFailureMsg += htmlMsg
#nsa markers
statMsg = 'logfile line count = ' + str(line_cnt)
htmlMsg = statMsg+'\n'
diff --git a/ci-scripts/sshconnection.py b/ci-scripts/sshconnection.py
index b85c40a0be..65e9c961d0 100644
--- a/ci-scripts/sshconnection.py
+++ b/ci-scripts/sshconnection.py
@@ -60,7 +60,8 @@ class SSHConnection():
connect_status = False
while count < 4:
self.ssh = pexpect.spawn('ssh -o PubkeyAuthentication=no {}@{}'.format(username,ipaddress))
- self.ssh.timeout = 5
+ # Longer timeout at connection due to asterix slowness
+ self.ssh.timeout = 25
self.sshresponse = self.ssh.expect(['Are you sure you want to continue connecting (yes/no)?', 'password:', 'Last login', pexpect.EOF, pexpect.TIMEOUT])
if self.sshresponse == 0:
self.ssh.sendline('yes')
diff --git a/ci-scripts/stats_monitor.py b/ci-scripts/stats_monitor.py
index 877194de59..933bf13203 100755
--- a/ci-scripts/stats_monitor.py
+++ b/ci-scripts/stats_monitor.py
@@ -17,9 +17,15 @@ class StatMonitor():
def __init__(self,cfg_file):
with open(cfg_file,'r') as file:
self.d = yaml.load(file)
- for node in self.d:
- for metric in self.d[node]:
- self.d[node][metric]=[]
+ for node in self.d:#so far we have enb or gnb as nodes
+ for metric_l1 in self.d[node]: #first level of metric keys
+ if metric_l1!="graph": #graph is a reserved word to configure graph paging, so it is disregarded
+ if self.d[node][metric_l1] is None:#first level is None -> create array
+ self.d[node][metric_l1]=[]
+ else: #first level is not None -> there is a second level -> create array
+ for metric_l2 in self.d[node][metric_l1]:
+ self.d[node][metric_l1][metric_l2]=[]
+
def process_gnb (self,node_type,output):
@@ -36,6 +42,11 @@ class StatMonitor():
percentage=float(result.group(2))/float(result.group(1))
self.d[node_type]['ulsch_err_perc_round_1'].append(percentage)
+ for k in self.d[node_type]['rt']:
+ result=re.match(rf'^.*\b{k}\b:\s+([0-9\.]+) us;\s+([0-9]+);\s+([0-9\.]+) us;',tmp)
+ if result is not None:
+ self.d[node_type]['rt'][k].append(float(result.group(3)))
+
def process_enb (self,node_type,output):
for line in output:
@@ -62,23 +73,37 @@ class StatMonitor():
def graph(self,node_type):
- col = 1
- figure, axis = plt.subplots(len(self.d[node_type]), col ,figsize=(10, 10))
- i=0
- for metric in self.d[node_type]:
- major_ticks = np.arange(0, len(self.d[node_type][metric])+1, 1)
- axis[i].set_xticks(major_ticks)
- axis[i].set_xticklabels([])
- axis[i].plot(self.d[node_type][metric],marker='o')
- axis[i].set_xlabel('time')
- axis[i].set_ylabel(metric)
- axis[i].set_title(metric)
- i+=1
+ for page in self.d[node_type]['graph']:#work out a set a graphs per page
+ col = 1
+ figure, axis = plt.subplots(len(self.d[node_type]['graph'][page]), col ,figsize=(10, 10))
+ i=0
+ for m in self.d[node_type]['graph'][page]:#metric may refer to 1 level or 2 levels
+ metric_path=m.split('.')
+ if len(metric_path)==1:#1 level
+ metric_l1=metric_path[0]
+ major_ticks = np.arange(0, len(self.d[node_type][metric_l1])+1, 1)
+ axis[i].set_xticks(major_ticks)
+ axis[i].set_xticklabels([])
+ axis[i].plot(self.d[node_type][metric_l1],marker='o')
+ axis[i].set_xlabel('time')
+ axis[i].set_ylabel(metric_l1)
+ axis[i].set_title(metric_l1)
+
+ else:#2 levels
+ metric_l1=metric_path[0]
+ metric_l2=metric_path[1]
+ major_ticks = np.arange(0, len(self.d[node_type][metric_l1][metric_l2])+1, 1)
+ axis[i].set_xticks(major_ticks)
+ axis[i].set_xticklabels([])
+ axis[i].plot(self.d[node_type][metric_l1][metric_l2],marker='o')
+ axis[i].set_xlabel('time')
+ axis[i].set_ylabel(metric_l2)
+ axis[i].set_title(metric_l2)
+ i+=1
- plt.tight_layout()
- # Combine all the operations and display
- plt.savefig(node_type+'_stats_monitor.png')
- plt.show()
+ plt.tight_layout()
+ #save as png
+ plt.savefig(node_type+'_stats_monitor_'+page+'.png')
if __name__ == "__main__":
@@ -88,7 +113,7 @@ if __name__ == "__main__":
mon=StatMonitor(cfg_filename)
#collecting stats when modem process is stopped
- CMD='ps aux | grep mode | grep -v grep'
+ CMD='ps aux | grep modem | grep -v grep'
process=subprocess.Popen(CMD, shell=True, stdout=subprocess.PIPE)
output = process.stdout.readlines()
while len(output)!=0 :
diff --git a/ci-scripts/stats_monitor_conf.yaml b/ci-scripts/stats_monitor_conf.yaml
index 6c0a2b0225..8760c067fc 100644
--- a/ci-scripts/stats_monitor_conf.yaml
+++ b/ci-scripts/stats_monitor_conf.yaml
@@ -2,10 +2,50 @@ enb :
PHR:
bler:
mcsoff:
- mcs:
+ mcs:
+ graph:
+ page1:
+ PHR:
+ bler:
+ mcsoff:
+ mcs:
gnb :
dlsch_err:
dlsch_err_perc_round_1:
ulsch_err:
- ulsch_err_perc_round_1:
\ No newline at end of file
+ ulsch_err_perc_round_1:
+ rt :
+ feprx:
+ feptx_prec:
+ feptx_ofdm:
+ feptx_total:
+ L1 Tx processing thread 0:
+ L1 Tx processing thread 1:
+ DLSCH encoding:
+ L1 Rx processing:
+ PUSCH inner-receiver:
+ PUSCH decoding:
+ DL & UL scheduling timing stats:
+ UL Indication:
+ graph :
+ page1:
+ dlsch_err:
+ dlsch_err_perc_round_1:
+ ulsch_err:
+ ulsch_err_perc_round_1:
+ page2:
+ rt.feprx:
+ rt.feptx_prec:
+ rt.feptx_ofdm:
+ rt.feptx_total:
+ page3:
+ rt.L1 Tx processing thread 0:
+ rt.L1 Tx processing thread 1:
+ rt.DLSCH encoding:
+ rt.L1 Rx processing:
+ page4:
+ rt.PUSCH inner-receiver:
+ rt.PUSCH decoding:
+ rt.DL & UL scheduling timing stats:
+ rt.UL Indication:
\ No newline at end of file
diff --git a/ci-scripts/xml_class_list.yml b/ci-scripts/xml_class_list.yml
index d8e1b26a21..9e33ee468d 100755
--- a/ci-scripts/xml_class_list.yml
+++ b/ci-scripts/xml_class_list.yml
@@ -37,6 +37,7 @@
- IdleSleep
- Perform_X2_Handover
- Build_Image
+ - Copy_Image_to_Test
- Deploy_Object
- Undeploy_Object
- Cppcheck_Analysis
diff --git a/ci-scripts/xml_files/container_nsa_b200_quectel.xml b/ci-scripts/xml_files/container_nsa_b200_quectel.xml
new file mode 100644
index 0000000000..76610c2656
--- /dev/null
+++ b/ci-scripts/xml_files/container_nsa_b200_quectel.xml
@@ -0,0 +1,153 @@
+
+
+ TEST-NSA-FR1-TM1-B200
+ NSA SanityCheck with QUECTEL
+ tasks
+ 1
+
+ 000001
+ 010002
+ 030000
+ 030101
+ 000001
+ 030102
+ 000001
+ 010000
+ 000001
+ 050000
+ 050001
+ 070000
+ 070001
+ 010002
+ 000001
+ 030202
+ 030201
+
+
+
+
+ Initialize_UE
+ Initialize Quectel
+ idefix
+ yes
+
+
+
+
+ Terminate_UE
+ Terminate Quectel
+ idefix
+
+
+
+ Copy_Image_to_Test
+ Copy gNB image to test server
+ oai-gnb
+ 0
+ 1
+
+
+
+ Deploy_Object
+ Deploy eNB (FDD/Band7/5MHz/B200) in a container
+ ci-scripts/yaml_files/nsa_b200_enb
+ 0
+ 0
+
+
+
+ Deploy_Object
+ Deploy gNB (TDD/Band78/40MHz/B200) in a container
+ ci-scripts/yaml_files/nsa_b200_gnb
+ 1
+ 1
+
+
+
+ IdleSleep
+ Sleep
+ 5
+
+
+
+ IdleSleep
+ Sleep
+ 20
+
+
+
+
+ Ping
+ Ping: 20pings in 20sec
+ idefix
+ -c 20
+ 1
+
+
+
+ Ping
+ Ping: 100pings in 20sec
+ idefix
+ -c 100 -i 0.2
+ 1
+
+
+
+ Iperf
+ iperf (DL/20Mbps/UDP)(60 sec)(single-ue profile)
+ -u -b 20M -t 60
+ DL
+ idefix
+ 3
+ single-ue
+
+
+
+ Iperf
+ iperf (UL/2Mbps/UDP)(60 sec)(single-ue profile)
+ -u -b 2M -t 60
+ UL
+ idefix
+ 1
+ single-ue
+
+
+
+ Undeploy_Object
+ Undeploy eNB
+ ci-scripts/yaml_files/nsa_b200_enb
+ 0
+ 0
+
+
+
+ Undeploy_Object
+ Undeploy gNB
+ ci-scripts/yaml_files/nsa_b200_gnb
+ 1
+ 1
+
+
+
+
diff --git a/ci-scripts/xml_files/fr1_nsa_2x2_quectel.xml b/ci-scripts/xml_files/fr1_nsa_2x2_quectel.xml
index 16dfd1e377..bdca76379d 100644
--- a/ci-scripts/xml_files/fr1_nsa_2x2_quectel.xml
+++ b/ci-scripts/xml_files/fr1_nsa_2x2_quectel.xml
@@ -113,8 +113,8 @@
Iperf
- iperf (DL/20Mbps/UDP)(60 sec)(single-ue profile)
- -u -b 20M -t 60
+ iperf (DL/60Mbps/UDP)(60 sec)(single-ue profile)
+ -u -b 60M -t 60
DL
nrmodule2_quectel
5
diff --git a/ci-scripts/xml_files/fr1_nsa_quectel.xml b/ci-scripts/xml_files/fr1_nsa_quectel.xml
index 6c11a66d91..2d0ff53525 100644
--- a/ci-scripts/xml_files/fr1_nsa_quectel.xml
+++ b/ci-scripts/xml_files/fr1_nsa_quectel.xml
@@ -110,8 +110,8 @@
Iperf
- iperf (DL/20Mbps/UDP)(60 sec)(single-ue profile)
- -u -b 20M -t 60
+ iperf (DL/60Mbps/UDP)(60 sec)(single-ue profile)
+ -u -b 60M -t 60
DL
idefix
3
diff --git a/ci-scripts/xml_files/fr1_sa_quectel.xml b/ci-scripts/xml_files/fr1_sa_quectel.xml
index b401465f80..f4473710cf 100644
--- a/ci-scripts/xml_files/fr1_sa_quectel.xml
+++ b/ci-scripts/xml_files/fr1_sa_quectel.xml
@@ -98,8 +98,8 @@
Iperf
- iperf (DL/20Mbps/UDP)(60 sec)(single-ue profile)
- -u -b 20M -t 60
+ iperf (DL/60Mbps/UDP)(60 sec)(single-ue profile)
+ -u -b 60M -t 60
DL
nrmodule2_quectel
5
diff --git a/ci-scripts/yaml_files/fr1_epc_20897/docker-compose.yml b/ci-scripts/yaml_files/fr1_epc_20897/docker-compose.yml
index 0005ce8844..a3675dc78e 100644
--- a/ci-scripts/yaml_files/fr1_epc_20897/docker-compose.yml
+++ b/ci-scripts/yaml_files/fr1_epc_20897/docker-compose.yml
@@ -111,6 +111,9 @@ services:
TAC_LB_SGW_TEST_0: '03'
TAC_HB_SGW_TEST_0: '00'
SGW_IPV4_ADDRESS_FOR_S11_TEST_0: 0.0.0.0
+ volumes:
+ - ./mme.conf:/openair-mme/etc/mme.conf
+ - ./entrypoint.sh:/openair-mme/bin/entrypoint.sh
healthcheck:
test: /bin/bash -c "pgrep oai_mme"
interval: 10s
diff --git a/ci-scripts/yaml_files/fr1_epc_20897/entrypoint.sh b/ci-scripts/yaml_files/fr1_epc_20897/entrypoint.sh
new file mode 100755
index 0000000000..27c6c401a6
--- /dev/null
+++ b/ci-scripts/yaml_files/fr1_epc_20897/entrypoint.sh
@@ -0,0 +1,73 @@
+#!/bin/bash
+
+set -euo pipefail
+
+# First see if all interfaces are up
+ifconfig
+
+# S10 might be on loopback --> needs bring-up
+if [[ "$MME_INTERFACE_NAME_FOR_S10" == *"lo:"* ]]
+then
+ ifconfig ${MME_INTERFACE_NAME_FOR_S10} ${MME_IPV4_ADDRESS_FOR_S10} up
+fi
+
+LIST_OF_NETWORKS=`ifconfig -s | egrep -v "^Iface|^lo" | cut -d' ' -f1`
+
+for if_name in $LIST_OF_NETWORKS
+do
+ IF_IP_ADDR=`ifconfig $if_name | grep inet | sed -e "s# *inet#inet#" | cut -d' ' -f2`
+ if [[ "${IF_IP_ADDR}" == "${MME_IPV4_ADDRESS_FOR_S1_MME}" ]]; then
+ echo "S1C is on $if_name"
+ MME_INTERFACE_NAME_FOR_S1_MME=$if_name
+ fi
+ if [[ "${IF_IP_ADDR}" == "${MME_IPV4_ADDRESS_FOR_S10}" ]]; then
+ echo "S10 is on $if_name"
+ MME_INTERFACE_NAME_FOR_S10=$if_name
+ fi
+ if [[ "${IF_IP_ADDR}" == "${MME_IPV4_ADDRESS_FOR_S11}" ]]; then
+ echo "S11 is on $if_name"
+ MME_INTERFACE_NAME_FOR_S11=$if_name
+ fi
+done
+
+CONFIG_DIR="/openair-mme/etc"
+
+for c in ${CONFIG_DIR}/mme_fd.conf; do
+ #echo "entrypoint.sh process config file $c"
+ sed -i -e "s#@TAC-LB#@TAC_LB#" -e "s#TAC-HB_#TAC_HB_#" ${c}
+ # grep variable names (format: ${VAR}) from template to be rendered
+ VARS=$(grep -oP '@[a-zA-Z0-9_]+@' ${c} | sort | uniq | xargs)
+ #echo "entrypoint.sh process vars $VARS"
+
+ # create sed expressions for substituting each occurrence of ${VAR}
+ # with the value of the environment variable "VAR"
+ EXPRESSIONS=""
+ for v in ${VARS}; do
+ #echo "var is $v"
+ NEW_VAR=`echo $v | sed -e "s#@##g"`
+ #echo "NEW_VAR is $NEW_VAR"
+ if [[ "${!NEW_VAR}x" == "x" ]]; then
+ echo "Error: Environment variable '${NEW_VAR}' is not set." \
+ "Config file '$(basename $c)' requires all of $VARS."
+ exit 1
+ fi
+ # Some fields require CIDR format
+ if [[ "${NEW_VAR}" == "MME_IPV4_ADDRESS_FOR_S1_MME" ]] || \
+ [[ "${NEW_VAR}" == "MME_IPV4_ADDRESS_FOR_S11" ]] || \
+ [[ "${NEW_VAR}" == "MME_IPV4_ADDRESS_FOR_S10" ]]; then
+ EXPRESSIONS="${EXPRESSIONS};s|${v}|${!NEW_VAR}/24|g"
+ else
+ EXPRESSIONS="${EXPRESSIONS};s|${v}|${!NEW_VAR}|g"
+ fi
+ done
+ EXPRESSIONS="${EXPRESSIONS#';'}"
+
+ # render template and inline replace config file
+ sed -i "${EXPRESSIONS}" ${c}
+done
+
+pushd /openair-mme/scripts
+./check_mme_s6a_certificate ${PREFIX} ${MME_FQDN}
+popd
+
+exec "$@"
diff --git a/ci-scripts/yaml_files/fr1_epc_20897/mme.conf b/ci-scripts/yaml_files/fr1_epc_20897/mme.conf
new file mode 100644
index 0000000000..9dcb44ef2a
--- /dev/null
+++ b/ci-scripts/yaml_files/fr1_epc_20897/mme.conf
@@ -0,0 +1,133 @@
+MME :
+{
+ REALM = "openairinterface.org"; # YOUR REALM HERE
+ INSTANCE = 1; # 0 is the default
+ PID_DIRECTORY = "/var/run"; # /var/run is the default
+ MAX_S1_ENB = 64;
+ MAX_UE = 4096;
+ RELATIVE_CAPACITY = 10;
+ EMERGENCY_ATTACH_SUPPORTED = "no";
+ UNAUTHENTICATED_IMSI_SUPPORTED = "no";
+ DUMMY_HANDOVER_FORWARDING_ENABLED = "yes";
+ EPS_NETWORK_FEATURE_SUPPORT_IMS_VOICE_OVER_PS_SESSION_IN_S1 = "no"; # DO NOT CHANGE
+ EPS_NETWORK_FEATURE_SUPPORT_EMERGENCY_BEARER_SERVICES_IN_S1_MODE = "no"; # DO NOT CHANGE
+ EPS_NETWORK_FEATURE_SUPPORT_LOCATION_SERVICES_VIA_EPC = "no"; # DO NOT CHANGE
+ EPS_NETWORK_FEATURE_SUPPORT_EXTENDED_SERVICE_REQUEST = "no"; # DO NOT CHANGE
+
+ # Display statistics about whole system (expressed in seconds)
+ MME_STATISTIC_TIMER = 10;
+ MME_MOBILITY_COMPLETION_TIMER = 2; # Amount of time in seconds the source MME waits to release resources after HANDOVER/TAU is complete (with or without.
+ MME_S10_HANDOVER_COMPLETION_TIMER = 2; # Amount of time in soconds the target MME waits to check if a handover/tau process has completed successfully.
+
+ IP_CAPABILITY = "IPV4V6";
+ INTERTASK_INTERFACE :
+ {
+ ITTI_QUEUE_SIZE = 2000000;
+ };
+
+ S6A :
+ {
+ S6A_CONF = "/openair-mme/etc/mme_fd.conf";
+ HSS_HOSTNAME = "hss.openairinterface.org"; # THE HSS FQDN ex: hss.epc.mnc001.mcc001.3gppnetwork.org
+ HSS_REALM = "openairinterface.org"; # THE HSS REALM ex: epc.mnc001.mcc001.3gppnetwork.org
+ };
+
+ SCTP :
+ {
+ SCTP_INSTREAMS = 8;
+ SCTP_OUTSTREAMS = 8;
+ };
+
+ S1AP :
+ {
+ S1AP_OUTCOME_TIMER = 10;
+ };
+
+ GUMMEI_LIST = (
+ {MCC="208" ; MNC="97"; MME_GID="32768" ; MME_CODE="3"; } # YOUR GUMMEI CONFIG HERE
+ );
+
+ TAI_LIST = (
+ {MCC="208" ; MNC="97"; TAC = "1"; }, # YOUR TAI CONFIG HERE
+ {MCC="208" ; MNC="97"; TAC = "2"; }, # YOUR TAI CONFIG HERE
+ {MCC="208" ; MNC="97"; TAC = "3"; } # YOUR TAI CONFIG HERE
+ );
+
+ NAS :
+ {
+ ORDERED_SUPPORTED_INTEGRITY_ALGORITHM_LIST = [ "EIA2" , "EIA1" , "EIA0" ];
+ ORDERED_SUPPORTED_CIPHERING_ALGORITHM_LIST = [ "EEA0" , "EEA1" , "EEA2" ];
+ T3402 = 12
+ T3412 = 0
+ T3422 = 6
+ T3450 = 6
+ T3460 = 6
+ T3470 = 6
+ T3485 = 3
+ T3486 = 3
+ T3489 = 4
+ T3495 = 3
+ NAS_FORCE_TAU = 0
+ STRICT_FILLER_BITS_CHECK = "yes";
+ };
+
+ NETWORK_INTERFACES :
+ {
+ # MME binded interface for S1-C or S1-MME communication (S1AP), can be ethernet interface, virtual ethernet interface, we don't advise wireless interfaces
+ MME_INTERFACE_NAME_FOR_S1_MME = "eth0"; # YOUR NETWORK CONFIG HERE
+ MME_IPV4_ADDRESS_FOR_S1_MME = "192.168.61.195/24"; # CIDR, YOUR NETWORK CONFIG HERE
+# MME_IPV6_ADDRESS_FOR_S1_MME = "fd00::191/118"; # YOUR NETWORK CONFIG HERE
+ # MME binded interface for S11 communication (GTPV2-C)
+ MME_INTERFACE_NAME_FOR_S11 = "eth0"; # YOUR NETWORK CONFIG HERE
+ MME_IPV4_ADDRESS_FOR_S11 = "192.168.61.195/24"; # CIDR, YOUR NETWORK CONFIG HERE
+# MME_IPV6_ADDRESS_FOR_S11 = "fd00:0:0:4::191/64";
+ MME_PORT_FOR_S11 = 2123; # YOUR NETWORK CONFIG HERE
+
+
+ #S10 Interface
+ MME_INTERFACE_NAME_FOR_S10 = "lo"; # YOUR NETWORK CONFIG HERE
+ MME_IPV4_ADDRESS_FOR_S10 = "127.0.0.10/24"; # CIDR, YOUR NETWORK CONFIG HERE
+# MME_IPV6_ADDRESS_FOR_S10 = "fd00:0:0:4::191/64";
+ MME_PORT_FOR_S10 = 2123; # YOUR NETWORK CONFIG HERE
+ };
+
+ LOGGING :
+ {
+ # OUTPUT choice in { "CONSOLE", `path to file`", "`IPv4@`:`TCP port num`"}
+ # `path to file` must start with '.' or '/'
+ # if TCP stream choice, then you can easily dump the traffic on the remote or local host: nc -l `TCP port num` > received.txt
+ OUTPUT = "CONSOLE";
+ THREAD_SAFE = "no"; # THREAD_SAFE choice in { "yes", "no" }, safe to let 'no'
+ COLOR = "yes"; # COLOR choice in { "yes", "no" } means use of ANSI styling codes or no
+ # Log level choice in { "EMERGENCY", "ALERT", "CRITICAL", "ERROR", "WARNING", "NOTICE", "INFO", "DEBUG", "TRACE"}
+ SCTP_LOG_LEVEL = "TRACE";
+ S10_LOG_LEVEL = "TRACE";
+ S11_LOG_LEVEL = "TRACE";
+ # NEW LOGS FOR MCE
+ SM_LOG_LEVEL = "TRACE";
+ MCE_APP_LOG_LEVEL = "TRACE";
+ M2AP_LOG_LEVEL = "TRACE";
+ GTPV2C_LOG_LEVEL = "TRACE";
+ UDP_LOG_LEVEL = "DEBUG";
+ S1AP_LOG_LEVEL = "DEBUG";
+ NAS_LOG_LEVEL = "TRACE";
+ MME_APP_LOG_LEVEL = "TRACE";
+ S6A_LOG_LEVEL = "TRACE";
+ UTIL_LOG_LEVEL = "ERROR";
+ MSC_LOG_LEVEL = "ERROR";
+ ITTI_LOG_LEVEL = "ERROR";
+ ASN1_VERBOSITY = "annoying";
+ };
+
+
+# WRR_LIST_SELECTION = (
+# {ID="tac-lb03.tac-hb00.tac.epc.mnc001.mcc001.3gppnetwork.org" ; SGW_IP_ADDRESS_FOR_S11="192.168.61.196";},
+# {ID="tac-lb01.tac-hb00.tac.epc.mnc097.mcc208.3gppnetwork.org" ; SGW_IP_ADDRESS_FOR_S11="192.168.61.196";},
+# {ID="tac-lb02.tac-hb00.tac.epc.mnc097.mcc208.3gppnetwork.org" ; MME_IP_ADDRESS_FOR_S10="0.0.0.0";},
+# {ID="tac-lb03.tac-hb00.tac.epc.mnc097.mcc208.3gppnetwork.org" ; MME_IP_ADDRESS_FOR_S10="0.0.0.0";}
+# );
+ WRR_LIST_SELECTION = (
+ {ID="tac-lb01.tac-hb00.tac.epc.mnc097.mcc208.3gppnetwork.org" ; SGW_IP_ADDRESS_FOR_S11="192.168.61.196";}
+ );
+};
+
diff --git a/ci-scripts/yaml_files/magma_nsa_20897/mme.conf b/ci-scripts/yaml_files/magma_nsa_20897/mme.conf
index e41fbe6304..242b780a40 100644
--- a/ci-scripts/yaml_files/magma_nsa_20897/mme.conf
+++ b/ci-scripts/yaml_files/magma_nsa_20897/mme.conf
@@ -56,9 +56,7 @@ MME :
# ------- MME served TAIs
TAI_LIST = (
- {MCC="208" ; MNC="97"; TAC = "1"; },
- {MCC="208" ; MNC="97"; TAC = "2"; },
- {MCC="208" ; MNC="97"; TAC = "3"; }
+ {MCC="208" ; MNC="97"; TAC = "1"; }
);
TAC_LIST = (
diff --git a/ci-scripts/yaml_files/nsa_b200_enb/docker-compose.yml b/ci-scripts/yaml_files/nsa_b200_enb/docker-compose.yml
new file mode 100644
index 0000000000..60e82de50a
--- /dev/null
+++ b/ci-scripts/yaml_files/nsa_b200_enb/docker-compose.yml
@@ -0,0 +1,53 @@
+version: '3.8'
+
+services:
+ enb_mono_fdd:
+ image: oai-enb:latest
+ privileged: true
+ container_name: nsa-b200-enb
+ environment:
+ USE_FDD_MONO: 'yes'
+ USE_B2XX: 'yes'
+ ENB_NAME: eNB-in-docker
+ MCC: '222'
+ MNC: '01'
+ MNC_LENGTH: 2
+ TAC: 1
+ UTRA_BAND_ID: 7
+ DL_FREQUENCY_IN_MHZ: 2680
+ UL_FREQUENCY_OFFSET_IN_MHZ: 120
+ NID_CELL: 0
+ NB_PRB: 25
+ ENABLE_MEASUREMENT_REPORTS: 'yes'
+ ENABLE_X2: 'yes'
+ MME_S1C_IP_ADDRESS: 192.168.18.210
+ ENB_S1C_IF_NAME: eth0
+ ENB_S1C_IP_ADDRESS: 192.168.68.130
+ ENB_S1U_IF_NAME: eth0
+ ENB_S1U_IP_ADDRESS: 192.168.68.130
+ ENB_X2_IP_ADDRESS: 192.168.68.130
+ RRC_INACTIVITY_THRESHOLD: 0
+ FLEXRAN_ENABLED: 'no'
+ FLEXRAN_INTERFACE_NAME: eth0
+ FLEXRAN_IPV4_ADDRESS: 192.168.18.210
+ THREAD_PARALLEL_CONFIG: PARALLEL_RU_L1_TRX_SPLIT
+ volumes:
+ - /dev:/dev
+ networks:
+ public_net:
+ ipv4_address: 192.168.68.130
+ healthcheck:
+ # pgrep does NOT work
+ test: /bin/bash -c "ps aux | grep -v grep | grep -c softmodem"
+ interval: 10s
+ timeout: 5s
+ retries: 5
+
+networks:
+ public_net:
+ name: nsa-b200-enb-net
+ ipam:
+ config:
+ - subnet: 192.168.68.128/26
+ driver_opts:
+ com.docker.network.bridge.name: "nsa-enb-net"
diff --git a/ci-scripts/yaml_files/nsa_b200_gnb/docker-compose.yml b/ci-scripts/yaml_files/nsa_b200_gnb/docker-compose.yml
new file mode 100644
index 0000000000..692f830e5d
--- /dev/null
+++ b/ci-scripts/yaml_files/nsa_b200_gnb/docker-compose.yml
@@ -0,0 +1,50 @@
+version: '3.8'
+
+services:
+ gnb_mono_tdd:
+ image: oai-gnb:latest
+ privileged: true
+ container_name: nsa-b200-gnb
+ environment:
+ USE_NSA_TDD_MONO: 'yes'
+ USE_B2XX: 'yes'
+ GNB_NAME: gNB-in-docker
+ MCC: '222'
+ MNC: '01'
+ MNC_LENGTH: 2
+ TAC: 1
+ ENABLE_X2: 'yes'
+ ENB_X2_IP_ADDRESS: 192.168.68.130
+ MME_S1C_IP_ADDRESS: 192.168.18.210
+ GNB_S1C_IF_NAME: eth0
+ GNB_S1C_IP_ADDRESS: 192.168.68.194
+ GNB_S1U_IF_NAME: eth0
+ GNB_S1U_IP_ADDRESS: 192.168.68.194
+ GNB_X2_IP_ADDRESS: 192.168.68.194
+ RRC_INACTIVITY_THRESHOLD: 0
+ FLEXRAN_ENABLED: 'no'
+ FLEXRAN_INTERFACE_NAME: eth0
+ FLEXRAN_IPV4_ADDRESS: 192.168.18.210
+ THREAD_PARALLEL_CONFIG: PARALLEL_RU_L1_TRX_SPLIT
+ USE_ADDITIONAL_OPTIONS: '-E -q'
+ volumes:
+ - /dev:/dev
+ networks:
+ public_net:
+ ipv4_address: 192.168.68.194
+ #entrypoint: /bin/bash -c "sleep infinity"
+ healthcheck:
+ # pgrep does NOT work
+ test: /bin/bash -c "ps aux | grep -v grep | grep -c softmodem"
+ interval: 10s
+ timeout: 5s
+ retries: 5
+
+networks:
+ public_net:
+ name: nsa-b200-gnb-net
+ ipam:
+ config:
+ - subnet: 192.168.68.192/26
+ driver_opts:
+ com.docker.network.bridge.name: "nsa-gnb-net"
diff --git a/doc/FEATURE_SET.md b/doc/FEATURE_SET.md
index 4105d17511..9443fbd56e 100644
--- a/doc/FEATURE_SET.md
+++ b/doc/FEATURE_SET.md
@@ -104,7 +104,7 @@ The MAC layer implements a subset of the **3GPP 36.321** release v8.6 in support
- RLC interface (AM, UM)
- UL power control
- Link adaptation
-- Connected DRX (CDRX) support for FDD LTE UE. Compatible with R13 from 3GPP. Support for Cat-M1 UE comming soon.
+- Connected DRX (CDRX) support for FDD LTE UE. Compatible with R13 from 3GPP. Support for Cat-M1 UE comming soon.
## eNB RLC Layer ##
@@ -206,7 +206,7 @@ The Physical layer implements **3GPP 36.211**, **36.212**, **36.213** and provid
- PRACH preamble format 0
- All downlink (DL) channels are supported: PSS, SSS, PBCH, PCFICH, PHICH, PDCCH, PDSCH, PMCH
- All uplink (UL) channels are supported: PRACH, PUSCH, PUCCH (format 1/1a/1b), SRS, DRS
-- LTE MBMS-dedicated cell (feMBMS) procedures subset for LTE release 14 (experimental)
+- LTE MBMS-dedicated cell (feMBMS) procedures subset for LTE release 14 (experimental)
- LTE non-MBSFN subframe (feMBMS) Carrier Adquistion Subframe-CAS procedures (PSS/SSS/PBCH/PDSH) (experimental)
- LTE MBSFN MBSFN subframe channel (feMBMS): PMCH (CS@1.25KHz) (channel estimation for 25MHz bandwidth) (experimental)
@@ -313,6 +313,7 @@ The following features are valid for the gNB and the 5G-NR UE.
- MAC downlink scheduler
- phy-test scheduler (fixed allocation and usable also without UE)
- regular scheduler with dynamic allocation
+ - MCS adaptation from HARQ BLER
- MAC header generation (including timing advance)
- ACK / NACK handling and HARQ procedures for downlink
- MAC uplink scheduler
@@ -398,7 +399,7 @@ The following features are valid for the gNB and the 5G-NR UE.
- Creates TUN interface to PDCP to inject and receive user-place traffic
- No connection to the core network
* Supporting Standalone (SA) mode:
- - UE can register with the 5G Core Network, establish a PDU Session and exchange user-plane traffic
+ - UE can register with the 5G Core Network, establish a PDU Session and exchange user-plane traffic
## NR UE PHY Layer ##
@@ -484,7 +485,7 @@ The following features are valid for the gNB and the 5G-NR UE.
- Interfaces with PDCP, MAC
**UE PDCP**
-* Tx/Rx operations according to 38.323 Rel.16
+* Tx/Rx operations according to 38.323 Rel.16
- Integrity protection and ciphering procedures
- Sequence number management, SDU dicard and in-order delivery
- Radio bearer establishment/handling and association with PDCP entities
diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c
index d140e83248..2d43669f17 100644
--- a/executables/nr-gnb.c
+++ b/executables/nr-gnb.c
@@ -108,6 +108,7 @@ time_stats_t softmodem_stats_rx_sf; // total rx time
//#define TICK_TO_US(ts) (ts.diff)
#define TICK_TO_US(ts) (ts.trials==0?0:ts.diff/ts.trials)
+#define L1STATSSTRLEN 16384
void tx_func(void *param) {
@@ -354,46 +355,63 @@ void rx_func(void *param) {
);
#endif
}
-static void *process_stats_thread(void *param) {
+static void dump_L1_meas_stats(PHY_VARS_gNB *gNB, RU_t *ru, char *output) {
+ int stroff = 0;
+ stroff += print_meas_log(gNB->phy_proc_tx_0, "L1 Tx processing thread 0", NULL, NULL, output);
+ stroff += print_meas_log(gNB->phy_proc_tx_1, "L1 Tx processing thread 1", NULL, NULL, output+stroff);
+ stroff += print_meas_log(&gNB->dlsch_encoding_stats, "DLSCH encoding", NULL, NULL, output+stroff);
+ stroff += print_meas_log(&gNB->phy_proc_rx, "L1 Rx processing", NULL, NULL, output+stroff);
+ stroff += print_meas_log(&gNB->ul_indication_stats, "UL Indication", NULL, NULL, output+stroff);
+ stroff += print_meas_log(&gNB->rx_pusch_stats, "PUSCH inner-receiver", NULL, NULL, output+stroff);
+ stroff += print_meas_log(&gNB->ulsch_decoding_stats, "PUSCH decoding", NULL, NULL, output+stroff);
+ if (ru->feprx) stroff += print_meas_log(&ru->ofdm_demod_stats,"feprx",NULL,NULL, output+stroff);
- PHY_VARS_gNB *gNB = (PHY_VARS_gNB *)param;
+ if (ru->feptx_ofdm) {
+ stroff += print_meas_log(&ru->precoding_stats,"feptx_prec",NULL,NULL, output+stroff);
+ stroff += print_meas_log(&ru->txdataF_copy_stats,"txdataF_copy",NULL,NULL, output+stroff);
+ stroff += print_meas_log(&ru->ofdm_mod_stats,"feptx_ofdm",NULL,NULL, output+stroff);
+ stroff += print_meas_log(&ru->ofdm_total_stats,"feptx_total",NULL,NULL, output+stroff);
+ }
+ if (ru->fh_north_asynch_in) stroff += print_meas_log(&ru->rx_fhaul,"rx_fhaul",NULL,NULL, output+stroff);
+
+ stroff += print_meas_log(&ru->tx_fhaul,"tx_fhaul",NULL,NULL, output+stroff);
+
+ if (ru->fh_north_out) {
+ stroff += print_meas_log(&ru->compression,"compression",NULL,NULL, output+stroff);
+ stroff += print_meas_log(&ru->transport,"transport",NULL,NULL, output+stroff);
+ }
+}
+
+void *nrL1_stats_thread(void *param) {
+ PHY_VARS_gNB *gNB = (PHY_VARS_gNB *)param;
+ RU_t *ru = RC.ru[0];
+ char output[L1STATSSTRLEN];
+ memset(output,0,L1STATSSTRLEN);
+ wait_sync("L1_stats_thread");
+ FILE *fd;
+ fd=fopen("nrL1_stats.log","w");
+ AssertFatal(fd!=NULL,"Cannot open nrL1_stats.log\n");
+
+ reset_meas(gNB->phy_proc_tx_0);
+ reset_meas(gNB->phy_proc_tx_1);
reset_meas(&gNB->dlsch_encoding_stats);
reset_meas(&gNB->phy_proc_rx);
reset_meas(&gNB->ul_indication_stats);
reset_meas(&gNB->rx_pusch_stats);
reset_meas(&gNB->ulsch_decoding_stats);
- wait_sync("process_stats_thread");
-
- while(!oai_exit)
- {
- sleep(1);
- print_meas(gNB->phy_proc_tx_0, "L1 Tx processing thread 0", NULL, NULL);
- print_meas(gNB->phy_proc_tx_1, "L1 Tx processing thread 1", NULL, NULL);
- print_meas(&gNB->dlsch_encoding_stats, "DLSCH encoding", NULL, NULL);
- print_meas(&gNB->phy_proc_rx, "L1 Rx processing", NULL, NULL);
- print_meas(&gNB->ul_indication_stats, "UL Indication", NULL, NULL);
- print_meas(&gNB->rx_pusch_stats, "PUSCH inner-receiver", NULL, NULL);
- print_meas(&gNB->ulsch_decoding_stats, "PUSCH decoding", NULL, NULL);
- }
- return(NULL);
-}
-
-void *nrL1_stats_thread(void *param) {
- PHY_VARS_gNB *gNB = (PHY_VARS_gNB *)param;
- wait_sync("L1_stats_thread");
- FILE *fd;
while (!oai_exit) {
sleep(1);
- fd=fopen("nrL1_stats.log","w");
- AssertFatal(fd!=NULL,"Cannot open nrL1_stats.log\n");
dump_nr_I0_stats(fd,gNB);
dump_pdsch_stats(fd,gNB);
dump_pusch_stats(fd,gNB);
- // nr_dump_uci_stats(fd,eNB,eNB->proc.L1_proc_tx.frame_tx);
- fclose(fd);
+ dump_L1_meas_stats(gNB, ru, output);
+ fprintf(fd,"%s\n",output);
+ fflush(fd);
+ fseek(fd,0,SEEK_SET);
}
+ fclose(fd);
return(NULL);
}
@@ -454,12 +472,13 @@ void init_gNB_Tpool(int inst) {
initNotifiedFIFO(gNB->resp_RU_tx);
notifiedFIFO_elt_t *msgRUTx = newNotifiedFIFO_elt(sizeof(processingData_RU_t),0,gNB->resp_RU_tx,ru_tx_func);
processingData_RU_t *msgData = (processingData_RU_t*)msgRUTx->msgData;
- msgData->next_slot = sf_ahead*gNB->frame_parms.slots_per_subframe; // first Tx slot
+ int first_tx_slot = sf_ahead*gNB->frame_parms.slots_per_subframe;
+ msgData->next_slot = get_next_downlink_slot(gNB, &gNB->gNB_config, 0, first_tx_slot-1);
pushNotifiedFIFO(gNB->resp_RU_tx,msgRUTx); // to unblock the process in the beginning
- // Stats measurement thread
- if(opp_enabled == 1) threadCreate(&proc->process_stats_thread, process_stats_thread,(void *)gNB, "time_meas", -1, OAI_PRIORITY_RT_LOW);
- threadCreate(&proc->L1_stats_thread,nrL1_stats_thread,(void*)gNB,"L1_stats",-1,OAI_PRIORITY_RT_LOW);
+ if (!get_softmodem_params()->emulate_l1) {
+ threadCreate(&proc->L1_stats_thread,nrL1_stats_thread,(void*)gNB,"L1_stats",-1,OAI_PRIORITY_RT_LOW);
+ }
}
diff --git a/executables/nr-ru.c b/executables/nr-ru.c
index 945eb3d4d1..a2539a3adf 100644
--- a/executables/nr-ru.c
+++ b/executables/nr-ru.c
@@ -1535,7 +1535,6 @@ void init_RU_proc(RU_t *ru) {
if (ru->feptx_ofdm) nr_init_feptx_thread(ru);
}
- if (opp_enabled == 1) threadCreate(&ru->ru_stats_thread,ru_stats_thread,(void *)ru, "emulateRF", -1, OAI_PRIORITY_RT_LOW);
}
void kill_NR_RU_proc(int inst) {
diff --git a/openair1/PHY/TOOLS/time_meas.c b/openair1/PHY/TOOLS/time_meas.c
index c62fbed106..996f7fb277 100644
--- a/openair1/PHY/TOOLS/time_meas.c
+++ b/openair1/PHY/TOOLS/time_meas.c
@@ -131,6 +131,49 @@ void print_meas(time_stats_t *ts,
}
}
+int print_meas_log(time_stats_t *ts,
+ const char *name,
+ time_stats_t *total_exec_time,
+ time_stats_t *sf_exec_time,
+ char *output)
+{
+ int stroff = 0;
+ static int first_time = 0;
+ static double cpu_freq_GHz = 0.0;
+
+ if (cpu_freq_GHz == 0.0)
+ cpu_freq_GHz = get_cpu_freq_GHz();
+
+ if (first_time == 0) {
+ first_time=1;
+
+ if ((total_exec_time == NULL) || (sf_exec_time== NULL))
+ stroff += sprintf(output, "%25s %25s %25s %25s %25s %6f\n","Name","Total","Per Trials", "Num Trials","CPU_F_GHz", cpu_freq_GHz);
+ else
+ stroff += sprintf(output+stroff, "%25s %25s %25s %20s %15s %6f\n","Name","Total","Average/Frame","Trials", "CPU_F_GHz", cpu_freq_GHz);
+ }
+
+ if (ts->trials>0) {
+ //printf("%20s: total: %10.3f ms, average: %10.3f us (%10d trials)\n", name, ts->diff/cpu_freq_GHz/1000000.0, ts->diff/ts->trials/cpu_freq_GHz/1000.0, ts->trials);
+ if ((total_exec_time == NULL) || (sf_exec_time== NULL)) {
+ stroff += sprintf(output+stroff, "%25s: %15.3f us; %15d; %15.3f us;\n",
+ name,
+ (ts->diff/ts->trials/cpu_freq_GHz/1000.0),
+ ts->trials,
+ ts->max/cpu_freq_GHz/1000.0);
+ } else {
+ stroff += sprintf(output+stroff, "%25s: %15.3f ms (%5.2f%%); %15.3f us (%5.2f%%); %15d;\n",
+ name,
+ (ts->diff/cpu_freq_GHz/1000000.0),
+ ((ts->diff/cpu_freq_GHz/1000000.0)/(total_exec_time->diff/cpu_freq_GHz/1000000.0))*100, // percentage
+ (ts->diff/ts->trials/cpu_freq_GHz/1000.0),
+ ((ts->diff/ts->trials/cpu_freq_GHz/1000.0)/(sf_exec_time->diff/sf_exec_time->trials/cpu_freq_GHz/1000.0))*100, // percentage
+ ts->trials);
+ }
+ }
+ return stroff;
+}
+
double get_time_meas_us(time_stats_t *ts)
{
static double cpu_freq_GHz = 0.0;
diff --git a/openair1/PHY/TOOLS/time_meas.h b/openair1/PHY/TOOLS/time_meas.h
index f78ea55530..1ef2935917 100644
--- a/openair1/PHY/TOOLS/time_meas.h
+++ b/openair1/PHY/TOOLS/time_meas.h
@@ -88,6 +88,7 @@ static inline void stop_meas(time_stats_t *ts) __attribute__((always_inline));
void print_meas_now(time_stats_t *ts, const char *name, FILE *file_name);
void print_meas(time_stats_t *ts, const char *name, time_stats_t *total_exec_time, time_stats_t *sf_exec_time);
+int print_meas_log(time_stats_t *ts, const char *name, time_stats_t *total_exec_time, time_stats_t *sf_exec_time, char *output);
double get_time_meas_us(time_stats_t *ts);
double get_cpu_freq_GHz(void);
diff --git a/openair2/GNB_APP/MACRLC_nr_paramdef.h b/openair2/GNB_APP/MACRLC_nr_paramdef.h
index 7858cd6c32..b17fced7b7 100644
--- a/openair2/GNB_APP/MACRLC_nr_paramdef.h
+++ b/openair2/GNB_APP/MACRLC_nr_paramdef.h
@@ -60,6 +60,11 @@
#define CONFIG_STRING_MACRLC_PUCCHTARGETSNRX10 "pucch_TargetSNRx10"
#define CONFIG_STRING_MACRLC_PUCCHFAILURETHRES "pucch_FailureThres"
#define CONFIG_STRING_MACRLC_PUSCHFAILURETHRES "pusch_FailureThres"
+#define CONFIG_STRING_MACRLC_DL_BLER_TARGET_UPPER "dl_bler_target_upper"
+#define CONFIG_STRING_MACRLC_DL_BLER_TARGET_LOWER "dl_bler_target_lower"
+#define CONFIG_STRING_MACRLC_DL_RD2_BLER_THRESHOLD "dl_rd2_bler_threshold"
+#define CONFIG_STRING_MACRLC_DL_MAX_MCS "dl_max_mcs"
+
/*-------------------------------------------------------------------------------------------------------------------------------------------------------*/
/* MacRLC configuration parameters */
@@ -88,6 +93,10 @@
{CONFIG_STRING_MACRLC_PUCCHTARGETSNRX10, NULL, 0, iptr:NULL, defintval:150, TYPE_INT, 0}, \
{CONFIG_STRING_MACRLC_PUCCHFAILURETHRES, NULL, 0, iptr:NULL, defintval:10, TYPE_INT, 0}, \
{CONFIG_STRING_MACRLC_PUSCHFAILURETHRES, NULL, 0, iptr:NULL, defintval:10, TYPE_INT, 0}, \
+{CONFIG_STRING_MACRLC_DL_BLER_TARGET_UPPER, "Upper threshold of BLER to decrease DL MCS", 0, dblptr:NULL, defdblval:0.15, TYPE_DOUBLE, 0}, \
+{CONFIG_STRING_MACRLC_DL_BLER_TARGET_LOWER, "Lower threshold of BLER to increase DL MCS", 0, dblptr:NULL, defdblval:0.05, TYPE_DOUBLE, 0}, \
+{CONFIG_STRING_MACRLC_DL_RD2_BLER_THRESHOLD, "Threshold of RD2/RETX2 BLER to decrease DL MCS", 0, dblptr:NULL, defdblval:0.01, TYPE_DOUBLE, 0}, \
+{CONFIG_STRING_MACRLC_DL_MAX_MCS, "Maximum DL MCS that should be used", 0, u8ptr:NULL, defintval:28, TYPE_UINT8, 0}, \
}
#define MACRLC_CC_IDX 0
#define MACRLC_TRANSPORT_N_PREFERENCE_IDX 1
@@ -111,5 +120,10 @@
#define MACRLC_PUCCHTARGETSNRX10_IDX 19
#define MACRLC_PUCCHFAILURETHRES_IDX 20
#define MACRLC_PUSCHFAILURETHRES_IDX 21
+#define MACRLC_DL_BLER_TARGET_UPPER_IDX 22
+#define MACRLC_DL_BLER_TARGET_LOWER_IDX 23
+#define MACRLC_DL_RD2_BLER_THRESHOLD_IDX 24
+#define MACRLC_DL_MAX_MCS_IDX 25
+
/*---------------------------------------------------------------------------------------------------------------------------------------------------------*/
#endif
diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c
index 7c81a5ef49..dffced1374 100644
--- a/openair2/GNB_APP/gnb_config.c
+++ b/openair2/GNB_APP/gnb_config.c
@@ -755,6 +755,10 @@ void RCconfig_nr_macrlc() {
AssertFatal(1==0,"MACRLC %d: %s unknown southbound midhaul\n",j,*(MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_S_PREFERENCE_IDX].strptr));
}
RC.nrmac[j]->ulsch_max_frame_inactivity = *(MacRLC_ParamList.paramarray[j][MACRLC_ULSCH_MAX_FRAME_INACTIVITY].uptr);
+ RC.nrmac[j]->dl_bler_target_upper = *(MacRLC_ParamList.paramarray[j][MACRLC_DL_BLER_TARGET_UPPER_IDX].dblptr);
+ RC.nrmac[j]->dl_bler_target_lower = *(MacRLC_ParamList.paramarray[j][MACRLC_DL_BLER_TARGET_LOWER_IDX].dblptr);
+ RC.nrmac[j]->dl_rd2_bler_threshold = *(MacRLC_ParamList.paramarray[j][MACRLC_DL_RD2_BLER_THRESHOLD_IDX].dblptr);
+ RC.nrmac[j]->dl_max_mcs = *(MacRLC_ParamList.paramarray[j][MACRLC_DL_MAX_MCS_IDX].u8ptr);
RC.nrmac[j]->num_ulprbbl = num_prbbl;
LOG_I(NR_MAC,"Blacklisted PRBS %d\n",num_prbbl);
memcpy(RC.nrmac[j]->ulprbbl,prbbl,275*sizeof(prbbl[0]));
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c
index 44bb5da1f2..cc388697d0 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c
@@ -382,6 +382,74 @@ int nr_write_ce_dlsch_pdu(module_id_t module_idP,
return offset;
}
+#define BLER_UPDATE_FRAME 10
+#define BLER_FILTER 0.9f
+int get_mcs_from_bler(module_id_t mod_id, int CC_id, frame_t frame, sub_frame_t slot, int UE_id)
+{
+ gNB_MAC_INST *nrmac = RC.nrmac[mod_id];
+ const NR_ServingCellConfigCommon_t *scc = nrmac->common_channels[CC_id].ServingCellConfigCommon;
+ const int n = nr_slots_per_frame[*scc->ssbSubcarrierSpacing];
+
+ NR_DL_bler_stats_t *bler_stats = &nrmac->UE_info.UE_sched_ctrl[UE_id].dl_bler_stats;
+ /* first call: everything is zero. Initialize to sensible default */
+ if (bler_stats->last_frame_slot == 0 && bler_stats->mcs == 0) {
+ bler_stats->last_frame_slot = frame * n + slot;
+ bler_stats->mcs = 9;
+ bler_stats->bler = (nrmac->dl_bler_target_lower + nrmac->dl_bler_target_upper) / 2;
+ bler_stats->rd2_bler = nrmac->dl_rd2_bler_threshold;
+ }
+ const int now = frame * n + slot;
+ int diff = now - bler_stats->last_frame_slot;
+ if (diff < 0) // wrap around
+ diff += 1024 * n;
+
+ const uint8_t old_mcs = bler_stats->mcs;
+ const NR_mac_stats_t *stats = &nrmac->UE_info.mac_stats[UE_id];
+ // TODO put back this condition when relevant
+ /*const int dret3x = stats->dlsch_rounds[3] - bler_stats->dlsch_rounds[3];
+ if (dret3x > 0) {
+ if there is a third retransmission, decrease MCS for stabilization and
+ restart averaging window to stabilize transmission
+ bler_stats->last_frame_slot = now;
+ bler_stats->mcs = max(9, bler_stats->mcs - 1);
+ memcpy(bler_stats->dlsch_rounds, stats->dlsch_rounds, sizeof(stats->dlsch_rounds));
+ LOG_D(MAC, "%4d.%2d: %d retx in 3rd round, setting MCS to %d and restarting window\n", frame, slot, dret3x, bler_stats->mcs);
+ return bler_stats->mcs;
+ }*/
+ if (diff < BLER_UPDATE_FRAME * n)
+ return old_mcs; // no update
+
+ // last update is longer than x frames ago
+ const int dtx = stats->dlsch_rounds[0] - bler_stats->dlsch_rounds[0];
+ const int dretx = stats->dlsch_rounds[1] - bler_stats->dlsch_rounds[1];
+ const int dretx2 = stats->dlsch_rounds[2] - bler_stats->dlsch_rounds[2];
+ const float bler_window = dtx > 0 ? (float) dretx / dtx : bler_stats->bler;
+ const float rd2_bler_wnd = dtx > 0 ? (float) dretx2 / dtx : bler_stats->rd2_bler;
+ bler_stats->bler = BLER_FILTER * bler_stats->bler + (1 - BLER_FILTER) * bler_window;
+ bler_stats->rd2_bler = BLER_FILTER / 4 * bler_stats->rd2_bler + (1 - BLER_FILTER / 4) * rd2_bler_wnd;
+
+ int new_mcs = old_mcs;
+ // TODO put back this condition when relevant
+ /* first ensure that number of 2nd retx is below threshold. If this is the
+ * case, use 1st retx to adjust faster
+ if (bler_stats->rd2_bler > nrmac->dl_rd2_bler_threshold && old_mcs > 6) {
+ new_mcs -= 2;
+ } else if (bler_stats->rd2_bler < nrmac->dl_rd2_bler_threshold) {*/
+ if (bler_stats->bler < nrmac->dl_bler_target_lower && old_mcs < nrmac->dl_max_mcs && dtx > 9)
+ new_mcs += 1;
+ else if (bler_stats->bler > nrmac->dl_bler_target_upper && old_mcs > 6)
+ new_mcs -= 1;
+ // else we are within threshold boundaries
+
+
+ bler_stats->last_frame_slot = now;
+ bler_stats->mcs = new_mcs;
+ memcpy(bler_stats->dlsch_rounds, stats->dlsch_rounds, sizeof(stats->dlsch_rounds));
+ LOG_D(MAC, "%4d.%2d MCS %d -> %d (dtx %d, dretx %d, BLER wnd %.3f avg %.6f, dretx2 %d, RD2 BLER wnd %.3f avg %.6f)\n",
+ frame, slot, old_mcs, new_mcs, dtx, dretx, bler_window, bler_stats->bler, dretx2, rd2_bler_wnd, bler_stats->rd2_bler);
+ return new_mcs;
+}
+
void nr_store_dlsch_buffer(module_id_t module_id,
frame_t frame,
sub_frame_t slot) {
@@ -630,8 +698,8 @@ void pf_dl(module_id_t module_id,
continue;
/* Calculate coeff */
- sched_pdsch->mcs = 9;
ps->nrOfLayers = 1;
+ sched_pdsch->mcs = get_mcs_from_bler(module_id, /* CC_id = */ 0, frame, slot, UE_id);
uint32_t tbs = pf_tbs[ps->mcsTableIdx][sched_pdsch->mcs];
coeff_ue[UE_id] = (float) tbs / thr_ue[UE_id];
LOG_D(NR_MAC,"b %d, thr_ue[%d] %f, tbs %d, coeff_ue[%d] %f\n",
diff --git a/openair2/LAYER2/NR_MAC_gNB/main.c b/openair2/LAYER2/NR_MAC_gNB/main.c
index 6e13e4bcc6..0089263620 100644
--- a/openair2/LAYER2/NR_MAC_gNB/main.c
+++ b/openair2/LAYER2/NR_MAC_gNB/main.c
@@ -81,22 +81,28 @@ void dump_mac_stats(gNB_MAC_INST *gNB, char *output, int strlen)
for (int UE_id = UE_info->list.head; UE_id >= 0; UE_id = UE_info->list.next[UE_id]) {
- stroff+=sprintf(output+stroff,"UE ID %d RNTI %04x (%d/%d) PH %d dB PCMAX %d dBm\n",
+ const NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id];
+ NR_mac_stats_t *stats = &UE_info->mac_stats[UE_id];
+ const int avg_rsrp = stats->num_rsrp_meas > 0 ? stats->cumul_rsrp / stats->num_rsrp_meas : 0;
+ stroff+=sprintf(output+stroff,"UE ID %d RNTI %04x (%d/%d) PH %d dB PCMAX %d dBm, average RSRP %d (%d meas)\n",
UE_id,
UE_info->rnti[UE_id],
num++,
UE_info->num_UEs,
- UE_info->UE_sched_ctrl[UE_id].ph,
- UE_info->UE_sched_ctrl[UE_id].pcmax);
+ sched_ctrl->ph,
+ sched_ctrl->pcmax,
+ avg_rsrp,
+ stats->num_rsrp_meas);
- NR_mac_stats_t *stats = &UE_info->mac_stats[UE_id];
- const int avg_rsrp = stats->num_rsrp_meas > 0 ? stats->cumul_rsrp / stats->num_rsrp_meas : 0;
- stroff+=sprintf(output+stroff,"UE %d: dlsch_rounds %d/%d/%d/%d, dlsch_errors %d, pucch0_DTX %d average RSRP %d (%d meas)\n",
+ stroff+=sprintf(output+stroff,"UE %d: dlsch_rounds %d/%d/%d/%d, dlsch_errors %d, pucch0_DTX %d, BLER %.5f MCS %d\n",
UE_id,
stats->dlsch_rounds[0], stats->dlsch_rounds[1],
- stats->dlsch_rounds[2], stats->dlsch_rounds[3], stats->dlsch_errors,
+ stats->dlsch_rounds[2], stats->dlsch_rounds[3],
+ stats->dlsch_errors,
stats->pucch0_DTX,
- avg_rsrp, stats->num_rsrp_meas);
+ sched_ctrl->dl_bler_stats.bler,
+ sched_ctrl->dl_bler_stats.mcs);
+
stats->num_rsrp_meas = 0;
stats->cumul_rsrp = 0 ;
stroff+=sprintf(output+stroff,"UE %d: dlsch_total_bytes %d\n", UE_id, stats->dlsch_total_bytes);
@@ -121,7 +127,7 @@ void dump_mac_stats(gNB_MAC_INST *gNB, char *output, int strlen)
}
}
}
- print_meas(&gNB->eNB_scheduler, "DL & UL scheduling timing stats", NULL, NULL);
+ print_meas_log(&gNB->eNB_scheduler, "DL & UL scheduling timing stats", NULL, NULL, output+stroff);
}
diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
index 699b92a831..81be37872b 100644
--- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
+++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
@@ -422,6 +422,13 @@ typedef struct NR_UE_harq {
//! fixme : need to enhace for the multiple TB CQI report
+typedef struct NR_DL_bler_stats {
+ frame_t last_frame_slot;
+ float bler;
+ float rd2_bler;
+ uint8_t mcs;
+ int dlsch_rounds[8];
+} NR_DL_bler_stats_t;
//
/*! As per spec 38.214 section 5.2.1.4.2
@@ -565,6 +572,9 @@ typedef struct {
/// per-LC status data
mac_rlc_status_resp_t rlc_status[MAX_NUM_LCID];
+ /// Estimation of HARQ from BLER
+ NR_DL_bler_stats_t dl_bler_stats;
+
int lcid_mask;
int lcid_to_schedule;
uint16_t ta_frame;
@@ -763,6 +773,10 @@ typedef struct gNB_MAC_INST_s {
NR_Type0_PDCCH_CSS_config_t type0_PDCCH_CSS_config[64];
bool first_MIB;
+ double dl_bler_target_upper;
+ double dl_bler_target_lower;
+ double dl_rd2_bler_threshold;
+ uint8_t dl_max_mcs;
} gNB_MAC_INST;
#endif /*__LAYER2_NR_MAC_GNB_H__ */