blob: 85aca353b61a14ca3bf78bd3c0868640def1e18f [file] [log] [blame]
Pau Espin Pedrol786a6bc2020-03-30 13:51:21 +02001# osmo_gsm_tester: base classes to share code among eNodeB subclasses.
2#
3# Copyright (C) 2020 by sysmocom - s.f.m.c. GmbH
4#
5# Author: Pau Espin Pedrol <pespin@sysmocom.de>
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as
9# published by the Free Software Foundation, either version 3 of the
10# License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20from abc import ABCMeta, abstractmethod
Pau Espin Pedrole1a58bd2020-04-10 20:46:07 +020021from ..core import log, config
Pau Espin Pedrolea8c3d42020-05-04 12:05:05 +020022from ..core import schema
Pau Espin Pedrol1abff4e2020-05-26 12:32:19 +020023from . import run_node
Pau Espin Pedrol786a6bc2020-03-30 13:51:21 +020024
Pau Espin Pedrolea8c3d42020-05-04 12:05:05 +020025def on_register_schemas():
26 resource_schema = {
27 'label': schema.STR,
28 'type': schema.STR,
Pau Espin Pedrolea8c3d42020-05-04 12:05:05 +020029 'gtp_bind_addr': schema.IPV4,
30 'id': schema.UINT,
31 'num_prb': schema.UINT,
32 'transmission_mode': schema.LTE_TRANSMISSION_MODE,
33 'tx_gain': schema.UINT,
34 'rx_gain': schema.UINT,
35 'rf_dev_type': schema.STR,
36 'rf_dev_args': schema.STR,
Pau Espin Pedrole592de82020-06-15 17:01:16 +020037 'additional_args[]': schema.STR,
Andre Puschmann0cfc0842020-08-26 18:19:15 +020038 'inactivity_timer': schema.INT,
Pau Espin Pedrolea8c3d42020-05-04 12:05:05 +020039 'enable_measurements': schema.BOOL_STR,
Andre Puschmann955249d2020-07-01 15:44:09 +020040 'enable_dl_awgn': schema.BOOL_STR,
41 'dl_awgn_snr': schema.INT,
Pau Espin Pedrolea8c3d42020-05-04 12:05:05 +020042 'a1_report_type': schema.STR,
43 'a1_report_value': schema.INT,
44 'a1_hysteresis': schema.INT,
45 'a1_time_to_trigger': schema.INT,
46 'a2_report_type': schema.STR,
47 'a2_report_value': schema.INT,
48 'a2_hysteresis': schema.INT,
49 'a2_time_to_trigger': schema.INT,
50 'a3_report_type': schema.STR,
51 'a3_report_value': schema.INT,
52 'a3_hysteresis': schema.INT,
53 'a3_time_to_trigger': schema.INT,
54 'num_cells': schema.UINT,
55 'cell_list[].cell_id': schema.UINT,
Andre Puschmann549826d2020-04-21 21:14:30 +020056 'cell_list[].rf_port': schema.UINT,
Pau Espin Pedrolea8c3d42020-05-04 12:05:05 +020057 'cell_list[].pci': schema.UINT,
58 'cell_list[].ncell_list[]': schema.UINT,
59 'cell_list[].scell_list[]': schema.UINT,
60 'cell_list[].dl_earfcn': schema.UINT,
61 'cell_list[].dl_rfemu.type': schema.STR,
62 'cell_list[].dl_rfemu.addr': schema.IPV4,
63 'cell_list[].dl_rfemu.ports[]': schema.UINT,
64 }
Pau Espin Pedrol1abff4e2020-05-26 12:32:19 +020065 for key, val in run_node.RunNode.schema().items():
66 resource_schema['run_node.%s' % key] = val
Pau Espin Pedrolea8c3d42020-05-04 12:05:05 +020067 schema.register_resource_schema('enb', resource_schema)
Pau Espin Pedrol786a6bc2020-03-30 13:51:21 +020068
69class eNodeB(log.Origin, metaclass=ABCMeta):
70
71##############
72# PROTECTED
73##############
Pau Espin Pedrola442cb82020-05-05 12:54:37 +020074 def __init__(self, testenv, conf, name):
Pau Espin Pedrol786a6bc2020-03-30 13:51:21 +020075 super().__init__(log.C_RUN, '%s' % name)
76 self._conf = conf
Pau Espin Pedrol1abff4e2020-05-26 12:32:19 +020077 self._run_node = run_node.RunNode.from_conf(conf.get('run_node', {}))
Andre Puschmann4b5a09a2020-04-14 22:24:00 +020078 self._gtp_bind_addr = conf.get('gtp_bind_addr', None)
79 if self._gtp_bind_addr is None:
Pau Espin Pedrol1abff4e2020-05-26 12:32:19 +020080 self._gtp_bind_addr = self._run_node.run_addr()
81 self.set_name('%s_%s' % (name, self._run_node.run_addr()))
Pau Espin Pedrole44e76a2020-03-31 12:35:19 +020082 self._txmode = 0
Pau Espin Pedrol491f77c2020-04-20 14:20:43 +020083 self._id = None
Pau Espin Pedrole44e76a2020-03-31 12:35:19 +020084 self._num_prb = 0
Pau Espin Pedrolf46ae222020-04-17 16:23:54 +020085 self._num_cells = None
Pau Espin Pedrole44e76a2020-03-31 12:35:19 +020086 self._epc = None
87
Pau Espin Pedrolc04528c2020-04-01 13:55:51 +020088 def configure(self, config_specifics_li):
Pau Espin Pedrole44e76a2020-03-31 12:35:19 +020089 values = dict(enb=config.get_defaults('enb'))
Pau Espin Pedrolc04528c2020-04-01 13:55:51 +020090 for config_specifics in config_specifics_li:
91 config.overlay(values, dict(enb=config.get_defaults(config_specifics)))
Pau Espin Pedrola442cb82020-05-05 12:54:37 +020092 config.overlay(values, dict(enb=self.testenv.suite().config().get('enb', {})))
Pau Espin Pedrolc04528c2020-04-01 13:55:51 +020093 for config_specifics in config_specifics_li:
Pau Espin Pedrola442cb82020-05-05 12:54:37 +020094 config.overlay(values, dict(enb=self.testenv.suite().config().get(config_specifics, {})))
Pau Espin Pedrole44e76a2020-03-31 12:35:19 +020095 config.overlay(values, dict(enb=self._conf))
Pau Espin Pedrol491f77c2020-04-20 14:20:43 +020096 self._id = int(values['enb'].get('id', None))
97 assert self._id is not None
Pau Espin Pedrole44e76a2020-03-31 12:35:19 +020098 self._num_prb = int(values['enb'].get('num_prb', None))
99 assert self._num_prb
100 self._txmode = int(values['enb'].get('transmission_mode', None))
101 assert self._txmode
102 config.overlay(values, dict(enb={ 'num_ports': self.num_ports() }))
Andre Puschmann0cfc0842020-08-26 18:19:15 +0200103 self._inactivity_timer = int(values['enb'].get('inactivity_timer', None))
104 assert self._inactivity_timer
Pau Espin Pedrole44e76a2020-03-31 12:35:19 +0200105 assert self._epc is not None
Pau Espin Pedrol1abff4e2020-05-26 12:32:19 +0200106 config.overlay(values, dict(enb={ 'addr': self.addr() }))
Pau Espin Pedrole44e76a2020-03-31 12:35:19 +0200107 config.overlay(values, dict(enb={ 'mme_addr': self._epc.addr() }))
Andre Puschmann4b5a09a2020-04-14 22:24:00 +0200108 config.overlay(values, dict(enb={ 'gtp_bind_addr': self._gtp_bind_addr }))
Pau Espin Pedrolf46ae222020-04-17 16:23:54 +0200109 self._num_cells = int(values['enb'].get('num_cells', None))
110 assert self._num_cells
111
112 # adjust cell_list to num_cells length:
113 len_cell_list = len(values['enb']['cell_list'])
114 if len_cell_list >= self._num_cells:
115 values['enb']['cell_list'] = values['enb']['cell_list'][:self._num_cells]
116 else:
117 raise log.Error('enb.cell_list items (%d) < enb.num_cells (%d) attribute!' % (len_cell_list, self._num_cells))
118 # adjust scell list (to only contain values available in cell_list):
119 cell_id_list = [c['cell_id'] for c in values['enb']['cell_list']]
120 for i in range(len(values['enb']['cell_list'])):
121 scell_list_old = values['enb']['cell_list'][i]['scell_list']
122 scell_list_new = []
123 for scell_id in scell_list_old:
124 if scell_id in cell_id_list:
125 scell_list_new.append(scell_id)
126 values['enb']['cell_list'][i]['scell_list'] = scell_list_new
127
Pau Espin Pedrole44e76a2020-03-31 12:35:19 +0200128 return values
129
Pau Espin Pedrol491f77c2020-04-20 14:20:43 +0200130 def id(self):
131 return self._id
132
Pau Espin Pedrole44e76a2020-03-31 12:35:19 +0200133 def num_ports(self):
134 if self._txmode == 1:
135 return 1
136 return 2
Pau Espin Pedrol786a6bc2020-03-30 13:51:21 +0200137
Andre Puschmann0957e9e2020-06-16 16:29:27 +0200138 def num_cells(self):
139 return self._num_cells
140
Pau Espin Pedrol786a6bc2020-03-30 13:51:21 +0200141########################
142# PUBLIC - INTERNAL API
143########################
144 def cleanup(self):
145 'Nothing to do by default. Subclass can override if required.'
146 pass
147
Pau Espin Pedrole44e76a2020-03-31 12:35:19 +0200148 def num_prb(self):
149 return self._num_prb
150
Andre Puschmanne2a6da62020-04-20 20:39:34 +0200151 #reference: srsLTE.git srslte_symbol_sz()
152 def num_prb2symbol_sz(self, num_prb):
Andre Puschmann0a501102020-06-02 22:35:27 +0200153 if num_prb == 6:
Andre Puschmanne2a6da62020-04-20 20:39:34 +0200154 return 128
Andre Puschmann0a501102020-06-02 22:35:27 +0200155 if num_prb == 50:
Andre Puschmanne2a6da62020-04-20 20:39:34 +0200156 return 768
Andre Puschmann0a501102020-06-02 22:35:27 +0200157 if num_prb == 75:
Andre Puschmanne2a6da62020-04-20 20:39:34 +0200158 return 1024
Andre Puschmann0a501102020-06-02 22:35:27 +0200159 return 1536
160
Andre Puschmanne2a6da62020-04-20 20:39:34 +0200161 raise log.Error('invalid num_prb %r', num_prb)
162
163 def num_prb2base_srate(self, num_prb):
164 return self.num_prb2symbol_sz(num_prb) * 15 * 1000
165
166 def get_zmq_rf_dev_args(self):
167 base_srate = self.num_prb2base_srate(self.num_prb())
168 # Define all 8 possible RF ports (2x CA with 2x2 MIMO)
169 rf_dev_args = 'fail_on_disconnect=true' \
170 + ',tx_port0=tcp://' + self.addr() + ':2000' \
171 + ',tx_port1=tcp://' + self.addr() + ':2002' \
172 + ',tx_port2=tcp://' + self.addr() + ':2004' \
173 + ',tx_port3=tcp://' + self.addr() + ':2006' \
174 + ',rx_port0=tcp://' + self.ue.addr() + ':2001' \
175 + ',rx_port1=tcp://' + self.ue.addr() + ':2003' \
176 + ',rx_port2=tcp://' + self.ue.addr() + ':2005' \
177 + ',rx_port3=tcp://' + self.ue.addr() + ':2007'
178
Andre Puschmanne2a6da62020-04-20 20:39:34 +0200179 rf_dev_args += ',id=enb,base_srate=' + str(base_srate)
180
181 return rf_dev_args
182
Pau Espin Pedrola442cb82020-05-05 12:54:37 +0200183 def get_instance_by_type(testenv, conf):
Pau Espin Pedrol1ee5ec52020-05-04 17:16:39 +0200184 """Allocate a ENB child class based on type. Opts are passed to the newly created object."""
185 enb_type = conf.get('type')
186 if enb_type is None:
187 raise RuntimeError('ENB type is not defined!')
188
189 if enb_type == 'amarisoftenb':
190 from .enb_amarisoft import AmarisoftENB
191 enb_class = AmarisoftENB
192 elif enb_type == 'srsenb':
193 from .enb_srs import srsENB
194 enb_class = srsENB
195 else:
196 raise log.Error('ENB type not supported:', enb_type)
Pau Espin Pedrola442cb82020-05-05 12:54:37 +0200197 return enb_class(testenv, conf)
Pau Espin Pedrol1ee5ec52020-05-04 17:16:39 +0200198
Pau Espin Pedrol786a6bc2020-03-30 13:51:21 +0200199###################
200# PUBLIC (test API included)
201###################
202 @abstractmethod
203 def start(self, epc):
204 'Starts ENB, it will connect to "epc"'
205 pass
206
207 @abstractmethod
208 def ue_add(self, ue):
209 pass
210
211 @abstractmethod
212 def running(self):
213 pass
214
215 @abstractmethod
216 def ue_max_rate(self, downlink=True):
217 pass
218
Pau Espin Pedrold4404d52020-04-20 13:29:31 +0200219 @abstractmethod
220 def get_rfemu(self, cell=0, dl=True):
221 'Get rfemu.RFemulation subclass implementation object for given cell index and direction.'
222 pass
223
Pau Espin Pedrol786a6bc2020-03-30 13:51:21 +0200224 def addr(self):
Pau Espin Pedrol1abff4e2020-05-26 12:32:19 +0200225 return self._run_node.run_addr()
Pau Espin Pedrol786a6bc2020-03-30 13:51:21 +0200226
Pau Espin Pedrol786a6bc2020-03-30 13:51:21 +0200227# vim: expandtab tabstop=4 shiftwidth=4