diff --git a/ci-scripts/args_parse.py b/ci-scripts/args_parse.py
index 84b3a84514bf18afa15cdf04fdc38f4c0c1abbbc..248e873cdd66845490ee2fbd5a74a6edd3a26e66 100644
--- a/ci-scripts/args_parse.py
+++ b/ci-scripts/args_parse.py
@@ -41,7 +41,7 @@ import constants as CONST
 #-----------------------------------------------------------
 
 
-def ArgsParse(argvs,CiTestObj,RAN,HTML,EPC,ldpc,HELP):
+def ArgsParse(argvs,CiTestObj,RAN,HTML,EPC,ldpc,CONTAINERS,HELP):
 
 
     py_param_file_present = False
@@ -79,6 +79,7 @@ def ArgsParse(argvs,CiTestObj,RAN,HTML,EPC,ldpc,HELP):
             RAN.ranRepository=matchReg.group(1)
             HTML.ranRepository=matchReg.group(1)
             ldpc.ranRepository=matchReg.group(1)
+            CONTAINERS.ranRepository=matchReg.group(1)
         elif re.match('^\-\-eNB_AllowMerge=(.+)$|^\-\-ranAllowMerge=(.+)$', myArgv, re.IGNORECASE):
             if re.match('^\-\-eNB_AllowMerge=(.+)$', myArgv, re.IGNORECASE):
                 matchReg = re.match('^\-\-eNB_AllowMerge=(.+)$', myArgv, re.IGNORECASE)
@@ -90,6 +91,7 @@ def ArgsParse(argvs,CiTestObj,RAN,HTML,EPC,ldpc,HELP):
                 CiTestObj.ranAllowMerge = True
                 RAN.ranAllowMerge=True
                 HTML.ranAllowMerge=True
+                CONTAINERS.ranAllowMerge=True
         elif re.match('^\-\-eNBBranch=(.+)$|^\-\-ranBranch=(.+)$', myArgv, re.IGNORECASE):
             if re.match('^\-\-eNBBranch=(.+)$', myArgv, re.IGNORECASE):
                 matchReg = re.match('^\-\-eNBBranch=(.+)$', myArgv, re.IGNORECASE)
@@ -99,6 +101,7 @@ def ArgsParse(argvs,CiTestObj,RAN,HTML,EPC,ldpc,HELP):
             RAN.ranBranch=matchReg.group(1)
             HTML.ranBranch=matchReg.group(1)
             ldpc.ranBranch=matchReg.group(1)
+            CONTAINERS.ranBranch=matchReg.group(1)
         elif re.match('^\-\-eNBCommitID=(.*)$|^\-\-ranCommitID=(.*)$', myArgv, re.IGNORECASE):
             if re.match('^\-\-eNBCommitID=(.*)$', myArgv, re.IGNORECASE):
                 matchReg = re.match('^\-\-eNBCommitID=(.*)$', myArgv, re.IGNORECASE)
@@ -108,6 +111,7 @@ def ArgsParse(argvs,CiTestObj,RAN,HTML,EPC,ldpc,HELP):
             RAN.ranCommitID=matchReg.group(1)
             HTML.ranCommitID=matchReg.group(1)
             ldpc.ranCommitID=matchReg.group(1)
+            CONTAINERS.ranCommitID=matchReg.group(1)
         elif re.match('^\-\-eNBTargetBranch=(.*)$|^\-\-ranTargetBranch=(.*)$', myArgv, re.IGNORECASE):
             if re.match('^\-\-eNBTargetBranch=(.*)$', myArgv, re.IGNORECASE):
                 matchReg = re.match('^\-\-eNBTargetBranch=(.*)$', myArgv, re.IGNORECASE)
@@ -117,50 +121,63 @@ def ArgsParse(argvs,CiTestObj,RAN,HTML,EPC,ldpc,HELP):
             RAN.ranTargetBranch=matchReg.group(1)
             HTML.ranTargetBranch=matchReg.group(1)
             ldpc.ranTargetBranch=matchReg.group(1)
+            CONTAINERS.ranTargetBranch=matchReg.group(1)
         elif re.match('^\-\-eNBIPAddress=(.+)$|^\-\-eNB[1-2]IPAddress=(.+)$', myArgv, re.IGNORECASE):
             if re.match('^\-\-eNBIPAddress=(.+)$', myArgv, re.IGNORECASE):
                 matchReg = re.match('^\-\-eNBIPAddress=(.+)$', myArgv, re.IGNORECASE)
                 RAN.eNBIPAddress=matchReg.group(1)
                 ldpc.eNBIpAddr=matchReg.group(1)
+                CONTAINERS.eNBIPAddress=matchReg.group(1)
             elif re.match('^\-\-eNB1IPAddress=(.+)$', myArgv, re.IGNORECASE):
                 matchReg = re.match('^\-\-eNB1IPAddress=(.+)$', myArgv, re.IGNORECASE)
                 RAN.eNB1IPAddress=matchReg.group(1)
+                CONTAINERS.eNB1IPAddress=matchReg.group(1)
             elif re.match('^\-\-eNB2IPAddress=(.+)$', myArgv, re.IGNORECASE):
                 matchReg = re.match('^\-\-eNB2IPAddress=(.+)$', myArgv, re.IGNORECASE)
                 RAN.eNB2IPAddress=matchReg.group(1)
+                CONTAINERS.eNB2IPAddress=matchReg.group(1)
         elif re.match('^\-\-eNBUserName=(.+)$|^\-\-eNB[1-2]UserName=(.+)$', myArgv, re.IGNORECASE):
             if re.match('^\-\-eNBUserName=(.+)$', myArgv, re.IGNORECASE):
                 matchReg = re.match('^\-\-eNBUserName=(.+)$', myArgv, re.IGNORECASE)
                 RAN.eNBUserName=matchReg.group(1)
                 ldpc.eNBUserName=matchReg.group(1)
+                CONTAINERS.eNBUserName=matchReg.group(1)
             elif re.match('^\-\-eNB1UserName=(.+)$', myArgv, re.IGNORECASE):
                 matchReg = re.match('^\-\-eNB1UserName=(.+)$', myArgv, re.IGNORECASE)
                 RAN.eNB1UserName=matchReg.group(1)
+                CONTAINERS.eNB1UserName=matchReg.group(1)
             elif re.match('^\-\-eNB2UserName=(.+)$', myArgv, re.IGNORECASE):
                 matchReg = re.match('^\-\-eNB2UserName=(.+)$', myArgv, re.IGNORECASE)
                 RAN.eNB2UserName=matchReg.group(1)
+                CONTAINERS.eNB2UserName=matchReg.group(1)
         elif re.match('^\-\-eNBPassword=(.+)$|^\-\-eNB[1-2]Password=(.+)$', myArgv, re.IGNORECASE):
             if re.match('^\-\-eNBPassword=(.+)$', myArgv, re.IGNORECASE):
                 matchReg = re.match('^\-\-eNBPassword=(.+)$', myArgv, re.IGNORECASE)
                 RAN.eNBPassword=matchReg.group(1)
                 ldpc.eNBPassWord=matchReg.group(1)
+                CONTAINERS.eNBPassword=matchReg.group(1)
             elif re.match('^\-\-eNB1Password=(.+)$', myArgv, re.IGNORECASE):
                 matchReg = re.match('^\-\-eNB1Password=(.+)$', myArgv, re.IGNORECASE)
                 RAN.eNB1Password=matchReg.group(1)
+                CONTAINERS.eNB1Password=matchReg.group(1)
             elif re.match('^\-\-eNB2Password=(.+)$', myArgv, re.IGNORECASE):
                 matchReg = re.match('^\-\-eNB2Password=(.+)$', myArgv, re.IGNORECASE)
                 RAN.eNB2Password=matchReg.group(1)
+                CONTAINERS.eNB2Password=matchReg.group(1)
         elif re.match('^\-\-eNBSourceCodePath=(.+)$|^\-\-eNB[1-2]SourceCodePath=(.+)$', myArgv, re.IGNORECASE):
             if re.match('^\-\-eNBSourceCodePath=(.+)$', myArgv, re.IGNORECASE):
                 matchReg = re.match('^\-\-eNBSourceCodePath=(.+)$', myArgv, re.IGNORECASE)
                 RAN.eNBSourceCodePath=matchReg.group(1)
                 ldpc.eNBSourceCodePath=matchReg.group(1)
+                CONTAINERS.eNBSourceCodePath=matchReg.group(1)
             elif re.match('^\-\-eNB1SourceCodePath=(.+)$', myArgv, re.IGNORECASE):
                 matchReg = re.match('^\-\-eNB1SourceCodePath=(.+)$', myArgv, re.IGNORECASE)
                 RAN.eNB1SourceCodePath=matchReg.group(1)
+                CONTAINERS.eNB1SourceCodePath=matchReg.group(1)
             elif re.match('^\-\-eNB2SourceCodePath=(.+)$', myArgv, re.IGNORECASE):
                 matchReg = re.match('^\-\-eNB2SourceCodePath=(.+)$', myArgv, re.IGNORECASE)
                 RAN.eNB2SourceCodePath=matchReg.group(1)
+                CONTAINERS.eNB2SourceCodePath=matchReg.group(1)
         elif re.match('^\-\-EPCIPAddress=(.+)$', myArgv, re.IGNORECASE):
             matchReg = re.match('^\-\-EPCIPAddress=(.+)$', myArgv, re.IGNORECASE)
             EPC.IPAddress=matchReg.group(1)
