diff --git a/ci-scripts/cls_containerize.py b/ci-scripts/cls_containerize.py
index f32e8b38646196b406836b45d2602190f639037b..63b707aa748a79db8c90eb049b9672f7e70cbe99 100644
--- a/ci-scripts/cls_containerize.py
+++ b/ci-scripts/cls_containerize.py
@@ -36,6 +36,7 @@ import re               # reg
 import logging
 import os
 import shutil
+import subprocess
 import time
 from multiprocessing import Process, Lock, SimpleQueue
 from zipfile import ZipFile
@@ -76,6 +77,9 @@ class Containerize():
 		self.eNB_instance = 0
 		self.eNB_serverId = ['', '', '']
 		self.yamlPath = ['', '', '']
+		self.services = ['', '', '']
+		self.nb_healthy = [0, 0, 0]
+		self.exitStatus = 0
 		self.eNB_logFile = ['', '', '']
 
 		self.testCase_id = ''
@@ -89,6 +93,14 @@ class Containerize():
 		self.allImagesSize = {}
 		self.collectInfo = {}
 
+		self.pingContName = ''
+		self.pingOptions = ''
+		self.pingLossThreshold = ''
+		self.svrContName = ''
+		self.svrOptions = ''
+		self.cliContName = ''
+		self.cliOptions = ''
+
 #-----------------------------------------------------------
 # Container management functions
 #-----------------------------------------------------------
@@ -476,7 +488,6 @@ class Containerize():
 			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
@@ -529,4 +540,307 @@ class Containerize():
 				HTML.CreateHtmlTestRow(RAN.runtime_stats, 'KO', logStatus)
 			else:
 				HTML.CreateHtmlTestRow(RAN.runtime_stats, 'OK', CONST.ALL_PROCESSES_OK)
