[PATCH] osmo-gsm-tester[master]: Add support for osmo-bts-octphy

Pau Espin Pedrol gerrit-no-reply at lists.osmocom.org
Thu Oct 26 09:53:09 UTC 2017


Review at  https://gerrit.osmocom.org/4425

Add support for osmo-bts-octphy

Specific parts for this class:
- Runs osmo-bts-octphy binary, that requires CAP_NET_RAW capability
because it uses an AF_PACKET socket.
- As a consequence, it must use the previously added APIs to set the
capability and modify the RPATH of the binary before launching it. These
APIs require extra host setup and installed dependencies that will be
documented soon in osmo-gsm-tester manual.
- A num_trx() helper method is added because the binary requires that
parameter.
- A allocate_phy_instances() is added to help build/fill the conf
dictionary to be used in the tmpl to be able to easily set up trx, phy
and insances.

A config to use a osmo-bts-octphy at full power is used (4 trx) is added
in this commit to show how can it be configured. However our
current license only has support to use 1 TRX, and so next commit drops
most configurations to simplify the setup to use only 1 TRX.

Change-Id: Ia350964fa539083bb68d439cad0caa8fdf85d297
---
M example/defaults.conf
M example/resources.conf
A src/osmo_gsm_tester/bts_octphy.py
M src/osmo_gsm_tester/resource.py
A src/osmo_gsm_tester/templates/osmo-bts-octphy.cfg.tmpl
5 files changed, 273 insertions(+), 1 deletion(-)


  git pull ssh://gerrit.osmocom.org:29418/osmo-gsm-tester refs/changes/25/4425/1

diff --git a/example/defaults.conf b/example/defaults.conf
index e2921a4..7711297 100644
--- a/example/defaults.conf
+++ b/example/defaults.conf
@@ -45,3 +45,43 @@
     - phys_chan_config: TCH/F
     - phys_chan_config: TCH/F
     - phys_chan_config: TCH/F
+
+osmo_bts_octphy:
+  trx_list:
+   - {}
+   - nominal_power: 23
+     max_power_red: 0
+     arfcn: 869
+     timeslot_list:
+     - phys_chan_config: CCCH+SDCCH4
+     - phys_chan_config: SDCCH8
+     - phys_chan_config: TCH/F
+     - phys_chan_config: TCH/F
+     - phys_chan_config: TCH/F
+     - phys_chan_config: TCH/F
+     - phys_chan_config: TCH/F
+     - phys_chan_config: TCH/F
+   - nominal_power: 23
+     max_power_red: 0
+     arfcn: 870
+     timeslot_list:
+     - phys_chan_config: CCCH+SDCCH4
+     - phys_chan_config: SDCCH8
+     - phys_chan_config: TCH/F
+     - phys_chan_config: TCH/F
+     - phys_chan_config: TCH/F
+     - phys_chan_config: TCH/F
+     - phys_chan_config: TCH/F
+     - phys_chan_config: TCH/F
+   - nominal_power: 23
+     max_power_red: 0
+     arfcn: 871
+     timeslot_list:
+     - phys_chan_config: CCCH+SDCCH4
+     - phys_chan_config: SDCCH8
+     - phys_chan_config: TCH/F
+     - phys_chan_config: TCH/F
+     - phys_chan_config: TCH/F
+     - phys_chan_config: TCH/F
+     - phys_chan_config: TCH/F
+     - phys_chan_config: TCH/F
diff --git a/example/resources.conf b/example/resources.conf
index 70c1c35..c611dea 100644
--- a/example/resources.conf
+++ b/example/resources.conf
@@ -31,6 +31,21 @@
   trx_remote_ip: 10.42.42.112
   ciphers: [a5_0, a5_1]
 
+- label: Octphy 3500
+  type: osmo-bts-octphy
+  ipa_unit_id: 8
+  addr: 10.42.42.52
+  band: GSM-1800
+  trx_list:
+  - hw_addr: 00:0c:90:2e:80:1e
+    net_device: eth1
+  - hw_addr: 00:0c:90:2e:80:1e
+    net_device: eth1
+  - hw_addr: 00:0c:90:2e:87:52
+    net_device: eth1
+  - hw_addr: 00:0c:90:2e:87:52
+    net_device: eth1
+
 arfcn:
   - arfcn: 512
     band: GSM-1800
