AETHER-2846 Support all parameters which lists in Aether Docs
AETHER-2847 Integrating with Prometheus and record eNB information
AETHER-2848 Move SAS configuration as enodeb base, not plugin in driver code
AETHER-2879 add gps information in prometheus
AETHER-2880 add ip and port as configurable parameter in enodebd
AETHER-2897 Firmware update feature over CWMP
AETHER-3022 Integrate firmware upgrade state into configuration workflow
AETHER-3120 Develop ACS state machine with firmware upgrade feature
Change-Id: I0bcbf2229ba3c1638f2a997f3c651f8d6240145d
diff --git a/.gitignore b/.gitignore
index 200ed83..bbd439d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,8 +1,12 @@
lte/
orc8r/
+prometheus.yml
metrics_pb2.py
metrics_pb2_grpc.py
+### Log ###
+*.log
+
### Python ###
# Byte-compiled / optimized / DLL files
__pycache__/
diff --git a/README.md b/README.md
index 60b0c16..a176859 100644
--- a/README.md
+++ b/README.md
@@ -2,6 +2,13 @@
eNodeB daemon is an Automatic Configuration Server (ACS) which forks from [Facebook Magma project](https://github.com/magma/magma). It currently tested with Sercomm eNodeB P27-SCE4255W small cell.
+# Run
+
+```
+make venv
+python main.py
+```
+
# Configuration
We have these configuration files for configuring eNodeBD service.
@@ -17,4 +24,29 @@
3. magma_configs/serial_numbers/_2009CW5000019_.yml
-The `serial_number.yml` will have the customized value for each configurable parameters. The value in `serial_number.yml` will override the value defines in `gateway.mconfig` and `acs_common.yml` when corresponding eNodeB connects (base on the serial number provided by eNodeB).
\ No newline at end of file
+The `serial_number.yml` will have the customized value for each configurable parameters. The value in `serial_number.yml` will override the value defines in `gateway.mconfig` and `acs_common.yml` when corresponding eNodeB connects (base on the serial number provided by eNodeB).
+
+# Prometheus Support
+
+The following example configuration can start a Prometheus container for monitoring data sent by enodebd. The enodebd will start prometheus server on port 8000 by default.
+
+```bash
+# prometheus configuration - prometheus.yml
+global:
+ scrape_interval: 15s
+ external_labels:
+ monitor: 'codelab-monitor'
+
+scrape_configs:
+ - job_name: 'prometheus'
+ scrape_interval: 5s
+ static_configs:
+ - targets: ['172.17.0.1:8000']
+```
+
+... and start prometheus container with docker command.
+
+```
+$ docker run -p 9090:9090 -v /home/ubuntu/magma-enodebd-new/prometheus.yml:/etc/prometheus/prometheus.yml prom/prometheus
+```
+
diff --git a/common/cert_utils.py b/common/cert_utils.py
index 3be5284..e19063f 100644
--- a/common/cert_utils.py
+++ b/common/cert_utils.py
@@ -20,6 +20,25 @@
from common.serialization_utils import write_to_file_atomically
+def load_key_bytes(key_file):
+ """Load a private key encoded in PEM format
+
+ Args:
+ key_file: path to the key file
+
+ Returns:
+ Bytes
+
+ Raises:
+ IOError: If file cannot be opened
+ ValueError: If the file content cannot be decoded successfully
+ TypeError: If the key_file is encrypted
+ """
+ with open(key_file, 'rb') as f:
+ key_bytes = f.read()
+
+ return key_bytes
+
def load_key(key_file):
"""Load a private key encoded in PEM format
@@ -128,6 +147,23 @@
return csr
+def load_cert_bytes(cert_file):
+ """Load certificate from a file
+
+ Args:
+ cert_file: path to file storing the cert in PEM format
+
+ Returns:
+ cert: an instance of x509.Certificate
+
+ Raises:
+ IOError: If file cannot be opened
+ ValueError: If the file content cannot be decoded successfully
+ """
+ with open(cert_file, 'rb') as f:
+ cert_pem = f.read()
+
+ return cert_pem
def load_cert(cert_file):
"""Load certificate from a file
diff --git a/common/service.py b/common/service.py
index 5a3ca98..59f06ca 100644
--- a/common/service.py
+++ b/common/service.py
@@ -230,6 +230,7 @@
is received or a StopService rpc call is made on the Service303
interface.
"""
+
logging.info("Starting %s...", self._name)
(host, port) = ServiceRegistry.get_service_address(self._name)
self._port = self._server.add_insecure_port('{}:{}'.format(host, port))
diff --git a/data_models/data_model_parameters.py b/data_models/data_model_parameters.py
index 27df4d9..751b351 100644
--- a/data_models/data_model_parameters.py
+++ b/data_models/data_model_parameters.py
@@ -31,20 +31,37 @@
SERIAL_NUMBER = 'Serial number'
CELL_ID = 'Cell ID'
+ IP_ADDRESS = "ip_address"
# Capabilities
DUPLEX_MODE_CAPABILITY = 'Duplex mode capability'
BAND_CAPABILITY = 'Band capability'
# RF-related parameters
- EARFCNDL = 'EARFCNDL'
- EARFCNUL = 'EARFCNUL'
+ EARFCNDL = 'earfcndl1'
+ EARFCNUL = 'earfcnul1'
+ EARFCNDL2 = 'earfcndl2'
+ EARFCNUL2 = 'earfcnul2'
+ EARFCNDL_LIST = 'earfcndl_list'
+ EARFCNUL_LIST = 'earfcnul_list'
+
+ FREQ_BAND_1 = "freq_band_1"
+ FREQ_BAND_2 = "freq_band_2"
+ FREQ_BAND_LIST = "freq_band_list"
+
BAND = 'Band'
PCI = 'PCI'
DL_BANDWIDTH = 'DL bandwidth'
UL_BANDWIDTH = 'UL bandwidth'
SUBFRAME_ASSIGNMENT = 'Subframe assignment'
SPECIAL_SUBFRAME_PATTERN = 'Special subframe pattern'
+ TX_POWER = "tx_power"
+ TUNNEL_TYPE = "tunnel_type"
+
+ # Radio Resource Management (RRM) parameters
+ CARRIER_AGG_ENABLE = "carrier_agg_enable"
+ CARRIER_NUMBER = "carrier_number"
+ CONTIGUOUS_CC = "contiguous_cc"
# Other LTE parameters
ADMIN_STATE = 'Admin state'
@@ -54,6 +71,7 @@
# RAN parameters
CELL_RESERVED = 'Cell reserved'
CELL_BARRED = 'Cell barred'
+ PRIM_SOURCE = "prim_source"
# Core network parameters
MME_IP = 'MME IP'
@@ -70,13 +88,15 @@
PLMN_N_PLMNID = 'PLMN %d PLMNID'
# PLMN arrays are added below
- TAC = 'TAC'
+ TAC = 'tac'
+ TAC2 = 'tac2'
IP_SEC_ENABLE = 'IPSec enable'
MME_POOL_ENABLE = 'MME pool enable'
# Management server parameters
PERIODIC_INFORM_ENABLE = 'Periodic inform enable'
PERIODIC_INFORM_INTERVAL = 'Periodic inform interval'
+ ENABLE_CWMP = "enable_cwmp"
# Performance management parameters
PERF_MGMT_ENABLE = 'Perf mgmt enable'
@@ -85,6 +105,33 @@
PERF_MGMT_USER = 'Perf mgmt username'
PERF_MGMT_PASSWORD = 'Perf mgmt password'
+ SAS_ENABLE = "sas_enabled"
+ SAS_SERVER_URL = "sas_server_url"
+ SAS_UID = "sas_uid"
+ SAS_CATEGORY = "sas_category"
+ SAS_CHANNEL_TYPE = "sas_channel_type"
+ SAS_CERT_SUBJECT = "sas_cert_subject"
+ SAS_IC_GROUP_ID = "sas_icg_group_id"
+ SAS_LOCATION = "sas_location"
+ SAS_HEIGHT_TYPE = "sas_height_type"
+ SAS_FCCID = "sas_fccid"
+ SAS_MEAS_CAPS = "sas_measure_capability"
+ SAS_MANU_ENABLE = "sas_manufacturer_prefix_enable"
+
+ SAS_CPI_ENABLE = "sas_cpi_enable"
+ SAS_CPI_IPE = "sas_cpi_ipe"
+ SAS_CPI_NAME = "sas_cpi_name"
+ SAS_CPI_ID = "sas_cpi_id"
+ SAS_CPI_DATA = "sas_cpi_signature_data"
+ SAS_ANTA_AZIMUTH = "sas_antenna_azimuth"
+ SAS_ANTA_DOWNTILT = "sas_antenna_downtilt"
+ SAS_ANTA_GAIN = "sas_antenna_gain"
+ SAS_ANTA_BEAMWIDTH = "sas_antenna_beamwidth"
+
+ FIRMWARE_VERSION = "firmware_version"
+ FIRMWARE_URL = "firmware_url"
+ FIRMWARE_SIZE = "firmware_size"
+
class TrParameterType():
BOOLEAN = 'boolean'
diff --git a/device_config/configuration_init.py b/device_config/configuration_init.py
index 4b156df..2c4e342 100644
--- a/device_config/configuration_init.py
+++ b/device_config/configuration_init.py
@@ -91,6 +91,8 @@
enb_config = _get_enb_yang_config(device_config) or \
_get_enb_config(mconfig, device_config)
+ print(enb_config)
+
_set_earfcn_freq_band_mode(
device_config, cfg_desired, data_model,
enb_config.earfcndl,
@@ -190,7 +192,6 @@
mconfig: mconfigs_pb2.EnodebD,
device_config: EnodebConfiguration,
) -> SingleEnodebConfig:
-
# The eNodeB parameters to be generated with default value,
# It will load from eNB configs based on serial number or default value
# The params is a nested list which contains 2 format of parameter names.
@@ -237,8 +238,13 @@
Set the following parameters:
- PCI
"""
- if pci not in range(0, 504 + 1):
+
+ if pci is int and pci not in range(0, 504 + 1):
raise ConfigurationError('Invalid PCI (%d)' % pci)
+
+ if pci is str and any(map(lambda x: int(x) not in range(0, 504 + 1), pci.split(","))):
+ raise ConfigurationError('Invalid PCI (%s)' % pci)
+
cfg.set_parameter(ParameterName.PCI, pci)
diff --git a/devices/freedomfi_one.py b/devices/freedomfi_one.py
index bfa66eb..4dfee90 100644
--- a/devices/freedomfi_one.py
+++ b/devices/freedomfi_one.py
@@ -48,6 +48,9 @@
EndSessionState,
EnodebAcsState,
ErrorState,
+ DownloadState,
+ WaitDownloadResponseState,
+ WaitInformTransferCompleteState,
GetParametersState,
SetParameterValuesState,
WaitGetParametersState,
@@ -59,113 +62,239 @@
from tr069 import models
+FAPSERVICE_PATH = "Device.Services.FAPService.1."
+FAP_CONTROL = FAPSERVICE_PATH + "FAPControl."
+
+
+class FreedomFiOneHandler(BasicEnodebAcsStateMachine):
+ def __init__(self, service: MagmaService,) -> None:
+ self._state_map = {}
+ super().__init__(service=service, use_param_key=True)
+
+ def reboot_asap(self) -> None:
+ self.transition("reboot")
+
+ def is_enodeb_connected(self) -> bool:
+ return not isinstance(self.state, WaitInformState)
+
+ def _init_state_map(self) -> None:
+ self._state_map = {
+ # Inform comes in -> Respond with InformResponse
+ "wait_inform": WaitInformState(self, when_done="get_rpc_methods"),
+ # If first inform after boot -> GetRpc request comes in, if not
+ # empty request comes in => Transition to get_transient_params
+ "get_rpc_methods": FreedomFiOneGetInitState(
+ self, when_done="get_transient_params",
+ ),
+ # Read transient readonly params.
+ "get_transient_params": FreedomFiOneSendGetTransientParametersState(
+ self, when_upgrade="firmware_upgrade", when_done="get_params",
+ ),
+ "firmware_upgrade": DownloadState(self, when_done="wait_download_response"),
+ "wait_download_response": WaitDownloadResponseState(
+ self, when_done="wait_transfer_complete"
+ ),
+ "wait_transfer_complete": WaitInformTransferCompleteState(
+ self,
+ when_done="get_params",
+ when_periodic="wait_transfer_complete",
+ when_timeout="end_session",
+ ),
+ "get_params": FreedomFiOneGetObjectParametersState(
+ self,
+ when_delete="delete_objs",
+ when_add="add_objs",
+ when_set="set_params",
+ when_skip="end_session",
+ ),
+ "delete_objs": DeleteObjectsState(
+ self, when_add="add_objs", when_skip="set_params",
+ ),
+ "add_objs": AddObjectsState(self, when_done="set_params"),
+ "set_params": SetParameterValuesState(self, when_done="wait_set_params",),
+ "wait_set_params": WaitSetParameterValuesState(
+ self,
+ when_done="check_get_params",
+ when_apply_invasive="check_get_params",
+ status_non_zero_allowed=True,
+ ),
+ "check_get_params": GetParametersState(
+ self, when_done="check_wait_get_params", request_all_params=True,
+ ),
+ "check_wait_get_params": WaitGetParametersState(
+ self, when_done="end_session",
+ ),
+ "end_session": EndSessionState(self),
+ # These states are only entered through manual user intervention
+ "reboot": EnbSendRebootState(self, when_done="wait_reboot"),
+ "wait_reboot": WaitRebootResponseState(
+ self, when_done="wait_post_reboot_inform",
+ ),
+ "wait_post_reboot_inform": WaitInformMRebootState(
+ self, when_done="wait_empty", when_timeout="wait_inform",
+ ),
+ # The states below are entered when an unexpected message type is
+ # received
+ "unexpected_fault": ErrorState(
+ self, inform_transition_target="wait_inform",
+ ),
+ }
+
+ @property
+ def device_name(self) -> str:
+ return EnodebDeviceName.FREEDOMFI_ONE
+
+ @property
+ def data_model_class(self) -> Type[DataModel]:
+ return FreedomFiOneTrDataModel
+
+ @property
+ def config_postprocessor(self) -> EnodebConfigurationPostProcessor:
+ return FreedomFiOneConfigurationInitializer(self)
+
+ @property
+ def state_map(self) -> Dict[str, EnodebAcsState]:
+ return self._state_map
+
+ @property
+ def disconnected_state_name(self) -> str:
+ return "wait_inform"
+
+ @property
+ def unexpected_fault_state_name(self) -> str:
+ return "unexpected_fault"
+
+
class SASParameters:
""" Class modeling the SAS parameters and their TR path"""
- # SAS parameters for FreedomFiOne
- FAP_CONTROL = "Device.Services.FAPService.1.FAPControl."
- FAPSERVICE_PATH = "Device.Services.FAPService.1."
-
- # Sas management parameters
- SAS_ENABLE = "sas_enabled"
- SAS_SERVER_URL = "sas_server_url"
- SAS_UID = "sas_uid"
- SAS_CATEGORY = "sas_category"
- SAS_CHANNEL_TYPE = "sas_channel_type"
- SAS_CERT_SUBJECT = "sas_cert_subject"
- SAS_IC_GROUP_ID = "sas_icg_group_id"
- SAS_LOCATION = "sas_location"
- SAS_HEIGHT_TYPE = "sas_height_type"
- SAS_CPI_ENABLE = "sas_cpi_enable"
- SAS_CPI_IPE = "sas_cpi_ipe" # Install param supplied enable
- FREQ_BAND_1 = "freq_band_1"
- FREQ_BAND_2 = "freq_band_2"
# For CBRS radios we set this to the limit and the SAS can reduce the
# power if needed.
- TX_POWER_CONFIG = "tx_power_config"
SAS_PARAMETERS = {
- SAS_ENABLE: TrParam(
- FAP_CONTROL + "LTE.X_000E8F_SAS.Enable",
+ ParameterName.SAS_ENABLE: TrParam(
+ FAP_CONTROL + "LTE.X_SCM_SAS.Enable",
is_invasive=False,
type=TrParameterType.BOOLEAN,
is_optional=False,
),
- SAS_SERVER_URL: TrParam(
- FAP_CONTROL + "LTE.X_000E8F_SAS.Server",
+ ParameterName.SAS_SERVER_URL: TrParam(
+ FAP_CONTROL + "LTE.X_SCM_SAS.Server",
is_invasive=False,
type=TrParameterType.STRING,
is_optional=False,
),
- SAS_UID: TrParam(
- FAP_CONTROL + "LTE.X_000E8F_SAS.UserContactInformation",
+ ParameterName.SAS_UID: TrParam(
+ FAP_CONTROL + "LTE.X_SCM_SAS.UserContactInformation",
is_invasive=False,
type=TrParameterType.STRING,
is_optional=False,
),
- SAS_CATEGORY: TrParam(
- FAP_CONTROL + "LTE.X_000E8F_SAS.Category",
+ ParameterName.SAS_CATEGORY: TrParam(
+ FAP_CONTROL + "LTE.X_SCM_SAS.Category",
is_invasive=False,
type=TrParameterType.STRING,
is_optional=False,
),
- SAS_CHANNEL_TYPE: TrParam(
- FAP_CONTROL + "LTE.X_000E8F_SAS.ProtectionLevel",
+ ParameterName.SAS_CHANNEL_TYPE: TrParam(
+ FAP_CONTROL + "LTE.X_SCM_SAS.ProtectionLevel",
is_invasive=False,
type=TrParameterType.STRING,
is_optional=False,
),
- SAS_CERT_SUBJECT: TrParam(
- FAP_CONTROL + "LTE.X_000E8F_SAS.CertSubject",
+ ParameterName.SAS_CERT_SUBJECT: TrParam(
+ FAP_CONTROL + "LTE.X_SCM_SAS.CertSubject",
is_invasive=False,
type=TrParameterType.STRING,
is_optional=False,
),
# SAS_IC_GROUP_ID: TrParam(
- # FAP_CONTROL + 'LTE.X_000E8F_SAS.ICGGroupId', is_invasive=False,
+ # FAP_CONTROL + 'LTE.X_SCM_SAS.ICGGroupId', is_invasive=False,
# type=TrParameterType.STRING, False),
- SAS_LOCATION: TrParam(
- FAP_CONTROL + "LTE.X_000E8F_SAS.Location",
+ ParameterName.SAS_LOCATION: TrParam(
+ FAP_CONTROL + "LTE.X_SCM_SAS.Location",
is_invasive=False,
type=TrParameterType.STRING,
is_optional=False,
),
- SAS_HEIGHT_TYPE: TrParam(
- FAP_CONTROL + "LTE.X_000E8F_SAS.HeightType",
+ ParameterName.SAS_HEIGHT_TYPE: TrParam(
+ FAP_CONTROL + "LTE.X_SCM_SAS.HeightType",
is_invasive=False,
type=TrParameterType.STRING,
is_optional=False,
),
- SAS_CPI_ENABLE: TrParam(
- FAP_CONTROL + "LTE.X_000E8F_SAS.CPIEnable",
+ ParameterName.SAS_CPI_ENABLE: TrParam(
+ FAP_CONTROL + "LTE.X_SCM_SAS.CPIEnable",
is_invasive=False,
type=TrParameterType.BOOLEAN,
is_optional=False,
),
- SAS_CPI_IPE: TrParam(
- FAP_CONTROL + "LTE.X_000E8F_SAS.CPIInstallParamSuppliedEnable",
+ ParameterName.SAS_CPI_IPE: TrParam(
+ FAP_CONTROL + "LTE.X_SCM_SAS.CPIInstallParamSuppliedEnable",
is_invasive=False,
type=TrParameterType.BOOLEAN,
is_optional=False,
),
- FREQ_BAND_1: TrParam(
- FAPSERVICE_PATH + "CellConfig.LTE.RAN.RF.FreqBandIndicator",
+ ParameterName.SAS_FCCID: TrParam(
+ FAP_CONTROL + "LTE.X_SCM_SAS.FCCIdentificationNumber",
is_invasive=False,
- type=TrParameterType.UNSIGNED_INT,
+ type=TrParameterType.STRING,
is_optional=False,
),
- FREQ_BAND_2: TrParam(
- FAPSERVICE_PATH + "CellConfig.LTE.RAN.RF.X_000E8F_FreqBandIndicator2",
+ ParameterName.SAS_MEAS_CAPS: TrParam(
+ FAP_CONTROL + "LTE.X_SCM_SAS.MeasCapability",
is_invasive=False,
- type=TrParameterType.UNSIGNED_INT,
+ type=TrParameterType.STRING,
is_optional=False,
),
- TX_POWER_CONFIG: TrParam(
- FAPSERVICE_PATH + "CellConfig.LTE.RAN.RF.X_000E8F_TxPowerConfig",
- is_invasive=True,
+ ParameterName.SAS_MANU_ENABLE: TrParam(
+ FAP_CONTROL + "LTE.X_SCM_SAS.ManufacturerPrefixEnable",
+ is_invasive=False,
+ type=TrParameterType.BOOLEAN,
+ is_optional=False,
+ ),
+ ParameterName.SAS_CPI_NAME: TrParam(
+ FAP_CONTROL + "LTE.X_SCM_SAS.CPIName",
+ is_invasive=False,
+ type=TrParameterType.STRING,
+ is_optional=False,
+ ),
+ ParameterName.SAS_CPI_ID: TrParam(
+ FAP_CONTROL + "LTE.X_SCM_SAS.CPIId",
+ is_invasive=False,
+ type=TrParameterType.STRING,
+ is_optional=False,
+ ),
+ ParameterName.SAS_ANTA_AZIMUTH: TrParam(
+ FAP_CONTROL + "LTE.X_SCM_SAS.AntennaAzimuth",
+ is_invasive=False,
type=TrParameterType.INT,
is_optional=False,
),
+ ParameterName.SAS_ANTA_DOWNTILT: TrParam(
+ FAP_CONTROL + "LTE.X_SCM_SAS.AntennaDowntilt",
+ is_invasive=False,
+ type=TrParameterType.INT,
+ is_optional=False,
+ ),
+ ParameterName.SAS_ANTA_GAIN: TrParam(
+ FAP_CONTROL + "LTE.X_SCM_SAS.AntennaGain",
+ is_invasive=False,
+ type=TrParameterType.INT,
+ is_optional=False,
+ ),
+ ParameterName.SAS_ANTA_BEAMWIDTH: TrParam(
+ FAP_CONTROL + "LTE.X_SCM_SAS.AntennaBeamwidth",
+ is_invasive=False,
+ type=TrParameterType.INT,
+ is_optional=False,
+ ),
+ ParameterName.SAS_CPI_DATA: TrParam(
+ FAP_CONTROL + "LTE.X_SCM_SAS.CPISignatureData",
+ is_invasive=False,
+ type=TrParameterType.STRING,
+ is_optional=False,
+ ),
}
@@ -177,10 +306,6 @@
and converting it to Magma understood fields.
"""
- DEFGW_STATUS_PATH = "Device.X_SCM_DeviceFeature.X_SCM_NEStatus.X_SCM_DEFGW_Status"
- SAS_STATUS_PATH = "Device.Services.FAPService.1.FAPControl.LTE.X_SCM_SAS.State"
- ENB_STATUS_PATH = "Device.X_SCM_DeviceFeature.X_SCM_NEStatus.X_SCM_eNB_Status"
-
# Status parameters
DEFAULT_GW = "defaultGW"
SYNC_STATUS = "syncStatus"
@@ -190,30 +315,18 @@
STATUS_PARAMETERS = {
# Status nodes
- # This works
DEFAULT_GW: TrParam(
- DEFGW_STATUS_PATH,
+ "Device.X_SCM_DeviceFeature.X_SCM_NEStatus.X_SCM_DEFGW_Status",
is_invasive=False,
type=TrParameterType.STRING,
is_optional=False,
),
- # SYNC_STATUS: TrParam(
- # STATUS_PATH + 'X_000E8F_Sync_Status', is_invasive=False,
- # type=TrParameterType.STRING, is_optional=False,
- # ),
- # This works
SAS_STATUS: TrParam(
- SAS_STATUS_PATH,
+ "Device.Services.FAPService.1.FAPControl.LTE.X_SCM_SAS.State",
is_invasive=False,
type=TrParameterType.STRING,
is_optional=False,
),
- # This doesn't work
- # ENB_STATUS: TrParam(
- # ENB_STATUS_PATH, is_invasive=False,
- # type=TrParameterType.STRING, is_optional=False,
- # ),
- # GPS status, lat, long
GPS_SCAN_STATUS: TrParam(
"Device.FAP.GPS.ScanStatus",
is_invasive=False,
@@ -232,6 +345,18 @@
type=TrParameterType.STRING,
is_optional=False,
),
+ ParameterName.SW_VERSION: TrParam(
+ "Device.DeviceInfo.SoftwareVersion",
+ is_invasive=False,
+ type=TrParameterType.STRING,
+ is_optional=False,
+ ),
+ ParameterName.SERIAL_NUMBER: TrParam(
+ "Device.DeviceInfo.SerialNumber",
+ is_invasive=False,
+ type=TrParameterType.STRING,
+ is_optional=False,
+ ),
}
# Derived status params that don't have tr69 representation.
@@ -374,6 +499,8 @@
)
pass_through_params = [ParameterName.GPS_LAT, ParameterName.GPS_LONG]
+
+ print(name_to_val)
for name in pass_through_params:
device_cfg.set_parameter(name, name_to_val[name])
@@ -384,159 +511,39 @@
miscellaneous properties
"""
- FAP_CONTROL = "Device.Services.FAPService.1.FAPControl."
- FAPSERVICE_PATH = "Device.Services.FAPService.1."
-
- # Tunnel ref format clobber it to non IPSEC as we don't support
- # IPSEC
- TUNNEL_REF = "tunnel_ref"
- PRIM_SOURCE = "prim_src"
-
- # Carrier aggregation
- CARRIER_AGG_ENABLE = "carrier_agg_enable"
- CARRIER_NUMBER = "carrier_number" # Carrier aggregation params
- CONTIGUOUS_CC = "contiguous_cc"
- WEB_UI_ENABLE = "web_ui_enable" # Enable or disable local enb UI
-
MISC_PARAMETERS = {
- # WEB_UI_ENABLE: TrParam(
- # 'Device.X_000E8F_DeviceFeature.X_000E8F_WebServerEnable',
- # is_invasive=False,
- # type=TrParameterType.BOOLEAN, is_optional=False,
- # ),
- CARRIER_AGG_ENABLE: TrParam(
- FAP_CONTROL + "LTE.X_000E8F_RRMConfig.X_000E8F_CA_Enable",
+ ParameterName.CARRIER_AGG_ENABLE: TrParam(
+ FAP_CONTROL + "LTE.X_SCM_RRMConfig.X_SCM_CA_Enable",
is_invasive=False,
type=TrParameterType.BOOLEAN,
is_optional=False,
),
- CARRIER_NUMBER: TrParam(
- FAP_CONTROL + "LTE.X_000E8F_RRMConfig.X_000E8F_Cell_Number",
+ ParameterName.CARRIER_NUMBER: TrParam(
+ FAP_CONTROL + "LTE.X_SCM_RRMConfig.X_SCM_Cell_Number",
is_invasive=False,
type=TrParameterType.INT,
is_optional=False,
),
- CONTIGUOUS_CC: TrParam(
- FAP_CONTROL + "LTE.X_000E8F_RRMConfig.X_000E8F_CELL_Freq_Contiguous",
+ ParameterName.CONTIGUOUS_CC: TrParam(
+ FAP_CONTROL + "LTE.X_SCM_RRMConfig.X_SCM_CELL_Freq_Contiguous",
is_invasive=False,
type=TrParameterType.INT,
is_optional=False,
),
- TUNNEL_REF: TrParam(
- FAPSERVICE_PATH + "CellConfig.LTE.Tunnel.1.TunnelRef",
+ ParameterName.PRIM_SOURCE: TrParam(
+ FAPSERVICE_PATH + "REM.X_SCM_tfcsManagerConfig.primSrc",
is_invasive=False,
type=TrParameterType.STRING,
is_optional=False,
),
- PRIM_SOURCE: TrParam(
- FAPSERVICE_PATH + "REM.X_000E8F_tfcsManagerConfig.primSrc",
+ ParameterName.ENABLE_CWMP: TrParam(
+ "Device.ManagementServer.EnableCWMP",
is_invasive=False,
- type=TrParameterType.STRING,
+ type=TrParameterType.BOOLEAN,
is_optional=False,
),
}
- # Hardcoded defaults
- defaults = {
- # Use IPV4 only
- TUNNEL_REF: "Device.IP.Interface.1.IPv4Address.1.",
- # Only synchronize with GPS
- PRIM_SOURCE: "FREE_RUNNING",
- # Always enable carrier aggregation for the CBRS bands
- CARRIER_AGG_ENABLE: False,
- CARRIER_NUMBER: 1, # CBRS has two carriers
- CONTIGUOUS_CC: 0, # Its not contiguous carrier
- }
-
-
-class FreedomFiOneHandler(BasicEnodebAcsStateMachine):
- def __init__(self, service: MagmaService,) -> None:
- self._state_map = {}
- super().__init__(service=service, use_param_key=True)
-
- def reboot_asap(self) -> None:
- self.transition("reboot")
-
- def is_enodeb_connected(self) -> bool:
- return not isinstance(self.state, WaitInformState)
-
- def _init_state_map(self) -> None:
- self._state_map = {
- # Inform comes in -> Respond with InformResponse
- "wait_inform": WaitInformState(self, when_done="get_rpc_methods"),
- # If first inform after boot -> GetRpc request comes in, if not
- # empty request comes in => Transition to get_transient_params
- "get_rpc_methods": FreedomFiOneGetInitState(
- self, when_done="get_transient_params",
- ),
- # Read transient readonly params.
- "get_transient_params": FreedomFiOneSendGetTransientParametersState(
- self, when_done="get_params",
- ),
- "get_params": FreedomFiOneGetObjectParametersState(
- self,
- when_delete="delete_objs",
- when_add="add_objs",
- when_set="set_params",
- when_skip="end_session",
- ),
- "delete_objs": DeleteObjectsState(
- self, when_add="add_objs", when_skip="set_params",
- ),
- "add_objs": AddObjectsState(self, when_done="set_params"),
- "set_params": SetParameterValuesState(self, when_done="wait_set_params",),
- "wait_set_params": WaitSetParameterValuesState(
- self,
- when_done="check_get_params",
- when_apply_invasive="check_get_params",
- status_non_zero_allowed=True,
- ),
- "check_get_params": GetParametersState(
- self, when_done="check_wait_get_params", request_all_params=True,
- ),
- "check_wait_get_params": WaitGetParametersState(
- self, when_done="end_session",
- ),
- "end_session": EndSessionState(self),
- # These states are only entered through manual user intervention
- "reboot": EnbSendRebootState(self, when_done="wait_reboot"),
- "wait_reboot": WaitRebootResponseState(
- self, when_done="wait_post_reboot_inform",
- ),
- "wait_post_reboot_inform": WaitInformMRebootState(
- self, when_done="wait_empty", when_timeout="wait_inform",
- ),
- # The states below are entered when an unexpected message type is
- # received
- "unexpected_fault": ErrorState(
- self, inform_transition_target="wait_inform",
- ),
- }
-
- @property
- def device_name(self) -> str:
- return EnodebDeviceName.FREEDOMFI_ONE
-
- @property
- def data_model_class(self) -> Type[DataModel]:
- return FreedomFiOneTrDataModel
-
- @property
- def config_postprocessor(self) -> EnodebConfigurationPostProcessor:
- return FreedomFiOneConfigurationInitializer(self)
-
- @property
- def state_map(self) -> Dict[str, EnodebAcsState]:
- return self._state_map
-
- @property
- def disconnected_state_name(self) -> str:
- return "wait_inform"
-
- @property
- def unexpected_fault_state_name(self) -> str:
- return "unexpected_fault"
-
class FreedomFiOneTrDataModel(DataModel):
"""
@@ -555,16 +562,10 @@
- Num PLMNs is not reported by these units
"""
- # Mapping of TR parameter paths to aliases
- DEVICE_PATH = "Device."
- FAPSERVICE_PATH = DEVICE_PATH + "Services.FAPService.1."
- FAP_CONTROL = FAPSERVICE_PATH + "FAPControl."
- BCCH = FAPSERVICE_PATH + "REM.LTE.Cell.1.BCCH."
-
PARAMETERS = {
# Top-level objects
ParameterName.DEVICE: TrParam(
- DEVICE_PATH,
+ "Device.",
is_invasive=False,
type=TrParameterType.OBJECT,
is_optional=False,
@@ -576,25 +577,67 @@
is_optional=False,
),
# Device info
- ParameterName.SW_VERSION: TrParam(
- DEVICE_PATH + "DeviceInfo.SoftwareVersion",
- is_invasive=False,
- type=TrParameterType.STRING,
- is_optional=False,
- ),
- ParameterName.SERIAL_NUMBER: TrParam(
- DEVICE_PATH + "DeviceInfo.SerialNumber",
+ ParameterName.IP_ADDRESS: TrParam(
+ "Device.IP.Interface.1.IPv4Address.1.IPAddress",
is_invasive=False,
type=TrParameterType.STRING,
is_optional=False,
),
# RF-related parameters
+ ParameterName.FREQ_BAND_1: TrParam(
+ FAPSERVICE_PATH + "CellConfig.LTE.RAN.RF.FreqBandIndicator",
+ is_invasive=False,
+ type=TrParameterType.UNSIGNED_INT,
+ is_optional=False,
+ ),
+ ParameterName.FREQ_BAND_2: TrParam(
+ FAPSERVICE_PATH + "CellConfig.LTE.RAN.RF.X_SCM_FreqBandIndicator2",
+ is_invasive=False,
+ type=TrParameterType.UNSIGNED_INT,
+ is_optional=False,
+ ),
+ ParameterName.FREQ_BAND_LIST: TrParam(
+ FAPSERVICE_PATH + "CellConfig.LTE.RAN.RF.X_SCM_FreqBandIndicatorConfigList",
+ is_invasive=False,
+ type=TrParameterType.STRING,
+ is_optional=False,
+ ),
ParameterName.EARFCNDL: TrParam(
FAPSERVICE_PATH + "CellConfig.LTE.RAN.RF.EARFCNDL",
is_invasive=False,
type=TrParameterType.INT,
is_optional=False,
),
+ ParameterName.EARFCNUL: TrParam(
+ FAPSERVICE_PATH + "CellConfig.LTE.RAN.RF.EARFCNUL",
+ is_invasive=False,
+ type=TrParameterType.INT,
+ is_optional=False,
+ ),
+ ParameterName.EARFCNDL2: TrParam(
+ FAPSERVICE_PATH + "CellConfig.LTE.RAN.RF.X_SCM_EARFCNDL2",
+ is_invasive=False,
+ type=TrParameterType.INT,
+ is_optional=False,
+ ),
+ ParameterName.EARFCNUL2: TrParam(
+ FAPSERVICE_PATH + "CellConfig.LTE.RAN.RF.X_SCM_EARFCNUL2",
+ is_invasive=False,
+ type=TrParameterType.INT,
+ is_optional=False,
+ ),
+ ParameterName.EARFCNDL_LIST: TrParam(
+ FAPSERVICE_PATH + "CellConfig.LTE.RAN.RF.X_SCM_EARFCNDLConfigList",
+ is_invasive=False,
+ type=TrParameterType.STRING,
+ is_optional=False,
+ ),
+ ParameterName.EARFCNUL_LIST: TrParam(
+ FAPSERVICE_PATH + "CellConfig.LTE.RAN.RF.X_SCM_EARFCNULConfigList",
+ is_invasive=False,
+ type=TrParameterType.STRING,
+ is_optional=False,
+ ),
ParameterName.DL_BANDWIDTH: TrParam(
FAPSERVICE_PATH + "CellConfig.LTE.RAN.RF.DLBandwidth",
is_invasive=False,
@@ -639,7 +682,7 @@
is_optional=False,
),
ParameterName.GPS_ENABLE: TrParam(
- DEVICE_PATH + "FAP.GPS.ScanOnBoot",
+ "Device.FAP.GPS.ScanOnBoot",
is_invasive=False,
type=TrParameterType.BOOLEAN,
is_optional=False,
@@ -657,46 +700,58 @@
type=TrParameterType.INT,
is_optional=False,
),
- # It may not work, comment out first
- # ParameterName.NUM_PLMNS: TrParam(
- # FAPSERVICE_PATH + 'CellConfig.LTE.EPC.PLMNListNumberOfEntries',
- # is_invasive=False,
- # type=TrParameterType.INT, is_optional=False,
- # ),
ParameterName.TAC: TrParam(
FAPSERVICE_PATH + "CellConfig.LTE.EPC.TAC",
is_invasive=False,
type=TrParameterType.INT,
is_optional=False,
),
+ ParameterName.TAC2: TrParam(
+ FAPSERVICE_PATH + "CellConfig.LTE.EPC.X_SCM_TAC2",
+ is_invasive=False,
+ type=TrParameterType.INT,
+ is_optional=False,
+ ),
# Management server parameters
ParameterName.PERIODIC_INFORM_ENABLE: TrParam(
- DEVICE_PATH + "ManagementServer.PeriodicInformEnable",
+ "Device.ManagementServer.PeriodicInformEnable",
is_invasive=False,
type=TrParameterType.BOOLEAN,
is_optional=False,
),
ParameterName.PERIODIC_INFORM_INTERVAL: TrParam(
- DEVICE_PATH + "ManagementServer.PeriodicInformInterval",
+ "Device.ManagementServer.PeriodicInformInterval",
is_invasive=False,
type=TrParameterType.INT,
is_optional=False,
),
# Performance management parameters
ParameterName.PERF_MGMT_ENABLE: TrParam(
- DEVICE_PATH + "FAP.PerfMgmt.Config.1.Enable",
+ "Device.FAP.PerfMgmt.Config.1.Enable",
is_invasive=False,
type=TrParameterType.BOOLEAN,
is_optional=False,
),
ParameterName.PERF_MGMT_UPLOAD_INTERVAL: TrParam(
- DEVICE_PATH + "FAP.PerfMgmt.Config.1.PeriodicUploadInterval",
+ "Device.FAP.PerfMgmt.Config.1.PeriodicUploadInterval",
is_invasive=False,
type=TrParameterType.INT,
is_optional=False,
),
ParameterName.PERF_MGMT_UPLOAD_URL: TrParam(
- DEVICE_PATH + "FAP.PerfMgmt.Config.1.URL",
+ "Device.FAP.PerfMgmt.Config.1.URL",
+ is_invasive=False,
+ type=TrParameterType.STRING,
+ is_optional=False,
+ ),
+ ParameterName.TX_POWER: TrParam(
+ FAPSERVICE_PATH + "CellConfig.LTE.RAN.RF.X_SCM_TxPowerConfig",
+ is_invasive=True,
+ type=TrParameterType.INT,
+ is_optional=False,
+ ),
+ ParameterName.TUNNEL_TYPE: TrParam(
+ FAPSERVICE_PATH + "CellConfig.LTE.Tunnel.1.TunnelRef",
is_invasive=False,
type=TrParameterType.STRING,
is_optional=False,
@@ -740,7 +795,6 @@
PARAMETERS.update(SASParameters.SAS_PARAMETERS)
PARAMETERS.update(FreedomFiOneMiscParameters.MISC_PARAMETERS)
PARAMETERS.update(StatusParameters.STATUS_PARAMETERS)
- # These are stateful parameters that have no tr-69 representation
PARAMETERS.update(StatusParameters.DERIVED_STATUS_PARAMETERS)
TRANSFORMS_FOR_MAGMA = {
@@ -812,7 +866,6 @@
"""
SAS_KEY = "sas"
- WEB_UI_ENABLE_LIST_KEY = "web_ui_enable_list"
def __init__(self, acs: EnodebAcsStateMachine):
super().__init__()
@@ -821,29 +874,9 @@
def postprocess(
self, mconfig: Any, service_cfg: Any, desired_cfg: EnodebConfiguration,
) -> None:
-
- desired_cfg.delete_parameter(ParameterName.EARFCNDL)
- desired_cfg.delete_parameter(ParameterName.DL_BANDWIDTH)
- desired_cfg.delete_parameter(ParameterName.UL_BANDWIDTH)
-
- # go through misc parameters and set them to default.
- for name, val in FreedomFiOneMiscParameters.defaults.items():
- desired_cfg.set_parameter(name, val)
-
# Bump up the parameter key version
self.acs.parameter_version_inc()
- if self.WEB_UI_ENABLE_LIST_KEY in service_cfg:
- serial_nos = service_cfg.get(self.WEB_UI_ENABLE_LIST_KEY)
- if self.acs.device_cfg.has_parameter(ParameterName.SERIAL_NUMBER,):
- if self.acs.get_parameter(ParameterName.SERIAL_NUMBER) in serial_nos:
- desired_cfg.set_parameter(
- FreedomFiOneMiscParameters.WEB_UI_ENABLE, True,
- )
- else:
- # This should not happen
- EnodebdLogger.error("Serial number unknown for device")
-
# Load eNB customized configuration from "./magma_config/serial_number/"
# and configure each connected eNB based on serial number
enbcfg = load_enb_config()
@@ -866,9 +899,10 @@
Some eNB parameters are read only and updated by the eNB itself.
"""
- def __init__(self, acs: EnodebAcsStateMachine, when_done: str):
+ def __init__(self, acs: EnodebAcsStateMachine, when_upgrade: str, when_done: str):
super().__init__()
self.acs = acs
+ self.upgrade_transition = when_upgrade
self.done_transition = when_done
def get_msg(self, message: Any) -> AcsMsgAndTransition:
@@ -877,11 +911,6 @@
request.ParameterNames = models.ParameterNames()
request.ParameterNames.string = []
- # request = models.GetParameterNames()
- # request.ParameterPath = "Device."
- # request.NextLevel = False
-
- # Get the status parameters which was defined in Line 171
for _, tr_param in StatusParameters.STATUS_PARAMETERS.items():
path = tr_param.path
request.ParameterNames.string.append(path)
@@ -905,7 +934,15 @@
name_to_val, self.acs.device_cfg,
)
- return AcsReadMsgResult(msg_handled=True, next_state=self.done_transition,)
+ print("In get transient state", name_to_val, type(name_to_val))
+ if name_to_val["SW version"] != "TEST3918@210224":
+ print("Get into Firmware Upgrade state")
+ return AcsReadMsgResult(
+ msg_handled=True, next_state=self.upgrade_transition
+ )
+
+ print("Skip firmware upgrade, configure the enb")
+ return AcsReadMsgResult(msg_handled=True, next_state=self.done_transition)
def state_description(self) -> str:
return "Getting transient read-only parameters"
@@ -1005,6 +1042,8 @@
obj_name = ParameterName.PLMN_N % i
desired = obj_to_params[obj_name]
names += desired
+
+ print(obj_to_params)
return names
def get_msg(self, message: Any) -> AcsMsgAndTransition:
diff --git a/magma_configs/enodebd.yml b/magma_configs/enodebd.yml
index ff5fe6e..346a6ed 100644
--- a/magma_configs/enodebd.yml
+++ b/magma_configs/enodebd.yml
@@ -13,6 +13,10 @@
#
# log_level is set in mconfig. It can be overridden here
+prometheus:
+ ip: 0.0.0.0
+ port: 8000
+
tr069:
interface: eth0 # NOTE: this value must be consistent with dnsmasq.conf
port: 48080
@@ -21,6 +25,10 @@
# if this is ever changed in dnsd.yml, this needs to be updated too
public_ip: 18.116.99.179
+ssl:
+ key: "./enodebd.key"
+ cert: "./enodebd.cert"
+
# TODO: @amar: This is a temp workaround to allow for testing until we
# connect enodebd with the domain proxy which is responsible for talking to
# SAS.
@@ -46,4 +54,3 @@
# Network interface to terminate S1
s1_interface: eth1
-
diff --git a/magma_configs/magmad.yml b/magma_configs/magmad.yml
index ccc7ff9..ecbafc4 100644
--- a/magma_configs/magmad.yml
+++ b/magma_configs/magmad.yml
@@ -18,47 +18,7 @@
# List of services for magmad to control
magma_services:
- # - control_proxy
- # - subscriberdb
- # - mobilityd
- # - directoryd
- enodebd
- # - sessiond
- # - mme
- # - pipelined
- # - envoy_controller
- # - redis
- # - dnsd
- # - policydb
- # - state
- # - eventd
- # - smsd
- # - ctraced
- # - health
- # - kernsnoopd
- # - liagentd
-
-# List of services that don't provide service303 interface
-# non_service303_services:
- # - control_proxy
- # - dnsd
- # - redis
- # - td-agent-bit
-
-# List of all possible dynamic services (enabled from gateway.mconfig)
-# registered_dynamic_services:
- # - redirectd
- # - td-agent-bit
- # - monitord
- # - dpid
-
-# A list of group of services which are linked together in systemd
-# linked_services:
- # -
- # - mme
- # - pipelined
- # - mobilityd
- # - sessiond
# list of services that are required to have meta before checking in
# (meta = data gathered via MagmaService.register_get_status_callback())
@@ -126,7 +86,6 @@
- pipelined
- state
- sessiond
-# - kernsnoopd
generic_command_config:
module: magma.magmad.generic_command.shell_command_executor
diff --git a/magma_configs/serial_number/2009CW5000019.yml b/magma_configs/serial_number/2009CW5000019.yml
index 0b0e52f..140781f 100644
--- a/magma_configs/serial_number/2009CW5000019.yml
+++ b/magma_configs/serial_number/2009CW5000019.yml
@@ -2,10 +2,9 @@
specialSubframePattern: 7
earfcndl: 44490
plmnidList: "305010"
-pci: 501
+pci: "100,101"
allowEnodebTransmit: False
subframeAssignment: 2
-tac: 2
cell_id: 1
mme_address: 172.21.143.206
mme_port: 36412
@@ -17,13 +16,45 @@
Periodic inform interval: 180
Perf mgmt enable: 0
Perf mgmt upload interval: 900
+ enable_cwmp: True
+ tac: 501
+ tac2: 501
+ # RRM / CA
+ earfcndl1: 55440
+ earfcnul1: 55440
+ earfcndl2: 55640
+ earfcnul2: 55640
+ earfcndl_list: "55440,55640"
+ earfcnul_list: "55440,55640"
+ carrier_agg_enable: False
+ carrier_number: 2
+ contiguous_cc: 0
+ prim_source: "FREE_RUNNING"
+ # RF
+ freq_band_1: 48
+ freq_band_2: 48
+ freq_band_list: "48,48"
+ tx_power: 20
+ tunnel_type: "Device.IP.Interface.1.IPv4Address.1."
sas:
sas_enabled: True
+ sas_cpi_enable: True
+ sas_manufacturer_prefix_enable: True
sas_server_url: "https://sas.goog/v1.2/"
sas_uid: "aether"
sas_category: "A"
sas_channel_type: "GAA"
sas_cert_subject: "/C=TW/O=Sercomm/OU=WInnForum CBSD Certificate/CN=P27-SCE4255W:2009CW5000019"
sas_location: "indoor"
- sas_height_type: "AGL"
\ No newline at end of file
+ sas_height_type: "AGL"
+ sas_fccid: "P27-SCE4255W"
+ sas_measure_capability: "RECEIVED_POWER_WITHOUT_GRANT"
+ sas_cpi_name: "onf-cpi"
+ sas_cpi_id: "GOOG-999999"
+
+ sas_antenna_azimuth: 0
+ sas_antenna_downtilt: 0
+ sas_antenna_gain: 5
+ sas_antenna_beamwidth: 360
+ sas_cpi_signature_data: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmY2NJZCI6IlAyNy1TQ0U0MjU1VyIsImNic2RTZXJpYWxOdW1iZXIiOiJTZXJjb21tLTIwMDlDVzUwMDAwMTkiLCJpbnN0YWxsYXRpb25QYXJhbSI6eyJsYXRpdHVkZSI6MzIuMzQ0NzUyLCJsb25naXR1ZGUiOi0xMTEuMDEyMzAyLCJoZWlnaHQiOjEsImhlaWdodFR5cGUiOiJBR0wiLCJpbmRvb3JEZXBsb3ltZW50Ijp0cnVlLCJhbnRlbm5hQXppbXV0aCI6MCwiYW50ZW5uYURvd250aWx0IjowLCJhbnRlbm5hR2FpbiI6NSwiYW50ZW5uYUJlYW13aWR0aCI6MzYwLCJob3Jpem9udGFsQWNjdXJhY3kiOjMsInZlcnRpY2FsQWNjdXJhY3kiOjMsImVpcnBDYXBhYmlsaXR5IjoyOH0sInByb2Zlc3Npb25hbEluc3RhbGxlckRhdGEiOnsiY3BpSWQiOiJHT09HLTAwMTIxMiIsImNwaU5hbWUiOiJXZWktWXUgQ2hlbiIsImluc3RhbGxDZXJ0aWZpY2F0aW9uVGltZSI6IjIwMjEtMDktMDlUMDA6MDA6MDBaIn19.ljSE95LcLwKXDgrFIX43M4BUTfmkl62KQvt0TNnsZh2SUgpw0ALQCEuSzh7KHRPOvVT5F8JjsKQeeewXSrHSLXPuPwCcxwYGDrwAp_SMiXJu7-ihL-ww_qOsZ-nu1W8alMe8oyxFiEYDN0957PBr9YP-Mj8uptVJ9VKJjf1bawzx0wihwXhTtioNMmvEO_zltD83BK14kaLM0aAcstgjHjNT7tIBE-0O3QGuN8o7jdGHxy9y7FUCPSmih2B5iu2ygVALGzYglnFebK873pp3mjKPh7XO776OjkNgYHHk5uCqf4JOf03z39Cn-CQVSnZTx-1LHV-mYJnhF4yk2R_chg"
diff --git a/main.py b/main.py
index aae8e96..c34aa0d 100644
--- a/main.py
+++ b/main.py
@@ -16,6 +16,7 @@
from unittest import mock
from lte.protos.mconfig import mconfigs_pb2
+from configuration.service_configs import load_service_config
from common.sentry import sentry_init
from common.service import MagmaService
from enodeb_status import (
@@ -30,6 +31,7 @@
from rpc_servicer import EnodebdRpcServicer
from stats_manager import StatsManager
from tr069.server import tr069_server
+from prometheus_client import start_http_server as prometheus_start_http_server
def get_context(ip: str):
@@ -47,6 +49,19 @@
service = MagmaService('enodebd', mconfigs_pb2.EnodebD())
logger.init()
+ enodebd_cfg = load_service_config('enodebd')
+ prometheus_cfg = enodebd_cfg.get("prometheus", None)
+
+ if not prometheus_cfg:
+ logger.warning("Prometheus configuration wasn't found in enodebd configuration.")
+ else:
+ prometheus_ip = prometheus_cfg.get("ip")
+ prometheus_port = prometheus_cfg.get("port")
+ prometheus_start_http_server(prometheus_port, addr=prometheus_ip)
+ logger.info(
+ "Starting Prometheus server on address %s:%d",
+ prometheus_ip, prometheus_port)
+
# Optionally pipe errors to Sentry
sentry_init(service_name=service.name)
diff --git a/metrics.py b/metrics.py
index 90c4b4f..877c4d9 100644
--- a/metrics.py
+++ b/metrics.py
@@ -54,6 +54,10 @@
'enodeb_reboots',
'ENodeB reboots by enodebd', ['cause'],
)
+STAT_ENODEB_LAST_CONFIGURED = Gauge(
+ 'enodeb_last_configured',
+ 'Information of configured eNodeB', ['serial_number', 'ip_address', 'gps_lat', 'gps_lon']
+)
# Metrics that are accumulated by eNodeB. Use gauges to avoid 'double-counting',
# since eNodeB does accumulation.
diff --git a/requirements.txt b/requirements.txt
index 41d602e..97556f1 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,3 +1,4 @@
+wheel==0.37.1
aiohttp==3.6.2
aiosignal==1.2.0
appdirs==1.4.4
@@ -40,3 +41,4 @@
urllib3==1.26.7
wrapt==1.13.3
yarl==1.7.2
+cryptography==36.0.1
\ No newline at end of file
diff --git a/state_machines/enb_acs_impl.py b/state_machines/enb_acs_impl.py
index 2a7367f..4a197d4 100644
--- a/state_machines/enb_acs_impl.py
+++ b/state_machines/enb_acs_impl.py
@@ -148,6 +148,7 @@
""" Process incoming message and maybe transition state """
self._reset_timeout()
msg_handled, next_state = self.state.read_msg(message)
+ logger.info("Received incoming message, transfer to new state: %s", next_state)
if not msg_handled:
self._transition_for_unexpected_msg(message)
_msg_handled, next_state = self.state.read_msg(message)
@@ -157,7 +158,9 @@
def _get_tr069_msg(self, message: Any) -> Any:
""" Get a new message to send, and maybe transition state """
msg_and_transition = self.state.get_msg(message)
+ logger.debug("Sending a new message to eNodeB")
if msg_and_transition.next_state:
+ logger.info("Transfer to new state: %s", msg_and_transition.next_state)
self.transition(msg_and_transition.next_state)
msg = msg_and_transition.msg
return msg
diff --git a/state_machines/enb_acs_states.py b/state_machines/enb_acs_states.py
index a9b84a5..d9e2ed9 100644
--- a/state_machines/enb_acs_states.py
+++ b/state_machines/enb_acs_states.py
@@ -10,10 +10,15 @@
See the License for the specific language governing permissions and
limitations under the License.
"""
+
+import time
from abc import ABC, abstractmethod
from collections import namedtuple
from typing import Any, Optional
+import metrics
+
+from configuration.service_configs import load_service_config
from data_models.data_model import InvalidTrParamPath
from data_models.data_model_parameters import ParameterName
from device_config.configuration_init import build_desired_config
@@ -964,6 +969,14 @@
'Status=%d' % message.Status,
)
self._mark_as_configured()
+
+ metrics.STAT_ENODEB_LAST_CONFIGURED.labels(
+ serial_number=self.acs.device_cfg.get_parameter("Serial number"),
+ ip_address=self.acs.device_cfg.get_parameter("ip_address"),
+ gps_lat=self.acs.device_cfg.get_parameter("GPS lat"),
+ gps_lon=self.acs.device_cfg.get_parameter("GPS long")
+ ).set(int(time.time()))
+
if not self.acs.are_invasive_changes_applied:
return AcsReadMsgResult(True, self.apply_invasive_transition)
return AcsReadMsgResult(True, self.done_transition)
@@ -1257,6 +1270,115 @@
return 'Waiting after eNB reboot to prevent race conditions'
+class DownloadState(EnodebAcsState):
+ """
+ The eNB handler will enter this state when firmware version is older than desired version.
+ """
+
+ def __init__(self, acs: EnodebAcsStateMachine, when_done: str):
+ super().__init__()
+ self.acs = acs
+ self.done_transition = when_done
+
+ def get_msg(self, message: Any) -> AcsMsgAndTransition:
+
+ print("ACS Device CFG")
+ print(self.acs.device_cfg._param_to_value)
+
+ request = models.Download()
+ request.CommandKey = "20220206215200"
+ request.FileType = "1 Firmware Upgrade Image"
+ request.URL = "http://18.116.99.179/firmware/Qproject_TEST3918_2102241222.ffw"
+ request.Username = ""
+ request.Password = ""
+ request.FileSize = 57208579
+ request.TargetFileName = "Qproject_TEST3918_2102241222.ffw"
+ request.DelaySeconds = 0
+ request.SuccessURL = ""
+ request.FailureURL = ""
+ return AcsMsgAndTransition(request, self.done_transition)
+
+ def state_description(self) -> str:
+ return 'Upgrade the firmware the desired version'
+
+class WaitDownloadResponseState(EnodebAcsState):
+ """
+ The eNB handler will enter this state after the Download command sent.
+ """
+
+ def __init__(self, acs: EnodebAcsStateMachine, when_done: str):
+ super().__init__()
+ self.acs = acs
+ self.done_transition = when_done
+
+ def read_msg(self, message: Any) -> AcsReadMsgResult:
+ if not isinstance(message, models.DownloadResponse):
+ return AcsReadMsgResult(False, None)
+ return AcsReadMsgResult(True, None)
+
+ def get_msg(self, message: Any) -> AcsMsgAndTransition:
+ """ Reply with empty message """
+ logger.info("Received Download Response from eNodeB")
+ return AcsMsgAndTransition(models.DummyInput(), self.done_transition)
+
+ def state_description(self) -> str:
+ return "Wait DownloadResponse message"
+
+class WaitInformTransferCompleteState(EnodebAcsState):
+ """
+ The eNB handler will enter this state after firmware upgraded and rebooted
+ """
+
+ REBOOT_TIMEOUT = 300 # In seconds
+ INFORM_EVENT_CODE = "7 TRANSFER COMPLETE"
+ PREIODIC_EVENT_CODE = "2 PERIODIC"
+
+ def __init__(self, acs: EnodebAcsStateMachine, when_done: str, when_periodic: str, when_timeout: str):
+ super().__init__()
+ self.acs = acs
+ self.done_transition = when_done
+ self.periodic_update_transition = when_periodic
+ self.timeout_transition = when_timeout
+ self.timeout_timer = None
+ self.timer_handle = None
+
+ def enter(self):
+ print("Get into the TransferComplete State")
+ self.timeout_timer = StateMachineTimer(self.REBOOT_TIMEOUT)
+
+ def check_timer() -> None:
+ if self.timeout_timer.is_done():
+ self.acs.transition(self.timeout_transition)
+ raise Tr069Error("Didn't receive Inform response after rebooting")
+
+ self.timer_handle = self.acs.event_loop.call_later(
+ self.REBOOT_TIMEOUT,
+ check_timer,
+ )
+
+ def exit(self):
+ self.timer_handle.cancel()
+ self.timeout_timer = None
+
+ def get_msg(self, message: Any) -> AcsMsgAndTransition:
+ return AcsMsgAndTransition(models.DummyInput(), None)
+
+ def read_msg(self, message: Any) -> AcsReadMsgResult:
+ if not isinstance(message, models.Inform):
+ return AcsReadMsgResult(False, None)
+ if does_inform_have_event(message, self.PREIODIC_EVENT_CODE):
+ logger.info("Receive Periodic update from enodeb")
+ return AcsReadMsgResult(True, self.periodic_update_transition)
+ if does_inform_have_event(message, self.INFORM_EVENT_CODE):
+ logger.info("Receive Transfer complete")
+ return AcsReadMsgResult(True, self.done_transition)
+
+ # Unhandled situation
+ return AcsReadMsgResult(False, None)
+
+ def state_description(self) -> str:
+ return "Wait DownloadResponse message"
+
class ErrorState(EnodebAcsState):
"""
The eNB handler will enter this state when an unhandled Fault is received.
@@ -1290,4 +1412,4 @@
def state_description(self) -> str:
return 'Error state - awaiting manual restart of enodebd service or ' \
- 'an Inform to be received from the eNB'
+ 'an Inform to be received from the eNB'
\ No newline at end of file