+		logging.info('\u001B[1m Undeploying OAI Object Pass\u001B[0m')
+
+	def DeployGenObject(self, HTML):
+		self.exitStatus = 0
+		logging.info('\u001B[1m Checking Services to deploy\u001B[0m')
+		cmd = 'cd ' + self.yamlPath[0] + ' && docker-compose config --services'
+		logging.debug(cmd)
+		try:
+			listServices = subprocess.check_output(cmd, shell=True, universal_newlines=True)
+		except Exception as e:
+			self.exitStatus = 1
+			HTML.CreateHtmlTestRow('SVC not Found', 'KO', CONST.ALL_PROCESSES_OK)
+			return
+		for reqSvc in self.services[0].split(' '):
+			res = re.search(reqSvc, listServices)
+			if res is None:
+				logging.error(reqSvc + ' not found in specified docker-compose')
+				self.exitStatus = 1
+		if (self.exitStatus == 1):
+			HTML.CreateHtmlTestRow('SVC not Found', 'KO', CONST.ALL_PROCESSES_OK)
+			return
+
+		if (self.ranAllowMerge):
+			cmd = 'cd ' + self.yamlPath[0] + ' && sed -e "s@develop@ci-temp@" docker-compose.y*ml > docker-compose-ci.yml'
+		else:
+			cmd = 'cd ' + self.yamlPath[0] + ' && sed -e "s@develop@develop@" docker-compose.y*ml > docker-compose-ci.yml'
+		logging.debug(cmd)
+		subprocess.run(cmd, shell=True)
+
+		cmd = 'cd ' + self.yamlPath[0] + ' && docker-compose -f docker-compose-ci.yml up -d ' + self.services[0]
+		logging.debug(cmd)
+		try:
+			deployStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=30)
+		except Exception as e:
+			self.exitStatus = 1
+			logging.error('Could not deploy')
+			HTML.CreateHtmlTestRow('Could not deploy', 'KO', CONST.ALL_PROCESSES_OK)
+			return
+
+		logging.info('\u001B[1m Checking if all deployed healthy\u001B[0m')
+		cmd = 'cd ' + self.yamlPath[0] + ' && docker-compose -f docker-compose-ci.yml ps -a'
+		count = 0
+		healthy = 0
+		while (count < 10):
+			count += 1
+			deployStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=10)
+			healthy = 0
+			for state in deployStatus.split('\n'):
+				res = re.search('Up \(healthy\)', state)
+				if res is not None:
+					healthy += 1
+			if healthy == self.nb_healthy[0]:
+				count = 100
+			else:
+				time.sleep(10)
+
+		#  HACK TO REMOVE LATER WHEN FIX
+		res = re.search('oai-nr-ue', self.services[0])
+		if res is not None:
+			cmd = 'docker exec rfsim5g-oai-nr-ue /bin/bash -c "ip route del default"'
+			logging.debug(cmd)
+			deployStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=10)
+			cmd = 'docker exec rfsim5g-oai-nr-ue /bin/bash -c "ip route del 12.1.1.0/24"'
+			logging.debug(cmd)
+			deployStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=10)
+			cmd = 'docker exec rfsim5g-oai-nr-ue /bin/bash -c "ip route add default via 12.1.1.2 dev oaitun_ue1"'
+			logging.debug(cmd)
+			deployStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=10)
+		#  END OF HACK TO REMOVE LATER WHEN FIX
+
+		if count == 100 and healthy == self.nb_healthy[0]:
+			HTML.CreateHtmlTestRow('n/a', 'OK', CONST.ALL_PROCESSES_OK)
+			logging.info('\u001B[1m Deploying OAI Object(s) PASS\u001B[0m')
+		else:
+			self.exitStatus = 1
+			HTML.CreateHtmlTestRow('Could not deploy in time', 'KO', CONST.ALL_PROCESSES_OK)
+			logging.error('\u001B[1m Deploying OAI Object(s) FAILED\u001B[0m')
+
+	def UndeployGenObject(self, HTML):
+		self.exitStatus = 0
+
+		if (self.ranAllowMerge):
+			cmd = 'cd ' + self.yamlPath[0] + ' && sed -e "s@develop@ci-temp@" docker-compose.y*ml > docker-compose-ci.yml'
+		else:
+			cmd = 'cd ' + self.yamlPath[0] + ' && sed -e "s@develop@develop@" docker-compose.y*ml > docker-compose-ci.yml'
+		logging.debug(cmd)
+		subprocess.run(cmd, shell=True)
+
+# if the containers are running, recover the logs!
+		cmd = 'cd ' + self.yamlPath[0] + ' && docker-compose -f docker-compose-ci.yml ps --all'
+		logging.debug(cmd)
+		deployStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=10)
+		anyLogs = False
+		for state in deployStatus.split('\n'):
+			res = re.search('Name|----------', state)
+			if res is not None:
+				continue
+			if len(state) == 0:
+				continue
+			res = re.search('^(?P<container_name>[a-zA-Z0-9\-\_]+) ', state)
+			if res is not None:
+				anyLogs = True
+				cName = res.group('container_name')
+				cmd = 'cd ' + self.yamlPath[0] + ' && docker logs ' + cName + ' > ' + cName + '.log 2>&1'
+				logging.debug(cmd)
+				deployStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=10)
+		if anyLogs:
+			cmd = 'mkdir -p ../cmake_targets/log && mv ' + self.yamlPath[0] + '/*.log ../cmake_targets/log'
+			logging.debug(cmd)
+			deployStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=10)
+
+		cmd = 'cd ' + self.yamlPath[0] + ' && docker-compose -f docker-compose-ci.yml down'
+		logging.debug(cmd)
+		try:
+			deployStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=100)
+		except Exception as e:
+			self.exitStatus = 1
+			logging.error('Could not undeploy')
+			HTML.CreateHtmlTestRow('Could not undeploy', 'KO', CONST.ALL_PROCESSES_OK)
+			logging.error('\u001B[1m Undeploying OAI Object(s) FAILED\u001B[0m')
+			return
+
+		HTML.CreateHtmlTestRow('n/a', 'OK', CONST.ALL_PROCESSES_OK)
+		logging.info('\u001B[1m Undeploying OAI Object(s) PASS\u001B[0m')
+
+	def PingFromContainer(self, HTML):
+		self.exitStatus = 0
+		cmd = 'mkdir -p ../cmake_targets/log'
+		deployStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=10)
+
+		cmd = 'docker exec ' + self.pingContName + ' /bin/bash -c "ping ' + self.pingOptions + '" 2>&1 | tee ../cmake_targets/log/ping_' + HTML.testCase_id + '.log'
+		logging.debug(cmd)
+		deployStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=100)
+
+		result = re.search(', (?P<packetloss>[0-9\.]+)% packet loss, time [0-9\.]+ms', deployStatus)
+		if result is None:
+			self.PingExit(HTML, False, 'Packet Loss Not Found')
+			return
+
+		packetloss = result.group('packetloss')
+		if float(packetloss) == 100:
+			self.PingExit(HTML, False, 'Packet Loss is 100%')
+			return
+
+		result = re.search('rtt min\/avg\/max\/mdev = (?P<rtt_min>[0-9\.]+)\/(?P<rtt_avg>[0-9\.]+)\/(?P<rtt_max>[0-9\.]+)\/[0-9\.]+ ms', deployStatus)
+		if result is None:
+			self.PingExit(HTML, False, 'Ping RTT_Min RTT_Avg RTT_Max Not Found!')
+			return
 