diff --git a/src/osmo_gsm_tester/bts_octphy.py b/src/osmo_gsm_tester/bts_octphy.py
new file mode 100644
index 0000000..5014f40
--- /dev/null
+++ b/src/osmo_gsm_tester/bts_octphy.py
@@ -0,0 +1,168 @@
+# osmo_gsm_tester: specifics for running an osmo-bts-octphy
+#
+# Copyright (C) 2016-2017 by sysmocom - s.f.m.c. GmbH
+#
+# Author: Pau Espin Pedrol <pespin at 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
+import tempfile
+from . import log, config, util, template, process, event_loop
+
+class OsmoBtsOctphy(log.Origin):
+    suite_run = None
+    bsc = None
+    run_dir = None
+    inst = None
+    env = None
+    pcu_sk_tmp_dir = None
+    values = None
+
+    BIN_BTS_OCTPHY = 'osmo-bts-octphy'
+
+    CONF_BTS_OCTPHY = 'osmo-bts-octphy.cfg'
+
+    def __init__(self, suite_run, conf):
+        super().__init__(log.C_RUN, OsmoBtsOctphy.BIN_BTS_OCTPHY)
+        self.suite_run = suite_run
+        self.conf = conf
+        self.env = {}
+        self.values = {}
+        self.pcu_sk_tmp_dir = tempfile.mkdtemp('', 'ogtpcusk')
+        if len(self.pcu_socket_path().encode()) > 107:
+            raise log.Error('Path for pcu socket is longer than max allowed len for unix socket path (107):', self.pcu_socket_path())
+
+    def cleanup(self):
+        if self.pcu_sk_tmp_dir:
+            try:
+                os.remove(self.pcu_socket_path())
+            except OSError:
+                pass
+            os.rmdir(self.pcu_sk_tmp_dir)
+
+    def pcu_socket_path(self):
+        return os.path.join(self.pcu_sk_tmp_dir, 'pcu_bts')
+
+    def remote_addr(self):
+        return self.conf.get('addr')
+
+    def start(self):
+        if self.bsc is None:
+            raise RuntimeError('BTS needs to be added to a BSC or NITB before it can be started')
+        self.suite_run.poll()
+
+        self.log('Starting to connect to', self.bsc)
+        self.run_dir = util.Dir(self.suite_run.get_test_run_dir().new_dir(self.name()))
+        self.configure()
+
+        self.inst = util.Dir(os.path.abspath(self.suite_run.trial.get_inst('osmo-bts')))
+        btsoct_path = self.inst.child('bin', OsmoBtsOctphy.BIN_BTS_OCTPHY)
+        lib = self.inst.child('lib')
+        if not os.path.isdir(lib):
+            raise RuntimeError('No lib/ in %r' % self.inst)
+
+        # setting capabilities will later disable use of LD_LIBRARY_PATH from ELF loader -> modify RPATH instead.
+        self.log('Setting RPATH for', OsmoBtsOctphy.BIN_BTS_OCTPHY)
+        util.change_elf_rpath(btsoct_path, util.prepend_library_path(lib))
+        # osmo-bty-octphy requires CAP_NET_RAW to open AF_PACKET socket:
+        self.log('Applying CAP_NET_RAW capability to', OsmoBtsOctphy.BIN_BTS_OCTPHY)
+        util.setcap_net_raw(btsoct_path)
+
+        self.launch_process(OsmoBtsOctphy.BIN_BTS_OCTPHY, '-r', '1',
+                            '-c', os.path.abspath(self.config_file),
+                            '-i', self.bsc.addr(), '-t', str(self.num_trx()))
+        #self.launch_process(OsmoBtsOctphy.BIN_PCU, '-r', '1')
+        self.suite_run.poll()
+
+    def launch_process(self, binary_name, *args):
+        binary = os.path.abspath(self.inst.child('bin', binary_name))
+        run_dir = self.run_dir.new_dir(binary_name)
+        if not os.path.isfile(binary):
+            raise RuntimeError('Binary missing: %r' % binary)
+        proc = process.Process(binary_name, run_dir,
+                               (binary,) + args,
+                               env=self.env)
+        self.suite_run.remember_to_stop(proc)
+        proc.launch()
+        return proc
+
+    def num_trx(self):
+        return len(self.values['osmo_bts_octphy'].get('trx_list', []))
+
+    def allocate_phy_instances(self, c):
+        '''
+        Generate match trx Z <-> phy X inst Y to use in vty config
+
+        We create a new phy for each trx found with a new hwaddr. If hwaddr is
+        already there, increase num_instances and give last instance index to
+        the current trx.
+        '''
+        phy_list = []
+        for trx in c.get('trx_list', []):
+            hwaddr = trx.get('hw_addr', None)
+            netdev = trx.get('net_device', None)
+            if hwaddr is None:
+                raise log.Error('Expected hw-addr value not found!')
+            found = False
+            phy_idx = 0
+            for phy in phy_list:
+                if phy['hw_addr'] == hwaddr:
+                    phy['num_instances'] += 1
+                    found = True
+                    break
+                phy_idx += 1
+            if not found:
+                phy_list.append({'hw_addr': hwaddr, 'net_device': netdev, 'num_instances': 1})
+            trx['phy_idx'] = phy_idx
+            trx['instance_idx'] = phy_list[phy_idx]['num_instances'] - 1
+        c['phy_list'] = phy_list
+
+    def configure(self):
+        if self.bsc is None:
+            raise RuntimeError('BTS needs to be added to a BSC or NITB before it can be configured')
+        self.config_file = self.run_dir.new_file(OsmoBtsOctphy.CONF_BTS_OCTPHY)
+        self.dbg(config_file=self.config_file)
+
+        values = dict(osmo_bts_octphy=config.get_defaults('osmo_bts_octphy'))
+        config.overlay(values, self.suite_run.config())
+        config.overlay(values, {
+                        'osmo_bts_octphy': {
+                            'oml_remote_ip': self.bsc.addr(),
+                            'pcu_socket_path': self.pcu_socket_path(),
+                        }
+        })
+        config.overlay(values, { 'osmo_bts_octphy': self.conf })
+
+        self.allocate_phy_instances(values['osmo_bts_octphy'])
+
+        self.dbg('OSMO-BTS-OCTPHY CONFIG:\n' + pprint.pformat(values))
+        self.values = values
+        with open(self.config_file, 'w') as f:
+            r = template.render(OsmoBtsOctphy.CONF_BTS_OCTPHY, values)
+            self.dbg(r)
+            f.write(r)
+
+    def conf_for_bsc(self):
+        values = config.get_defaults('bsc_bts')
+        config.overlay(values, config.get_defaults('osmo_bts_octphy'))
+        config.overlay(values, self.conf)
+        self.dbg(conf=values)
+        return values
+
+    def set_bsc(self, bsc):
+        self.bsc = bsc
+
+# vim: expandtab tabstop=4 shiftwidth=4
diff --git a/src/osmo_gsm_tester/resource.py b/src/osmo_gsm_tester/resource.py
index 7e55129..25bb00f 100644
--- a/src/osmo_gsm_tester/resource.py
+++ b/src/osmo_gsm_tester/resource.py
@@ -29,7 +29,7 @@
 from . import schema
 from . import ofono_client
 from . import osmo_nitb
