blob: 3c1f77126f2d96d66d0db6cbc8682af23e2d1d34 [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 Pedrol786a6bc2020-03-30 13:51:21 +020022
23
24class eNodeB(log.Origin, metaclass=ABCMeta):
25
26##############
27# PROTECTED
28##############
29 def __init__(self, suite_run, conf, name):
30 super().__init__(log.C_RUN, '%s' % name)
31 self._conf = conf
32 self._addr = conf.get('addr', None)
33 if self._addr is None:
34 raise log.Error('addr not set')
Andre Puschmann4b5a09a2020-04-14 22:24:00 +020035 self._gtp_bind_addr = conf.get('gtp_bind_addr', None)
36 if self._gtp_bind_addr is None:
37 self._gtp_bind_addr = self._addr
Pau Espin Pedrol786a6bc2020-03-30 13:51:21 +020038 self.set_name('%s_%s' % (name, self._addr))
Pau Espin Pedrole44e76a2020-03-31 12:35:19 +020039 self._txmode = 0
Pau Espin Pedrol491f77c2020-04-20 14:20:43 +020040 self._id = None
Pau Espin Pedrole44e76a2020-03-31 12:35:19 +020041 self._num_prb = 0
Pau Espin Pedrolf46ae222020-04-17 16:23:54 +020042 self._num_cells = None
Pau Espin Pedrole44e76a2020-03-31 12:35:19 +020043 self._epc = None
44
Pau Espin Pedrolc04528c2020-04-01 13:55:51 +020045 def configure(self, config_specifics_li):
Pau Espin Pedrole44e76a2020-03-31 12:35:19 +020046 values = dict(enb=config.get_defaults('enb'))
Pau Espin Pedrolc04528c2020-04-01 13:55:51 +020047 for config_specifics in config_specifics_li:
48 config.overlay(values, dict(enb=config.get_defaults(config_specifics)))
Pau Espin Pedrole44e76a2020-03-31 12:35:19 +020049 config.overlay(values, dict(enb=self.suite_run.config().get('enb', {})))
Pau Espin Pedrolc04528c2020-04-01 13:55:51 +020050 for config_specifics in config_specifics_li:
51 config.overlay(values, dict(enb=self.suite_run.config().get(config_specifics, {})))
Pau Espin Pedrole44e76a2020-03-31 12:35:19 +020052 config.overlay(values, dict(enb=self._conf))
Pau Espin Pedrol491f77c2020-04-20 14:20:43 +020053 self._id = int(values['enb'].get('id', None))
54 assert self._id is not None
Pau Espin Pedrole44e76a2020-03-31 12:35:19 +020055 self._num_prb = int(values['enb'].get('num_prb', None))
56 assert self._num_prb
57 self._txmode = int(values['enb'].get('transmission_mode', None))
58 assert self._txmode
59 config.overlay(values, dict(enb={ 'num_ports': self.num_ports() }))
60 assert self._epc is not None
61 config.overlay(values, dict(enb={ 'mme_addr': self._epc.addr() }))
Andre Puschmann4b5a09a2020-04-14 22:24:00 +020062 config.overlay(values, dict(enb={ 'gtp_bind_addr': self._gtp_bind_addr }))
Pau Espin Pedrolf46ae222020-04-17 16:23:54 +020063 self._num_cells = int(values['enb'].get('num_cells', None))
64 assert self._num_cells
65
66 # adjust cell_list to num_cells length:
67 len_cell_list = len(values['enb']['cell_list'])
68 if len_cell_list >= self._num_cells:
69 values['enb']['cell_list'] = values['enb']['cell_list'][:self._num_cells]
70 else:
71 raise log.Error('enb.cell_list items (%d) < enb.num_cells (%d) attribute!' % (len_cell_list, self._num_cells))
72 # adjust scell list (to only contain values available in cell_list):
73 cell_id_list = [c['cell_id'] for c in values['enb']['cell_list']]
74 for i in range(len(values['enb']['cell_list'])):
75 scell_list_old = values['enb']['cell_list'][i]['scell_list']
76 scell_list_new = []
77 for scell_id in scell_list_old:
78 if scell_id in cell_id_list:
79 scell_list_new.append(scell_id)
80 values['enb']['cell_list'][i]['scell_list'] = scell_list_new
81
Pau Espin Pedrole44e76a2020-03-31 12:35:19 +020082 return values
83
Pau Espin Pedrol491f77c2020-04-20 14:20:43 +020084 def id(self):
85 return self._id
86
Pau Espin Pedrole44e76a2020-03-31 12:35:19 +020087 def num_ports(self):
88 if self._txmode == 1:
89 return 1
90 return 2
Pau Espin Pedrol786a6bc2020-03-30 13:51:21 +020091
92########################
93# PUBLIC - INTERNAL API
94########################
95 def cleanup(self):
96 'Nothing to do by default. Subclass can override if required.'
97 pass
98
Pau Espin Pedrole44e76a2020-03-31 12:35:19 +020099 def num_prb(self):
100 return self._num_prb
101
Andre Puschmanne2a6da62020-04-20 20:39:34 +0200102 #reference: srsLTE.git srslte_symbol_sz()
103 def num_prb2symbol_sz(self, num_prb):
104 if num_prb <= 6:
105 return 128
106 if num_prb <= 15:
107 return 256
108 if num_prb <= 25:
109 return 384
110 if num_prb <= 50:
111 return 768
112 if num_prb <= 75:
113 return 1024
114 if num_prb <= 110:
115 return 1536
116 raise log.Error('invalid num_prb %r', num_prb)
117
118 def num_prb2base_srate(self, num_prb):
119 return self.num_prb2symbol_sz(num_prb) * 15 * 1000
120
121 def get_zmq_rf_dev_args(self):
122 base_srate = self.num_prb2base_srate(self.num_prb())
123 # Define all 8 possible RF ports (2x CA with 2x2 MIMO)
124 rf_dev_args = 'fail_on_disconnect=true' \
125 + ',tx_port0=tcp://' + self.addr() + ':2000' \
126 + ',tx_port1=tcp://' + self.addr() + ':2002' \
127 + ',tx_port2=tcp://' + self.addr() + ':2004' \
128 + ',tx_port3=tcp://' + self.addr() + ':2006' \
129 + ',rx_port0=tcp://' + self.ue.addr() + ':2001' \
130 + ',rx_port1=tcp://' + self.ue.addr() + ':2003' \
131 + ',rx_port2=tcp://' + self.ue.addr() + ':2005' \
132 + ',rx_port3=tcp://' + self.ue.addr() + ':2007'
133
134 if self._num_cells == 1:
135 # Single carrier
136 if self.num_ports() == 1:
137 # SISO
138 rf_dev_args += ',tx_freq0=2630e6,rx_freq0=2510e6'
139 elif self.num_ports() == 2:
140 # MIMO
141 rf_dev_args += ',tx_freq0=2630e6,tx_freq1=2630e6,rx_freq0=2510e6,rx_freq1=2510e6'
142 elif self._num_cells == 2:
143 # 2x class
144 if self.num_ports() == 1:
145 # SISO
146 rf_dev_args += ',tx_freq0=2630e6,tx_freq1=2650e6,rx_freq0=2510e6,rx_freq1=2530e6'
147 elif self.num_ports() == 2:
148 # MIMO
149 rf_dev_args += ',tx_freq0=2630e6,tx_freq1=2630e6,tx_freq2=2650e6,tx_freq3=2650e6,rx_freq0=2510e6,rx_freq1=2510e6,rx_freq2=2530e6,rx_freq3=2530e6'
150
151 rf_dev_args += ',id=enb,base_srate=' + str(base_srate)
152
153 return rf_dev_args
154
Pau Espin Pedrol786a6bc2020-03-30 13:51:21 +0200155###################
156# PUBLIC (test API included)
157###################
158 @abstractmethod
159 def start(self, epc):
160 'Starts ENB, it will connect to "epc"'
161 pass
162
163 @abstractmethod
164 def ue_add(self, ue):
165 pass
166
167 @abstractmethod
168 def running(self):
169 pass
170
171 @abstractmethod
172 def ue_max_rate(self, downlink=True):
173 pass
174
Pau Espin Pedrold4404d52020-04-20 13:29:31 +0200175 @abstractmethod
176 def get_rfemu(self, cell=0, dl=True):
177 'Get rfemu.RFemulation subclass implementation object for given cell index and direction.'
178 pass
179
Pau Espin Pedrol786a6bc2020-03-30 13:51:21 +0200180 def addr(self):
181 return self._addr
182
Pau Espin Pedrole44e76a2020-03-31 12:35:19 +0200183 def ue_max_rate(self, downlink=True):
184 # The max rate for a single UE per PRB configuration in TM1
185 max_phy_rate_tm1_dl = { 6 : 3.5e6,
186 15 : 11e6,
187 25 : 18e6,
188 50 : 36e6,
189 75 : 55e6,
190 100 : 75e6 }
191 max_phy_rate_tm1_ul = { 6 : 0.9e6,
192 15 : 4.7e6,
193 25 : 10e6,
194 50 : 23e6,
195 75 : 34e6,
196 100 : 51e6 }
197 if downlink:
198 max_rate = max_phy_rate_tm1_dl[self.num_prb()]
199 else:
200 max_rate = max_phy_rate_tm1_ul[self.num_prb()]
201 #TODO: calculate for non-standard prb numbers.
202 if self._txmode > 2:
203 max_rate *= 2
204 # We use 3 control symbols for 6, 15 and 25 PRBs which results in lower max rate
205 if self.num_prb() < 50:
206 max_rate *= 0.9
207 return max_rate
208
Pau Espin Pedrol786a6bc2020-03-30 13:51:21 +0200209# vim: expandtab tabstop=4 shiftwidth=4