<p>Pau Espin Pedrol <strong>merged</strong> this change.</p><p><a href="https://gerrit.osmocom.org/10195">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Jenkins Builder: Verified
  Harald Welte: Looks good to me, approved

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">nanobts: Support multiTRX<br><br>num_trx is left for now by default to 1, but it has been tested to work<br>properly (current tests pass and both trx are configured) with<br>num_trx=2.<br><br>Change-Id: Ib3962f824a804e2aa582601475a8514c6cb0d8e7<br>---<br>M example/defaults.conf<br>M example/resources.conf.prod<br>M example/resources.conf.rnd<br>M src/osmo_gsm_tester/bts_nanobts.py<br>M src/osmo_gsm_tester/resource.py<br>5 files changed, 104 insertions(+), 71 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/example/defaults.conf b/example/defaults.conf</span><br><span>index 1e84200..f7bd1b1 100644</span><br><span>--- a/example/defaults.conf</span><br><span>+++ b/example/defaults.conf</span><br><span>@@ -58,3 +58,6 @@</span><br><span> </span><br><span> osmo_bts_octphy:</span><br><span>   max_trx: 2</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+nanobts:</span><br><span style="color: hsl(120, 100%, 40%);">+  max_trx: 2</span><br><span>diff --git a/example/resources.conf.prod b/example/resources.conf.prod</span><br><span>index 6481254..6023fc4 100644</span><br><span>--- a/example/resources.conf.prod</span><br><span>+++ b/example/resources.conf.prod</span><br><span>@@ -47,22 +47,30 @@</span><br><span> - label: NanoBTS-ONW-1900</span><br><span>   type: nanobts</span><br><span>   ipa_unit_id: 9</span><br><span style="color: hsl(0, 100%, 40%);">-  addr: 10.42.42.120</span><br><span>   band: GSM-1900</span><br><span style="color: hsl(0, 100%, 40%);">-  power_supply:</span><br><span style="color: hsl(0, 100%, 40%);">-    type: 'sispm'</span><br><span style="color: hsl(0, 100%, 40%);">-    device: '01:01:4d:98:24'</span><br><span style="color: hsl(0, 100%, 40%);">-    port: '1'</span><br><span style="color: hsl(120, 100%, 40%);">+  trx_list:</span><br><span style="color: hsl(120, 100%, 40%);">+    - addr: 10.42.42.120</span><br><span style="color: hsl(120, 100%, 40%);">+      power_supply:</span><br><span style="color: hsl(120, 100%, 40%);">+        type: 'sispm'</span><br><span style="color: hsl(120, 100%, 40%);">+        device: '01:01:4d:98:24'</span><br><span style="color: hsl(120, 100%, 40%);">+        port: '1'</span><br><span> </span><br><span> - label: NanoBTS-ONW-900</span><br><span>   type: nanobts</span><br><span>   ipa_unit_id: 10</span><br><span style="color: hsl(0, 100%, 40%);">-  addr: 10.42.42.121</span><br><span>   band: GSM-900</span><br><span style="color: hsl(0, 100%, 40%);">-  power_supply:</span><br><span style="color: hsl(0, 100%, 40%);">-    type: 'sispm'</span><br><span style="color: hsl(0, 100%, 40%);">-    device: '01:01:4d:98:24'</span><br><span style="color: hsl(0, 100%, 40%);">-    port: '2'</span><br><span style="color: hsl(120, 100%, 40%);">+  num_trx: 1</span><br><span style="color: hsl(120, 100%, 40%);">+  trx_list:</span><br><span style="color: hsl(120, 100%, 40%);">+    - addr: 10.42.42.121</span><br><span style="color: hsl(120, 100%, 40%);">+      power_supply:</span><br><span style="color: hsl(120, 100%, 40%);">+        type: 'sispm'</span><br><span style="color: hsl(120, 100%, 40%);">+        device: '01:01:4d:98:24'</span><br><span style="color: hsl(120, 100%, 40%);">+        port: '2'</span><br><span style="color: hsl(120, 100%, 40%);">+    - addr: 10.42.42.122</span><br><span style="color: hsl(120, 100%, 40%);">+      power_supply:</span><br><span style="color: hsl(120, 100%, 40%);">+        type: 'sispm'</span><br><span style="color: hsl(120, 100%, 40%);">+        device: '01:01:4d:98:24'</span><br><span style="color: hsl(120, 100%, 40%);">+        port: '3'</span><br><span> </span><br><span> arfcn:</span><br><span>   - arfcn: 512</span><br><span>diff --git a/example/resources.conf.rnd b/example/resources.conf.rnd</span><br><span>index 05fce87..4e5c173 100644</span><br><span>--- a/example/resources.conf.rnd</span><br><span>+++ b/example/resources.conf.rnd</span><br><span>@@ -30,12 +30,13 @@</span><br><span> - label: NanoBTS-ONW-1900</span><br><span>   type: nanobts</span><br><span>   ipa_unit_id: 9</span><br><span style="color: hsl(0, 100%, 40%);">-  addr: 10.42.42.120</span><br><span>   band: GSM-1900</span><br><span style="color: hsl(0, 100%, 40%);">-  power_supply:</span><br><span style="color: hsl(0, 100%, 40%);">-    type: 'sispm'</span><br><span style="color: hsl(0, 100%, 40%);">-    device: '01:01:55:2e:b6'</span><br><span style="color: hsl(0, 100%, 40%);">-    port: '1'</span><br><span style="color: hsl(120, 100%, 40%);">+  trx_list:</span><br><span style="color: hsl(120, 100%, 40%);">+    - addr: 10.42.42.120</span><br><span style="color: hsl(120, 100%, 40%);">+      power_supply:</span><br><span style="color: hsl(120, 100%, 40%);">+        type: 'sispm'</span><br><span style="color: hsl(120, 100%, 40%);">+        device: '01:01:55:2e:b6'</span><br><span style="color: hsl(120, 100%, 40%);">+        port: '1'</span><br><span> </span><br><span> arfcn:</span><br><span>   - arfcn: 512</span><br><span>diff --git a/src/osmo_gsm_tester/bts_nanobts.py b/src/osmo_gsm_tester/bts_nanobts.py</span><br><span>index 29a8ac5..7f0151f 100644</span><br><span>--- a/src/osmo_gsm_tester/bts_nanobts.py</span><br><span>+++ b/src/osmo_gsm_tester/bts_nanobts.py</span><br><span>@@ -28,28 +28,37 @@</span><br><span> </span><br><span> class NanoBts(bts.Bts):</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    pwsup = None</span><br><span style="color: hsl(120, 100%, 40%);">+    pwsup_list = []</span><br><span>     _pcu = None</span><br><span> ##############</span><br><span> # PROTECTED</span><br><span> ##############</span><br><span>     def __init__(self, suite_run, conf):</span><br><span style="color: hsl(0, 100%, 40%);">-        if conf.get('addr') is None:</span><br><span style="color: hsl(0, 100%, 40%);">-            raise log.Error('No attribute addr provided in conf!')</span><br><span style="color: hsl(0, 100%, 40%);">-        super().__init__(suite_run, conf, 'nanobts_%s' % conf.get('addr'), 'nanobts')</span><br><span style="color: hsl(120, 100%, 40%);">+        super().__init__(suite_run, conf, 'nanobts_%s' % conf.get('label', 'nolabel'), 'nanobts')</span><br><span> </span><br><span>     def _configure(self):</span><br><span>         if self.bsc is None:</span><br><span>             raise log.Error('BTS needs to be added to a BSC or NITB before it can be configured')</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        pwsup_opt = self.conf.get('power_supply', {})</span><br><span style="color: hsl(0, 100%, 40%);">-        if not pwsup_opt:</span><br><span style="color: hsl(0, 100%, 40%);">-            raise log.Error('No power_supply attribute provided in conf!')</span><br><span style="color: hsl(0, 100%, 40%);">-        pwsup_type = pwsup_opt.get('type')</span><br><span style="color: hsl(0, 100%, 40%);">-        if not pwsup_type:</span><br><span style="color: hsl(0, 100%, 40%);">-            raise log.Error('No type attribute provided in power_supply conf!')</span><br><span style="color: hsl(120, 100%, 40%);">+        for trx_i in range(self.num_trx()):</span><br><span style="color: hsl(120, 100%, 40%);">+            pwsup_opt = self.conf.get('trx_list')[trx_i].get('power_supply', {})</span><br><span style="color: hsl(120, 100%, 40%);">+            if not pwsup_opt:</span><br><span style="color: hsl(120, 100%, 40%);">+                raise log.Error('No power_supply attribute provided in conf for TRX %d!' % trx_i)</span><br><span style="color: hsl(120, 100%, 40%);">+            pwsup_type = pwsup_opt.get('type')</span><br><span style="color: hsl(120, 100%, 40%);">+            if not pwsup_type:</span><br><span style="color: hsl(120, 100%, 40%);">+                raise log.Error('No type attribute provided in power_supply conf for TRX %d!' % trx_i)</span><br><span style="color: hsl(120, 100%, 40%);">+            self.pwsup_list.append(powersupply.get_instance_by_type(pwsup_type, pwsup_opt))</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        self.pwsup = powersupply.get_instance_by_type(pwsup_type, pwsup_opt)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def get_pcap_filter_all_trx_ip(self):</span><br><span style="color: hsl(120, 100%, 40%);">+        ret = "("</span><br><span style="color: hsl(120, 100%, 40%);">+        for trx_i in range(self.num_trx()):</span><br><span style="color: hsl(120, 100%, 40%);">+            if trx_i != 0:</span><br><span style="color: hsl(120, 100%, 40%);">+                ret = ret + " or "</span><br><span style="color: hsl(120, 100%, 40%);">+            bts_trx_ip = self.conf.get('trx_list')[trx_i].get('addr')</span><br><span style="color: hsl(120, 100%, 40%);">+            ret = ret + "host " + bts_trx_ip</span><br><span style="color: hsl(120, 100%, 40%);">+        ret = ret + ")"</span><br><span style="color: hsl(120, 100%, 40%);">+        return ret</span><br><span> </span><br><span> ########################</span><br><span> # PUBLIC - INTERNAL API</span><br><span>@@ -61,9 +70,11 @@</span><br><span>         band = values.get('band')</span><br><span>         trx_list = values.get('trx_list')</span><br><span>         if band == 'GSM-1900':</span><br><span style="color: hsl(0, 100%, 40%);">-            config.overlay(trx_list[0], { 'arfcn' : '531' })</span><br><span style="color: hsl(120, 100%, 40%);">+            for trx_i in range(len(trx_list)):</span><br><span style="color: hsl(120, 100%, 40%);">+                config.overlay(trx_list[trx_i], { 'arfcn' : str(531 + trx_i * 2) })</span><br><span>         elif band == 'GSM-900':</span><br><span style="color: hsl(0, 100%, 40%);">-            config.overlay(trx_list[0], { 'arfcn' : '50' })</span><br><span style="color: hsl(120, 100%, 40%);">+            for trx_i in range(len(trx_list)):</span><br><span style="color: hsl(120, 100%, 40%);">+                config.overlay(trx_list[trx_i], { 'arfcn' : str(50 + trx_i * 2) })</span><br><span> </span><br><span>         config.overlay(values, { 'osmobsc_bts_type': 'nanobts' })</span><br><span> </span><br><span>@@ -72,9 +83,10 @@</span><br><span> </span><br><span> </span><br><span>     def cleanup(self):</span><br><span style="color: hsl(0, 100%, 40%);">-        if self.pwsup:</span><br><span style="color: hsl(0, 100%, 40%);">-            self.dbg('Powering off NanoBTS')</span><br><span style="color: hsl(0, 100%, 40%);">-            self.pwsup.power_set(False)</span><br><span style="color: hsl(120, 100%, 40%);">+        for pwsup in self.pwsup_list:</span><br><span style="color: hsl(120, 100%, 40%);">+            self.dbg('Powering off NanoBTS TRX')</span><br><span style="color: hsl(120, 100%, 40%);">+            pwsup.power_set(False)</span><br><span style="color: hsl(120, 100%, 40%);">+        self.pwsup_list = []</span><br><span> </span><br><span> ###################</span><br><span> # PUBLIC (test API included)</span><br><span>@@ -87,44 +99,50 @@</span><br><span>         self._configure()</span><br><span> </span><br><span>         unitid = int(self.conf.get('ipa_unit_id'))</span><br><span style="color: hsl(0, 100%, 40%);">-        bts_ip = self.remote_addr()</span><br><span style="color: hsl(0, 100%, 40%);">-        # This fine for now, however concurrent tests using Nanobts may run into "address already in use" since dst is broadcast.</span><br><span style="color: hsl(0, 100%, 40%);">-        # Once concurrency is needed, a new config attr should be added to have an extra static IP assigned on the main-unit to each Nanobts resource.</span><br><span style="color: hsl(0, 100%, 40%);">-        local_bind_ip =util.dst_ip_get_local_bind(bts_ip)</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        # Make sure nanoBTS is powered and in a clean state:</span><br><span style="color: hsl(0, 100%, 40%);">-        self.pwsup.power_cycle(1.0)</span><br><span style="color: hsl(120, 100%, 40%);">+        # Make sure all nanoBTS TRX are powered and in a clean state:</span><br><span style="color: hsl(120, 100%, 40%);">+        for pwsup in self.pwsup_list:</span><br><span style="color: hsl(120, 100%, 40%);">+            self.dbg('Powering cycling NanoBTS TRX')</span><br><span style="color: hsl(120, 100%, 40%);">+            pwsup.power_cycle(1.0)</span><br><span> </span><br><span>         pcap_recorder.PcapRecorder(self.suite_run, self.run_dir.new_dir('pcap'), None,</span><br><span style="color: hsl(0, 100%, 40%);">-                                   'host %s and port not 22' % self.remote_addr())</span><br><span style="color: hsl(120, 100%, 40%);">+                                   '%s and port not 22' % self.get_pcap_filter_all_trx_ip())</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        self.log('Finding nanobts %s, binding on %s...' % (bts_ip, local_bind_ip))</span><br><span style="color: hsl(0, 100%, 40%);">-        ipfind = AbisIpFind(self.suite_run, self.run_dir, local_bind_ip, 'preconf')</span><br><span style="color: hsl(0, 100%, 40%);">-        ipfind.start()</span><br><span style="color: hsl(0, 100%, 40%);">-        ipfind.wait_bts_ready(bts_ip)</span><br><span style="color: hsl(0, 100%, 40%);">-        running_unitid = ipfind.get_unitid_by_ip(bts_ip)</span><br><span style="color: hsl(0, 100%, 40%);">-        self.log('Found nanobts %s with unit_id %d' % (bts_ip, running_unitid))</span><br><span style="color: hsl(0, 100%, 40%);">-        ipfind.stop()</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        ipconfig = IpAccessConfig(self.suite_run, self.run_dir, bts_ip)</span><br><span style="color: hsl(0, 100%, 40%);">-        if running_unitid != unitid:</span><br><span style="color: hsl(0, 100%, 40%);">-            if not ipconfig.set_unit_id(unitid, False):</span><br><span style="color: hsl(0, 100%, 40%);">-                raise log.Error('Failed configuring unit id %d' % unitid)</span><br><span style="color: hsl(0, 100%, 40%);">-        # Apply OML IP and restart nanoBTS as it is required to apply the changes.</span><br><span style="color: hsl(0, 100%, 40%);">-        if not ipconfig.set_oml_ip(self.bsc.addr(), True):</span><br><span style="color: hsl(0, 100%, 40%);">-            raise log.Error('Failed configuring OML IP %s' % bts_ip)</span><br><span style="color: hsl(120, 100%, 40%);">+        # TODO: If setting N TRX, we should set up them in parallel instead of waiting for each one.</span><br><span style="color: hsl(120, 100%, 40%);">+        for trx_i in range(self.num_trx()):</span><br><span style="color: hsl(120, 100%, 40%);">+            bts_trx_ip = self.conf.get('trx_list')[trx_i].get('addr')</span><br><span style="color: hsl(120, 100%, 40%);">+            # This fine for now, however concurrent tests using Nanobts may run into "address already in use" since dst is broadcast.</span><br><span style="color: hsl(120, 100%, 40%);">+            # Once concurrency is needed, a new config attr should be added to have an extra static IP assigned on the main-unit to each Nanobts resource.</span><br><span style="color: hsl(120, 100%, 40%);">+            local_bind_ip = util.dst_ip_get_local_bind(bts_trx_ip)</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        # Let some time for BTS to restart. It takes much more than 20 secs, and</span><br><span style="color: hsl(0, 100%, 40%);">-        # this way we make sure we don't catch responses in abisip-find prior to</span><br><span style="color: hsl(0, 100%, 40%);">-        # BTS restarting.</span><br><span style="color: hsl(0, 100%, 40%);">-        MainLoop.sleep(self, 20)</span><br><span style="color: hsl(120, 100%, 40%);">+            self.log('Finding nanobts %s, binding on %s...' % (bts_trx_ip, local_bind_ip))</span><br><span style="color: hsl(120, 100%, 40%);">+            ipfind = AbisIpFind(self.suite_run, self.run_dir, local_bind_ip, 'preconf')</span><br><span style="color: hsl(120, 100%, 40%);">+            ipfind.start()</span><br><span style="color: hsl(120, 100%, 40%);">+            ipfind.wait_bts_ready(bts_trx_ip)</span><br><span style="color: hsl(120, 100%, 40%);">+            running_unitid, running_trx = ipfind.get_unitid_by_ip(bts_trx_ip)</span><br><span style="color: hsl(120, 100%, 40%);">+            self.log('Found nanobts %s with unit_id %d trx %d' % (bts_trx_ip, running_unitid, running_trx))</span><br><span style="color: hsl(120, 100%, 40%);">+            ipfind.stop()</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        self.log('Starting to connect to', self.bsc)</span><br><span style="color: hsl(0, 100%, 40%);">-        ipfind = AbisIpFind(self.suite_run, self.run_dir, local_bind_ip, 'postconf')</span><br><span style="color: hsl(0, 100%, 40%);">-        ipfind.start()</span><br><span style="color: hsl(0, 100%, 40%);">-        ipfind.wait_bts_ready(bts_ip)</span><br><span style="color: hsl(0, 100%, 40%);">-        self.log('nanoBTS configured and running')</span><br><span style="color: hsl(0, 100%, 40%);">-        ipfind.stop()</span><br><span style="color: hsl(120, 100%, 40%);">+            ipconfig = IpAccessConfig(self.suite_run, self.run_dir, bts_trx_ip)</span><br><span style="color: hsl(120, 100%, 40%);">+            if running_unitid != unitid or running_trx != trx_i:</span><br><span style="color: hsl(120, 100%, 40%);">+                if not ipconfig.set_unit_id(unitid, trx_i, False):</span><br><span style="color: hsl(120, 100%, 40%);">+                    raise log.Error('Failed configuring unit id %d trx %d' % (unitid, trx_i))</span><br><span style="color: hsl(120, 100%, 40%);">+            # Apply OML IP and restart nanoBTS as it is required to apply the changes.</span><br><span style="color: hsl(120, 100%, 40%);">+            if not ipconfig.set_oml_ip(self.bsc.addr(), True):</span><br><span style="color: hsl(120, 100%, 40%);">+                raise log.Error('Failed configuring OML IP %s' % bts_trx_ip)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            # Let some time for BTS to restart. It takes much more than 20 secs, and</span><br><span style="color: hsl(120, 100%, 40%);">+            # this way we make sure we don't catch responses in abisip-find prior to</span><br><span style="color: hsl(120, 100%, 40%);">+            # BTS restarting.</span><br><span style="color: hsl(120, 100%, 40%);">+            MainLoop.sleep(self, 20)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            self.log('Starting to connect id %d trx %d to' % (unitid, trx_i), self.bsc)</span><br><span style="color: hsl(120, 100%, 40%);">+            ipfind = AbisIpFind(self.suite_run, self.run_dir, local_bind_ip, 'postconf')</span><br><span style="color: hsl(120, 100%, 40%);">+            ipfind.start()</span><br><span style="color: hsl(120, 100%, 40%);">+            ipfind.wait_bts_ready(bts_trx_ip)</span><br><span style="color: hsl(120, 100%, 40%);">+            self.log('nanoBTS id %d trx %d configured and running' % (unitid, trx_i))</span><br><span style="color: hsl(120, 100%, 40%);">+            ipfind.stop()</span><br><span> </span><br><span>         MainLoop.wait(self, self.bsc.bts_is_connected, self, timeout=600)</span><br><span>         self.log('nanoBTS connected to BSC')</span><br><span>@@ -161,7 +179,7 @@</span><br><span>     proc = None</span><br><span> </span><br><span>     BIN_ABISIP_FIND = 'abisip-find'</span><br><span style="color: hsl(0, 100%, 40%);">-    BTS_UNIT_ID_RE = re.compile("Unit_ID='(?P<unit_id>\d+)/\d+/\d+'")</span><br><span style="color: hsl(120, 100%, 40%);">+    BTS_UNIT_ID_RE = re.compile("Unit_ID='(?P<unit_id>\d+)/\d+/(?P<trx_id>\d+)'")</span><br><span> </span><br><span>     def __init__(self, suite_run, parent_run_dir, bind_ip, name_suffix):</span><br><span>         super().__init__(log.C_RUN, AbisIpFind.BIN_ABISIP_FIND + '-' + name_suffix)</span><br><span>@@ -207,7 +225,8 @@</span><br><span>             res = AbisIpFind.BTS_UNIT_ID_RE.search(line)</span><br><span>             if res:</span><br><span>                 unit_id = int(res.group('unit_id'))</span><br><span style="color: hsl(0, 100%, 40%);">-                return unit_id</span><br><span style="color: hsl(120, 100%, 40%);">+                trx_id = int(res.group('trx_id'))</span><br><span style="color: hsl(120, 100%, 40%);">+                return (unit_id, trx_id)</span><br><span>             raise log.Error('abisip-find unit_id field for nanobts %s not found in %s' %(ipaddr, line))</span><br><span> </span><br><span>     def bts_ready(self, ipaddr):</span><br><span>@@ -261,13 +280,14 @@</span><br><span>             raise e</span><br><span>         return self.proc.result</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    def set_unit_id(self, unitid, restart=False):</span><br><span style="color: hsl(120, 100%, 40%);">+    def set_unit_id(self, unitid, trx_num, restart=False):</span><br><span style="color: hsl(120, 100%, 40%);">+        uid_str = '%d/0/%d' % (unitid, trx_num)</span><br><span>         if restart:</span><br><span style="color: hsl(0, 100%, 40%);">-            retcode = self.run('unitid', '--restart', '--unit-id', '%d/0/0' % unitid, self.bts_ip)</span><br><span style="color: hsl(120, 100%, 40%);">+            retcode = self.run('unitid', '--restart', '--unit-id', '%s' % uid_str, self.bts_ip)</span><br><span>         else:</span><br><span style="color: hsl(0, 100%, 40%);">-            retcode = self.run('unitid', '--unit-id', '%d/0/0' % unitid, self.bts_ip)</span><br><span style="color: hsl(120, 100%, 40%);">+            retcode = self.run('unitid', '--unit-id', '%s' % uid_str, self.bts_ip)</span><br><span>         if retcode != 0:</span><br><span style="color: hsl(0, 100%, 40%);">-            log.err('ipaccess-config --unit-id %d/0/0 returned error code %d' % (unitid, retcode))</span><br><span style="color: hsl(120, 100%, 40%);">+            log.err('ipaccess-config --unit-id %s returned error code %d' % (uid_str, retcode))</span><br><span>         return retcode == 0</span><br><span> </span><br><span>     def set_oml_ip(self, omlip, restart=False):</span><br><span>diff --git a/src/osmo_gsm_tester/resource.py b/src/osmo_gsm_tester/resource.py</span><br><span>index 28c4117..dca8090 100644</span><br><span>--- a/src/osmo_gsm_tester/resource.py</span><br><span>+++ b/src/osmo_gsm_tester/resource.py</span><br><span>@@ -57,17 +57,18 @@</span><br><span>         'bts[].trx_remote_ip': schema.IPV4,</span><br><span>         'bts[].launch_trx': schema.BOOL_STR,</span><br><span>         'bts[].direct_pcu': schema.BOOL_STR,</span><br><span style="color: hsl(0, 100%, 40%);">-        'bts[].power_supply.type': schema.STR,</span><br><span style="color: hsl(0, 100%, 40%);">-        'bts[].power_supply.device': schema.STR,</span><br><span style="color: hsl(0, 100%, 40%);">-        'bts[].power_supply.port': schema.STR,</span><br><span>         'bts[].ciphers[]': schema.CIPHER,</span><br><span>         'bts[].num_trx': schema.UINT,</span><br><span>         'bts[].max_trx': schema.UINT,</span><br><span style="color: hsl(120, 100%, 40%);">+        'bts[].trx_list[].addr': schema.IPV4,</span><br><span>         'bts[].trx_list[].hw_addr': schema.HWADDR,</span><br><span>         'bts[].trx_list[].net_device': schema.STR,</span><br><span>         'bts[].trx_list[].nominal_power': schema.UINT,</span><br><span>         'bts[].trx_list[].max_power_red': schema.UINT,</span><br><span>         'bts[].trx_list[].timeslot_list[].phys_chan_config': schema.PHY_CHAN,</span><br><span style="color: hsl(120, 100%, 40%);">+        'bts[].trx_list[].power_supply.type': schema.STR,</span><br><span style="color: hsl(120, 100%, 40%);">+        'bts[].trx_list[].power_supply.device': schema.STR,</span><br><span style="color: hsl(120, 100%, 40%);">+        'bts[].trx_list[].power_supply.port': schema.STR,</span><br><span>         'arfcn[].arfcn': schema.INT,</span><br><span>         'arfcn[].band': schema.BAND,</span><br><span>         'modem[].label': schema.STR,</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/10195">change 10195</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/10195"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-gsm-tester </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: merged </div>
<div style="display:none"> Gerrit-Change-Id: Ib3962f824a804e2aa582601475a8514c6cb0d8e7 </div>
<div style="display:none"> Gerrit-Change-Number: 10195 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Pau Espin Pedrol <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Harald Welte <laforge@gnumonks.org> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder </div>
<div style="display:none"> Gerrit-Reviewer: Pau Espin Pedrol <pespin@sysmocom.de> </div>