+		rtt_min = result.group('rtt_min')
+		rtt_avg = result.group('rtt_avg')
+		rtt_max = result.group('rtt_max')
+		pal_msg = 'Packet Loss : ' + packetloss + '%'
+		min_msg = 'RTT(Min)    : ' + rtt_min + ' ms'
+		avg_msg = 'RTT(Avg)    : ' + rtt_avg + ' ms'
+		max_msg = 'RTT(Max)    : ' + rtt_max + ' ms'
+
+		message = 'ping result\n'
+		message += '    ' + pal_msg + '\n'
+		message += '    ' + min_msg + '\n'
+		message += '    ' + avg_msg + '\n'
+		message += '    ' + max_msg + '\n'
+		packetLossOK = True
+		if float(packetloss) > float(self.pingLossThreshold):
+			message += '\nPacket Loss too high'
+			packetLossOK = False
+		elif float(packetloss) > 0:
+			message += '\nPacket Loss is not 0%'
+		self.PingExit(HTML, packetLossOK, message)
+
+		if packetLossOK:
+			logging.debug('\u001B[1;37;44m ping result \u001B[0m')
+			logging.debug('\u001B[1;34m    ' + pal_msg + '\u001B[0m')
+			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')
+			logging.info('\u001B[1m Ping Test PASS\u001B[0m')
+
+	def PingExit(self, HTML, status, message):
+		html_queue = SimpleQueue()
+		html_cell = '<pre style="background-color:white">UE\n' + message + '</pre>'
+		html_queue.put(html_cell)
+		if status:
+			HTML.CreateHtmlTestRowQueue(self.pingOptions, 'OK', 1, html_queue)
+		else:
+			self.exitStatus = 1
+			logging.error('\u001B[1;37;41m ' + message + ' \u001B[0m')
+			HTML.CreateHtmlTestRowQueue(self.pingOptions, 'KO', 1, html_queue)
+
+	def IperfFromContainer(self, HTML):
+		self.exitStatus = 0
+
+		cmd = 'mkdir -p ../cmake_targets/log'
+		logStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=10)
+
+		# Start the server process
+		cmd = 'docker exec -d ' + self.svrContName + ' /bin/bash -c "nohup iperf ' + self.svrOptions + ' > /tmp/iperf_server.log 2>&1"'
+		logging.debug(cmd)
+		serverStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=10)
+		time.sleep(5)
+
+		# Start the client process
+		cmd = 'docker exec ' + self.cliContName + ' /bin/bash -c "iperf ' + self.cliOptions + '" 2>&1 | tee ../cmake_targets/log/iperf_client_' + HTML.testCase_id + '.log'
+		logging.debug(cmd)
+		clientStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=100)
+
+		# Stop the server process
+		cmd = 'docker exec ' + self.svrContName + ' /bin/bash -c "pkill iperf"'
+		logging.debug(cmd)
+		serverStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=10)
+		time.sleep(5)
+		cmd = 'docker cp ' + self.svrContName + ':/tmp/iperf_server.log ../cmake_targets/log/iperf_server_' + HTML.testCase_id + '.log'
+		logging.debug(cmd)
+		serverStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=10)
+
+		# Analyze client output
+		result = re.search('Server Report:', clientStatus)
+		if result is None:
+			result = re.search('read failed: Connection refused', clientStatus)
+			if result is not None:
+				message = 'Could not connect to iperf server!'
+			else:
+				message = 'Server Report and Connection refused Not Found!'
+			self.IperfExit(HTML, False, message)
+			return
+
+		# Computing the requested bandwidth in float
+		result = re.search('-b (?P<iperf_bandwidth>[0-9\.]+)[KMG]', self.cliOptions)
+		if result is not None:
+			req_bandwidth = result.group('iperf_bandwidth')
+			req_bw = float(req_bandwidth)
+			result = re.search('-b [0-9\.]+K', self.cliOptions)
+			if result is not None:
+				req_bandwidth = '%.1f Kbits/sec' % req_bw
+				req_bw = req_bw * 1000
+			result = re.search('-b [0-9\.]+M', self.cliOptions)
+			if result is not None:
+				req_bandwidth = '%.1f Mbits/sec' % req_bw
+				req_bw = req_bw * 1000000
+
+		reportLine = None
+		reportLineFound = False
+		for iLine in clientStatus.split('\n'):
+			if reportLineFound:
+				reportLine = iLine
+				reportLineFound = False
+			res = re.search('Server Report:', iLine)
+			if res is not None:
+				reportLineFound = True
+		result = None
+		if reportLine is not None:
+			result = re.search('(?:|\[ *\d+\].*) (?P<bitrate>[0-9\.]+ [KMG]bits\/sec) +(?P<jitter>[0-9\.]+ ms) +(\d+\/ ..\d+) +(\((?P<packetloss>[0-9\.]+)%\))', reportLine)
+		iperfStatus = True
+		if result is not None:
+			bitrate = result.group('bitrate')
+			packetloss = result.group('packetloss')
+			jitter = result.group('jitter')
+			logging.debug('\u001B[1;37;44m iperf result \u001B[0m')
+			iperfStatus = True
+			msg = 'Req Bitrate : ' + req_bandwidth + '\n'
+			logging.debug('\u001B[1;34m    Req Bitrate : ' + req_bandwidth + '\u001B[0m')
+			if bitrate is not None:
+				msg += 'Bitrate     : ' + bitrate + '\n'
+				logging.debug('\u001B[1;34m    Bitrate     : ' + bitrate + '\u001B[0m')
+				result = re.search('(?P<real_bw>[0-9\.]+) [KMG]bits/sec', str(bitrate))
+				if result is not None:
+					actual_bw = float(str(result.group('real_bw')))
+					result = re.search('[0-9\.]+ K', bitrate)
+					if result is not None:
+						actual_bw = actual_bw * 1000
+					result = re.search('[0-9\.]+ M', bitrate)
+					if result is not None:
+						actual_bw = actual_bw * 1000000
+					br_loss = 100 * actual_bw / req_bw
+					if br_loss < 90:
+						iperfStatus = False
+					bitperf = '%.2f ' % br_loss
+					msg += 'Bitrate Perf: ' + bitperf + '%\n'
+					logging.debug('\u001B[1;34m    Bitrate Perf: ' + bitperf + '%\u001B[0m')
+			if packetloss is not None:
+				msg += 'Packet Loss : ' + packetloss + '%\n'
+				logging.debug('\u001B[1;34m    Packet Loss : ' + packetloss + '%\u001B[0m')
+				if float(packetloss) > float(5):
+					msg += 'Packet Loss too high!\n'
+					logging.debug('\u001B[1;37;41m Packet Loss too high \u001B[0m')
+					iperfStatus = False
+			if jitter is not None:
+				msg += 'Jitter      : ' + jitter + '\n'
+				logging.debug('\u001B[1;34m    Jitter      : ' + jitter + '\u001B[0m')
+			self.IperfExit(HTML, iperfStatus, msg)
+		else:
+			logging.error('problem?')
+		if iperfStatus:
+			logging.info('\u001B[1m Iperf Test PASS\u001B[0m')
+
+	def IperfExit(self, HTML, status, message):
+		html_queue = SimpleQueue()
+		html_cell = '<pre style="background-color:white">UE\n' + message + '</pre>'
+		html_queue.put(html_cell)
+		if status:
+			HTML.CreateHtmlTestRowQueue(self.cliOptions, 'OK', 1, html_queue)
+		else:
+			self.exitStatus = 1
+			HTML.CreateHtmlTestRowQueue(self.cliOptions, 'KO', 1, html_queue)
diff --git a/ci-scripts/main.py b/ci-scripts/main.py
index 8a76d8dbce5482d26f330a4596b0b39ac50911b2..f87fc1ed9c04f1df697aaf510a256421b6398c81 100644
--- a/ci-scripts/main.py
+++ b/ci-scripts/main.py
@@ -372,6 +372,41 @@ def GetParametersFromXML(action):
 		if (string_field is not None):
 			CONTAINERS.yamlPath[CONTAINERS.eNB_instance] = string_field
 