diff --git a/ci-scripts/build_fr1_from_yaml.py b/ci-scripts/build_fr1_from_yaml.py
new file mode 100755
index 0000000000000000000000000000000000000000..a5492df6f6bc2d009ce010965c99a407a096081e
--- /dev/null
+++ b/ci-scripts/build_fr1_from_yaml.py
@@ -0,0 +1,83 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+Created on Tue Jul  7 23:04:51 2020
+
+@author: hardy
+"""
+
+
+
+import yaml
+import sys
+import subprocess
+
+      
+
+def main():
+  f_yaml=sys.argv[1]
+  f_sh=sys.argv[2]
+  #filename='py_params_template.yaml'
+  with open(f_yaml,'r') as file:
+    # The FullLoader parameter handles the conversion from YAML
+    # scalar values to Python the dictionary format
+    print('Loading '+f_yaml)
+    params = yaml.load(file,Loader=yaml.FullLoader)
+
+
+  with open(f_sh,'w') as f:
+    f.write('#!/bin/sh\n')
+    for i in range (0, len(params['steps'])):
+      step=params['steps'][i].split(',')
+      mode=step[0]
+      f_xml=step[1]
+      line='python3 main.py ' + \
+           '--mode='+ mode + ' ' + \
+           '--ranRepository=' + params['ranRepository'] + ' ' + \
+           '--ranBranch=' + params['ranBranch'] + ' ' + \
+           '--ranCommitID=' + params['ranCommitID'] + ' ' + \
+           '--ranAllowMerge=' + params['ranAllowMerge'] + ' ' + \
+           '--ranTargetBranch=' + params['ranTargetBranch'] + ' ' + \
+           \
+           '--ADBIPAddress=' + params['ADB']['ADBIPAddress'] + ' ' + \
+           '--ADBUserName=' + params['ADB']['ADBUserName'] + ' ' + \
+           '--ADBPassword=' + params['ADB']['ADBPassword'] + ' ' + \
+           \
+           '--UEIPAddress=' + params['UE']['UEIPAddress'] + ' ' + \
+           '--UEUserName=' + params['UE']['UEUserName'] + ' ' + \
+           '--UEPassword=' + params['UE']['UEPassword'] + ' ' + \
+           '--UESourceCodePath=' + params['UE']['UESourceCodePath'] + ' ' + \
+           \
+           '--EPCIPAddress=' + params['EPC']['EPCIPAddress'] + ' ' + \
+           '--EPCUserName=' + params['EPC']['EPCUserName'] + ' ' + \
+           '--EPCPassword=' + params['EPC']['EPCPassword'] + ' ' + \
+           '--EPCSourceCodePath=' + params['EPC']['EPCSourceCodePath'] + ' ' + \
+           '--EPCType=' + params['EPC']['EPCType'] + ' ' + \
+           \
+           '--eNBIPAddress=' + params['RAN'][0]['eNBIPAddress'] + ' ' + \
+           '--eNBUserName=' + params['RAN'][0]['eNBUserName'] + ' ' + \
+           '--eNBPassword=' + params['RAN'][0]['eNBPassword'] + ' ' + \
+           '--eNBSourceCodePath=' + params['RAN'][0]['eNBSourceCodePath'] + ' ' + \
+           \
+           '--eNB1IPAddress=' + params['RAN'][1]['eNB1IPAddress'] + ' ' + \
+           '--eNB1UserName=' + params['RAN'][1]['eNB1UserName'] + ' ' + \
+           '--eNB1Password=' + params['RAN'][1]['eNB1Password'] + ' ' + \
+           '--eNB1SourceCodePath=' + params['RAN'][1]['eNB1SourceCodePath'] + ' '
+      if mode!="InitiateHtml":
+         line+='--XMLTestFile=' + f_xml
+      #if mode is InitiateHTML we have a special processing to mention all xml files from the list
+      #loop starting at 1 to avoid the xml file mentioned with InitiateHtml in yaml file (file is none)
+      else:
+         for i in range (1, len(params['steps'])):
+            step=params['steps'][i].split(',')
+            f_xml=step[1]
+            line+='--XMLTestFile=' + f_xml+' '
+      line+='\n'
+      print(line)
+      f.write(line)
+  subprocess.call(['chmod','777',f_sh])
+
+if __name__ == "__main__":
+    main()
+
+
diff --git a/ci-scripts/build_fr1_template.yaml b/ci-scripts/build_fr1_template.yaml
new file mode 100755
index 0000000000000000000000000000000000000000..2a8f9cc6a02a3e7a798f90c6d0a9f02c292fbf7f
--- /dev/null
+++ b/ci-scripts/build_fr1_template.yaml
@@ -0,0 +1,46 @@
+
+ranRepository : https://gitlab.eurecom.fr/oai/openairinterface5g.git
+ranBranch : BRANCH_NAME 
+ranCommitID : COMMIT_ID 
+ranAllowMerge : 'true' 
+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_epc_closure.xml
+
+
+ADB: #on Caracal
+  ADBIPAddress : 192.168.18.196
+  ADBUserName : oaici
+  ADBPassword : KkexF6CErOi1fNuebCPsuIVK
+
+RAN:
+    - eNBIPAddress : 192.168.18.199 #eNB on Minimassive
+      eNBUserName : oaicicd
+      eNBPassword : HzB*nkryaITdVd08TKlT#2Z5a!7M#~qn
+      eNBSourceCodePath : /tmp/CI-FR1-eNB
+    - eNB1IPAddress : 192.168.18.198 #gNB on Mozart
+      eNB1UserName : oaicicd
+      eNB1Password : 7zkDOFgh@w3HvRBMPTMh@BAx
+      eNB1SourceCodePath : /tmp/CI-FR1-gNB
+
+
+EPC: #on Nikaia 
+  EPCIPAddress : 192.168.18.99
+  EPCUserName : nikaia
+  EPCPassword : linux
+  EPCSourceCodePath : /tmp/CI-FR1-EPC
+  EPCType : ltebox
+
+
+UE:
+  UEIPAddress : none
+  UEUserName : none
+  UEPassword : none
+  UESourceCodePath : none
+
+
diff --git a/ci-scripts/cls_containerize.py b/ci-scripts/cls_containerize.py
new file mode 100644
index 0000000000000000000000000000000000000000..1f95d2602f5daa0f0defea20f77af09f911f014f
--- /dev/null
+++ b/ci-scripts/cls_containerize.py
@@ -0,0 +1,410 @@
+#/*
+# * 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
+# */
+#---------------------------------------------------------------------
+# Python for CI of OAI-eNB + COTS-UE
+#
+#   Required Python Version
+#     Python 3.x
+#
+#   Required Python Package
+#     pexpect
+#---------------------------------------------------------------------
+
+#-----------------------------------------------------------
+# Import
+#-----------------------------------------------------------
+import sys              # arg
+import re               # reg
+import logging
+import os
+import time
+from multiprocessing import Process, Lock, SimpleQueue
+
+#-----------------------------------------------------------
+# OAI Testing modules
+#-----------------------------------------------------------
+import sshconnection as SSH
+import helpreadme as HELP
+import constants as CONST
+
+#-----------------------------------------------------------
+# Class Declaration
+#-----------------------------------------------------------
+class Containerize():
+
+	def __init__(self):
+		
+		self.ranRepository = ''
+		self.ranBranch = ''
+		self.ranAllowMerge = False
+		self.ranCommitID = ''
+		self.ranTargetBranch = ''
+		self.eNBIPAddress = ''
+		self.eNBUserName = ''
+		self.eNBPassword = ''
+		self.eNBSourceCodePath = ''
+		self.eNB1IPAddress = ''
+		self.eNB1UserName = ''
+		self.eNB1Password = ''
+		self.eNB1SourceCodePath = ''
+		self.eNB2IPAddress = ''
+		self.eNB2UserName = ''
+		self.eNB2Password = ''
+		self.eNB2SourceCodePath = ''
+		self.forcedWorkspaceCleanup = False
+		self.imageKind = ''
+		self.eNB_instance = 0
+		self.eNB_serverId = ['', '', '']
+		self.yamlPath = ['', '', '']
+		self.eNB_logFile = ['', '', '']
+
+		self.testCase_id = ''
+
+		self.flexranCtrlDeployed = False
+		self.flexranCtrlIpAddress = ''
+
+#-----------------------------------------------------------
+# Container management functions
+#-----------------------------------------------------------
+
+	def BuildImage(self, HTML):
+		if self.ranRepository == '' or self.ranBranch == '' or self.ranCommitID == '':
+			HELP.GenericHelp(CONST.Version)
+			sys.exit('Insufficient Parameter')
+		if self.eNB_serverId[self.eNB_instance] == '0':
+			lIpAddr = self.eNBIPAddress
+			lUserName = self.eNBUserName
+			lPassWord = self.eNBPassword
+			lSourcePath = self.eNBSourceCodePath
+		elif self.eNB_serverId[self.eNB_instance] == '1':
+			lIpAddr = self.eNB1IPAddress
+			lUserName = self.eNB1UserName
+			lPassWord = self.eNB1Password
+			lSourcePath = self.eNB1SourceCodePath
+		elif self.eNB_serverId[self.eNB_instance] == '2':
+			lIpAddr = self.eNB2IPAddress
+			lUserName = self.eNB2UserName
+			lPassWord = self.eNB2Password
+			lSourcePath = self.eNB2SourceCodePath
+		if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '':
+			HELP.GenericHelp(CONST.Version)
+			sys.exit('Insufficient Parameter')
+		logging.debug('Building on server: ' + lIpAddr)
+		mySSH = SSH.SSHConnection()
+		mySSH.open(lIpAddr, lUserName, lPassWord)
+
+		imageNames = []
+		result = re.search('eNB', self.imageKind)
+		# Creating a tupple with the imageName and the DockerFile prefix pattern
+		if result is not None:
+			imageNames.append(('oai-enb', 'eNB'))
+		else:
+			result = re.search('gNB', self.imageKind)
+			if result is not None:
+				imageNames.append(('oai-gnb', 'gNB'))
+			else:
+				result = re.search('all', self.imageKind)
+				if result is not None:
+					imageNames.append(('oai-enb', 'eNB'))
+					imageNames.append(('oai-gnb', 'gNB'))
+					imageNames.append(('oai-lte-ue', 'lteUE'))
+					imageNames.append(('oai-nr-ue', 'nrUE'))
+		if len(imageNames) == 0:
+			imageNames.append(('oai-enb', 'eNB'))
+		# Workaround for some servers, we need to erase completely the workspace
+		if self.forcedWorkspaceCleanup:
+			mySSH.command('echo ' + lPassWord + ' | sudo -S rm -Rf ' + lSourcePath, '\$', 15)
+		self.testCase_id = HTML.testCase_id
+		# on RedHat/CentOS .git extension is mandatory
+		result = re.search('([a-zA-Z0-9\:\-\.\/])+\.git', self.ranRepository)
+		if result is not None:
+			full_ran_repo_name = self.ranRepository
+		else:
+			full_ran_repo_name = self.ranRepository + '.git'
+		mySSH.command('mkdir -p ' + lSourcePath, '\$', 5)
+		mySSH.command('cd ' + lSourcePath, '\$', 5)
+		mySSH.command('if [ ! -e .git ]; then stdbuf -o0 git clone ' + full_ran_repo_name + ' .; else stdbuf -o0 git fetch --prune; fi', '\$', 600)
+		# Raphael: here add a check if git clone or git fetch went smoothly
+		mySSH.command('git config user.email "jenkins@openairinterface.org"', '\$', 5)
+		mySSH.command('git config user.name "OAI Jenkins"', '\$', 5)
+
+		mySSH.command('echo ' + lPassWord + ' | sudo -S git clean -x -d -ff', '\$', 30)
+		mySSH.command('mkdir -p cmake_targets/log', '\$', 5)
+		# if the commit ID is provided use it to point to it
+		if self.ranCommitID != '':
+			mySSH.command('git checkout -f ' + self.ranCommitID, '\$', 5)
+		# if the branch is not develop, then it is a merge request and we need to do 
+		# the potential merge. Note that merge conflicts should already been checked earlier
+		imageTag = 'develop'
+		if (self.ranAllowMerge):
+			imageTag = 'ci-temp'
+			if self.ranTargetBranch == '':
+				if (self.ranBranch != 'develop') and (self.ranBranch != 'origin/develop'):
+					mySSH.command('git merge --ff origin/develop -m "Temporary merge for CI"', '\$', 5)
+			else:
+				logging.debug('Merging with the target branch: ' + self.ranTargetBranch)
+				mySSH.command('git merge --ff origin/' + self.ranTargetBranch + ' -m "Temporary merge for CI"', '\$', 5)
+		# Let's remove any previous run artifacts if still there
+		mySSH.command('docker image prune --force', '\$', 5)
+		mySSH.command('docker image rm ran-build:' + imageTag, '\$', 5)
+		for image,pattern in imageNames:
+			mySSH.command('docker image rm ' + image + ':' + imageTag, '\$', 5)
+		# Build the shared image
+		mySSH.command('docker build --target ran-build --tag ran-build:' + imageTag + ' --file docker/Dockerfile.ran.ubuntu18 --build-arg NEEDED_GIT_PROXY="http://proxy.eurecom.fr:8080" . > cmake_targets/log/ran-build.log 2>&1', '\$', 800)
+		# Build the target image(s)
+		previousImage='ran-build:' + imageTag
+		danglingShaOnes=[]
+		for image,pattern in imageNames:
+			# the archived Dockerfiles have "ran-build:latest" as base image
+			# we need to update them with proper tag
+			mySSH.command('sed -i -e "s#ran-build:latest#ran-build:' + imageTag + '#" docker/Dockerfile.' + pattern + '.ubuntu18', '\$', 5)
+			mySSH.command('docker build --target ' + image + ' --tag ' + image + ':' + imageTag + ' --file docker/Dockerfile.' + pattern + '.ubuntu18 . > cmake_targets/log/' + image + '.log 2>&1', '\$', 600)
+			# Retrieving the dangling image(s) for the log collection
+			mySSH.command('docker images --filter "dangling=true" --filter "since=' + previousImage + '" -q | sed -e "s#^#sha=#"', '\$', 5)
+			result = re.search('sha=(?P<imageShaOne>[a-zA-Z0-9\-\_]+)', mySSH.getBefore())
+			if result is not None:
+				danglingShaOnes.append((image, result.group('imageShaOne')))
+			previousImage=image + ':' + imageTag
+
+		imageTag = 'ci-temp'
+		# First verify if images were properly created.
+		status = True
+		mySSH.command('docker image inspect --format=\'Size = {{.Size}} bytes\' ran-build:' + imageTag, '\$', 5)
+		if mySSH.getBefore().count('No such object') != 0:
+			logging.error('Could not build properly ran-build')
+			status = False
+		else:
+			result = re.search('Size = (?P<size>[0-9\-]+) bytes', mySSH.getBefore())
+			if result is not None:
+				imageSize = float(result.group('size'))
+				imageSize = imageSize / 1000
+				if imageSize < 1000:
+					logging.debug('\u001B[1m   ran-build size is ' + ('%.0f' % imageSize) + ' kbytes\u001B[0m')
+				else:
+					imageSize = imageSize / 1000
+					if imageSize < 1000:
+						logging.debug('\u001B[1m   ran-build size is ' + ('%.0f' % imageSize) + ' Mbytes\u001B[0m')
+					else:
+						imageSize = imageSize / 1000
+						logging.debug('\u001B[1m   ran-build size is ' + ('%.3f' % imageSize) + ' Gbytes\u001B[0m')
+			else:
+				logging.debug('ran-build size is unknown')
+		for image,pattern in imageNames:
+			mySSH.command('docker image inspect --format=\'Size = {{.Size}} bytes\' ' + image + ':' + imageTag, '\$', 5)
+			if mySSH.getBefore().count('No such object') != 0:
+				logging.error('Could not build properly ' + image)
+				status = False
+			else:
+				result = re.search('Size = (?P<size>[0-9\-]+) bytes', mySSH.getBefore())
+				if result is not None:
+					imageSize = float(result.group('size'))
+					imageSize = imageSize / 1000
+					if imageSize < 1000:
+						logging.debug('\u001B[1m   ' + image + ' size is ' + ('%.0f' % imageSize) + ' kbytes\u001B[0m')
+					else:
+						imageSize = imageSize / 1000
+						if imageSize < 1000:
+							logging.debug('\u001B[1m   ' + image + ' size is ' + ('%.0f' % imageSize) + ' Mbytes\u001B[0m')
+						else:
+							imageSize = imageSize / 1000
+							logging.debug('\u001B[1m   ' + image + ' size is ' + ('%.3f' % imageSize) + ' Gbytes\u001B[0m')
+				else:
+					logging.debug('ran-build size is unknown')
+		if not status:
+			mySSH.close()
+			logging.error('\u001B[1m Building OAI Images Failed\u001B[0m')
+			HTML.CreateHtmlTestRow(self.imageKind, 'KO', CONST.ALL_PROCESSES_OK)
+			HTML.CreateHtmlTabFooter(False)
+			sys.exit(1)
+
+		# Recover build logs, for the moment only possible when build is successful
+		mySSH.command('docker create --name test ran-build:' + imageTag, '\$', 5)
+		mySSH.command('mkdir -p cmake_targets/log/ran-build', '\$', 5)
+		mySSH.command('docker cp test:/oai-ran/cmake_targets/log/. cmake_targets/log/ran-build', '\$', 5)
+		mySSH.command('docker rm -f test', '\$', 5)
+		for image,shaone in danglingShaOnes:
+			mySSH.command('mkdir -p cmake_targets/log/' + image, '\$', 5)
+			mySSH.command('docker create --name test ' + shaone, '\$', 5)
+			mySSH.command('docker cp test:/oai-ran/cmake_targets/log/. cmake_targets/log/' + image, '\$', 5)
+			mySSH.command('docker rm -f test', '\$', 5)
+		mySSH.command('docker image prune --force', '\$', 5)
+		mySSH.command('cd cmake_targets', '\$', 5)
+		mySSH.command('mkdir -p build_log_' + self.testCase_id, '\$', 5)
+		mySSH.command('mv log/* ' + 'build_log_' + self.testCase_id, '\$', 5)
+		mySSH.close()
+
+		logging.info('\u001B[1m Building OAI Image(s) Pass\u001B[0m')
+		HTML.CreateHtmlTestRow(self.imageKind, 'OK', CONST.ALL_PROCESSES_OK)
+
+	def DeployObject(self, HTML, EPC):
+		if self.eNB_serverId[self.eNB_instance] == '0':
+			lIpAddr = self.eNBIPAddress
+			lUserName = self.eNBUserName
+			lPassWord = self.eNBPassword
+			lSourcePath = self.eNBSourceCodePath
+		elif self.eNB_serverId[self.eNB_instance] == '1':
+			lIpAddr = self.eNB1IPAddress
+			lUserName = self.eNB1UserName
+			lPassWord = self.eNB1Password
+			lSourcePath = self.eNB1SourceCodePath
+		elif self.eNB_serverId[self.eNB_instance] == '2':
+			lIpAddr = self.eNB2IPAddress
+			lUserName = self.eNB2UserName
+			lPassWord = self.eNB2Password
+			lSourcePath = self.eNB2SourceCodePath
+		if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '':
+			HELP.GenericHelp(CONST.Version)
+			sys.exit('Insufficient Parameter')
+		logging.debug('\u001B[1m Deploying OAI Object on server: ' + lIpAddr + '\u001B[0m')
+		mySSH = SSH.SSHConnection()
+		mySSH.open(lIpAddr, lUserName, lPassWord)
+		# Putting the CPUs in a good 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 -D 0; fi', '\$', 5)
+			time.sleep(5)
+		
+		mySSH.command('cd ' + lSourcePath + '/' + self.yamlPath[self.eNB_instance], '\$', 5)
+		mySSH.command('cp docker-compose.yml ci-docker-compose.yml', '\$', 5)
+		imageTag = 'develop'
+		if (self.ranAllowMerge):
+			imageTag = 'ci-temp'
+		mySSH.command('sed -i -e "s/image: oai-enb:latest/image: oai-enb:' + imageTag + '/" ci-docker-compose.yml', '\$', 2)
+		localMmeIpAddr = EPC.MmeIPAddress
+		mySSH.command('sed -i -e "s/CI_MME_IP_ADDR/' + localMmeIpAddr + '/" ci-docker-compose.yml', '\$', 2)
+		if self.flexranCtrlDeployed:
+			mySSH.command('sed -i -e \'s/FLEXRAN_ENABLED:.*/FLEXRAN_ENABLED: "yes"/\' ci-docker-compose.yml', '\$', 2)
+			mySSH.command('sed -i -e "s/CI_FLEXRAN_CTL_IP_ADDR/' + self.flexranCtrlIpAddress + '/" ci-docker-compose.yml', '\$', 2)
+		else:
+			mySSH.command('sed -i -e "s/FLEXRAN_ENABLED:.*$/FLEXRAN_ENABLED: \"no\"/" ci-docker-compose.yml', '\$', 2)
+			mySSH.command('sed -i -e "s/CI_FLEXRAN_CTL_IP_ADDR/127.0.0.1/" ci-docker-compose.yml', '\$', 2)
+		# Currently support only one
+		mySSH.command('docker-compose --file ci-docker-compose.yml config --services | sed -e "s@^@service=@"', '\$', 2)
+		result = re.search('service=(?P<svc_name>[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)
+
+		# Checking Status
+		mySSH.command('docker-compose --file ci-docker-compose.yml config', '\$', 5)
+		result = re.search('container_name: (?P<container_name>[a-zA-Z0-9\-\_]+)', mySSH.getBefore())
+		unhealthyNb = 0
+		healthyNb = 0
+		startingNb = 0
+		containerName = ''
+		if result is not None:
+			containerName = result.group('container_name')
+			time.sleep(5)
+			cnt = 0
+			while (cnt < 3):
+				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')
+				if healthyNb == 1:
+					cnt = 10
+				else:
+					time.sleep(10)
+					cnt += 1
+		logging.debug(' -- ' + str(healthyNb) + ' healthy container(s)')
+		logging.debug(' -- ' + str(unhealthyNb) + ' unhealthy container(s)')
+		logging.debug(' -- ' + str(startingNb) + ' still starting container(s)')
+
+		status = False
+		if healthyNb == 1:
+			cnt = 0
+			while (cnt < 20):
+				mySSH.command('docker logs ' + containerName + ' | egrep --text --color=never -i "wait|sync|Starting"', '\$', 30) 
+				result = re.search('got sync|Starting F1AP at CU', mySSH.getBefore())
+				if result is None:
+					time.sleep(6)
+					cnt += 1
+				else:
+					cnt = 100
+					status = True
+					logging.info('\u001B[1m Deploying OAI object Pass\u001B[0m')
+					time.sleep(10)
+		mySSH.close()
+
+		self.testCase_id = HTML.testCase_id
+		self.eNB_logFile[self.eNB_instance] = 'enb_' + self.testCase_id + '.log'
+
+		if status:
+			HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK)
+		else:
+			HTML.CreateHtmlTestRow('N/A', 'KO', CONST.ALL_PROCESSES_OK)
+
+	def UndeployObject(self, HTML, RAN):
+		logging.info('\u001B[1m Undeploying OAI Object Pass\u001B[0m')
+		if self.eNB_serverId[self.eNB_instance] == '0':
+			lIpAddr = self.eNBIPAddress
+			lUserName = self.eNBUserName
+			lPassWord = self.eNBPassword
+			lSourcePath = self.eNBSourceCodePath
+		elif self.eNB_serverId[self.eNB_instance] == '1':
+			lIpAddr = self.eNB1IPAddress
+			lUserName = self.eNB1UserName
+			lPassWord = self.eNB1Password
+			lSourcePath = self.eNB1SourceCodePath
+		elif self.eNB_serverId[self.eNB_instance] == '2':
+			lIpAddr = self.eNB2IPAddress
+			lUserName = self.eNB2UserName
+			lPassWord = self.eNB2Password
+			lSourcePath = self.eNB2SourceCodePath
+		if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '':
+			HELP.GenericHelp(CONST.Version)
+			sys.exit('Insufficient Parameter')
+		logging.debug('\u001B[1m Deploying OAI Object on server: ' + lIpAddr + '\u001B[0m')
+		mySSH = SSH.SSHConnection()
+		mySSH.open(lIpAddr, lUserName, lPassWord)
+		mySSH.command('cd ' + lSourcePath + '/' + self.yamlPath[self.eNB_instance], '\$', 5)
+		# Currently support only one
+		mySSH.command('docker-compose --file ci-docker-compose.yml config', '\$', 5)
+		result = re.search('container_name: (?P<container_name>[a-zA-Z0-9\-\_]+)', mySSH.getBefore())
+		if result is not None:
+			containerName = result.group('container_name')
+			mySSH.command('docker kill --signal INT ' + containerName, '\$', 30)
+			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)
+
+		# 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!
+		copyin_res = mySSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/' + self.eNB_logFile[self.eNB_instance], '.')
+		nodeB_prefix = 'e'
+		if (copyin_res == -1):
+			HTML.htmleNBFailureMsg='Could not copy ' + nodeB_prefix + 'NB logfile to analyze it!'
+			HTML.CreateHtmlTestRow('N/A', 'KO', CONST.ENB_PROCESS_NOLOGFILE_TO_ANALYZE)
+		else:
+			logging.debug('\u001B[1m Analyzing ' + nodeB_prefix + 'NB logfile \u001B[0m ' + self.eNB_logFile[self.eNB_instance])
+			logStatus = RAN.AnalyzeLogFile_eNB(self.eNB_logFile[self.eNB_instance], HTML)
+			if (logStatus < 0):
+				HTML.CreateHtmlTestRow(RAN.runtime_stats, 'KO', logStatus)
+			else:
+				HTML.CreateHtmlTestRow(RAN.runtime_stats, 'OK', CONST.ALL_PROCESSES_OK)
+
diff --git a/ci-scripts/cls_oaicitest.py b/ci-scripts/cls_oaicitest.py
index 37d648a5b065becafa5218c756de3cc654f4bc61..9a643b416a2a634c2d162ef2d86c70dd21e1622a 100644
--- a/ci-scripts/cls_oaicitest.py
+++ b/ci-scripts/cls_oaicitest.py
@@ -42,6 +42,7 @@ import xml.etree.ElementTree as ET
 import logging
 import datetime
 import signal
+import statistics as stat
 from multiprocessing import Process, Lock, SimpleQueue
 logging.basicConfig(
 	level=logging.DEBUG,
@@ -53,6 +54,52 @@ import helpreadme as HELP
 import constants as CONST
 import sshconnection
 
+
+
+
+#-----------------------------------------------------------
+# Utility functions
+#-----------------------------------------------------------
+
+def GetPingTimeAnalysis(ping_log_file):
+	#ping time values read from file
+	t_ping=[]
+	#ping stats (dictionary) to be returned by the function
+	ping_stat={}
+	if (os.path.isfile(ping_log_file)):
+		with open(ping_log_file,"r") as f:
+			for line in f:
+				#looking for time=xxx ms field
+				result=re.match('^.+time=(?P<ping_time>[0-9\.]+)',line)
+				if result != None:
+					t_ping.append(float(result.group('ping_time')))
+
+		#initial stats
+		ping_stat['min_0']=min(t_ping)
+		ping_stat['mean_0']=stat.mean(t_ping)
+		ping_stat['median_0']=stat.median(t_ping)
+		ping_stat['max_0']=max(t_ping)
+
+		#get index of max value
+		
+		max_loc=t_ping.index(max(t_ping))
+		ping_stat['max_loc']=max_loc
+		#remove it
+		t_ping.pop(max_loc)
+		#new stats after removing max value
+		ping_stat['min_1']=min(t_ping)
+		ping_stat['mean_1']=stat.mean(t_ping)
+		ping_stat['median_1']=stat.median(t_ping)
+		ping_stat['max_1']=max(t_ping)
+
+		return ping_stat
+
+	else:
+		logging.error("Ping log file does not exist")
+		return -1
+
+	
+
 #-----------------------------------------------------------
 # OaiCiTest Class Definition
 #-----------------------------------------------------------
@@ -216,7 +263,7 @@ class OaiCiTest():
 			HTML.CreateHtmlTabFooter(False)
 			self.ConditionalExit()
 
-	def CheckFlexranCtrlInstallation(self,RAN,EPC):
+	def CheckFlexranCtrlInstallation(self,RAN,EPC,CONTAINERS):
 		if EPC.IPAddress == '' or EPC.UserName == '' or EPC.Password == '':
 			return
 		SSH = sshconnection.SSHConnection()
@@ -225,7 +272,18 @@ class OaiCiTest():
 		result = re.search('/opt/flexran_rtc/build/rt_controller', SSH.getBefore())
 		if result is not None:
 			RAN.flexranCtrlInstalled=True
+			RAN.flexranCtrlIpAddress=EPC.IPAddress
 			logging.debug('Flexran Controller is installed')
+		else:
+			# Maybe flexran-rtc is deployed into a container
+			SSH.command('docker inspect --format="FLEX_RTC_IP_ADDR = {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}" prod-flexran-rtc', '\$', 5)
+			result = re.search('FLEX_RTC_IP_ADDR = (?P<flex_ip_addr>[0-9\.]+)', SSH.getBefore())
+			if result is not None:
+				RAN.flexranCtrlDeployed=True
+				RAN.flexranCtrlIpAddress=result.group('flex_ip_addr')
+				CONTAINERS.flexranCtrlDeployed=True
+				CONTAINERS.flexranCtrlIpAddress=result.group('flex_ip_addr')
+				logging.debug('Flexran Controller is deployed: ' + RAN.flexranCtrlIpAddress)
 		SSH.close()
 
 	def InitializeFlexranCtrl(self, HTML,RAN,EPC):
@@ -547,7 +605,7 @@ class OaiCiTest():
 				HTML.htmlUEFailureMsg='nr-uesoftmodem did NOT synced'
 				HTML.CreateHtmlTestRow(self.air_interface + ' ' +  self.Initialize_OAI_UE_args, 'KO', CONST.OAI_UE_PROCESS_COULD_NOT_SYNC, 'OAI UE')
 			logging.error('\033[91mInitialize OAI UE Failed! \033[0m')
-			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 
 	def checkDevTTYisUnlocked(self):
 		SSH = sshconnection.SSHConnection()
@@ -625,7 +683,7 @@ class OaiCiTest():
 		HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK)
 		self.checkDevTTYisUnlocked()
 
-	def AttachCatM(self,HTML,RAN,COTS_UE):
+	def AttachCatM(self,HTML,RAN,COTS_UE,EPC):
 		if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '':
 			HELP.GenericHelp(CONST.Version)
 			sys.exit('Insufficient Parameter')
@@ -698,7 +756,7 @@ class OaiCiTest():
 			html_cell = '<pre style="background-color:white">CAT-M module Attachment Failed</pre>'
 			html_queue.put(html_cell)
 			HTML.CreateHtmlTestRowQueue('N/A', 'KO', 1, html_queue)
-			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 
 	def PingCatM(self,HTML,RAN,EPC,COTS_UE):
 		if EPC.IPAddress == '' or EPC.UserName == '' or EPC.Password == '' or EPC.SourceCodePath == '':
@@ -709,7 +767,7 @@ class OaiCiTest():
 		pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE,RAN,EPC)
 		if (pStatus < 0):
 			HTML.CreateHtmlTestRow(self.ping_args, 'KO', pStatus)
-			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 			return
 		try:
 			statusQueue = SimpleQueue()
@@ -730,7 +788,7 @@ class OaiCiTest():
 					moduleIPAddr = result.group('ipaddr')
 				else:
 					HTML.CreateHtmlTestRow(self.ping_args, 'KO', pStatus)
-					self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+					self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 					return
 			ping_time = re.findall("-c (\d+)",str(self.ping_args))
 			device_id = 'catm'
@@ -794,7 +852,7 @@ class OaiCiTest():
 				HTML.CreateHtmlTestRowQueue(self.ping_args, 'OK', 1, statusQueue)
 			else:
 				HTML.CreateHtmlTestRowQueue(self.ping_args, 'KO', 1, statusQueue)
-				self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+				self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 		except:
 			os.kill(os.getppid(),signal.SIGUSR1)
 
@@ -895,7 +953,7 @@ class OaiCiTest():
 		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)
+			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 			return
 		multi_jobs = []
 		status_queue = SimpleQueue()
@@ -914,7 +972,7 @@ class OaiCiTest():
 
 		if (status_queue.empty()):
 			HTML.CreateHtmlTestRow('N/A', 'KO', CONST.ALL_PROCESSES_OK)
-			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 			return
 		else:
 			attach_status = True
@@ -943,7 +1001,7 @@ class OaiCiTest():
 					time.sleep(5)
 			else:
 				HTML.CreateHtmlTestRowQueue('N/A', 'KO', len(self.UEDevices), html_queue)
-				self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+				self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 
 	def DetachUE_common(self, device_id, idx,COTS_UE):
 		try:
@@ -976,7 +1034,7 @@ class OaiCiTest():
 		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)
+			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 			return
 		multi_jobs = []
 		cnt = 0
@@ -1227,6 +1285,8 @@ class OaiCiTest():
 				if lDataConnectionState == 3:
 					dataConnectionState = 'Data State:    SUSPENDED'
 			result = re.search('mDataConnectionReason=(?P<dataConnectionReason>[0-9a-zA-Z_]+)', SSH.getBefore())
+			time.sleep(1)
+			SSH.close()
 			dataConnectionReason = 'Data Reason:   UNKNOWN'
 			if result is not None:
 				dataConnectionReason = 'Data Reason:   ' + result.group('dataConnectionReason')
@@ -1240,7 +1300,6 @@ class OaiCiTest():
 			qMsg = serviceState + '\n' + dataConnectionState + '\n' + dataConnectionReason
 			statusQueue.put(qMsg)
 			lock.release()
-			SSH.close()
 		except:
 			os.kill(os.getppid(),signal.SIGUSR1)
 
@@ -1267,12 +1326,12 @@ class OaiCiTest():
 			i += 1
 		for job in multi_jobs:
 			job.join()
-		if RAN.flexranCtrlInstalled and RAN.flexranCtrlStarted:
+		if (RAN.flexranCtrlInstalled and RAN.flexranCtrlStarted) or RAN.flexranCtrlDeployed:
 			SSH = sshconnection.SSHConnection()
 			SSH.open(EPC.IPAddress, EPC.UserName, EPC.Password)
-			SSH.command('cd /opt/flexran_rtc', '\$', 5)
-			SSH.command('curl http://localhost:9999/stats | jq \'.\' > log/check_status_' + self.testCase_id + '.log 2>&1', '\$', 5)
-			SSH.command('cat log/check_status_' + self.testCase_id + '.log | jq \'.eNB_config[0].UE\' | grep -c rnti | sed -e "s#^#Nb Connected UE = #"', '\$', 5)
+			SSH.command('cd ' + EPC.SourceCodePath + '/scripts', '\$', 5)
+			SSH.command('curl http://' + RAN.flexranCtrlIpAddress + ':9999/stats | jq \'.\' > check_status_' + self.testCase_id + '.log 2>&1', '\$', 5)
+			SSH.command('cat check_status_' + self.testCase_id + '.log | jq \'.eNB_config[0].UE\' | grep -c rnti | sed -e "s#^#Nb Connected UE = #"', '\$', 5)
 			result = re.search('Nb Connected UE = (?P<nb_ues>[0-9]+)', SSH.getBefore())
 			passStatus = True
 			if result is not None:
@@ -1291,7 +1350,7 @@ class OaiCiTest():
 
 		if (status_queue.empty()):
 			HTML.CreateHtmlTestRow(htmlOptions, 'KO', CONST.ALL_PROCESSES_OK)
-			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 		else:
 			check_status = True
 			html_queue = SimpleQueue()
@@ -1307,7 +1366,7 @@ class OaiCiTest():
 				HTML.CreateHtmlTestRowQueue(htmlOptions, 'OK', len(self.UEDevices), html_queue)
 			else:
 				HTML.CreateHtmlTestRowQueue(htmlOptions, 'KO', len(self.UEDevices), html_queue)
-				self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+				self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 
 	def GetAllUEIPAddresses(self):
 		SSH = sshconnection.SSHConnection()
@@ -1397,17 +1456,26 @@ class OaiCiTest():
 				if re.match('OAI-Rel14-Docker', EPC.Type, re.IGNORECASE):
 					launchFromTrfContainer = True
 				if launchFromTrfContainer:
-					ping_status = SSH.command('docker exec -it prod-trf-gen /bin/bash -c "ping ' + self.ping_args + ' ' + UE_IPAddress + '" 2>&1 | tee ping_' + self.testCase_id + '_' + device_id + '.log', '\$', int(ping_time[0])*1.5)
+					ping_status = SSH.command('docker exec -it prod-trf-gen /bin/bash -c "ping ' + self.ping_args + ' ' + UE_IPAddress + '" 2>&1 | tee ping_' + self.testCase_id + '_' + device_id + '.log', '\$', int(ping_time[0])*1.5)				
 				else:
 					ping_status = SSH.command('stdbuf -o0 ping ' + self.ping_args + ' ' + UE_IPAddress + ' 2>&1 | stdbuf -o0 tee ping_' + self.testCase_id + '_' + device_id + '.log', '\$', int(ping_time[0])*1.5)
+				#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', '.')
+
 				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:
@@ -1416,6 +1484,7 @@ class OaiCiTest():
 				SSH.close()
 				self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message)
 				return
+			#search is done on cat result
 			result = re.search(', (?P<packetloss>[0-9\.]+)% packet loss, time [0-9\.]+ms', SSH.getBefore())
 			if result is None:
 				message = 'Packet Loss Not Found!'
@@ -1450,7 +1519,27 @@ class OaiCiTest():
 			logging.debug('\u001B[1;34m    ' + min_msg + '\u001B[0m')
 			logging.debug('\u001B[1;34m    ' + avg_msg + '\u001B[0m')
 			logging.debug('\u001B[1;34m    ' + max_msg + '\u001B[0m')
-			qMsg = pal_msg + '\n' + min_msg + '\n' + avg_msg + '\n' + max_msg
+
+			#adding extra ping stats from local file
+			ping_log_file='ping_' + self.testCase_id + '_' + device_id + '.log'
+			logging.debug('Analyzing Ping log file : ' + os.getcwd() + '/' + ping_log_file)
+			ping_stat=GetPingTimeAnalysis(ping_log_file)
+			ping_stat_msg=''
+			if (ping_stat!=-1) and (len(ping_stat)!=0):
+				ping_stat_msg+='Ping stats before removing largest value : \n'
+				ping_stat_msg+='RTT(Min)    : ' + str("{:.2f}".format(ping_stat['min_0'])) + 'ms \n'
+				ping_stat_msg+='RTT(Mean)   : ' + str("{:.2f}".format(ping_stat['mean_0'])) + 'ms \n'
+				ping_stat_msg+='RTT(Median) : ' + str("{:.2f}".format(ping_stat['median_0'])) + 'ms \n'
+				ping_stat_msg+='RTT(Max)    : ' + str("{:.2f}".format(ping_stat['max_0'])) + 'ms \n'
+				ping_stat_msg+='Max Index   : ' + str(ping_stat['max_loc']) + '\n'
+				ping_stat_msg+='Ping stats after removing largest value : \n'
+				ping_stat_msg+='RTT(Min)    : ' + str("{:.2f}".format(ping_stat['min_1'])) + 'ms \n'
+				ping_stat_msg+='RTT(Mean)   : ' + str("{:.2f}".format(ping_stat['mean_1'])) + 'ms \n'
+				ping_stat_msg+='RTT(Median) : ' + str("{:.2f}".format(ping_stat['median_1'])) + 'ms \n'
+				ping_stat_msg+='RTT(Max)    : ' + str("{:.2f}".format(ping_stat['max_1'])) + 'ms \n'
+
+			#building html message
+			qMsg = pal_msg + '\n' + min_msg + '\n' + avg_msg + '\n' + max_msg + '\n' + ping_stat_msg
 			packetLossOK = True
 			if packetloss is not None:
 				if float(packetloss) > float(self.ping_packetloss_threshold):
@@ -1485,7 +1574,7 @@ class OaiCiTest():
 		pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE,RAN,EPC)
 		if (pStatus < 0):
 			HTML.CreateHtmlTestRow(self.ping_args, 'KO', pStatus)
-			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 			return
 		ping_from_eNB = re.search('oaitun_enb1', str(self.ping_args))
 		if ping_from_eNB is not None:
@@ -1587,12 +1676,12 @@ class OaiCiTest():
 		pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE,RAN,EPC)
 		if (pStatus < 0):
 			HTML.CreateHtmlTestRow(self.ping_args, 'KO', pStatus)
-			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+			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)
+			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 			return
 		multi_jobs = []
 		i = 0
@@ -1610,7 +1699,7 @@ class OaiCiTest():
 
 		if (status_queue.empty()):
 			HTML.CreateHtmlTestRow(self.ping_args, 'KO', CONST.ALL_PROCESSES_OK)
-			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 		else:
 			ping_status = True
 			html_queue = SimpleQueue()
@@ -1627,7 +1716,7 @@ class OaiCiTest():
 				HTML.CreateHtmlTestRowQueue(self.ping_args, 'OK', len(self.UEDevices), html_queue)
 			else:
 				HTML.CreateHtmlTestRowQueue(self.ping_args, 'KO', len(self.UEDevices), html_queue)
-				self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+				self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 
 	def Iperf_ComputeTime(self):
 		result = re.search('-t (?P<iperf_time>\d+)', str(self.iperf_args))
@@ -1934,15 +2023,34 @@ class OaiCiTest():
 			ret = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, encoding='utf-8')
 			if ret.stdout is not None:
 				EPC_Iperf_UE_IPAddress = ret.stdout.strip()
+		# 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):
+			launchFromTrfContainer = True
+			SSH.open(EPC.IPAddress, EPC.UserName, EPC.Password)
+			SSH.command('docker inspect --format="TRF_IP_ADDR = {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}" prod-trf-gen', '\$', 5)
+			result = re.search('TRF_IP_ADDR = (?P<trf_ip_addr>[0-9\.]+)', SSH.getBefore())
+			if result is not None:
+				EPC_Iperf_UE_IPAddress = result.group('trf_ip_addr')
+			SSH.close()
 		port = 5001 + idx
+		udpOptions = ''
+		if udpIperf:
+			udpOptions = '-u '
 		if launchFromEpc:
 			SSH.open(EPC.IPAddress, EPC.UserName, EPC.Password)
 			SSH.command('cd ' + EPC.SourceCodePath + '/scripts', '\$', 5)
 			SSH.command('rm -f iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5)
-			if udpIperf:
-				SSH.command('echo $USER; nohup iperf -u -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', EPC.UserName, 5)
+			if launchFromTrfContainer:
+				if self.ueIperfVersion == self.dummyIperfVersion:
+					prefix = ''
+				else:
+					prefix = ''
+					if self.ueIperfVersion == '2.0.5':
+						prefix = '/iperf-2.0.5/bin/'
+				SSH.command('docker exec -d prod-trf-gen /bin/bash -c "nohup ' + prefix + 'iperf ' + udpOptions + '-s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log &"', '\$', 5)
 			else:
-				SSH.command('echo $USER; nohup iperf -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', EPC.UserName, 5)
+				SSH.command('echo $USER; nohup iperf ' + udpOptions + '-s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', EPC.UserName, 5)
 			SSH.close()
 		else:
 			if self.ueIperfVersion == self.dummyIperfVersion:
@@ -1951,10 +2059,7 @@ class OaiCiTest():
 				prefix = ''
 				if self.ueIperfVersion == '2.0.5':
 					prefix = '/opt/iperf-2.0.5/bin/'
-			if udpIperf:
-				cmd = 'nohup ' + prefix + 'iperf -u -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log 2>&1 &'
-			else:
-				cmd = 'nohup ' + prefix + 'iperf -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log 2>&1 &'
+			cmd = 'nohup ' + prefix + 'iperf ' + udpOptions + '-s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log 2>&1 &'
 			logging.debug(cmd)
 			subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, encoding='utf-8')
 		time.sleep(0.5)
@@ -2000,13 +2105,16 @@ class OaiCiTest():
 		# Kill iperf server on EPC side
 		if launchFromEpc:
 			SSH.open(EPC.IPAddress, EPC.UserName, EPC.Password)
-			SSH.command('killall --signal SIGKILL iperf', EPC.UserName, 5)
+			if launchFromTrfContainer:
+				SSH.command('docker exec -it prod-trf-gen /bin/bash -c "killall --signal SIGKILL iperf"', '\$', 5)
+			else:
+				SSH.command('killall --signal SIGKILL iperf', EPC.UserName, 5)
 			SSH.close()
 		else:
 			cmd = 'killall --signal SIGKILL iperf'
 			logging.debug(cmd)
 			subprocess.run(cmd, shell=True)
-			time.sleep(1)			
+			time.sleep(1)
 			SSH.copyout(EPC.IPAddress, EPC.UserName, EPC.Password, 'iperf_server_' + self.testCase_id + '_' + device_id + '.log', EPC.SourceCodePath + '/scripts')
 		# in case of failure, retrieve server log
 		if (clientStatus == -1) or (clientStatus == -2):
@@ -2014,6 +2122,10 @@ class OaiCiTest():
 				time.sleep(1)
 				if (os.path.isfile('iperf_server_' + self.testCase_id + '_' + device_id + '.log')):
 					os.remove('iperf_server_' + self.testCase_id + '_' + device_id + '.log')
+				if launchFromTrfContainer:
+					SSH.open(EPC.IPAddress, EPC.UserName, EPC.Password)
+					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)
 		# in case of OAI-UE 
@@ -2212,8 +2324,16 @@ class OaiCiTest():
 				else:
 					SSH.copyin(self.ADBIPAddress, self.ADBUserName, self.ADBPassword, EPC.SourceCodePath + '/scripts/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.')
 				# fromdos has to be called on the python executor not on ADB server
-				cmd = 'fromdos -o iperf_server_' + self.testCase_id + '_' + device_id + '.log'
-				subprocess.run(cmd, shell=True)
+				cmd = 'fromdos -o iperf_server_' + self.testCase_id + '_' + device_id + '.log 2>&1 > /dev/null'
+				try:
+					subprocess.run(cmd, shell=True)
+				except:
+					pass
+				cmd = 'dos2unix -o iperf_server_' + self.testCase_id + '_' + device_id + '.log 2>&1 > /dev/null'
+				try:
+					subprocess.run(cmd, shell=True)
+				except:
+					pass
 				self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, modified_options)
 
 			# in case of OAI UE: 
@@ -2237,7 +2357,7 @@ class OaiCiTest():
 		pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE,RAN,EPC)
 		if (pStatus < 0):
 			HTML.CreateHtmlTestRow(self.iperf_args, 'KO', pStatus)
-			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 			return
 		server_on_enb = re.search('-R', str(self.iperf_args))
 		if server_on_enb is not None:
@@ -2335,7 +2455,7 @@ class OaiCiTest():
 			HTML.CreateHtmlTestRowQueue(self.iperf_args, 'OK', len(self.UEDevices), html_queue)
 		else:
 			HTML.CreateHtmlTestRowQueue(self.iperf_args, 'KO', len(self.UEDevices), html_queue)
-			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 
 	def Iperf(self,HTML,RAN,EPC,COTS_UE):
 		result = re.search('noS1', str(RAN.Initialize_eNB_args))
@@ -2353,13 +2473,13 @@ class OaiCiTest():
 		pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE,RAN,EPC)
 		if (pStatus < 0):
 			HTML.CreateHtmlTestRow(self.iperf_args, 'KO', pStatus)
-			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 			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)
+			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 			return
 
 		self.dummyIperfVersion = '2.0.10'
@@ -2390,7 +2510,7 @@ class OaiCiTest():
 
 		if (status_queue.empty()):
 			HTML.CreateHtmlTestRow(self.iperf_args, 'KO', CONST.ALL_PROCESSES_OK)
-			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 		else:
 			iperf_status = True
 			iperf_noperf = False
@@ -2412,7 +2532,7 @@ class OaiCiTest():
 				HTML.CreateHtmlTestRowQueue(self.iperf_args, 'OK', len(self.UEDevices), html_queue)
 			else:
 				HTML.CreateHtmlTestRowQueue(self.iperf_args, 'KO', len(self.UEDevices), html_queue)
-				self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+				self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 
 	def CheckProcessExist(self, check_eNB, check_OAI_UE,RAN,EPC):
 		multi_jobs = []
@@ -2873,11 +2993,11 @@ class OaiCiTest():
 					# Not an error then
 					if (logStatus != CONST.OAI_UE_PROCESS_COULD_NOT_SYNC) or (ueAction != 'Sniffing'):
 						self.Initialize_OAI_UE_args = ''
-						self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+						self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 				else:
 					if (logStatus == CONST.OAI_UE_PROCESS_COULD_NOT_SYNC):
 						self.Initialize_OAI_UE_args = ''
-						self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+						self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 			else:
 				logging.debug('\u001B[1m' + ueAction + ' Completed \u001B[0m')
 				HTML.htmlUEFailureMsg='<b>' + ueAction + ' Completed</b>\n' + HTML.htmlUEFailureMsg
@@ -2886,7 +3006,7 @@ class OaiCiTest():
 		else:
 			HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK)
 
-	def AutoTerminateUEandeNB(self,HTML,RAN,COTS_UE):
+	def AutoTerminateUEandeNB(self,HTML,RAN,COTS_UE,EPC):
 		if (self.ADBIPAddress != 'none'):
 			self.testCase_id = 'AUTO-KILL-UE'
 			HTML.testCase_id=self.testCase_id
@@ -2902,13 +3022,17 @@ class OaiCiTest():
 			self.ShowTestID()
 			self.TerminateOAIUE(HTML,RAN,COTS_UE)
 		if (RAN.Initialize_eNB_args != ''):
-			self.testCase_id = 'AUTO-KILL-eNB'
+			self.testCase_id = 'AUTO-KILL-RAN'
 			HTML.testCase_id=self.testCase_id
-			self.desc = 'Automatic Termination of eNB'
-			HTML.desc='Automatic Termination of eNB'
+			self.desc = 'Automatic Termination of all RAN nodes'
+			HTML.desc='Automatic Termination of RAN nodes'
 			self.ShowTestID()
-			RAN.eNB_instance=0
-			RAN.TerminateeNB()
+			#terminate all RAN nodes eNB/gNB/OCP
+			for instance in range(0, len(RAN.air_interface)):
+				if RAN.air_interface[instance]!='':
+					logging.debug('Auto Termination of Instance ' + str(instance) + ' : ' + RAN.air_interface[instance])
+					RAN.eNB_instance=instance
+					RAN.TerminateeNB(HTML,EPC)
 		if RAN.flexranCtrlInstalled and RAN.flexranCtrlStarted:
 			self.testCase_id = 'AUTO-KILL-flexran-ctl'
 			HTML.testCase_id=self.testCase_id
@@ -3050,7 +3174,7 @@ class OaiCiTest():
 		SSH.command('cd ' + SourceCodePath, '\$', 5)
 		SSH.command('cd cmake_targets', '\$', 5)
 		SSH.command('rm -f build.log.zip', '\$', 5)
-		SSH.command('zip build.log.zip build_log_*/*', '\$', 60)
+		SSH.command('zip -r build.log.zip build_log_*/*', '\$', 60)
 		SSH.close()
 
 	def LogCollectPing(self,EPC):
diff --git a/ci-scripts/conf_files/cu.band7.tm1.100PRB.conf b/ci-scripts/conf_files/cu.band7.tm1.100PRB.conf
index 42cade271c0da45f4a067ec5d9ce5a7c7f1a2e0e..e2c94b14ab176b9273373f7631ae3ac188a547c4 100644
--- a/ci-scripts/conf_files/cu.band7.tm1.100PRB.conf
+++ b/ci-scripts/conf_files/cu.band7.tm1.100PRB.conf
@@ -215,7 +215,7 @@ log_config = {
 NETWORK_CONTROLLER : {
   FLEXRAN_ENABLED        = "no";
   FLEXRAN_INTERFACE_NAME = "lo";
-  FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+  FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
   FLEXRAN_PORT           = 2210;
   FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
   FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/cu.band7.tm1.25PRB.conf b/ci-scripts/conf_files/cu.band7.tm1.25PRB.conf
index 51f727726709dd95cb0ce01d15fa6136a8034f6e..5b994ed29b15cb99f374d7b11fb5e2fc20cc7ab4 100644
--- a/ci-scripts/conf_files/cu.band7.tm1.25PRB.conf
+++ b/ci-scripts/conf_files/cu.band7.tm1.25PRB.conf
@@ -215,7 +215,7 @@ log_config = {
 NETWORK_CONTROLLER : {
   FLEXRAN_ENABLED        = "no";
   FLEXRAN_INTERFACE_NAME = "lo";
-  FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+  FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
   FLEXRAN_PORT           = 2210;
   FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
   FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/cu.band7.tm1.50PRB.conf b/ci-scripts/conf_files/cu.band7.tm1.50PRB.conf
index 9946713c3adb89dd2f63a7c59af337af7e3cac73..148c5a9903f2e435cf17bd884c0234ca6be686e0 100644
--- a/ci-scripts/conf_files/cu.band7.tm1.50PRB.conf
+++ b/ci-scripts/conf_files/cu.band7.tm1.50PRB.conf
@@ -215,7 +215,7 @@ log_config = {
 NETWORK_CONTROLLER : {
   FLEXRAN_ENABLED        = "no";
   FLEXRAN_INTERFACE_NAME = "lo";
-  FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+  FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
   FLEXRAN_PORT           = 2210;
   FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
   FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/du.band7.tm1.100PRB.usrpb210.conf b/ci-scripts/conf_files/du.band7.tm1.100PRB.usrpb210.conf
index 7167bffa6d1724d9cd48a42306b9281ade3d30fb..a3ecffb9be7b349cfe35a940483bbf558c0b1856 100644
--- a/ci-scripts/conf_files/du.band7.tm1.100PRB.usrpb210.conf
+++ b/ci-scripts/conf_files/du.band7.tm1.100PRB.usrpb210.conf
@@ -112,7 +112,7 @@ log_config = {
 NETWORK_CONTROLLER : {
   FLEXRAN_ENABLED        = "no";
   FLEXRAN_INTERFACE_NAME = "lo";
-  FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+  FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
   FLEXRAN_PORT           = 2210;
   FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
   FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/du.band7.tm1.25PRB.usrpb210.conf b/ci-scripts/conf_files/du.band7.tm1.25PRB.usrpb210.conf
index 3c951a2a6e908e591b31911802bdd856cbaf438c..1920992d70c608a764529c747e3115e274e970ac 100644
--- a/ci-scripts/conf_files/du.band7.tm1.25PRB.usrpb210.conf
+++ b/ci-scripts/conf_files/du.band7.tm1.25PRB.usrpb210.conf
@@ -112,7 +112,7 @@ log_config = {
 NETWORK_CONTROLLER : {
   FLEXRAN_ENABLED        = "no";
   FLEXRAN_INTERFACE_NAME = "lo";
-  FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+  FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
   FLEXRAN_PORT           = 2210;
   FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
   FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/du.band7.tm1.50PRB.usrpb210.conf b/ci-scripts/conf_files/du.band7.tm1.50PRB.usrpb210.conf
index 4726269312cbbead4fdb7a3e15d46bc853d39447..5df8da05a3aeca11bb4c9c4148f0b00b1bbb0c38 100644
--- a/ci-scripts/conf_files/du.band7.tm1.50PRB.usrpb210.conf
+++ b/ci-scripts/conf_files/du.band7.tm1.50PRB.usrpb210.conf
@@ -112,7 +112,7 @@ log_config = {
 NETWORK_CONTROLLER : {
   FLEXRAN_ENABLED        = "no";
   FLEXRAN_INTERFACE_NAME = "lo";
-  FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+  FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
   FLEXRAN_PORT           = 2210;
   FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
   FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/enb.band13.tm1.25PRB.usrpb210.conf b/ci-scripts/conf_files/enb.band13.tm1.25PRB.usrpb210.conf
index 0c247e9ef9a39e181291b9d371043b052cfc9aa2..e70ca782050be7e67afa529540d178608a7b523b 100644
--- a/ci-scripts/conf_files/enb.band13.tm1.25PRB.usrpb210.conf
+++ b/ci-scripts/conf_files/enb.band13.tm1.25PRB.usrpb210.conf
@@ -239,7 +239,7 @@ NETWORK_CONTROLLER :
 {
     FLEXRAN_ENABLED        = "no";
     FLEXRAN_INTERFACE_NAME = "eth0";
-    FLEXRAN_IPV4_ADDRESS   = "CI_MME_IP_ADDR";
+    FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
     FLEXRAN_PORT           = 2210;
     FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
     FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/enb.band13.tm1.50PRB.emtc.conf b/ci-scripts/conf_files/enb.band13.tm1.50PRB.emtc.conf
index f560958e152ca2a8c3505cfb48bc54872f64a80c..400d1a6c9d8099fbf1beb09ac4c2cce18a61286b 100644
--- a/ci-scripts/conf_files/enb.band13.tm1.50PRB.emtc.conf
+++ b/ci-scripts/conf_files/enb.band13.tm1.50PRB.emtc.conf
@@ -448,7 +448,7 @@ NETWORK_CONTROLLER :
 {
     FLEXRAN_ENABLED        = "no";
     FLEXRAN_INTERFACE_NAME = "lo";
-    FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+    FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
     FLEXRAN_PORT           = 2210;
     FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
     FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/enb.band17.tm1.25PRB.usrpb210.conf b/ci-scripts/conf_files/enb.band17.tm1.25PRB.usrpb210.conf
index ba81f832db38f6da06e99dc7d15a01b41af0a50a..bd2999b5d549037804d4f6f16d1de2aa0129adcd 100644
--- a/ci-scripts/conf_files/enb.band17.tm1.25PRB.usrpb210.conf
+++ b/ci-scripts/conf_files/enb.band17.tm1.25PRB.usrpb210.conf
@@ -251,7 +251,7 @@ NETWORK_CONTROLLER :
 {
     FLEXRAN_ENABLED        = "no";
     FLEXRAN_INTERFACE_NAME = "eth0";
-    FLEXRAN_IPV4_ADDRESS   = "CI_MME_IP_ADDR";
+    FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
     FLEXRAN_PORT           = 2210;
     FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
     FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/enb.band17.tm1.mbms.25PRB.usrpb210.conf b/ci-scripts/conf_files/enb.band17.tm1.mbms.25PRB.usrpb210.conf
index 79bbd7ee6f3e8dc800693b5fba603324d751ffe7..19ef6d07972c60cfece101229bd8d5436e51da74 100644
--- a/ci-scripts/conf_files/enb.band17.tm1.mbms.25PRB.usrpb210.conf
+++ b/ci-scripts/conf_files/enb.band17.tm1.mbms.25PRB.usrpb210.conf
@@ -395,7 +395,7 @@ NETWORK_CONTROLLER :
 {
     FLEXRAN_ENABLED        = "no";
     FLEXRAN_INTERFACE_NAME = "eth0";
-    FLEXRAN_IPV4_ADDRESS   = "CI_MME_IP_ADDR";
+    FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
     FLEXRAN_PORT           = 2210;
     FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
     FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/enb.band40.tm1.100PRB.FairScheduler.usrpb210.conf b/ci-scripts/conf_files/enb.band40.tm1.100PRB.FairScheduler.usrpb210.conf
index b5fd1255bbb8c57384532e919c39240d18620ee2..f34878c5691efa7def3f353cbb7922b6a98e8feb 100644
--- a/ci-scripts/conf_files/enb.band40.tm1.100PRB.FairScheduler.usrpb210.conf
+++ b/ci-scripts/conf_files/enb.band40.tm1.100PRB.FairScheduler.usrpb210.conf
@@ -228,7 +228,7 @@ NETWORK_CONTROLLER :
 {
     FLEXRAN_ENABLED        = "no";
     FLEXRAN_INTERFACE_NAME = "lo";
-    FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+    FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
     FLEXRAN_PORT           = 2210;
     FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
     FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/enb.band40.tm1.25PRB.FairScheduler.usrpb210.conf b/ci-scripts/conf_files/enb.band40.tm1.25PRB.FairScheduler.usrpb210.conf
index 552dfd637b9388a0fb4a58436c3e9e63a292a7bc..e2e482a7c7d98496635bb6d2f2f89b71237d0bfc 100644
--- a/ci-scripts/conf_files/enb.band40.tm1.25PRB.FairScheduler.usrpb210.conf
+++ b/ci-scripts/conf_files/enb.band40.tm1.25PRB.FairScheduler.usrpb210.conf
@@ -228,7 +228,7 @@ NETWORK_CONTROLLER :
 {
     FLEXRAN_ENABLED        = "no";
     FLEXRAN_INTERFACE_NAME = "lo";
-    FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+    FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
     FLEXRAN_PORT           = 2210;
     FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
     FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/enb.band40.tm1.50PRB.FairScheduler.usrpb210.conf b/ci-scripts/conf_files/enb.band40.tm1.50PRB.FairScheduler.usrpb210.conf
index d95d2b6ac1ac4ffb69880599312164a2bae15f3b..bfea139e92147d58a8b44e2803e899072ff3121f 100644
--- a/ci-scripts/conf_files/enb.band40.tm1.50PRB.FairScheduler.usrpb210.conf
+++ b/ci-scripts/conf_files/enb.band40.tm1.50PRB.FairScheduler.usrpb210.conf
@@ -228,7 +228,7 @@ NETWORK_CONTROLLER :
 {
     FLEXRAN_ENABLED        = "no";
     FLEXRAN_INTERFACE_NAME = "lo";
-    FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+    FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
     FLEXRAN_PORT           = 2210;
     FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
     FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/enb.band40.tm2.25PRB.FairScheduler.usrpb210.conf b/ci-scripts/conf_files/enb.band40.tm2.25PRB.FairScheduler.usrpb210.conf
index e466a23ab0b2aa47b5a4939e33ed66f6805e1dcc..4e0025770b4a645805b9ff17f0b6eccfcf11a777 100644
--- a/ci-scripts/conf_files/enb.band40.tm2.25PRB.FairScheduler.usrpb210.conf
+++ b/ci-scripts/conf_files/enb.band40.tm2.25PRB.FairScheduler.usrpb210.conf
@@ -226,7 +226,7 @@ NETWORK_CONTROLLER :
 {
     FLEXRAN_ENABLED        = "no";
     FLEXRAN_INTERFACE_NAME = "lo";
-    FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+    FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
     FLEXRAN_PORT           = 2210;
     FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
     FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/enb.band7.tm1.100PRB.usrpb210.conf b/ci-scripts/conf_files/enb.band7.tm1.100PRB.usrpb210.conf
index e3cdb033c93976a1dbff96a27687e1d3b87a847f..1627d21e1aefba2c49c003ef85f6c20994ec37b9 100644
--- a/ci-scripts/conf_files/enb.band7.tm1.100PRB.usrpb210.conf
+++ b/ci-scripts/conf_files/enb.band7.tm1.100PRB.usrpb210.conf
@@ -247,7 +247,7 @@ NETWORK_CONTROLLER :
 {
     FLEXRAN_ENABLED        = "no";
     FLEXRAN_INTERFACE_NAME = "lo";
-    FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+    FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
     FLEXRAN_PORT           = 2210;
     FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
     FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/enb.band7.tm1.25PRB.slave.usrpb210.conf b/ci-scripts/conf_files/enb.band7.tm1.25PRB.slave.usrpb210.conf
index f95530b251ef009e4a55923b507c860ece8c72dd..efa1fa64b8004325aea95792c11c3f82635a075b 100644
--- a/ci-scripts/conf_files/enb.band7.tm1.25PRB.slave.usrpb210.conf
+++ b/ci-scripts/conf_files/enb.band7.tm1.25PRB.slave.usrpb210.conf
@@ -256,7 +256,7 @@ NETWORK_CONTROLLER :
 {
     FLEXRAN_ENABLED        = "no";
     FLEXRAN_INTERFACE_NAME = "eth0";
-    FLEXRAN_IPV4_ADDRESS   = "CI_MME_IP_ADDR";
+    FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
     FLEXRAN_PORT           = 2210;
     FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
     FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/enb.band7.tm1.25PRB.usrpb210.conf b/ci-scripts/conf_files/enb.band7.tm1.25PRB.usrpb210.conf
index eddb34a5791dabc06b0404485ab459e36e14916b..f29fc163b3d0459df1e633c397f3b67fb0711575 100644
--- a/ci-scripts/conf_files/enb.band7.tm1.25PRB.usrpb210.conf
+++ b/ci-scripts/conf_files/enb.band7.tm1.25PRB.usrpb210.conf
@@ -28,83 +28,85 @@ eNBs =
       node_function             = "3GPP_eNODEB";
       node_timing               = "synch_to_ext_device";
       node_synch_ref            = 0;
-      frame_type					      = "FDD";
-      tdd_config 					      = 3;
-      tdd_config_s            			      = 0;
-      prefix_type             			      = "NORMAL";
-      eutra_band              			      = 7;
-      downlink_frequency      			      = 2680000000L;
-      uplink_frequency_offset 			      = -120000000;
-      Nid_cell					      = 0;
-      N_RB_DL                 			      = 25;
-      Nid_cell_mbsfn          			      = 0;
-      nb_antenna_ports                                = 1;
-      nb_antennas_tx          			      = 1;
-      nb_antennas_rx          			      = 1;
-      tx_gain                                            = 90;
-      rx_gain                                            = 125;
-      pbch_repetition                                 = "FALSE";
-      prach_root              			      = 0;
-      prach_config_index      			      = 0;
-      prach_high_speed        			      = "DISABLE";
-      prach_zero_correlation  			      = 1;
-      prach_freq_offset       			      = 2;
-      pucch_delta_shift       			      = 1;
-      pucch_nRB_CQI           			      = 0;
-      pucch_nCS_AN            			      = 0;
-      pucch_n1_AN             			      = 0;
-      pdsch_referenceSignalPower 			      = -25;
-      pdsch_p_b                  			      = 0;
-      pusch_n_SB                 			      = 1;
-      pusch_enable64QAM          			      = "DISABLE";
-      pusch_hoppingMode                                  = "interSubFrame";
-      pusch_hoppingOffset                                = 0;
-      pusch_groupHoppingEnabled  			      = "ENABLE";
-      pusch_groupAssignment      			      = 0;
-      pusch_sequenceHoppingEnabled		   	      = "DISABLE";
-      pusch_nDMRS1                                       = 1;
-      phich_duration                                     = "NORMAL";
-      phich_resource                                     = "ONESIXTH";
-      srs_enable                                         = "DISABLE";
-      /*  srs_BandwidthConfig                                =;
-      srs_SubframeConfig                                 =;
-      srs_ackNackST                                      =;
-      srs_MaxUpPts                                       =;*/
-
-      pusch_p0_Nominal                                   = -96;
-      pusch_alpha                                        = "AL1";
-      pucch_p0_Nominal                                   = -104;
-      msg3_delta_Preamble                                = 6;
-      pucch_deltaF_Format1                               = "deltaF2";
-      pucch_deltaF_Format1b                              = "deltaF3";
-      pucch_deltaF_Format2                               = "deltaF0";
-      pucch_deltaF_Format2a                              = "deltaF0";
-      pucch_deltaF_Format2b		    	      = "deltaF0";
-
-      rach_numberOfRA_Preambles                          = 64;
-      rach_preamblesGroupAConfig                         = "DISABLE";
+      frame_type                = "FDD";
+      tdd_config                = 3;
+      tdd_config_s              = 0;
+      prefix_type               = "NORMAL";
+      eutra_band                = 7;
+      downlink_frequency        = 2680000000L;
+      uplink_frequency_offset   = -120000000;
+      Nid_cell                  = 0;
+      N_RB_DL                   = 25;
+      Nid_cell_mbsfn            = 0;
+      nb_antenna_ports          = 1;
+      nb_antennas_tx            = 1;
+      nb_antennas_rx            = 1;
+      tx_gain                   = 90;
+      rx_gain                   = 125;
+      pbch_repetition           = "FALSE";
+      prach_root                = 0;
+      prach_config_index        = 0;
+      prach_high_speed          = "DISABLE";
+      prach_zero_correlation    = 1;
+      prach_freq_offset         = 2;
+      pucch_delta_shift         = 1;
+      pucch_nRB_CQI             = 0;
+      pucch_nCS_AN              = 0;
+      pucch_n1_AN               = 0;
+      pdsch_referenceSignalPower= -25;
+      pdsch_p_b                 = 0;
+      pusch_n_SB                = 1;
+      pusch_enable64QAM         = "DISABLE";
+      pusch_hoppingMode         = "interSubFrame";
+      pusch_hoppingOffset       = 0;
+      pusch_groupHoppingEnabled = "ENABLE";
+      pusch_groupAssignment     = 0;
+      pusch_sequenceHoppingEnabled = "DISABLE";
+      pusch_nDMRS1              = 1;
+      phich_duration            = "NORMAL";
+      phich_resource            = "ONESIXTH";
+      srs_enable                = "DISABLE";
       /*
-      rach_sizeOfRA_PreamblesGroupA                      = ;
-      rach_messageSizeGroupA                             = ;
-      rach_messagePowerOffsetGroupB                      = ;
+      srs_BandwidthConfig       =;
+      srs_SubframeConfig        =;
+      srs_ackNackST             =;
+      srs_MaxUpPts              =;
       */
-      rach_powerRampingStep                              = 4;
-      rach_preambleInitialReceivedTargetPower            = -108;
-      rach_preambleTransMax                              = 10;
-      rach_raResponseWindowSize                          = 10;
-      rach_macContentionResolutionTimer                  = 48;
-      rach_maxHARQ_Msg3Tx                                = 4;
-
-      pcch_default_PagingCycle                           = 128;
-      pcch_nB                                            = "oneT";
-      bcch_modificationPeriodCoeff			      = 2;
-      ue_TimersAndConstants_t300			      = 1000;
-      ue_TimersAndConstants_t301			      = 1000;
-      ue_TimersAndConstants_t310			      = 1000;
-      ue_TimersAndConstants_t311			      = 10000;
-      ue_TimersAndConstants_n310			      = 20;
-      ue_TimersAndConstants_n311			      = 1;
-      ue_TransmissionMode                                    = 1;
+
+      pusch_p0_Nominal          = -96;
+      pusch_alpha               = "AL1";
+      pucch_p0_Nominal          = -104;
+      msg3_delta_Preamble       = 6;
+      pucch_deltaF_Format1      = "deltaF2";
+      pucch_deltaF_Format1b     = "deltaF3";
+      pucch_deltaF_Format2      = "deltaF0";
+      pucch_deltaF_Format2a     = "deltaF0";
+      pucch_deltaF_Format2b     = "deltaF0";
+
+      rach_numberOfRA_Preambles                = 64;
+      rach_preamblesGroupAConfig               = "DISABLE";
+      /*
+      rach_sizeOfRA_PreamblesGroupA            = ;
+      rach_messageSizeGroupA                   = ;
+      rach_messagePowerOffsetGroupB            = ;
+      */
+      rach_powerRampingStep                    = 4;
+      rach_preambleInitialReceivedTargetPower  = -108;
+      rach_preambleTransMax                    = 10;
+      rach_raResponseWindowSize                = 10;
+      rach_macContentionResolutionTimer        = 48;
+      rach_maxHARQ_Msg3Tx                      = 4;
+
+      pcch_default_PagingCycle                 = 128;
+      pcch_nB                                  = "oneT";
+      bcch_modificationPeriodCoeff             = 2;
+      ue_TimersAndConstants_t300               = 1000;
+      ue_TimersAndConstants_t301               = 1000;
+      ue_TimersAndConstants_t310               = 1000;
+      ue_TimersAndConstants_t311               = 10000;
+      ue_TimersAndConstants_n310               = 20;
+      ue_TimersAndConstants_n311               = 1;
+      ue_TransmissionMode                      = 1;
 
       //Parameters for SIB18
       rxPool_sc_CP_Len                                       = "normal";
@@ -116,27 +118,28 @@ eNBs =
       rxPool_ResourceConfig_offsetIndicator_present          = "prSmall";
       rxPool_ResourceConfig_offsetIndicator_choice           = 0;
       rxPool_ResourceConfig_subframeBitmap_present           = "prBs40";
-      rxPool_ResourceConfig_subframeBitmap_choice_bs_buf              = "00000000000000000000";
-      rxPool_ResourceConfig_subframeBitmap_choice_bs_size             = 5;
-      rxPool_ResourceConfig_subframeBitmap_choice_bs_bits_unused      = 0;
-/*    rxPool_dataHoppingConfig_hoppingParameter                       = 0;
-      rxPool_dataHoppingConfig_numSubbands                            = "ns1";
-      rxPool_dataHoppingConfig_rbOffset                               = 0;
-      rxPool_commTxResourceUC-ReqAllowed                              = "TRUE";
+      rxPool_ResourceConfig_subframeBitmap_choice_bs_buf     = "00000000000000000000";
+      rxPool_ResourceConfig_subframeBitmap_choice_bs_size    = 5;
+      rxPool_ResourceConfig_subframeBitmap_choice_bs_bits_unused = 0;
+/*
+      rxPool_dataHoppingConfig_hoppingParameter              = 0;
+      rxPool_dataHoppingConfig_numSubbands                   = "ns1";
+      rxPool_dataHoppingConfig_rbOffset                      = 0;
+      rxPool_commTxResourceUC-ReqAllowed                     = "TRUE";
 */
       // Parameters for SIB19
-      discRxPool_cp_Len                                               = "normal"
-      discRxPool_discPeriod                                           = "rf32"
-      discRxPool_numRetx                                              = 1;
-      discRxPool_numRepetition                                        = 2;
-      discRxPool_ResourceConfig_prb_Num                               = 5;
-      discRxPool_ResourceConfig_prb_Start                             = 3;
-      discRxPool_ResourceConfig_prb_End                               = 21;
-      discRxPool_ResourceConfig_offsetIndicator_present               = "prSmall";
-      discRxPool_ResourceConfig_offsetIndicator_choice                = 0;
-      discRxPool_ResourceConfig_subframeBitmap_present                = "prBs40";
-      discRxPool_ResourceConfig_subframeBitmap_choice_bs_buf          = "f0ffffffff";
-      discRxPool_ResourceConfig_subframeBitmap_choice_bs_size         = 5;
+      discRxPool_cp_Len                                      = "normal"
+      discRxPool_discPeriod                                  = "rf32"
+      discRxPool_numRetx                                     = 1;
+      discRxPool_numRepetition                               = 2;
+      discRxPool_ResourceConfig_prb_Num                      = 5;
+      discRxPool_ResourceConfig_prb_Start                    = 3;
+      discRxPool_ResourceConfig_prb_End                      = 21;
+      discRxPool_ResourceConfig_offsetIndicator_present      = "prSmall";
+      discRxPool_ResourceConfig_offsetIndicator_choice       = 0;
+      discRxPool_ResourceConfig_subframeBitmap_present       = "prBs40";
+      discRxPool_ResourceConfig_subframeBitmap_choice_bs_buf = "f0ffffffff";
+      discRxPool_ResourceConfig_subframeBitmap_choice_bs_size= 5;
       discRxPool_ResourceConfig_subframeBitmap_choice_bs_bits_unused  = 0;
 
       }
@@ -204,40 +207,43 @@ eNBs =
   }
 );
 
-MACRLCs = (
-	{
-	num_cc = 1;
-	tr_s_preference = "local_L1";
-	tr_n_preference = "local_RRC";
-	phy_test_mode = 0;
-        puSch10xSnr     =  160;
-        puCch10xSnr     =  160;
-        }  
+MACRLCs =
+(
+  {
+    num_cc          = 1;
+    tr_s_preference = "local_L1";
+    tr_n_preference = "local_RRC";
+    phy_test_mode   = 0;
+    puSch10xSnr     =  160;
+    puCch10xSnr     =  160;
+  }  
 );
 
-L1s = (
-    	{
-	num_cc = 1;
-	tr_n_preference = "local_mac";
-        }  
+L1s =
+(
+  {
+    num_cc = 1;
+    tr_n_preference = "local_mac";
+  }  
 );
 
-RUs = (
-    {		  
-       local_rf       = "yes"
-         nb_tx          = 1
-         nb_rx          = 1
-         att_tx         = 0
-         att_rx         = 0;
-         bands          = [7];
-         max_pdschReferenceSignalPower = -27;
-         max_rxgain                    = 125;
-         eNB_instances  = [0];
-
-    }
+RUs =
+(
+  {
+    local_rf                      = "yes"
+    nb_tx                         = 1
+    nb_rx                         = 1
+    att_tx                        = 0
+    att_rx                        = 0;
+    bands                         = [7];
+    max_pdschReferenceSignalPower = -27;
+    max_rxgain                    = 125;
+    eNB_instances                 = [0];
+  }
 );  
 
-THREAD_STRUCT = (
+THREAD_STRUCT =
+(
   {
     #three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT"
     parallel_config    = "PARALLEL_SINGLE_THREAD";
@@ -250,27 +256,27 @@ NETWORK_CONTROLLER :
 {
     FLEXRAN_ENABLED        = "no";
     FLEXRAN_INTERFACE_NAME = "eth0";
-    FLEXRAN_IPV4_ADDRESS   = "CI_MME_IP_ADDR";
+    FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
     FLEXRAN_PORT           = 2210;
     FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
     FLEXRAN_AWAIT_RECONF   = "no";
 };
 
-     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";
-    };
+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";
+};
 
diff --git a/ci-scripts/conf_files/enb.band7.tm1.50PRB.usrpb210.conf b/ci-scripts/conf_files/enb.band7.tm1.50PRB.usrpb210.conf
index b5d7f35a76e9218390cbe650a79e252e928a006a..4d89ad96daa3708d0e67b8bb12ca163870f472f1 100644
--- a/ci-scripts/conf_files/enb.band7.tm1.50PRB.usrpb210.conf
+++ b/ci-scripts/conf_files/enb.band7.tm1.50PRB.usrpb210.conf
@@ -255,7 +255,7 @@ NETWORK_CONTROLLER :
 {
     FLEXRAN_ENABLED        = "no";
     FLEXRAN_INTERFACE_NAME = "lo";
-    FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+    FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
     FLEXRAN_PORT           = 2210;
     FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
     FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/enb.band7.tm1.fr1.25PRB.usrpb210.conf b/ci-scripts/conf_files/enb.band7.tm1.fr1.25PRB.usrpb210.conf
old mode 100755
new mode 100644
diff --git a/ci-scripts/conf_files/enb.band7.tm2.25PRB.usrpb210.conf b/ci-scripts/conf_files/enb.band7.tm2.25PRB.usrpb210.conf
index 67cc5706aec87266a8406e2332d7c37fe06d39de..72754165d06319d5e38dec4eecafd0ee933d2b5a 100644
--- a/ci-scripts/conf_files/enb.band7.tm2.25PRB.usrpb210.conf
+++ b/ci-scripts/conf_files/enb.band7.tm2.25PRB.usrpb210.conf
@@ -249,7 +249,7 @@ NETWORK_CONTROLLER :
 {
     FLEXRAN_ENABLED        = "no";
     FLEXRAN_INTERFACE_NAME = "lo";
-    FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+    FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
     FLEXRAN_PORT           = 2210;
     FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
     FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/enb.slave.band13.tm1.25PRB.usrpb210.conf b/ci-scripts/conf_files/enb.slave.band13.tm1.25PRB.usrpb210.conf
index 1b5376644b67e82bf7ff7bd33843f5b2d2251c24..da65aad775e4154d95f8ff2ea9c7d571c556d89e 100644
--- a/ci-scripts/conf_files/enb.slave.band13.tm1.25PRB.usrpb210.conf
+++ b/ci-scripts/conf_files/enb.slave.band13.tm1.25PRB.usrpb210.conf
@@ -244,7 +244,7 @@ NETWORK_CONTROLLER :
 {
     FLEXRAN_ENABLED        = "no";
     FLEXRAN_INTERFACE_NAME = "eth0";
-    FLEXRAN_IPV4_ADDRESS   = "CI_MME_IP_ADDR";
+    FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
     FLEXRAN_PORT           = 2210;
     FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
     FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpb210.conf b/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpb210.conf
old mode 100755
new mode 100644
diff --git a/ci-scripts/conf_files/rcc.band40.tm1.100PRB.FairScheduler.usrpb210.conf b/ci-scripts/conf_files/rcc.band40.tm1.100PRB.FairScheduler.usrpb210.conf
index 2bf79a3d7e027d9257c608901b66b2b890751a19..d01e4e1c4e039ba4e77888b8b29537b9798c16a0 100644
--- a/ci-scripts/conf_files/rcc.band40.tm1.100PRB.FairScheduler.usrpb210.conf
+++ b/ci-scripts/conf_files/rcc.band40.tm1.100PRB.FairScheduler.usrpb210.conf
@@ -235,7 +235,7 @@ NETWORK_CONTROLLER :
 {
     FLEXRAN_ENABLED        = "no";
     FLEXRAN_INTERFACE_NAME = "lo";
-    FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+    FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
     FLEXRAN_PORT           = 2210;
     FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
     FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/rcc.band40.tm1.25PRB.FairScheduler.usrpb210.conf b/ci-scripts/conf_files/rcc.band40.tm1.25PRB.FairScheduler.usrpb210.conf
index 6b0e7de659006601a6e6486fc3bff11a91485bb5..419598647b123e8d151037127fea63f3fbc6393e 100644
--- a/ci-scripts/conf_files/rcc.band40.tm1.25PRB.FairScheduler.usrpb210.conf
+++ b/ci-scripts/conf_files/rcc.band40.tm1.25PRB.FairScheduler.usrpb210.conf
@@ -235,7 +235,7 @@ NETWORK_CONTROLLER :
 {
     FLEXRAN_ENABLED        = "no";
     FLEXRAN_INTERFACE_NAME = "lo";
-    FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+    FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
     FLEXRAN_PORT           = 2210;
     FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
     FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/rcc.band40.tm1.50PRB.FairScheduler.usrpb210.conf b/ci-scripts/conf_files/rcc.band40.tm1.50PRB.FairScheduler.usrpb210.conf
index 6b41d785066a73ec7dae03af05f65401980ad43f..d4f2eb9ef2f46def7cb4e273ee1f8ce9e303e6e2 100644
--- a/ci-scripts/conf_files/rcc.band40.tm1.50PRB.FairScheduler.usrpb210.conf
+++ b/ci-scripts/conf_files/rcc.band40.tm1.50PRB.FairScheduler.usrpb210.conf
@@ -235,7 +235,7 @@ NETWORK_CONTROLLER :
 {
     FLEXRAN_ENABLED        = "no";
     FLEXRAN_INTERFACE_NAME = "lo";
-    FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+    FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
     FLEXRAN_PORT           = 2210;
     FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
     FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/rcc.band7.tm1.if4p5.lo.100PRB.usrpb210.conf b/ci-scripts/conf_files/rcc.band7.tm1.if4p5.lo.100PRB.usrpb210.conf
index 5df8f16f78e137858c3d2847951210fbefe05bae..683fff0bc800106c28dd84f51c6df3a5d7036d07 100644
--- a/ci-scripts/conf_files/rcc.band7.tm1.if4p5.lo.100PRB.usrpb210.conf
+++ b/ci-scripts/conf_files/rcc.band7.tm1.if4p5.lo.100PRB.usrpb210.conf
@@ -254,7 +254,7 @@ NETWORK_CONTROLLER :
 {
     FLEXRAN_ENABLED        = "no";
     FLEXRAN_INTERFACE_NAME = "lo";
-    FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+    FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
     FLEXRAN_PORT           = 2210;
     FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
     FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/rcc.band7.tm1.if4p5.lo.25PRB.usrpb210.conf b/ci-scripts/conf_files/rcc.band7.tm1.if4p5.lo.25PRB.usrpb210.conf
index ad753bb11408f1f9d9122bdd13a0cd5990172c66..2c3c11b84f287cc237922114166ecf9809863331 100644
--- a/ci-scripts/conf_files/rcc.band7.tm1.if4p5.lo.25PRB.usrpb210.conf
+++ b/ci-scripts/conf_files/rcc.band7.tm1.if4p5.lo.25PRB.usrpb210.conf
@@ -254,7 +254,7 @@ NETWORK_CONTROLLER :
 {
     FLEXRAN_ENABLED        = "no";
     FLEXRAN_INTERFACE_NAME = "lo";
-    FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+    FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
     FLEXRAN_PORT           = 2210;
     FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
     FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/rcc.band7.tm1.if4p5.lo.50PRB.usrpb210.conf b/ci-scripts/conf_files/rcc.band7.tm1.if4p5.lo.50PRB.usrpb210.conf
index dbe3aff3dcc5cc283cbcdc03fecb926bed9a2f2f..49365a1f616e58a44e7641c68b2a4d153fab9664 100644
--- a/ci-scripts/conf_files/rcc.band7.tm1.if4p5.lo.50PRB.usrpb210.conf
+++ b/ci-scripts/conf_files/rcc.band7.tm1.if4p5.lo.50PRB.usrpb210.conf
@@ -254,7 +254,7 @@ NETWORK_CONTROLLER :
 {
     FLEXRAN_ENABLED        = "no";
     FLEXRAN_INTERFACE_NAME = "lo";
-    FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+    FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
     FLEXRAN_PORT           = 2210;
     FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
     FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/rru.fdd.band7.conf b/ci-scripts/conf_files/rru.fdd.band7.conf
index ea923ae3718a6a61ed08481d16e1f91df8f1db5b..057f518046573be0b8de1bfc15096792bbe38964 100644
--- a/ci-scripts/conf_files/rru.fdd.band7.conf
+++ b/ci-scripts/conf_files/rru.fdd.band7.conf
@@ -1,23 +1,25 @@
-RUs = (
-    {
-        local_if_name                    = "lo";
-        remote_address                   = "127.0.0.1"
-        local_address                    = "127.0.0.2";
-        local_portc                       = 50000;
-        remote_portc                      = 50000;
-        local_portd                       = 50001;
-        remote_portd                      = 50001;
-        local_rf                         = "yes"
-        tr_preference                    = "udp_if4p5";
-        nb_tx                            = 1;
-        nb_rx                            = 1;
-        max_pdschReferenceSignalPower    = -27;
-        max_rxgain                       = 115;
-        bands                            = [7];
-    }
+RUs =
+(
+  {
+    local_if_name                 = "lo";
+    remote_address                = "127.0.0.1"
+    local_address                 = "127.0.0.2";
+    local_portc                   = 50000;
+    remote_portc                  = 50000;
+    local_portd                   = 50001;
+    remote_portd                  = 50001;
+    local_rf                      = "yes"
+    tr_preference                 = "udp_if4p5";
+    nb_tx                         = 1;
+    nb_rx                         = 1;
+    max_pdschReferenceSignalPower = -27;
+    max_rxgain                    = 115;
+    bands                         = [7];
+  }
 );
 
-THREAD_STRUCT = (
+THREAD_STRUCT =
+(
   {
     #three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT"
     parallel_config    = "PARALLEL_SINGLE_THREAD";
@@ -26,19 +28,20 @@ THREAD_STRUCT = (
   }
 );
 
-log_config = {
-      global_log_level                      ="error";
-      global_log_verbosity                  ="medium";
-      hw_log_level                          ="error";
-      hw_log_verbosity                      ="medium";
-      phy_log_level                         ="error";
-      phy_log_verbosity                     ="medium";
-      mac_log_level                         ="error";
-      mac_log_verbosity                     ="high";
-      rlc_log_level                         ="error";
-      rlc_log_verbosity                     ="medium";
-      pdcp_log_level                        ="error";
-      pdcp_log_verbosity                    ="medium";
-      rrc_log_level                         ="error";
-      rrc_log_verbosity                     ="medium";
+log_config =
+{
+  global_log_level      ="error";
+  global_log_verbosity  ="medium";
+  hw_log_level          ="error";
+  hw_log_verbosity      ="medium";
+  phy_log_level         ="error";
+  phy_log_verbosity     ="medium";
+  mac_log_level         ="error";
+  mac_log_verbosity     ="high";
+  rlc_log_level         ="error";
+  rlc_log_verbosity     ="medium";
+  pdcp_log_level        ="error";
+  pdcp_log_verbosity    ="medium";
+  rrc_log_level         ="error";
+  rrc_log_verbosity     ="medium";
 };
diff --git a/ci-scripts/conf_files/rru.tdd.band40.conf b/ci-scripts/conf_files/rru.tdd.band40.conf
index 904f8c95989efadaedeb94755688cd1c6bb4a717..5ce3a515f58987b63d4a578925eb24a7cf5de4d2 100644
--- a/ci-scripts/conf_files/rru.tdd.band40.conf
+++ b/ci-scripts/conf_files/rru.tdd.band40.conf
@@ -1,23 +1,25 @@
-RUs = (
-    {
-        local_if_name                    = "lo";
-        remote_address                   = "127.0.0.1"
-        local_address                    = "127.0.0.2";
-        local_portc                       = 50000;
-        remote_portc                      = 50000;
-        local_portd                       = 50001;
-        remote_portd                      = 50001;
-        local_rf                         = "yes"
-        tr_preference                    = "udp_if4p5";
-        nb_tx                            = 1;
-        nb_rx                            = 1;
-        max_pdschReferenceSignalPower    = -27;
-        max_rxgain                       = 115;
-        bands                            = [40];
-    }
+RUs =
+(
+  {
+    local_if_name                 = "lo";
+    remote_address                = "127.0.0.1"
+    local_address                 = "127.0.0.2";
+    local_portc                   = 50000;
+    remote_portc                  = 50000;
+    local_portd                   = 50001;
+    remote_portd                  = 50001;
+    local_rf                      = "yes"
+    tr_preference                 = "udp_if4p5";
+    nb_tx                         = 1;
+    nb_rx                         = 1;
+    max_pdschReferenceSignalPower = -27;
+    max_rxgain                    = 115;
+    bands                         = [40];
+  }
 );
 
-THREAD_STRUCT = (
+THREAD_STRUCT =
+(
   {
     #three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT"
     parallel_config    = "PARALLEL_SINGLE_THREAD";
@@ -26,19 +28,20 @@ THREAD_STRUCT = (
   }
 );
 
-log_config = {
-      global_log_level                      ="error";
-      global_log_verbosity                  ="medium";
-      hw_log_level                          ="error";
-      hw_log_verbosity                      ="medium";
-      phy_log_level                         ="error";
-      phy_log_verbosity                     ="medium";
-      mac_log_level                         ="error";
-      mac_log_verbosity                     ="high";
-      rlc_log_level                         ="error";
-      rlc_log_verbosity                     ="medium";
-      pdcp_log_level                        ="error";
-      pdcp_log_verbosity                    ="medium";
-      rrc_log_level                         ="error";
-      rrc_log_verbosity                     ="medium";
+log_config =
+{
+  global_log_level      ="error";
+  global_log_verbosity  ="medium";
+  hw_log_level          ="error";
+  hw_log_verbosity      ="medium";
+  phy_log_level         ="error";
+  phy_log_verbosity     ="medium";
+  mac_log_level         ="error";
+  mac_log_verbosity     ="high";
+  rlc_log_level         ="error";
+  rlc_log_verbosity     ="medium";
+  pdcp_log_level        ="error";
+  pdcp_log_verbosity    ="medium";
+  rrc_log_level         ="error";
+  rrc_log_verbosity     ="medium";
 };
diff --git a/ci-scripts/constants.py b/ci-scripts/constants.py
index c5698c5a3ef38dee1ad100933b3a63bbef1b7478..a0e1ac5c45c57490db5edf3115e39e25098d667f 100644
--- a/ci-scripts/constants.py
+++ b/ci-scripts/constants.py
@@ -59,6 +59,7 @@ OAI_UE_PROCESS_NO_TUNNEL_INTERFACE = -24
 OAI_UE_PROCESS_SEG_FAULT = -25
 OAI_UE_PROCESS_NO_MBMS_MSGS = -26
 OAI_UE_PROCESS_OK = +6
+INVALID_PARAMETER = -50
 
 UE_STATUS_DETACHED = 0
 UE_STATUS_DETACHING = 1
diff --git a/ci-scripts/epc.py b/ci-scripts/epc.py
index a1994c5ac31b5b30d9f2e40acba29505dc8517e4..cd5a74765435065df2b8643b47e17b7917a5f86c 100644
--- a/ci-scripts/epc.py
+++ b/ci-scripts/epc.py
@@ -46,7 +46,6 @@ from multiprocessing import Process, Lock, SimpleQueue
 import sshconnection as SSH 
 import helpreadme as HELP
 import constants as CONST
-import html
 
 #-----------------------------------------------------------
 # Class Declaration
@@ -61,18 +60,18 @@ class EPCManagement():
 		self.SourceCodePath = ''
 		self.Type = ''
 		self.PcapFileName = ''
-		self.htmlObj = None
 		self.testCase_id = ''
 		self.MmeIPAddress = ''
 		self.containerPrefix = 'prod'
 		self.mmeConfFile = 'mme.conf'
+		self.yamlPath = ''
 
 
 #-----------------------------------------------------------
 # EPC management functions
 #-----------------------------------------------------------
 
-	def InitializeHSS(self):
+	def InitializeHSS(self, HTML):
 		if self.IPAddress == '' or self.UserName == '' or self.Password == '' or self.SourceCodePath == '' or self.Type == '':
 			HELP.GenericHelp(CONST.Version)
 			HELP.EPCSrvHelp(self.IPAddress, self.UserName, self.Password, self.SourceCodePath, self.Type)
@@ -114,10 +113,9 @@ class EPCManagement():
 		else:
 			logging.error('This option should not occur!')
 		mySSH.close()
-		if self.htmlObj is not None:
-			self.htmlObj.CreateHtmlTestRow(self.Type, 'OK', CONST.ALL_PROCESSES_OK)
+		HTML.CreateHtmlTestRow(self.Type, 'OK', CONST.ALL_PROCESSES_OK)
 
-	def InitializeMME(self):
+	def InitializeMME(self, HTML):
 		if self.IPAddress == '' or self.UserName == '' or self.Password == '' or self.SourceCodePath == '' or self.Type == '':
 			HELP.GenericHelp(CONST.Version)
 			HELP.EPCSrvHelp(self.IPAddress, self.UserName, self.Password, self.SourceCodePath, self.Type)
@@ -153,8 +151,7 @@ class EPCManagement():
 		else:
 			logging.error('This option should not occur!')
 		mySSH.close()
-		if self.htmlObj is not None:
-			self.htmlObj.CreateHtmlTestRow(self.Type, 'OK', CONST.ALL_PROCESSES_OK)
+		HTML.CreateHtmlTestRow(self.Type, 'OK', CONST.ALL_PROCESSES_OK)
 
 	def SetMmeIPAddress(self):
 		# Not an error if we don't need an EPC
@@ -175,7 +172,7 @@ class EPCManagement():
 		else:
 			self.MmeIPAddress = self.IPAddress
 
-	def InitializeSPGW(self):
+	def InitializeSPGW(self, HTML):
 		if self.IPAddress == '' or self.UserName == '' or self.Password == '' or self.SourceCodePath == '' or self.Type == '':
 			HELP.GenericHelp(CONST.Version)
 			HELP.EPCSrvHelp(self.IPAddress, self.UserName, self.Password, self.SourceCodePath, self.Type)
@@ -212,15 +209,14 @@ class EPCManagement():
 		else:
 			logging.error('This option should not occur!')
 		mySSH.close()
-		if self.htmlObj is not None:
-			self.htmlObj.CreateHtmlTestRow(self.Type, 'OK', CONST.ALL_PROCESSES_OK)
+		HTML.CreateHtmlTestRow(self.Type, 'OK', CONST.ALL_PROCESSES_OK)
 
 	def CheckHSSProcess(self, status_queue):
 		try:
 			mySSH = SSH.SSHConnection() 
 			mySSH.open(self.IPAddress, self.UserName, self.Password)
 			if re.match('OAI-Rel14-Docker', self.Type, re.IGNORECASE):
-				mySSH.command('docker exec -it ' + self.containerPrefix + '-oai-hss /bin/bash -c "ps aux | grep oai_hss"', '\$', 5)
+				mySSH.command('docker top ' + self.containerPrefix + '-oai-hss', '\$', 5)
 			else:
 				mySSH.command('stdbuf -o0 ps -aux | grep --color=never hss | grep -v grep', '\$', 5)
 			if re.match('OAI-Rel14-CUPS', self.Type, re.IGNORECASE) or re.match('OAI-Rel14-Docker', self.Type, re.IGNORECASE):
@@ -245,7 +241,7 @@ class EPCManagement():
 			mySSH = SSH.SSHConnection() 
 			mySSH.open(self.IPAddress, self.UserName, self.Password)
 			if re.match('OAI-Rel14-Docker', self.Type, re.IGNORECASE):
-				mySSH.command('docker exec -it ' + self.containerPrefix + '-oai-mme /bin/bash -c "ps aux | grep oai_mme"', '\$', 5)
+				mySSH.command('docker top ' + self.containerPrefix + '-oai-mme', '\$', 5)
 			else:
 				mySSH.command('stdbuf -o0 ps -aux | grep --color=never mme | grep -v grep', '\$', 5)
 			if re.match('OAI-Rel14-Docker', self.Type, re.IGNORECASE):
@@ -272,11 +268,11 @@ class EPCManagement():
 			mySSH = SSH.SSHConnection() 
 			mySSH.open(self.IPAddress, self.UserName, self.Password)
 			if re.match('OAI-Rel14-Docker', self.Type, re.IGNORECASE):
-				mySSH.command('docker exec -it ' + self.containerPrefix + '-oai-spgwc /bin/bash -c "ps aux | grep oai_spgwc"', '\$', 5)
-				result = re.search('oai_spgwc -o -c ', mySSH.getBefore())
+				mySSH.command('docker top ' + self.containerPrefix + '-oai-spgwc', '\$', 5)
+				result = re.search('oai_spgwc -', mySSH.getBefore())
 				if result is not None:
-					mySSH.command('docker exec -it ' + self.containerPrefix + '-oai-spgwu-tiny /bin/bash -c "ps aux | grep oai_spgwu"', '\$', 5)
-					result = re.search('oai_spgwu -o -c ', mySSH.getBefore())
+					mySSH.command('docker top ' + self.containerPrefix + '-oai-spgwu-tiny', '\$', 5)
+					result = re.search('oai_spgwu -', mySSH.getBefore())
 			elif re.match('OAI-Rel14-CUPS', self.Type, re.IGNORECASE):
 				mySSH.command('stdbuf -o0 ps -aux | grep --color=never spgw | grep -v grep', '\$', 5)
 				result = re.search('spgwu -c ', mySSH.getBefore())
@@ -297,7 +293,7 @@ class EPCManagement():
 		except:
 			os.kill(os.getppid(),signal.SIGUSR1)
 
-	def TerminateHSS(self):
+	def TerminateHSS(self, HTML):
 		mySSH = SSH.SSHConnection() 
 		mySSH.open(self.IPAddress, self.UserName, self.Password)
 		if re.match('OAI-Rel14-Docker', self.Type, re.IGNORECASE):
@@ -330,10 +326,9 @@ class EPCManagement():
 		else:
 			logging.error('This should not happen!')
 		mySSH.close()
-		if self.htmlObj is not None:
-			self.htmlObj.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK)
+		HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK)
 
-	def TerminateMME(self):
+	def TerminateMME(self, HTML):
 		mySSH = SSH.SSHConnection() 
 		mySSH.open(self.IPAddress, self.UserName, self.Password)
 		if re.match('OAI-Rel14-Docker', self.Type, re.IGNORECASE):
@@ -357,10 +352,9 @@ class EPCManagement():
 		else:
 			logging.error('This should not happen!')
 		mySSH.close()
-		if self.htmlObj is not None:
-			self.htmlObj.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK)
+		HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK)
 
-	def TerminateSPGW(self):
+	def TerminateSPGW(self, HTML):
 		mySSH = SSH.SSHConnection() 
 		mySSH.open(self.IPAddress, self.UserName, self.Password)
 		if re.match('OAI-Rel14-Docker', self.Type, re.IGNORECASE):
@@ -401,8 +395,155 @@ class EPCManagement():
 		else:
 			logging.error('This should not happen!')
 		mySSH.close()
-		if self.htmlObj is not None:
-			self.htmlObj.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK)
+		HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK)
+
+	def DeployEpc(self, HTML):
+		logging.debug('Trying to deploy')
+		if not re.match('OAI-Rel14-Docker', self.Type, re.IGNORECASE):
+			HTML.CreateHtmlTestRow(self.Type, 'KO', CONST.INVALID_PARAMETER)
+			HTML.CreateHtmlTabFooter(False)
+			sys.exit('Deploy not possible with this EPC type: ' + self.Type)
+
+		if self.IPAddress == '' or self.UserName == '' or self.Password == '' or self.SourceCodePath == '' or self.Type == '':
+			HELP.GenericHelp(CONST.Version)
+			HELP.EPCSrvHelp(self.IPAddress, self.UserName, self.Password, self.SourceCodePath, self.Type)
+			sys.exit('Insufficient EPC Parameters')
+		mySSH = SSH.SSHConnection() 
+		mySSH.open(self.IPAddress, self.UserName, self.Password)
+		mySSH.command('docker-compose --version', '\$', 5)
+		result = re.search('docker-compose version 1', mySSH.getBefore())
+		if result is None:
+			mySSH.close()
+			HTML.CreateHtmlTestRow(self.Type, 'KO', CONST.INVALID_PARAMETER)
+			HTML.CreateHtmlTabFooter(False)
+			sys.exit('docker-compose not installed on ' + self.IPAddress)
+
+		mySSH.command('if [ -d ' + self.SourceCodePath + '/scripts ]; then echo ' + self.Password + ' | sudo -S rm -Rf ' + self.SourceCodePath + '/scripts ; fi', '\$', 5)
+		mySSH.command('if [ -d ' + self.SourceCodePath + '/logs ]; then echo ' + self.Password + ' | sudo -S rm -Rf ' + self.SourceCodePath + '/logs ; fi', '\$', 5)
+		mySSH.command('mkdir -p ' + self.SourceCodePath + '/scripts ' + self.SourceCodePath + '/logs', '\$', 5)
+
+		# deploying and configuring the cassandra database
+		# container names and services are currently hard-coded.
+		# they could be recovered by:
+		# - docker-compose config --services
+		# - docker-compose config | grep container_name
+		mySSH.command('cd ' + self.SourceCodePath + '/scripts', '\$', 5)
+		mySSH.copyout(self.IPAddress, self.UserName, self.Password, './' + self.yamlPath + '/docker-compose.yml', self.SourceCodePath + '/scripts')
+		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)
+
+		# databases take time...
+		time.sleep(10)
+		cnt = 0
+		db_init_status = False
+		while (cnt < 10):
+			mySSH.command('docker logs prod-db-init', '\$', 5)
+			result = re.search('OK', mySSH.getBefore())
+			if result is not None:
+				cnt = 10
+				db_init_status = True
+			else:
+				time.sleep(5)
+				cnt += 1
+		mySSH.command('docker rm -f prod-db-init', '\$', 5)
+		if not db_init_status:
+			HTML.CreateHtmlTestRow(self.Type, 'KO', CONST.INVALID_PARAMETER)
+			HTML.CreateHtmlTabFooter(False)
+			sys.exit('Cassandra DB deployment/configuration went wrong!')
+
+		# deploying EPC cNFs
+		mySSH.command('docker-compose up -d oai_spgwu', '\$', 60)
+		listOfContainers = 'prod-cassandra prod-oai-hss prod-oai-mme prod-oai-spgwc prod-oai-spgwu-tiny'
+		expectedHealthyContainers = 5
+
+		# Checking for additional services
+		mySSH.command('docker-compose config', '\$', 5)
+		configResponse = mySSH.getBefore()
+		if configResponse.count('flexran_rtc') == 1:
+			mySSH.command('docker-compose up -d flexran_rtc', '\$', 60)
+			listOfContainers += ' prod-flexran-rtc'
+			expectedHealthyContainers += 1
+		if configResponse.count('trf_gen') == 1:
+			mySSH.command('docker-compose up -d trf_gen', '\$', 60)
+			listOfContainers += ' prod-trf-gen'
+			expectedHealthyContainers += 1
+
+		# Checking if all are healthy
+		cnt = 0
+		while (cnt < 3):
+			mySSH.command('docker inspect --format=\'{{.State.Health.Status}}\' ' + listOfContainers, '\$', 10)
+			unhealthyNb = mySSH.getBefore().count('unhealthy')
+			healthyNb = mySSH.getBefore().count('healthy') - unhealthyNb
+			startingNb = mySSH.getBefore().count('starting')
+			if healthyNb == expectedHealthyContainers:
+				cnt = 10
+			else:
+				time.sleep(10)
+				cnt += 1
+		logging.debug(' -- ' + str(healthyNb) + ' healthy container(s)')
+		logging.debug(' -- ' + str(unhealthyNb) + ' unhealthy container(s)')
+		logging.debug(' -- ' + str(startingNb) + ' still starting container(s)')
+		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)
+			mySSH.command('docker exec -d prod-oai-mme /bin/bash -c "nohup tshark -i any -f \'port 3868 or port 2123 or port 36412\' -w /tmp/mme_check_run.pcap 2>&1 > /dev/null"', '\$', 10)
+			mySSH.command('docker exec -d prod-oai-spgwc /bin/bash -c "nohup tshark -i any -f \'port 2123 or port 8805\' -w /tmp/spgwc_check_run.pcap 2>&1 > /dev/null"', '\$', 10)
+			# on SPGW-U, not capturing on SGI to avoid huge file
+			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)
+		else:
+			mySSH.close()
+			logging.debug('Deployment went wrong')
+			HTML.CreateHtmlTestRow(self.Type, 'KO', CONST.INVALID_PARAMETER)
+
+	def UndeployEpc(self, HTML):
+		logging.debug('Trying to undeploy')
+		# No check down, we suppose everything done before.
+
+		mySSH = SSH.SSHConnection() 
+		mySSH.open(self.IPAddress, self.UserName, self.Password)
+		# Recovering logs and pcap files
+		mySSH.command('cd ' + self.SourceCodePath + '/logs', '\$', 5)
+		mySSH.command('docker exec -it prod-oai-hss /bin/bash -c "killall --signal SIGINT oai_hss tshark"', '\$', 5)
+		mySSH.command('docker exec -it prod-oai-mme /bin/bash -c "killall --signal SIGINT tshark"', '\$', 5)
+		mySSH.command('docker exec -it prod-oai-spgwc /bin/bash -c "killall --signal SIGINT oai_spgwc tshark"', '\$', 5)
+		mySSH.command('docker exec -it prod-oai-spgwu-tiny /bin/bash -c "killall --signal SIGINT tshark"', '\$', 5)
+		mySSH.command('docker logs prod-oai-hss > hss_' + self.testCase_id + '.log', '\$', 5)
+		mySSH.command('docker logs prod-oai-mme > mme_' + self.testCase_id + '.log', '\$', 5)
+		mySSH.command('docker logs prod-oai-spgwc > spgwc_' + self.testCase_id + '.log', '\$', 5)
+		mySSH.command('docker logs prod-oai-spgwu-tiny > spgwu_' + self.testCase_id + '.log', '\$', 5)
+		mySSH.command('docker cp prod-oai-hss:/tmp/hss_check_run.pcap hss_' + self.testCase_id + '.pcap', '\$', 60)
+		mySSH.command('docker cp prod-oai-mme:/tmp/mme_check_run.pcap mme_' + self.testCase_id + '.pcap', '\$', 60)
+		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
+		mySSH.command('cd ' + self.SourceCodePath + '/scripts', '\$', 5)
+		listOfContainers = 'prod-cassandra prod-oai-hss prod-oai-mme prod-oai-spgwc prod-oai-spgwu-tiny'
+		nbContainers = 5
+		# Checking for additional services
+		mySSH.command('docker-compose config', '\$', 5)
+		configResponse = mySSH.getBefore()
+		if configResponse.count('flexran_rtc') == 1:
+			listOfContainers += ' prod-flexran-rtc'
+			nbContainers += 1
+		if configResponse.count('trf_gen') == 1:
+			listOfContainers += ' prod-trf-gen'
+			nbContainers += 1
+
+		mySSH.command('docker-compose down', '\$', 60)
+		mySSH.command('docker inspect --format=\'{{.State.Health.Status}}\' ' + listOfContainers, '\$', 10)
+		noMoreContainerNb = mySSH.getBefore().count('No such object')
+		mySSH.command('docker inspect --format=\'{{.Name}}\' prod-oai-public-net prod-oai-private-net', '\$', 10)
+		noMoreNetworkNb = mySSH.getBefore().count('No such object')
+		mySSH.close()
+		if noMoreContainerNb == nbContainers and noMoreNetworkNb == 2:
+			logging.debug('Undeployment OK')
+			HTML.CreateHtmlTestRow(self.Type, 'OK', CONST.ALL_PROCESSES_OK)
+		else:
+			logging.debug('Undeployment went wrong')
+			HTML.CreateHtmlTestRow(self.Type, 'KO', CONST.INVALID_PARAMETER)
 
 	def LogCollectHSS(self):
 		mySSH = SSH.SSHConnection() 
@@ -410,9 +551,17 @@ class EPCManagement():
 		mySSH.command('cd ' + self.SourceCodePath + '/scripts', '\$', 5)
 		mySSH.command('rm -f hss.log.zip', '\$', 5)
 		if re.match('OAI-Rel14-Docker', self.Type, re.IGNORECASE):
-			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)
+			mySSH.command('docker inspect prod-oai-hss', '\$', 10)
+			result = re.search('No such object', mySSH.getBefore())
+			if result is not None:
+				mySSH.command('cd ../logs', '\$', 5)
+				mySSH.command('rm -f hss.log.zip', '\$', 5)
+				mySSH.command('zip hss.log.zip hss_*.*', '\$', 60)
+				mySSH.command('mv hss.log.zip ../scripts', '\$', 60)
+			else:
+				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('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)
@@ -432,9 +581,17 @@ class EPCManagement():
 		mySSH.command('cd ' + self.SourceCodePath + '/scripts', '\$', 5)
 		mySSH.command('rm -f mme.log.zip', '\$', 5)
 		if re.match('OAI-Rel14-Docker', self.Type, re.IGNORECASE):
-			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)
+			mySSH.command('docker inspect prod-oai-mme', '\$', 10)
+			result = re.search('No such object', mySSH.getBefore())
+			if result is not None:
+				mySSH.command('cd ../logs', '\$', 5)
+				mySSH.command('rm -f mme.log.zip', '\$', 5)
+				mySSH.command('zip mme.log.zip mme_*.*', '\$', 60)
+				mySSH.command('mv mme.log.zip ../scripts', '\$', 60)
+			else:
+				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('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)
@@ -451,11 +608,19 @@ class EPCManagement():
 		mySSH.command('cd ' + self.SourceCodePath + '/scripts', '\$', 5)
 		mySSH.command('rm -f spgw.log.zip', '\$', 5)
 		if re.match('OAI-Rel14-Docker', self.Type, re.IGNORECASE):
-			mySSH.command('docker cp ' + self.containerPrefix + '-oai-spgwc:/openair-spgwc/spgwc_check_run.log .', '\$', 60)
-			mySSH.command('docker cp ' + self.containerPrefix + '-oai-spgwu-tiny:/openair-spgwu-tiny/spgwu_check_run.log .', '\$', 60)
-			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)
+			mySSH.command('docker inspect prod-oai-mme', '\$', 10)
+			result = re.search('No such object', mySSH.getBefore())
+			if result is not None:
+				mySSH.command('cd ../logs', '\$', 5)
+				mySSH.command('rm -f spgw.log.zip', '\$', 5)
+				mySSH.command('zip spgw.log.zip spgw*.*', '\$', 60)
+				mySSH.command('mv spgw.log.zip ../scripts', '\$', 60)
+			else:
+				mySSH.command('docker cp ' + self.containerPrefix + '-oai-spgwc:/openair-spgwc/spgwc_check_run.log .', '\$', 60)
+				mySSH.command('docker cp ' + self.containerPrefix + '-oai-spgwu-tiny:/openair-spgwu-tiny/spgwu_check_run.log .', '\$', 60)
+				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('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)
diff --git a/ci-scripts/main.py b/ci-scripts/main.py
index 8fbc3b93a0170cf9559403f2b414e598b33e36be..38a1a07d147ebd8ad8d71999a6e15906626a43a0 100644
--- a/ci-scripts/main.py
+++ b/ci-scripts/main.py
@@ -41,6 +41,7 @@ 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_containerize     #class Containerize for all container-based operations on RAN/UE objects
 
 
 import sshconnection 
@@ -98,24 +99,34 @@ def AssignParams(params_dict):
 
 
 def GetParametersFromXML(action):
-	if action == 'Build_eNB':
+	if action == 'Build_eNB' or action == 'Build_Image':
 		RAN.Build_eNB_args=test.findtext('Build_eNB_args')
+		CONTAINERS.imageKind=test.findtext('kind')
 		forced_workspace_cleanup = test.findtext('forced_workspace_cleanup')
 		if (forced_workspace_cleanup is None):
 			RAN.Build_eNB_forced_workspace_cleanup=False
+			CONTAINERS.forcedWorkspaceCleanup=False
 		else:
 			if re.match('true', forced_workspace_cleanup, re.IGNORECASE):
 				RAN.Build_eNB_forced_workspace_cleanup=True
+				CONTAINERS.forcedWorkspaceCleanup=True
 			else:
-				RAN.Build_eNB_forced_workspace_cleanup=False
+				RAN.Build_eNB_forced_workspace_cleanup=True
+				CONTAINERS.forcedWorkspaceCleanup=False
 		eNB_instance=test.findtext('eNB_instance')
 		if (eNB_instance is None):
 			RAN.eNB_instance=0
+			CONTAINERS.eNB_instance=0
 		else:
 			RAN.eNB_instance=int(eNB_instance)
-		RAN.eNB_serverId=test.findtext('eNB_serverId')
-		if (RAN.eNB_serverId is None):
-			RAN.eNB_serverId='0'
+			CONTAINERS.eNB_instance=int(eNB_instance)
+		eNB_serverId=test.findtext('eNB_serverId')
+		if (eNB_serverId is None):
+			RAN.eNB_serverId[RAN.eNB_instance]='0'
+			CONTAINERS.eNB_serverId[RAN.eNB_instance]='0'
+		else:
+			RAN.eNB_serverId[RAN.eNB_instance]=eNB_serverId
+			CONTAINERS.eNB_serverId[CONTAINERS.eNB_instance]=eNB_serverId
 		xmlBgBuildField = test.findtext('backgroundBuild')
 		if (xmlBgBuildField is None):
 			RAN.backgroundBuild=False
@@ -132,9 +143,11 @@ def GetParametersFromXML(action):
 			RAN.eNB_instance=0
 		else:
 			RAN.eNB_instance=int(eNB_instance)
-		RAN.eNB_serverId=test.findtext('eNB_serverId')
-		if (RAN.eNB_serverId is None):
-			RAN.eNB_serverId='0'
+		eNB_serverId=test.findtext('eNB_serverId')
+		if (eNB_serverId is None):
+			RAN.eNB_serverId[RAN.eNB_instance]='0'
+		else:
+			RAN.eNB_serverId[RAN.eNB_instance]=eNB_serverId
 
 	elif action == 'Initialize_eNB':
 		RAN.Initialize_eNB_args=test.findtext('Initialize_eNB_args')
@@ -143,9 +156,11 @@ def GetParametersFromXML(action):
 			RAN.eNB_instance=0
 		else:
 			RAN.eNB_instance=int(eNB_instance)
-		RAN.eNB_serverId=test.findtext('eNB_serverId')
-		if (RAN.eNB_serverId is None):
-			RAN.eNB_serverId='0'
+		eNB_serverId=test.findtext('eNB_serverId')
+		if (eNB_serverId is None):
+			RAN.eNB_serverId[RAN.eNB_instance]='0'
+		else:
+			RAN.eNB_serverId[RAN.eNB_instance]=eNB_serverId
 			
 		#local variable air_interface
 		air_interface = test.findtext('air_interface')		
@@ -162,10 +177,12 @@ def GetParametersFromXML(action):
 			RAN.eNB_instance=0
 		else:
 			RAN.eNB_instance=int(eNB_instance)
-		RAN.eNB_serverId=test.findtext('eNB_serverId')
-		if (RAN.eNB_serverId is None):
-			RAN.eNB_serverId='0'
-			
+		eNB_serverId=test.findtext('eNB_serverId')
+		if (eNB_serverId is None):
+			RAN.eNB_serverId[RAN.eNB_instance]='0'
+		else:
+			RAN.eNB_serverId[RAN.eNB_instance]=eNB_serverId
+
 		#local variable air_interface
 		air_interface = test.findtext('air_interface')		
 		if (air_interface is None) or (air_interface.lower() not in ['nr','lte','ocp']):
@@ -288,6 +305,27 @@ def GetParametersFromXML(action):
 		if (string_field is not None):
 			EPC.mmeConfFile = string_field
 
+	elif action == 'Deploy_EPC':
+		string_field = test.findtext('parameters')
+		if (string_field is not None):
+			EPC.yamlPath = string_field
+
+	elif action == 'Deploy_Object' or action == 'Undeploy_Object':
+		eNB_instance=test.findtext('eNB_instance')
+		if (eNB_instance is None):
+			CONTAINERS.eNB_instance=0
+		else:
+			CONTAINERS.eNB_instance=int(eNB_instance)
+		eNB_serverId=test.findtext('eNB_serverId')
+		if (eNB_serverId is None):
+			CONTAINERS.eNB_serverId[CONTAINERS.eNB_instance]='0'
+		else:
+			CONTAINERS.eNB_serverId[CONTAINERS.eNB_instance]=eNB_serverId
+		string_field = test.findtext('yaml_path')
+		if (string_field is not None):
+			CONTAINERS.yamlPath[CONTAINERS.eNB_instance] = string_field
+
+
 	else: # ie action == 'Run_PhySim':
 		ldpc.runargs = test.findtext('physim_run_args')
 		
@@ -339,11 +377,7 @@ SSH = sshconnection.SSHConnection()
 EPC = epc.EPCManagement()
 RAN = ran.RANManagement()
 HTML = html.HTMLManagement()
-
-EPC.htmlObj=HTML
-RAN.htmlObj=HTML
-RAN.epcObj=EPC
-
+CONTAINERS = cls_containerize.Containerize()
 
 ldpc=cls_physim.PhySim()    #create an instance for LDPC test using GPU or CPU build
 
@@ -354,7 +388,7 @@ ldpc=cls_physim.PhySim()    #create an instance for LDPC test using GPU or CPU b
 #-----------------------------------------------------------
 
 import args_parse
-py_param_file_present, py_params, mode = args_parse.ArgsParse(sys.argv,CiTestObj,RAN,HTML,EPC,ldpc,HELP)
+py_param_file_present, py_params, mode = args_parse.ArgsParse(sys.argv,CiTestObj,RAN,HTML,EPC,ldpc,CONTAINERS,HELP)
 
 
 
@@ -383,8 +417,8 @@ if re.match('^TerminateeNB$', mode, re.IGNORECASE):
 	if RAN.eNBIPAddress == '' or RAN.eNBUserName == '' or RAN.eNBPassword == '':
 		HELP.GenericHelp(CONST.Version)
 		sys.exit('Insufficient Parameter')
-	RAN.eNB_serverId='0'
 	RAN.eNB_instance=0
+	RAN.eNB_serverId[0]='0'
 	RAN.eNBSourceCodePath='/tmp/'
 	RAN.TerminateeNB()
 elif re.match('^TerminateUE$', mode, re.IGNORECASE):
@@ -495,7 +529,7 @@ elif re.match('^FinalizeHtml$', mode, re.IGNORECASE):
 	HTML.CreateHtmlFooter(CiTestObj.finalStatus)
 elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re.IGNORECASE):
 	logging.debug('\u001B[1m----------------------------------------\u001B[0m')
-	logging.debug('\u001B[1m  Starting Scenario \u001B[0m')
+	logging.debug('\u001B[1m  Starting Scenario: ' + CiTestObj.testXMLfiles[0] + '\u001B[0m')
 	logging.debug('\u001B[1m----------------------------------------\u001B[0m')
 	if re.match('^TesteNB$', mode, re.IGNORECASE):
 		if RAN.eNBIPAddress == '' or RAN.ranRepository == '' or RAN.ranBranch == '' or RAN.eNBUserName == '' or RAN.eNBPassword == '' or RAN.eNBSourceCodePath == '' or EPC.IPAddress == '' or EPC.UserName == '' or EPC.Password == '' or EPC.Type == '' or EPC.SourceCodePath == '' or CiTestObj.ADBIPAddress == '' or CiTestObj.ADBUserName == '' or CiTestObj.ADBPassword == '':
@@ -566,7 +600,7 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re
 			logging.debug('ERROR: requested test is invalidly formatted: ' + test)
 			sys.exit(1)
 	if (EPC.IPAddress != '') and (EPC.IPAddress != 'none'):
-		CiTestObj.CheckFlexranCtrlInstallation(RAN,EPC)
+		CiTestObj.CheckFlexranCtrlInstallation(RAN,EPC,CONTAINERS)
 		EPC.SetMmeIPAddress()
 
 	#get the list of tests to be done
@@ -626,17 +660,16 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re
 							RAN.prematureExit = True
 							break
 				if action == 'Build_eNB':
-					RAN.BuildeNB()
+					RAN.BuildeNB(HTML)
 				elif action == 'WaitEndBuild_eNB':
-					RAN.WaitBuildeNBisFinished()
+					RAN.WaitBuildeNBisFinished(HTML)
 				elif action == 'Initialize_eNB':
 					check_eNB = False
 					check_OAI_UE = False
 					RAN.pStatus=CiTestObj.CheckProcessExist(check_eNB, check_OAI_UE,RAN,EPC)
-
-					RAN.InitializeeNB()
+					RAN.InitializeeNB(HTML, EPC)
 				elif action == 'Terminate_eNB':
-					RAN.TerminateeNB()
+					RAN.TerminateeNB(HTML, EPC)
 				elif action == 'Initialize_UE':
 					CiTestObj.InitializeUE(HTML,COTS_UE)
 				elif action == 'Terminate_UE':
@@ -656,17 +689,17 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re
 				elif action == 'Initialize_OAI_UE':
 					CiTestObj.InitializeOAIUE(HTML,RAN,EPC,COTS_UE)
 				elif action == 'Terminate_OAI_UE':
-					CiTestObj.TerminateOAIUE(HTML,RAN,COTS_UE)
+					CiTestObj.TerminateOAIUE(HTML,RAN,COTS_UE,EPC)
 				elif action == 'Initialize_CatM_module':
 					CiTestObj.InitializeCatM(HTML)
 				elif action == 'Terminate_CatM_module':
 					CiTestObj.TerminateCatM(HTML)
 				elif action == 'Attach_CatM_module':
-					CiTestObj.AttachCatM(HTML,RAN,COTS_UE)
+					CiTestObj.AttachCatM(HTML,RAN,COTS_UE,EPC)
 				elif action == 'Detach_CatM_module':
 					CiTestObj.TerminateCatM(HTML)
 				elif action == 'Ping_CatM_module':
-					CiTestObj.PingCatM(HTML,RAN,EPC,COTS_UE)
+					CiTestObj.PingCatM(HTML,RAN,EPC,COTS_UE,EPC)
 				elif action == 'Ping':
 					CiTestObj.Ping(HTML,RAN,EPC,COTS_UE)
 				elif action == 'Iperf':
@@ -674,17 +707,21 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re
 				elif action == 'Reboot_UE':
 					CiTestObj.RebootUE(HTML,RAN,EPC)
 				elif action == 'Initialize_HSS':
-					EPC.InitializeHSS()
+					EPC.InitializeHSS(HTML)
 				elif action == 'Terminate_HSS':
-					EPC.TerminateHSS()
+					EPC.TerminateHSS(HTML)
 				elif action == 'Initialize_MME':
-					EPC.InitializeMME()
+					EPC.InitializeMME(HTML)
 				elif action == 'Terminate_MME':
-					EPC.TerminateMME()
+					EPC.TerminateMME(HTML)
 				elif action == 'Initialize_SPGW':
-					EPC.InitializeSPGW()
+					EPC.InitializeSPGW(HTML)
 				elif action == 'Terminate_SPGW':
-					EPC.TerminateSPGW()
+					EPC.TerminateSPGW(HTML)
+				elif action == 'Deploy_EPC':
+					EPC.DeployEpc(HTML)
+				elif action == 'Undeploy_EPC':
+					EPC.UndeployEpc(HTML)
 				elif action == 'Initialize_FlexranCtrl':
 					CiTestObj.InitializeFlexranCtrl(HTML,RAN,EPC)
 				elif action == 'Terminate_FlexranCtrl':
@@ -698,6 +735,12 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re
 					if ldpc.exitStatus==1:sys.exit()
 				elif action == 'Run_PhySim':
 					HTML=ldpc.Run_PhySim(HTML,CONST,id)
+				elif action == 'Build_Image':
+					CONTAINERS.BuildImage(HTML)
+				elif action == 'Deploy_Object':
+					CONTAINERS.DeployObject(HTML, EPC)
+				elif action == 'Undeploy_Object':
+					CONTAINERS.UndeployObject(HTML, RAN)
 				else:
 					sys.exit('Invalid class (action) from xml')
 				if not RAN.prematureExit:
@@ -707,14 +750,14 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re
 						HTML.testStabilityPointReached = True
 		CiTestObj.FailReportCnt += 1
 	if CiTestObj.FailReportCnt == CiTestObj.repeatCounts[0] and RAN.prematureExit:
-		logging.debug('Testsuite failed ' + str(CiTestObj.FailReportCnt) + ' time(s)')
+		logging.debug('Scenario failed ' + str(CiTestObj.FailReportCnt) + ' time(s)')
 		HTML.CreateHtmlTabFooter(False)
 		if CiTestObj.testUnstable and (CiTestObj.testStabilityPointReached or CiTestObj.testMinStableId == '999999'):
 			logging.debug('Scenario has reached minimal stability point -- Not a Failure')
 		else:
 			sys.exit('Failed Scenario')
 	else:
-		logging.info('Testsuite passed after ' + str(CiTestObj.FailReportCnt) + ' time(s)')
+		logging.info('Scenario passed after ' + str(CiTestObj.FailReportCnt) + ' time(s)')
 		HTML.CreateHtmlTabFooter(True)
 elif re.match('^LoadParams$', mode, re.IGNORECASE):
 	pass
diff --git a/ci-scripts/ran.py b/ci-scripts/ran.py
index 6425d55c8f98b870fbc4acb7b035a26885eb22bd..774d7f19c6a4f240ca36409aa2418a8b0005c57f 100644
--- a/ci-scripts/ran.py
+++ b/ci-scripts/ran.py
@@ -42,10 +42,8 @@ from multiprocessing import Process, Lock, SimpleQueue
 # OAI Testing modules
 #-----------------------------------------------------------
 import sshconnection as SSH
-import epc 
 import helpreadme as HELP
 import constants as CONST
-import html
 
 #-----------------------------------------------------------
 # Class Declaration
@@ -77,19 +75,20 @@ class RANManagement():
 		self.backgroundBuildTestId = ['', '', '']
 		self.Build_eNB_forced_workspace_cleanup = False
 		self.Initialize_eNB_args = ''
+		self.imageKind = ''
 		self.air_interface = ['', '', ''] #changed from 'lte' to '' may lead to side effects in main
 		self.eNB_instance = 0
-		self.eNB_serverId = ''
+		self.eNB_serverId = ['', '', '']
 		self.eNBLogFiles = ['', '', '']
 		self.eNBOptions = ['', '', '']
 		self.eNBmbmsEnables = [False, False, False]
 		self.eNBstatuses = [-1, -1, -1]
 		self.flexranCtrlInstalled = False
 		self.flexranCtrlStarted = False
+		self.flexranCtrlDeployed = False
+		self.flexranCtrlIpAddress = ''
 		self.testCase_id = ''
 		self.epcPcapFile = ''
-		self.htmlObj = None
-		self.epcObj = None
 		self.runtime_stats= ''
 
 
@@ -98,21 +97,21 @@ class RANManagement():
 # RAN management functions
 #-----------------------------------------------------------
 
-	def BuildeNB(self):
+	def BuildeNB(self, HTML):
 		if self.ranRepository == '' or self.ranBranch == '' or self.ranCommitID == '':
 			HELP.GenericHelp(CONST.Version)
 			sys.exit('Insufficient Parameter')
-		if self.eNB_serverId == '0':
+		if self.eNB_serverId[self.eNB_instance] == '0':
 			lIpAddr = self.eNBIPAddress
 			lUserName = self.eNBUserName
 			lPassWord = self.eNBPassword
 			lSourcePath = self.eNBSourceCodePath
-		elif self.eNB_serverId == '1':
+		elif self.eNB_serverId[self.eNB_instance] == '1':
 			lIpAddr = self.eNB1IPAddress
 			lUserName = self.eNB1UserName
 			lPassWord = self.eNB1Password
 			lSourcePath = self.eNB1SourceCodePath
-		elif self.eNB_serverId == '2':
+		elif self.eNB_serverId[self.eNB_instance] == '2':
 			lIpAddr = self.eNB2IPAddress
 			lUserName = self.eNB2UserName
 			lPassWord = self.eNB2Password
@@ -120,6 +119,7 @@ class RANManagement():
 		if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '':
 			HELP.GenericHelp(CONST.Version)
 			sys.exit('Insufficient Parameter')
+		logging.debug('Building on server: ' + lIpAddr)
 		mySSH = SSH.SSHConnection()
 		mySSH.open(lIpAddr, lUserName, lPassWord)
 		
@@ -137,10 +137,7 @@ class RANManagement():
 		# Worakround for some servers, we need to erase completely the workspace
 		if self.Build_eNB_forced_workspace_cleanup:
 			mySSH.command('echo ' + lPassWord + ' | sudo -S rm -Rf ' + lSourcePath, '\$', 15)
-		if self.htmlObj is not None:
-			self.testCase_id = self.htmlObj.testCase_id
-		else:
-			self.testCase_id = '000000'
+		self.testCase_id = HTML.testCase_id
 		# on RedHat/CentOS .git extension is mandatory
 		result = re.search('([a-zA-Z0-9\:\-\.\/])+\.git', self.ranRepository)
 		if result is not None:
@@ -181,8 +178,7 @@ class RANManagement():
 						mismatch = True
 				if not mismatch:
 					mySSH.close()
-					if self.htmlObj is not None:
-						self.htmlObj.CreateHtmlTestRow(self.Build_eNB_args, 'OK', CONST.ALL_PROCESSES_OK)
+					HTML.CreateHtmlTestRow(self.Build_eNB_args, 'OK', CONST.ALL_PROCESSES_OK)
 					return
 
 		mySSH.command('echo ' + lPassWord + ' | sudo -S git clean -x -d -ff', '\$', 30)
@@ -209,26 +205,25 @@ class RANManagement():
 			mySSH.command('echo ' + lPassWord + ' | sudo -S ls', '\$', 5)
 			mySSH.command('echo $USER; nohup sudo -E ./my-lte-softmodem-build.sh' + ' > ' + lSourcePath + '/cmake_targets/compile_oai_enb.log ' + ' 2>&1 &', lUserName, 5)
 			mySSH.close()
-			if self.htmlObj is not None:
-				self.htmlObj.CreateHtmlTestRow(self.Build_eNB_args, 'OK', CONST.ALL_PROCESSES_OK)
+			HTML.CreateHtmlTestRow(self.Build_eNB_args, 'OK', CONST.ALL_PROCESSES_OK)
 			self.backgroundBuildTestId[int(self.eNB_instance)] = self.testCase_id
 			return
 		mySSH.command('stdbuf -o0 ./build_oai ' + self.Build_eNB_args + ' 2>&1 | stdbuf -o0 tee compile_oai_enb.log', 'Bypassing the Tests|build have failed', 1500)
 		mySSH.close()
-		self.checkBuildeNB(lIpAddr, lUserName, lPassWord, lSourcePath, self.testCase_id)
+		self.checkBuildeNB(lIpAddr, lUserName, lPassWord, lSourcePath, self.testCase_id, HTML)
 
-	def WaitBuildeNBisFinished(self):
-		if self.eNB_serverId == '0':
+	def WaitBuildeNBisFinished(self, HTML):
+		if self.eNB_serverId[self.eNB_instance] == '0':
 			lIpAddr = self.eNBIPAddress
 			lUserName = self.eNBUserName
 			lPassWord = self.eNBPassword
 			lSourcePath = self.eNBSourceCodePath
-		elif self.eNB_serverId == '1':
+		elif self.eNB_serverId[self.eNB_instance] == '1':
 			lIpAddr = self.eNB1IPAddress
 			lUserName = self.eNB1UserName
 			lPassWord = self.eNB1Password
 			lSourcePath = self.eNB1SourceCodePath
-		elif self.eNB_serverId == '2':
+		elif self.eNB_serverId[self.eNB_instance] == '2':
 			lIpAddr = self.eNB2IPAddress
 			lUserName = self.eNB2UserName
 			lPassWord = self.eNB2Password
@@ -236,6 +231,7 @@ class RANManagement():
 		if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '':
 			HELP.GenericHelp(CONST.Version)
 			sys.exit('Insufficient Parameter')
+		logging.debug('Waiting for end of build on server: ' + lIpAddr)
 		mySSH = SSH.SSHConnection()
 		mySSH.open(lIpAddr, lUserName, lPassWord)
 		count = 40
@@ -249,11 +245,10 @@ class RANManagement():
 				count -= 1
 				time.sleep(30)
 		mySSH.close()
-		self.checkBuildeNB(lIpAddr, lUserName, lPassWord, lSourcePath, self.backgroundBuildTestId[int(self.eNB_instance)])
+		self.checkBuildeNB(lIpAddr, lUserName, lPassWord, lSourcePath, self.backgroundBuildTestId[int(self.eNB_instance)], HTML)
 
-	def checkBuildeNB(self, lIpAddr, lUserName, lPassWord, lSourcePath, testcaseId):
-		if self.htmlObj is not None:
-			self.htmlObj.testCase_id=testcaseId
+	def checkBuildeNB(self, lIpAddr, lUserName, lPassWord, lSourcePath, testcaseId, HTML):
+		HTML.testCase_id=testcaseId
 
 		mySSH = SSH.SSHConnection()
 		mySSH.open(lIpAddr, lUserName, lPassWord)
@@ -284,7 +279,7 @@ class RANManagement():
 		mySSH.command('mkdir -p build_log_' + testcaseId, '\$', 5)
 		mySSH.command('mv log/* ' + 'build_log_' + testcaseId, '\$', 5)
 		mySSH.command('mv compile_oai_enb.log ' + 'build_log_' + testcaseId, '\$', 5)
-		if self.eNB_serverId != '0':
+		if self.eNB_serverId[self.eNB_instance] != '0':
 			mySSH.command('cd cmake_targets', '\$', 5)
 			mySSH.command('if [ -e tmp_build' + testcaseId + '.zip ]; then rm -f tmp_build' + testcaseId + '.zip; fi', '\$', 5)
 			mySSH.command('zip -r -qq tmp_build' + testcaseId + '.zip build_log_' + testcaseId, '\$', 5)
@@ -307,27 +302,25 @@ class RANManagement():
 		#generate logging info depending on buildStatus and air interface
 		if buildStatus:
 			logging.info('\u001B[1m Building OAI ' + self.air_interface[self.eNB_instance] + ' Pass\u001B[0m')
-			if self.htmlObj is not None:
-				self.htmlObj.CreateHtmlTestRow(self.Build_eNB_args, 'OK', CONST.ALL_PROCESSES_OK)		
+			HTML.CreateHtmlTestRow(self.Build_eNB_args, 'OK', CONST.ALL_PROCESSES_OK)
 		else:
 			logging.error('\u001B[1m Building OAI ' + self.air_interface[self.eNB_instance] + ' Failed\u001B[0m')
-			if self.htmlObj is not None:
-				self.htmlObj.CreateHtmlTestRow(self.Build_eNB_args, 'KO', CONST.ALL_PROCESSES_OK)
-				self.htmlObj.CreateHtmlTabFooter(False)
+			HTML.CreateHtmlTestRow(self.Build_eNB_args, 'KO', CONST.ALL_PROCESSES_OK)
+			HTML.CreateHtmlTabFooter(False)
 			sys.exit(1)
 
-	def InitializeeNB(self):
-		if self.eNB_serverId == '0':
+	def InitializeeNB(self, HTML, EPC):
+		if self.eNB_serverId[self.eNB_instance] == '0':
 			lIpAddr = self.eNBIPAddress
 			lUserName = self.eNBUserName
 			lPassWord = self.eNBPassword
 			lSourcePath = self.eNBSourceCodePath
-		elif self.eNB_serverId == '1':
+		elif self.eNB_serverId[self.eNB_instance] == '1':
 			lIpAddr = self.eNB1IPAddress
 			lUserName = self.eNB1UserName
 			lPassWord = self.eNB1Password
 			lSourcePath = self.eNB1SourceCodePath
-		elif self.eNB_serverId == '2':
+		elif self.eNB_serverId[self.eNB_instance] == '2':
 			lIpAddr = self.eNB2IPAddress
 			lUserName = self.eNB2UserName
 			lPassWord = self.eNB2Password
@@ -335,24 +328,21 @@ class RANManagement():
 		if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '':
 			HELP.GenericHelp(CONST.Version)
 			sys.exit('Insufficient Parameter')
+		logging.debug('Starting eNB/gNB on server: ' + lIpAddr)
 
-		if self.htmlObj is not None:
-			self.testCase_id = self.htmlObj.testCase_id
-		else:
-			self.testCase_id = '000000'
+		self.testCase_id = HTML.testCase_id
 		mySSH = SSH.SSHConnection()
 		
 		if (self.pStatus < 0):
-			if self.htmlObj is not None:
-				self.htmlObj.CreateHtmlTestRow(self.air_interface[self.eNB_instance] + ' ' + self.Initialize_eNB_args, 'KO', self.pStatus)
-				self.htmlObj.CreateHtmlTabFooter(False)
+			HTML.CreateHtmlTestRow(self.air_interface[self.eNB_instance] + ' ' + self.Initialize_eNB_args, 'KO', self.pStatus)
+			HTML.CreateHtmlTabFooter(False)
 			sys.exit(1)
 		# If tracer options is on, running tshark on EPC side and capture traffic b/ EPC and eNB
 		result = re.search('T_stdout', str(self.Initialize_eNB_args))
-		if (result is not None) and (self.epcObj is not None):
-			localEpcIpAddr = self.epcObj.IPAddress
-			localEpcUserName = self.epcObj.UserName
-			localEpcPassword = self.epcObj.Password
+		if (result is not None):
+			localEpcIpAddr = EPC.IPAddress
+			localEpcUserName = EPC.UserName
+			localEpcPassword = EPC.Password
 			mySSH.open(localEpcIpAddr, localEpcUserName, localEpcPassword)
 			mySSH.command('ip addr show | awk -f /tmp/active_net_interfaces.awk | egrep -v "lo|tun"', '\$', 5)
 			result = re.search('interfaceToUse=(?P<eth_interface>[a-zA-Z0-9\-\_]+)done', mySSH.getBefore())
@@ -400,17 +390,17 @@ class RANManagement():
 				mySSH.command('echo ' + lPassWord + ' | sudo -S uhd_find_devices', '\$', 60)
 		# Make a copy and adapt to EPC / eNB IP addresses
 		mySSH.command('cp ' + full_config_file + ' ' + ci_full_config_file, '\$', 5)
-		if self.epcObj is not None:
-			localMmeIpAddr = self.epcObj.MmeIPAddress
-			mySSH.command('sed -i -e \'s/CI_MME_IP_ADDR/' + localMmeIpAddr + '/\' ' + ci_full_config_file, '\$', 2);
+		localMmeIpAddr = EPC.MmeIPAddress
+		mySSH.command('sed -i -e \'s/CI_MME_IP_ADDR/' + localMmeIpAddr + '/\' ' + ci_full_config_file, '\$', 2);
 		mySSH.command('sed -i -e \'s/CI_ENB_IP_ADDR/' + lIpAddr + '/\' ' + ci_full_config_file, '\$', 2);
 		mySSH.command('sed -i -e \'s/CI_GNB_IP_ADDR/' + lIpAddr + '/\' ' + ci_full_config_file, '\$', 2);
 		mySSH.command('sed -i -e \'s/CI_RCC_IP_ADDR/' + self.eNBIPAddress + '/\' ' + ci_full_config_file, '\$', 2);
 		mySSH.command('sed -i -e \'s/CI_RRU1_IP_ADDR/' + self.eNB1IPAddress + '/\' ' + ci_full_config_file, '\$', 2);
 		mySSH.command('sed -i -e \'s/CI_RRU2_IP_ADDR/' + self.eNB2IPAddress + '/\' ' + ci_full_config_file, '\$', 2);
 		mySSH.command('sed -i -e \'s/CI_FR1_CTL_ENB_IP_ADDR/' + self.eNBIPAddress + '/\' ' + ci_full_config_file, '\$', 2);
-		if self.flexranCtrlInstalled and self.flexranCtrlStarted:
+		if (self.flexranCtrlInstalled and self.flexranCtrlStarted) or self.flexranCtrlDeployed:
 			mySSH.command('sed -i -e \'s/FLEXRAN_ENABLED.*;/FLEXRAN_ENABLED        = "yes";/\' ' + ci_full_config_file, '\$', 2);
+			mySSH.command('sed -i -e \'s/CI_FLEXRAN_CTL_IP_ADDR/' + self.flexranCtrlIpAddress + '/\' ' + ci_full_config_file, '\$', 2);
 		else:
 			mySSH.command('sed -i -e \'s/FLEXRAN_ENABLED.*;/FLEXRAN_ENABLED        = "no";/\' ' + ci_full_config_file, '\$', 2);
 		self.eNBmbmsEnables[int(self.eNB_instance)] = False
@@ -452,14 +442,13 @@ class RANManagement():
 				mySSH.close()
 				doLoop = False
 				logging.error('\u001B[1;37;41m eNB/gNB/ocp-eNB logging system did not show got sync! \u001B[0m')
-				if self.htmlObj is not None:
-					self.htmlObj.CreateHtmlTestRow(self.air_interface[self.eNB_instance] + ' -O ' + config_file + extra_options, 'KO', CONST.ALL_PROCESSES_OK)
+				HTML.CreateHtmlTestRow(self.air_interface[self.eNB_instance] + ' -O ' + config_file + extra_options, 'KO', CONST.ALL_PROCESSES_OK)
 				# In case of T tracer recording, we need to kill tshark on EPC side
 				result = re.search('T_stdout', str(self.Initialize_eNB_args))
-				if (result is not None) and (self.epcObj is not None):
-					localEpcIpAddr = self.epcObj.IPAddress
-					localEpcUserName = self.epcObj.UserName
-					localEpcPassword = self.epcObj.Password
+				if (result is not None):
+					localEpcIpAddr = EPC.IPAddress
+					localEpcUserName = EPC.UserName
+					localEpcPassword = EPC.Password
 					mySSH.open(localEpcIpAddr, localEpcUserName, localEpcPassword)
 					logging.debug('\u001B[1m Stopping tshark \u001B[0m')
 					mySSH.command('echo ' + localEpcPassword + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5)
@@ -507,11 +496,10 @@ class RANManagement():
 				else:
 					logging.error('\u001B[1m oaitun_enm1 interface is either NOT mounted or NOT configured\u001B[0m')
 		if enbDidSync:
-			self.eNBstatuses[int(self.eNB_instance)] = int(self.eNB_serverId)
+			self.eNBstatuses[int(self.eNB_instance)] = int(self.eNB_serverId[self.eNB_instance])
 
 		mySSH.close()
-		if self.htmlObj is not None:
-			self.htmlObj.CreateHtmlTestRow(self.air_interface[self.eNB_instance] + ' -O ' + config_file + extra_options, 'OK', CONST.ALL_PROCESSES_OK)
+		HTML.CreateHtmlTestRow(self.air_interface[self.eNB_instance] + ' -O ' + config_file + extra_options, 'OK', CONST.ALL_PROCESSES_OK)
 		logging.debug('\u001B[1m Initialize eNB/gNB/ocp-eNB Completed\u001B[0m')
 
 	def CheckeNBProcess(self, status_queue):
@@ -546,18 +534,18 @@ class RANManagement():
 		except:
 			os.kill(os.getppid(),signal.SIGUSR1)
 
-	def TerminateeNB(self):
-		if self.eNB_serverId == '0':
+	def TerminateeNB(self, HTML, EPC):
+		if self.eNB_serverId[self.eNB_instance] == '0':
 			lIpAddr = self.eNBIPAddress
 			lUserName = self.eNBUserName
 			lPassWord = self.eNBPassword
 			lSourcePath = self.eNBSourceCodePath
-		elif self.eNB_serverId == '1':
+		elif self.eNB_serverId[self.eNB_instance] == '1':
 			lIpAddr = self.eNB1IPAddress
 			lUserName = self.eNB1UserName
 			lPassWord = self.eNB1Password
 			lSourcePath = self.eNB1SourceCodePath
-		elif self.eNB_serverId == '2':
+		elif self.eNB_serverId[self.eNB_instance] == '2':
 			lIpAddr = self.eNB2IPAddress
 			lUserName = self.eNB2UserName
 			lPassWord = self.eNB2Password
@@ -565,6 +553,7 @@ class RANManagement():
 		if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '':
 			HELP.GenericHelp(CONST.Version)
 			sys.exit('Insufficient Parameter')
+		logging.debug('Stopping eNB/gNB on server: ' + lIpAddr)
 		mySSH = SSH.SSHConnection()
 		mySSH.open(lIpAddr, lUserName, lPassWord)
 		mySSH.command('cd ' + lSourcePath + '/cmake_targets', '\$', 5)
@@ -586,10 +575,10 @@ class RANManagement():
 		mySSH.close()
 		# If tracer options is on, stopping tshark on EPC side
 		result = re.search('T_stdout', str(self.Initialize_eNB_args))
-		if (result is not None) and (self.epcObj is not None):
-			localEpcIpAddr = self.epcObj.IPAddress
-			localEpcUserName = self.epcObj.UserName
-			localEpcPassword = self.epcObj.Password
+		if (result is not None):
+			localEpcIpAddr = EPC.IPAddress
+			localEpcUserName = EPC.UserName
+			localEpcPassword = EPC.Password
 			mySSH.open(localEpcIpAddr, localEpcUserName, localEpcPassword)
 			logging.debug('\u001B[1m Stopping tshark \u001B[0m')
 			mySSH.command('echo ' + localEpcPassword + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5)
@@ -613,9 +602,8 @@ class RANManagement():
 			mySSH.close()
 			mySSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/' + extracted_log_file, '.')
 			logging.debug('\u001B[1m Analyzing eNB replay logfile \u001B[0m')
-			logStatus = self.AnalyzeLogFile_eNB(extracted_log_file)
-			if self.htmlObj is not None:
-				self.htmlObj.CreateHtmlTestRow(self.runtime_stats, 'OK', CONST.ALL_PROCESSES_OK)
+			logStatus = self.AnalyzeLogFile_eNB(extracted_log_file, HTML)
+			HTML.CreateHtmlTestRow(self.runtime_stats, 'OK', CONST.ALL_PROCESSES_OK)
 			self.eNBLogFiles[int(self.eNB_instance)] = ''
 		else:
 			analyzeFile = False
@@ -627,27 +615,23 @@ class RANManagement():
 				copyin_res = mySSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/' + fileToAnalyze, '.')
 				if (copyin_res == -1):
 					logging.debug('\u001B[1;37;41m Could not copy ' + nodeB_prefix + 'NB logfile to analyze it! \u001B[0m')
-					if self.htmlObj is not None:
-						self.htmlObj.htmleNBFailureMsg='Could not copy ' + nodeB_prefix + 'NB logfile to analyze it!'
-						self.htmlObj.CreateHtmlTestRow('N/A', 'KO', CONST.ENB_PROCESS_NOLOGFILE_TO_ANALYZE)
+					HTML.htmleNBFailureMsg='Could not copy ' + nodeB_prefix + 'NB logfile to analyze it!'
+					HTML.CreateHtmlTestRow('N/A', 'KO', CONST.ENB_PROCESS_NOLOGFILE_TO_ANALYZE)
 					self.eNBmbmsEnables[int(self.eNB_instance)] = False
 					return
-				if self.eNB_serverId != '0':
+				if self.eNB_serverId[self.eNB_instance] != '0':
 					mySSH.copyout(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, './' + fileToAnalyze, self.eNBSourceCodePath + '/cmake_targets/')
 				logging.debug('\u001B[1m Analyzing ' + nodeB_prefix + 'NB logfile \u001B[0m ' + fileToAnalyze)
-				logStatus = self.AnalyzeLogFile_eNB(fileToAnalyze)
+				logStatus = self.AnalyzeLogFile_eNB(fileToAnalyze, HTML)
 				if (logStatus < 0):
-					if self.htmlObj is not None:
-						self.htmlObj.CreateHtmlTestRow('N/A', 'KO', logStatus)
+					HTML.CreateHtmlTestRow('N/A', 'KO', logStatus)
 					self.preamtureExit = True
 					self.eNBmbmsEnables[int(self.eNB_instance)] = False
 					return
 				else:
-					if self.htmlObj is not None:
-						self.htmlObj.CreateHtmlTestRow(self.runtime_stats, 'OK', CONST.ALL_PROCESSES_OK)
+					HTML.CreateHtmlTestRow(self.runtime_stats, 'OK', CONST.ALL_PROCESSES_OK)
 			else:
-				if self.htmlObj is not None:
-					self.htmlObj.CreateHtmlTestRow(self.runtime_stats, 'OK', CONST.ALL_PROCESSES_OK)
+				HTML.CreateHtmlTestRow(self.runtime_stats, 'OK', CONST.ALL_PROCESSES_OK)
 		self.eNBmbmsEnables[int(self.eNB_instance)] = False
 		self.eNBstatuses[int(self.eNB_instance)] = -1
 
@@ -661,7 +645,7 @@ class RANManagement():
 		mySSH.command('echo ' + self.eNBPassword + ' | sudo -S rm enb*.log core* enb_*record.raw enb_*.pcap enb_*txt', '\$', 5)
 		mySSH.close()
 
-	def AnalyzeLogFile_eNB(self, eNBlogFile):
+	def AnalyzeLogFile_eNB(self, eNBlogFile, HTML):
 		if (not os.path.isfile('./' + eNBlogFile)):
 			return -1
 		enb_log_file = open('./' + eNBlogFile, 'r')
@@ -709,7 +693,11 @@ class RANManagement():
 		NSA_RAPROC_PUSCH_check = 0
 		#dlsch and ulsch statistics (dictionary)
 		dlsch_ulsch_stats = {}
-		
+		#count "L1 thread not ready" msg 	
+		L1_thread_not_ready_cnt = 0
+		#count "problem receiving samples" msg
+		pb_receiving_samples_cnt = 0
+	
 		for line in enb_log_file.readlines():
 			# Runtime statistics
 			result = re.search('Run time:' ,str(line))
@@ -874,6 +862,15 @@ 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())
+			#count "L1 thread not ready" msg
+			result = re.search('\[PHY\]\s+L1_thread isn\'t ready', str(line))
+			if result is not None:
+				L1_thread_not_ready_cnt += 1	
+			#count "problem receiving samples" msg
+			result = re.search('\[PHY\]\s+problem receiving samples', str(line))
+			if result is not None:
+				pb_receiving_samples_cnt += 1				
+
 		enb_log_file.close()
 		logging.debug('   File analysis completed')
 		if (self.air_interface[self.eNB_instance] == 'lte-softmodem') or (self.air_interface[self.eNB_instance] == 'ocp-enb'):
@@ -903,6 +900,17 @@ class RANManagement():
 				htmlMsg = statMsg+'\n'
 			logging.debug(statMsg)
 			htmleNBFailureMsg += htmlMsg
+			#L1 thread not ready log
+			statMsg = '[PHY] L1 thread is not ready msg count =  '+str(L1_thread_not_ready_cnt)
+			htmlMsg = statMsg+'\n'
+			logging.debug(statMsg)
+			htmleNBFailureMsg += htmlMsg
+			#problem receiving samples log
+			statMsg = '[PHY] problem receiving samples msg count =  '+str(pb_receiving_samples_cnt)
+			htmlMsg = statMsg+'\n'
+			logging.debug(statMsg)
+			htmleNBFailureMsg += htmlMsg
+
 			#ulsch and dlsch statistics
 			if len(dlsch_ulsch_stats)!=0: #check if dictionary is not empty
 				statMsg=''
@@ -1018,8 +1026,7 @@ class RANManagement():
 			logging.debug('\u001B[1;37;41m ' + rlcMsg + ' \u001B[0m')
 			htmleNBFailureMsg += rlcMsg + '\n'
 			global_status = CONST.ENB_PROCESS_REALTIME_ISSUE
-		if self.htmlObj is not None:
-			self.htmlObj.htmleNBFailureMsg=htmleNBFailureMsg
+		HTML.htmleNBFailureMsg=htmleNBFailureMsg
 		# Runtime statistics for console output and HTML
 		if runTime != '':
 			logging.debug(runTime)
diff --git a/ci-scripts/runTestOnVM.sh b/ci-scripts/runTestOnVM.sh
index 6c87f5dac33bdee9d67078413c75f0f60a1ff2d5..70eabb7b695ecc4218c2d80143e47f3ff8124b0b 100755
--- a/ci-scripts/runTestOnVM.sh
+++ b/ci-scripts/runTestOnVM.sh
@@ -2200,7 +2200,7 @@ function run_test_on_vm {
             mkdir --parents $ARCHIVES_LOC
         fi
 
-        local try_cnt="0"
+        local try_cnt=0
         NR_STATUS=0
 
         ######### start of RA TEST loop
@@ -2232,7 +2232,7 @@ function run_test_on_vm {
                 scp -o StrictHostKeyChecking=no ubuntu@$GNB_VM_IP_ADDR:/home/ubuntu/tmp/cmake_targets/log/$CURRENT_GNB_LOG_FILE $ARCHIVES_LOC
                 scp -o StrictHostKeyChecking=no ubuntu@$NR_UE_VM_IP_ADDR:/home/ubuntu/tmp/cmake_targets/log/$CURRENT_NR_UE_LOG_FILE $ARCHIVES_LOC
                 SYNC_STATUS=-1
-                try_cnt=$[$try_cnt+1]
+                try_cnt=$((try_cnt+1))
                 continue
             fi
 
@@ -2255,9 +2255,10 @@ function run_test_on_vm {
             if [ $RA_STATUS -ne 0 ]
             then
                 echo "RA test NOT OK"
-                try_cnt=$[$try_cnt+1]
+                echo "try_cnt = " $try_cnt
+                try_cnt=$((try_cnt+1))
             else
-                try_cnt=$[$try_cnt+10]
+                try_cnt=$((try_cnt+10))
             fi
         done
         ########### end RA test
@@ -2266,7 +2267,7 @@ function run_test_on_vm {
 
 
         ######### start of PHY TEST loop
-        try_cnt="0"
+        try_cnt=0
         while [ $try_cnt -lt 4 ]
         do
 
@@ -2297,7 +2298,7 @@ function run_test_on_vm {
                 scp -o StrictHostKeyChecking=no ubuntu@$GNB_VM_IP_ADDR:/home/ubuntu/tmp/cmake_targets/log/$CURRENT_GNB_LOG_FILE $ARCHIVES_LOC
                 scp -o StrictHostKeyChecking=no ubuntu@$NR_UE_VM_IP_ADDR:/home/ubuntu/tmp/cmake_targets/log/$CURRENT_NR_UE_LOG_FILE $ARCHIVES_LOC
                 SYNC_STATUS=-1
-                try_cnt=$[$try_cnt+1]
+                try_cnt=$((try_cnt+1))
                 continue
             fi
 
@@ -2337,7 +2338,7 @@ function run_test_on_vm {
                 terminate_enb_ue_basic_sim $GNB_VM_CMDS $GNB_VM_IP_ADDR 1
                 scp -o StrictHostKeyChecking=no ubuntu@$GNB_VM_IP_ADDR:/home/ubuntu/tmp/cmake_targets/log/$CURRENT_GNB_LOG_FILE $ARCHIVES_LOC
                 scp -o StrictHostKeyChecking=no ubuntu@$NR_UE_VM_IP_ADDR:/home/ubuntu/tmp/cmake_targets/log/$CURRENT_NR_UE_LOG_FILE $ARCHIVES_LOC
-                try_cnt=$[$try_cnt+1]
+                try_cnt=$((try_cnt+1))
                 continue
             fi
 
@@ -2363,9 +2364,9 @@ function run_test_on_vm {
             if [ $IPERF_STATUS -ne 0 ]
             then
                 echo "UL test not OK"
-                try_cnt=$[$try_cnt+1]
+                try_cnt=$((try_cnt+1))
             else
-                try_cnt=$[$try_cnt+10]
+                try_cnt=$((try_cnt+10))
             fi
         done
         ######### end of loop
diff --git a/ci-scripts/tcp_iperf_stats.awk b/ci-scripts/tcp_iperf_stats.awk
index 3a00e4555f744fa8cf2ce87c9baad3067ddc3bc1..b21bf16a2ff7e2b2b0f8c85759671766fd501f24 100644
--- a/ci-scripts/tcp_iperf_stats.awk
+++ b/ci-scripts/tcp_iperf_stats.awk
@@ -21,7 +21,11 @@
 BEGIN{max=0;min=10000}
 {
     if ($0 ~/Mbits/) {
-        split($0,a,"MBytes")
+        if ($0 ~/KBytes/) {
+            split($0,a,"KBytes")
+        } else {
+            split($0,a,"MBytes")
+        }
         split(a[2],b)
         if (b[1]>max) {
             max=b[1]
diff --git a/ci-scripts/xml_class_list.yml b/ci-scripts/xml_class_list.yml
index 2c20988851e7e6565f99d553b27455be53f62e85..0e00a2e7d413da5784e7c88210335bfa335406ec 100755
--- a/ci-scripts/xml_class_list.yml
+++ b/ci-scripts/xml_class_list.yml
@@ -19,6 +19,8 @@
   - Reboot_UE
   - Initialize_FlexranCtrl
   - Terminate_FlexranCtrl
+  - Deploy_EPC
+  - Undeploy_EPC
   - Initialize_HSS
   - Terminate_HSS
   - Initialize_MME
@@ -32,3 +34,6 @@
   - Ping_CatM_module
   - IdleSleep
   - Perform_X2_Handover
+  - Build_Image
+  - Deploy_Object
+  - Undeploy_Object
diff --git a/ci-scripts/xml_files/fr1_image_build.xml b/ci-scripts/xml_files/fr1_image_build.xml
new file mode 100644
index 0000000000000000000000000000000000000000..9dd386b646cd6e1975882e62f49852700efd5cf8
--- /dev/null
+++ b/ci-scripts/xml_files/fr1_image_build.xml
@@ -0,0 +1,40 @@
+<!--
+
+ 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
+
+-->
+<testCaseList>
+	<htmlTabRef>build-tab</htmlTabRef>
+	<htmlTabName>Build</htmlTabName>
+	<htmlTabIcon>wrench</htmlTabIcon>
+	<TestCaseRequestedList>
+ 000001
+	</TestCaseRequestedList>
+	<TestCaseExclusionList></TestCaseExclusionList>
+
+	<testCase id="000001">
+		<class>Build_Image</class>
+		<desc>Build eNB Image</desc>
+		<kind>all</kind>
+		<eNB_instance>0</eNB_instance>
+		<eNB_serverId>0</eNB_serverId>
+	</testCase>
+
+</testCaseList>
diff --git a/ci-scripts/xml_files/fr1_oai_cn_deploy.xml b/ci-scripts/xml_files/fr1_oai_cn_deploy.xml
new file mode 100644
index 0000000000000000000000000000000000000000..919def7aa39c2ec33891132ffe01d83f493049fc
--- /dev/null
+++ b/ci-scripts/xml_files/fr1_oai_cn_deploy.xml
@@ -0,0 +1,39 @@
+<!--
+
+ 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
+
+-->
+<testCaseList>
+	<htmlTabRef>epc-deploy-tab</htmlTabRef>
+	<htmlTabName>EPC-Deploy</htmlTabName>
+	<htmlTabIcon>log-in</htmlTabIcon>
+	<TestCaseRequestedList>
+ 000100
+	</TestCaseRequestedList>
+	<TestCaseExclusionList>
+	</TestCaseExclusionList>
+
+	<testCase id="000100">
+		<class>Deploy_EPC</class>
+		<desc>Deploy all EPC containers</desc>
+		<parameters>yaml_files/fr1_epc_tim</parameters>
+	</testCase>
+
+</testCaseList>
diff --git a/ci-scripts/xml_files/fr1_oai_cn_undeploy.xml b/ci-scripts/xml_files/fr1_oai_cn_undeploy.xml
new file mode 100644
index 0000000000000000000000000000000000000000..76192efea14f0e5b0c9b48fb30fe0f6b9756fd61
--- /dev/null
+++ b/ci-scripts/xml_files/fr1_oai_cn_undeploy.xml
@@ -0,0 +1,38 @@
+<!--
+
+ 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
+
+-->
+<testCaseList>
+	<htmlTabRef>epc-undeploy-tab</htmlTabRef>
+	<htmlTabName>EPC-Undeploy</htmlTabName>
+	<htmlTabIcon>log-out</htmlTabIcon>
+	<TestCaseRequestedList>
+ 000200
+	</TestCaseRequestedList>
+	<TestCaseExclusionList>
+	</TestCaseExclusionList>
+
+	<testCase id="000200">
+		<class>Undeploy_EPC</class>
+		<desc>Undeploy all EPC containers</desc>
+	</testCase>
+
+</testCaseList>
diff --git a/ci-scripts/xml_files/fr1_ran_ue_base.xml b/ci-scripts/xml_files/fr1_ran_ue_base.xml
new file mode 100644
index 0000000000000000000000000000000000000000..847967f81e9f9808d982f89615eed1c1be9a079d
--- /dev/null
+++ b/ci-scripts/xml_files/fr1_ran_ue_base.xml
@@ -0,0 +1,150 @@
+<!--
+
+ 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
+
+-->
+<testCaseList>
+	<htmlTabRef>TEST-FR1-TM1</htmlTabRef>
+	<htmlTabName>FR1</htmlTabName>
+	<htmlTabIcon>tasks</htmlTabIcon>
+	<TestCaseRequestedList>
+ 010000
+ 030000
+ 040000
+ 010001
+ 000001
+ 050000
+ 050001
+ 050002
+ 050002
+ 000001
+ 060000
+ 060001
+ 000001
+ 010002
+ 000001
+ 070001
+ 070000
+ 010003
+	</TestCaseRequestedList>
+	<TestCaseExclusionList></TestCaseExclusionList>
+
+	<testCase id="010000">
+		<class>Initialize_UE</class>
+		<desc>Initialize UE</desc>
+	</testCase>
+
+	<testCase id="010003">
+		<class>Terminate_UE</class>
+		<desc>Terminate UE</desc>
+	</testCase>
+
+	<testCase id="010001">
+		<class>Attach_UE</class>
+		<desc>Attach UE</desc>
+	</testCase>
+
+	<testCase id="010002">
+		<class>Detach_UE</class>
+		<desc>Detach UE</desc>
+	</testCase>
+
+
+	<testCase id="030000">
+		<class>Initialize_eNB</class>
+		<desc>Initialize eNB</desc>
+		<Initialize_eNB_args>-O ci-scripts/conf_files/enb.band7.tm1.fr1.25PRB.usrpb210.conf</Initialize_eNB_args>
+		<eNB_instance>0</eNB_instance>
+		<eNB_serverId>0</eNB_serverId>
+		<air_interface>lte</air_interface>
+   </testCase>
+
+
+	<testCase id="040000">
+		<class>Initialize_eNB</class>
+		<desc>Initialize gNB</desc>
+		<Initialize_eNB_args>-O ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpb210.conf -E</Initialize_eNB_args>
+		<eNB_instance>1</eNB_instance>
+		<eNB_serverId>1</eNB_serverId>
+		<air_interface>nr</air_interface>
+	</testCase>
+
+	<testCase id="000001">
+		<class>IdleSleep</class>
+		<desc>Sleep</desc>
+		<idle_sleep_time_in_sec>20</idle_sleep_time_in_sec>
+	</testCase>
+
+	<testCase id="050000">
+		<class>Ping</class>
+		<desc>Ping: 20pings in 20sec</desc>
+		<ping_args>-c 20</ping_args>
+		<ping_packetloss_threshold>50</ping_packetloss_threshold>
+	</testCase>
+
+	<testCase id="050001">
+		<class>Ping</class>
+		<desc>Ping: 5pings in 1sec</desc>
+		<ping_args>-c 5 -i 0.2</ping_args>
+		<ping_packetloss_threshold>50</ping_packetloss_threshold>
+	</testCase>
+
+	<testCase id="050002">
+		<class>Ping</class>
+		<desc>Ping: 100pings in 20sec</desc>
+		<ping_args>-c 100 -i 0.2</ping_args>
+		<ping_packetloss_threshold>50</ping_packetloss_threshold>
+	</testCase>
+
+
+	<testCase id="060000">
+		<class>Iperf</class>
+		<desc>iperf (DL/1Mbps/UDP)(30 sec)(single-ue profile)</desc>
+		<iperf_args>-u -b 1M -t 30 -i 1</iperf_args>
+		<iperf_packetloss_threshold>50</iperf_packetloss_threshold>
+		<iperf_profile>single-ue</iperf_profile>
+	</testCase>
+
+	<testCase id="060001">
+		<class>Iperf</class>
+		<desc>iperf (UL/1Mbps/UDP)(30 sec)(single-ue profile)</desc>
+		<iperf_args>-u -b 1M -t 30 -i 1 -R</iperf_args>
+		<iperf_packetloss_threshold>50</iperf_packetloss_threshold>
+		<iperf_profile>single-ue</iperf_profile>
+	</testCase>
+
+	<testCase id="070000">
+		<class>Terminate_eNB</class>
+		<desc>Terminate eNB</desc>
+		<eNB_instance>0</eNB_instance>
+		<eNB_serverId>0</eNB_serverId>
+		<air_interface>lte</air_interface>
+	</testCase>
+
+	<testCase id="070001">
+		<class>Terminate_eNB</class>
+		<desc>Terminate gNB</desc>
+		<eNB_instance>1</eNB_instance>
+		<eNB_serverId>1</eNB_serverId>
+		<air_interface>nr</air_interface>
+	</testCase>
+
+</testCaseList>
+
diff --git a/ci-scripts/xml_files/fr1_ran_ue_proc.xml b/ci-scripts/xml_files/fr1_ran_ue_iperf.xml
similarity index 81%
rename from ci-scripts/xml_files/fr1_ran_ue_proc.xml
rename to ci-scripts/xml_files/fr1_ran_ue_iperf.xml
index 446433ec306a34b88da01b573ab6ff80ea1a3d8b..8ead3afc62ee152e39cc03bc389c53b4409b3be9 100644
--- a/ci-scripts/xml_files/fr1_ran_ue_proc.xml
+++ b/ci-scripts/xml_files/fr1_ran_ue_iperf.xml
@@ -31,9 +31,9 @@
  010001
  000001
  050000
- 050001
- 050002
- 050003
+ 000001
+ 060000
+ 060001
  000001
  010002
  000001
@@ -93,29 +93,25 @@
 		<class>Ping</class>
 		<desc>Ping: 20pings in 20sec</desc>
 		<ping_args>-c 20</ping_args>
-		<ping_packetloss_threshold>0</ping_packetloss_threshold>
+		<ping_packetloss_threshold>50</ping_packetloss_threshold>
 	</testCase>
 
-	<testCase id="050001">
-		<class>Ping</class>
-		<desc>Ping: 5pings in 1sec</desc>
-		<ping_args>-c 5 -i 0.2</ping_args>
-		<ping_packetloss_threshold>0</ping_packetloss_threshold>
-	</testCase>
 
-	<testCase id="050002">
-		<class>Ping</class>
-		<desc>Ping: 100pings in 20sec</desc>
-		<ping_args>-c 100 -i 0.2</ping_args>
-		<ping_packetloss_threshold>0</ping_packetloss_threshold>
+	<testCase id="060000">
+		<class>Iperf</class>
+		<desc>iperf (DL/2.5Mbps/UDP)(60 sec)(single-ue profile)</desc>
+		<iperf_args>-u -b 2.5M -t 60 -i 1</iperf_args>
+		<iperf_packetloss_threshold>50</iperf_packetloss_threshold>
+		<iperf_profile>single-ue</iperf_profile>
 	</testCase>
 
-	<testCase id="050003">$
-	<class>Ping</class>$
-	<desc>Ping: 100pings in 20sec size 1000</desc>$
-	<ping_args>-c 100 -i 0.2 -s 1000</ping_args>$
-	<ping_packetloss_threshold>0</ping_packetloss_threshold>$
-	</testCase>$
+	<testCase id="060001">
+		<class>Iperf</class>
+		<desc>iperf (UL/1.5Mbps/UDP)(60 sec)(single-ue profile)</desc>
+		<iperf_args>-u -b 1.5M -t 60 -i 1 -R</iperf_args>
+		<iperf_packetloss_threshold>50</iperf_packetloss_threshold>
+		<iperf_profile>single-ue</iperf_profile>
+	</testCase>
 
 	<testCase id="070000">
 		<class>Terminate_eNB</class>
diff --git a/ci-scripts/xml_files/fr1_usrp210_band7_deploy_test_05mhz_tm1.xml b/ci-scripts/xml_files/fr1_usrp210_band7_deploy_test_05mhz_tm1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3d04fdeb2997e03d63152c017307144cf3c80f46
--- /dev/null
+++ b/ci-scripts/xml_files/fr1_usrp210_band7_deploy_test_05mhz_tm1.xml
@@ -0,0 +1,133 @@
+<!--
+
+ 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
+
+-->
+<testCaseList>
+	<htmlTabRef>test-deploy-enb-mono</htmlTabRef>
+	<htmlTabName>Test-Deploy-eNB-Mono</htmlTabName>
+	<htmlTabIcon>tasks</htmlTabIcon>
+	<repeatCount>1</repeatCount>
+	<TestCaseRequestedList>
+ 040101
+ 030101 000020 040301 000021 040501 040601 040611 040641 040651 040401 040201 030201
+	</TestCaseRequestedList>
+	<TestCaseExclusionList></TestCaseExclusionList>
+
+	<testCase id="000001">
+		<class>IdleSleep</class>
+		<desc>Waiting for 60 seconds</desc>
+		<idle_sleep_time_in_sec>60</idle_sleep_time_in_sec>
+	</testCase>
+
+	<testCase id="000002">
+		<class>IdleSleep</class>
+		<desc>Waiting for 10 seconds</desc>
+		<idle_sleep_time_in_sec>10</idle_sleep_time_in_sec>
+	</testCase>
+
+    <testCase id="000020">
+        <class>CheckStatusUE</class>
+        <desc>Check UE(s) status before attachment</desc>
+        <expectedNbOfConnectedUEs>0</expectedNbOfConnectedUEs>
+    </testCase>
+
+    <testCase id="000021">
+        <class>CheckStatusUE</class>
+        <desc>Check UE(s) status after attachment</desc>
+        <expectedNbOfConnectedUEs>1</expectedNbOfConnectedUEs>
+    </testCase>
+
+	<testCase id="030101">
+		<class>Deploy_Object</class>
+		<desc>Deploy eNB (FDD/Band7/5MHz) in a container</desc>
+		<yaml_path>ci-scripts/yaml_files/fr1_enb_mono_fdd_tim</yaml_path>
+		<eNB_instance>0</eNB_instance>
+		<eNB_serverId>0</eNB_serverId>
+	</testCase>
+
+	<testCase id="030201">
+		<class>Undeploy_Object</class>
+		<desc>Undeploy eNB</desc>
+		<yaml_path>ci-scripts/yaml_files/fr1_enb_mono_fdd_tim</yaml_path>
+		<eNB_instance>0</eNB_instance>
+		<eNB_serverId>0</eNB_serverId>
+	</testCase>
+
+	<testCase id="040101">
+		<class>Initialize_UE</class>
+		<desc>Initialize UE</desc>
+	</testCase>
+
+	<testCase id="040201">
+		<class>Terminate_UE</class>
+		<desc>Terminate UE</desc>
+	</testCase>
+
+	<testCase id="040301">
+		<class>Attach_UE</class>
+		<desc>Attach UE</desc>
+	</testCase>
+
+	<testCase id="040401">
+		<class>Detach_UE</class>
+		<desc>Detach UE</desc>
+	</testCase>
+
+	<testCase id="040501">
+		<class>Ping</class>
+		<desc>ping (5MHz - 20 sec)</desc>
+		<ping_args>-c 20</ping_args>
+		<ping_packetloss_threshold>5</ping_packetloss_threshold>
+	</testCase>
+
+	<testCase id="040601">
+		<class>Iperf</class>
+		<desc>iperf (5MHz - DL/15Mbps/UDP)(30 sec)</desc>
+		<iperf_args>-u -b 15M -t 30 -i 1</iperf_args>
+		<iperf_packetloss_threshold>50</iperf_packetloss_threshold>
+		<iperf_profile>single-ue</iperf_profile>
+	</testCase>
+
+	<testCase id="040611">
+		<class>Iperf</class>
+		<desc>iperf (5MHz - DL/TCP)(30 sec)</desc>
+		<iperf_args>-t 30 -i 1</iperf_args>
+		<iperf_packetloss_threshold>50</iperf_packetloss_threshold>
+		<iperf_profile>single-ue</iperf_profile>
+	</testCase>
+
+	<testCase id="040641">
+		<class>Iperf</class>
+		<desc>iperf (5MHz - UL/7.5Mbps/UDP)(30 sec)</desc>
+		<iperf_args>-u -b 7.5M -t 30 -i 1 -R</iperf_args>
+		<iperf_packetloss_threshold>50</iperf_packetloss_threshold>
+		<iperf_profile>single-ue</iperf_profile>
+	</testCase>
+
+	<testCase id="040651">
+		<class>Iperf</class>
+		<desc>iperf (5MHz - UL/TCP)(30 sec)</desc>
+		<iperf_args>-t 30 -i 1 -R</iperf_args>
+		<iperf_packetloss_threshold>50</iperf_packetloss_threshold>
+		<iperf_profile>single-ue</iperf_profile>
+	</testCase>
+
+</testCaseList>
diff --git a/ci-scripts/yaml_files/fr1_enb_mono_fdd_tim/docker-compose.yml b/ci-scripts/yaml_files/fr1_enb_mono_fdd_tim/docker-compose.yml
new file mode 100644
index 0000000000000000000000000000000000000000..2df277d78baa8c43a6cdb15cbda2735e7d2eb9e5
--- /dev/null
+++ b/ci-scripts/yaml_files/fr1_enb_mono_fdd_tim/docker-compose.yml
@@ -0,0 +1,49 @@
+version: '3.8'
+
+services:
+    enb_mono_fdd:
+        image: oai-enb:latest
+        privileged: true
+        container_name: prod-enb-mono-fdd
+        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: 10
+            NB_PRB: 25
+            MME_S1C_IP_ADDRESS: CI_MME_IP_ADDR
+            ENB_S1C_IF_NAME: eth0
+            ENB_S1C_IP_ADDRESS: 192.168.61.30
+            ENB_S1U_IF_NAME: eth0
+            ENB_S1U_IP_ADDRESS: 192.168.61.30
+            ENB_X2_IP_ADDRESS: 192.168.61.30
+            FLEXRAN_ENABLED: 'no'
+            FLEXRAN_INTERFACE_NAME: eth0
+            FLEXRAN_IPV4_ADDRESS: CI_FLEXRAN_CTL_IP_ADDR
+            USE_ADDITIONAL_OPTIONS: '--RUs.[0].max_rxgain 115 --RUs.[0].max_pdschReferenceSignalPower -27 --eNBs.[0].component_carriers.[0].pucch_p0_Nominal -96'
+        volumes:
+            - /dev:/dev
+        networks:
+            public_net:
+                ipv4_address: 192.168.61.30
+        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: prod-oai-public-net
+        ipam:
+            config:
+                - subnet: 192.168.61.0/26
+
diff --git a/ci-scripts/yaml_files/fr1_epc_tim/docker-compose.yml b/ci-scripts/yaml_files/fr1_epc_tim/docker-compose.yml
new file mode 100644
index 0000000000000000000000000000000000000000..28ae154838aed5b750eb9954ef7467f05318198d
--- /dev/null
+++ b/ci-scripts/yaml_files/fr1_epc_tim/docker-compose.yml
@@ -0,0 +1,203 @@
+version: '3.8'
+
+services:
+    cassandra:
+        image: cassandra:2.1
+        container_name: prod-cassandra
+        networks:
+            private_net:
+                ipv4_address: 192.168.68.2
+        environment:
+            CASSANDRA_CLUSTER_NAME: "OAI HSS Cluster"
+            CASSANDRA_ENDPOINT_SNITCH: GossipingPropertyFileSnitch
+        healthcheck:
+            test: /bin/bash -c "nodetool status"
+            interval: 10s
+            timeout: 5s
+            retries: 5
+
+    db_init:
+        image: cassandra:2.1
+        container_name: prod-db-init
+        depends_on: [cassandra]
+        deploy:
+            restart_policy:
+                condition: on-failure
+                max_attempts: 10
+        networks:
+            private_net:
+                ipv4_address: 192.168.68.4
+        volumes:
+            - ./oai_db.cql:/home/oai_db.cql
+        entrypoint: /bin/bash -c "cqlsh --file /home/oai_db.cql 192.168.68.2 && echo 'OK'"
+
+    oai_hss:
+        image: oai-hss:production
+        container_name: prod-oai-hss
+        privileged: true
+        depends_on: [cassandra]
+        networks:
+            private_net:
+                ipv4_address: 192.168.68.3
+            public_net:
+                ipv4_address: 192.168.61.2
+        environment:
+            REALM: openairinterface.org
+            HSS_FQDN: hss.openairinterface.org
+            PREFIX: /openair-hss/etc
+            cassandra_Server_IP: 192.168.68.2
+            OP_KEY: 1006020f0a478bf6b699f15c062e42b3
+            LTE_K: fec86ba6eb707ed08905757b1bb44b8f
+            APN1: oai.ipv4
+            APN2: internet
+            FIRST_IMSI: 222010100001120
+            NB_USERS: 10
+        healthcheck:
+            test: /bin/bash -c "pgrep oai_hss"
+            interval: 10s
+            timeout: 5s
+            retries: 5
+
+    oai_mme:
+        image: oai-mme:production
+        container_name: prod-oai-mme
+        privileged: true
+        depends_on: [oai_hss]
+        networks:
+            public_net:
+                ipv4_address: 192.168.61.3
+        environment:
+            REALM: openairinterface.org
+            PREFIX: /openair-mme/etc
+            INSTANCE: 1
+            PID_DIRECTORY: /var/run
+            HSS_IP_ADDR: 192.168.61.2
+            HSS_HOSTNAME: hss
+            HSS_FQDN: hss.openairinterface.org
+            HSS_REALM: openairinterface.org
+            MCC: '222'
+            MNC: '01'
+            MME_GID: 32768
+            MME_CODE: 3
+            TAC_0: 1
+            TAC_1: 2
+            TAC_2: 3
+            MME_FQDN: mme.openairinterface.org
+            MME_S6A_IP_ADDR: 192.168.61.3
+            MME_INTERFACE_NAME_FOR_S1_MME: eth0
+            MME_IPV4_ADDRESS_FOR_S1_MME: 192.168.61.3
+            MME_INTERFACE_NAME_FOR_S11: eth0
+            MME_IPV4_ADDRESS_FOR_S11: 192.168.61.3
+            MME_INTERFACE_NAME_FOR_S10: lo
+            MME_IPV4_ADDRESS_FOR_S10: 127.0.0.10
+            OUTPUT: CONSOLE
+            SGW_IPV4_ADDRESS_FOR_S11_0: 192.168.61.4
+            PEER_MME_IPV4_ADDRESS_FOR_S10_0: 0.0.0.0
+            PEER_MME_IPV4_ADDRESS_FOR_S10_1: 0.0.0.0
+            MCC_SGW_0: '222'
+            MNC3_SGW_0: '001'
+            TAC_LB_SGW_0: '01'
+            TAC_HB_SGW_0: '00'
+            MCC_MME_0: '222'
+            MNC3_MME_0: '001'
+            TAC_LB_MME_0: '02'
+            TAC_HB_MME_0: '00'
+            MCC_MME_1: '222'
+            MNC3_MME_1: '001'
+            TAC_LB_MME_1: '03'
+            TAC_HB_MME_1: '00'
+            TAC_LB_SGW_TEST_0: '03'
+            TAC_HB_SGW_TEST_0: '00'
+            SGW_IPV4_ADDRESS_FOR_S11_TEST_0: 0.0.0.0
+        healthcheck:
+            test: /bin/bash -c "pgrep oai_mme"
+            interval: 10s
+            timeout: 5s
+            retries: 5
+
+    oai_spgwc:
+        image: oai-spgwc:production
+        privileged: true
+        depends_on: [oai_mme]
+        container_name: prod-oai-spgwc
+        networks:
+            public_net:
+                ipv4_address: 192.168.61.4
+        environment:
+            PID_DIRECTORY: /var/run
+            SGW_INTERFACE_NAME_FOR_S11: eth0
+            SGW_IP_FOR_S5_S8_CP: 127.0.0.11/8
+            PGW_IP_FOR_S5_S8_CP: 127.0.0.12/8
+            PGW_INTERFACE_NAME_FOR_SX: eth0
+            DEFAULT_APN: oai.ipv4
+            DEFAULT_DNS_IPV4_ADDRESS: 192.168.18.129
+            DEFAULT_DNS_SEC_IPV4_ADDRESS: 8.8.4.4
+            UE_IP_ADDRESS_POOL: '12.1.1.2 - 12.1.1.254'
+            PUSH_PROTOCOL_OPTION: 'yes'
+        healthcheck:
+            test: /bin/bash -c "pgrep oai_spgwc"
+            interval: 10s
+            timeout: 5s
+            retries: 5
+
+    oai_spgwu:
+        image: oai-spgwu-tiny:production
+        privileged: true
+        container_name: prod-oai-spgwu-tiny
+        depends_on: [oai_spgwc]
+        networks:
+            public_net:
+                ipv4_address: 192.168.61.5
+        environment:
+            PID_DIRECTORY: /var/run
+            INSTANCE: 1
+            SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP: eth0
+            PGW_INTERFACE_NAME_FOR_SGI: eth0
+            SGW_INTERFACE_NAME_FOR_SX: eth0
+            SPGWC0_IP_ADDRESS: 192.168.61.4
+            NETWORK_UE_IP: '12.1.1.0/24'
+            NETWORK_UE_NAT_OPTION: 'yes'
+        healthcheck:
+            test: /bin/bash -c "pgrep oai_spgwu"
+            interval: 10s
+            timeout: 5s
+            retries: 5
+
+    flexran_rtc:
+        image: flexran-rtc:production
+        privileged: true
+        container_name: prod-flexran-rtc
+        networks:
+            public_net:
+                ipv4_address: 192.168.61.10
+        healthcheck:
+            test: /bin/bash -c "pgrep rt_controller"
+            interval: 10s
+            timeout: 5s
+            retries: 5
+
+    trf_gen:
+        image: trf-gen:production
+        privileged: true
+        container_name: prod-trf-gen
+        networks:
+            public_net:
+                ipv4_address: 192.168.61.11
+        entrypoint: /bin/bash -c "ip route add 12.1.1.0/24 via 192.168.61.5 dev eth0; sleep infinity"
+        healthcheck:
+            test: /bin/bash -c "ping -c 2 192.168.61.5"
+            interval: 10s
+            timeout: 5s
+            retries: 5
+
+networks:
+    private_net:
+        name: prod-oai-private-net
+        ipam:
+            config:
+                - subnet: 192.168.68.0/26
+    public_net:
+        name: prod-oai-public-net
+        ipam:
+            config:
+                - subnet: 192.168.61.0/26
diff --git a/cmake_targets/tools/build_helper b/cmake_targets/tools/build_helper
index f76eae7f284684ca0794af3b7ff96c47e54ffcdc..674d4a0cacf5312336a5df55376ba7e2af3aec30 100755
--- a/cmake_targets/tools/build_helper
+++ b/cmake_targets/tools/build_helper
@@ -114,6 +114,8 @@ check_supported_distribution() {
         "rhel7.7")     return 0 ;;
         "rhel7.8")     return 0 ;;
         "rhel8.2")     return 0 ;;
+        "rhel8.3")     return 0 ;;
+        "rhel8.4")     return 0 ;;
         "centos7")     return 0 ;;
     esac
     return 1
diff --git a/doc/BUILD.md b/doc/BUILD.md
index ba5db55cab38822d97d0a41710c6ca2a0e2cab17..bbb06a1e6985adbc28b55b25a87d8e61c350aabd 100644
--- a/doc/BUILD.md
+++ b/doc/BUILD.md
@@ -51,6 +51,19 @@ Calling the `build_oai` script with the -h option gives the list of all availabl
 
 # Building PHY Simulators
 
+The PHY layer simulators (LTE and NR) can be built as follows:  
+
+```
+cd <your oai installation directory>/openairinterface5g/
+source oaienv
+cd cmake_targets/
+./build_oai -I --phy_simulators
+```
+
+After completing the build, the binaries are available in the cmake_targets/phy_simulators/build directory.  
+A copy is also available in the target/bin directory, with all binaries suffixed by the 3GPP release number, today **.Rel15**.  
+
+
 Detailed information about these simulators can be found [in this dedicated page](https://gitlab.eurecom.fr/oai/openairinterface5g/wikis/OpenAirLTEPhySimul)
 
 # Building UEs, eNodeB and gNodeB Executables
diff --git a/docker/Dockerfile.eNB.rhel8.2 b/docker/Dockerfile.eNB.rhel8.2
index 363b070934b903bc2978a1e88e4db48daadddfd2..5fcd5a7b9f07d041f66d3aa92dca8a3c72c57c83 100644
--- a/docker/Dockerfile.eNB.rhel8.2
+++ b/docker/Dockerfile.eNB.rhel8.2
@@ -32,6 +32,7 @@ WORKDIR /oai-ran
 #run build_oai to build the target image
 RUN /bin/sh oaienv && \ 
     cd cmake_targets && \
+    rm -Rf log && \
     mkdir -p log && \
     ./build_oai --eNB --ninja -w USRP
 
diff --git a/docker/Dockerfile.eNB.rhel8.2.oc4-4 b/docker/Dockerfile.eNB.rhel8.2.oc4-4
index 039183a0f22675a62e308744596e9e4e109e6b7d..5b784c08a28f0c47d79e384c08bc46f3834ade68 100644
--- a/docker/Dockerfile.eNB.rhel8.2.oc4-4
+++ b/docker/Dockerfile.eNB.rhel8.2.oc4-4
@@ -33,6 +33,7 @@ WORKDIR /oai-ran
 #run build_oai to build the target image
 RUN /bin/sh oaienv && \ 
     cd cmake_targets && \
+    rm -Rf log && \
     mkdir -p log && \
     ./build_oai --eNB --ninja -w USRP
 
diff --git a/docker/Dockerfile.eNB.ubuntu18 b/docker/Dockerfile.eNB.ubuntu18
index 9b6e5cb47d818f65493fc478b41cf4916b7e8781..cdfb37ebfc343637e2bfbdce2ff3d2f0f147a09c 100644
--- a/docker/Dockerfile.eNB.ubuntu18
+++ b/docker/Dockerfile.eNB.ubuntu18
@@ -32,9 +32,14 @@ WORKDIR /oai-ran
 #run build_oai to build the target image
 RUN /bin/sh oaienv && \ 
     cd cmake_targets && \
+    rm -Rf log && \
     mkdir -p log && \
     ./build_oai --eNB --ninja -w USRP
 
+RUN apt-get install -y python3-pip && \
+    pip3 install --ignore-installed pyyaml && \
+    python3 ./docker/scripts/generateTemplate.py ./docker/scripts/enb_parameters.yaml
+
 # debug
 #RUN ldconfig -v && ldd /oai-ran/targets/bin/lte-softmodem.Rel15
 #RUN ls -ls /oai-ran/targets/bin
@@ -73,6 +78,7 @@ RUN apt-get update && \
 
 WORKDIR /opt/oai-enb/bin
 COPY --from=enb-build /oai-ran/targets/bin/lte-softmodem.Rel15 .
+COPY --from=enb-build /oai-ran/docker/scripts/enb_entrypoint.sh entrypoint.sh
 
 WORKDIR /usr/local/lib/
 COPY --from=enb-build /oai-ran/targets/bin/liboai_eth_transpro.so.Rel15 .
@@ -104,21 +110,17 @@ RUN ldconfig
 
 # Copy the relevant configuration files for eNB
 WORKDIR /opt/oai-enb/etc
-COPY --from=enb-build /oai-ran/ci-scripts/conf_files/enb.* ./
-COPY --from=enb-build /oai-ran/ci-scripts/conf_files/rcc.* ./
-COPY --from=enb-build /oai-ran/ci-scripts/conf_files/cu.* ./
-COPY --from=enb-build /oai-ran/ci-scripts/conf_files/du.* ./
-COPY --from=enb-build /oai-ran/ci-scripts/conf_files/rru.* ./
+COPY --from=enb-build /oai-ran/docker/etc .
 
 WORKDIR /opt/oai-enb
 
-#EXPOSE 2152/udp  # S1U, GTP/UDP
+# 2152 --> S1U, GTP/UDP
+# 36412 --> S1C, SCTP/UDP
+# 36422 --> X2C, SCTP/UDP
+EXPOSE 2152/udp 36412/udp 36422/udp
 #EXPOSE 22100/tcp # ?
-#EXPOSE 36412/udp # S1C, SCTP/UDP
-#EXPOSE 36422/udp # X2C, SCTP/UDP
 #EXPOSE 50000/udp # IF5 / ORI (control)
 #EXPOSE 50001/udp # IF5 / ECPRI (data)
 
-#CMD ["/opt/oai-enb/bin/lte-softmodem", "-O", "/opt/oai-enb/etc/enb.conf"]
-#ENTRYPOINT ["/opt/oai-enb/bin/entrypoint.sh"]
-CMD ["sleep", "infinity"]
+ENTRYPOINT ["/opt/oai-enb/bin/entrypoint.sh"]
+CMD ["/opt/oai-enb/bin/lte-softmodem.Rel15", "-O", "/opt/oai-enb/etc/enb.conf"]
diff --git a/docker/Dockerfile.gNB.rhel8.2 b/docker/Dockerfile.gNB.rhel8.2
index 901df9757ccca49449948019d1931139f1ab18dc..fb9ade927f8db1a1c7d559b3ddb26db4cb6af8df 100644
--- a/docker/Dockerfile.gNB.rhel8.2
+++ b/docker/Dockerfile.gNB.rhel8.2
@@ -32,6 +32,7 @@ WORKDIR /oai-ran
 #run build_oai to build the target image
 RUN /bin/sh oaienv && \ 
     cd cmake_targets && \
+    rm -Rf log && \
     mkdir -p log && \
     ./build_oai --gNB --ninja -w USRP
 
diff --git a/docker/Dockerfile.gNB.rhel8.2.oc4-4 b/docker/Dockerfile.gNB.rhel8.2.oc4-4
index 197bc2a92ad9c69b0b1e139e84f674b8f78cb363..1e1eba016e34c503f9b87ae3c26f5cbf2df21430 100644
--- a/docker/Dockerfile.gNB.rhel8.2.oc4-4
+++ b/docker/Dockerfile.gNB.rhel8.2.oc4-4
@@ -33,6 +33,7 @@ WORKDIR /oai-ran
 #run build_oai to build the target image
 RUN /bin/sh oaienv && \ 
     cd cmake_targets && \
+    rm -Rf log && \
     mkdir -p log && \
     ./build_oai --gNB --ninja -w USRP
 
diff --git a/docker/Dockerfile.gNB.ubuntu18 b/docker/Dockerfile.gNB.ubuntu18
index 4135b0e785f73928724d0531a56fda4c6ea92c09..d43ad4709dbedcef7c76861cc2677a38c95dc8d4 100644
--- a/docker/Dockerfile.gNB.ubuntu18
+++ b/docker/Dockerfile.gNB.ubuntu18
@@ -32,6 +32,7 @@ WORKDIR /oai-ran
 #run build_oai to build the target image
 RUN /bin/sh oaienv && \ 
     cd cmake_targets && \
+    rm -Rf log && \
     mkdir -p log && \
     ./build_oai --gNB --ninja -w USRP
 
diff --git a/docker/Dockerfile.lteUE.rhel8.2 b/docker/Dockerfile.lteUE.rhel8.2
index 6b64fdec1e1950dbc4e8e4067074e6dd64929ac4..0a853dcd6b5dc211a730cf0a82f074e9118eea61 100644
--- a/docker/Dockerfile.lteUE.rhel8.2
+++ b/docker/Dockerfile.lteUE.rhel8.2
@@ -33,6 +33,7 @@ WORKDIR /oai-ran
 #run build_oai to build the target image
 RUN /bin/sh oaienv && \ 
     cd cmake_targets && \
+    rm -Rf log && \
     mkdir -p log && \
     ./build_oai --UE --ninja -w USRP
 
diff --git a/docker/Dockerfile.lteUE.rhel8.2.oc4-4 b/docker/Dockerfile.lteUE.rhel8.2.oc4-4
index c390e01e3b9210672a1ba21cf90826c26f301c94..1339d18de62c244d7db97b6bdd5bf3a292e1d1ca 100644
--- a/docker/Dockerfile.lteUE.rhel8.2.oc4-4
+++ b/docker/Dockerfile.lteUE.rhel8.2.oc4-4
@@ -33,6 +33,7 @@ WORKDIR /oai-ran
 #run build_oai to build the target image
 RUN /bin/sh oaienv && \ 
     cd cmake_targets && \
+    rm -Rf log && \
     mkdir -p log && \
     ./build_oai --UE --ninja -w USRP
 
diff --git a/docker/Dockerfile.lteUE.ubuntu18 b/docker/Dockerfile.lteUE.ubuntu18
index f1233d6a01440feffc4f2aa93a65dbf7caf49cdf..8793cc54f79d87e470a46a4520b7f2ee519d1865 100644
--- a/docker/Dockerfile.lteUE.ubuntu18
+++ b/docker/Dockerfile.lteUE.ubuntu18
@@ -32,6 +32,7 @@ WORKDIR /oai-ran
 #run build_oai to build the target image
 RUN /bin/sh oaienv && \ 
     cd cmake_targets && \
+    rm -Rf log && \
     mkdir -p log && \
     ./build_oai --UE --ninja -w USRP
 
diff --git a/docker/Dockerfile.nrUE.rhel8.2 b/docker/Dockerfile.nrUE.rhel8.2
index 466eeedd403dabdfb1835136720003d3c2a387eb..f9f3f8e4bfcdfd4e95d3d8ae10ed206788f7af53 100644
--- a/docker/Dockerfile.nrUE.rhel8.2
+++ b/docker/Dockerfile.nrUE.rhel8.2
@@ -32,6 +32,7 @@ WORKDIR /oai-ran
 #run build_oai to build the target image
 RUN /bin/sh oaienv && \ 
     cd cmake_targets && \
+    rm -Rf log && \
     mkdir -p log && \
     ./build_oai --nrUE --ninja -w USRP
 
diff --git a/docker/Dockerfile.nrUE.rhel8.2.oc4-4 b/docker/Dockerfile.nrUE.rhel8.2.oc4-4
index 3b09b18b552eb5b20c13b3890d509c2e049bfadd..d900fff998d633eccaa0685dc71bad20820de92a 100644
--- a/docker/Dockerfile.nrUE.rhel8.2.oc4-4
+++ b/docker/Dockerfile.nrUE.rhel8.2.oc4-4
@@ -33,6 +33,7 @@ WORKDIR /oai-ran
 #run build_oai to build the target image
 RUN /bin/sh oaienv && \ 
     cd cmake_targets && \
+    rm -Rf log && \
     mkdir -p log && \
     ./build_oai --nrUE --ninja -w USRP
 
diff --git a/docker/Dockerfile.nrUE.ubuntu18 b/docker/Dockerfile.nrUE.ubuntu18
index eecadacb507b89b584b1b9dc3d5c3eda9c6e7648..5450194f3539ad83663017e31e53e10185dc9a37 100644
--- a/docker/Dockerfile.nrUE.ubuntu18
+++ b/docker/Dockerfile.nrUE.ubuntu18
@@ -32,6 +32,7 @@ WORKDIR /oai-ran
 #run build_oai to build the target image
 RUN /bin/sh oaienv && \ 
     cd cmake_targets && \
+    rm -Rf log && \
     mkdir -p log && \
     ./build_oai --nrUE --ninja -w USRP
 
diff --git a/docker/scripts/enb_entrypoint.sh b/docker/scripts/enb_entrypoint.sh
new file mode 100755
index 0000000000000000000000000000000000000000..31d99b2a676e2393ee16d4107fbd902943d145b2
--- /dev/null
+++ b/docker/scripts/enb_entrypoint.sh
@@ -0,0 +1,65 @@
+#!/bin/bash
+
+set -euo pipefail
+
+# Based another env var, pick one template to use
+if [[ -v USE_FDD_CU ]]; then ln -s /opt/oai-enb/etc/cu.fdd.conf /opt/oai-enb/etc/enb.conf; fi
+if [[ -v USE_FDD_DU ]]; then ln -s /opt/oai-enb/etc/du.fdd.conf /opt/oai-enb/etc/enb.conf; fi
+if [[ -v USE_FDD_MONO ]]; then ln -s /opt/oai-enb/etc/enb.fdd.conf /opt/oai-enb/etc/enb.conf; fi
+if [[ -v USE_TDD_MONO ]]; then ln -s /opt/oai-enb/etc/enb.tdd.conf /opt/oai-enb/etc/enb.conf; fi
+if [[ -v USE_FDD_RCC ]]; then ln -s /opt/oai-enb/etc/rcc.if4p5.enb.fdd.conf /opt/oai-enb/etc/enb.conf; fi
+if [[ -v USE_FDD_RRU ]]; then ln -s /opt/oai-enb/etc/rru.fdd.conf /opt/oai-enb/etc/enb.conf; fi
+if [[ -v USE_TDD_RRU ]]; then ln -s /opt/oai-enb/etc/rru.tdd.conf /opt/oai-enb/etc/enb.conf; fi
+
+# Only this template will be manipulated
+CONFIG_FILES=`ls /opt/oai-enb/etc/enb.conf`
+
+for c in ${CONFIG_FILES}; do
+    # grep variable names (format: ${VAR}) from template to be rendered
+    VARS=$(grep -oP '@[a-zA-Z0-9_]+@' ${c} | sort | uniq | xargs)
+
+    # create sed expressions for substituting each occurrence of ${VAR}
+    # with the value of the environment variable "VAR"
+    EXPRESSIONS=""
+    for v in ${VARS}; do
+        NEW_VAR=`echo $v | sed -e "s#@##g"`
+        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
+        EXPRESSIONS="${EXPRESSIONS};s|${v}|${!NEW_VAR}|g"
+    done
+    EXPRESSIONS="${EXPRESSIONS#';'}"
+
+    # render template and inline replace config file
+    sed -i "${EXPRESSIONS}" ${c}
+done
+
+# Load the USRP binaries
+if [[ -v USE_B2XX ]]; then
+    /usr/lib/uhd/utils/uhd_images_downloader.py -t b2xx
+elif [[ -v USE_X3XX ]]; then
+    /usr/lib/uhd/utils/uhd_images_downloader.py -t x3xx
+elif [[ -v USE_N3XX ]]; then
+    /usr/lib/uhd/utils/uhd_images_downloader.py -t n3xx
+fi
+
+echo "=================================="
+echo "== Starting eNB soft modem"
+if [[ -v USE_ADDITIONAL_OPTIONS ]]; then
+    echo "Additional option(s): ${USE_ADDITIONAL_OPTIONS}"
+    new_args=()
+    while [[ $# -gt 0 ]]; do
+        new_args+=("$1")
+        shift
+    done
+    for word in ${USE_ADDITIONAL_OPTIONS}; do
+        new_args+=("$word")
+    done
+    echo "${new_args[@]}"
+    exec "${new_args[@]}"
+else
+    echo "$@"
+    exec "$@"
+fi
diff --git a/docker/scripts/enb_parameters.yaml b/docker/scripts/enb_parameters.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..a60fc20e29434725379d3fbe8172dd33c22e2f3f
--- /dev/null
+++ b/docker/scripts/enb_parameters.yaml
@@ -0,0 +1,248 @@
+#/*
+# * 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
+# */
+
+---
+- paths:
+    source_dir: "ci-scripts/conf_files/"
+    dest_dir: docker/etc
+    
+- configurations:
+  - filePrefix: cu
+    outputfilename: "cu.fdd.conf"
+    config:
+    - key: Active_eNBs
+      env: "@ENB_NAME@"
+    - key: eNB_name
+      env: "@ENB_NAME@"
+    - key: plmn_list
+      env:
+        mcc: "@MCC@"
+        mnc: "@MNC@"
+        mnc_length: "@MNC_LENGTH@"
+    - key: tracking_area_code
+      env: "@TAC@"
+    - key: local_s_if_name
+      env: "@F1_IF_NAME@"
+    - key: remote_s_address
+      env: "@F1_DU_IP_ADDRESS@"
+    - key: local_s_address
+      env: "@F1_CU_IP_ADDRESS@"
+    - key: eutra_band
+      env: "@UTRA_BAND_ID@"
+    - key: downlink_frequency
+      env: "@DL_FREQUENCY_IN_MHZ@000000"
+    - key: uplink_frequency_offset
+      env: "@UL_FREQUENCY_OFFSET_IN_MHZ@000000"
+    - key: Nid_cell
+      env: "@NID_CELL@"
+    - key: N_RB_DL
+      env: "@NB_PRB@"
+    - key: ipv4
+      env: "@MME_S1C_IP_ADDRESS@"
+    - key: ENB_INTERFACE_NAME_FOR_S1_MME
+      env: "@S1C_IF_NAME@"
+    - key: ENB_IPV4_ADDRESS_FOR_S1_MME
+      env: "@F1_CU_IP_ADDRESS@"
+    - key: ENB_INTERFACE_NAME_FOR_S1U
+      env: "@S1U_IF_NAME@"
+    - key: ENB_IPV4_ADDRESS_FOR_S1U
+      env: "@F1_CU_IP_ADDRESS@"
+    - key: ENB_IPV4_ADDRESS_FOR_X2C
+      env: "@F1_CU_IP_ADDRESS@"
+      
+  - filePrefix: du
+    outputfilename: "du.fdd.conf"
+    config:
+    - key: Active_eNBs
+      env: "@ENB_NAME@"
+    - key: eNB_name
+      env: "@ENB_NAME@"
+    - key: plmn_list
+      env:
+        mcc: "@MCC@"
+        mnc: "@MNC@"
+        mnc_length: "@MNC_LENGTH@"
+    - key: tracking_area_code
+      env: "@TAC@"
+    - key: local_n_if_name
+      env: "@F1_IF_NAME@"
+    - key: remote_n_address
+      env: "@F1_DU_IP_ADDRESS@"
+    - key: local_n_address
+      env: "@F1_CU_IP_ADDRESS@"
+    - key: eutra_band
+      env: "@UTRA_BAND_ID@"
+    - key: downlink_frequency
+      env: "@DL_FREQUENCY_IN_MHZ@000000"
+    - key: uplink_frequency_offset
+      env: "@UL_FREQUENCY_OFFSET_IN_MHZ@000000"
+    - key: Nid_cell
+      env: "@NID_CELL@"
+    - key: N_RB_DL
+      env: "@NB_PRB@"
+      
+  - filePrefix: rru.fdd
+    outputfilename: "rru.fdd.conf"
+    config:
+    - key: local_if_name
+      env: "@RRU_IF4P5_IF_NAME@"
+    - key: remote_address
+      env: "@RCC_REMOTE_IP_ADDRESS@"
+    - key: local_address
+      env: "@RRU_LOCAL_IP_ADDRESS@"
+    - key: bands
+      env: "@UTRA_BAND_ID@"
+      
+  - filePrefix: rru.tdd
+    outputfilename: "rru.tdd.conf"
+    config:
+    - key: local_if_name
+      env: "@RRU_IF4P5_IF_NAME@"
+    - key: remote_address
+      env: "@RCC_REMOTE_IP_ADDRESS@"
+    - key: local_address
+      env: "@RRU_LOCAL_IP_ADDRESS@"
+    - key: bands
+      env: "@UTRA_BAND_ID@"
+      
+  - filePrefix: enb.band7.tm1.25PRB.usrpb210
+    outputfilename: "enb.fdd.conf"
+    config:
+    - key: Active_eNBs
+      env: "@ENB_NAME@"
+    - key: eNB_name
+      env: "@ENB_NAME@"
+    - key: plmn_list
+      env:
+        mcc: "@MCC@"
+        mnc: "@MNC@"
+        mnc_length: "@MNC_LENGTH@"
+    - key: tracking_area_code
+      env: "@TAC@"
+    - key: eutra_band
+      env: "@UTRA_BAND_ID@"
+    - key: downlink_frequency
+      env: "@DL_FREQUENCY_IN_MHZ@000000"
+    - key: uplink_frequency_offset
+      env: "@UL_FREQUENCY_OFFSET_IN_MHZ@000000"
+    - key: Nid_cell
+      env: "@NID_CELL@"
+    - key: N_RB_DL
+      env: "@NB_PRB@"
+    - key: ipv4
+      env: "@MME_S1C_IP_ADDRESS@"
+    - key: ENB_INTERFACE_NAME_FOR_S1_MME
+      env: "@ENB_S1C_IF_NAME@"
+    - key: ENB_IPV4_ADDRESS_FOR_S1_MME
+      env: "@ENB_S1C_IP_ADDRESS@"
+    - key: ENB_INTERFACE_NAME_FOR_S1U
+      env: "@ENB_S1U_IF_NAME@"
+    - key: ENB_IPV4_ADDRESS_FOR_S1U
+      env: "@ENB_S1U_IP_ADDRESS@"
+    - key: ENB_IPV4_ADDRESS_FOR_X2C
+      env: "@ENB_X2_IP_ADDRESS@"
+    - key: FLEXRAN_ENABLED
+      env: "@FLEXRAN_ENABLED@"
+    - key: FLEXRAN_INTERFACE_NAME
+      env: "@FLEXRAN_INTERFACE_NAME@"
+    - key: FLEXRAN_IPV4_ADDRESS
+      env: "@FLEXRAN_IPV4_ADDRESS@"
+      
+  - filePrefix: enb.band40.tm1.25PRB.FairScheduler.usrpb210
+    outputfilename: "enb.tdd.conf"
+    config:
+    - key: Active_eNBs
+      env: "@ENB_NAME@"
+    - key: eNB_name
+      env: "@ENB_NAME@"
+    - key: plmn_list
+      env:
+        mcc: "@MCC@"
+        mnc: "@MNC@"
+        mnc_length: "@MNC_LENGTH@"
+    - key: tracking_area_code
+      env: "@TAC@"
+    - key: eutra_band
+      env: "@UTRA_BAND_ID@"
+    - key: downlink_frequency
+      env: "@DL_FREQUENCY_IN_MHZ@000000"
+    - key: uplink_frequency_offset
+      env: "@UL_FREQUENCY_OFFSET_IN_MHZ@000000"
+    - key: Nid_cell
+      env: "@NID_CELL@"
+    - key: N_RB_DL
+      env: "@NB_PRB@"
+    - key: ipv4
+      env: "@MME_S1C_IP_ADDRESS@"
+    - key: ENB_INTERFACE_NAME_FOR_S1_MME
+      env: "@S1C_IF_NAME@"
+    - key: ENB_IPV4_ADDRESS_FOR_S1_MME
+      env: "@F1_CU_IP_ADDRESS@"
+    - key: ENB_INTERFACE_NAME_FOR_S1U
+      env: "@S1U_IF_NAME@"
+    - key: ENB_IPV4_ADDRESS_FOR_S1U
+      env: "@F1_CU_IP_ADDRESS@"
+    - key: ENB_IPV4_ADDRESS_FOR_X2C
+      env: "@F1_CU_IP_ADDRESS@"
+      
+  - filePrefix: "rcc.band7.tm1.nfapi"
+    outputfilename: "rcc.if4p5.enb.fdd.conf"
+    config:
+    - key: Active_eNBs
+      env: "@ENB_NAME@"
+    - key: eNB_name
+      env: "@ENB_NAME@"
+    - key: plmn_list
+      env:
+        mcc: "@MCC@"
+        mnc: "@MNC@"
+        mnc_length: "@MNC_LENGTH@"
+    - key: tracking_area_code
+      env: "@TAC@"
+    - key: local_s_if_name
+      env: "@F1_IF_NAME@"
+    - key: remote_s_address
+      env: "@F1_DU_IP_ADDRESS@"
+    - key: local_s_address
+      env: "@F1_CU_IP_ADDRESS@"
+    - key: eutra_band
+      env: "@UTRA_BAND_ID@"
+    - key: downlink_frequency
+      env: "@DL_FREQUENCY_IN_MHZ@000000"
+    - key: uplink_frequency_offset
+      env: "@UL_FREQUENCY_OFFSET_IN_MHZ@000000"
+    - key: Nid_cell
+      env: "@NID_CELL@"
+    - key: N_RB_DL
+      env: "@NB_PRB@"
+    - key: ipv4
+      env: "@MME_S1C_IP_ADDRESS@"
+    - key: ENB_INTERFACE_NAME_FOR_S1_MME
+      env: "@S1C_IF_NAME@"
+    - key: ENB_IPV4_ADDRESS_FOR_S1_MME
+      env: "@F1_CU_IP_ADDRESS@"
+    - key: ENB_INTERFACE_NAME_FOR_S1U
+      env: "@S1U_IF_NAME@"
+    - key: ENB_IPV4_ADDRESS_FOR_S1U
+      env: "@F1_CU_IP_ADDRESS@"
+    - key: ENB_IPV4_ADDRESS_FOR_X2C
+      env: "@F1_CU_IP_ADDRESS@"
+
diff --git a/docker/scripts/generateTemplate.py b/docker/scripts/generateTemplate.py
new file mode 100644
index 0000000000000000000000000000000000000000..4949e9cf21531849fd3fa72d4adb18d8fa0c950a
--- /dev/null
+++ b/docker/scripts/generateTemplate.py
@@ -0,0 +1,89 @@
+#/*
+# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+# * contributor license agreements.  See the NOTICE file distributed with
+# * this work for additional information regarding copyright ownership.
+# * The OpenAirInterface Software Alliance licenses this file to You under
+# * the OAI Public License, Version 1.1  (the "License"); you may not use this file
+# * except in compliance with the License.
+# * You may obtain a copy of the License at
+# *
+# *      http://www.openairinterface.org/?page_id=698
+# *
+# * Unless required by applicable law or agreed to in writing, software
+# * distributed under the License is distributed on an "AS IS" BASIS,
+# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# * See the License for the specific language governing permissions and
+# * limitations under the License.
+# *-------------------------------------------------------------------------------
+# * For more information about the OpenAirInterface (OAI) Software Alliance:
+# *      contact@openairinterface.org
+# */
+#---------------------------------------------------------------------
+
+#-----------------------------------------------------------
+# Import
+#-----------------------------------------------------------
+import re
+import yaml
+import os
+import sys
+
+
+def main():
+  #read yaml input parameters
+  f = open(f'{sys.argv[1]}',)
+  data = yaml.full_load(f)
+  dir = os.listdir(f'{data[0]["paths"]["source_dir"]}')
+
+
+  #identify configs, read and replace corresponding values
+  for config in data[1]["configurations"]:
+    filePrefix = config["filePrefix"]
+    outputfilename = config["outputfilename"]
+    for inputfile in dir:
+      if inputfile.find(filePrefix) >=0:
+        prefix_outputfile = {"cu": f'{data[0]["paths"]["dest_dir"]}/{outputfilename}', 
+                             "du": f'{data[0]["paths"]["dest_dir"]}/{outputfilename}',
+                             "rru.fdd": f'{data[0]["paths"]["dest_dir"]}/{outputfilename}',
+                             "rru.tdd": f'{data[0]["paths"]["dest_dir"]}/{outputfilename}',
+                             "enb.band7.tm1.25PRB.usrpb210": f'{data[0]["paths"]["dest_dir"]}/{outputfilename}',
+                             "enb.band40.tm1.25PRB.FairScheduler.usrpb210": f'{data[0]["paths"]["dest_dir"]}/{outputfilename}',
+                             "rcc.band7.tm1.nfapi": f'{data[0]["paths"]["dest_dir"]}/{outputfilename}'
+                             }
+        if filePrefix in prefix_outputfile:
+          outputfile1 = prefix_outputfile[filePrefix]  
+      
+        directory = f'{data[0]["paths"]["dest_dir"]}'
+        if not os.path.exists(directory):
+          os.makedirs(directory, exist_ok=True)
+
+        with open(f'{data[0]["paths"]["source_dir"]}{inputfile}', mode='r') as inputfile, \
+             open(outputfile1, mode='w') as outputfile:
+          for line in inputfile:
+            count = 0
+            for key in config["config"]:
+              if line.find(key["key"]) >= 0:
+                count += 1
+                if re.search(r'preference', line):
+                  templine = line
+                elif re.search(r'plmn_list', line):
+                  templine = re.sub(r'[0-9]+', '""', line)
+                  templine = re.sub(r'\"\"', key["env"]["mcc"], templine, 1)
+                  templine = re.sub(r'\"\"', key["env"]["mnc"], templine, 1) 
+                  templine = re.sub(r'\"\"', key["env"]["mnc_length"], templine, 1)               
+                elif re.search('downlink_frequency', line):
+                  templine = re.sub(r'[0-9]+', key["env"], line)
+                elif re.search('uplink_frequency_offset', line):
+                  templine = re.sub(r'[0-9]+', key["env"], line)
+               
+                elif re.search(r'"(.*?)"', line):
+                  templine = re.sub(r'(?<=")[^"]*(?=")', key["env"], line)    
+                elif re.search(r'[0-9]', line):
+                  templine = re.sub(r'\d+', key["env"], line)
+                outputfile.write(templine)
+            
+            if count == 0:
+              outputfile.write(line)
+              
+if __name__ == "__main__":
+    main()
diff --git a/openair3/SCTP/sctp_eNB_task.c b/openair3/SCTP/sctp_eNB_task.c
index 972bef0a0745c9593b0a038a06d21cbeb8192659..ee006338c5a0e64532dd024b0f0b6488fc542412 100644
--- a/openair3/SCTP/sctp_eNB_task.c
+++ b/openair3/SCTP/sctp_eNB_task.c
@@ -413,10 +413,16 @@ sctp_handle_new_association_req(
     }
 
     /* Subscribe to all events */
-    memset((void *)&events, 1, sizeof(struct sctp_event_subscribe));
+    events.sctp_data_io_event = 1;
+    events.sctp_association_event = 1;
+    events.sctp_address_event = 1;
+    events.sctp_send_failure_event = 1;
+    events.sctp_peer_error_event = 1;
+    events.sctp_shutdown_event = 1;
+    events.sctp_partial_delivery_event = 1;
 
     if (setsockopt(sd, IPPROTO_SCTP, SCTP_EVENTS, &events,
-                   sizeof(struct sctp_event_subscribe)) < 0) {
+                   8) < 0) {
         SCTP_ERROR("Setsockopt IPPROTO_SCTP_EVENTS failed: %s\n",
                    strerror(errno));
         close(sd);
@@ -759,10 +765,16 @@ static int sctp_create_new_listener(
         }
     }
 
-    memset((void *)&event, 1, sizeof(struct sctp_event_subscribe));
+    event.sctp_data_io_event = 1;
+    event.sctp_association_event = 1;
+    event.sctp_address_event = 1;
+    event.sctp_send_failure_event = 1;
+    event.sctp_peer_error_event = 1;
+    event.sctp_shutdown_event = 1;
+    event.sctp_partial_delivery_event = 1;
 
     if (setsockopt(sd, IPPROTO_SCTP, SCTP_EVENTS, &event,
-                   sizeof(struct sctp_event_subscribe)) < 0) {
+                   8) < 0) {
         SCTP_ERROR("setsockopt: %s:%d\n", strerror(errno), errno);
         if (sd != -1) {
             close(sd);
diff --git a/openair3/SCTP/sctp_primitives_client.c b/openair3/SCTP/sctp_primitives_client.c
index bb71a854e168d6782935bde1f92df2bd84c58076..e19f20c957b55e0adbcf667720ed9ee210b104ee 100644
--- a/openair3/SCTP/sctp_primitives_client.c
+++ b/openair3/SCTP/sctp_primitives_client.c
@@ -241,10 +241,16 @@ int sctp_connect_to_remote_host(char *local_ip_addr[],
   }
 
   /* Subscribe to all events */
-  memset((void *)&events, 1, sizeof(struct sctp_event_subscribe));
+  events.sctp_data_io_event = 1;
+  events.sctp_association_event = 1;
+  events.sctp_address_event = 1;
+  events.sctp_send_failure_event = 1;
+  events.sctp_peer_error_event = 1;
+  events.sctp_shutdown_event = 1;
+  events.sctp_partial_delivery_event = 1;
 
   if (setsockopt(sd, IPPROTO_SCTP, SCTP_EVENTS, &events,
-                 sizeof(struct sctp_event_subscribe)) < 0) {
+                 8) < 0) {
     SCTP_ERROR("Setsockopt IPPROTO_SCTP_EVENTS failed: %s\n",
                strerror(errno));
     return -1;