-from . import bts_sysmo, bts_osmotrx
+from . import bts_sysmo, bts_osmotrx, bts_octphy
 
 from .util import is_dict, is_list
 
@@ -83,6 +83,7 @@
 KNOWN_BTS_TYPES = {
         'osmo-bts-sysmo': bts_sysmo.SysmoBts,
         'osmo-bts-trx': bts_osmotrx.OsmoBtsTrx,
+        'osmo-bts-octphy': bts_octphy.OsmoBtsOctphy,
     }
 
 def register_bts_type(name, clazz):
diff --git a/src/osmo_gsm_tester/templates/osmo-bts-octphy.cfg.tmpl b/src/osmo_gsm_tester/templates/osmo-bts-octphy.cfg.tmpl
new file mode 100644
index 0000000..13cdb1d
--- /dev/null
+++ b/src/osmo_gsm_tester/templates/osmo-bts-octphy.cfg.tmpl
@@ -0,0 +1,48 @@
+! Configuration rendered by osmo-gsm-tester
+log stderr
+  logging color 1
+  logging print extended-timestamp 1
+  logging print category 1
+  logging level abis debug
+  logging level oml debug
+  logging level pag debug
+  logging level rll debug
+  logging level rr debug
+  logging level rsl debug
+!
+
+%for phy in osmo_bts_octphy.phy_list:
+phy ${loop.index}
+ octphy hw-addr ${phy.hw_addr}
+ octphy net-device ${phy.net_device}
+ octphy rx-gain 70
+ %for inst in range(phy.num_instances):
+ instance ${loop.index}
+ %endfor
+%endfor
+bts 0
+ band ${osmo_bts_octphy.band}
+ ipa unit-id ${osmo_bts_octphy.ipa_unit_id} 0
+ oml remote-ip ${osmo_bts_octphy.oml_remote_ip}
+ pcu-socket ${osmo_bts_octphy.pcu_socket_path}
+ gsmtap-sapi bcch
+ gsmtap-sapi ccch
+ gsmtap-sapi rach
+ gsmtap-sapi agch
+ gsmtap-sapi pch
+ gsmtap-sapi sdcch
+ gsmtap-sapi tch/f
+ gsmtap-sapi tch/h
+ gsmtap-sapi pacch
+ gsmtap-sapi pdtch
+ gsmtap-sapi ptcch
+ gsmtap-sapi cbch
+ gsmtap-sapi sacch
+%for trx in osmo_bts_octphy.trx_list:
+ trx ${loop.index}
+  power-ramp max-initial 23000 mdBm
+  power-ramp step-size 2000 mdB
+  power-ramp step-interval 1
+  ms-power-control dsp
+  phy ${trx.phy_idx} instance ${trx.instance_idx}
+%endfor

-- 
To view, visit https://gerrit.osmocom.org/4425
To unsubscribe, visit https://gerrit.osmocom.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ia350964fa539083bb68d439cad0caa8fdf85d297
Gerrit-PatchSet: 1
Gerrit-Project: osmo-gsm-tester
Gerrit-Branch: master
Gerrit-Owner: Pau Espin Pedrol <pespin at sysmocom.de>


More information about the gerrit-log mailing list