+	elif action == 'DeployGenObject' or action == 'UndeployGenObject':
+		string_field=test.findtext('yaml_path')
+		if (string_field is not None):
+			CONTAINERS.yamlPath[0] = string_field
+		string_field=test.findtext('services')
+		if (string_field is not None):
+			CONTAINERS.services[0] = string_field
+		string_field=test.findtext('nb_healthy')
+		if (string_field is not None):
+			CONTAINERS.nb_healthy[0] = int(string_field)
+
+	elif action == 'PingFromContainer':
+		string_field = test.findtext('container_name')
+		if (string_field is not None):
+			CONTAINERS.pingContName = string_field
+		string_field = test.findtext('options')
+		if (string_field is not None):
+			CONTAINERS.pingOptions = string_field
+		string_field = test.findtext('loss_threshold')
+		if (string_field is not None):
+			CONTAINERS.pingLossThreshold = string_field
+
+	elif action == 'IperfFromContainer':
+		string_field = test.findtext('server_container_name')
+		if (string_field is not None):
+			CONTAINERS.svrContName = string_field
+		string_field = test.findtext('server_options')
+		if (string_field is not None):
+			CONTAINERS.svrOptions = string_field
+		string_field = test.findtext('client_container_name')
+		if (string_field is not None):
+			CONTAINERS.cliContName = string_field
+		string_field = test.findtext('client_options')
+		if (string_field is not None):
+			CONTAINERS.cliOptions = string_field
 
 	else: # ie action == 'Run_PhySim':
 		ldpc.runargs = test.findtext('physim_run_args')
