blob: 6b9ac56f76ae8cbc6a40a3d72579a8def9149d49 [file] [log] [blame]
Wei-Yu Chenad55cb82022-02-15 20:07:01 +08001# SPDX-FileCopyrightText: 2020 The Magma Authors.
2# SPDX-FileCopyrightText: 2022 Open Networking Foundation <support@opennetworking.org>
3#
4# SPDX-License-Identifier: BSD-3-Clause
Wei-Yu Chen49950b92021-11-08 19:19:18 +08005
6from typing import Any, Callable, Dict, List, Optional, Type
7
8from common.service import MagmaService
9from data_models import transform_for_enb, transform_for_magma
10from data_models.data_model import DataModel, TrParam
11from data_models.data_model_parameters import (
12 ParameterName,
13 TrParameterType,
14)
15from device_config.enodeb_config_postprocessor import (
16 EnodebConfigurationPostProcessor,
17)
18from device_config.enodeb_configuration import EnodebConfiguration
19from devices.device_utils import EnodebDeviceName
20from exceptions import Tr069Error
21from logger import EnodebdLogger as logger
22from state_machines.acs_state_utils import (
23 get_all_objects_to_add,
24 get_all_objects_to_delete,
25)
26from state_machines.enb_acs import EnodebAcsStateMachine
27from state_machines.enb_acs_impl import BasicEnodebAcsStateMachine
28from state_machines.enb_acs_states import (
29 AcsMsgAndTransition,
30 AcsReadMsgResult,
31 AddObjectsState,
32 DeleteObjectsState,
33 EndSessionState,
34 EnodebAcsState,
35 ErrorState,
36 GetParametersState,
37 GetRPCMethodsState,
38 SendGetTransientParametersState,
39 SendRebootState,
40 SetParameterValuesNotAdminState,
41 WaitEmptyMessageState,
42 WaitGetObjectParametersState,
43 WaitGetParametersState,
44 WaitGetTransientParametersState,
45 WaitInformMRebootState,
46 WaitInformState,
47 WaitRebootResponseState,
48 WaitSetParameterValuesState,
49)
50from tr069 import models
51
52
53class CaviumHandler(BasicEnodebAcsStateMachine):
54 def __init__(
55 self,
56 service: MagmaService,
57 ) -> None:
58 self._state_map = {}
59 super().__init__(service=service, use_param_key=False)
60
61 def reboot_asap(self) -> None:
62 self.transition('reboot')
63
64 def is_enodeb_connected(self) -> bool:
65 return not isinstance(self.state, WaitInformState)
66
67 def _init_state_map(self) -> None:
68 self._state_map = {
69 'wait_inform': WaitInformState(self, when_done='get_rpc_methods'),
70 'get_rpc_methods': GetRPCMethodsState(self, when_done='wait_empty', when_skip='get_transient_params'),
71 'wait_empty': WaitEmptyMessageState(self, when_done='get_transient_params'),
72 'get_transient_params': SendGetTransientParametersState(self, when_done='wait_get_transient_params'),
73 'wait_get_transient_params': WaitGetTransientParametersState(self, when_get='get_params', when_get_obj_params='get_obj_params', when_delete='delete_objs', when_add='add_objs', when_set='set_params', when_skip='end_session'),
74 'get_params': GetParametersState(self, when_done='wait_get_params'),
75 'wait_get_params': WaitGetParametersState(self, when_done='get_obj_params'),
76 'get_obj_params': CaviumGetObjectParametersState(self, when_done='wait_get_obj_params'),
77 'wait_get_obj_params': CaviumWaitGetObjectParametersState(self, when_edit='disable_admin', when_skip='get_transient_params'),
78 'disable_admin': CaviumDisableAdminEnableState(self, admin_value=False, when_done='wait_disable_admin'),
79 'wait_disable_admin': CaviumWaitDisableAdminEnableState(self, admin_value=False, when_add='add_objs', when_delete='delete_objs', when_done='set_params'),
80 'delete_objs': DeleteObjectsState(self, when_add='add_objs', when_skip='set_params'),
81 'add_objs': AddObjectsState(self, when_done='set_params'),
82 'set_params': SetParameterValuesNotAdminState(self, when_done='wait_set_params'),
83 'wait_set_params': WaitSetParameterValuesState(self, when_done='enable_admin', when_apply_invasive='enable_admin'),
84 'enable_admin': CaviumDisableAdminEnableState(self, admin_value=True, when_done='wait_enable_admin'),
85 'wait_enable_admin': CaviumWaitDisableAdminEnableState(self, admin_value=True, when_done='check_get_params', when_add='check_get_params', when_delete='check_get_params'),
86 'check_get_params': GetParametersState(self, when_done='check_wait_get_params', request_all_params=True),
87 'check_wait_get_params': WaitGetParametersState(self, when_done='end_session'),
88 'end_session': EndSessionState(self),
89 # Below states only entered through manual user intervention
90 'reboot': SendRebootState(self, when_done='wait_reboot'),
91 'wait_reboot': WaitRebootResponseState(self, when_done='wait_post_reboot_inform'),
92 'wait_post_reboot_inform': WaitInformMRebootState(self, when_done='wait_reboot_delay', when_timeout='wait_inform'),
93 # The states below are entered when an unexpected message type is
94 # received
95 'unexpected_fault': ErrorState(self, inform_transition_target='wait_inform'),
96 }
97
98 @property
99 def device_name(self) -> str:
100 return EnodebDeviceName.CAVIUM
101
102 @property
103 def data_model_class(self) -> Type[DataModel]:
104 return CaviumTrDataModel
105
106 @property
107 def config_postprocessor(self) -> EnodebConfigurationPostProcessor:
108 return CaviumTrConfigurationInitializer()
109
110 @property
111 def state_map(self) -> Dict[str, EnodebAcsState]:
112 return self._state_map
113
114 @property
115 def disconnected_state_name(self) -> str:
116 return 'wait_inform'
117
118 @property
119 def unexpected_fault_state_name(self) -> str:
120 return 'unexpected_fault'
121
122
123class CaviumGetObjectParametersState(EnodebAcsState):
124 """
125 When booted, the PLMN list is empty so we cannot get individual
126 object parameters. Instead, get the parent object PLMN_LIST
127 which will include any children if they exist.
128 """
129
130 def __init__(self, acs: EnodebAcsStateMachine, when_done: str):
131 super().__init__()
132 self.acs = acs
133 self.done_transition = when_done
134
135 def get_msg(self, message: Any) -> AcsMsgAndTransition:
136 """ Respond with GetParameterValuesRequest """
137 names = [ParameterName.PLMN_LIST]
138
139 # Generate the request
140 request = models.GetParameterValues()
141 request.ParameterNames = models.ParameterNames()
142 request.ParameterNames.arrayType = 'xsd:string[%d]' \
143 % len(names)
144 request.ParameterNames.string = []
145 for name in names:
146 path = self.acs.data_model.get_parameter(name).path
147 request.ParameterNames.string.append(path)
148
149 return AcsMsgAndTransition(request, self.done_transition)
150
151 def state_description(self) -> str:
152 return 'Getting object parameters'
153
154
155class CaviumWaitGetObjectParametersState(WaitGetObjectParametersState):
156 def __init__(
157 self,
158 acs: EnodebAcsStateMachine,
159 when_edit: str,
160 when_skip: str,
161 ):
162 super().__init__(
163 acs=acs,
164 when_add=when_edit,
165 when_delete=when_edit,
166 when_set=when_edit,
167 when_skip=when_skip,
168 )
169
170
171class CaviumDisableAdminEnableState(EnodebAcsState):
172 """
173 Cavium requires that we disable 'Admin Enable' before configuring
174 most parameters
175 """
176
177 def __init__(self, acs: EnodebAcsStateMachine, admin_value: bool, when_done: str):
178 super().__init__()
179 self.acs = acs
180 self.admin_value = admin_value
181 self.done_transition = when_done
182
183 def read_msg(self, message: Any) -> AcsReadMsgResult:
184 if not isinstance(message, models.DummyInput):
185 return AcsReadMsgResult(False, None)
186 return AcsReadMsgResult(True, None)
187
188 def get_msg(self, message: Any) -> AcsMsgAndTransition:
189 """
190 Returns:
191 A SetParameterValueRequest for setting 'Admin Enable' to False
192 """
193 param_name = ParameterName.ADMIN_STATE
194 # if we want the cell to be down don't force it up
195 desired_admin_value = \
196 self.acs.desired_cfg.get_parameter(param_name) \
197 and self.admin_value
198 admin_value = \
199 self.acs.data_model.transform_for_enb(
200 param_name,
201 desired_admin_value,
202 )
203 admin_path = self.acs.data_model.get_parameter(param_name).path
204 param_values = {admin_path: admin_value}
205
206 request = models.SetParameterValues()
207 request.ParameterList = models.ParameterValueList()
208 request.ParameterList.arrayType = 'cwmp:ParameterValueStruct[%d]' \
209 % len(param_values)
210
211 name_value = models.ParameterValueStruct()
212 name_value.Name = admin_path
213 name_value.Value = models.anySimpleType()
214 name_value.Value.type = 'xsd:string'
215 name_value.Value.Data = str(admin_value)
216 request.ParameterList.ParameterValueStruct = [name_value]
217
218 return AcsMsgAndTransition(request, self.done_transition)
219
220 def state_description(self) -> str:
221 return 'Disabling admin_enable (Cavium only)'
222
223
224class CaviumWaitDisableAdminEnableState(EnodebAcsState):
225 def __init__(
226 self,
227 acs: EnodebAcsStateMachine,
228 admin_value: bool,
229 when_done: str,
230 when_add: str,
231 when_delete: str,
232 ):
233 super().__init__()
234 self.acs = acs
235 self.done_transition = when_done
236 self.add_obj_transition = when_add
237 self.del_obj_transition = when_delete
238 self.admin_value = admin_value
239
240 def read_msg(self, message: Any) -> Optional[str]:
241 if type(message) == models.Fault:
242 logger.error('Received Fault in response to SetParameterValues')
243 if message.SetParameterValuesFault is not None:
244 for fault in message.SetParameterValuesFault:
245 logger.error(
246 'SetParameterValuesFault Param: %s, Code: %s, String: %s',
247 fault.ParameterName, fault.FaultCode, fault.FaultString,
248 )
249 raise Tr069Error(
250 'Received Fault in response to SetParameterValues '
251 '(faultstring = %s)' % message.FaultString,
252 )
253 elif not isinstance(message, models.SetParameterValuesResponse):
254 return AcsReadMsgResult(False, None)
255 if message.Status != 0:
256 raise Tr069Error(
257 'Received SetParameterValuesResponse with '
258 'Status=%d' % message.Status,
259 )
260 param_name = ParameterName.ADMIN_STATE
261 desired_admin_value = \
262 self.acs.desired_cfg.get_parameter(param_name) \
263 and self.admin_value
264 magma_value = \
265 self.acs.data_model.transform_for_magma(
266 param_name,
267 desired_admin_value,
268 )
269 self.acs.device_cfg.set_parameter(param_name, magma_value)
270
271 if len(
272 get_all_objects_to_delete(
273 self.acs.desired_cfg,
274 self.acs.device_cfg,
275 ),
276 ) > 0:
277 return AcsReadMsgResult(True, self.del_obj_transition)
278 elif len(
279 get_all_objects_to_add(
280 self.acs.desired_cfg,
281 self.acs.device_cfg,
282 ),
283 ) > 0:
284 return AcsReadMsgResult(True, self.add_obj_transition)
285 else:
286 return AcsReadMsgResult(True, self.done_transition)
287
288 def state_description(self) -> str:
289 return 'Disabling admin_enable (Cavium only)'
290
291
292class CaviumTrDataModel(DataModel):
293 """
294 Class to represent relevant data model parameters from TR-196/TR-098/TR-181.
295 This class is effectively read-only
296 """
297 # Mapping of TR parameter paths to aliases
298 DEVICE_PATH = 'Device.'
299 FAPSERVICE_PATH = DEVICE_PATH + 'Services.FAPService.1.'
300 PARAMETERS = {
301 # Top-level objects
302 ParameterName.DEVICE: TrParam(DEVICE_PATH, True, TrParameterType.OBJECT, False),
303 ParameterName.FAP_SERVICE: TrParam(FAPSERVICE_PATH, True, TrParameterType.OBJECT, False),
304
305 # Device info parameters
306 ParameterName.GPS_STATUS: TrParam(DEVICE_PATH + 'FAP.GPS.ContinuousGPSStatus.GotFix', True, TrParameterType.BOOLEAN, False),
307 ParameterName.GPS_LAT: TrParam(DEVICE_PATH + 'FAP.GPS.LockedLatitude', True, TrParameterType.INT, False),
308 ParameterName.GPS_LONG: TrParam(DEVICE_PATH + 'FAP.GPS.LockedLongitude', True, TrParameterType.INT, False),
309 ParameterName.SW_VERSION: TrParam(DEVICE_PATH + 'DeviceInfo.SoftwareVersion', True, TrParameterType.STRING, False),
310 ParameterName.SERIAL_NUMBER: TrParam(DEVICE_PATH + 'DeviceInfo.SerialNumber', True, TrParameterType.STRING, False),
311
312 # Capabilities
313 ParameterName.DUPLEX_MODE_CAPABILITY: TrParam(
314 FAPSERVICE_PATH + 'Capabilities.LTE.DuplexMode', True, TrParameterType.STRING, False,
315 ),
316 ParameterName.BAND_CAPABILITY: TrParam(FAPSERVICE_PATH + 'Capabilities.LTE.BandsSupported', True, TrParameterType.UNSIGNED_INT, False),
317
318 # RF-related parameters
319 ParameterName.EARFCNDL: TrParam(FAPSERVICE_PATH + 'CellConfig.LTE.RAN.RF.EARFCNDL', True, TrParameterType.UNSIGNED_INT, False),
320 ParameterName.EARFCNUL: TrParam(FAPSERVICE_PATH + 'CellConfig.LTE.RAN.RF.EARFCNUL', True, TrParameterType.UNSIGNED_INT, False),
321 ParameterName.BAND: TrParam(FAPSERVICE_PATH + 'CellConfig.LTE.RAN.RF.FreqBandIndicator', True, TrParameterType.UNSIGNED_INT, False),
Wei-Yu Chen8d064162022-05-27 21:06:55 +0800322 ParameterName.PCI1: TrParam(FAPSERVICE_PATH + 'CellConfig.LTE.RAN.RF.PhyCellID', True, TrParameterType.STRING, False),
Wei-Yu Chen49950b92021-11-08 19:19:18 +0800323 ParameterName.DL_BANDWIDTH: TrParam(FAPSERVICE_PATH + 'CellConfig.LTE.RAN.RF.DLBandwidth', True, TrParameterType.STRING, False),
324 ParameterName.UL_BANDWIDTH: TrParam(FAPSERVICE_PATH + 'CellConfig.LTE.RAN.RF.ULBandwidth', True, TrParameterType.STRING, False),
325 ParameterName.CELL_ID: TrParam(FAPSERVICE_PATH + 'CellConfig.LTE.RAN.Common.CellIdentity', True, TrParameterType.UNSIGNED_INT, False),
326
327 # Other LTE parameters
328 ParameterName.ADMIN_STATE: TrParam(FAPSERVICE_PATH + 'FAPControl.LTE.AdminState', False, TrParameterType.BOOLEAN, False),
329 ParameterName.OP_STATE: TrParam(FAPSERVICE_PATH + 'FAPControl.LTE.OpState', True, TrParameterType.BOOLEAN, False),
330 ParameterName.RF_TX_STATUS: TrParam(FAPSERVICE_PATH + 'FAPControl.LTE.RFTxStatus', True, TrParameterType.BOOLEAN, False),
331
332 # RAN parameters
333 ParameterName.CELL_RESERVED: TrParam(
334 FAPSERVICE_PATH
335 + 'CellConfig.LTE.RAN.CellRestriction.CellReservedForOperatorUse', True, TrParameterType.BOOLEAN, False,
336 ),
337 ParameterName.CELL_BARRED: TrParam(
338 FAPSERVICE_PATH
339 + 'CellConfig.LTE.RAN.CellRestriction.CellBarred', True, TrParameterType.BOOLEAN, False,
340 ),
341
342 # Core network parameters
Wei-Yu Chen8d064162022-05-27 21:06:55 +0800343 ParameterName.MME_ADDRESS: TrParam(
Wei-Yu Chen49950b92021-11-08 19:19:18 +0800344 FAPSERVICE_PATH + 'FAPControl.LTE.Gateway.S1SigLinkServerList', True, TrParameterType.STRING, False,
345 ),
346 ParameterName.MME_PORT: TrParam(FAPSERVICE_PATH + 'FAPControl.LTE.Gateway.S1SigLinkPort', True, TrParameterType.UNSIGNED_INT, False),
347 ParameterName.NUM_PLMNS: TrParam(
348 FAPSERVICE_PATH + 'CellConfig.LTE.EPC.PLMNListNumberOfEntries', True, TrParameterType.UNSIGNED_INT, False,
349 ),
350 ParameterName.PLMN: TrParam(FAPSERVICE_PATH + 'CellConfig.LTE.EPC.PLMNList.', True, TrParameterType.OBJECT, False),
351 # PLMN arrays are added below
Wei-Yu Chen8d064162022-05-27 21:06:55 +0800352 ParameterName.TAC1: TrParam(FAPSERVICE_PATH + 'CellConfig.LTE.EPC.TAC', True, TrParameterType.UNSIGNED_INT, False),
Wei-Yu Chen49950b92021-11-08 19:19:18 +0800353 ParameterName.IP_SEC_ENABLE: TrParam(
354 DEVICE_PATH + 'IPsec.Enable', False, TrParameterType.BOOLEAN, False,
355 ),
356 ParameterName.PERIODIC_INFORM_INTERVAL:
357 TrParam(DEVICE_PATH + 'ManagementServer.PeriodicInformInterval', False, TrParameterType.UNSIGNED_INT, False),
358
359 # Management server parameters
360 ParameterName.PERIODIC_INFORM_ENABLE: TrParam(
361 DEVICE_PATH + 'ManagementServer.PeriodicInformEnable',
362 False, TrParameterType.BOOLEAN, False,
363 ),
364 ParameterName.PERIODIC_INFORM_INTERVAL: TrParam(
365 DEVICE_PATH + 'ManagementServer.PeriodicInformInterval',
366 False, TrParameterType.UNSIGNED_INT, False,
367 ),
368
369 # Performance management parameters
370 ParameterName.PERF_MGMT_ENABLE: TrParam(
371 FAPSERVICE_PATH + 'PerfMgmt.Config.1.Enable', False, TrParameterType.BOOLEAN, False,
372 ),
373 ParameterName.PERF_MGMT_UPLOAD_INTERVAL: TrParam(
374 FAPSERVICE_PATH + 'PerfMgmt.Config.1.PeriodicUploadInterval', False, TrParameterType.UNSIGNED_INT, False,
375 ),
376 ParameterName.PERF_MGMT_UPLOAD_URL: TrParam(
377 FAPSERVICE_PATH + 'PerfMgmt.Config.1.URL', False, TrParameterType.STRING, False,
378 ),
379 ParameterName.PERF_MGMT_USER: TrParam(
380 FAPSERVICE_PATH + 'PerfMgmt.Config.1.Username',
381 False, TrParameterType.STRING, False,
382 ),
383 ParameterName.PERF_MGMT_PASSWORD: TrParam(
384 FAPSERVICE_PATH + 'PerfMgmt.Config.1.Password',
385 False, TrParameterType.STRING, False,
386 ),
387
388 # PLMN Info
389 ParameterName.PLMN_LIST: TrParam(
390 FAPSERVICE_PATH + 'CellConfig.LTE.EPC.PLMNList.', False, TrParameterType.OBJECT, False,
391 ),
392 }
393
394 NUM_PLMNS_IN_CONFIG = 6
395 for i in range(1, NUM_PLMNS_IN_CONFIG + 1):
396 PARAMETERS[ParameterName.PLMN_N % i] = TrParam(
397 FAPSERVICE_PATH + 'CellConfig.LTE.EPC.PLMNList.%d.' % i, True, TrParameterType.OBJECT, False,
398 )
399 PARAMETERS[ParameterName.PLMN_N_CELL_RESERVED % i] = TrParam(
400 FAPSERVICE_PATH
401 + 'CellConfig.LTE.EPC.PLMNList.%d.CellReservedForOperatorUse' % i, True, TrParameterType.BOOLEAN, False,
402 )
403 PARAMETERS[ParameterName.PLMN_N_ENABLE % i] = TrParam(
404 FAPSERVICE_PATH + 'CellConfig.LTE.EPC.PLMNList.%d.Enable' % i, True, TrParameterType.BOOLEAN, False,
405 )
406 PARAMETERS[ParameterName.PLMN_N_PRIMARY % i] = TrParam(
407 FAPSERVICE_PATH + 'CellConfig.LTE.EPC.PLMNList.%d.IsPrimary' % i, True, TrParameterType.BOOLEAN, False,
408 )
409 PARAMETERS[ParameterName.PLMN_N_PLMNID % i] = TrParam(
410 FAPSERVICE_PATH + 'CellConfig.LTE.EPC.PLMNList.%d.PLMNID' % i, True, TrParameterType.STRING, False,
411 )
412
413 TRANSFORMS_FOR_ENB = {
414 ParameterName.DL_BANDWIDTH: transform_for_enb.bandwidth,
415 ParameterName.UL_BANDWIDTH: transform_for_enb.bandwidth,
416 }
417 TRANSFORMS_FOR_MAGMA = {
418 ParameterName.DL_BANDWIDTH: transform_for_magma.bandwidth,
419 ParameterName.UL_BANDWIDTH: transform_for_magma.bandwidth,
420 # We don't set GPS, so we don't need transform for enb
421 ParameterName.GPS_LAT: transform_for_magma.gps_tr181,
422 ParameterName.GPS_LONG: transform_for_magma.gps_tr181,
423 }
424
425 @classmethod
426 def get_parameter(cls, param_name: ParameterName) -> Optional[TrParam]:
427 return cls.PARAMETERS.get(param_name)
428
429 @classmethod
430 def _get_magma_transforms(
431 cls,
432 ) -> Dict[ParameterName, Callable[[Any], Any]]:
433 return cls.TRANSFORMS_FOR_MAGMA
434
435 @classmethod
436 def _get_enb_transforms(cls) -> Dict[ParameterName, Callable[[Any], Any]]:
437 return cls.TRANSFORMS_FOR_ENB
438
439 @classmethod
440 def get_load_parameters(cls) -> List[ParameterName]:
441 """
442 Load all the parameters instead of a subset.
443 """
444 return [ParameterName.DEVICE]
445
446 @classmethod
447 def get_num_plmns(cls) -> int:
448 return cls.NUM_PLMNS_IN_CONFIG
449
450 @classmethod
451 def get_parameter_names(cls) -> List[ParameterName]:
452 excluded_params = [
453 str(ParameterName.DEVICE),
454 str(ParameterName.FAP_SERVICE),
455 ]
456 names = list(
457 filter(
458 lambda x: (not str(x).startswith('PLMN'))
459 and (str(x) not in excluded_params),
460 cls.PARAMETERS.keys(),
461 ),
462 )
463 return names
464
465 @classmethod
466 def get_numbered_param_names(
467 cls,
468 ) -> Dict[ParameterName, List[ParameterName]]:
469 names = {}
470 for i in range(1, cls.NUM_PLMNS_IN_CONFIG + 1):
471 params = []
472 params.append(ParameterName.PLMN_N_CELL_RESERVED % i)
473 params.append(ParameterName.PLMN_N_ENABLE % i)
474 params.append(ParameterName.PLMN_N_PRIMARY % i)
475 params.append(ParameterName.PLMN_N_PLMNID % i)
476 names[ParameterName.PLMN_N % i] = params
477 return names
478
479
480class CaviumTrConfigurationInitializer(EnodebConfigurationPostProcessor):
Wei-Yu Chen8d064162022-05-27 21:06:55 +0800481 def postprocess(self, desired_cfg: EnodebConfiguration) -> None:
Wei-Yu Chen49950b92021-11-08 19:19:18 +0800482 desired_cfg.set_parameter(ParameterName.CELL_BARRED, True)
483 desired_cfg.set_parameter(ParameterName.ADMIN_STATE, True)