2020-02-11 16:45:26 +00:00
|
|
|
# osmo_gsm_tester: specifics for running an SRS eNodeB process
|
|
|
|
#
|
|
|
|
# Copyright (C) 2020 by sysmocom - s.f.m.c. GmbH
|
|
|
|
#
|
|
|
|
# Author: Pau Espin Pedrol <pespin@sysmocom.de>
|
|
|
|
#
|
|
|
|
# This program is free software: you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU General Public License as
|
|
|
|
# published by the Free Software Foundation, either version 3 of the
|
|
|
|
# License, or (at your option) any later version.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
import os
|
|
|
|
import pprint
|
|
|
|
|
2020-04-10 18:46:07 +00:00
|
|
|
from ..core import log, util, config, template, process, remote
|
2020-08-24 16:17:35 +00:00
|
|
|
from ..core.event_loop import MainLoop
|
2020-03-30 11:51:21 +00:00
|
|
|
from . import enb
|
2020-04-20 11:29:31 +00:00
|
|
|
from . import rfemu
|
2020-06-19 13:47:32 +00:00
|
|
|
from .srslte_common import srslte_common
|
2020-02-11 16:45:26 +00:00
|
|
|
|
2020-05-04 10:05:05 +00:00
|
|
|
from ..core import schema
|
|
|
|
|
|
|
|
def on_register_schemas():
|
2021-05-10 15:04:40 +00:00
|
|
|
resource_schema = {
|
|
|
|
'prerun_scripts[]': schema.STR,
|
|
|
|
'postrun_scripts[]': schema.STR,
|
2021-05-10 15:57:05 +00:00
|
|
|
'remote_dir': schema.STR
|
2021-05-10 15:04:40 +00:00
|
|
|
}
|
|
|
|
schema.register_resource_schema('enb', resource_schema)
|
|
|
|
|
2020-05-04 10:05:05 +00:00
|
|
|
config_schema = {
|
|
|
|
'enable_pcap': schema.BOOL_STR,
|
2021-03-16 13:53:45 +00:00
|
|
|
'enable_tracing': schema.BOOL_STR,
|
2020-11-16 11:39:43 +00:00
|
|
|
'enable_ul_qam64': schema.BOOL_STR,
|
2020-06-18 12:52:39 +00:00
|
|
|
'log_all_level': schema.STR,
|
2020-05-04 10:05:05 +00:00
|
|
|
}
|
|
|
|
schema.register_config_schema('enb', config_schema)
|
|
|
|
|
2020-02-13 18:29:55 +00:00
|
|
|
def rf_type_valid(rf_type_str):
|
2021-05-10 15:08:14 +00:00
|
|
|
return rf_type_str in ('zmq', 'uhd', 'soapy', 'bladerf', 'fapi')
|
2020-02-13 18:29:55 +00:00
|
|
|
|
2020-06-19 13:47:32 +00:00
|
|
|
class srsENB(enb.eNodeB, srslte_common):
|
2020-02-11 16:45:26 +00:00
|
|
|
|
|
|
|
REMOTE_DIR = '/osmo-gsm-tester-srsenb'
|
|
|
|
BINFILE = 'srsenb'
|
|
|
|
CFGFILE = 'srsenb.conf'
|
|
|
|
CFGFILE_SIB = 'srsenb_sib.conf'
|
|
|
|
CFGFILE_RR = 'srsenb_rr.conf'
|
|
|
|
CFGFILE_DRB = 'srsenb_drb.conf'
|
|
|
|
LOGFILE = 'srsenb.log'
|
2021-05-10 19:43:31 +00:00
|
|
|
PCAPFILE = 'srsenb_mac.pcap'
|
|
|
|
S1AP_PCAPFILE = 'srsenb_s1ap.pcap'
|
2021-03-16 13:53:45 +00:00
|
|
|
TRACINGFILE = 'srsenb_tracing.log'
|
|
|
|
METRICSFILE = 'srsenb_metrics.csv'
|
2020-02-11 16:45:26 +00:00
|
|
|
|
2020-05-05 10:54:37 +00:00
|
|
|
def __init__(self, testenv, conf):
|
|
|
|
super().__init__(testenv, conf, srsENB.BINFILE)
|
2020-09-14 16:14:15 +00:00
|
|
|
srslte_common.__init__(self)
|
2020-02-11 16:45:26 +00:00
|
|
|
self.ue = None
|
|
|
|
self.run_dir = None
|
2020-04-20 11:29:31 +00:00
|
|
|
self.gen_conf = None
|
2020-02-11 16:45:26 +00:00
|
|
|
self.config_file = None
|
|
|
|
self.config_sib_file = None
|
|
|
|
self.config_rr_file = None
|
|
|
|
self.config_drb_file = None
|
2021-03-16 13:53:45 +00:00
|
|
|
self.tracing_file = None
|
2020-03-16 11:42:17 +00:00
|
|
|
self.log_file = None
|
|
|
|
self.pcap_file = None
|
2021-05-10 19:43:31 +00:00
|
|
|
self.s1ap_pcap_file = None
|
2020-02-11 16:45:26 +00:00
|
|
|
self.process = None
|
|
|
|
self.rem_host = None
|
2020-05-25 14:08:25 +00:00
|
|
|
self.remote_run_dir = None
|
2020-02-11 16:45:26 +00:00
|
|
|
self.remote_config_file = None
|
|
|
|
self.remote_config_sib_file = None
|
|
|
|
self.remote_config_rr_file = None
|
|
|
|
self.remote_config_drb_file = None
|
|
|
|
self.remote_log_file = None
|
2020-03-16 11:42:17 +00:00
|
|
|
self.remote_pcap_file = None
|
2021-05-10 19:43:31 +00:00
|
|
|
self.remote_s1ap_pcap_file = None
|
2021-03-16 13:53:45 +00:00
|
|
|
self.remote_tracing_file = None
|
|
|
|
self.remote_metrics_file = None
|
2020-03-16 11:42:17 +00:00
|
|
|
self.enable_pcap = False
|
2020-12-17 17:01:13 +00:00
|
|
|
self.enable_ul_qam64 = False
|
2021-03-16 13:53:45 +00:00
|
|
|
self.enable_tracing = False
|
2020-06-19 13:47:32 +00:00
|
|
|
self.metrics_file = None
|
2021-03-16 13:53:45 +00:00
|
|
|
self.have_metrics_file = False
|
2020-08-24 16:17:35 +00:00
|
|
|
self.stop_sleep_time = 6 # We require at most 5s to stop
|
2020-05-05 10:54:37 +00:00
|
|
|
self.testenv = testenv
|
2020-04-01 17:51:08 +00:00
|
|
|
self._additional_args = []
|
2020-02-13 18:29:55 +00:00
|
|
|
if not rf_type_valid(conf.get('rf_dev_type', None)):
|
|
|
|
raise log.Error('Invalid rf_dev_type=%s' % conf.get('rf_dev_type', None))
|
2020-02-11 16:45:26 +00:00
|
|
|
|
|
|
|
def cleanup(self):
|
|
|
|
if self.process is None:
|
|
|
|
return
|
2020-05-26 10:32:19 +00:00
|
|
|
if self._run_node.is_local():
|
2020-02-11 16:45:26 +00:00
|
|
|
return
|
2020-08-24 16:17:35 +00:00
|
|
|
|
|
|
|
# Make sure we give the UE time to tear down
|
|
|
|
self.sleep_after_stop()
|
|
|
|
|
2021-05-10 15:04:40 +00:00
|
|
|
# Execute the post run tasks.
|
|
|
|
if not self.postrun_tasks():
|
|
|
|
self.log('Could not execute the post run tasks')
|
|
|
|
|
2021-03-16 13:53:45 +00:00
|
|
|
# copy back files (may not exist, for instance if there was an early error of process):
|
|
|
|
self.scp_back_metrics(raiseException=False)
|
|
|
|
|
2020-02-11 16:45:26 +00:00
|
|
|
# copy back files (may not exist, for instance if there was an early error of process):
|
|
|
|
try:
|
|
|
|
self.rem_host.scpfrom('scp-back-log', self.remote_log_file, self.log_file)
|
|
|
|
except Exception as e:
|
|
|
|
self.log(repr(e))
|
2020-03-16 11:42:17 +00:00
|
|
|
if self.enable_pcap:
|
|
|
|
try:
|
|
|
|
self.rem_host.scpfrom('scp-back-pcap', self.remote_pcap_file, self.pcap_file)
|
|
|
|
except Exception as e:
|
|
|
|
self.log(repr(e))
|
2021-05-10 19:43:31 +00:00
|
|
|
try:
|
|
|
|
self.rem_host.scpfrom('scp-back-s1-pcap', self.remote_s1ap_pcap_file, self.s1ap_pcap_file)
|
|
|
|
except Exception as e:
|
|
|
|
self.log(repr(e))
|
2021-03-16 13:53:45 +00:00
|
|
|
if self.enable_tracing:
|
|
|
|
try:
|
|
|
|
self.rem_host.scpfrom('scp-back-tracing', self.remote_tracing_file, self.tracing_file)
|
|
|
|
except Exception as e:
|
|
|
|
self.log(repr(e))
|
2020-02-11 16:45:26 +00:00
|
|
|
|
2020-06-19 13:47:32 +00:00
|
|
|
# Collect KPIs for each TC
|
2021-01-29 16:45:18 +00:00
|
|
|
self.testenv.test().set_kpis(self.get_kpi_tree())
|
4g: Introduce ZMQ GnuRadio stream broker
srsENB currently creates 1 zmq stream (1 tx, 1 rx) for each cell (2 if
MIMO is enabled). Each cell transceives on a given EARFCN (and several
cells can transmit on same EARFCN).
However, for handover test purposes, we want to join all cells operating
on the same EARFCN to transceive on the same ZMQ conn, so that an srsUE
can interact with them at the same time (same as if the medium was shared).
Furthermore, we want to set different gains on each of those paths
before merging them in order to emulate RF conditions like handover.
In order to do so, a new element called the Broker is introduced, which
is placed in between ENBs and UEs ZMQ conenctions, multiplexing the
connections on the ENB side towards the UE side.
A separate process for the broker is run remotely (ENB run host) which
listens on a ctrl socket for commands. An internal Broker class is used
in osmo-gsm-tester to interact with the remote script, for instance to
configure the ports, start and stop the remote process, send commands to
it, etc.
On each ENB, when the rfemu "gnuradio_zmq" rfemu implementation is selected
in configuration, it will configure its zmq connections and the UE ones to
go over the Broker.
As a result, that means the UE zmq port configuration is expected to be
different than when no broker is in used, since there's the multiplexing
per EARFCN in between.
In this commit, only 1 ENB is supported, but multi-enb support is
planned in the future.
The handover test passes in the docker setup with this config:
"""
OSMO_GSM_TESTER_OPTS="-T -l dbg -s 4g:srsue-rftype@zmq+srsenb-rftype@zmq+" \
"mod-enb-nprb@6+mod-enb-ncells@2+mod-enb-cells-2ca+suite-4g@10,2+" \
"mod-enb-meas-enable -t =handover.py"
"""
and in resources.conf (or scenario), added:
"""
enb:
...
cell_list:
- dl_rfemu:
type: gnuradio_zmq
- dl_rfemu:
type: gnuradio_zmq
"""
Note that since the broker is used, there's not need for mod-srsue-ncarriers@2
since the broker is joining the 2 enb cells into 1 stream on the UE side.
Change-Id: I6282cda400558dcb356276786d91e6388524c5b1
2020-10-05 17:23:38 +00:00
|
|
|
# Clean up for parent class:
|
|
|
|
super().cleanup()
|
2020-06-19 13:47:32 +00:00
|
|
|
|
2021-03-16 13:53:45 +00:00
|
|
|
def scp_back_metrics(self, raiseException=True):
|
|
|
|
''' Copy back metrics only if they have not been copied back yet '''
|
|
|
|
if not self.have_metrics_file:
|
|
|
|
# file is not properly flushed until the process has stopped.
|
|
|
|
if self.running():
|
|
|
|
self.stop()
|
|
|
|
|
|
|
|
# only SCP back if not running locally
|
|
|
|
if not self._run_node.is_local():
|
|
|
|
try:
|
|
|
|
self.rem_host.scpfrom('scp-back-metrics', self.remote_metrics_file, self.metrics_file)
|
|
|
|
except Exception as e:
|
|
|
|
if raiseException:
|
|
|
|
self.err('Failed copying back metrics file from remote host')
|
|
|
|
raise e
|
|
|
|
else:
|
|
|
|
# only log error
|
|
|
|
self.log(repr(e))
|
|
|
|
# make sure to only call it once
|
|
|
|
self.have_metrics_file = True
|
|
|
|
else:
|
|
|
|
self.dbg('Metrics have already been copied back')
|
|
|
|
|
2021-05-10 15:04:40 +00:00
|
|
|
def run_task(self, task):
|
|
|
|
# Get the arguments.
|
|
|
|
args_index = task.find('args=')
|
|
|
|
|
|
|
|
args = ()
|
|
|
|
# No arguments, all the string is the script.
|
|
|
|
if args_index == -1:
|
|
|
|
index = task.rfind('/')
|
|
|
|
task_name = task [index + 1:]
|
|
|
|
run_dir = util.Dir(self.run_dir.new_dir(task_name))
|
|
|
|
args = (task,)
|
|
|
|
self.log(f'task name is: {task_name}')
|
|
|
|
self.log(f'Running the script: {task} in the run dir: {run_dir}')
|
|
|
|
else:
|
|
|
|
ntask = task[:args_index - 1]
|
|
|
|
index = ntask.rfind('/')
|
|
|
|
task_name = ntask [index + 1:]
|
|
|
|
run_dir = util.Dir(self.run_dir.new_dir(task_name))
|
|
|
|
args = (ntask,)
|
|
|
|
args += tuple(task[args_index + 5:].split(','))
|
|
|
|
self.log(f'task name is: {task_name}')
|
|
|
|
self.log(f'Running the script: {task} in the run dir: {run_dir} with args: {args}')
|
|
|
|
|
|
|
|
proc = process.Process(task_name, run_dir, args)
|
|
|
|
# Set the timeout to a high value 20 minutes.
|
|
|
|
proc.set_default_wait_timeout(1200)
|
|
|
|
returncode = proc.launch_sync()
|
|
|
|
if returncode != 0:
|
|
|
|
raise log.Error('Error executing the pre run scripts. Aborting')
|
|
|
|
return False
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
# Runs all the tasks that are intended to run before the execution of the eNodeb.
|
|
|
|
def prerun_tasks(self):
|
|
|
|
prerun_tasklist = self._conf.get('prerun_scripts', None)
|
|
|
|
if not prerun_tasklist:
|
|
|
|
return True
|
|
|
|
|
|
|
|
for task in prerun_tasklist:
|
|
|
|
if not self.run_task(task):
|
|
|
|
return False
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
# Runs all the tasks that are intended to run after the execution of the eNodeb.
|
|
|
|
def postrun_tasks(self):
|
|
|
|
postrun_tasklist = self._conf.get('postrun_scripts', None)
|
|
|
|
if not postrun_tasklist:
|
|
|
|
return True
|
|
|
|
|
|
|
|
for task in postrun_tasklist:
|
|
|
|
if not self.run_task(task):
|
|
|
|
return False
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
2020-02-11 16:45:26 +00:00
|
|
|
def start(self, epc):
|
|
|
|
self.log('Starting srsENB')
|
2020-03-31 10:35:19 +00:00
|
|
|
self._epc = epc
|
2020-05-11 08:56:52 +00:00
|
|
|
self.run_dir = util.Dir(self.testenv.test().get_run_dir().new_dir(self.name()))
|
2020-02-11 16:45:26 +00:00
|
|
|
self.configure()
|
2021-05-10 15:04:40 +00:00
|
|
|
|
|
|
|
if not self.prerun_tasks():
|
|
|
|
self.log('Pre run tasks failed. Aborting')
|
|
|
|
return
|
|
|
|
|
2020-05-26 10:32:19 +00:00
|
|
|
if self._run_node.is_local():
|
2020-02-11 16:45:26 +00:00
|
|
|
self.start_locally()
|
2020-05-26 10:32:19 +00:00
|
|
|
else:
|
|
|
|
self.start_remotely()
|
2020-02-11 16:45:26 +00:00
|
|
|
|
2020-03-24 15:39:35 +00:00
|
|
|
# send t+Enter to enable console trace
|
|
|
|
self.dbg('Enabling console trace')
|
|
|
|
self.process.stdin_write('t\n')
|
|
|
|
|
2021-01-08 11:34:48 +00:00
|
|
|
def stop(self):
|
|
|
|
# Implemented in srslte_common.py
|
|
|
|
srslte_common.stop(self)
|
|
|
|
|
2020-02-11 16:45:26 +00:00
|
|
|
def start_remotely(self):
|
|
|
|
remote_env = { 'LD_LIBRARY_PATH': self.remote_inst.child('lib') }
|
|
|
|
remote_binary = self.remote_inst.child('bin', srsENB.BINFILE)
|
2020-04-16 11:35:59 +00:00
|
|
|
args = (remote_binary, self.remote_config_file)
|
2020-04-01 17:51:08 +00:00
|
|
|
args += tuple(self._additional_args)
|
2020-02-11 16:45:26 +00:00
|
|
|
|
2020-05-25 14:08:25 +00:00
|
|
|
self.process = self.rem_host.RemoteProcessSafeExit(srsENB.BINFILE, self.remote_run_dir, args, remote_env=remote_env, wait_time_sec=7)
|
2020-05-05 10:54:37 +00:00
|
|
|
self.testenv.remember_to_stop(self.process)
|
2020-02-11 16:45:26 +00:00
|
|
|
self.process.launch()
|
|
|
|
|
|
|
|
def start_locally(self):
|
2020-04-16 11:35:59 +00:00
|
|
|
binary = self.inst.child('bin', srsENB.BINFILE)
|
|
|
|
lib = self.inst.child('lib')
|
2020-02-11 16:45:26 +00:00
|
|
|
env = { 'LD_LIBRARY_PATH': util.prepend_library_path(lib) }
|
2020-04-16 11:35:59 +00:00
|
|
|
args = (binary, os.path.abspath(self.config_file))
|
2020-04-01 17:51:08 +00:00
|
|
|
args += tuple(self._additional_args)
|
2020-02-11 16:45:26 +00:00
|
|
|
|
|
|
|
self.process = process.Process(self.name(), self.run_dir, args, env=env)
|
2020-05-05 10:54:37 +00:00
|
|
|
self.testenv.remember_to_stop(self.process)
|
2020-02-11 16:45:26 +00:00
|
|
|
self.process.launch()
|
|
|
|
|
2020-03-31 08:49:47 +00:00
|
|
|
def gen_conf_file(self, path, filename, values):
|
|
|
|
self.dbg('srsENB ' + filename + ':\n' + pprint.pformat(values))
|
|
|
|
|
|
|
|
with open(path, 'w') as f:
|
|
|
|
r = template.render(filename, values)
|
|
|
|
self.dbg(r)
|
|
|
|
f.write(r)
|
2020-02-11 16:45:26 +00:00
|
|
|
|
2020-03-31 08:49:47 +00:00
|
|
|
def configure(self):
|
2020-05-26 10:51:44 +00:00
|
|
|
self.inst = util.Dir(os.path.abspath(self.testenv.suite().trial().get_inst('srslte', self._run_node.run_label())))
|
2020-04-16 11:35:59 +00:00
|
|
|
if not os.path.isdir(self.inst.child('lib')):
|
|
|
|
raise log.Error('No lib/ in', self.inst)
|
|
|
|
if not self.inst.isfile('bin', srsENB.BINFILE):
|
|
|
|
raise log.Error('No %s binary in' % srsENB.BINFILE, self.inst)
|
|
|
|
|
|
|
|
self.config_file = self.run_dir.child(srsENB.CFGFILE)
|
|
|
|
self.config_sib_file = self.run_dir.child(srsENB.CFGFILE_SIB)
|
|
|
|
self.config_rr_file = self.run_dir.child(srsENB.CFGFILE_RR)
|
|
|
|
self.config_drb_file = self.run_dir.child(srsENB.CFGFILE_DRB)
|
|
|
|
self.log_file = self.run_dir.child(srsENB.LOGFILE)
|
|
|
|
self.pcap_file = self.run_dir.child(srsENB.PCAPFILE)
|
2021-05-10 19:43:31 +00:00
|
|
|
self.s1ap_pcap_file = self.run_dir.child(srsENB.S1AP_PCAPFILE)
|
2021-03-16 13:53:45 +00:00
|
|
|
self.metrics_file = self.run_dir.child(srsENB.METRICSFILE)
|
|
|
|
self.tracing_file = self.run_dir.child(srsENB.TRACINGFILE)
|
2020-04-16 11:35:59 +00:00
|
|
|
|
2020-05-26 10:32:19 +00:00
|
|
|
if not self._run_node.is_local():
|
|
|
|
self.rem_host = remote.RemoteHost(self.run_dir, self._run_node.ssh_user(), self._run_node.ssh_addr())
|
2020-04-16 11:35:59 +00:00
|
|
|
remote_prefix_dir = util.Dir(srsENB.REMOTE_DIR)
|
2021-05-10 15:57:05 +00:00
|
|
|
|
|
|
|
# Modify the default remote directory if it is provided by the configuration.
|
|
|
|
remote_path = self._conf.get('remote_dir', None)
|
|
|
|
if remote_path:
|
|
|
|
remote_prefix_dir = util.Dir(remote_path)
|
|
|
|
self.log(f'Setting the remote dir to: {remote_path}')
|
|
|
|
|
2020-04-16 11:35:59 +00:00
|
|
|
self.remote_inst = util.Dir(remote_prefix_dir.child(os.path.basename(str(self.inst))))
|
2020-10-22 13:46:42 +00:00
|
|
|
self.remote_run_dir = util.Dir(remote_prefix_dir.child(self.name()))
|
2020-04-16 11:35:59 +00:00
|
|
|
|
2020-05-25 14:08:25 +00:00
|
|
|
self.remote_config_file = self.remote_run_dir.child(srsENB.CFGFILE)
|
|
|
|
self.remote_config_sib_file = self.remote_run_dir.child(srsENB.CFGFILE_SIB)
|
|
|
|
self.remote_config_rr_file = self.remote_run_dir.child(srsENB.CFGFILE_RR)
|
|
|
|
self.remote_config_drb_file = self.remote_run_dir.child(srsENB.CFGFILE_DRB)
|
|
|
|
self.remote_log_file = self.remote_run_dir.child(srsENB.LOGFILE)
|
|
|
|
self.remote_pcap_file = self.remote_run_dir.child(srsENB.PCAPFILE)
|
2021-05-10 19:43:31 +00:00
|
|
|
self.remote_s1ap_pcap_file = self.remote_run_dir.child(srsENB.S1AP_PCAPFILE)
|
2021-03-16 13:53:45 +00:00
|
|
|
self.remote_metrics_file = self.remote_run_dir.child(srsENB.METRICSFILE)
|
|
|
|
self.remote_tracing_file = self.remote_run_dir.child(srsENB.TRACINGFILE)
|
2020-04-16 11:35:59 +00:00
|
|
|
|
2020-04-01 11:55:51 +00:00
|
|
|
values = super().configure(['srsenb'])
|
2020-02-13 18:29:55 +00:00
|
|
|
|
2021-03-16 13:53:45 +00:00
|
|
|
metricsfile = self.metrics_file if self._run_node.is_local() else self.remote_metrics_file
|
|
|
|
tracingfile = self.tracing_file if self._run_node.is_local() else self.remote_tracing_file
|
2020-05-26 10:32:19 +00:00
|
|
|
sibfile = self.config_sib_file if self._run_node.is_local() else self.remote_config_sib_file
|
|
|
|
rrfile = self.config_rr_file if self._run_node.is_local() else self.remote_config_rr_file
|
|
|
|
drbfile = self.config_drb_file if self._run_node.is_local() else self.remote_config_drb_file
|
|
|
|
logfile = self.log_file if self._run_node.is_local() else self.remote_log_file
|
|
|
|
pcapfile = self.pcap_file if self._run_node.is_local() else self.remote_pcap_file
|
2021-05-10 19:43:31 +00:00
|
|
|
s1ap_pcapfile = self.s1ap_pcap_file if self._run_node.is_local() else self.remote_s1ap_pcap_file
|
2021-03-16 13:53:45 +00:00
|
|
|
config.overlay(values, dict(enb=dict(metrics_filename=metricsfile,
|
|
|
|
tracing_filename=tracingfile,
|
|
|
|
sib_filename=sibfile,
|
2020-04-16 11:35:59 +00:00
|
|
|
rr_filename=rrfile,
|
|
|
|
drb_filename=drbfile,
|
|
|
|
log_filename=logfile,
|
|
|
|
pcap_filename=pcapfile,
|
2021-05-10 19:43:31 +00:00
|
|
|
s1ap_pcap_filename=s1ap_pcapfile,
|
2020-04-16 11:35:59 +00:00
|
|
|
)))
|
|
|
|
|
2020-03-16 11:42:17 +00:00
|
|
|
# Convert parsed boolean string to Python boolean:
|
|
|
|
self.enable_pcap = util.str2bool(values['enb'].get('enable_pcap', 'false'))
|
|
|
|
config.overlay(values, dict(enb={'enable_pcap': self.enable_pcap}))
|
|
|
|
|
2021-03-16 13:53:45 +00:00
|
|
|
self.enable_tracing = util.str2bool(values['enb'].get('enable_tracing', 'false'))
|
|
|
|
config.overlay(values, dict(enb={'enable_tracing': self.enable_tracing}))
|
|
|
|
|
2020-12-17 17:01:13 +00:00
|
|
|
self.enable_ul_qam64 = util.str2bool(values['enb'].get('enable_ul_qam64', 'false'))
|
|
|
|
config.overlay(values, dict(enb={'enable_ul_qam64': self.enable_ul_qam64}))
|
|
|
|
|
2020-09-02 20:24:11 +00:00
|
|
|
config.overlay(values, dict(enb={'enable_dl_awgn': util.str2bool(values['enb'].get('enable_dl_awgn', 'false'))}))
|
2020-10-12 14:57:10 +00:00
|
|
|
config.overlay(values, dict(enb={'rf_dev_sync': values['enb'].get('rf_dev_sync', None)}))
|
2020-09-02 20:24:11 +00:00
|
|
|
|
2020-06-15 15:01:16 +00:00
|
|
|
self._additional_args = []
|
|
|
|
for add_args in values['enb'].get('additional_args', []):
|
|
|
|
self._additional_args += add_args.split()
|
2020-04-01 17:51:08 +00:00
|
|
|
|
2020-02-13 18:29:55 +00:00
|
|
|
# We need to set some specific variables programatically here to match IP addresses:
|
|
|
|
if self._conf.get('rf_dev_type') == 'zmq':
|
4g: Introduce ZMQ GnuRadio stream broker
srsENB currently creates 1 zmq stream (1 tx, 1 rx) for each cell (2 if
MIMO is enabled). Each cell transceives on a given EARFCN (and several
cells can transmit on same EARFCN).
However, for handover test purposes, we want to join all cells operating
on the same EARFCN to transceive on the same ZMQ conn, so that an srsUE
can interact with them at the same time (same as if the medium was shared).
Furthermore, we want to set different gains on each of those paths
before merging them in order to emulate RF conditions like handover.
In order to do so, a new element called the Broker is introduced, which
is placed in between ENBs and UEs ZMQ conenctions, multiplexing the
connections on the ENB side towards the UE side.
A separate process for the broker is run remotely (ENB run host) which
listens on a ctrl socket for commands. An internal Broker class is used
in osmo-gsm-tester to interact with the remote script, for instance to
configure the ports, start and stop the remote process, send commands to
it, etc.
On each ENB, when the rfemu "gnuradio_zmq" rfemu implementation is selected
in configuration, it will configure its zmq connections and the UE ones to
go over the Broker.
As a result, that means the UE zmq port configuration is expected to be
different than when no broker is in used, since there's the multiplexing
per EARFCN in between.
In this commit, only 1 ENB is supported, but multi-enb support is
planned in the future.
The handover test passes in the docker setup with this config:
"""
OSMO_GSM_TESTER_OPTS="-T -l dbg -s 4g:srsue-rftype@zmq+srsenb-rftype@zmq+" \
"mod-enb-nprb@6+mod-enb-ncells@2+mod-enb-cells-2ca+suite-4g@10,2+" \
"mod-enb-meas-enable -t =handover.py"
"""
and in resources.conf (or scenario), added:
"""
enb:
...
cell_list:
- dl_rfemu:
type: gnuradio_zmq
- dl_rfemu:
type: gnuradio_zmq
"""
Note that since the broker is used, there's not need for mod-srsue-ncarriers@2
since the broker is joining the 2 enb cells into 1 stream on the UE side.
Change-Id: I6282cda400558dcb356276786d91e6388524c5b1
2020-10-05 17:23:38 +00:00
|
|
|
rf_dev_args = self.get_zmq_rf_dev_args(values)
|
2020-02-27 14:05:11 +00:00
|
|
|
config.overlay(values, dict(enb=dict(rf_dev_args=rf_dev_args)))
|
2020-03-26 19:54:45 +00:00
|
|
|
|
|
|
|
# Set UHD frame size as a function of the cell bandwidth on B2XX
|
2020-04-07 16:51:57 +00:00
|
|
|
if self._conf.get('rf_dev_type') == 'uhd' and values['enb'].get('rf_dev_args', None) is not None:
|
2020-03-26 19:54:45 +00:00
|
|
|
if 'b200' in values['enb'].get('rf_dev_args'):
|
|
|
|
rf_dev_args = values['enb'].get('rf_dev_args', '')
|
|
|
|
rf_dev_args += ',' if rf_dev_args != '' and not rf_dev_args.endswith(',') else ''
|
|
|
|
|
2020-09-23 15:07:07 +00:00
|
|
|
if self._num_prb == 75:
|
|
|
|
rf_dev_args += 'master_clock_rate=15.36e6,'
|
|
|
|
|
|
|
|
if self._txmode <= 2:
|
|
|
|
# SISO config
|
|
|
|
if self._num_prb < 25:
|
|
|
|
rf_dev_args += 'send_frame_size=512,recv_frame_size=512'
|
|
|
|
elif self._num_prb == 25:
|
|
|
|
rf_dev_args += 'send_frame_size=1024,recv_frame_size=1024'
|
|
|
|
else:
|
|
|
|
rf_dev_args += ''
|
|
|
|
else:
|
|
|
|
# MIMO config
|
2020-03-26 19:54:45 +00:00
|
|
|
rf_dev_args += 'num_recv_frames=64,num_send_frames=64'
|
2020-09-23 15:07:07 +00:00
|
|
|
if self._num_prb > 50:
|
|
|
|
# Reduce over the wire format to sc12
|
|
|
|
rf_dev_args += ',otw_format=sc12'
|
2020-03-26 19:54:45 +00:00
|
|
|
|
|
|
|
config.overlay(values, dict(enb=dict(rf_dev_args=rf_dev_args)))
|
2020-02-11 16:45:26 +00:00
|
|
|
|
2021-05-10 15:08:14 +00:00
|
|
|
if self._conf.get('rf_dev_type') == 'fapi':
|
|
|
|
rf_dev_args = ''
|
|
|
|
config.overlay(values, dict(enb=dict(rf_dev_args=rf_dev_args)))
|
|
|
|
|
2020-04-20 11:29:31 +00:00
|
|
|
self.gen_conf = values
|
|
|
|
|
2020-03-31 08:49:47 +00:00
|
|
|
self.gen_conf_file(self.config_file, srsENB.CFGFILE, values)
|
|
|
|
self.gen_conf_file(self.config_sib_file, srsENB.CFGFILE_SIB, values)
|
|
|
|
self.gen_conf_file(self.config_rr_file, srsENB.CFGFILE_RR, values)
|
|
|
|
self.gen_conf_file(self.config_drb_file, srsENB.CFGFILE_DRB, values)
|
2020-02-11 16:45:26 +00:00
|
|
|
|
2020-05-26 10:32:19 +00:00
|
|
|
if not self._run_node.is_local():
|
2020-04-16 11:35:59 +00:00
|
|
|
self.rem_host.recreate_remote_dir(self.remote_inst)
|
|
|
|
self.rem_host.scp('scp-inst-to-remote', str(self.inst), remote_prefix_dir)
|
2020-05-25 14:08:25 +00:00
|
|
|
self.rem_host.recreate_remote_dir(self.remote_run_dir)
|
2020-04-16 11:35:59 +00:00
|
|
|
self.rem_host.scp('scp-cfg-to-remote', self.config_file, self.remote_config_file)
|
|
|
|
self.rem_host.scp('scp-cfg-sib-to-remote', self.config_sib_file, self.remote_config_sib_file)
|
|
|
|
self.rem_host.scp('scp-cfg-rr-to-remote', self.config_rr_file, self.remote_config_rr_file)
|
|
|
|
self.rem_host.scp('scp-cfg-drb-to-remote', self.config_drb_file, self.remote_config_drb_file)
|
|
|
|
|
2020-02-11 16:45:26 +00:00
|
|
|
def ue_add(self, ue):
|
|
|
|
if self.ue is not None:
|
|
|
|
raise log.Error("More than one UE per ENB not yet supported (ZeroMQ)")
|
|
|
|
self.ue = ue
|
|
|
|
|
|
|
|
def running(self):
|
|
|
|
return not self.process.terminated()
|
|
|
|
|
2021-01-05 13:14:48 +00:00
|
|
|
def get_counter(self, counter_name):
|
|
|
|
if counter_name == 'prach_received':
|
|
|
|
return self.process.get_counter_stdout('RACH:')
|
|
|
|
raise log.Error('counter %s not implemented!' % counter_name)
|
|
|
|
|
2021-01-29 16:45:18 +00:00
|
|
|
def get_kpis(self):
|
|
|
|
return srslte_common.get_kpis(self)
|
|
|
|
|
2020-04-20 11:29:31 +00:00
|
|
|
def get_rfemu(self, cell=0, dl=True):
|
|
|
|
cell_list = self.gen_conf['enb'].get('cell_list', None)
|
|
|
|
if cell_list is None or len(cell_list) < cell + 1:
|
|
|
|
raise log.Error('cell_list attribute or subitem not found!')
|
|
|
|
rfemu_cfg = cell_list[cell].get('dl_rfemu', None)
|
2020-06-30 12:19:40 +00:00
|
|
|
if rfemu_cfg is None:
|
2020-04-20 11:29:31 +00:00
|
|
|
raise log.Error('rfemu attribute not found in cell_list item!')
|
4g: Introduce ZMQ GnuRadio stream broker
srsENB currently creates 1 zmq stream (1 tx, 1 rx) for each cell (2 if
MIMO is enabled). Each cell transceives on a given EARFCN (and several
cells can transmit on same EARFCN).
However, for handover test purposes, we want to join all cells operating
on the same EARFCN to transceive on the same ZMQ conn, so that an srsUE
can interact with them at the same time (same as if the medium was shared).
Furthermore, we want to set different gains on each of those paths
before merging them in order to emulate RF conditions like handover.
In order to do so, a new element called the Broker is introduced, which
is placed in between ENBs and UEs ZMQ conenctions, multiplexing the
connections on the ENB side towards the UE side.
A separate process for the broker is run remotely (ENB run host) which
listens on a ctrl socket for commands. An internal Broker class is used
in osmo-gsm-tester to interact with the remote script, for instance to
configure the ports, start and stop the remote process, send commands to
it, etc.
On each ENB, when the rfemu "gnuradio_zmq" rfemu implementation is selected
in configuration, it will configure its zmq connections and the UE ones to
go over the Broker.
As a result, that means the UE zmq port configuration is expected to be
different than when no broker is in used, since there's the multiplexing
per EARFCN in between.
In this commit, only 1 ENB is supported, but multi-enb support is
planned in the future.
The handover test passes in the docker setup with this config:
"""
OSMO_GSM_TESTER_OPTS="-T -l dbg -s 4g:srsue-rftype@zmq+srsenb-rftype@zmq+" \
"mod-enb-nprb@6+mod-enb-ncells@2+mod-enb-cells-2ca+suite-4g@10,2+" \
"mod-enb-meas-enable -t =handover.py"
"""
and in resources.conf (or scenario), added:
"""
enb:
...
cell_list:
- dl_rfemu:
type: gnuradio_zmq
- dl_rfemu:
type: gnuradio_zmq
"""
Note that since the broker is used, there's not need for mod-srsue-ncarriers@2
since the broker is joining the 2 enb cells into 1 stream on the UE side.
Change-Id: I6282cda400558dcb356276786d91e6388524c5b1
2020-10-05 17:23:38 +00:00
|
|
|
if rfemu_cfg['type'] == 'srsenb_stdin' or rfemu_cfg['type'] == 'gnuradio_zmq':
|
2020-10-05 10:40:24 +00:00
|
|
|
# These fields are required so the rfemu class can interact with us:
|
|
|
|
config.overlay(rfemu_cfg, dict(enb=self,
|
|
|
|
cell_id=cell_list[cell]['cell_id']))
|
2020-09-02 20:17:54 +00:00
|
|
|
|
2020-04-20 11:29:31 +00:00
|
|
|
rfemu_obj = rfemu.get_instance_by_type(rfemu_cfg['type'], rfemu_cfg)
|
|
|
|
return rfemu_obj
|
|
|
|
|
2020-09-02 20:17:54 +00:00
|
|
|
def ue_max_rate(self, downlink=True, num_carriers=1):
|
2020-11-07 12:51:54 +00:00
|
|
|
# The max rate for a single UE per PRB configuration in TM1 with MCS 28
|
|
|
|
if 'dl_qam256' in self.ue.features():
|
2020-12-18 09:04:04 +00:00
|
|
|
max_phy_rate_tm1_dl = {6: 4.4e6,
|
|
|
|
15: 14e6,
|
|
|
|
25: 24e6,
|
|
|
|
50: 49e6,
|
|
|
|
75: 75e6,
|
|
|
|
100: 98e6}
|
2020-11-07 12:51:54 +00:00
|
|
|
else:
|
2020-12-18 09:04:04 +00:00
|
|
|
max_phy_rate_tm1_dl = {6: 3.3e6,
|
2020-11-07 12:51:54 +00:00
|
|
|
15: 11e6,
|
|
|
|
25: 18e6,
|
|
|
|
50: 36e6,
|
|
|
|
75: 55e6,
|
|
|
|
100: 75e6}
|
2020-11-16 11:39:43 +00:00
|
|
|
|
2020-12-17 17:01:13 +00:00
|
|
|
if self.enable_ul_qam64 and 'ul_qam64' in self.ue.features():
|
2020-11-16 11:39:43 +00:00
|
|
|
max_phy_rate_tm1_ul = { 6 : 2.7e6,
|
|
|
|
15 : 6.5e6,
|
|
|
|
25 : 14e6,
|
|
|
|
50 : 32e6,
|
|
|
|
75 : 34e6,
|
2020-12-18 09:04:04 +00:00
|
|
|
100 : 71e6 }
|
2020-11-16 11:39:43 +00:00
|
|
|
else:
|
|
|
|
max_phy_rate_tm1_ul = { 6 : 1.7e6,
|
|
|
|
15 : 4.7e6,
|
|
|
|
25 : 10e6,
|
|
|
|
50 : 23e6,
|
|
|
|
75 : 34e6,
|
|
|
|
100 : 51e6 }
|
2020-11-07 12:51:54 +00:00
|
|
|
|
2020-05-27 08:37:46 +00:00
|
|
|
if downlink:
|
|
|
|
max_rate = max_phy_rate_tm1_dl[self.num_prb()]
|
|
|
|
else:
|
|
|
|
max_rate = max_phy_rate_tm1_ul[self.num_prb()]
|
|
|
|
|
|
|
|
# MIMO only supported for Downlink
|
2020-06-02 09:58:03 +00:00
|
|
|
if downlink:
|
|
|
|
if self._txmode > 2:
|
|
|
|
max_rate *= 2
|
|
|
|
|
|
|
|
# For 6 PRBs the max throughput is significantly lower
|
|
|
|
if self._txmode >= 2 and self.num_prb() == 6:
|
|
|
|
max_rate *= 0.85
|
2020-05-27 08:37:46 +00:00
|
|
|
|
2020-09-02 20:17:54 +00:00
|
|
|
# Assume we schedule all carriers
|
|
|
|
max_rate *= num_carriers
|
|
|
|
|
2020-09-08 15:02:44 +00:00
|
|
|
# Reduce expected UL rate due to missing extendedBSR support (see issue #1708)
|
|
|
|
if downlink == False and num_carriers == 4 and self.num_prb() == 100:
|
|
|
|
# all carriers run at 70% approx.
|
|
|
|
max_rate *= 0.7
|
|
|
|
|
2020-05-27 08:37:46 +00:00
|
|
|
return max_rate
|
|
|
|
|
2020-02-11 16:45:26 +00:00
|
|
|
# vim: expandtab tabstop=4 shiftwidth=4
|