@@ -479,6 +514,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')
+	if RAN.eNBIPAddress == 'none':
+		sys.exit(0)
 	RAN.eNB_instance=0
 	RAN.eNB_serverId[0]='0'
 	RAN.eNBSourceCodePath='/tmp/'
@@ -514,11 +551,15 @@ elif re.match('^LogCollectBuild$', mode, re.IGNORECASE):
 	if (RAN.eNBIPAddress == '' or RAN.eNBUserName == '' or RAN.eNBPassword == '' or RAN.eNBSourceCodePath == '') and (CiTestObj.UEIPAddress == '' or CiTestObj.UEUserName == '' or CiTestObj.UEPassword == '' or CiTestObj.UESourceCodePath == ''):
 		HELP.GenericHelp(CONST.Version)
 		sys.exit('Insufficient Parameter')
+	if RAN.eNBIPAddress == 'none':
+		sys.exit(0)
 	CiTestObj.LogCollectBuild(RAN)
 elif re.match('^LogCollecteNB$', mode, re.IGNORECASE):
 	if RAN.eNBIPAddress == '' or RAN.eNBUserName == '' or RAN.eNBPassword == '' or RAN.eNBSourceCodePath == '':
 		HELP.GenericHelp(CONST.Version)
 		sys.exit('Insufficient Parameter')
+	if RAN.eNBIPAddress == 'none':
+		sys.exit(0)
 	RAN.LogCollecteNB()
 elif re.match('^LogCollectHSS$', mode, re.IGNORECASE):
 	if EPC.IPAddress == '' or EPC.UserName == '' or EPC.Password == '' or EPC.Type == '' or EPC.SourceCodePath == '':
