Initial srsLTE support
2 tests (iperf3, ping) working against a full srs{UE,ENB,EPC} network using ZeroMQ backend for RF (so no real RF support yet, that will come next). Related: OS##4295, OS#4296 Change-Id: I290c0d79258a9f94f00c7ff2e1c6c5579c0e32f4
This commit is contained in:
parent
ab2ffae89a
commit
c8b0f9359e
|
@ -92,3 +92,11 @@ osmo_bts_oc2g:
|
|||
max_trx: 1
|
||||
trx_list:
|
||||
- nominal_power: 25
|
||||
|
||||
srsepc:
|
||||
mcc: 901
|
||||
mnc: 70
|
||||
|
||||
srsenb:
|
||||
mcc: 901
|
||||
mnc: 70
|
||||
|
|
|
@ -11,6 +11,12 @@ ip_address:
|
|||
- addr: 10.42.42.9
|
||||
- addr: 10.42.42.10
|
||||
|
||||
run_node:
|
||||
- run_type: ssh
|
||||
run_addr: 10.42.42.118
|
||||
ssh_user: jenkins
|
||||
ssh_addr: 10.42.42.116
|
||||
|
||||
bts:
|
||||
- label: sysmoBTS 1002
|
||||
type: osmo-bts-sysmo
|
||||
|
@ -148,6 +154,12 @@ bts:
|
|||
direct_pcu: true
|
||||
ciphers: [a5_0, a5_1, a5_3]
|
||||
|
||||
enb:
|
||||
- label: srsENB-zmq
|
||||
type: srsenb
|
||||
remote_user: jenkins
|
||||
addr: 10.42.42.117
|
||||
|
||||
arfcn:
|
||||
- arfcn: 512
|
||||
band: GSM-1800
|
||||
|
@ -227,5 +239,14 @@ modem:
|
|||
ciphers: [a5_0, a5_1]
|
||||
features: ['sms', 'voice', 'ussd', 'gprs', 'sim']
|
||||
|
||||
- label: srsUE-zmq_1
|
||||
type: srsue
|
||||
remote_user: jenkins
|
||||
addr: 10.42.42.116
|
||||
imsi: '001010123456789'
|
||||
ki: '00112233445566778899aabbccddeeff'
|
||||
auth_algo: 'xor'
|
||||
|
||||
|
||||
osmocon_phone:
|
||||
- serial_device: '/dev/serial/by-id/usb-Silicon_Labs_CP2104_USB_to_UART_Bridge_Controller_00897B41-if00-port0'
|
||||
|
|
|
@ -29,6 +29,7 @@ from . import schema
|
|||
from . import bts_sysmo, bts_osmotrx, bts_osmovirtual, bts_octphy, bts_nanobts, bts_oc2g
|
||||
from . import modem
|
||||
from . import ms_osmo_mobile
|
||||
from . import srs_ue, srs_enb
|
||||
|
||||
from .util import is_dict, is_list
|
||||
|
||||
|
@ -45,7 +46,8 @@ R_BTS = 'bts'
|
|||
R_ARFCN = 'arfcn'
|
||||
R_MODEM = 'modem'
|
||||
R_OSMOCON = 'osmocon_phone'
|
||||
R_ALL = (R_IP_ADDRESS, R_RUN_NODE, R_BTS, R_ARFCN, R_MODEM, R_OSMOCON)
|
||||
R_ENB = 'enb'
|
||||
R_ALL = (R_IP_ADDRESS, R_RUN_NODE, R_BTS, R_ARFCN, R_MODEM, R_OSMOCON, R_ENB)
|
||||
|
||||
RESOURCES_SCHEMA = {
|
||||
'ip_address[].addr': schema.IPV4,
|
||||
|
@ -83,6 +85,11 @@ RESOURCES_SCHEMA = {
|
|||
'bts[].osmo_trx.max_trxd_version': schema.UINT,
|
||||
'bts[].osmo_trx.channels[].rx_path': schema.STR,
|
||||
'bts[].osmo_trx.channels[].tx_path': schema.STR,
|
||||
'enb[].label': schema.STR,
|
||||
'enb[].type': schema.STR,
|
||||
'enb[].remote_user': schema.STR,
|
||||
'enb[].addr': schema.IPV4,
|
||||
'enb[].band': schema.BAND,
|
||||
'arfcn[].arfcn': schema.INT,
|
||||
'arfcn[].band': schema.BAND,
|
||||
'modem[].type': schema.STR,
|
||||
|
@ -91,6 +98,8 @@ RESOURCES_SCHEMA = {
|
|||
'modem[].imsi': schema.IMSI,
|
||||
'modem[].ki': schema.KI,
|
||||
'modem[].auth_algo': schema.AUTH_ALGO,
|
||||
'modem[].remote_user': schema.STR,
|
||||
'modem[].addr': schema.IPV4,
|
||||
'modem[].ciphers[]': schema.CIPHER,
|
||||
'modem[].features[]': schema.MODEM_FEATURE,
|
||||
'osmocon_phone[].serial_device': schema.STR,
|
||||
|
@ -115,12 +124,16 @@ KNOWN_BTS_TYPES = {
|
|||
'nanobts': bts_nanobts.NanoBts,
|
||||
}
|
||||
|
||||
KNOWN_ENB_TYPES = {
|
||||
'srsenb': srs_enb.srsENB,
|
||||
}
|
||||
|
||||
KNOWN_MS_TYPES = {
|
||||
# Map None to ofono for forward compability
|
||||
None: modem.Modem,
|
||||
'ofono': modem.Modem,
|
||||
'osmo-mobile': ms_osmo_mobile.MSOsmoMobile,
|
||||
'srsue': srs_ue.srsUE,
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,197 @@
|
|||
# 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
|
||||
|
||||
from . import log, util, config, template, process, remote
|
||||
|
||||
class srsENB(log.Origin):
|
||||
|
||||
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'
|
||||
|
||||
def __init__(self, suite_run, conf):
|
||||
super().__init__(log.C_RUN, 'srsenb')
|
||||
self._addr = conf.get('addr', None)
|
||||
if self._addr is None:
|
||||
raise log.Error('addr not set')
|
||||
self.set_name('srsenb_%s' % self._addr)
|
||||
self.ue = None
|
||||
self.epc = None
|
||||
self.run_dir = None
|
||||
self.config_file = None
|
||||
self.config_sib_file = None
|
||||
self.config_rr_file = None
|
||||
self.config_drb_file = None
|
||||
self.process = None
|
||||
self.rem_host = None
|
||||
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
|
||||
self.suite_run = suite_run
|
||||
self.nof_prb=100
|
||||
if self.nof_prb == 75:
|
||||
self.base_srate=15.36e6
|
||||
else:
|
||||
self.base_srate=23.04e6
|
||||
self.remote_user = conf.get('remote_user', None)
|
||||
|
||||
def cleanup(self):
|
||||
if self.process is None:
|
||||
return
|
||||
if self.setup_runs_locally():
|
||||
return
|
||||
# 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))
|
||||
|
||||
def setup_runs_locally(self):
|
||||
return self.remote_user is None
|
||||
|
||||
def start(self, epc):
|
||||
self.log('Starting srsENB')
|
||||
self.epc = epc
|
||||
self.run_dir = util.Dir(self.suite_run.get_test_run_dir().new_dir(self.name()))
|
||||
self.configure()
|
||||
if self.remote_user:
|
||||
self.start_remotely()
|
||||
else:
|
||||
self.start_locally()
|
||||
|
||||
def start_remotely(self):
|
||||
self.inst = util.Dir(os.path.abspath(self.suite_run.trial.get_inst('srslte')))
|
||||
lib = self.inst.child('lib')
|
||||
if not os.path.isdir(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.rem_host = remote.RemoteHost(self.run_dir, self.remote_user, self._addr)
|
||||
remote_prefix_dir = util.Dir(srsENB.REMOTE_DIR)
|
||||
self.remote_inst = util.Dir(remote_prefix_dir.child(os.path.basename(str(self.inst))))
|
||||
remote_run_dir = util.Dir(remote_prefix_dir.child(srsENB.BINFILE))
|
||||
|
||||
self.remote_config_file = remote_run_dir.child(srsENB.CFGFILE)
|
||||
self.remote_config_sib_file = remote_run_dir.child(srsENB.CFGFILE_SIB)
|
||||
self.remote_config_rr_file = remote_run_dir.child(srsENB.CFGFILE_RR)
|
||||
self.remote_config_drb_file = remote_run_dir.child(srsENB.CFGFILE_DRB)
|
||||
self.remote_log_file = remote_run_dir.child(srsENB.LOGFILE)
|
||||
|
||||
self.rem_host.recreate_remote_dir(self.remote_inst)
|
||||
self.rem_host.scp('scp-inst-to-remote', str(self.inst), remote_prefix_dir)
|
||||
self.rem_host.create_remote_dir(remote_run_dir)
|
||||
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)
|
||||
|
||||
remote_env = { 'LD_LIBRARY_PATH': self.remote_inst.child('lib') }
|
||||
remote_binary = self.remote_inst.child('bin', srsENB.BINFILE)
|
||||
args = (remote_binary, self.remote_config_file,
|
||||
'--enb_files.sib_config=' + self.remote_config_sib_file,
|
||||
'--enb_files.rr_config=' + self.remote_config_rr_file,
|
||||
'--enb_files.drb_config=' + self.remote_config_drb_file,
|
||||
'--rf.device_name=zmq',
|
||||
'--rf.device_args="fail_on_disconnect=true,tx_port=tcp://'+ self.addr() +':2000,rx_port=tcp://'+ self.ue.addr() +':2001,id=enb,base_srate='+ str(self.base_srate) + '"',
|
||||
'--expert.nof_phy_threads=1',
|
||||
'--expert.rrc_inactivity_timer=1500',
|
||||
'--enb.n_prb=' + str(self.nof_prb),
|
||||
'--log.filename=' + self.remote_log_file)
|
||||
|
||||
self.process = self.rem_host.RemoteProcessFixIgnoreSIGHUP(srsENB.BINFILE, util.Dir(srsENB.REMOTE_DIR), args, remote_env=remote_env)
|
||||
self.suite_run.remember_to_stop(self.process)
|
||||
self.process.launch()
|
||||
|
||||
def start_locally(self):
|
||||
inst = util.Dir(os.path.abspath(self.suite_run.trial.get_inst('srslte')))
|
||||
|
||||
binary = inst.child('bin', BINFILE)
|
||||
if not os.path.isfile(binary):
|
||||
raise log.Error('Binary missing:', binary)
|
||||
lib = inst.child('lib')
|
||||
if not os.path.isdir(lib):
|
||||
raise log.Error('No lib/ in', inst)
|
||||
|
||||
env = { 'LD_LIBRARY_PATH': util.prepend_library_path(lib) }
|
||||
|
||||
self.dbg(run_dir=self.run_dir, binary=binary, env=env)
|
||||
args = (binary, os.path.abspath(self.config_file),
|
||||
'--enb_files.sib_config=' + os.path.abspath(self.config_sib_file),
|
||||
'--enb_files.rr_config=' + os.path.abspath(self.config_rr_file),
|
||||
'--enb_files.drb_config=' + os.path.abspath(self.config_drb_file),
|
||||
'--rf.device_name=zmq',
|
||||
'--rf.device_args="fail_on_disconnect=true,tx_port=tcp://'+ self.addr() +':2000,rx_port=tcp://'+ self.ue.addr() +':2001,id=enb,base_srate='+ str(self.base_srate) + '"',
|
||||
'--expert.nof_phy_threads=1',
|
||||
'--expert.rrc_inactivity_timer=1500',
|
||||
'--enb.n_prb=' + str(self.nof_prb),
|
||||
'--log.filename=' + self.log_file)
|
||||
|
||||
self.process = process.Process(self.name(), self.run_dir, args, env=env)
|
||||
self.suite_run.remember_to_stop(self.process)
|
||||
self.process.launch()
|
||||
|
||||
def gen_conf_file(self, path, filename):
|
||||
self.dbg(config_file=path)
|
||||
|
||||
values = dict(enb=config.get_defaults('srsenb'))
|
||||
config.overlay(values, self.suite_run.config())
|
||||
config.overlay(values, dict(enb={ 'run_addr': self.addr(),
|
||||
'mme_addr': self.epc.addr()}))
|
||||
|
||||
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)
|
||||
|
||||
def configure(self):
|
||||
self.config_file = self.run_dir.new_file(srsENB.CFGFILE)
|
||||
self.config_sib_file = self.run_dir.new_file(srsENB.CFGFILE_SIB)
|
||||
self.config_rr_file = self.run_dir.new_file(srsENB.CFGFILE_RR)
|
||||
self.config_drb_file = self.run_dir.new_file(srsENB.CFGFILE_DRB)
|
||||
self.log_file = self.run_dir.new_file(srsENB.LOGFILE)
|
||||
|
||||
self.gen_conf_file(self.config_file, srsENB.CFGFILE)
|
||||
self.gen_conf_file(self.config_sib_file, srsENB.CFGFILE_SIB)
|
||||
self.gen_conf_file(self.config_rr_file, srsENB.CFGFILE_RR)
|
||||
self.gen_conf_file(self.config_drb_file, srsENB.CFGFILE_DRB)
|
||||
|
||||
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()
|
||||
|
||||
def addr(self):
|
||||
return self._addr
|
||||
|
||||
# vim: expandtab tabstop=4 shiftwidth=4
|
|
@ -0,0 +1,207 @@
|
|||
# osmo_gsm_tester: specifics for running an SRS EPC 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
|
||||
|
||||
from . import log, util, config, template, process, remote
|
||||
|
||||
class srsEPC(log.Origin):
|
||||
|
||||
REMOTE_DIR = '/osmo-gsm-tester-srsepc'
|
||||
BINFILE = 'srsepc'
|
||||
CFGFILE = 'srsepc.conf'
|
||||
DBFILE = 'srsepc_user_db.csv'
|
||||
PCAPFILE = 'srsepc.pcap'
|
||||
LOGFILE = 'srsepc.log'
|
||||
|
||||
def __init__(self, suite_run, run_node):
|
||||
super().__init__(log.C_RUN, 'srsepc')
|
||||
self._addr = run_node.run_addr()
|
||||
self.set_name('srsepc_%s' % self._addr)
|
||||
self.run_dir = None
|
||||
self.config_file = None
|
||||
self.db_file = None
|
||||
self.log_file = None
|
||||
self.pcap_file = None
|
||||
self.process = None
|
||||
self.rem_host = None
|
||||
self.remote_config_file = None
|
||||
self.remote_db_file = None
|
||||
self.remote_log_file = None
|
||||
self.remote_pcap_file = None
|
||||
self.subscriber_list = []
|
||||
self.suite_run = suite_run
|
||||
self._run_node = run_node
|
||||
|
||||
def cleanup(self):
|
||||
if self.process is None:
|
||||
return
|
||||
if self._run_node.is_local():
|
||||
return
|
||||
# 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))
|
||||
try:
|
||||
self.rem_host.scpfrom('scp-back-pcap', self.remote_pcap_file, self.pcap_file)
|
||||
except Exception as e:
|
||||
self.log(repr(e))
|
||||
|
||||
def start(self):
|
||||
self.log('Starting srsepc')
|
||||
self.run_dir = util.Dir(self.suite_run.get_test_run_dir().new_dir(self.name()))
|
||||
self.configure()
|
||||
if self._run_node.is_local():
|
||||
self.start_locally()
|
||||
else:
|
||||
self.start_remotely()
|
||||
|
||||
def start_remotely(self):
|
||||
self.inst = util.Dir(os.path.abspath(self.suite_run.trial.get_inst('srslte')))
|
||||
lib = self.inst.child('lib')
|
||||
if not os.path.isdir(lib):
|
||||
raise log.Error('No lib/ in', self.inst)
|
||||
if not self.inst.isfile('bin', srsEPC.BINFILE):
|
||||
raise log.Error('No %s binary in' % srsEPC.BINFILE, self.inst)
|
||||
|
||||
self.rem_host = remote.RemoteHost(self.run_dir, self._run_node.ssh_user(), self._run_node.ssh_addr())
|
||||
remote_prefix_dir = util.Dir(srsEPC.REMOTE_DIR)
|
||||
remote_inst = util.Dir(remote_prefix_dir.child(os.path.basename(str(self.inst))))
|
||||
remote_run_dir = util.Dir(remote_prefix_dir.child(srsEPC.BINFILE))
|
||||
self.remote_config_file = remote_run_dir.child(srsEPC.CFGFILE)
|
||||
self.remote_db_file = remote_run_dir.child(srsEPC.DBFILE)
|
||||
self.remote_log_file = remote_run_dir.child(srsEPC.LOGFILE)
|
||||
self.remote_pcap_file = remote_run_dir.child(srsEPC.PCAPFILE)
|
||||
|
||||
self.rem_host.recreate_remote_dir(remote_inst)
|
||||
self.rem_host.scp('scp-inst-to-remote', str(self.inst), remote_prefix_dir)
|
||||
self.rem_host.create_remote_dir(remote_run_dir)
|
||||
self.rem_host.scp('scp-cfg-to-remote', self.config_file, self.remote_config_file)
|
||||
self.rem_host.scp('scp-db-to-remote', self.db_file, self.remote_db_file)
|
||||
|
||||
remote_lib = remote_inst.child('lib')
|
||||
remote_binary = remote_inst.child('bin', srsEPC.BINFILE)
|
||||
# setting capabilities will later disable use of LD_LIBRARY_PATH from ELF loader -> modify RPATH instead.
|
||||
self.log('Setting RPATH for srsepc')
|
||||
self.rem_host.change_elf_rpath(remote_binary, remote_lib)
|
||||
# srsepc requires CAP_NET_ADMIN to create tunnel devices: ioctl(TUNSETIFF):
|
||||
self.log('Applying CAP_NET_ADMIN capability to srsepc')
|
||||
self.rem_host.setcap_net_admin(remote_binary)
|
||||
|
||||
args = (remote_binary, self.remote_config_file,
|
||||
'--hss.db_file=' + self.remote_db_file,
|
||||
'--log.filename=' + self.remote_log_file,
|
||||
'--pcap.enable=true',
|
||||
'--pcap.filename=' + self.remote_pcap_file)
|
||||
|
||||
self.process = self.rem_host.RemoteProcess(srsEPC.BINFILE, args)
|
||||
#self.process = self.rem_host.RemoteProcessFixIgnoreSIGHUP(srsEPC.BINFILE, remote_run_dir, args)
|
||||
self.suite_run.remember_to_stop(self.process)
|
||||
self.process.launch()
|
||||
|
||||
def start_locally(self):
|
||||
inst = util.Dir(os.path.abspath(self.suite_run.trial.get_inst('srslte')))
|
||||
|
||||
binary = inst.child('bin', BINFILE)
|
||||
if not os.path.isfile(binary):
|
||||
raise log.Error('Binary missing:', binary)
|
||||
lib = inst.child('lib')
|
||||
if not os.path.isdir(lib):
|
||||
raise log.Error('No lib/ in', inst)
|
||||
|
||||
env = {}
|
||||
# setting capabilities will later disable use of LD_LIBRARY_PATH from ELF loader -> modify RPATH instead.
|
||||
self.log('Setting RPATH for srsepc')
|
||||
# srsepc binary needs patchelf <= 0.9 (0.10 and current master fail) to avoid failing during patch. OS#4389, patchelf-GH#192.
|
||||
util.change_elf_rpath(binary, util.prepend_library_path(lib), self.run_dir.new_dir('patchelf'))
|
||||
# srsepc requires CAP_NET_ADMIN to create tunnel devices: ioctl(TUNSETIFF):
|
||||
self.log('Applying CAP_NET_ADMIN capability to srsepc')
|
||||
util.setcap_net_admin(binary, self.run_dir.new_dir('setcap_net_admin'))
|
||||
|
||||
self.dbg(run_dir=self.run_dir, binary=binary, env=env)
|
||||
args = (binary, os.path.abspath(self.config_file),
|
||||
'--hss.db_file=' + self.db_file,
|
||||
'--log.filename=' + self.log_file,
|
||||
'--pcap.enable=true',
|
||||
'--pcap.filename=' + self.pcap_file)
|
||||
|
||||
self.process = process.Process(self.name(), self.run_dir, args, env=env)
|
||||
self.suite_run.remember_to_stop(self.process)
|
||||
self.process.launch()
|
||||
|
||||
def configure(self):
|
||||
self.config_file = self.run_dir.new_file(srsEPC.CFGFILE)
|
||||
self.db_file = self.run_dir.new_file(srsEPC.DBFILE)
|
||||
self.log_file = self.run_dir.new_file(srsEPC.LOGFILE)
|
||||
self.pcap_file = self.run_dir.new_file(srsEPC.PCAPFILE)
|
||||
self.dbg(config_file=self.config_file, db_file=self.db_file)
|
||||
|
||||
values = dict(epc=config.get_defaults('srsepc'))
|
||||
config.overlay(values, dict(epc=dict(hss=dict(subscribers=self.subscriber_list))))
|
||||
config.overlay(values, self.suite_run.config())
|
||||
config.overlay(values, dict(epc={'run_addr': self.addr()}))
|
||||
|
||||
self.dbg('SRSEPC CONFIG:\n' + pprint.pformat(values))
|
||||
|
||||
with open(self.config_file, 'w') as f:
|
||||
r = template.render(srsEPC.CFGFILE, values)
|
||||
self.dbg(r)
|
||||
f.write(r)
|
||||
with open(self.db_file, 'w') as f:
|
||||
r = template.render(srsEPC.DBFILE, values)
|
||||
self.dbg(r)
|
||||
f.write(r)
|
||||
|
||||
def subscriber_add(self, modem, msisdn=None, algo_str=None):
|
||||
if msisdn is None:
|
||||
msisdn = self.suite_run.resources_pool.next_msisdn(modem)
|
||||
modem.set_msisdn(msisdn)
|
||||
|
||||
if algo_str is None:
|
||||
algo_str = modem.auth_algo() or util.OSMO_AUTH_ALGO_NONE
|
||||
|
||||
if algo_str != util.OSMO_AUTH_ALGO_NONE and not modem.ki():
|
||||
raise log.Error("Auth algo %r selected but no KI specified" % algo_str)
|
||||
|
||||
subscriber_id = len(self.subscriber_list) # list index
|
||||
self.subscriber_list.append({'id': subscriber_id, 'imsi': modem.imsi(), 'msisdn': msisdn, 'auth_algo': algo_str, 'ki': modem.ki(), 'opc': None})
|
||||
|
||||
self.log('Add subscriber', msisdn=msisdn, imsi=modem.imsi(), subscriber_id=subscriber_id,
|
||||
algo_str=algo_str)
|
||||
return subscriber_id
|
||||
|
||||
def enb_is_connected(self, enb):
|
||||
# FIXME: srspec's stdout: "S1 Setup Request - eNB Id 0x66c0", but srsenb.conf has "enb_id = 0x19B"
|
||||
return 'S1 Setup Request - eNB Id' in (self.process.get_stdout() or '')
|
||||
|
||||
def running(self):
|
||||
return not self.process.terminated()
|
||||
|
||||
def addr(self):
|
||||
return self._addr
|
||||
|
||||
def tun_addr(self):
|
||||
return '172.16.0.1'
|
||||
|
||||
def run_node(self):
|
||||
return self._run_node
|
||||
|
||||
# vim: expandtab tabstop=4 shiftwidth=4
|
|
@ -0,0 +1,213 @@
|
|||
# osmo_gsm_tester: specifics for running an SRS UE 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
|
||||
|
||||
from . import log, util, config, template, process, remote
|
||||
from .run_node import RunNode
|
||||
from .ms import MS
|
||||
|
||||
class srsUE(MS):
|
||||
|
||||
REMOTE_DIR = '/osmo-gsm-tester-srsue'
|
||||
BINFILE = 'srsue'
|
||||
CFGFILE = 'srsue.conf'
|
||||
PCAPFILE = 'srsue.pcap'
|
||||
LOGFILE = 'srsue.log'
|
||||
|
||||
def __init__(self, suite_run, conf):
|
||||
self._addr = conf.get('addr', None)
|
||||
if self._addr is None:
|
||||
raise log.Error('addr not set')
|
||||
super().__init__('srsue_%s' % self._addr, conf)
|
||||
self.enb = None
|
||||
self.run_dir = None
|
||||
self.config_file = None
|
||||
self.log_file = None
|
||||
self.pcap_file = None
|
||||
self.process = None
|
||||
self.rem_host = None
|
||||
self.remote_config_file = None
|
||||
self.remote_log_file = None
|
||||
self.remote_pcap_file = None
|
||||
self.suite_run = suite_run
|
||||
self.nof_prb=50
|
||||
if self.nof_prb == 75:
|
||||
self.base_srate=15.36e6
|
||||
else:
|
||||
self.base_srate=23.04e6
|
||||
self.remote_user = conf.get('remote_user', None)
|
||||
|
||||
def cleanup(self):
|
||||
if self.process is None:
|
||||
return
|
||||
if self.setup_runs_locally():
|
||||
return
|
||||
# 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))
|
||||
try:
|
||||
self.rem_host.scpfrom('scp-back-pcap', self.remote_pcap_file, self.pcap_file)
|
||||
except Exception as e:
|
||||
self.log(repr(e))
|
||||
|
||||
def setup_runs_locally(self):
|
||||
return self.remote_user is None
|
||||
|
||||
def netns(self):
|
||||
return "srsue1"
|
||||
|
||||
def connect(self, enb):
|
||||
self.log('Starting srsue')
|
||||
self.enb = enb
|
||||
self.run_dir = util.Dir(self.suite_run.get_test_run_dir().new_dir(self.name()))
|
||||
self.configure()
|
||||
if self.setup_runs_locally():
|
||||
self.start_locally()
|
||||
else:
|
||||
self.start_remotely()
|
||||
|
||||
def start_remotely(self):
|
||||
self.inst = util.Dir(os.path.abspath(self.suite_run.trial.get_inst('srslte')))
|
||||
lib = self.inst.child('lib')
|
||||
if not os.path.isdir(lib):
|
||||
raise log.Error('No lib/ in', self.inst)
|
||||
if not self.inst.isfile('bin', srsUE.BINFILE):
|
||||
raise log.Error('No %s binary in' % srsUE.BINFILE, self.inst)
|
||||
|
||||
self.rem_host = remote.RemoteHost(self.run_dir, self.remote_user, self._addr)
|
||||
remote_prefix_dir = util.Dir(srsUE.REMOTE_DIR)
|
||||
remote_inst = util.Dir(remote_prefix_dir.child(os.path.basename(str(self.inst))))
|
||||
remote_run_dir = util.Dir(remote_prefix_dir.child(srsUE.BINFILE))
|
||||
self.remote_config_file = remote_run_dir.child(srsUE.CFGFILE)
|
||||
self.remote_log_file = remote_run_dir.child(srsUE.LOGFILE)
|
||||
self.remote_pcap_file = remote_run_dir.child(srsUE.PCAPFILE)
|
||||
|
||||
self.rem_host.recreate_remote_dir(remote_inst)
|
||||
self.rem_host.scp('scp-inst-to-remote', str(self.inst), remote_prefix_dir)
|
||||
self.rem_host.create_remote_dir(remote_run_dir)
|
||||
self.rem_host.scp('scp-cfg-to-remote', self.config_file, self.remote_config_file)
|
||||
|
||||
remote_lib = remote_inst.child('lib')
|
||||
remote_binary = remote_inst.child('bin', srsUE.BINFILE)
|
||||
# setting capabilities will later disable use of LD_LIBRARY_PATH from ELF loader -> modify RPATH instead.
|
||||
self.log('Setting RPATH for srsue')
|
||||
# srsue binary needs patchelf >= 0.9+52 to avoid failing during patch. OS#4389, patchelf-GH#192.
|
||||
self.rem_host.set_remote_env({'PATCHELF_BIN': '/opt/bin/patchelf-v0.10' })
|
||||
self.rem_host.change_elf_rpath(remote_binary, remote_lib)
|
||||
|
||||
# srsue requires CAP_SYS_ADMIN to cjump to net network namespace: netns(CLONE_NEWNET):
|
||||
# srsue requires CAP_NET_ADMIN to create tunnel devices: ioctl(TUNSETIFF):
|
||||
self.log('Applying CAP_SYS_ADMIN+CAP_NET_ADMIN capability to srsue')
|
||||
self.rem_host.setcap_netsys_admin(remote_binary)
|
||||
|
||||
#'strace', '-ff',
|
||||
args = (remote_binary, self.remote_config_file,
|
||||
'--rf.device_name=zmq',
|
||||
'--rf.device_args="tx_port=tcp://'+ self.addr() +':2001,rx_port=tcp://'+ self.enb.addr() +':2000,id=ue,base_srate='+ str(self.base_srate) + '"',
|
||||
'--phy.nof_phy_threads=1',
|
||||
'--gw.netns=' + self.netns(),
|
||||
'--log.filename=' + 'stdout', #self.remote_log_file,
|
||||
'--pcap.enable=true',
|
||||
'--pcap.filename=' + self.remote_pcap_file)
|
||||
|
||||
self.process = self.rem_host.RemoteProcessFixIgnoreSIGHUP(srsUE.BINFILE, util.Dir(srsUE.REMOTE_DIR), args)
|
||||
#self.process = self.rem_host.RemoteProcessFixIgnoreSIGHUP(srsUE.BINFILE, remote_run_dir, args, remote_lib)
|
||||
self.suite_run.remember_to_stop(self.process)
|
||||
self.process.launch()
|
||||
|
||||
def start_locally(self):
|
||||
inst = util.Dir(os.path.abspath(self.suite_run.trial.get_inst('srslte')))
|
||||
|
||||
binary = inst.child('bin', BINFILE)
|
||||
if not os.path.isfile(binary):
|
||||
raise log.Error('Binary missing:', binary)
|
||||
lib = inst.child('lib')
|
||||
if not os.path.isdir(lib):
|
||||
raise log.Error('No lib/ in', inst)
|
||||
|
||||
env = {}
|
||||
|
||||
# setting capabilities will later disable use of LD_LIBRARY_PATH from ELF loader -> modify RPATH instead.
|
||||
self.log('Setting RPATH for srsue')
|
||||
util.change_elf_rpath(binary, util.prepend_library_path(lib), self.run_dir.new_dir('patchelf'))
|
||||
|
||||
# srsue requires CAP_SYS_ADMIN to cjump to net network namespace: netns(CLONE_NEWNET):
|
||||
# srsue requires CAP_NET_ADMIN to create tunnel devices: ioctl(TUNSETIFF):
|
||||
self.log('Applying CAP_SYS_ADMIN+CAP_NET_ADMIN capability to srsue')
|
||||
util.setcap_netsys_admin(binary, self.run_dir.new_dir('setcap_netsys_admin'))
|
||||
|
||||
args = (binary, os.path.abspath(self.config_file),
|
||||
'--rf.device_name=zmq',
|
||||
'--rf.device_args="tx_port=tcp://'+ self.addr() +':2001,rx_port=tcp://'+ self.enb.addr() +':2000,id=ue,base_srate='+ str(self.base_srate) + '"',
|
||||
'--phy.nof_phy_threads=1',
|
||||
'--gw.netns=' + self.netns(),
|
||||
'--log.filename=' + self.log_file,
|
||||
'--pcap.enable=true',
|
||||
'--pcap.filename=' + self.pcap_file)
|
||||
|
||||
self.dbg(run_dir=self.run_dir, binary=binary, env=env)
|
||||
self.process = process.Process(self.name(), self.run_dir, args, env=env)
|
||||
self.suite_run.remember_to_stop(self.process)
|
||||
self.process.launch()
|
||||
|
||||
def configure(self):
|
||||
self.config_file = self.run_dir.new_file(srsUE.CFGFILE)
|
||||
self.log_file = self.run_dir.child(srsUE.LOGFILE)
|
||||
self.pcap_file = self.run_dir.new_file(srsUE.PCAPFILE)
|
||||
self.dbg(config_file=self.config_file)
|
||||
|
||||
values = dict(ue=config.get_defaults('srsue'))
|
||||
config.overlay(values, self.suite_run.config())
|
||||
config.overlay(values, dict(ue=self._conf))
|
||||
|
||||
self.dbg('SRSUE CONFIG:\n' + pprint.pformat(values))
|
||||
|
||||
with open(self.config_file, 'w') as f:
|
||||
r = template.render(srsUE.CFGFILE, values)
|
||||
self.dbg(r)
|
||||
f.write(r)
|
||||
|
||||
def is_connected(self, mcc_mnc=None):
|
||||
return 'Network attach successful.' in (self.process.get_stdout() or '')
|
||||
|
||||
def is_attached(self):
|
||||
return self.is_connected()
|
||||
|
||||
def running(self):
|
||||
return not self.process.terminated()
|
||||
|
||||
def addr(self):
|
||||
return self._addr
|
||||
|
||||
def run_node(self):
|
||||
# TODO: move to an object
|
||||
return RunNode(RunNode.T_REM_SSH, self._addr, self.remote_user, self._addr)
|
||||
|
||||
def run_netns_wait(self, name, popen_args):
|
||||
if self.setup_runs_locally():
|
||||
proc = process.NetNSProcess(name, self.run_dir.new_dir(name), self.netns(), popen_args, env={})
|
||||
else:
|
||||
proc = self.rem_host.RemoteNetNSProcess(name, self.netns(), popen_args, env={})
|
||||
proc.launch_sync()
|
||||
|
||||
# vim: expandtab tabstop=4 shiftwidth=4
|
|
@ -25,6 +25,7 @@ from . import config, log, util, resource, test
|
|||
from .event_loop import MainLoop
|
||||
from . import osmo_nitb, osmo_hlr, osmo_mgcpgw, osmo_mgw, osmo_msc, osmo_bsc, osmo_stp, osmo_ggsn, osmo_sgsn, esme, osmocon, ms_driver, iperf3, process
|
||||
from . import run_node
|
||||
from . import srs_epc
|
||||
|
||||
class Timeout(Exception):
|
||||
pass
|
||||
|
@ -362,6 +363,18 @@ class SuiteRun(log.Origin):
|
|||
def run_node(self, specifics=None):
|
||||
return run_node.RunNode.from_conf(self.reserved_resources.get(resource.R_RUN_NODE, specifics=specifics))
|
||||
|
||||
def enb(self, specifics=None):
|
||||
enb = enb_obj(self, self.reserved_resources.get(resource.R_ENB, specifics=specifics))
|
||||
self.register_for_cleanup(enb)
|
||||
return enb
|
||||
|
||||
def epc(self, run_node=None):
|
||||
if run_node is None:
|
||||
run_node = self.run_node()
|
||||
epc_obj = srs_epc.srsEPC(self, run_node)
|
||||
self.register_for_cleanup(epc_obj)
|
||||
return epc_obj
|
||||
|
||||
def osmocon(self, specifics=None):
|
||||
conf = self.reserved_resources.get(resource.R_OSMOCON, specifics=specifics)
|
||||
osmocon_obj = osmocon.Osmocon(self, conf=conf)
|
||||
|
@ -481,4 +494,12 @@ def bts_obj(suite_run, conf):
|
|||
raise RuntimeError('No such BTS type is defined: %r' % bts_type)
|
||||
return bts_class(suite_run, conf)
|
||||
|
||||
def enb_obj(suite_run, conf):
|
||||
enb_type = conf.get('type')
|
||||
log.dbg('create ENB object', type=enb_type)
|
||||
enb_class = resource.KNOWN_ENB_TYPES.get(enb_type)
|
||||
if enb_class is None:
|
||||
raise RuntimeError('No such ENB type is defined: %r' % enb_type)
|
||||
return enb_class(suite_run, conf)
|
||||
|
||||
# vim: expandtab tabstop=4 shiftwidth=4
|
||||
|
|
|
@ -0,0 +1,279 @@
|
|||
#####################################################################
|
||||
# srsENB configuration file
|
||||
#####################################################################
|
||||
|
||||
#####################################################################
|
||||
# eNB configuration
|
||||
#
|
||||
# enb_id: 20-bit eNB identifier.
|
||||
# cell_id: 8-bit cell identifier.
|
||||
# tac: 16-bit Tracking Area Code.
|
||||
# mcc: Mobile Country Code
|
||||
# mnc: Mobile Network Code
|
||||
# mme_addr: IP address of MME for S1 connnection
|
||||
# gtp_bind_addr: Local IP address to bind for GTP connection
|
||||
# s1c_bind_addr: Local IP address to bind for S1AP connection
|
||||
# n_prb: Number of Physical Resource Blocks (6,15,25,50,75,100)
|
||||
# tm: Transmission mode 1-4 (TM1 default)
|
||||
# nof_ports: Number of Tx ports (1 port default, set to 2 for TM2/3/4)
|
||||
#
|
||||
#####################################################################
|
||||
[enb]
|
||||
enb_id = 0x19B
|
||||
cell_id = 0x01
|
||||
phy_cell_id = 1
|
||||
tac = 0x0007
|
||||
mcc = ${enb.mcc}
|
||||
mnc = ${enb.mnc}
|
||||
mme_addr = ${enb.mme_addr}
|
||||
gtp_bind_addr = ${enb.run_addr}
|
||||
s1c_bind_addr = ${enb.run_addr}
|
||||
n_prb = 50
|
||||
#tm = 4
|
||||
#nof_ports = 2
|
||||
|
||||
#####################################################################
|
||||
# eNB configuration files
|
||||
#
|
||||
# sib_config: SIB1, SIB2 and SIB3 configuration file
|
||||
# note: when enabling mbms, use the sib.conf.mbsfn configuration file which includes SIB13
|
||||
# rr_config: Radio Resources configuration file
|
||||
# drb_config: DRB configuration file
|
||||
#####################################################################
|
||||
[enb_files]
|
||||
sib_config = sib.conf
|
||||
rr_config = rr.conf
|
||||
drb_config = drb.conf
|
||||
|
||||
#####################################################################
|
||||
# RF configuration
|
||||
#
|
||||
# dl_earfcn: EARFCN code for DL
|
||||
# tx_gain: Transmit gain (dB).
|
||||
# rx_gain: Optional receive gain (dB). If disabled, AGC if enabled
|
||||
#
|
||||
# Optional parameters:
|
||||
# dl_freq: Override DL frequency corresponding to dl_earfcn
|
||||
# ul_freq: Override UL frequency corresponding to dl_earfcn (must be set if dl_freq is set)
|
||||
# device_name: Device driver family. Supported options: "auto" (uses first found), "UHD" or "bladeRF"
|
||||
# device_args: Arguments for the device driver. Options are "auto" or any string.
|
||||
# Default for UHD: "recv_frame_size=9232,send_frame_size=9232"
|
||||
# Default for bladeRF: ""
|
||||
# #time_adv_nsamples: Transmission time advance (in number of samples) to compensate for RF delay
|
||||
# from antenna to timestamp insertion.
|
||||
# Default "auto". B210 USRP: 100 samples, bladeRF: 27.
|
||||
# burst_preamble_us: Preamble length to transmit before start of burst.
|
||||
# Default "auto". B210 USRP: 400 us, bladeRF: 0 us.
|
||||
#####################################################################
|
||||
[rf]
|
||||
dl_earfcn = 3400
|
||||
tx_gain = 80
|
||||
rx_gain = 40
|
||||
|
||||
#device_name = auto
|
||||
|
||||
# For best performance in 2x2 MIMO and >= 15 MHz use the following device_args settings:
|
||||
# USRP B210: num_recv_frames=64,num_send_frames=64
|
||||
|
||||
# For best performance when BW<5 MHz (25 PRB), use the following device_args settings:
|
||||
# USRP B210: send_frame_size=512,recv_frame_size=512
|
||||
|
||||
#device_args = auto
|
||||
#time_adv_nsamples = auto
|
||||
#burst_preamble_us = auto
|
||||
|
||||
|
||||
#####################################################################
|
||||
# MAC-layer packet capture configuration
|
||||
#
|
||||
# Packets are captured to file in the compact format decoded by
|
||||
# the Wireshark mac-lte-framed dissector and with DLT 147.
|
||||
# To use the dissector, edit the preferences for DLT_USER to
|
||||
# add an entry with DLT=147, Payload Protocol=mac-lte-framed.
|
||||
# For more information see: https://wiki.wireshark.org/MAC-LTE
|
||||
#
|
||||
# Please note that this setting will by default only capture MAC
|
||||
# frames on dedicated channels, and not SIB. You have to build with
|
||||
# WRITE_SIB_PCAP enabled in enb/src/stack/mac/mac.cc if you want
|
||||
# SIB to be part of the MAC pcap file.
|
||||
#
|
||||
# enable: Enable MAC layer packet captures (true/false)
|
||||
# filename: File path to use for packet captures
|
||||
#####################################################################
|
||||
[pcap]
|
||||
enable = false
|
||||
filename = /tmp/enb.pcap
|
||||
|
||||
#####################################################################
|
||||
# Log configuration
|
||||
#
|
||||
# Log levels can be set for individual layers. "all_level" sets log
|
||||
# level for all layers unless otherwise configured.
|
||||
# Format: e.g. phy_level = info
|
||||
#
|
||||
# In the same way, packet hex dumps can be limited for each level.
|
||||
# "all_hex_limit" sets the hex limit for all layers unless otherwise
|
||||
# configured.
|
||||
# Format: e.g. phy_hex_limit = 32
|
||||
#
|
||||
# Logging layers: rf, phy, phy_lib, mac, rlc, pdcp, rrc, gtpu, s1ap, all
|
||||
# Logging levels: debug, info, warning, error, none
|
||||
#
|
||||
# filename: File path to use for log output. Can be set to stdout
|
||||
# to print logs to standard output
|
||||
# file_max_size: Maximum file size (in kilobytes). When passed, multiple files are created.
|
||||
# If set to negative, a single log file will be created.
|
||||
#####################################################################
|
||||
[log]
|
||||
all_level = warning
|
||||
all_hex_limit = 32
|
||||
filename = /tmp/enb.log
|
||||
file_max_size = -1
|
||||
|
||||
[gui]
|
||||
enable = false
|
||||
|
||||
#####################################################################
|
||||
# Scheduler configuration options
|
||||
#
|
||||
# max_aggr_level: Optional maximum aggregation level index (l=log2(L) can be 0, 1, 2 or 3)
|
||||
# pdsch_mcs: Optional fixed PDSCH MCS (ignores reported CQIs if specified)
|
||||
# pdsch_max_mcs: Optional PDSCH MCS limit
|
||||
# pusch_mcs: Optional fixed PUSCH MCS (ignores reported CQIs if specified)
|
||||
# pusch_max_mcs: Optional PUSCH MCS limit
|
||||
# #nof_ctrl_symbols: Number of control symbols
|
||||
#
|
||||
#####################################################################
|
||||
[scheduler]
|
||||
#max_aggr_level = -1
|
||||
#pdsch_mcs = -1
|
||||
#pdsch_max_mcs = -1
|
||||
#pusch_mcs = -1
|
||||
pusch_max_mcs = 16
|
||||
nof_ctrl_symbols = 3
|
||||
|
||||
#####################################################################
|
||||
# eMBMS configuration options
|
||||
#
|
||||
# enable: Enable MBMS transmission in the eNB
|
||||
# m1u_multiaddr: Multicast addres the M1-U socket will register to
|
||||
# m1u_if_addr: Address of the inteferface the M1-U interface will listen for multicast packets.
|
||||
#
|
||||
#####################################################################
|
||||
[embms]
|
||||
#enable = false
|
||||
#m1u_multiaddr = 239.255.0.1
|
||||
#m1u_if_addr = 127.0.1.201
|
||||
|
||||
|
||||
|
||||
#####################################################################
|
||||
# Channel emulator options:
|
||||
# enable: Enable/Disable internal Downlink/Uplink channel emulator
|
||||
#
|
||||
# -- Fading emulator
|
||||
# fading.enable: Enable/disable fading simulator
|
||||
# fading.model: Fading model + maximum doppler (E.g. none, epa5, eva70, etu300, etc)
|
||||
#
|
||||
# -- Delay Emulator delay(t) = delay_min + (delay_max - delay_min) * (1 + sin(2pi*t/period)) / 2
|
||||
# Maximum speed [m/s]: (delay_max - delay_min) * pi * 300 / period
|
||||
# delay.enable: Enable/disable delay simulator
|
||||
# delay.period_s: Delay period in seconds.
|
||||
# delay.init_time_s: Delay initial time in seconds.
|
||||
# delay.maximum_us: Maximum delay in microseconds
|
||||
# delay.minumum_us: Minimum delay in microseconds
|
||||
#
|
||||
# -- Radio-Link Failure (RLF) Emulator
|
||||
# rlf.enable: Enable/disable RLF simulator
|
||||
# rlf.t_on_ms: Time for On state of the channel (ms)
|
||||
# rlf.t_off_ms: Time for Off state of the channel (ms)
|
||||
#
|
||||
# -- High Speed Train Doppler model simulator
|
||||
# hst.enable: Enable/Disable HST simulator
|
||||
# hst.period_s: HST simulation period in seconds
|
||||
# hst.fd_hz: Doppler frequency in Hz
|
||||
# hst.init_time_s: Initial time in seconds
|
||||
#####################################################################
|
||||
[channel.dl]
|
||||
#enable = false
|
||||
|
||||
[channel.dl.fading]
|
||||
#enable = false
|
||||
#model = none
|
||||
|
||||
[channel.dl.delay]
|
||||
#enable = false
|
||||
#period_s = 3600
|
||||
#init_time_s = 0
|
||||
#maximum_us = 100
|
||||
#minimum_us = 10
|
||||
|
||||
[channel.dl.rlf]
|
||||
#enable = false
|
||||
#t_on_ms = 10000
|
||||
#t_off_ms = 2000
|
||||
|
||||
[channel.dl.hst]
|
||||
#enable = false
|
||||
#period_s = 7.2
|
||||
#fd_hz = 750.0
|
||||
#init_time_s = 0.0
|
||||
|
||||
[channel.ul]
|
||||
#enable = false
|
||||
|
||||
[channel.ul.fading]
|
||||
#enable = false
|
||||
#model = none
|
||||
|
||||
[channel.ul.delay]
|
||||
#enable = false
|
||||
#period_s = 3600
|
||||
#init_time_s = 0
|
||||
#maximum_us = 100
|
||||
#minimum_us = 10
|
||||
|
||||
[channel.ul.rlf]
|
||||
#enable = false
|
||||
#t_on_ms = 10000
|
||||
#t_off_ms = 2000
|
||||
|
||||
[channel.ul.hst]
|
||||
#enable = false
|
||||
#period_s = 7.2
|
||||
#fd_hz = -750.0
|
||||
#init_time_s = 0.0
|
||||
|
||||
|
||||
#####################################################################
|
||||
# Expert configuration options
|
||||
#
|
||||
# pusch_max_its: Maximum number of turbo decoder iterations (Default 4)
|
||||
# pusch_8bit_decoder: Use 8-bit for LLR representation and turbo decoder trellis computation (Experimental)
|
||||
# nof_phy_threads: Selects the number of PHY threads (maximum 4, minimum 1, default 2)
|
||||
# metrics_period_secs: Sets the period at which metrics are requested from the eNB.
|
||||
# metrics_csv_enable: Write eNB metrics to CSV file.
|
||||
# metrics_csv_filename: File path to use for CSV metrics.
|
||||
# pregenerate_signals: Pregenerate uplink signals after attach. Improves CPU performance.
|
||||
# tx_amplitude: Transmit amplitude factor (set 0-1 to reduce PAPR)
|
||||
# link_failure_nof_err: Number of PUSCH failures after which a radio-link failure is triggered.
|
||||
# a link failure is when SNR<0 and CRC=KO
|
||||
# max_prach_offset_us: Maximum allowed RACH offset (in us)
|
||||
# eea_pref_list: Ordered preference list for the selection of encryption algorithm (EEA) (default: EEA0, EEA2, EEA1).
|
||||
# eia_pref_list: Ordered preference list for the selection of integrity algorithm (EIA) (default: EIA2, EIA1, EIA0).
|
||||
#
|
||||
#####################################################################
|
||||
[expert]
|
||||
#pusch_max_its = 8 # These are half iterations
|
||||
#pusch_8bit_decoder = false
|
||||
#nof_phy_threads = 3
|
||||
#metrics_period_secs = 1
|
||||
#metrics_csv_enable = false
|
||||
#metrics_csv_filename = /tmp/enb_metrics.csv
|
||||
#pregenerate_signals = false
|
||||
#tx_amplitude = 0.6
|
||||
#link_failure_nof_err = 50
|
||||
#rrc_inactivity_timer = 60000
|
||||
#max_prach_offset_us = 30
|
||||
#eea_pref_list = EEA0, EEA2, EEA1
|
||||
#eia_pref_list = EIA2, EIA1, EIA0
|
|
@ -0,0 +1,54 @@
|
|||
|
||||
// All times are in ms. Use -1 for infinity, where available
|
||||
|
||||
qci_config = (
|
||||
|
||||
{
|
||||
qci=7;
|
||||
pdcp_config = {
|
||||
discard_timer = 100;
|
||||
pdcp_sn_size = 12;
|
||||
}
|
||||
rlc_config = {
|
||||
ul_um = {
|
||||
sn_field_length = 10;
|
||||
};
|
||||
dl_um = {
|
||||
sn_field_length = 10;
|
||||
t_reordering = 45;
|
||||
};
|
||||
};
|
||||
logical_channel_config = {
|
||||
priority = 13;
|
||||
prioritized_bit_rate = -1;
|
||||
bucket_size_duration = 100;
|
||||
log_chan_group = 2;
|
||||
};
|
||||
},
|
||||
{
|
||||
qci=9;
|
||||
pdcp_config = {
|
||||
discard_timer = -1;
|
||||
status_report_required = true;
|
||||
}
|
||||
rlc_config = {
|
||||
ul_am = {
|
||||
t_poll_retx = 120;
|
||||
poll_pdu = 64;
|
||||
poll_byte = 750;
|
||||
max_retx_thresh = 16;
|
||||
};
|
||||
dl_am = {
|
||||
t_reordering = 50;
|
||||
t_status_prohibit = 50;
|
||||
};
|
||||
};
|
||||
logical_channel_config = {
|
||||
priority = 11;
|
||||
prioritized_bit_rate = -1;
|
||||
bucket_size_duration = 100;
|
||||
log_chan_group = 3;
|
||||
};
|
||||
}
|
||||
|
||||
);
|
|
@ -0,0 +1,90 @@
|
|||
mac_cnfg =
|
||||
{
|
||||
phr_cnfg =
|
||||
{
|
||||
dl_pathloss_change = "dB3"; // Valid: 1, 3, 6 or INFINITY
|
||||
periodic_phr_timer = 50;
|
||||
prohibit_phr_timer = 0;
|
||||
};
|
||||
ulsch_cnfg =
|
||||
{
|
||||
max_harq_tx = 4;
|
||||
periodic_bsr_timer = 20; // in ms
|
||||
retx_bsr_timer = 320; // in ms
|
||||
};
|
||||
|
||||
time_alignment_timer = -1; // -1 is infinity
|
||||
};
|
||||
|
||||
phy_cnfg =
|
||||
{
|
||||
phich_cnfg =
|
||||
{
|
||||
duration = "Normal";
|
||||
resources = "1/6";
|
||||
};
|
||||
|
||||
pusch_cnfg_ded =
|
||||
{
|
||||
beta_offset_ack_idx = 6;
|
||||
beta_offset_ri_idx = 6;
|
||||
beta_offset_cqi_idx = 6;
|
||||
};
|
||||
|
||||
// PUCCH-SR resources are scheduled on time-frequeny domain first, then multiplexed in the same resource.
|
||||
sched_request_cnfg =
|
||||
{
|
||||
dsr_trans_max = 64;
|
||||
period = 20; // in ms
|
||||
subframe = [1]; // vector of subframe indices allowed for SR transmissions
|
||||
nof_prb = 2; // number of PRBs on each extreme used for SR (total prb is twice this number)
|
||||
};
|
||||
cqi_report_cnfg =
|
||||
{
|
||||
mode = "periodic";
|
||||
simultaneousAckCQI = true;
|
||||
period = 40; // in ms
|
||||
subframe = [0];
|
||||
nof_prb = 2;
|
||||
m_ri = 8; // RI period in CQI period
|
||||
};
|
||||
};
|
||||
|
||||
cell_list =
|
||||
(
|
||||
{
|
||||
// rf_port = 0;
|
||||
// cell_id = 0x01;
|
||||
// tac = 0x0001;
|
||||
// pci = 1;
|
||||
// root_seq_idx = 204;
|
||||
// dl_earfcn = 3400;
|
||||
// ul_earfcn = 474;
|
||||
ho_active = false;
|
||||
|
||||
// CA cells
|
||||
scell_list = (
|
||||
{cell_id = 0x02; cross_carrier_scheduling = false; scheduling_cell_id = 0x02; ul_allowed = true}
|
||||
)
|
||||
|
||||
// Cells available for handover
|
||||
meas_cell_list =
|
||||
(
|
||||
{
|
||||
eci = 0x19C02;
|
||||
dl_earfcn = 2850;
|
||||
pci = 2;
|
||||
}
|
||||
);
|
||||
|
||||
// ReportCfg (only A3 supported)
|
||||
meas_report_desc = {
|
||||
a3_report_type = "RSRP";
|
||||
a3_offset = 6;
|
||||
a3_hysteresis = 0;
|
||||
a3_time_to_trigger = 480;
|
||||
rsrq_config = 4;
|
||||
};
|
||||
}
|
||||
// Add here more cells
|
||||
);
|
|
@ -0,0 +1,118 @@
|
|||
sib1 =
|
||||
{
|
||||
intra_freq_reselection = "Allowed";
|
||||
q_rx_lev_min = -65;
|
||||
//p_max = 3;
|
||||
cell_barred = "NotBarred"
|
||||
si_window_length = 20;
|
||||
sched_info =
|
||||
(
|
||||
{
|
||||
si_periodicity = 16;
|
||||
si_mapping_info = []; // comma-separated array of SIB-indexes (from 3 to 13).
|
||||
// Leave empty or commented to just scheduler sib2
|
||||
}
|
||||
);
|
||||
system_info_value_tag = 0;
|
||||
};
|
||||
|
||||
sib2 =
|
||||
{
|
||||
rr_config_common_sib =
|
||||
{
|
||||
rach_cnfg =
|
||||
{
|
||||
num_ra_preambles = 52;
|
||||
preamble_init_rx_target_pwr = -104;
|
||||
pwr_ramping_step = 6; // in dB
|
||||
preamble_trans_max = 10;
|
||||
ra_resp_win_size = 10; // in ms
|
||||
mac_con_res_timer = 64; // in ms
|
||||
max_harq_msg3_tx = 4;
|
||||
};
|
||||
bcch_cnfg =
|
||||
{
|
||||
modification_period_coeff = 16; // in ms
|
||||
};
|
||||
pcch_cnfg =
|
||||
{
|
||||
default_paging_cycle = 32; // in rf
|
||||
nB = "1";
|
||||
};
|
||||
prach_cnfg =
|
||||
{
|
||||
root_sequence_index = 128;
|
||||
prach_cnfg_info =
|
||||
{
|
||||
high_speed_flag = false;
|
||||
prach_config_index = 3;
|
||||
prach_freq_offset = 2;
|
||||
zero_correlation_zone_config = 5;
|
||||
};
|
||||
};
|
||||
pdsch_cnfg =
|
||||
{
|
||||
/* Warning: Currently disabled and forced to p_b=1 for TM2/3/4 and p_b=0 for TM1
|
||||
*/
|
||||
p_b = 1;
|
||||
rs_power = 0;
|
||||
};
|
||||
pusch_cnfg =
|
||||
{
|
||||
n_sb = 1;
|
||||
hopping_mode = "inter-subframe";
|
||||
pusch_hopping_offset = 2;
|
||||
enable_64_qam = false; // 64QAM PUSCH is not currently enabled
|
||||
ul_rs =
|
||||
{
|
||||
cyclic_shift = 0;
|
||||
group_assignment_pusch = 0;
|
||||
group_hopping_enabled = false;
|
||||
sequence_hopping_enabled = false;
|
||||
};
|
||||
};
|
||||
pucch_cnfg =
|
||||
{
|
||||
delta_pucch_shift = 2;
|
||||
n_rb_cqi = 2;
|
||||
n_cs_an = 0;
|
||||
n1_pucch_an = 12;
|
||||
};
|
||||
ul_pwr_ctrl =
|
||||
{
|
||||
p0_nominal_pusch = -85;
|
||||
alpha = 0.7;
|
||||
p0_nominal_pucch = -107;
|
||||
delta_flist_pucch =
|
||||
{
|
||||
format_1 = 0;
|
||||
format_1b = 3;
|
||||
format_2 = 1;
|
||||
format_2a = 2;
|
||||
format_2b = 2;
|
||||
};
|
||||
delta_preamble_msg3 = 6;
|
||||
};
|
||||
ul_cp_length = "len1";
|
||||
};
|
||||
|
||||
ue_timers_and_constants =
|
||||
{
|
||||
t300 = 2000; // in ms
|
||||
t301 = 100; // in ms
|
||||
t310 = 1000; // in ms
|
||||
n310 = 1;
|
||||
t311 = 1000; // in ms
|
||||
n311 = 1;
|
||||
};
|
||||
|
||||
freqInfo =
|
||||
{
|
||||
ul_carrier_freq_present = true;
|
||||
ul_bw_present = true;
|
||||
additional_spectrum_emission = 1;
|
||||
};
|
||||
|
||||
time_alignment_timer = "INFINITY"; // use "sf500", "sf750", etc.
|
||||
};
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
#####################################################################
|
||||
# srsEPC configuration file
|
||||
#####################################################################
|
||||
|
||||
#####################################################################
|
||||
# MME configuration
|
||||
#
|
||||
# mme_code: 8-bit MME code identifies the MME within a group.
|
||||
# mme_group: 16-bit MME group identifier.
|
||||
# tac: 16-bit Tracking Area Code.
|
||||
# mcc: Mobile Country Code
|
||||
# mnc: Mobile Network Code
|
||||
# apn: Set Access Point Name (APN)
|
||||
# mme_bind_addr: IP bind addr to listen for eNB S1-MME connnections
|
||||
# dns_addr: DNS server address for the UEs
|
||||
# encryption_algo: Preferred encryption algorithm for NAS layer
|
||||
# (default: EEA0, support: EEA1, EEA2)
|
||||
# integrity_algo: Preferred integrity protection algorithm for NAS
|
||||
# (default: EIA1, support: EIA1, EIA2 (EIA0 not support)
|
||||
# paging_timer: Value of paging timer in seconds (T3413)
|
||||
#
|
||||
#####################################################################
|
||||
[mme]
|
||||
mme_code = 0x1a
|
||||
mme_group = 0x0001
|
||||
tac = 0x0007
|
||||
mcc = ${epc.mcc}
|
||||
mnc = ${epc.mnc}
|
||||
mme_bind_addr = ${epc.run_addr}
|
||||
apn = srsapn
|
||||
dns_addr = 8.8.8.8
|
||||
encryption_algo = EEA0
|
||||
integrity_algo = EIA1
|
||||
paging_timer = 2
|
||||
|
||||
#####################################################################
|
||||
# HSS configuration
|
||||
#
|
||||
# db_file: Location of .csv file that stores UEs information.
|
||||
#
|
||||
#####################################################################
|
||||
[hss]
|
||||
db_file = user_db.csv
|
||||
|
||||
#####################################################################
|
||||
# SP-GW configuration
|
||||
#
|
||||
# gtpu_bind_addr: GTP-U bind address.
|
||||
# sgi_if_addr: SGi TUN interface IP address.
|
||||
# sgi_if_name: SGi TUN interface name.
|
||||
# max_paging_queue: Maximum packets in paging queue (per UE).
|
||||
#
|
||||
#####################################################################
|
||||
|
||||
[spgw]
|
||||
gtpu_bind_addr = ${epc.run_addr}
|
||||
sgi_if_addr = 172.16.0.1
|
||||
sgi_if_name = srs_spgw_sgi
|
||||
max_paging_queue = 100
|
||||
|
||||
####################################################################
|
||||
# PCAP configuration
|
||||
#
|
||||
# Packets are captured to file in the compact format decoded by
|
||||
# the Wireshark s1ap dissector and with DLT 150.
|
||||
# To use the dissector, edit the preferences for DLT_USER to
|
||||
# add an entry with DLT=150, Payload Protocol=s1ap.
|
||||
#
|
||||
# enable: Enable or disable the PCAP.
|
||||
# filename: File name where to save the PCAP.
|
||||
#
|
||||
####################################################################
|
||||
[pcap]
|
||||
enable = false
|
||||
filename = /tmp/epc.pcap
|
||||
|
||||
####################################################################
|
||||
# Log configuration
|
||||
#
|
||||
# Log levels can be set for individual layers. "all_level" sets log
|
||||
# level for all layers unless otherwise configured.
|
||||
# Format: e.g. s1ap_level = info
|
||||
#
|
||||
# In the same way, packet hex dumps can be limited for each level.
|
||||
# "all_hex_limit" sets the hex limit for all layers unless otherwise
|
||||
# configured.
|
||||
# Format: e.g. s1ap_hex_limit = 32
|
||||
#
|
||||
# Logging layers: nas, s1ap, mme_gtpc, spgw_gtpc, gtpu, spgw, hss, all
|
||||
# Logging levels: debug, info, warning, error, none
|
||||
#
|
||||
# filename: File path to use for log output. Can be set to stdout
|
||||
# to print logs to standard output
|
||||
#####################################################################
|
||||
[log]
|
||||
all_level = info
|
||||
all_hex_limit = 32
|
||||
filename = /tmp/epc.log
|
||||
|
||||
#nas_level = debug
|
||||
#s1ap_level = debug
|
||||
#mme_gtpc_level = debug
|
||||
#spgw_gtpc_level = debug
|
||||
#gtpu_level = debug
|
||||
#spgw_level = debug
|
||||
#hss_level = debug
|
|
@ -0,0 +1,24 @@
|
|||
#
|
||||
# .csv to store UE's information in HSS
|
||||
# Kept in the following format: "Name,Auth,IMSI,Key,OP_Type,OP,AMF,SQN,QCI,IP_alloc"
|
||||
#
|
||||
# Name: Human readable name to help distinguish UE's. Ignored by the HSS
|
||||
# IMSI: UE's IMSI value
|
||||
# Auth: Authentication algorithm used by the UE. Valid algorithms are XOR
|
||||
# (xor) and MILENAGE (mil)
|
||||
# Key: UE's key, where other keys are derived from. Stored in hexadecimal
|
||||
# OP_Type: Operator's code type, either OP or OPc
|
||||
# OP/OPc: Operator Code/Cyphered Operator Code, stored in hexadecimal
|
||||
# AMF: Authentication management field, stored in hexadecimal
|
||||
# SQN: UE's Sequence number for freshness of the authentication
|
||||
# QCI: QoS Class Identifier for the UE's default bearer.
|
||||
# IP_alloc: IP allocation stratagy for the SPGW.
|
||||
# With 'dynamic' the SPGW will automatically allocate IPs
|
||||
# With a valid IPv4 (e.g. '172.16.0.2') the UE will have a statically assigned IP.
|
||||
#
|
||||
# Note: Lines starting by '#' are ignored and will be overwritten
|
||||
#ue2,mil,001010123456780,00112233445566778899aabbccddeeff,opc,63bfa50ee6523365ff14c1f45f88737d,8000,000000001234,7,dynamic
|
||||
#ue1,xor,001010123456789,00112233445566778899aabbccddeeff,opc,63bfa50ee6523365ff14c1f45f88737d,9001,000000001255,7,dynamic
|
||||
%for sub in epc.hss.subscribers:
|
||||
ogt${sub.id},${sub.auth_algo},${sub.imsi},${sub.ki},opc,63bfa50ee6523365ff14c1f45f88737d,8000,000000001234,7,dynamic
|
||||
%endfor
|
|
@ -0,0 +1,347 @@
|
|||
#####################################################################
|
||||
# srsUE configuration file
|
||||
#####################################################################
|
||||
|
||||
#####################################################################
|
||||
# RF configuration
|
||||
#
|
||||
# dl_earfcn: Downlink EARFCN code.
|
||||
# freq_offset: Uplink and Downlink optional frequency offset (in Hz)
|
||||
# tx_gain: Transmit gain (dB).
|
||||
# rx_gain: Optional receive gain (dB). If disabled, AGC if enabled
|
||||
#
|
||||
# Optional parameters:
|
||||
# dl_freq: Override DL frequency corresponding to dl_earfcn
|
||||
# ul_freq: Override UL frequency corresponding to dl_earfcn
|
||||
# nof_radios: Number of available RF devices
|
||||
# nof_rf_channels: Number of RF channels per radio
|
||||
# nof_rx_ant: Number of RX antennas per channel
|
||||
# device_name: Device driver family. Supported options: "auto" (uses first found), "UHD" or "bladeRF"
|
||||
# device_args: Arguments for the device driver. Options are "auto" or any string.
|
||||
# Default for UHD: "recv_frame_size=9232,send_frame_size=9232"
|
||||
# Default for bladeRF: ""
|
||||
# device_args_2: Arguments for the RF device driver 2.
|
||||
# device_args_3: Arguments for the RF device driver 3.
|
||||
# time_adv_nsamples: Transmission time advance (in number of samples) to compensate for RF delay
|
||||
# from antenna to timestamp insertion.
|
||||
# Default "auto". B210 USRP: 100 samples, bladeRF: 27.
|
||||
# burst_preamble_us: Preamble length to transmit before start of burst.
|
||||
# Default "auto". B210 USRP: 400 us, bladeRF: 0 us.
|
||||
# continuous_tx: Transmit samples continuously to the radio or on bursts (auto/yes/no).
|
||||
# Default is auto (yes for UHD, no for rest)
|
||||
#####################################################################
|
||||
[rf]
|
||||
dl_earfcn = 3400
|
||||
freq_offset = 0
|
||||
tx_gain = 80
|
||||
#rx_gain = 40
|
||||
|
||||
#nof_radios = 1
|
||||
#nof_rx_ant = 1
|
||||
|
||||
# For best performance in 2x2 MIMO and >= 15 MHz use the following device_args settings:
|
||||
# USRP B210: num_recv_frames=64,num_send_frames=64
|
||||
|
||||
# For best performance when BW<5 MHz (25 PRB), use the following device_args settings:
|
||||
# USRP B210: send_frame_size=512,recv_frame_size=512
|
||||
|
||||
#device_args = auto
|
||||
#time_adv_nsamples = auto
|
||||
#burst_preamble_us = auto
|
||||
#continuous_tx = auto
|
||||
|
||||
|
||||
#####################################################################
|
||||
# Packet capture configuration
|
||||
#
|
||||
# Packet capture is supported at both MAC and NAS layers.
|
||||
# MAC-layer packets are captured to file in the compact format
|
||||
# decoded by the Wireshark mac-lte-framed dissector.
|
||||
# To use this dissector, edit the preferences for DLT_USER to
|
||||
# add an entry with DLT=147, Payload Protocol=mac-lte-framed.
|
||||
# For more information see: https://wiki.wireshark.org/MAC-LTE
|
||||
# NAS-layer packets are dissected with DLT=148, and
|
||||
# Payload Protocol = nas-eps.
|
||||
#
|
||||
# enable: Enable MAC layer packet captures (true/false)
|
||||
# filename: File path to use for MAC packet captures
|
||||
# nas_enable: Enable NAS layer packet captures (true/false)
|
||||
# nas_filename: File path to use for NAS packet captures
|
||||
#####################################################################
|
||||
[pcap]
|
||||
enable = false
|
||||
filename = /tmp/ue.pcap
|
||||
nas_enable = false
|
||||
nas_filename = /tmp/nas.pcap
|
||||
|
||||
#####################################################################
|
||||
# Log configuration
|
||||
#
|
||||
# Log levels can be set for individual layers. "all_level" sets log
|
||||
# level for all layers unless otherwise configured.
|
||||
# Format: e.g. phy_level = info
|
||||
#
|
||||
# In the same way, packet hex dumps can be limited for each level.
|
||||
# "all_hex_limit" sets the hex limit for all layers unless otherwise
|
||||
# configured.
|
||||
# Format: e.g. phy_hex_limit = 32
|
||||
#
|
||||
# Logging layers: rf, phy, mac, rlc, pdcp, rrc, nas, gw, usim, all
|
||||
# Logging levels: debug, info, warning, error, none
|
||||
#
|
||||
# filename: File path to use for log output. Can be set to stdout
|
||||
# to print logs to standard output
|
||||
# file_max_size: Maximum file size (in kilobytes). When passed, multiple files are created.
|
||||
# If set to negative, a single log file will be created.
|
||||
#####################################################################
|
||||
[log]
|
||||
all_level = warning
|
||||
phy_lib_level = none
|
||||
all_hex_limit = 32
|
||||
filename = /tmp/ue.log
|
||||
file_max_size = -1
|
||||
|
||||
#####################################################################
|
||||
# USIM configuration
|
||||
#
|
||||
# mode: USIM mode (soft/pcsc)
|
||||
# algo: Authentication algorithm (xor/milenage)
|
||||
# op/opc: 128-bit Operator Variant Algorithm Configuration Field (hex)
|
||||
# - Specify either op or opc (only used in milenage)
|
||||
# k: 128-bit subscriber key (hex)
|
||||
# imsi: 15 digit International Mobile Subscriber Identity
|
||||
# imei: 15 digit International Mobile Station Equipment Identity
|
||||
# pin: PIN in case real SIM card is used
|
||||
# reader: Specify card reader by it's name as listed by 'pcsc_scan'. If empty, try all available readers.
|
||||
#####################################################################
|
||||
[usim]
|
||||
mode = soft
|
||||
algo = ${ue.auth_algo}
|
||||
#opc = 63BFA50EE6523365FF14C1F45F88737D
|
||||
k = ${ue.ki}
|
||||
imsi = ${ue.imsi}
|
||||
imei = 353490069873319
|
||||
#reader =
|
||||
#pin = 1234
|
||||
|
||||
#####################################################################
|
||||
# RRC configuration
|
||||
#
|
||||
# ue_category: Sets UE category (range 1-5). Default: 4
|
||||
# release: UE Release (8 to 10)
|
||||
# feature_group: Hex value of the featureGroupIndicators field in the
|
||||
# UECapabilityInformation message. Default 0xe6041000
|
||||
# mbms_service_id: MBMS service id for autostarting MBMS reception
|
||||
# (default -1 means disabled)
|
||||
# mbms_service_port: Port of the MBMS service
|
||||
#####################################################################
|
||||
[rrc]
|
||||
#ue_category = 4
|
||||
#release = 8
|
||||
#feature_group = 0xe6041000
|
||||
#mbms_service_id = -1
|
||||
#mbms_service_port = 4321
|
||||
|
||||
#####################################################################
|
||||
# NAS configuration
|
||||
#
|
||||
# apn: Set Access Point Name (APN)
|
||||
# apn_protocol: Set APN protocol (IPv4, IPv6 or IPv4v6.)
|
||||
# user: Username for CHAP authentication
|
||||
# pass: Password for CHAP authentication
|
||||
# force_imsi_attach: Whether to always perform an IMSI attach
|
||||
# eia: List of integrity algorithms included in UE capabilities
|
||||
# Supported: 1 - Snow3G, 2 - AES
|
||||
# eea: List of ciphering algorithms included in UE capabilities
|
||||
# Supported: 0 - NULL, 1 - Snow3G, 2 - AES
|
||||
#####################################################################
|
||||
[nas]
|
||||
#apn = internetinternet
|
||||
#apn_protocol = ipv4
|
||||
#user = srsuser
|
||||
#pass = srspass
|
||||
#force_imsi_attach = false
|
||||
#eia = 1,2
|
||||
#eea = 0,1,2
|
||||
|
||||
#####################################################################
|
||||
# GW configuration
|
||||
#
|
||||
# netns: Network namespace to create TUN device. Default: empty
|
||||
# ip_devname: Name of the tun_srsue device. Default: tun_srsue
|
||||
# ip_netmask: Netmask of the tun_srsue device. Default: 255.255.255.0
|
||||
#####################################################################
|
||||
[gw]
|
||||
#netns =
|
||||
#ip_devname = tun_srsue
|
||||
#ip_netmask = 255.255.255.0
|
||||
|
||||
#####################################################################
|
||||
# GUI configuration
|
||||
#
|
||||
# Simple GUI displaying PDSCH constellation and channel freq response.
|
||||
# (Requires building with srsGUI)
|
||||
# enable: Enable the graphical interface (true/false)
|
||||
#####################################################################
|
||||
[gui]
|
||||
enable = false
|
||||
|
||||
#####################################################################
|
||||
# Channel emulator options:
|
||||
# enable: Enable/Disable internal Downlink/Uplink channel emulator
|
||||
#
|
||||
# -- Fading emulator
|
||||
# fading.enable: Enable/disable fading simulator
|
||||
# fading.model: Fading model + maximum doppler (E.g. none, epa5, eva70, etu300, etc)
|
||||
#
|
||||
# -- Delay Emulator delay(t) = delay_min + (delay_max - delay_min) * (1 + sin(2pi*t/period)) / 2
|
||||
# Maximum speed [m/s]: (delay_max - delay_min) * pi * 300 / period
|
||||
# delay.enable: Enable/disable delay simulator
|
||||
# delay.period_s: Delay period in seconds.
|
||||
# delay.init_time_s: Delay initial time in seconds.
|
||||
# delay.maximum_us: Maximum delay in microseconds
|
||||
# delay.minumum_us: Minimum delay in microseconds
|
||||
#
|
||||
# -- Radio-Link Failure (RLF) Emulator
|
||||
# rlf.enable: Enable/disable RLF simulator
|
||||
# rlf.t_on_ms: Time for On state of the channel (ms)
|
||||
# rlf.t_off_ms: Time for Off state of the channel (ms)
|
||||
#
|
||||
# -- High Speed Train Doppler model simulator
|
||||
# hst.enable: Enable/Disable HST simulator
|
||||
# hst.period_s: HST simulation period in seconds
|
||||
# hst.fd_hz: Doppler frequency in Hz
|
||||
# hst.init_time_s: Initial time in seconds
|
||||
#####################################################################
|
||||
[channel.dl]
|
||||
#enable = false
|
||||
|
||||
[channel.dl.fading]
|
||||
#enable = false
|
||||
#model = none
|
||||
|
||||
[channel.dl.delay]
|
||||
#enable = false
|
||||
#period_s = 3600
|
||||
#init_time_s = 0
|
||||
#maximum_us = 100
|
||||
#minimum_us = 10
|
||||
|
||||
[channel.dl.rlf]
|
||||
#enable = false
|
||||
#t_on_ms = 10000
|
||||
#t_off_ms = 2000
|
||||
|
||||
[channel.dl.hst]
|
||||
#enable = false
|
||||
#period_s = 7.2
|
||||
#fd_hz = 750.0
|
||||
#init_time_s = 0.0
|
||||
|
||||
[channel.ul]
|
||||
#enable = false
|
||||
|
||||
[channel.ul.fading]
|
||||
#enable = false
|
||||
#model = none
|
||||
|
||||
[channel.ul.delay]
|
||||
#enable = false
|
||||
#period_s = 3600
|
||||
#init_time_s = 0
|
||||
#maximum_us = 100
|
||||
#minimum_us = 10
|
||||
|
||||
[channel.ul.rlf]
|
||||
#enable = false
|
||||
#t_on_ms = 10000
|
||||
#t_off_ms = 2000
|
||||
|
||||
[channel.ul.hst]
|
||||
#enable = false
|
||||
#period_s = 7.2
|
||||
#fd_hz = -750.0
|
||||
#init_time_s = 0.0
|
||||
|
||||
#####################################################################
|
||||
# PHY configuration options
|
||||
#
|
||||
# rx_gain_offset: RX Gain offset to add to rx_gain to calibrate RSRP readings
|
||||
# prach_gain: PRACH gain (dB). If defined, forces a gain for the tranmsission of PRACH only.,
|
||||
# Default is to use tx_gain in [rf] section.
|
||||
# cqi_max: Upper bound on the maximum CQI to be reported. Default 15.
|
||||
# cqi_fixed: Fixes the reported CQI to a constant value. Default disabled.
|
||||
# snr_ema_coeff: Sets the SNR exponential moving average coefficient (Default 0.1)
|
||||
# snr_estim_alg: Sets the noise estimation algorithm. (Default refs)
|
||||
# Options: pss: use difference between received and known pss signal,
|
||||
# refs: use difference between noise references and noiseless (after filtering)
|
||||
# empty: use empty subcarriers in the boarder of pss/sss signal
|
||||
# pdsch_max_its: Maximum number of turbo decoder iterations (Default 4)
|
||||
# nof_phy_threads: Selects the number of PHY threads (maximum 4, minimum 1, default 2)
|
||||
# equalizer_mode: Selects equalizer mode. Valid modes are: "mmse", "zf" or any
|
||||
# non-negative real number to indicate a regularized zf coefficient.
|
||||
# Default is MMSE.
|
||||
# sfo_ema: EMA coefficient to average sample offsets used to compute SFO
|
||||
# sfo_correct_period: Period in ms to correct sample time to adjust for SFO
|
||||
# sss_algorithm: Selects the SSS estimation algorithm. Can choose between
|
||||
# {full, partial, diff}.
|
||||
# estimator_fil_auto: The channel estimator smooths the channel estimate with an adaptative filter.
|
||||
# estimator_fil_stddev: Sets the channel estimator smooth gaussian filter standard deviation.
|
||||
# estimator_fil_order: Sets the channel estimator smooth gaussian filter order (even values perform better).
|
||||
# The taps are [w, 1-2w, w]
|
||||
#
|
||||
# snr_to_cqi_offset: Sets an offset in the SNR to CQI table. This is used to adjust the reported CQI.
|
||||
#
|
||||
# pregenerate_signals: Pregenerate uplink signals after attach. Improves CPU performance.
|
||||
#
|
||||
# interpolate_subframe_enabled: Interpolates in the time domain the channel estimates within 1 subframe. Default is to average.
|
||||
#
|
||||
# sic_pss_enabled: Applies Successive Interference Cancellation to PSS signals when searching for neighbour cells.
|
||||
# Must be disabled if cells have identical channel and timing, for instance if generated from
|
||||
# the same source.
|
||||
#
|
||||
# pdsch_csi_enabled: Stores the Channel State Information and uses it for weightening the softbits. It is only
|
||||
# used in TM1. It is True by default.
|
||||
#
|
||||
# pdsch_8bit_decoder: Use 8-bit for LLR representation and turbo decoder trellis computation (Experimental)
|
||||
# force_ul_amplitude: Forces the peak amplitude in the PUCCH, PUSCH and SRS (set 0.0 to 1.0, set to 0 or negative for disabling)
|
||||
#
|
||||
#####################################################################
|
||||
[phy]
|
||||
#rx_gain_offset = 62
|
||||
#prach_gain = 30
|
||||
#cqi_max = 15
|
||||
#cqi_fixed = 10
|
||||
#snr_ema_coeff = 0.1
|
||||
#snr_estim_alg = refs
|
||||
#pdsch_max_its = 8 # These are half iterations
|
||||
#nof_phy_threads = 3
|
||||
#equalizer_mode = mmse
|
||||
#sfo_ema = 0.1
|
||||
#sfo_correct_period = 10
|
||||
#sss_algorithm = full
|
||||
#estimator_fil_auto = false
|
||||
#estimator_fil_stddev = 1.0
|
||||
#estimator_fil_order = 4
|
||||
#snr_to_cqi_offset = 0.0
|
||||
#interpolate_subframe_enabled = false
|
||||
#sic_pss_enabled = true
|
||||
#pregenerate_signals = false
|
||||
#pdsch_csi_enabled = true
|
||||
#pdsch_8bit_decoder = false
|
||||
#force_ul_amplitude = 0
|
||||
|
||||
#####################################################################
|
||||
# General configuration options
|
||||
#
|
||||
# metrics_csv_enable: Write UE metrics to CSV file.
|
||||
#
|
||||
# metrics_period_secs: Sets the period at which metrics are requested from the UE.
|
||||
#
|
||||
# metrics_csv_filename: File path to use for CSV metrics.
|
||||
#
|
||||
#####################################################################
|
||||
[general]
|
||||
#metrics_csv_enable = false
|
||||
#metrics_period_secs = 1
|
||||
#metrics_csv_filename = /tmp/ue_metrics.csv
|
|
@ -0,0 +1,44 @@
|
|||
#!/usr/bin/env python3
|
||||
from osmo_gsm_tester.testenv import *
|
||||
|
||||
def print_results(cli_res, srv_res):
|
||||
cli_sent = cli_res['end']['sum_sent']
|
||||
cli_recv = cli_res['end']['sum_received']
|
||||
print("RESULT client:")
|
||||
print("\tSEND: %d KB, %d kbps, %d seconds (%d retrans)" % (cli_sent['bytes']/1000, cli_sent['bits_per_second']/1000, cli_sent['seconds'], cli_sent['retransmits']))
|
||||
print("\tRECV: %d KB, %d kbps, %d seconds" % (cli_recv['bytes']/1000, cli_recv['bits_per_second']/1000, cli_recv['seconds']))
|
||||
print("RESULT server:")
|
||||
print("\tSEND: %d KB, %d kbps, %d seconds" % (cli_sent['bytes']/1000, cli_sent['bits_per_second']/1000, cli_sent['seconds']))
|
||||
print("\tRECV: %d KB, %d kbps, %d seconds" % (cli_recv['bytes']/1000, cli_recv['bits_per_second']/1000, cli_recv['seconds']))
|
||||
|
||||
|
||||
epc = suite.epc()
|
||||
enb = suite.enb()
|
||||
ue = suite.modem()
|
||||
iperf3srv = suite.iperf3srv({'addr': epc.tun_addr()})
|
||||
iperf3srv.set_run_node(epc.run_node())
|
||||
iperf3cli = iperf3srv.create_client()
|
||||
iperf3cli.set_run_node(ue.run_node())
|
||||
|
||||
epc.subscriber_add(ue)
|
||||
epc.start()
|
||||
enb.ue_add(ue)
|
||||
enb.start(epc)
|
||||
|
||||
print('waiting for ENB to connect to EPC...')
|
||||
wait(epc.enb_is_connected, enb)
|
||||
print('ENB is connected to EPC')
|
||||
|
||||
ue.connect(enb)
|
||||
|
||||
iperf3srv.start()
|
||||
proc = iperf3cli.prepare_test_proc(ue.netns())
|
||||
|
||||
print('waiting for UE to attach...')
|
||||
wait(ue.is_connected, None)
|
||||
print('UE is attached')
|
||||
|
||||
print("Running iperf3 client to %s through %s" % (str(iperf3cli), ue.netns()))
|
||||
proc.launch_sync()
|
||||
iperf3srv.stop()
|
||||
print_results(iperf3cli.get_results(), iperf3srv.get_results())
|
|
@ -1,22 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
from osmo_gsm_tester.testenv import *
|
||||
|
||||
#epc = suite.epc()
|
||||
#enb = suite.enb()
|
||||
ue = suite.modem()
|
||||
|
||||
#enb.start()
|
||||
#epc.enb_add(enb)
|
||||
#epc.start()
|
||||
|
||||
#wait(epc.enb_is_connected, enb)
|
||||
|
||||
#hss/epc.subscriber_add(ue)
|
||||
|
||||
#ue.connect(epc.mcc_mnc())
|
||||
ue.connect()
|
||||
|
||||
|
||||
print('waiting for modem to attach...')
|
||||
#wait(ue.is_connected, msc.mcc_mnc())
|
||||
sleep(10)
|
|
@ -0,0 +1,22 @@
|
|||
#!/usr/bin/env python3
|
||||
from osmo_gsm_tester.testenv import *
|
||||
|
||||
epc = suite.epc()
|
||||
enb = suite.enb()
|
||||
ue = suite.modem()
|
||||
|
||||
epc.subscriber_add(ue)
|
||||
epc.start()
|
||||
enb.ue_add(ue)
|
||||
enb.start(epc)
|
||||
|
||||
print('waiting for ENB to connect to EPC...')
|
||||
wait(epc.enb_is_connected, enb)
|
||||
print('ENB is connected to EPC')
|
||||
|
||||
ue.connect(enb)
|
||||
print('waiting for UE to attach...')
|
||||
wait(ue.is_connected, None)
|
||||
print('UE is attached')
|
||||
|
||||
ue.run_netns_wait('ping', ('ping', '-c', '10', epc.tun_addr()))
|
|
@ -1,6 +1,9 @@
|
|||
resources:
|
||||
ip_address:
|
||||
run_node: # for EPC
|
||||
- times: 1
|
||||
enb:
|
||||
- times: 1
|
||||
type: srsenb
|
||||
modem:
|
||||
- times: 1
|
||||
type: srsue
|
||||
|
|
Loading…
Reference in New Issue