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>