@@ -802,7 +843,7 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re
 				elif action == 'Build_PhySim':
 					HTML=ldpc.Build_PhySim(HTML,CONST)
 					if ldpc.exitStatus==1:
-						RAN.prematureExit = False
+						RAN.prematureExit = True
 				elif action == 'Run_PhySim':
 					HTML=ldpc.Run_PhySim(HTML,CONST,id)
 				elif action == 'Build_Image':
@@ -815,9 +856,25 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re
 					SCA.CppCheckAnalysis(HTML)
 				elif action == 'Deploy_Run_PhySim':
 					PHYSIM.Deploy_PhySim(HTML, RAN)
+				elif action == 'DeployGenObject':
+					CONTAINERS.DeployGenObject(HTML)
+					if CONTAINERS.exitStatus==1:
+						RAN.prematureExit = True
+				elif action == 'UndeployGenObject':
+					CONTAINERS.UndeployGenObject(HTML)
+					if CONTAINERS.exitStatus==1:
+						RAN.prematureExit = True
+				elif action == 'PingFromContainer':
+					CONTAINERS.PingFromContainer(HTML)
+					if CONTAINERS.exitStatus==1:
+						RAN.prematureExit = True
+				elif action == 'IperfFromContainer':
+					CONTAINERS.IperfFromContainer(HTML)
+					if CONTAINERS.exitStatus==1:
+						RAN.prematureExit = True
 				else:
 					sys.exit('Invalid class (action) from xml')
-				if not RAN.prematureExit:
+				if RAN.prematureExit:
 					if CiTestObj.testCase_id == CiTestObj.testMinStableId:
 						logging.debug('Scenario has reached minimal stability point')
 						CiTestObj.testStabilityPointReached = True
diff --git a/ci-scripts/xml_class_list.yml b/ci-scripts/xml_class_list.yml
index a43e5b79c01a33b54146edad0976624e8ccb523e..d8e1b26a215ddabafbea38471a0c6f0b34e71f86 100755
--- a/ci-scripts/xml_class_list.yml
+++ b/ci-scripts/xml_class_list.yml
@@ -41,3 +41,7 @@
   - Undeploy_Object
   - Cppcheck_Analysis
   - Deploy_Run_PhySim
