This is merely a historical archive of years 2008-2021, before the migration to mailman3.
A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.
srs_andre gerrit-no-reply at lists.osmocom.orgHello Nils,
I'd like you to do a code review. Please visit
https://gerrit.osmocom.org/c/osmo-gsm-tester/+/21217
to review the following change.
Change subject: Modems: Introduce Android UEs
......................................................................
Modems: Introduce Android UEs
To expand the test capacities we would like to introduce
Android UEs as a new modem. Currently the following tests
are supported:
- Ping
- iPerf3 DL/UL
- RRC Mobile MT Ping
Change-Id: Iab37a0de59d6643d21bced34ddca06ff40fa62df
---
M src/osmo_gsm_tester/core/process.py
M src/osmo_gsm_tester/core/remote.py
M src/osmo_gsm_tester/core/schema.py
M src/osmo_gsm_tester/obj/enb_srs.py
M src/osmo_gsm_tester/obj/iperf3.py
M src/osmo_gsm_tester/obj/ms.py
A src/osmo_gsm_tester/obj/ms_android.py
M src/osmo_gsm_tester/obj/run_node.py
M sysmocom/default-suites.conf
A sysmocom/scenarios/androidue at .conf
M sysmocom/suites/4g/iperf3_dl.py
M sysmocom/suites/4g/iperf3_ul.py
A utils/bin/osmo-gsm-tester_androidue_conn_chk.sh
A utils/bin/osmo-gsm-tester_androidue_diag_parser.sh
14 files changed, 607 insertions(+), 12 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-gsm-tester refs/changes/17/21217/1
diff --git a/src/osmo_gsm_tester/core/process.py b/src/osmo_gsm_tester/core/process.py
index eaf8de7..5840881 100644
--- a/src/osmo_gsm_tester/core/process.py
+++ b/src/osmo_gsm_tester/core/process.py
@@ -381,12 +381,24 @@
class RemoteProcess(Process):
- def __init__(self, name, run_dir, remote_user, remote_host, remote_cwd, popen_args, remote_env={}, **popen_kwargs):
+ def __init__(self, name, run_dir, remote_user, remote_host, remote_cwd, popen_args,
+ remote_env={}, remote_port=None, **popen_kwargs):
super().__init__(name, run_dir, popen_args, **popen_kwargs)
self.remote_user = remote_user
self.remote_host = remote_host
self.remote_cwd = remote_cwd
self.remote_env = remote_env
+ self.remote_port = remote_port
+
+ # check if the command should be executed on an Android UE
+ is_ue_cmd = False
+ android_cmds = ['iperf3-cli', 'ping', 'set-airplane-mode', 'set-apn', 'get-ip',
+ 'rx-monitor', 'tx-monitor', 'diag-monitor', 'kill-diag-monitor', 'clear-diag_logs']
+ if self.remote_port:
+ for cmd in android_cmds:
+ if cmd in name:
+ self.remote_user = 'root'
+ is_ue_cmd = True
# hacky: instead of just prepending ssh, i.e. piping stdout and stderr
# over the ssh link, we should probably run on the remote side,
@@ -402,6 +414,12 @@
'%s %s %s' % (cd,
' '.join(['%s=%r'%(k,v) for k,v in self.remote_env.items()]),
' '.join(self.popen_args))]
+
+ # add arguments to directly connect to the Android UE
+ if is_ue_cmd:
+ self.popen_args.insert(1, '-p') # add ssh parameters
+ self.popen_args.insert(2, str(self.remote_port))
+
self.dbg(self.popen_args, dir=self.run_dir, conf=self.popen_kwargs, remote_env=self.remote_env)
def RunError(self, msg_prefix):
@@ -443,14 +461,21 @@
super().__init__(name, run_dir, remote_user, remote_host, remote_cwd, args, **popen_kwargs)
def run_local_sync(run_dir, name, popen_args):
- run_dir =run_dir.new_dir(name)
+ run_dir = run_dir.new_dir(name)
proc = Process(name, run_dir, popen_args)
proc.launch_sync()
return proc
+def run_local(run_dir, name, popen_args):
+ run_dir = run_dir.new_dir(name)
+ proc = Process(name, run_dir, popen_args)
+ proc.launch()
+ return proc
+
def run_local_netns_sync(run_dir, name, netns, popen_args):
- run_dir =run_dir.new_dir(name)
+ run_dir = run_dir.new_dir(name)
proc = NetNSProcess(name, run_dir, netns, popen_args)
proc.launch_sync()
return proc
+
# vim: expandtab tabstop=4 shiftwidth=4
diff --git a/src/osmo_gsm_tester/core/remote.py b/src/osmo_gsm_tester/core/remote.py
index 8deb25d..ef77c2cd 100644
--- a/src/osmo_gsm_tester/core/remote.py
+++ b/src/osmo_gsm_tester/core/remote.py
@@ -28,13 +28,14 @@
WRAPPER_SCRIPT = 'ssh_sigkiller.sh'
- def __init__(self, run_dir, remote_user = 'root', remote_host = 'localhost', remote_cwd=None):
+ def __init__(self, run_dir, remote_user = 'root', remote_host = 'localhost', remote_cwd=None, remote_port=None):
super().__init__(log.C_RUN, 'host-' + remote_user + '@' + remote_host)
self.run_dir = util.Dir(run_dir.new_dir(self.name()))
self.remote_user = remote_user
self.remote_host = remote_host
self.remote_cwd = remote_cwd
self.remote_env = {}
+ self.remote_port = remote_port
def user(self):
return self.remote_user
@@ -51,9 +52,13 @@
def get_remote_env(self):
return self.remote_env
+ def ssh_port(self):
+ return self.remote_port
+
def RemoteProcess(self, name, popen_args, remote_env={}, **popen_kwargs):
run_dir = self.run_dir.new_dir(name)
- return process.RemoteProcess(name, run_dir, self.user(), self.host(), self.cwd(), popen_args, remote_env=remote_env, **popen_kwargs)
+ return process.RemoteProcess(name, run_dir, self.user(), self.host(), self.cwd(), popen_args,
+ remote_env=remote_env, remote_port=self.ssh_port(), **popen_kwargs)
def generate_wrapper_script(self, wait_time_sec):
wrapper_script = self.run_dir.new_file(RemoteHost.WRAPPER_SCRIPT)
diff --git a/src/osmo_gsm_tester/core/schema.py b/src/osmo_gsm_tester/core/schema.py
index d56d6ec..6496e57 100644
--- a/src/osmo_gsm_tester/core/schema.py
+++ b/src/osmo_gsm_tester/core/schema.py
@@ -111,7 +111,7 @@
raise ValueError('Unknown Cipher value: %r' % val)
def modem_feature(val):
- if val in ('sms', 'gprs', 'voice', 'ussd', 'sim', '2g', '3g', '4g', 'dl_qam256', 'ul_qam64'):
+ if val in ('sms', 'gprs', 'voice', 'ussd', 'sim', '2g', '3g', '4g', 'dl_qam256', 'ul_qam64', 'qc_diag'):
return True
raise ValueError('Unknown Modem Feature: %r' % val)
diff --git a/src/osmo_gsm_tester/obj/enb_srs.py b/src/osmo_gsm_tester/obj/enb_srs.py
index 53beda8..307368f 100644
--- a/src/osmo_gsm_tester/obj/enb_srs.py
+++ b/src/osmo_gsm_tester/obj/enb_srs.py
@@ -114,6 +114,7 @@
self.start_remotely()
# send t+Enter to enable console trace
+ MainLoop.sleep(3)
self.dbg('Enabling console trace')
self.process.stdin_write('t\n')
diff --git a/src/osmo_gsm_tester/obj/iperf3.py b/src/osmo_gsm_tester/obj/iperf3.py
index 4785f78..f0309d2 100644
--- a/src/osmo_gsm_tester/obj/iperf3.py
+++ b/src/osmo_gsm_tester/obj/iperf3.py
@@ -232,7 +232,7 @@
locally = not self._run_node or self._run_node.is_local()
return locally
- def prepare_test_proc(self, dir=None, netns=None, time_sec=None, proto=None, bitrate=0, tos=None):
+ def prepare_test_proc(self, dir=None, netns=None, time_sec=None, proto=None, bitrate=0, tos=None, ue=None):
values = config.get_defaults('iperf3cli')
config.overlay(values, self.testenv.suite().config().get('iperf3cli', {}))
@@ -264,6 +264,12 @@
popen_args = ('iperf3', '-c', self.server.addr(),
'-p', str(self.server.port()), '-J',
'-t', str(time_sec))
+
+ # In case the modem is an Android UE we have to extend the iPerf3 command for local execution
+ if self._run_node.is_local() and ue.ue_serial:
+ adb_cmd_pref = ['adb', '-s', ue.ue_serial, 'exec-out', 'su', '-c']
+ popen_args = adb_cmd_pref + list(popen_args)
+
if dir == IPerf3Client.DIR_DL:
popen_args += ('-R',)
elif dir == IPerf3Client.DIR_BI:
@@ -281,7 +287,8 @@
return proc
def prepare_test_proc_remotely(self, netns, popen_args):
- self.rem_host = remote.RemoteHost(self.run_dir, self._run_node.ssh_user(), self._run_node.ssh_addr())
+ self.rem_host = remote.RemoteHost(self.run_dir, self._run_node.ssh_user(), self._run_node.ssh_addr(),
+ None, self._run_node.ssh_port())
remote_prefix_dir = util.Dir(IPerf3Client.REMOTE_DIR)
remote_run_dir = util.Dir(remote_prefix_dir.child('cli-' + str(self)))
diff --git a/src/osmo_gsm_tester/obj/ms.py b/src/osmo_gsm_tester/obj/ms.py
index 70ce558..bfd3f3b 100644
--- a/src/osmo_gsm_tester/obj/ms.py
+++ b/src/osmo_gsm_tester/obj/ms.py
@@ -72,6 +72,9 @@
elif ms_type == 'srsue':
from .ms_srs import srsUE
ms_class = srsUE
+ elif ms_type == 'androidue':
+ from .ms_android import AndroidUE
+ ms_class = AndroidUE
elif ms_type == 'amarisoftue':
from .ms_amarisoft import AmarisoftUE
ms_class = AmarisoftUE
diff --git a/src/osmo_gsm_tester/obj/ms_android.py b/src/osmo_gsm_tester/obj/ms_android.py
new file mode 100644
index 0000000..0d9ed16
--- /dev/null
+++ b/src/osmo_gsm_tester/obj/ms_android.py
@@ -0,0 +1,526 @@
+# Author: Nils Fürste <nils.fuerste at softwareradiosystems.com>
+# Author: Bedran Karakoc <bedran.karakoc at softwareradiosystems.com>
+
+import pprint
+import time
+import re
+
+from ..core import log, util, config, remote, process
+from ..core import schema
+from .run_node import RunNode
+from .ms import MS
+from .srslte_common import srslte_common
+from .ms_srs import srsUEMetrics
+
+
+def on_register_schemas():
+ resource_schema = {
+ 'additional_args[]': schema.STR,
+ 'apn': schema.STR,
+ 'apn_name': schema.STR,
+ 'apn_mcc': schema.STR,
+ 'apn_mnc': schema.STR,
+ 'sel_apn': schema.STR,
+ 'ue_serial': schema.STR,
+ 'enable_pcap': schema.BOOL_STR,
+ }
+ for key, val in RunNode.schema().items():
+ resource_schema['run_node.%s' % key] = val
+ schema.register_resource_schema('modem', resource_schema)
+
+ config_schema = {
+ 'enable_pcap': schema.BOOL_STR,
+ 'log_all_level': schema.STR,
+ }
+ schema.register_config_schema('modem', config_schema)
+
+
+class AndroidUE(MS, srslte_common):
+
+ REMOTEDIR = '/osmo-gsm-tester-androidue'
+ METRICSFILE = 'android_ue_metrics.csv'
+ PCAPFILE = 'android_ue.pcap'
+
+ def __init__(self, testenv, conf):
+ self._run_node = RunNode.from_conf(conf.get('run_node', {}))
+ super().__init__('androidue_%s' % self.addr(), testenv, conf)
+ srslte_common.__init__(self)
+ self.run_dir = None
+ self.rem_host = None
+ self.testenv = testenv
+ self.emm_connected = False
+ self.rrc_connected = False
+ self.connect_timeout = 300 # sec
+ self.ue_serial = None # stores the UE serial if available
+ self.remote_port = None
+ self.conn_reset_intvl = 20
+ self.remote_pcap_file = None
+ self.pcap_file = None
+ self.ue_data_intf = None
+ self.remote_metrics_file = None
+ self.metrics_file = None
+ self.remote_run_dir = None
+ self.have_metrics_file = False
+ self.rx_monitor_proc = None
+ self.tx_monitor_proc = None
+ self.diag_monitor_proc = None
+ self.diag_parser_proc = None
+ self.enable_pcap = None
+
+ def cleanup(self):
+ if self.process is None:
+ return
+ if self._run_node.is_local():
+ return
+
+ # stop monitoring
+ self.stop()
+
+ def scp_back_pcap(self):
+ if self.enable_pcap:
+ DIAG_PARSER = 'osmo-gsm-tester_androidue_diag_parser.sh'
+ if not self._run_node.is_local():
+ popen_args_diag_parser = [DIAG_PARSER, str(self.ue_serial), str(self.remote_run_dir), str(self.remote_pcap_file)]
+ diag_parser_proc = self.rem_host.RemoteProcess("diag-parser", popen_args_diag_parser, env={})
+ diag_parser_proc.launch()
+ else:
+ popen_args_diag_parser = [DIAG_PARSER, str(self.ue_serial), str(self.run_dir), str(self.pcap_file)]
+ diag_parser_proc = process.run_local(self.run_dir, "diag-parser", popen_args_diag_parser)
+
+ timeout_ = 300 # timeout in s
+ while timeout_ > 0:
+ diag_parser_stdout = diag_parser_proc.get_stdout()
+ if diag_parser_stdout.count('Pulling new .qmdl file...') > 1:
+ # If the parsers pulls the .qmdl file for the second time we know that
+ # the parsing of the first one is done
+ break
+ time.sleep(2)
+ timeout_ -= 2
+
+ if timeout_ <= 0:
+ raise log.Error("Writing PCAP failed")
+
+ if not self._run_node.is_local():
+ try:
+ self.rem_host.scpfrom('scp-back-pcap', self.remote_pcap_file, self.pcap_file)
+ except Exception as e:
+ self.log(repr(e))
+ else:
+ pass
+
+ def stop(self):
+ # terminate bitrate monitors and save metrics
+ brate_rx_raw = self.rx_monitor_proc.get_stdout().split('\n')
+ brate_tx_raw = self.tx_monitor_proc.get_stdout().split('\n')
+ brate_rx_raw.remove('')
+ self.rx_monitor_proc.terminate()
+ brate_tx_raw.remove('')
+ self.tx_monitor_proc.terminate()
+ self.save_metrics(brate_rx_raw[1:], brate_tx_raw[1:])
+
+ # kill diag monitor if started
+ if self.diag_monitor_proc:
+ kill_diag_proc = self.rem_host.RemoteProcess("kill-diag-monitor", ['/vendor/bin/diag_mdlog', '-k'], env={})
+ kill_diag_proc.launch_sync()
+ time.sleep(3)
+ if self.diag_monitor_proc.is_running():
+ self.diag_monitor_proc.terminate()
+ self.diag_parser_proc.terminate()
+
+ # enable airplane mode
+ self.set_airplane_mode(True)
+
+ # scp back pcap file
+ self.scp_back_pcap()
+
+ def start(self):
+ # check if device is available over ADB
+ if not self.check_device_availability():
+ self.log("Can't find requested device. Restarting ADB and check again")
+ self.restart_adb_inst(True)
+ if not self.check_device_availability():
+ raise log.Error("Device with serial %s is not available" % self.ue_serial)
+
+ # enable airplane mode
+ self.set_airplane_mode(True)
+
+ # clear working directories
+ self.clear_work_dirs()
+
+ def clear_work_dirs(self):
+ # clear remote_run_dir
+ popen_args_clear_run_dir = ['sudo', 'rm', '-rf', '-v', str(self.remote_run_dir) + '/*', '||', 'true']
+ clear_run_dir_proc = self.run_netns_wait('clear-run_dir', popen_args_clear_run_dir)
+ self.dbg("Deleted the following files: %s" % clear_run_dir_proc.get_stdout())
+
+ # clear diag_logs
+ popen_args_clear_diag_logs = ['rm', '-r', '/data/local/tmp/diag_logs/*', '||', 'true']
+ clear_diag_logs_proc = self.run_netns_wait('clear-diag_logs', popen_args_clear_diag_logs)
+ self.dbg("Deleted the following files: %s" % clear_diag_logs_proc.get_stdout())
+
+ def check_device_availability(self):
+ serials_cmd = ['adb', 'devices']
+ proc = self.run_netns_wait("devices", serials_cmd)
+ return self.ue_serial in proc.get_stdout()
+
+ def restart_adb_inst(self, as_root=False):
+ self.run_netns_wait("kill-adb", ['sudo', 'adb', 'kill-server'])
+ if as_root:
+ self.run_netns_wait("start-adb", ['adb', 'start-server'])
+ else:
+ self.run_netns_wait("start-adb", ['sudo', 'adb', 'start-server'])
+ return
+
+ def connect(self, enb):
+ self.log('Starting AndroidUE')
+ self.configure()
+ CONN_CHK = 'osmo-gsm-tester_androidue_conn_chk.sh'
+ popen_args_emm_conn_chk = [CONN_CHK, self.ue_serial]
+
+ if not self._run_node.is_local():
+ emm_conn_chk_proc = self.rem_host.RemoteProcess('emm-conn-chk', popen_args_emm_conn_chk, env={})
+ emm_conn_chk_proc.launch()
+ else:
+ emm_conn_chk_proc = process.run_local(self.run_dir, 'emm-conn-chk', popen_args_emm_conn_chk)
+
+ # check connection status
+ timer = self.connect_timeout
+ while timer > 0:
+ if 'LTE' in emm_conn_chk_proc.get_stdout():
+ if self.get_assigned_addr():
+ self.emm_connected = True
+ self.rrc_connected = True
+ emm_conn_chk_proc.terminate()
+ break
+
+ # reset connection
+ if timer % self.conn_reset_intvl == 0:
+ self.set_airplane_mode(True)
+ time.sleep(2)
+ timer -= 2
+ self.set_airplane_mode(False)
+ time.sleep(1)
+ timer -= 1
+
+ if timer == 0:
+ raise log.Error("Android UE %s connection timer expired" % self.ue_serial)
+
+ # start bit rate monitoring on Android UE
+ popen_args_rx = ['while', 'true;', 'do',
+ 'echo', '`cat', '/sys/class/net/' + self.ue_data_intf + '/statistics/rx_bytes`;',
+ 'sleep', '1;', 'done']
+ popen_args_tx = ['while', 'true;', 'do',
+ 'echo', '`cat', '/sys/class/net/' + self.ue_data_intf + '/statistics/tx_bytes`;',
+ 'sleep', '1;', 'done']
+
+ if not self._run_node.is_local():
+ self.rx_monitor_proc = self.rem_host.RemoteProcess("rx-monitor", popen_args_rx, env={})
+ self.rx_monitor_proc.launch()
+ self.tx_monitor_proc = self.rem_host.RemoteProcess("tx-monitor", popen_args_tx, env={})
+ self.tx_monitor_proc.launch()
+ else:
+ self.rx_monitor_proc = process.run_local(self.run_dir, "rx-monitor", popen_args_rx)
+ self.tx_monitor_proc = process.run_local(self.run_dir, "tx-monitor", popen_args_tx)
+
+ # start diag_mdlog and parsing
+ if 'qc_diag' in self.features():
+ DIAG_PARSER = 'osmo-gsm-tester_androidue_diag_parser.sh'
+ self.pcap_file = self.run_dir.child(AndroidUE.PCAPFILE)
+ self.remote_pcap_file = self.remote_run_dir.child(AndroidUE.PCAPFILE)
+
+ popen_args_diag = ['/vendor/bin/diag_mdlog', '-s', '90000', '-f', '/data/local/tmp/ogt_diag.cfg',
+ '-o', '/data/local/tmp/diag_logs']
+
+ if not self._run_node.is_local():
+ self.diag_monitor_proc = self.rem_host.RemoteProcess("diag-monitor", popen_args_diag, env={})
+ self.diag_monitor_proc.launch()
+
+ popen_args_diag_parser = [DIAG_PARSER, str(self.ue_serial), str(self.remote_run_dir), str(self.remote_pcap_file)]
+ self.diag_parser_proc = self.rem_host.RemoteProcess("diag-parser", popen_args_diag_parser, env={})
+ self.diag_parser_proc.launch()
+ else:
+ self.diag_monitor_proc = process.run_local(self.run_dir, "diag-monitor", popen_args_diag)
+ self.diag_monitor_proc.launch()
+
+ popen_args_diag_parser = [DIAG_PARSER, str(self.ue_serial), str(self.run_dir), str(self.pcap_file)]
+ self.diag_parser_proc = process.run_local(self.run_dir, "diag-parser", popen_args_diag_parser)
+
+ def configure(self):
+ values = dict(ue=config.get_defaults('androidue'))
+ config.overlay(values, dict(ue=self.testenv.suite().config().get('modem', {})))
+ config.overlay(values, dict(ue=self._conf))
+ self.dbg('AndroidUE CONFIG:\n' + pprint.pformat(values))
+
+ self.remote_port = values['ue']['run_node']['remote_port']
+ self.ue_serial = values['ue']['ue_serial']
+
+ if 'qc_diag' in self.features():
+ self.enable_pcap = util.str2bool(values['ue'].get('enable_pcap', 'false'))
+
+ self.run_dir = util.Dir(self.testenv.test().get_run_dir().new_dir(self.name()))
+ self.metrics_file = self.run_dir.child(AndroidUE.METRICSFILE)
+ 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(), None, remote_port=self.remote_port)
+ self.remote_run_dir = util.Dir(AndroidUE.REMOTEDIR)
+ self.remote_metrics_file = self.remote_run_dir.child(AndroidUE.METRICSFILE)
+
+ # set APN
+ apn_params = {
+ "carrier": str(values['ue']['apn_name'] or 'default'),
+ "apn": str(values['ue']['apn']), # mandatory
+ "proxy": str(''),
+ "port": str(''),
+ "user": str(''),
+ "password": str(''),
+ "server": str(''),
+ "mmsc": str(''),
+ "mmsport": str(''),
+ "mmsproxy": str(''),
+ "mcc": str(values['ue']['apn_mcc']), # mandatory
+ "mnc": str(values['ue']['apn_mnc']), # mandatory
+ "auth": str('-1'),
+ "type": str(''),
+ "protocol": str(''),
+ "mvnotype": str(''),
+ "mvnoval": str(''),
+ "groupid": str('-1')
+ }
+
+ # make sure UE is not in airplane mode
+ self.set_airplane_mode(False)
+ time.sleep(1)
+
+ self.dbg("Set APN parameters: " + str(apn_params))
+ # self.set_apn(apn_params, True)
+
+ # move back in airplane mode
+ time.sleep(1)
+ self.set_airplane_mode(False)
+
+ # clear working directories
+ self.clear_work_dirs()
+
+ def is_rrc_connected(self):
+ if not ('qc_diag' in self.features()):
+ raise log.Error("Checking RRC state not supported (missing qc_diag feature?)")
+
+ if not self.diag_monitor_proc:
+ raise log.Error("Diag monitor crashed or not started")
+
+ diag_mon_stdout_l = self.diag_monitor_proc.get_stdout().split("\n")
+ rrc_connected = self.rrc_connected
+ for line in diag_mon_stdout_l:
+ if "rrc_state=RRC_IDLE_CAMPED" in line:
+ rrc_connected = False
+ # elif "LTE_RRC_STATE_CHANGE: RRC_IDLE_NOT_CAMPED" in line: # UE lost connection, throw exception
+ # raise log.Error("Android UE lost connection to the eNB")
+ elif "rrc_state=" in line:
+ rrc_connected = True
+ return rrc_connected
+
+ def is_registered(self, mcc_mnc=None):
+ return self.emm_connected
+
+ def get_counter(self, counter_name):
+ self.stop()
+ if counter_name == 'prach_sent':
+ # not implemented so far, return 2 to pass tests
+ return 2
+ elif counter_name == 'paging_received':
+ diag_parser_stdout_l = self.diag_parser_proc.get_stdout().split("\n")
+ return diag_parser_stdout_l.count('Paging received')
+ else:
+ raise log.Error("Counter %s not implemented" % counter_name)
+
+ def get_assigned_addr(self, ipv6=False):
+ ip_prefix = "172.16.0"
+ proc = self.run_netns_wait("get-ip", ['ip', 'addr', 'show'])
+ out_l = proc.get_stdout().split('\n')
+ ip = None
+ for line in out_l:
+ if ip_prefix in line:
+ ip = line.split(' ')[5][:-3] # UE's IP
+ self.ue_data_intf = line.split(' ')[-1] # UE's data interface
+ return ip
+
+ def running(self):
+ # check if device is available over ADB
+ if not (self.ue_serial is None):
+ serials_cmd = ['adb', 'devices']
+ proc = self.run_netns_wait("devices", serials_cmd)
+ if self.ue_serial in proc.get_stdout():
+ return True
+ self.dbg("Device with serial %s is currently not available" % self.ue_serial)
+ return False
+
+ def addr(self):
+ return self._run_node.run_addr()
+
+ def run_node(self):
+ return self._run_node
+
+ def features(self):
+ return self._conf.get('features', [])
+
+ def run_netns_wait(self, name, popen_args):
+ if self._run_node.is_local():
+ # use adb locally instead of ssh
+ adb_cmd_pref = ['adb', '-s', self.ue_serial, 'exec-out', 'su', '-c']
+ popen_args = adb_cmd_pref + list(popen_args)
+ proc = process.run_local_sync(self.run_dir, name, popen_args)
+ else:
+ proc = self.rem_host.RemoteProcess(name, popen_args, env={})
+ proc.launch_sync()
+ return proc
+
+ def verify_metric(self, value, operation='avg', metric='dl_brate', criterion='gt', window=1):
+ self.stop()
+ if self.have_metrics_file:
+ metrics = srsUEMetrics(self.metrics_file)
+ return metrics.verify(value, operation, metric, criterion, window)
+ else:
+ raise log.Error("Metrics file not available")
+
+ def netns(self):
+ return None # no netns needed
+
+ def set_airplane_mode(self, apm_state):
+ self.log("Setting airplane mode: " + str(apm_state))
+ popen_args = ['settings', 'put', 'global', 'airplane_mode_on', str(int(apm_state)),
+ '&&', 'su', '-c', '\"', 'am', 'broadcast', '-a', 'android.intent.action.AIRPLANE_MODE', '\"']
+ self.run_netns_wait("set-airplane-mode", popen_args)
+
+ def get_carrier_id(self, carrier_name):
+ qry_carrier_cmd = "content query --uri \"content://telephony/carriers\" "
+
+ proc = self.run_netns_wait("set-apn", [qry_carrier_cmd])
+ available_carriers = proc.get_stdout().split("\n")
+ carr_id = -1
+ for carr in available_carriers:
+ if 'name=' + carrier_name in carr: # found carrier
+ carr_id = re.findall(r'_id=(\S+),', carr)[0]
+ break
+
+ return carr_id
+
+ def set_new_carrier(self, apn_parameter, carr_id):
+ # check if carrier was found, delete it if exists
+ if carr_id != -1:
+ self.delete_apn(apn_parameter["carrier"])
+
+ # build command to add/update carrier
+ set_carrier_cmd = "content insert --uri content://telephony/carriers" \
+ + " --bind name:s:\"" + apn_parameter["carrier"] + "\"" \
+ + " --bind numeric:s:\"" + apn_parameter["mcc"] + apn_parameter["mnc"] + "\"" \
+ + " --bind mcc:s:\"" + apn_parameter["mcc"] + "\"" \
+ + " --bind mnc:s:\"" + apn_parameter["mnc"] + "\""\
+ + " --bind apn:s:\"" + apn_parameter["apn"] + "\"" \
+ + " --bind user:s:\"" + apn_parameter["user"] + "\"" \
+ + " --bind password:s:\"" + apn_parameter["password"] + "\"" \
+ + " --bind mmsc:s:\"" + apn_parameter["mmsc"] + "\"" \
+ + " --bind mmsport:s:\"" + apn_parameter["mmsport"] + "\"" \
+ + " --bind mmsproxy:s:\"" + apn_parameter["mmsproxy"] + "\"" \
+ + " --bind authtype:s:\"" + apn_parameter["auth"] + "\"" \
+ + " --bind type:s:\"" + apn_parameter["type"] + "\"" \
+ + " --bind protocol:s:\"" + apn_parameter["protocol"] + "\"" \
+ + " --bind mvno_type:s:\"" + apn_parameter["mvnotype"] + "\"" \
+ + " --bind mvno_match_data:s:\"" + apn_parameter["mvnoval"] + "\"" \
+ + " --bind sub_id:s:\"" + apn_parameter["groupid"] + "\""
+
+ self.run_netns_wait("set-apn", [set_carrier_cmd])
+
+ # return carrier ID
+ return self.get_carrier_id(apn_parameter["carrier"])
+
+ def set_preferred_apn(self, carr_id):
+ if carr_id != -1:
+ set_apn_cmd = "content insert --uri content://telephony/carriers/preferapn --bind apn_id:s:\"" + str(carr_id) + "\""
+ self.run_netns_wait("set-apn", [set_apn_cmd])
+
+ def set_apn(self, apn_param, sel_apn):
+ # search for carrier in APN database
+ carrier_id = self.get_carrier_id(apn_param["carrier"])
+
+ # add/update carrier
+ carrier_id = self.set_new_carrier(apn_param, carrier_id)
+
+ # select as preferred APN
+ if sel_apn:
+ self.set_preferred_apn(carrier_id)
+
+ def select_apn(self, carr_name):
+ # search for carrier_id
+ carr_id = self.get_carrier_id(carr_name)
+ if carr_id == 0:
+ return False
+
+ # select carrier by id
+ sel_apn_cmd = "content update --uri content://telephony/carriers/preferapn --bind apn_id:s:\"" + str(carr_id) + "\""
+ self.run_netns_wait("set-apn", [sel_apn_cmd])
+ return True
+
+ def delete_apn(self, carr_name):
+ set_apn_cmd = "content delete --uri content://telephony/carriers --where \'name=\"" + str(carr_name) + "\" \'"
+ self.run_netns_wait("set-apn", [set_apn_cmd])
+
+ def is_emm_connected(self):
+ time.sleep(2)
+ proc = self.run_netns_wait("emm-conn-chk", ['getprop', '\"gsm.network.type\"'])
+ return 'LTE' in proc.get_stdout()
+
+ def save_metrics(self, brate_rx_l, brate_tx_l):
+ if len(brate_rx_l) < 2 or len(brate_tx_l) < 2:
+ raise log.Error("Insufficient data available to write metrics file")
+
+ # cut of elements if lists don't have the same length
+ if len(brate_rx_l) > len(brate_tx_l):
+ brate_rx_l = brate_rx_l[:len(brate_tx_l) - len(brate_rx_l)]
+
+ if len(brate_rx_l) < len(brate_tx_l):
+ brate_tx_l = brate_tx_l[:len(brate_rx_l) - len(brate_tx_l)]
+
+ # get start value
+ brate_rx_last = int(brate_rx_l[0])
+ brate_tx_last = int(brate_tx_l[0])
+
+ with open(self.metrics_file, "w") as ue_metrics_fh:
+ ue_metrics_fh.write("time;cc;earfcn;pci;rsrp;pl;cfo;pci_neigh;rsrp_neigh;cfo_neigh;"
+ + "dl_mcs;dl_snr;dl_turbo;dl_brate;dl_bler;"
+ + "ul_ta;ul_mcs;ul_buff;ul_brate;ul_bler;rf_o;rf_u;rf_l;"
+ + "is_attached\n")
+ for i in range(1, len(brate_rx_l)):
+ time = "0"
+ cc = "0"
+ earfcn = "0"
+ pci = "0"
+ rsrp = "0"
+ pl = "0"
+ cfo = "0"
+ pci_neigh = "0"
+ rsrp_neigh = "0"
+ cfo_neigh = "0"
+ dl_mcs = "0"
+ dl_snr = "0"
+ dl_turbo = "0"
+ dl_brate = str((int(brate_rx_l[i]) - brate_rx_last) * 8)
+ brate_rx_last = int(brate_rx_l[i])
+ dl_bler = "0"
+ ul_ta = "0"
+ ul_mcs = "0"
+ ul_buff = "0"
+ ul_brate = str((int(brate_tx_l[i]) - brate_tx_last) * 8)
+ brate_tx_last = int(brate_tx_l[i])
+ ul_bler = "0"
+ rf_o = "0"
+ rf_u = "0"
+ rf_l = "0"
+ is_attached = "0"
+
+ line = time + ";" + cc + ";" + earfcn + ";" + pci + ";" + rsrp + ";" + pl + ";" + cfo + ";" \
+ + pci_neigh + ";" + rsrp_neigh + ";" + cfo_neigh + ";" + dl_mcs + ";" + dl_snr + ";" \
+ + dl_turbo + ";" + dl_brate + ";" + dl_bler + ";" + ul_ta + ";" + ul_mcs + ";" + ul_buff + ";" \
+ + ul_brate + ";" + ul_bler + ";" + rf_o + ";" + rf_u + ";" + rf_l + ";" + is_attached
+ ue_metrics_fh.write(line + "\n")
+
+ self.have_metrics_file = True
diff --git a/src/osmo_gsm_tester/obj/run_node.py b/src/osmo_gsm_tester/obj/run_node.py
index 6a030ac..c907944 100644
--- a/src/osmo_gsm_tester/obj/run_node.py
+++ b/src/osmo_gsm_tester/obj/run_node.py
@@ -30,13 +30,14 @@
T_LOCAL = 'local'
T_REM_SSH = 'ssh'
- def __init__(self, type=None, run_addr=None, ssh_user=None, ssh_addr=None, run_label=None):
+ def __init__(self, type=None, run_addr=None, ssh_user=None, ssh_addr=None, run_label=None, remote_port=None):
super().__init__(log.C_RUN, 'runnode')
self._type = type
self._run_addr = run_addr
self._ssh_user = ssh_user
self._ssh_addr = ssh_addr
self._run_label = run_label
+ self._remote_port = remote_port
if not self._type:
raise log.Error('run_type not set')
if not self._run_addr:
@@ -55,7 +56,7 @@
def from_conf(cls, conf):
return cls(conf.get('run_type', None), conf.get('run_addr', None),
conf.get('ssh_user', None), conf.get('ssh_addr', None),
- conf.get('run_label', None))
+ conf.get('run_label', None), conf.get('remote_port', None))
@classmethod
def schema(cls):
@@ -65,6 +66,7 @@
'ssh_user': schema.STR,
'ssh_addr': schema.IPV4,
'run_label': schema.STR,
+ 'remote_port': schema.STR,
}
return resource_schema
@@ -89,4 +91,7 @@
def run_label(self):
return self._run_label
+ def ssh_port(self):
+ return self._remote_port
+
# vim: expandtab tabstop=4 shiftwidth=4
diff --git a/sysmocom/default-suites.conf b/sysmocom/default-suites.conf
index b32d7b1..4c196b4 100644
--- a/sysmocom/default-suites.conf
+++ b/sysmocom/default-suites.conf
@@ -172,3 +172,4 @@
- encryption
- 4g:srsenb-rftype at zmq+srsue-rftype@zmq
+- 4g:androidue at mi5g+srsenb-rftype@uhd+mod-enb-nprb at 25+mod-enb-txmode@1
diff --git a/sysmocom/scenarios/androidue at .conf b/sysmocom/scenarios/androidue at .conf
new file mode 100644
index 0000000..a129c0e
--- /dev/null
+++ b/sysmocom/scenarios/androidue at .conf
@@ -0,0 +1,3 @@
+resources:
+ modem:
+ - label: ${param1}
diff --git a/sysmocom/suites/4g/iperf3_dl.py b/sysmocom/suites/4g/iperf3_dl.py
index bf5b1f0..ed137bd 100755
--- a/sysmocom/suites/4g/iperf3_dl.py
+++ b/sysmocom/suites/4g/iperf3_dl.py
@@ -23,7 +23,7 @@
max_rate = enb.ue_max_rate(downlink=True, num_carriers=ue.num_carriers)
iperf3srv.start()
-proc = iperf3cli.prepare_test_proc(iperf3cli.DIR_DL, ue.netns(), bitrate=max_rate)
+proc = iperf3cli.prepare_test_proc(iperf3cli.DIR_DL, ue.netns(), bitrate=max_rate, ue=ue)
print('waiting for UE to attach...')
wait(ue.is_registered)
diff --git a/sysmocom/suites/4g/iperf3_ul.py b/sysmocom/suites/4g/iperf3_ul.py
index 6c0d25d..6cc9f21 100755
--- a/sysmocom/suites/4g/iperf3_ul.py
+++ b/sysmocom/suites/4g/iperf3_ul.py
@@ -23,7 +23,7 @@
max_rate = enb.ue_max_rate(downlink=False, num_carriers=ue.num_carriers)
iperf3srv.start()
-proc = iperf3cli.prepare_test_proc(iperf3cli.DIR_UL, ue.netns(), bitrate=max_rate)
+proc = iperf3cli.prepare_test_proc(iperf3cli.DIR_UL, ue.netns(), bitrate=max_rate, ue=ue)
print('waiting for UE to attach...')
wait(ue.is_registered)
diff --git a/utils/bin/osmo-gsm-tester_androidue_conn_chk.sh b/utils/bin/osmo-gsm-tester_androidue_conn_chk.sh
new file mode 100644
index 0000000..8e126cd
--- /dev/null
+++ b/utils/bin/osmo-gsm-tester_androidue_conn_chk.sh
@@ -0,0 +1,9 @@
+# osmo-gsm-tester_androidue_conn_chk.sh $serial
+while true; do
+ sudo adb -s "$1" shell getprop "gsm.network.type";
+ sleep 1;
+done
+
+
+
+
diff --git a/utils/bin/osmo-gsm-tester_androidue_diag_parser.sh b/utils/bin/osmo-gsm-tester_androidue_diag_parser.sh
new file mode 100644
index 0000000..00a2f81
--- /dev/null
+++ b/utils/bin/osmo-gsm-tester_androidue_diag_parser.sh
@@ -0,0 +1,10 @@
+# format ./osmo-gsm-tester_androidue_diag_parser.sh $serial $run_dir $pcap_path
+while true; do
+ echo "Pulling new qmdl file...";
+ sudo adb -s "$1" pull /data/local/tmp/diag_logs "$2" > /dev/null;
+ wait $!;
+ QMDL_FN=$(find "$2" -maxdepth 2 -type f -name "*.qmdl");
+ wait $!;
+ sudo scat -t qc --event -d "$QMDL_FN" -F "$3";
+ wait $!;
+done
\ No newline at end of file
--
To view, visit https://gerrit.osmocom.org/c/osmo-gsm-tester/+/21217
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-gsm-tester
Gerrit-Branch: master
Gerrit-Change-Id: Iab37a0de59d6643d21bced34ddca06ff40fa62df
Gerrit-Change-Number: 21217
Gerrit-PatchSet: 1
Gerrit-Owner: srs_andre <andre at softwareradiosystems.com>
Gerrit-Reviewer: Nils <nils.fuerste at softwareradiosystems.com>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20201117/295edab8/attachment.htm>