+  - DeployGenObject
+  - UndeployGenObject
+  - PingFromContainer
+  - IperfFromContainer
diff --git a/ci-scripts/xml_files/container_5g_rfsim.xml b/ci-scripts/xml_files/container_5g_rfsim.xml
new file mode 100644
index 0000000000000000000000000000000000000000..8847c1189429ec8acc3f9f18d71a5d064a2a141e
--- /dev/null
+++ b/ci-scripts/xml_files/container_5g_rfsim.xml
@@ -0,0 +1,103 @@
+<!--
+
+ 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>rfsim-5gnr</htmlTabRef>
+        <htmlTabName>Testing 5G NR RF sim in containers</htmlTabName>
+        <htmlTabIcon>wrench</htmlTabIcon>
+        <TestCaseRequestedList>
+ 000001
+ 000002
+ 000003
+ 020001
+ 020002
+ 030001
+ 030002
+ 100001
+        </TestCaseRequestedList>
+        <TestCaseExclusionList></TestCaseExclusionList>
+
+        <testCase id="000001">
+                <class>DeployGenObject</class>
+                <desc>Deploy OAI 5G CoreNetwork</desc>
+                <yaml_path>yaml_files/5g_rfsimulator</yaml_path>
+                <services>mysql oai-nrf oai-amf oai-smf oai-spgwu oai-ext-dn</services>
+                <nb_healthy>6</nb_healthy>
+        </testCase>
+
+        <testCase id="000002">
+                <class>DeployGenObject</class>
+                <desc>Deploy OAI 5G gNB RF sim SA</desc>
+                <yaml_path>yaml_files/5g_rfsimulator</yaml_path>
+                <services>oai-gnb</services>
+                <nb_healthy>7</nb_healthy>
+        </testCase>
+
+        <testCase id="000003">
+                <class>DeployGenObject</class>
+                <desc>Deploy OAI 5G NR-UE RF sim SA</desc>
+                <yaml_path>yaml_files/5g_rfsimulator</yaml_path>
+                <services>oai-nr-ue</services>
+                <nb_healthy>8</nb_healthy>
+        </testCase>
+
+        <testCase id="020001">
+                <class>PingFromContainer</class>
+                <desc>Ping ext-dn from NR-UE</desc>
+                <container_name>rfsim5g-oai-nr-ue</container_name>
+                <options>-I oaitun_ue1 -c 20 192.168.72.135</options>
+                <loss_threshold>5</loss_threshold>
+        </testCase>
+
+        <testCase id="020002">
+                <class>PingFromContainer</class>
+                <desc>Ping NR-UE from ext-dn</desc>
+		<container_name>rfsim5g-oai-ext-dn</container_name>
+                <options>-c 20 12.1.1.2</options>
+                <loss_threshold>5</loss_threshold>
+        </testCase>
+
+        <testCase id="030001">
+                <class>IperfFromContainer</class>
+                <desc>Iperf UDP Downlink</desc>
+                <server_container_name>rfsim5g-oai-nr-ue</server_container_name>
+                <client_container_name>rfsim5g-oai-ext-dn</client_container_name>
+                <server_options>-B 12.1.1.2 -u -i 1 -s</server_options>
+                <client_options>-c 12.1.1.2 -u -i 1 -t 30 -b 400K</client_options>
+        </testCase>
+
+        <testCase id="030002">
+                <class>IperfFromContainer</class>
+                <desc>Iperf UDP Uplink</desc>
+                <server_container_name>rfsim5g-oai-ext-dn</server_container_name>
+                <client_container_name>rfsim5g-oai-nr-ue</client_container_name>
+                <server_options>-u -i 1 -s</server_options>
+                <client_options>-B 12.1.1.2 -c 192.168.72.135 -u -i 1 -t 30 -b 20K</client_options>
+        </testCase>
+
+        <testCase id="100001">
+                <class>UndeployGenObject</class>
+                <desc>Undeploy all OAI 5G stack</desc>
+                <yaml_path>yaml_files/5g_rfsimulator</yaml_path>
+        </testCase>
+
+</testCaseList>
diff --git a/ci-scripts/xml_files/container_5g_rfsim_down.xml b/ci-scripts/xml_files/container_5g_rfsim_down.xml
new file mode 100644
index 0000000000000000000000000000000000000000..57b0f67a214c297fe86648559e29aaf04012c1f7
--- /dev/null
+++ b/ci-scripts/xml_files/container_5g_rfsim_down.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>rfsim-5gnr-down</htmlTabRef>
+        <htmlTabName>CleanUp 5G RF</htmlTabName>
+        <htmlTabIcon>trash</htmlTabIcon>
+        <TestCaseRequestedList>
+ 100002
+        </TestCaseRequestedList>
+        <TestCaseExclusionList></TestCaseExclusionList>
+
+        <testCase id="100002">
+                <class>UndeployGenObject</class>
+                <desc>Undeploy all OAI 5G stack</desc>
+                <yaml_path>yaml_files/5g_rfsimulator</yaml_path>
+        </testCase>
+
+</testCaseList>
diff --git a/ci-scripts/yaml_files/5g_rfsimulator/docker-compose.yaml b/ci-scripts/yaml_files/5g_rfsimulator/docker-compose.yaml
index 02cf95bc5910c7452278c047f38b743ba8296e84..5da7a353ab3ccc373d9d7830c85775be06fb5dea 100644
--- a/ci-scripts/yaml_files/5g_rfsimulator/docker-compose.yaml
+++ b/ci-scripts/yaml_files/5g_rfsimulator/docker-compose.yaml
@@ -206,7 +206,7 @@ services:
         privileged: true
         container_name: rfsim5g-oai-ext-dn
         entrypoint: /bin/bash -c \
-              "apt update; apt install -y iptables iproute2 iperf iputils-ping;"\
+              "apt update; apt install -y procps iptables iproute2 iperf iputils-ping;"\
               "iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;"\
               "ip route add 12.1.1.0/24 via 192.168.72.134 dev eth0; sleep infinity"
         depends_on: