VOL-944: ADTRAN ONU: Refactoring to better support new OpenOMCI features
Change-Id: I93e7841924240d872070d7af2978f0e5a35674fc
diff --git a/voltha/adapters/adtran_onu/adtran_onu.py b/voltha/adapters/adtran_onu/adtran_onu.py
index 1f76dfb..81a5f9a 100755
--- a/voltha/adapters/adtran_onu/adtran_onu.py
+++ b/voltha/adapters/adtran_onu/adtran_onu.py
@@ -23,8 +23,10 @@
from voltha.protos import third_party
from adtran_onu_handler import AdtranOnuHandler
from voltha.extensions.omci.openomci_agent import OpenOMCIAgent, OpenOmciAgentDefaults
-from voltha.extensions.omci.database.mib_db_dict import MibDbVolatileDict
from twisted.internet import reactor
+from omci.adtn_capabilities_task import AdtnCapabilitiesTask
+from omci.adtn_get_mds_task import AdtnGetMdsTask
+from omci.adtn_mib_sync import AdtnMibSynchronizer
from copy import deepcopy
_ = third_party
@@ -38,12 +40,17 @@
device_handler_class=AdtranOnuHandler,
name='adtran_onu',
vendor='Adtran, Inc.',
- version='0.9',
+ version='0.10',
device_type='adtran_onu',
vendor_id='ADTN')
# Customize OpenOMCI for Adtran ONUs
self.adtran_omci = deepcopy(OpenOmciAgentDefaults)
+ self.adtran_omci['mib-synchronizer']['state-machine'] = AdtnMibSynchronizer
+ self.adtran_omci['mib-synchronizer']['tasks']['get-mds'] = AdtnGetMdsTask
+ self.adtran_omci['mib-synchronizer']['tasks']['mib-audit'] = AdtnGetMdsTask
+ self.adtran_omci['omci-capabilities']['tasks']['get-capabilities'] = AdtnCapabilitiesTask
+
# TODO: Continue to customize adtran_omci here as needed
self._omci_agent = OpenOMCIAgent(self.adapter_agent.core,
diff --git a/voltha/adapters/adtran_onu/adtran_onu_handler.py b/voltha/adapters/adtran_onu/adtran_onu_handler.py
index bba4872..8e7282f 100644
--- a/voltha/adapters/adtran_onu/adtran_onu_handler.py
+++ b/voltha/adapters/adtran_onu/adtran_onu_handler.py
@@ -21,6 +21,7 @@
from pon_port import PonPort
from uni_port import UniPort
from heartbeat import HeartBeat
+from omci.omci import OMCI
from voltha.adapters.adtran_olt.alarms.adapter_alarms import AdapterAlarms
from onu_pm_metrics import OnuPmMetrics
@@ -58,6 +59,9 @@
self._mgmt_gemport_aes = False
self._upstream_channel_speed = 0
+ self._openomci = OMCI(self, adapter.omci_agent)
+ self._in_sync_subscription = None
+
self._unis = dict() # Port # -> UniPort
self._pon = None
self._heartbeat = HeartBeat.create(self, device_id)
@@ -127,14 +131,8 @@
return self._olt_created # ONU was created with deprecated 'child_device_detected' call
@property
- def omci_agent(self):
- return self.adapter.omci_agent
-
- @property
- def omci(self):
- # TODO: Decrement access to Communications channel at this point? What about current PM stuff?
- _onu_omci_device = self._pon.onu_omci_device
- return _onu_omci_device.omci_cc if _onu_omci_device is not None else None
+ def openomci(self):
+ return self._openomci
@property
def heartbeat(self):
@@ -175,6 +173,10 @@
# Register for adapter messages
self.adapter_agent.register_for_inter_adapter_messages()
+ # OpenOMCI Startup
+ self._subscribe_to_events()
+ self._openomci.enabled = True
+
# Port startup
if self._pon is not None:
self._pon.enabled = True
@@ -199,8 +201,8 @@
self._heartbeat.stop()
# OMCI Communications
- # if self._onu_omci_device is not None:
- # self._onu_omci_device.stop()
+ self._unsubscribe_to_events()
+ self._openomci.enabled = False
# Port shutdown
for port in self.uni_ports:
@@ -215,8 +217,9 @@
_ = yield queue.get()
def receive_message(self, msg):
- if self.omci is not None and self.enabled:
- self.omci.receive_message(msg)
+ if self.enabled:
+ # TODO: Have OpenOMCI actually receive the messages
+ self.openomci.receive_message(msg)
def activate(self, device):
self.log.info('activating')
@@ -372,7 +375,7 @@
def is_upstream(port):
return not is_downstream(port)
- omci = self.omci
+ omci = self.openomci.omci_cc
for flow in flows:
_type = None
@@ -565,7 +568,7 @@
# MIB Reset - For ADTRAN ONU, we do not get a response
# back (because we are rebooting)
pass
- yield self.omci.send_reboot(timeout=0.1)
+ yield self.openomci.omci_cc.send_reboot(timeout=0.1)
except TimeoutError:
# This is expected
@@ -652,9 +655,8 @@
parent_device = self.adapter_agent.get_device(device.parent_id)
assert parent_device
-
for uni in self.uni_ports:
- #port_id = 'uni-{}'.format(uni.port_number)
+ # port_id = 'uni-{}'.format(uni.port_number)
port_id = uni.port_id_name()
try:
@@ -782,8 +784,7 @@
self._pon.delete()
# OpenOMCI cleanup
- if self.omci_agent is not None:
- self.omci_agent.remove_device(self.device_id, cleanup=True)
+ self._openomci.delete()
def _check_for_mock_config(self, data):
# Check for MOCK configuration
@@ -1185,3 +1186,51 @@
# Handle next event (self._event_deferred is None if we got stopped)
self._event_deferred = reactor.callLater(0, self.handle_onu_events)
+
+ def _subscribe_to_events(self):
+ from voltha.extensions.omci.onu_device_entry import OnuDeviceEvents, \
+ OnuDeviceEntry
+
+ # OMCI MIB Database sync status
+ bus = self.openomci.onu_omci_device.event_bus
+ topic = OnuDeviceEntry.event_bus_topic(self.device_id,
+ OnuDeviceEvents.MibDatabaseSyncEvent)
+ self._in_sync_subscription = bus.subscribe(topic, self.in_sync_handler)
+
+ def _unsubscribe_to_events(self):
+ insync, self._in_sync_subscription = self._in_sync_subscription, None
+
+ if insync is not None:
+ bus = self.openomci.onu_omci_device.event_bus
+ bus.unsubscribe(insync)
+
+ def in_sync_handler(self, _topic, msg):
+ # Create UNI Ports on first In-Sync event
+
+ if self._in_sync_subscription is not None:
+ try:
+ from voltha.extensions.omci.onu_device_entry import IN_SYNC_KEY
+
+ if msg[IN_SYNC_KEY]:
+ # Do not proceed if we have not got our vENET information yet.
+
+ if len(self.uni_ports) > 0:
+ # Drop subscription....
+ insync, self._in_sync_subscription = self._in_sync_subscription, None
+
+ if insync is not None:
+ bus = self.openomci.onu_omci_device.event_bus
+ bus.unsubscribe(insync)
+
+ # Set up UNI Ports. The UNI ports are currently created when the xPON
+ # vENET information is created. Once xPON is removed, we need to create
+ # them from the information provided from the MIB upload UNI-G and other
+ # UNI related MEs.
+
+ for uni in self.uni_ports:
+ uni.add_logical_port(None, None)
+ else:
+ self._deferred = reactor.callLater(5, self.in_sync_handler, _topic, msg)
+
+ except Exception as e:
+ self.log.exception('in-sync', e=e)
diff --git a/voltha/adapters/adtran_onu/heartbeat.py b/voltha/adapters/adtran_onu/heartbeat.py
index b35daab..2d5796f 100644
--- a/voltha/adapters/adtran_onu/heartbeat.py
+++ b/voltha/adapters/adtran_onu/heartbeat.py
@@ -100,7 +100,7 @@
def check_pulse(self):
if self.enabled:
try:
- self._defer = self._handler.omci.send(OntGFrame(self.check_item).get())
+ self._defer = self._handler.openomci.omci_cc.send(OntGFrame(self.check_item).get())
self._defer.addCallbacks(self._heartbeat_success, self._heartbeat_fail)
except Exception as e:
diff --git a/voltha/adapters/adtran_onu/omci/adtn_capabilities_task.py b/voltha/adapters/adtran_onu/omci/adtn_capabilities_task.py
new file mode 100644
index 0000000..6be8fd7
--- /dev/null
+++ b/voltha/adapters/adtran_onu/omci/adtn_capabilities_task.py
@@ -0,0 +1,143 @@
+#
+# Copyright 2018 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+from voltha.extensions.omci.tasks.onu_capabilities_task import OnuCapabilitiesTask
+from twisted.internet.defer import failure
+
+
+class AdtnCapabilitiesTask(OnuCapabilitiesTask):
+ """
+ OpenOMCI MIB Capabilities Task - ADTRAN ONUs
+
+ This task requests information on supported MEs via the OMCI (ME#287)
+ Managed entity.
+
+ This task should be ran after MIB Synchronization and before any MIB
+ Downloads to the ONU.
+
+ Upon completion, the Task deferred callback is invoked with dictionary
+ containing the supported managed entities and message types.
+
+ results = {
+ 'supported-managed-entities': {set of supported managed entities},
+ 'supported-message-types': {set of supported message types}
+ }
+ """
+ def __init__(self, omci_agent, device_id):
+ """
+ Class initialization
+
+ :param omci_agent: (OmciAdapterAgent) OMCI Adapter agent
+ :param device_id: (str) ONU Device ID
+ """
+ super(AdtnCapabilitiesTask, self).__init__(omci_agent, device_id)
+ self._omci_managed = False # TODO: Look up capabilities/model number
+
+ @property
+ def supported_managed_entities(self):
+ """
+ Return a set of the Managed Entity class IDs supported on this ONU
+
+ None is returned if not MEs have been discovered
+
+ :return: (set of ints)
+ """
+ if self._omci_managed:
+ return super(AdtnCapabilitiesTask, self).supported_managed_entities
+
+ me_1287800f1 = [
+ 2, 5, 6, 7, 11, 24, 45, 46, 47, 48, 49, 50, 51, 52, 79, 84, 89, 130,
+ 131, 133, 134, 135, 136, 137, 148, 157, 158, 159, 171, 256, 257, 262,
+ 263, 264, 266, 268, 272, 273, 274, 277, 278, 279, 280, 281, 297, 298,
+ 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312,
+ 329, 330, 332, 334, 336, 340, 341, 342, 343, 348, 425, 426, 65300,
+ 65400, 65401, 65402, 65403, 65404, 65406, 65407, 65408, 65409, 65410,
+ 65411, 65412, 65413, 65414, 65420, 65421, 65422, 65423, 65424
+ ]
+ return frozenset(list(me_1287800f1))
+
+ @property
+ def supported_message_types(self):
+ """
+ Return a set of the Message Types supported on this ONU
+
+ None is returned if no message types have been discovered
+
+ :return: (set of EntityOperations)
+ """
+ if self._omci_managed:
+ return super(AdtnCapabilitiesTask, self).supported_message_types
+
+ from voltha.extensions.omci.omci_entities import EntityOperations
+ op_11287800f1 = [
+ EntityOperations.Create,
+ EntityOperations.CreateComplete,
+ EntityOperations.Delete,
+ EntityOperations.Set,
+ EntityOperations.Get,
+ EntityOperations.GetComplete,
+ EntityOperations.GetAllAlarms,
+ EntityOperations.GetAllAlarmsNext,
+ EntityOperations.MibUpload,
+ EntityOperations.MibUploadNext,
+ EntityOperations.MibReset,
+ EntityOperations.AlarmNotification,
+ EntityOperations.AttributeValueChange,
+ EntityOperations.Test,
+ EntityOperations.StartSoftwareDownload,
+ EntityOperations.DownloadSection,
+ EntityOperations.EndSoftwareDownload,
+ EntityOperations.ActivateSoftware,
+ EntityOperations.CommitSoftware,
+ EntityOperations.SynchronizeTime,
+ EntityOperations.Reboot,
+ EntityOperations.GetNext,
+ ]
+ return frozenset(op_11287800f1)
+
+ def perform_get_capabilities(self):
+ """
+ Perform the MIB Capabilities sequence.
+
+ The sequence is to perform a Get request with the attribute mask equal
+ to 'me_type_table'. The response to this request will carry the size
+ of (number of get-next sequences).
+
+ Then a loop is entered and get-next commands are sent for each sequence
+ requested.
+ """
+ self.log.info('perform-get')
+
+ if self._omci_managed:
+ # Return generator deferred/results
+ return super(AdtnCapabilitiesTask, self).perform_get_capabilities()
+
+ # Fixed values, no need to query
+ try:
+ self._supported_entities = self.supported_managed_entities
+ self._supported_msg_types = self.supported_message_types
+
+ self.log.debug('get-success',
+ supported_entities=self.supported_managed_entities,
+ supported_msg_types=self.supported_message_types)
+ results = {
+ 'supported-managed-entities': self.supported_managed_entities,
+ 'supported-message-types': self.supported_message_types
+ }
+ self.deferred.callback(results)
+
+ except Exception as e:
+ self.log.exception('get-failed', e=e)
+ self.deferred.errback(failure.Failure(e))
diff --git a/voltha/adapters/adtran_onu/omci/adtn_get_mds_task.py b/voltha/adapters/adtran_onu/omci/adtn_get_mds_task.py
new file mode 100644
index 0000000..0de236f
--- /dev/null
+++ b/voltha/adapters/adtran_onu/omci/adtn_get_mds_task.py
@@ -0,0 +1,56 @@
+#
+# Copyright 2018 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+from voltha.extensions.omci.tasks.get_mds_task import GetMdsTask
+
+
+class AdtnGetMdsTask(GetMdsTask):
+ """
+ OpenOMCI Get MIB Data Sync value task - Adtran ONU
+
+ On successful completion, this task will call the 'callback' method of the
+ deferred returned by the start method and return the value of the MIB
+ Data Sync attribute of the ONT Data ME
+ """
+ name = "ADTN: Get MDS Task"
+
+ def __init__(self, omci_agent, device_id):
+ """
+ Class initialization
+
+ :param omci_agent: (OmciAdapterAgent) OMCI Adapter agent
+ :param device_id: (str) ONU Device ID
+ """
+ super(AdtnGetMdsTask, self).__init__(omci_agent, device_id)
+
+ self.name = AdtnGetMdsTask.name
+ self._device = omci_agent.get_device(device_id)
+ self._omci_managed = False # TODO: Look up capabilities/model number/check handler
+
+ def perform_get_mds(self):
+ """
+ Get the 'mib_data_sync' attribute of the ONU
+ """
+ self.log.info('perform-get-mds')
+
+ if self._omci_managed:
+ return super(AdtnGetMdsTask, self).perform_get_mds()
+
+ # Non-OMCI managed ADTN ONUs always return 0 for MDS, use the MIB
+ # sync value and depend on an accelerated mib resync to do the
+ # proper comparison
+
+ self.deferred.callback(self._device.mib_synchronizer.mib_data_sync)
+
diff --git a/voltha/adapters/adtran_onu/omci/adtn_mib_download_task.py b/voltha/adapters/adtran_onu/omci/adtn_mib_download_task.py
new file mode 100644
index 0000000..a6d6d5c
--- /dev/null
+++ b/voltha/adapters/adtran_onu/omci/adtn_mib_download_task.py
@@ -0,0 +1,522 @@
+#
+# Copyright 2018 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+from twisted.internet import reactor
+from voltha.extensions.omci.tasks.task import Task
+from twisted.internet.defer import inlineCallbacks, TimeoutError, failure
+from voltha.extensions.omci.omci_me import OntDataFrame
+from voltha.extensions.omci.omci_defs import *
+
+
+class AdtnMibDownloadTask(Task):
+ """
+ OpenOMCI MIB Download Example
+
+ This task takes the legacy OMCI 'script' for provisioning the Adtran ONU
+ and converts it to run as a Task on the OpenOMCI Task runner. This is
+ in order to begin to decompose service instantiation in preparation for
+ Technology Profile work.
+
+ Once technology profiles are ready, some of this task may hang around or
+ be moved into OpenOMCI if there are any very common settings/configs to do
+ for any profile that may be provided in the v2.0 release
+
+ Currently, the only service tech profiles expected by v2.0 will be for AT&T
+ residential data service and DT residential data service.
+ """
+ task_priority = Task.DEFAULT_PRIORITY
+ name = "ADTRAN MIB Download Example Task"
+
+ def __init__(self, omci_agent, device_id):
+ """
+ Class initialization
+
+ :param omci_agent: (OmciAdapterAgent) OMCI Adapter agent
+ :param device_id: (str) ONU Device ID
+ """
+ super(AdtnMibDownloadTask, self).__init__(AdtnMibDownloadTask.name,
+ omci_agent,
+ device_id,
+ priority=AdtnMibDownloadTask.task_priority)
+ self._local_deferred = None
+
+ def cancel_deferred(self):
+ super(AdtnMibDownloadTask, self).cancel_deferred()
+
+ d, self._local_deferred = self._local_deferred, None
+ try:
+ if d is not None and not d.called:
+ d.cancel()
+ except:
+ pass
+
+ def start(self):
+ """
+ Start the MIB Download
+ """
+ super(AdtnMibDownloadTask, self).start()
+ self._local_deferred = reactor.callLater(0, self.perform_mib_download)
+
+ def stop(self):
+ """
+ Shutdown MIB Synchronization tasks
+ """
+ self.log.debug('stopping')
+
+ self.cancel_deferred()
+ super(AdtnMibDownloadTask, self).stop()
+
+ @inlineCallbacks
+ def perform_mib_download(self):
+ """
+ Send the commands
+ """
+ self.log.info('perform-download')
+
+ # if not self.enabled:
+ # returnValue('not-enabled')
+ #
+ # device = self._handler.adapter_agent.get_device(self._handler.device_id)
+ #
+ # def resources_available():
+ # return (device.vlan > 0 and
+ # len(self._handler.uni_ports) > 0 and
+ # len(self._handler.pon_port.tconts) and
+ # len(self._handler.pon_port.gem_ports))
+ #
+ # if not self._bridge_initialized and resources_available():
+ # device.reason = 'Performing OMCI Download'
+ # self._handler.adapter_agent.update_device(device)
+ #
+ # omci = self.omci_cc
+ #
+ # #############################################
+ # # All our variables here
+ # # TODO: Move elsewhere in future version of this software
+ # # TODO: Make as many entity IDs dynamic/discovered as possible
+ #
+ # frame = None
+ # gal_enet_profile_entity_id = 0x100
+ # ieee_mapper_service_profile_entity_id = 0x100
+ # mac_bridge_service_profile_entity_id = 0x100
+ # mac_bridge_port_ani_entity_id = 0x100
+ # ethernet_uni_entity_id = 0x101 # TODO: This can be retrieved from the UNI-G instance_id
+ # vlan_tcis_1 = 0x900
+ # vlan_config_entity_id = vlan_tcis_1
+ # cvid = device.vlan
+ #
+ # try:
+ # ################################################################################
+ # # TCONTS
+ # #
+ # # EntityID will be referenced by:
+ # # - GemPortNetworkCtp
+ # # References:
+ # # - ONU created TCONT (created on ONU startup)
+ #
+ # omci_dev = self._onu_omci_device
+ # tcont_idents = omci_dev.query_mib(Tcont.class_id)
+ # self.log.debug('tcont-idents', tcont_idents=tcont_idents)
+ #
+ # for tcont in self._handler.pon_port.tconts.itervalues():
+ # free_entity_id = next((k for k, v in tcont_idents.items()
+ # if isinstance(k, int) and
+ # v.get('attributes', {}).get('alloc_id', 0) == 0xFFFF), None)
+ # if free_entity_id is None:
+ # self.log.error('no-available-tconts')
+ # break
+ #
+ # yield tcont.add_to_hardware(omci, free_entity_id)
+ #
+ # ################################################################################
+ # # GEMS (GemPortNetworkCtp and GemInterworkingTp)
+ # #
+ # # For both of these MEs, the entity_id is the GEM Port ID. The entity id of the
+ # # GemInterworkingTp ME could be different since it has an attribute to specify
+ # # the GemPortNetworkCtp entity id.
+ # #
+ # # TODO: In the GEM Port routine to add, it has a hardcoded upstream TM ID of 0x8000
+ # # for the GemPortNetworkCtp ME
+ # #
+ # # GemPortNetworkCtp
+ # # EntityID will be referenced by:
+ # # - GemInterworkingTp
+ # # References:
+ # # - TCONT
+ # # - Hardcoded upstream TM Entity ID
+ # # - (Possibly in Future) Upstream Traffic descriptor profile pointer
+ # #
+ # # GemInterworkingTp
+ # # EntityID will be referenced by:
+ # # - Ieee8021pMapperServiceProfile
+ # # References:
+ # # - GemPortNetworkCtp
+ # # - Ieee8021pMapperServiceProfile
+ # # - GalEthernetProfile
+ # #
+ # for gem_port in self._handler.pon_port.gem_ports.itervalues():
+ # tcont = gem_port.tcont
+ # if tcont is None:
+ # self.log.error('unknown-tcont-reference', gem_id=gem_port.gem_id)
+ # continue
+ #
+ # yield gem_port.add_to_hardware(omci,
+ # tcont.entity_id,
+ # ieee_mapper_service_profile_entity_id,
+ # gal_enet_profile_entity_id)
+ #
+ # ########################################################################################
+ # # Create GalEthernetProfile - Once per ONU/PON interface
+ # #
+ # # EntityID will be referenced by:
+ # # - GemInterworkingTp
+ # # References:
+ # # - Nothing
+ #
+ # frame = GalEthernetProfileFrame(gal_enet_profile_entity_id,
+ # max_gem_payload_size=1518).create() # Max GEM Payload size
+ # results = yield omci.send(frame)
+ #
+ # status = results.fields['omci_message'].fields['success_code']
+ # error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
+ # self.log.debug('create-gal-ethernet-profile', status=status, error_mask=error_mask)
+ #
+ # ################################################################################
+ # # MAC Bridge Service Profile - Once per UNI
+ # #
+ # # EntityID will be referenced by:
+ # # - MAC Bridge Port Configuration Data
+ # # References:
+ # # - Nothing
+ #
+ # attributes = {
+ # 'spanning_tree_ind': False,
+ # # TODO: CB: see if we need or can use any of the following...
+ # # 'learning_ind': True,
+ # # 'priority': 0x8000,
+ # # 'max_age': 20 * 256,
+ # # 'hello_time': 2 * 256,
+ # # 'forward_delay': 15 * 256,
+ # # 'unknown_mac_address_discard': True
+ # }
+ # frame = MacBridgeServiceProfileFrame(mac_bridge_service_profile_entity_id,
+ # attributes).create()
+ # results = yield omci.send(frame)
+ #
+ # status = results.fields['omci_message'].fields['success_code']
+ # error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
+ # self.log.debug('create-mac-bridge-service-profile', status=status, error_mask=error_mask)
+ #
+ # ################################################################################
+ # # IEEE 802.1 Mapper Service config - Once per PON
+ # #
+ # # EntityID will be referenced by:
+ # # - MAC Bridge Port Configuration Data for the PON port
+ # # References:
+ # # - Nothing at this point. When a GEM port is created, this entity will
+ # # be updated to reference the GEM Interworking TP
+ #
+ # frame = Ieee8021pMapperServiceProfileFrame(ieee_mapper_service_profile_entity_id).create()
+ # results = yield omci.send(frame)
+ #
+ # status = results.fields['omci_message'].fields['success_code']
+ # error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
+ # self.log.debug('create-8021p-mapper-service-profile', status=status, error_mask=error_mask)
+ #
+ # ################################################################################
+ # # Create MAC Bridge Port Configuration Data for the PON port via IEEE 802.1
+ # # mapper service. Upon receipt by the ONU, the ONU will create an instance
+ # # of the following before returning the response.
+ # #
+ # # - MAC bridge port designation data
+ # # - MAC bridge port filter table data
+ # # - MAC bridge port bridge table data
+ # #
+ # # EntityID will be referenced by:
+ # # - Implicitly by the VLAN tagging filter data
+ # # References:
+ # # - MAC Bridge Service Profile (the bridge)
+ # # - IEEE 802.1p mapper service profile for PON port
+ #
+ # frame = MacBridgePortConfigurationDataFrame(
+ # mac_bridge_port_ani_entity_id, # Entity ID
+ # bridge_id_pointer=mac_bridge_service_profile_entity_id, # Bridge Entity ID
+ # # TODO: The PORT number for this port and the UNI port are the same. Is this correct?
+ # port_num=0, # Port ID
+ # tp_type=3, # TP Type (IEEE 802.1p mapper service)
+ # tp_pointer=ieee_mapper_service_profile_entity_id # TP ID, 8021p mapper ID
+ # ).create()
+ # results = yield omci.send(frame)
+ #
+ # status = results.fields['omci_message'].fields['success_code']
+ # error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
+ # self.log.debug('create-mac-bridge-port-configuration-data-part-1', status=status, error_mask=error_mask)
+ #
+ # ################################################################################
+ # # MAC Bridge Port config
+ # # This configuration is for Ethernet UNI
+ # #
+ # # EntityID will be referenced by:
+ # # - Nothing
+ # # References:
+ # # - MAC Bridge Service Profile (the bridge)
+ # # - PPTP Ethernet UNI
+ #
+ # frame = MacBridgePortConfigurationDataFrame(
+ # 0x000, # Entity ID - This is read-only/set-by-create !!!
+ # bridge_id_pointer=mac_bridge_service_profile_entity_id, # Bridge Entity ID
+ # port_num=0, # Port ID
+ # tp_type=1, # PPTP Ethernet UNI
+ # tp_pointer=ethernet_uni_entity_id # TP ID, 8021p mapper Id
+ # ).create()
+ # results = yield omci.send(frame)
+ #
+ # status = results.fields['omci_message'].fields['success_code']
+ # error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
+ # self.log.debug('create-mac-bridge-port-configuration-data-part-2', status=status, error_mask=error_mask)
+ #
+ # ################################################################################
+ # # VLAN Tagging Filter config
+ # #
+ # # EntityID will be referenced by:
+ # # - Nothing
+ # # References:
+ # # - MacBridgePortConfigurationData for the ANI/PON side
+ # #
+ # # Set anything, this request will not be used when using Extended Vlan
+ #
+ # frame = VlanTaggingFilterDataFrame(
+ # mac_bridge_port_ani_entity_id, # Entity ID
+ # vlan_tcis=[vlan_tcis_1], # VLAN IDs
+ # forward_operation=0x10
+ # ).create()
+ # results = yield omci.send(frame)
+ #
+ # status = results.fields['omci_message'].fields['success_code']
+ # error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
+ # self.log.debug('create-vlan-tagging-filter-data', status=status, error_mask=error_mask)
+ #
+ # ################################################################################
+ # # Update the IEEE 802.1p Mapper Service Profile config
+ # #
+ # # EntityID was created prior to this call. This is a set
+ # #
+ # # References:
+ # # - Gem Interwork TPs are set here
+ # #
+ # # TODO: All p-bits currently go to the one and only GEMPORT ID for now
+ # gem_ports = self._handler.pon_port.gem_ports
+ # gem_entity_ids = [gem_port.entity_id for _, gem_port in self._gem_ports.items()] \
+ # if len(self._gem_ports) else [OmciNullPointer]
+ #
+ # frame = Ieee8021pMapperServiceProfileFrame(
+ # ieee_mapper_service_profile_entity_id, # 802.1p mapper Service Mapper Profile ID
+ # interwork_tp_pointers=gem_entity_ids # Interworking TP IDs
+ # ).set()
+ # results = yield omci.send(frame)
+ #
+ # status = results.fields['omci_message'].fields['success_code']
+ # failed_attributes_mask = results.fields['omci_message'].fields['failed_attributes_mask']
+ # unsupported_attributes_mask = results.fields['omci_message'].fields['unsupported_attributes_mask']
+ # self.log.debug('set-8021p-mapper-service-profile', status=status,
+ # failed_attributes_mask=failed_attributes_mask,
+ # unsupported_attributes_mask=unsupported_attributes_mask)
+ #
+ # ################################################################################
+ # # Unlock UNI
+ # #
+ # # EntityID will be referenced by:
+ # # - MAC bridge port configuration data for the UNI side
+ # # References:
+ # # - Nothing
+ #
+ # attributes = dict(
+ # administrative_state=0 # 0 - Unlock
+ # )
+ # frame = PptpEthernetUniFrame(
+ # ethernet_uni_entity_id, # Entity ID
+ # attributes=attributes # See above
+ # ).set()
+ # results = yield omci.send(frame)
+ #
+ # status = results.fields['omci_message'].fields['success_code']
+ # failed_attributes_mask = results.fields['omci_message'].fields['failed_attributes_mask']
+ # unsupported_attributes_mask = results.fields['omci_message'].fields['unsupported_attributes_mask']
+ # self.log.debug('set-pptp-ethernet-uni', status=status,
+ # failed_attributes_mask=failed_attributes_mask,
+ # unsupported_attributes_mask=unsupported_attributes_mask)
+ #
+ # ################################################################################
+ # # Create Extended VLAN Tagging Operation config
+ # #
+ # # EntityID relates to the VLAN TCIS
+ # # References:
+ # # - VLAN TCIS from previously created VLAN Tagging filter data
+ # # - PPTP Ethernet UNI
+ # #
+ # # TODO: add entry here for additional UNI interfaces
+ #
+ # attributes = dict(
+ # association_type=2, # Assoc Type, PPTP Ethernet UNI
+ # associated_me_pointer=ethernet_uni_entity_id # Assoc ME, PPTP Entity Id
+ # )
+ #
+ # frame = ExtendedVlanTaggingOperationConfigurationDataFrame(
+ # vlan_config_entity_id,
+ # attributes=attributes
+ # ).create()
+ # results = yield omci.send(frame)
+ #
+ # status = results.fields['omci_message'].fields['success_code']
+ # error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
+ # self.log.debug('create-extended-vlan-tagging-operation-configuration-data', status=status,
+ # error_mask=error_mask)
+ #
+ # ################################################################################
+ # # Update Extended VLAN Tagging Operation Config Data
+ # #
+ # # Specifies the TPIDs in use and that operations in the downstream direction are
+ # # inverse to the operations in the upstream direction
+ # # TODO: Downstream mode may need to be modified once we work more on the flow rules
+ #
+ # attributes = dict(
+ # input_tpid=0x8100, # input TPID
+ # output_tpid=0x8100, # output TPID
+ # downstream_mode=0, # inverse of upstream
+ # )
+ # frame = ExtendedVlanTaggingOperationConfigurationDataFrame(
+ # vlan_config_entity_id,
+ # attributes=attributes
+ # ).set()
+ # results = yield omci.send(frame)
+ #
+ # status = results.fields['omci_message'].fields['success_code']
+ # failed_attributes_mask = results.fields['omci_message'].fields['failed_attributes_mask']
+ # unsupported_attributes_mask = results.fields['omci_message'].fields['unsupported_attributes_mask']
+ # self.log.debug('set-extended-vlan-tagging-operation-configuration-data', status=status,
+ # failed_attributes_mask=failed_attributes_mask,
+ # unsupported_attributes_mask=unsupported_attributes_mask)
+ #
+ # ################################################################################
+ # # Update Extended VLAN Tagging Operation Config Data
+ # #
+ # # parameters: Entity Id ( 0x900), Filter Inner Vlan Id(0x1000-4096,do not filter on Inner vid,
+ # # Treatment Inner Vlan Id : 2
+ #
+ # attributes = dict(
+ # received_frame_vlan_tagging_operation_table=
+ # VlanTaggingOperation(
+ # filter_outer_priority=15, # This entry is not a double-tag rule
+ # filter_outer_vid=4096, # Do not filter on the outer VID value
+ # filter_outer_tpid_de=0, # Do not filter on the outer TPID field
+ #
+ # filter_inner_priority=15, # This is a no-tag rule, ignore all other VLAN tag filter fields
+ # filter_inner_vid=0x1000, # Do not filter on the inner VID
+ # filter_inner_tpid_de=0, # Do not filter on inner TPID field
+ # filter_ether_type=0, # Do not filter on EtherType
+ #
+ # treatment_tags_to_remove=0, # Remove 0 tags
+ # treatment_outer_priority=15, # Do not add an outer tag
+ # treatment_outer_vid=0, # n/a
+ # treatment_outer_tpid_de=0, # n/a
+ #
+ # treatment_inner_priority=0, # Add an inner tag and insert this value as the priority
+ # treatment_inner_vid=cvid, # use this value as the VID in the inner VLAN tag
+ # treatment_inner_tpid_de=4 # set TPID = 0x8100
+ # )
+ # )
+ # frame = ExtendedVlanTaggingOperationConfigurationDataFrame(
+ # vlan_config_entity_id, # Entity ID BP: Oldvalue 0x202
+ # attributes=attributes # See above
+ # ).set()
+ # results = yield omci.send(frame)
+ #
+ # status = results.fields['omci_message'].fields['success_code']
+ # failed_attributes_mask = results.fields['omci_message'].fields['failed_attributes_mask']
+ # unsupported_attributes_mask = results.fields['omci_message'].fields['unsupported_attributes_mask']
+ # self.log.debug('set-extended-vlan-tagging-operation-configuration-data-untagged', status=status,
+ # failed_attributes_mask=failed_attributes_mask,
+ # unsupported_attributes_mask=unsupported_attributes_mask)
+ #
+ # # BP: This is for AT&T RG's
+ # #
+ # # TODO: CB: NOTE: TRY THIS ONCE OTHER SEQUENCES WORK
+ # #
+ # # Set AR - ExtendedVlanTaggingOperationConfigData
+ # # 514 - RxVlanTaggingOperationTable - add VLAN <cvid> to priority tagged pkts - c-vid
+ # # results = yield omci.send_set_extended_vlan_tagging_operation_vlan_configuration_data_single_tag(
+ # # 0x900, # Entity ID
+ # # 8, # Filter Inner Priority, do not filter on Inner Priority
+ # # 0, # Filter Inner VID, this will be 0 in CORD
+ # # 0, # Filter Inner TPID DE
+ # # 1, # Treatment tags, number of tags to remove
+ # # 8, # Treatment inner priority, copy Inner Priority
+ # # 2) # Treatment inner VID, this will be 2 in CORD
+ #
+ # # Set AR - ExtendedVlanTaggingOperationConfigData
+ # # 514 - RxVlanTaggingOperationTable - add VLAN <cvid> to priority tagged pkts - c-vid
+ # # results = yield omci.send_set_extended_vlan_tagging_operation_vlan_configuration_data_single_tag(
+ # # 0x200, # Entity ID
+ # # 8, # Filter Inner Priority
+ # # 0, # Filter Inner VID
+ # # 0, # Filter Inner TPID DE
+ # # 1, # Treatment tags to remove
+ # # 8, # Treatment inner priority
+ # # cvid) # Treatment inner VID
+ # #
+ # # Set AR - ExtendedVlanTaggingOperationConfigData
+ # # 514 - RxVlanTaggingOperationTable - add VLAN <cvid> to untagged pkts - c-vid
+ # # results = yield omci.send_set_extended_vlan_tagging_operation_vlan_configuration_data_untagged(
+ # # 0x100, # Entity ID BP: Oldvalue 0x202
+ # # 0x1000, # Filter Inner VID BP: Oldvalue 0x1000
+ # # cvid) # Treatment inner VID BP: cvid
+ #
+ # # success = results.fields['omci_message'].fields['success_code'] == 0
+ # # error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
+ #
+ # ###############################################################################
+ # # If here, we are done
+ # self._bridge_initialized = True
+ # device.reason = ''
+ # self._handler.adapter_agent.update_device(device)
+ #
+ # except TimeoutError as e:
+ # self.log.warn('rx-timeout', frame=frame)
+ # self._deferred = reactor.callLater(_STARTUP_RETRY_WAIT,
+ # self.resync_omci_settings)
+ # returnValue('retry-pending')
+ #
+ # except Exception as e:
+ # self.log.exception('omci-setup', e=e)
+ # device.reason = 'OMCI setup sequence failure: ' + e.message
+ # self._handler.adapter_agent.update_device(device)
+ #
+ # # Try again later
+ # self._deferred = reactor.callLater(_STARTUP_RETRY_WAIT,
+ # self.resync_omci_settings)
+ # else:
+ # self._deferred = reactor.callLater(_STARTUP_RETRY_WAIT,
+ # self.resync_omci_settings)
+
+ self.deferred.callback("TODO: Done, what should we provide back that is of value?")
+ #
+ # except TimeoutError as e:
+ # self.log.warn('download-timeout', e=e)
+ # self.deferred.errback(failure.Failure(e))
+ # # TODO: Recover any allocated objects (tconts, priority queues, ...)
+ # except Exception as e:
+ # self.log.exception('download', e=e)
+ # self.deferred.errback(failure.Failure(e))
+ # TODO: Recover any allocated objects (tconts, priority queues, ...)
diff --git a/voltha/adapters/adtran_onu/omci/adtn_mib_sync.py b/voltha/adapters/adtran_onu/omci/adtn_mib_sync.py
new file mode 100644
index 0000000..21e11d4
--- /dev/null
+++ b/voltha/adapters/adtran_onu/omci/adtn_mib_sync.py
@@ -0,0 +1,59 @@
+#
+# Copyright 2018 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+from voltha.extensions.omci.state_machines.mib_sync import MibSynchronizer
+
+
+class AdtnMibSynchronizer(MibSynchronizer):
+ """
+ OpenOMCI MIB Synchronizer state machine for Adtran ONUs
+ """
+ ADTN_RESYNC_DELAY = 60 # Periodically force a resync
+
+ def __init__(self, agent, device_id, mib_sync_tasks, db):
+ """
+ Class initialization
+
+ :param agent: (OpenOmciAgent) Agent
+ :param device_id: (str) ONU Device ID
+ :param db: (MibDbVolatileDict) MIB Database
+ :param mib_sync_tasks: (dict) Tasks to run
+ """
+ super(AdtnMibSynchronizer, self).__init__(agent, device_id, mib_sync_tasks, db,
+ # states=MibSynchronizer.DEFAULT_STATES,
+ # transitions=MibSynchronizer.DEFAULT_TRANSITIONS,
+ # initial_state='disabled',
+ # timeout_delay=MibSynchronizer.DEFAULT_TIMEOUT_RETRY,
+ # audit_delay=MibSynchronizer.DEFAULT_AUDIT_DELAY,
+ resync_delay=AdtnMibSynchronizer.ADTN_RESYNC_DELAY)
+ self._omci_managed = False # TODO: Look up model number/check handler
+
+ def on_enter_auditing(self):
+ """
+ Perform a MIB Audit. If our last MIB resync was too long in the
+ past, perform a resynchronization anyway
+ """
+ # Is this a model that supports full OMCI management. If so, use standard
+ # forced resync delay
+
+ if not self._omci_managed and self._check_if_mib_data_sync_supported():
+ self._omci_managed = True
+ # Revert to standard timeouts
+ self._resync_delay = MibSynchronizer.DEFAULT_RESYNC_DELAY
+
+ super(AdtnMibSynchronizer, self).on_enter_auditing()
+
+ def _check_if_mib_data_sync_supported(self):
+ return False # TODO: Look up to see if we are/check handler
diff --git a/voltha/adapters/adtran_onu/omci/omci.py b/voltha/adapters/adtran_onu/omci/omci.py
new file mode 100644
index 0000000..ea7abaf
--- /dev/null
+++ b/voltha/adapters/adtran_onu/omci/omci.py
@@ -0,0 +1,784 @@
+# Copyright 2018-present Adtran, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import structlog
+from twisted.internet.defer import inlineCallbacks, returnValue, TimeoutError
+from twisted.internet import reactor
+
+from voltha.protos.device_pb2 import Image
+
+from voltha.protos.common_pb2 import OperStatus, ConnectStatus
+from voltha.extensions.omci.onu_configuration import OMCCVersion
+
+from omci_entities import onu_custom_me_entities
+from voltha.extensions.omci.omci_me import *
+
+_STARTUP_RETRY_WAIT = 5
+# abbreviations
+OP = EntityOperations
+
+
+class OMCI(object):
+ """
+ OpenOMCI Support
+ """
+ def __init__(self, handler, omci_agent):
+ self.log = structlog.get_logger(device_id=handler.device_id)
+ self._handler = handler
+ self._openomci_agent = omci_agent
+ self._enabled = False
+ self._connected = False
+ self._deferred = None
+ self._resync_deferred = None # For TCont/GEM use
+ self._bridge_initialized = False
+ self._in_sync_reached = False
+
+ self._omcc_version = OMCCVersion.Unknown
+ self._total_tcont_count = 0 # From ANI-G ME
+ self._qos_flexibility = 0 # From ONT2_G ME
+
+ self._in_sync_subscription = None
+ self._connectivity_subscription = None
+ self._capabilities_subscription = None
+
+ self._mib_download_task = None
+ self._mib_download_deferred = None
+
+ self._onu_omci_device = omci_agent.add_device(handler.device_id,
+ handler.adapter_agent,
+ onu_custom_me_entities(),
+ support_classes=handler.adapter.adtran_omci)
+
+ def __str__(self):
+ return "OMCI"
+
+ @property
+ def omci_agent(self):
+ return self._openomci_agent
+
+ @property
+ def omci_cc(self):
+ # TODO: Decrement access to Communications channel at this point? What about current PM stuff?
+ return self.onu_omci_device.omci_cc if self._onu_omci_device is not None else None
+
+ def receive_message(self, msg):
+ if self.enabled:
+ # TODO: Have OpenOMCI actually receive the messages
+ self.omci_cc.receive_message(msg)
+
+ def _start(self):
+ self._cancel_deferred()
+
+ # Subscriber to events of interest in OpenOMCI
+ self._subscribe_to_events()
+ self._onu_omci_device.start()
+
+ if self._onu_omci_device.mib_db_in_sync:
+ self._deferred = reactor.callLater(0, self._mib_in_sync)
+
+ def _stop(self):
+ self._cancel_deferred()
+
+ # Unsubscribe to OpenOMCI Events
+ self._unsubscribe_to_events()
+ self._onu_omci_device.stop() # Will also cancel any running tasks/state-machines
+
+ self._mib_download_task = None
+ self._bridge_initialized = False
+ self._in_sync_reached = False
+
+ # TODO: stop h/w sync
+
+ def _cancel_deferred(self):
+ d1, self._deferred = self._deferred, None
+ d2, self._resync_deferred = self._resync_deferred, None
+ d3, self._mib_download_deferred = self._mib_download_deferred, None
+
+ for d in [d1, d2, d3]:
+ try:
+ if d is not None and not d.called:
+ d.cancel()
+ except:
+ pass
+
+ def _cancel_resync_deferred(self):
+ d, self._resync_deferred = self._resync_deferred, None
+ try:
+ if d is not None and not d.called:
+ d.cancel()
+ except:
+ pass
+
+ def delete(self):
+ self.enabled = False
+
+ agent, self._openomci_agent = self._openomci_agent, None
+ device_id = self._handler.device_id
+ self._onu_omci_device = None
+ self._handler = None
+
+ if agent is not None:
+ agent(device_id, cleanup=True)
+
+ @property
+ def enabled(self):
+ return self._enabled
+
+ @enabled.setter
+ def enabled(self, value):
+ if self._enabled != value:
+ self._enabled = value
+
+ if value:
+ self._start()
+ else:
+ self._stop()
+
+ @property
+ def connected(self):
+ return self._connected
+
+ @property
+ def onu_omci_device(self):
+ return self._onu_omci_device
+
+ def _mib_in_sync(self):
+ """
+ This method is ran whenever the ONU MIB database is in-sync. This is often after
+ the initial MIB Upload during ONU startup, or after it has gone out-of-sync and
+ then back in. This second case could be due a reboot of the ONU and a new version
+ of firmware is running on the ONU hardware.
+ """
+ self.log.info('mib-in-sync')
+
+ device = self._handler.adapter_agent.get_device(self._handler.device_id)
+ device.oper_status = OperStatus.ACTIVE
+ device.connect_status = ConnectStatus.REACHABLE
+ device.reason = 'MIB Synchronization complete'
+ self._handler.adapter_agent.update_device(device)
+
+ omci_dev = self._onu_omci_device
+ config = omci_dev.configuration
+
+ # In Sync, we can register logical ports now. Ideally this could occur on
+ # the first time we received a successful (no timeout) OMCI Rx response.
+ try:
+ device = self._handler.adapter_agent.get_device(self._handler.device_id)
+
+ ani_g = config.ani_g_entities
+ uni_g = config.uni_g_entities
+ pon_ports = len(ani_g) if ani_g is not None else 0
+ uni_ports = len(uni_g) if uni_g is not None else 0
+
+ assert pon_ports == 1, 'Expected one PON/ANI port, got {}'.format(pon_ports)
+ assert uni_ports == 1, 'Expected one UNI port, got {}'.format(uni_ports)
+
+ self._total_tcont_count = ani_g.get('total-tcont-count')
+ self._qos_flexibility = config.qos_configuration_flexibility or 0
+ self._omcc_version = config.omcc_version or OMCCVersion.Unknown
+
+ # vendorProductCode = str(config.vendor_product_code or 'unknown').rstrip('\0')
+
+ host_info = omci_dev.query_mib(IpHostConfigData.class_id)
+ mgmt_mac_address = next((host_info[inst].get('attributes').get('mac_address')
+ for inst in host_info
+ if isinstance(inst, int)), 'unknown')
+ device.mac_address = str(mgmt_mac_address)
+ device.model = str(config.version or 'unknown').rstrip('\0')
+
+ equipment_id = config.equipment_id or " unknown unknown "
+ eqpt_boot_version = str(equipment_id).rstrip('\0')
+ # eqptId = eqpt_boot_version[:10] # ie) BVMDZ10DRA
+ boot_version = eqpt_boot_version[12:] # ie) CML.D55~
+
+ images = [Image(name='boot-code',
+ version=boot_version.rstrip('\0'),
+ is_active=False,
+ is_committed=True,
+ is_valid=True,
+ install_datetime='Not Available',
+ hash='Not Available')] + \
+ config.software_images
+
+ del (device.images.image[:]) # Clear previous entries
+ device.images.image.extend(images)
+
+ # Save our device information
+ self._handler.adapter_agent.update_device(device)
+
+ # Start MIB download TODO: This will be replaced with a MIB Download task soon
+ self._in_sync_reached = True
+ self._deferred = reactor.callLater(0, self.resync_omci_settings)
+
+ except Exception as e:
+ self.log.exception('device-info-load', e=e)
+ self._deferred = reactor.callLater(_STARTUP_RETRY_WAIT, self._mib_in_sync())
+
+ def gem_or_tcont_added(self):
+ if self._in_sync_reached:
+ self._cancel_resync_deferred()
+ self._resync_deferred = reactor.callLater(_STARTUP_RETRY_WAIT,
+ self.resync_omci_settings)
+
+ @inlineCallbacks
+ def resync_omci_settings(self):
+ #
+ # TODO: All of these steps below are being moved into an OpenOMCI Task. !!!!
+ #
+ # This will first be the AdtnMibDownloadTask task. As more ONUs are converted
+ # to OpenOMCI, I am hoping to come up with a shared/generic version all can use
+ #
+ # Note also that this sets up everything for the user right now. It will be refactored
+ # once Service Tech Profiles are available.
+ #
+ self._cancel_resync_deferred()
+ self.log.debug('resync-omci-settings', initialized=self._bridge_initialized)
+
+ if not self.enabled:
+ returnValue('not-enabled')
+
+ device = self._handler.adapter_agent.get_device(self._handler.device_id)
+
+ def resources_available():
+ return (device.vlan > 0 and
+ len(self._handler.uni_ports) > 0 and
+ len(self._handler.pon_port.tconts) and
+ len(self._handler.pon_port.gem_ports))
+
+ if not self._bridge_initialized and self._in_sync_reached and resources_available():
+ device.reason = 'Performing OMCI Download'
+ self._handler.adapter_agent.update_device(device)
+
+ omci = self.omci_cc
+
+ #############################################
+ # All our variables here
+ # TODO: Move elsewhere in future version of this software
+ # TODO: Make as many entity IDs dynamic/discovered as possible
+
+ frame = None
+ gal_enet_profile_entity_id = 0x100
+ ieee_mapper_service_profile_entity_id = 0x100
+ mac_bridge_service_profile_entity_id = 0x100
+ mac_bridge_port_ani_entity_id = 0x100
+ ethernet_uni_entity_id = 0x101 # TODO: This can be retrieved from the UNI-G instance_id
+ vlan_tcis_1 = 0x900
+ vlan_config_entity_id = vlan_tcis_1
+ cvid = device.vlan
+
+ try:
+ ################################################################################
+ # TCONTS
+ #
+ # EntityID will be referenced by:
+ # - GemPortNetworkCtp
+ # References:
+ # - ONU created TCONT (created on ONU startup)
+
+ omci_dev = self._onu_omci_device
+ tcont_idents = omci_dev.query_mib(Tcont.class_id)
+ self.log.debug('tcont-idents', tcont_idents=tcont_idents)
+
+ for tcont in self._handler.pon_port.tconts.itervalues():
+ free_entity_id = next((k for k, v in tcont_idents.items()
+ if isinstance(k, int) and
+ v.get('attributes', {}).get('alloc_id', 0) == 0xFFFF), None)
+ if free_entity_id is None:
+ self.log.error('no-available-tconts')
+ break
+
+ yield tcont.add_to_hardware(omci, free_entity_id)
+
+ ################################################################################
+ # GEMS (GemPortNetworkCtp and GemInterworkingTp)
+ #
+ # For both of these MEs, the entity_id is the GEM Port ID. The entity id of the
+ # GemInterworkingTp ME could be different since it has an attribute to specify
+ # the GemPortNetworkCtp entity id.
+ #
+ # TODO: In the GEM Port routine to add, it has a hardcoded upstream TM ID of 0x8000
+ # for the GemPortNetworkCtp ME
+ #
+ # GemPortNetworkCtp
+ # EntityID will be referenced by:
+ # - GemInterworkingTp
+ # References:
+ # - TCONT
+ # - Hardcoded upstream TM Entity ID
+ # - (Possibly in Future) Upstream Traffic descriptor profile pointer
+ #
+ # GemInterworkingTp
+ # EntityID will be referenced by:
+ # - Ieee8021pMapperServiceProfile
+ # References:
+ # - GemPortNetworkCtp
+ # - Ieee8021pMapperServiceProfile
+ # - GalEthernetProfile
+ #
+ for gem_port in self._handler.pon_port.gem_ports.itervalues():
+ tcont = gem_port.tcont
+ if tcont is None:
+ self.log.error('unknown-tcont-reference', gem_id=gem_port.gem_id)
+ continue
+
+ yield gem_port.add_to_hardware(omci,
+ tcont.entity_id,
+ ieee_mapper_service_profile_entity_id,
+ gal_enet_profile_entity_id)
+
+ ########################################################################################
+ # Create GalEthernetProfile - Once per ONU/PON interface
+ #
+ # EntityID will be referenced by:
+ # - GemInterworkingTp
+ # References:
+ # - Nothing
+
+ frame = GalEthernetProfileFrame(gal_enet_profile_entity_id,
+ max_gem_payload_size=1518).create() # Max GEM Payload size
+ results = yield omci.send(frame)
+
+ status = results.fields['omci_message'].fields['success_code']
+ error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
+ self.log.debug('create-gal-ethernet-profile', status=status, error_mask=error_mask)
+
+ ################################################################################
+ # MAC Bridge Service Profile - Once per UNI
+ #
+ # EntityID will be referenced by:
+ # - MAC Bridge Port Configuration Data
+ # References:
+ # - Nothing
+
+ attributes = {
+ 'spanning_tree_ind': False,
+ # TODO: CB: see if we need or can use any of the following...
+ # 'learning_ind': True,
+ # 'priority': 0x8000,
+ # 'max_age': 20 * 256,
+ # 'hello_time': 2 * 256,
+ # 'forward_delay': 15 * 256,
+ # 'unknown_mac_address_discard': True
+ }
+ frame = MacBridgeServiceProfileFrame(mac_bridge_service_profile_entity_id,
+ attributes).create()
+ results = yield omci.send(frame)
+
+ status = results.fields['omci_message'].fields['success_code']
+ error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
+ self.log.debug('create-mac-bridge-service-profile', status=status, error_mask=error_mask)
+
+ ################################################################################
+ # IEEE 802.1 Mapper Service config - Once per PON
+ #
+ # EntityID will be referenced by:
+ # - MAC Bridge Port Configuration Data for the PON port
+ # References:
+ # - Nothing at this point. When a GEM port is created, this entity will
+ # be updated to reference the GEM Interworking TP
+
+ frame = Ieee8021pMapperServiceProfileFrame(ieee_mapper_service_profile_entity_id).create()
+ results = yield omci.send(frame)
+
+ status = results.fields['omci_message'].fields['success_code']
+ error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
+ self.log.debug('create-8021p-mapper-service-profile', status=status, error_mask=error_mask)
+
+ ################################################################################
+ # Create MAC Bridge Port Configuration Data for the PON port via IEEE 802.1
+ # mapper service. Upon receipt by the ONU, the ONU will create an instance
+ # of the following before returning the response.
+ #
+ # - MAC bridge port designation data
+ # - MAC bridge port filter table data
+ # - MAC bridge port bridge table data
+ #
+ # EntityID will be referenced by:
+ # - Implicitly by the VLAN tagging filter data
+ # References:
+ # - MAC Bridge Service Profile (the bridge)
+ # - IEEE 802.1p mapper service profile for PON port
+
+ frame = MacBridgePortConfigurationDataFrame(
+ mac_bridge_port_ani_entity_id, # Entity ID
+ bridge_id_pointer=mac_bridge_service_profile_entity_id, # Bridge Entity ID
+ # TODO: The PORT number for this port and the UNI port are the same. Is this correct?
+ port_num=0, # Port ID
+ tp_type=3, # TP Type (IEEE 802.1p mapper service)
+ tp_pointer=ieee_mapper_service_profile_entity_id # TP ID, 8021p mapper ID
+ ).create()
+ results = yield omci.send(frame)
+
+ status = results.fields['omci_message'].fields['success_code']
+ error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
+ self.log.debug('create-mac-bridge-port-configuration-data-part-1', status=status, error_mask=error_mask)
+
+ ################################################################################
+ # MAC Bridge Port config
+ # This configuration is for Ethernet UNI
+ #
+ # EntityID will be referenced by:
+ # - Nothing
+ # References:
+ # - MAC Bridge Service Profile (the bridge)
+ # - PPTP Ethernet UNI
+
+ frame = MacBridgePortConfigurationDataFrame(
+ 0x000, # Entity ID - This is read-only/set-by-create !!!
+ bridge_id_pointer=mac_bridge_service_profile_entity_id, # Bridge Entity ID
+ port_num=0, # Port ID
+ tp_type=1, # PPTP Ethernet UNI
+ tp_pointer=ethernet_uni_entity_id # TP ID, 8021p mapper Id
+ ).create()
+ results = yield omci.send(frame)
+
+ status = results.fields['omci_message'].fields['success_code']
+ error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
+ self.log.debug('create-mac-bridge-port-configuration-data-part-2', status=status, error_mask=error_mask)
+
+ ################################################################################
+ # VLAN Tagging Filter config
+ #
+ # EntityID will be referenced by:
+ # - Nothing
+ # References:
+ # - MacBridgePortConfigurationData for the ANI/PON side
+ #
+ # Set anything, this request will not be used when using Extended Vlan
+
+ frame = VlanTaggingFilterDataFrame(
+ mac_bridge_port_ani_entity_id, # Entity ID
+ vlan_tcis=[vlan_tcis_1], # VLAN IDs
+ forward_operation=0x10
+ ).create()
+ results = yield omci.send(frame)
+
+ status = results.fields['omci_message'].fields['success_code']
+ error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
+ self.log.debug('create-vlan-tagging-filter-data', status=status, error_mask=error_mask)
+
+ ################################################################################
+ # Update the IEEE 802.1p Mapper Service Profile config
+ #
+ # EntityID was created prior to this call. This is a set
+ #
+ # References:
+ # - Gem Interwork TPs are set here
+ #
+ # TODO: All p-bits currently go to the one and only GEMPORT ID for now
+ gem_ports = self._handler.pon_port.gem_ports
+ gem_entity_ids = [gem_port.entity_id for _, gem_port in gem_ports.items()] \
+ if len(gem_ports) else [OmciNullPointer]
+
+ frame = Ieee8021pMapperServiceProfileFrame(
+ ieee_mapper_service_profile_entity_id, # 802.1p mapper Service Mapper Profile ID
+ interwork_tp_pointers=gem_entity_ids # Interworking TP IDs
+ ).set()
+ results = yield omci.send(frame)
+
+ status = results.fields['omci_message'].fields['success_code']
+ failed_attributes_mask = results.fields['omci_message'].fields['failed_attributes_mask']
+ unsupported_attributes_mask = results.fields['omci_message'].fields['unsupported_attributes_mask']
+ self.log.debug('set-8021p-mapper-service-profile', status=status,
+ failed_attributes_mask=failed_attributes_mask,
+ unsupported_attributes_mask=unsupported_attributes_mask)
+
+ ################################################################################
+ # Unlock UNI
+ #
+ # EntityID will be referenced by:
+ # - MAC bridge port configuration data for the UNI side
+ # References:
+ # - Nothing
+
+ attributes = dict(
+ administrative_state=0 # 0 - Unlock
+ )
+ frame = PptpEthernetUniFrame(
+ ethernet_uni_entity_id, # Entity ID
+ attributes=attributes # See above
+ ).set()
+ results = yield omci.send(frame)
+
+ status = results.fields['omci_message'].fields['success_code']
+ failed_attributes_mask = results.fields['omci_message'].fields['failed_attributes_mask']
+ unsupported_attributes_mask = results.fields['omci_message'].fields['unsupported_attributes_mask']
+ self.log.debug('set-pptp-ethernet-uni', status=status,
+ failed_attributes_mask=failed_attributes_mask,
+ unsupported_attributes_mask=unsupported_attributes_mask)
+
+ ################################################################################
+ # Create Extended VLAN Tagging Operation config
+ #
+ # EntityID relates to the VLAN TCIS
+ # References:
+ # - VLAN TCIS from previously created VLAN Tagging filter data
+ # - PPTP Ethernet UNI
+ #
+ # TODO: add entry here for additional UNI interfaces
+
+ attributes = dict(
+ association_type=2, # Assoc Type, PPTP Ethernet UNI
+ associated_me_pointer=ethernet_uni_entity_id # Assoc ME, PPTP Entity Id
+ )
+
+ frame = ExtendedVlanTaggingOperationConfigurationDataFrame(
+ vlan_config_entity_id,
+ attributes=attributes
+ ).create()
+ results = yield omci.send(frame)
+
+ status = results.fields['omci_message'].fields['success_code']
+ error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
+ self.log.debug('create-extended-vlan-tagging-operation-configuration-data', status=status, error_mask=error_mask)
+
+ ################################################################################
+ # Update Extended VLAN Tagging Operation Config Data
+ #
+ # Specifies the TPIDs in use and that operations in the downstream direction are
+ # inverse to the operations in the upstream direction
+ # TODO: Downstream mode may need to be modified once we work more on the flow rules
+
+ attributes = dict(
+ input_tpid=0x8100, # input TPID
+ output_tpid=0x8100, # output TPID
+ downstream_mode=0, # inverse of upstream
+ )
+ frame = ExtendedVlanTaggingOperationConfigurationDataFrame(
+ vlan_config_entity_id,
+ attributes=attributes
+ ).set()
+ results = yield omci.send(frame)
+
+ status = results.fields['omci_message'].fields['success_code']
+ failed_attributes_mask = results.fields['omci_message'].fields['failed_attributes_mask']
+ unsupported_attributes_mask = results.fields['omci_message'].fields['unsupported_attributes_mask']
+ self.log.debug('set-extended-vlan-tagging-operation-configuration-data', status=status,
+ failed_attributes_mask=failed_attributes_mask,
+ unsupported_attributes_mask=unsupported_attributes_mask)
+
+ ################################################################################
+ # Update Extended VLAN Tagging Operation Config Data
+ #
+ # parameters: Entity Id ( 0x900), Filter Inner Vlan Id(0x1000-4096,do not filter on Inner vid,
+ # Treatment Inner Vlan Id : 2
+
+ attributes = dict(
+ received_frame_vlan_tagging_operation_table=
+ VlanTaggingOperation(
+ filter_outer_priority=15, # This entry is not a double-tag rule
+ filter_outer_vid=4096, # Do not filter on the outer VID value
+ filter_outer_tpid_de=0, # Do not filter on the outer TPID field
+
+ filter_inner_priority=15, # This is a no-tag rule, ignore all other VLAN tag filter fields
+ filter_inner_vid=0x1000, # Do not filter on the inner VID
+ filter_inner_tpid_de=0, # Do not filter on inner TPID field
+ filter_ether_type=0, # Do not filter on EtherType
+
+ treatment_tags_to_remove=0, # Remove 0 tags
+ treatment_outer_priority=15, # Do not add an outer tag
+ treatment_outer_vid=0, # n/a
+ treatment_outer_tpid_de=0, # n/a
+
+ treatment_inner_priority=0, # Add an inner tag and insert this value as the priority
+ treatment_inner_vid=cvid, # use this value as the VID in the inner VLAN tag
+ treatment_inner_tpid_de=4 # set TPID = 0x8100
+ )
+ )
+ frame = ExtendedVlanTaggingOperationConfigurationDataFrame(
+ vlan_config_entity_id, # Entity ID BP: Oldvalue 0x202
+ attributes=attributes # See above
+ ).set()
+ results = yield omci.send(frame)
+
+ status = results.fields['omci_message'].fields['success_code']
+ failed_attributes_mask = results.fields['omci_message'].fields['failed_attributes_mask']
+ unsupported_attributes_mask = results.fields['omci_message'].fields['unsupported_attributes_mask']
+ self.log.debug('set-extended-vlan-tagging-operation-configuration-data-untagged', status=status,
+ failed_attributes_mask=failed_attributes_mask,
+ unsupported_attributes_mask=unsupported_attributes_mask)
+
+ # BP: This is for AT&T RG's
+ #
+ # TODO: CB: NOTE: TRY THIS ONCE OTHER SEQUENCES WORK
+ #
+ # Set AR - ExtendedVlanTaggingOperationConfigData
+ # 514 - RxVlanTaggingOperationTable - add VLAN <cvid> to priority tagged pkts - c-vid
+ # results = yield omci.send_set_extended_vlan_tagging_operation_vlan_configuration_data_single_tag(
+ # 0x900, # Entity ID
+ # 8, # Filter Inner Priority, do not filter on Inner Priority
+ # 0, # Filter Inner VID, this will be 0 in CORD
+ # 0, # Filter Inner TPID DE
+ # 1, # Treatment tags, number of tags to remove
+ # 8, # Treatment inner priority, copy Inner Priority
+ # 2) # Treatment inner VID, this will be 2 in CORD
+
+ # Set AR - ExtendedVlanTaggingOperationConfigData
+ # 514 - RxVlanTaggingOperationTable - add VLAN <cvid> to priority tagged pkts - c-vid
+ # results = yield omci.send_set_extended_vlan_tagging_operation_vlan_configuration_data_single_tag(
+ # 0x200, # Entity ID
+ # 8, # Filter Inner Priority
+ # 0, # Filter Inner VID
+ # 0, # Filter Inner TPID DE
+ # 1, # Treatment tags to remove
+ # 8, # Treatment inner priority
+ # cvid) # Treatment inner VID
+ #
+ # Set AR - ExtendedVlanTaggingOperationConfigData
+ # 514 - RxVlanTaggingOperationTable - add VLAN <cvid> to untagged pkts - c-vid
+ #results = yield omci.send_set_extended_vlan_tagging_operation_vlan_configuration_data_untagged(
+ # 0x100, # Entity ID BP: Oldvalue 0x202
+ # 0x1000, # Filter Inner VID BP: Oldvalue 0x1000
+ # cvid) # Treatment inner VID BP: cvid
+
+ # success = results.fields['omci_message'].fields['success_code'] == 0
+ # error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
+
+ ###############################################################################
+ # If here, we are done
+ self._bridge_initialized = True
+ device.reason = ''
+ self._handler.adapter_agent.update_device(device)
+
+ except TimeoutError as e:
+ self.log.warn('rx-timeout', frame=frame)
+ self._deferred = reactor.callLater(_STARTUP_RETRY_WAIT,
+ self.resync_omci_settings)
+ returnValue('retry-pending')
+
+ except Exception as e:
+ self.log.exception('omci-setup', e=e)
+ device.reason = 'OMCI setup sequence failure: ' + e.message
+ self._handler.adapter_agent.update_device(device)
+
+ # Try again later
+ self._deferred = reactor.callLater(_STARTUP_RETRY_WAIT,
+ self.resync_omci_settings)
+ else:
+ self._deferred = reactor.callLater(_STARTUP_RETRY_WAIT,
+ self.resync_omci_settings)
+
+ def _subscribe_to_events(self):
+ from voltha.extensions.omci.onu_device_entry import OnuDeviceEvents, \
+ OnuDeviceEntry
+ from voltha.extensions.omci.omci_cc import OMCI_CC, OmciCCRxEvents
+
+ # OMCI MIB Database sync status
+
+ bus = self._onu_omci_device.event_bus
+ topic = OnuDeviceEntry.event_bus_topic(self._handler.device_id,
+ OnuDeviceEvents.MibDatabaseSyncEvent)
+ self._in_sync_subscription = bus.subscribe(topic, self.in_sync_handler)
+
+ # OMCI Capabilities (MEs and Message Types
+
+ bus = self._onu_omci_device.event_bus
+ topic = OnuDeviceEntry.event_bus_topic(self._handler.device_id,
+ OnuDeviceEvents.OmciCapabilitiesEvent)
+ self._capabilities_subscription = bus.subscribe(topic, self.capabilties_handler)
+
+ # OMCI-CC Connectivity Events (for reachability/heartbeat)
+
+ bus = self._onu_omci_device.omci_cc.event_bus
+ topic = OMCI_CC.event_bus_topic(self._handler.device_id,
+ OmciCCRxEvents.Connectivity)
+ self._connectivity_subscription = bus.subscribe(topic, self.onu_is_reachable)
+
+ def _unsubscribe_to_events(self):
+ insync, self._in_sync_subscription = self._in_sync_subscription, None
+ connect, self._connectivity_subscription = self._connectivity_subscription, None
+ caps, self._capabilities_subscription = self._capabilities_subscription, None
+
+ if insync is not None:
+ bus = self._onu_omci_device.event_bus
+ bus.unsubscribe(insync)
+
+ if connect is not None:
+ bus = self._onu_omci_device.omci_cc.event_bus
+ bus.unsubscribe(connect)
+
+ if caps is not None:
+ bus = self._onu_omci_device.event_bus
+ bus.unsubscribe(caps)
+
+ def in_sync_handler(self, _topic, msg):
+ if self._in_sync_subscription is not None:
+ try:
+ from voltha.extensions.omci.onu_device_entry import IN_SYNC_KEY
+
+ if msg[IN_SYNC_KEY]:
+ # Start up device_info load from MIB DB
+ reactor.callLater(0, self._mib_in_sync)
+ else:
+ # Cancel any running/scheduled MIB download task
+ try:
+ d, self._mib_download_deferred = self._mib_download_deferred, None
+ d.cancel()
+ except:
+ pass
+
+ except Exception as e:
+ self.log.exception('in-sync', e=e)
+
+ def capabilties_handler(self, _topic, _msg):
+ """
+ This event occurs after an ONU reaches the In-Sync state and the OMCI ME has
+ been queried for supported ME and message types.
+
+ At this point, we can act upon any download device and/or service Technology
+ profiles (when they exist). For now, just run our somewhat fixed script
+ """
+ if self._capabilities_subscription is not None:
+ from adtn_mib_download_task import AdtnMibDownloadTask
+
+ def success(_results):
+ self._mib_download_task = None
+ pass # TODO. What's next...
+
+ def failure(_reason):
+ self._mib_download_task = None
+ # TODO: Handle failure, retry for now?
+ self._mib_download_deferred = reactor.callLater(_STARTUP_RETRY_WAIT,
+ self.capabilties_handler)
+ self._mib_download_task = AdtnMibDownloadTask(self.omci_agent, self._handler.device_id)
+ self._mib_download_deferred = self._onu_omci_device.task_runner.queue_task(self._mib_download_task)
+ self._mib_download_deferred.addCallbacks(success, failure)
+
+ def onu_is_reachable(self, _topic, msg):
+ """
+ Reach-ability change event
+ :param _topic: (str) subscription topic, not used
+ :param msg: (dict) 'connected' key holds True if reachable
+ """
+ from voltha.extensions.omci.omci_cc import CONNECTED_KEY
+ if self._connectivity_subscription is not None:
+ try:
+ connected = msg[CONNECTED_KEY]
+
+ # TODO: For now, only care about the first connect occurrence.
+ # Later we could use this for a heartbeat, but may want some hysteresis
+ # Cancel any 'reachable' subscriptions
+ if connected:
+ evt_bus = self._onu_omci_device.omci_cc.event_bus
+ evt_bus.unsubscribe(self._connectivity_subscription)
+ self._connectivity_subscription = None
+ self._connected = True
+
+ device = self._handler.adapter_agent.get_device(self._handler.device_id)
+ device.oper_status = OperStatus.ACTIVE
+ device.connect_status = ConnectStatus.REACHABLE
+ self._handler.adapter_agent.update_device(device)
+
+ except Exception as e:
+ self.log.exception('onu-reachable', e=e)
diff --git a/voltha/adapters/adtran_onu/onu_gem_port.py b/voltha/adapters/adtran_onu/onu_gem_port.py
index 0cff8ac..03ea477 100644
--- a/voltha/adapters/adtran_onu/onu_gem_port.py
+++ b/voltha/adapters/adtran_onu/onu_gem_port.py
@@ -98,7 +98,10 @@
port_id=self.gem_id,
tcont_id=tcont_entity_id,
direction=direction,
- upstream_tm=0x8000 # TM ID, 32768 unique ID set in TD set TODO: Parameterize
+ upstream_tm=0x8000 # TM ID, 32768 unique ID set in TD set TODO: Parameterize
+ # This is Priority Queue ME with this entity ID
+ # and the ME's related port value is 0x01.00.0007
+ # which is slot=0x01, tcont# = 0x00, priority= 0x0007
).create()
results = yield omci.send(frame)
diff --git a/voltha/adapters/adtran_onu/onu_pm_metrics.py b/voltha/adapters/adtran_onu/onu_pm_metrics.py
index d4aa5f6..20a45b3 100644
--- a/voltha/adapters/adtran_onu/onu_pm_metrics.py
+++ b/voltha/adapters/adtran_onu/onu_pm_metrics.py
@@ -128,7 +128,7 @@
def collect_port_metrics(self):
metrics = dict()
- metrics['omci'] = self.collect_metrics(self.handler.omci,
+ metrics['omci'] = self.collect_metrics(self.handler.openomci.omci_cc,
self.omci_pm_names,
self.omci_metrics_config)
diff --git a/voltha/adapters/adtran_onu/pon_port.py b/voltha/adapters/adtran_onu/pon_port.py
index 63c410e..1cfa003 100644
--- a/voltha/adapters/adtran_onu/pon_port.py
+++ b/voltha/adapters/adtran_onu/pon_port.py
@@ -13,54 +13,32 @@
# limitations under the License.
import structlog
-from twisted.internet.defer import inlineCallbacks, returnValue, TimeoutError
-from twisted.internet import reactor
-
-from voltha.protos.common_pb2 import AdminState
-from voltha.protos.device_pb2 import Port, Image
-
-from voltha.protos.common_pb2 import OperStatus, ConnectStatus
-
-from omci.omci_entities import onu_custom_me_entities
-from voltha.extensions.omci.omci_me import *
-
-_STARTUP_RETRY_WAIT = 5
-# abbreviations
-OP = EntityOperations
+from twisted.internet.defer import inlineCallbacks, returnValue
+from voltha.protos.common_pb2 import AdminState, OperStatus
+from voltha.protos.device_pb2 import Port
class PonPort(object):
- """Wraps northbound-port / vlan bridge support for ONU"""
+ """Wraps northbound-port/ANI support for ONU"""
MIN_GEM_ENTITY_ID = 0x4900
MAX_GEM_ENTITY_ID = 0x4AFF
def __init__(self, handler, port_no):
+ self.log = structlog.get_logger(device_id=handler.device_id, port_no=port_no)
+
self._enabled = False
self._valid = True
self._handler = handler
self._deferred = None
- self._resync_deferred = None # For TCont/GEM use
self._port = None
self._port_number = port_no
- self._connected = False
- self._dev_info_loaded = False
- self._bridge_initialized = False
self._next_entity_id = PonPort.MIN_GEM_ENTITY_ID
- self.log = structlog.get_logger(device_id=handler.device_id, port_no=port_no)
self._admin_state = AdminState.ENABLED
self._oper_status = OperStatus.ACTIVE
self._gem_ports = {} # gem-id -> GemPort
self._tconts = {} # alloc-id -> TCont
- self._in_sync_subscription = None
- self._connectivity_subscription = None
-
- self._onu_omci_device = handler.omci_agent.add_device(handler.device_id,
- handler.adapter_agent,
- onu_custom_me_entities(),
- support_classes=handler.adapter.adtran_omci)
- # TODO: Add stats, alarm reference, ...
def __str__(self):
return "PonPort" # TODO: Encode current state
@@ -77,55 +55,28 @@
self._oper_status = OperStatus.ACTIVE
self._update_adapter_agent()
- # Subscriber to events of interest in OpenOMCI
- self._subscribe_to_events()
- self._onu_omci_device.start()
-
- # Begin ONU Activation sequence if already in sync
- if self._onu_omci_device.mib_db_in_sync:
- self._deferred = reactor.callLater(0, self._mib_in_sync)
- else:
- device = self._handler.adapter_agent.get_device(self._handler.device_id)
- device.reason = 'Waiting for MIB upload completion'
- self._handler.adapter_agent.update_device(device)
-
def _stop(self):
self._cancel_deferred()
- # Unsubscribe to OpenOMCI Events
- self._unsubscribe_to_events()
- self._onu_omci_device.stop()
self._admin_state = AdminState.DISABLED
self._oper_status = OperStatus.UNKNOWN
self._update_adapter_agent()
- self._dev_info_loaded = False
# TODO: stop h/w sync
- pass
def _cancel_deferred(self):
d1, self._deferred = self._deferred, None
- d2, self._resync_deferred = self._resync_deferred, None
- for d in [d1, d2]:
+ for d in [d1]:
try:
if d is not None and not d.called:
d.cancel()
except:
pass
- def _cancel_resync_deferred(self):
- d, self._resync_deferred = self._resync_deferred, None
- try:
- if d is not None and not d.called:
- d.cancel()
- except:
- pass
-
def delete(self):
self.enabled = False
self._valid = False
- self._onu_omci_device = None
self._handler = None
@property
@@ -143,10 +94,6 @@
self._stop()
@property
- def connected(self):
- return self._connected
-
- @property
def port_number(self):
return self._port_number
@@ -160,6 +107,14 @@
return entity_id
+ @property
+ def tconts(self):
+ return self._tconts
+
+ @property
+ def gem_ports(self):
+ return self._gem_ports
+
def get_port(self):
"""
Get the VOLTHA PORT object for this port
@@ -191,504 +146,9 @@
# adapter_agent add_port also does an update of port status
try:
self._handler.adapter_agent.add_port(self._handler.device_id, self.get_port())
-
except Exception as e:
self.log.exception('update-port', e=e)
- @property
- def onu_omci_device(self):
- return self._onu_omci_device
-
- def _mib_in_sync(self):
- if self._handler.is_mock:
- return # Done, Mock has no bridge support
-
- if not self._dev_info_loaded:
- # Here if in sync. But verify first
-
- omci = self._onu_omci_device
- in_sync = omci.mib_db_in_sync
- self.log.info('mib-in-sync', in_sync=in_sync, already_loaded=self._dev_info_loaded)
-
- device = self._handler.adapter_agent.get_device(self._handler.device_id)
- device.oper_status = OperStatus.ACTIVE
- device.connect_status = ConnectStatus.REACHABLE
- device.reason = 'MIB Synchronization complete'
- self._handler.adapter_agent.update_device(device)
-
- # In Sync, we can register logical ports now. Ideally this could occur on
- # the first time we received a successful (no timeout) OMCI Rx response.
- try:
- for uni in self._handler.uni_ports:
- uni.add_logical_port(None, None)
-
- #BKP
- device = self._handler.adapter_agent.get_device(self._handler.device_id)
-
- vendor = omci.query_mib_single_attribute(OntG.class_id, 0, 'vendor_id') or 'ADTN'
- assert vendor == 'ADTN', \
- "Invalid Device/Wrong device adapter assigned: '{}'".format(vendor)
-
- # TODO: Get serial number and validate!
- num_ports = omci.query_mib_single_attribute(CircuitPack.class_id,
- 257, 'number_of_ports') or 1
- assert num_ports == 1, 'Invalid number of ports: {}'.format(num_ports)
-
- host_info = omci.query_mib(IpHostConfigData.class_id)
- mgmt_mac_address = next((host_info[inst].get('attributes').get('mac_address')
- for inst in host_info
- if isinstance(inst, int)), 'unknown')
- device.mac_address = str(mgmt_mac_address)
-
- ont2_attributes = omci.query_mib(Ont2G.class_id, 0, ['equipment_id',
- 'omcc_version',
- 'vendor_product_code'])
- equipment_id = ont2_attributes.get('equipment_id') or " unknown unknown "
- eqptId_bootVersion = str(equipment_id).rstrip('\0')
- eqptId = eqptId_bootVersion[0:10] # ie) BVMDZ10DRA
- bootVersion = eqptId_bootVersion[12:20] # ie) CML.D55~
-
- omcc_version = int(ont2_attributes.get('omcc_version', 0))
- vendorProductCode = str(ont2_attributes.get('vendor_product_code', 'unknown')).rstrip('\0')
-
- images = [Image(name='boot-code',
- version=bootVersion.rstrip('\0'),
- is_active=False,
- is_committed=True,
- is_valid=True,
- install_datetime='Not Available',
- hash='Not Available')]
-
- model = omci.query_mib_single_attribute(OntG.class_id, 0, 'version') or 'unknown'
- device.model = str(model).rstrip('\0')
-
- sw_info = {k: v.get('attributes') for k, v in omci.query_mib(SoftwareImage.class_id).items()
- if isinstance(k, int)}
-
- for info in sw_info.itervalues():
- is_active = info.get('is_active', False)
- if is_active:
- device.firmware_version = str(info.get('version', 'Not Available').rstrip('\0'))
-
- images.append(Image(name='running-revision' if is_active else 'candidate-revision',
- version=str(info.get('version', 'Not Available').rstrip('\0')),
- is_active=is_active,
- is_committed=info.get('is_committed', False),
- is_valid=info.get('is_valid', False),
- install_datetime='Not Available',
- hash=str(info.get('image_hash', 'Not Available').rstrip('\0'))))
- device.images.image.extend(images)
-
- # Save our device information
- self._handler.adapter_agent.update_device(device)
- self._dev_info_loaded = True
- self._bridge_initialized = False
-
- except Exception as e:
- self.log.exception('device-info-load', e=e)
- self._deferred = reactor.callLater(_STARTUP_RETRY_WAIT, self._mib_in_sync())
-
- self._deferred = reactor.callLater(0, self.resync_omci_settings)
-
- @inlineCallbacks
- def resync_omci_settings(self):
- self._cancel_resync_deferred()
-
- device = self._handler.adapter_agent.get_device(self._handler.device_id)
-
- if not self._bridge_initialized and device.vlan > 0 :
- self.log.info('resync-omci-settings', initialized=self._bridge_initialized)
- #device = self._handler.adapter_agent.get_device(self._handler.device_id)
-
- if not self.enabled or device is None:
- returnValue('not-enabled')
-
- device.reason = 'Performing OMCI Setup'
- self._handler.adapter_agent.update_device(device)
-
- omci = self._handler.omci
-
- #############################################
- # All our variables here
- # TODO: Move elsewhere in future version of this software
- # TODO: Make as many entity IDs dynamic/discovered as possible
- frame = None
- gal_enet_profile_entity_id = 0x100
- ieee_mapper_service_profile_entity_id = 0x100
- mac_bridge_service_profile_entity_id = 0x100
- mac_bridge_port_ani_entity_id = 0x100
- ethernet_uni_entity_id = 0x101
- vlan_tcis_1 = 0x900
- vlan_config_entity_id = vlan_tcis_1
- cvid = device.vlan
-
- try:
- ################################################################################
- # TCONTS
- # get tconts in database
- omci_dev = self._onu_omci_device
- tcont_idents = omci_dev.query_mib(Tcont.class_id)
- self.log.debug('tcont-idents', tcont_idents=tcont_idents)
-
- for tcont in self._tconts.itervalues():
- free_entity_id = next((k for k, v in tcont_idents.items()
- if isinstance(k, int) and v.get('attributes', {}).get('alloc_id', 0) == 0xFFFF), None)
- if free_entity_id is None:
- self.log.error('no-available-tconts')
- break
- results = yield tcont.add_to_hardware(omci, free_entity_id)
-
- ################################################################################
- # GEMS
- for gem_port in self._gem_ports.itervalues():
- tcont = gem_port.tcont
- if tcont is None:
- self.log.error('unknown-tcont-reference', gem_id=gem_port.gem_id)
- continue
-
- results = yield gem_port.add_to_hardware(omci,
- tcont.entity_id,
- ieee_mapper_service_profile_entity_id,
- gal_enet_profile_entity_id)
-
- ########################################################################################
- # Create GalEthernetProfile - Once per ONU/PON interface
- #
- # EntityID will be referenced by:
- # - GEM Interworking TPs when a new GEM Port is created
- # References:
- # - Nothing
-
- frame = GalEthernetProfileFrame(gal_enet_profile_entity_id,
- max_gem_payload_size=1518).create() # Max GEM Payload size
- results = yield omci.send(frame)
-
- status = results.fields['omci_message'].fields['success_code']
- error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
- self.log.debug('create-gal-ethernet-profile', status=status, error_mask=error_mask)
-
- ################################################################################
- # MAC Bridge Service Profile - Once per UNI
- #
- # EntityID will be referenced by:
- # - MAC Bridge Port Configuration Data
- # References:
- # - Nothing
-
- attributes = {
- 'spanning_tree_ind': False,
- # TODO: CB: see if we need or can use any of the following...
- # 'learning_ind': True,
- # 'priority': 0x8000,
- # 'max_age': 20 * 256,
- # 'hello_time': 2 * 256,
- # 'forward_delay': 15 * 256,
- # 'unknown_mac_address_discard': True
- }
- frame = MacBridgeServiceProfileFrame(mac_bridge_service_profile_entity_id,
- attributes).create()
- results = yield omci.send(frame)
-
- status = results.fields['omci_message'].fields['success_code']
- error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
- self.log.debug('create-mac-bridge-service-profile', status=status, error_mask=error_mask)
-
- ################################################################################
- # IEEE 802.1 Mapper Service config - Once per PON
- #
- # EntityID will be referenced by:
- # - MAC Bridge Port Configuration Data for the PON port
- # References:
- # - Nothing at this point. When a GEM port is created, this entity will
- # be updated to reference the GEM Interworking TP
-
- frame = Ieee8021pMapperServiceProfileFrame(ieee_mapper_service_profile_entity_id).create()
- results = yield omci.send(frame)
-
- status = results.fields['omci_message'].fields['success_code']
- error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
- self.log.debug('create-8021p-mapper-service-profile', status=status, error_mask=error_mask)
-
- ################################################################################
- # Create MAC Bridge Port Configuration Data for the PON port via IEEE 802.1
- # mapper service. Upon receipt by the ONU, the ONU will create an instance
- # of the following before returning the response.
- #
- # - MAC bridge port designation data
- # - MAC bridge port filter table data
- # - MAC bridge port bridge table data
- #
- # EntityID will be referenced by:
- # - Implicitly by the VLAN tagging filter data
- # -
- # -
- # -
- # References:
- # - MAC Bridge Service Profile (the bridge)
- # - IEEE 802.1p mapper service profile for PON port
-
- frame = MacBridgePortConfigurationDataFrame(
- mac_bridge_port_ani_entity_id, # Entity ID
- bridge_id_pointer=mac_bridge_service_profile_entity_id, # Bridge Entity ID BP: oldvalue 0x201
- # TODO: The PORT number for this port and the UNI port are the same. Is this correct?
- port_num=0, # Port ID BP: oldvalue 2
- tp_type=3, # TP Type (IEEE 802.1p mapper service) BP: oldvalue 1, 802.1 mapper GPON intf
- tp_pointer=ieee_mapper_service_profile_entity_id # TP ID, 8021p mapper ID BP: oldvalue 0x102
- ).create()
- results = yield omci.send(frame)
-
- status = results.fields['omci_message'].fields['success_code']
- error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
- self.log.debug('create-mac-bridge-port-configuration-data-part-1', status=status, error_mask=error_mask)
-
- ################################################################################
- # MAC Bridge Port config
- # This configuration is for Ethernet UNI
- #
- # EntityID will be referenced by:
- # -
- # -
- # -
- # -
- # References:
- # - MAC Bridge Service Profile (the bridge)
- # - PPTP Ethernet UNI
-
- frame = MacBridgePortConfigurationDataFrame(
- 0x000, # Entity ID BP: oldvalue 0x201
- bridge_id_pointer=mac_bridge_service_profile_entity_id, # Bridge Entity ID BP: oldvalue 0x201
- port_num=0, # Port ID BP: oldvalue 3
- tp_type=1, # PPTP Ethernet UNI BP: oldvalue 3
- tp_pointer=ethernet_uni_entity_id # TP ID, 8021p mapper Id BP: oldvalue 0x8001
- ).create()
- results = yield omci.send(frame)
-
- status = results.fields['omci_message'].fields['success_code']
- error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
- self.log.debug('create-mac-bridge-port-configuration-data-part-2', status=status, error_mask=error_mask)
-
- ################################################################################
- # VLAN Tagging Filter config
- #
- # EntityID will be referenced by:
- # - Nothing
- # References:
- # - Implicitly linked to an instance of the MAC bridge port configuration data
- # for the PON port
- # TODO: Probably need to get VLAN ID from device.vlan
- # Set anything, this request will not be used when using Extended Vlan
-
- frame = VlanTaggingFilterDataFrame(
- mac_bridge_port_ani_entity_id, # Entity ID BP: Oldvalue 0x2102
- vlan_tcis=[vlan_tcis_1], # VLAN IDs BP: cvid
- forward_operation=0x10
- ).create()
- results = yield omci.send(frame)
-
- status = results.fields['omci_message'].fields['success_code']
- error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
- self.log.debug('create-vlan-tagging-filter-data', status=status, error_mask=error_mask)
-
- ################################################################################
- # Update the IEEE 802.1p Mapper Service Profile config
- #
- # EntityID was created prior to this call
- # References:
- # -
- # -
- # TODO: All p-bits currently go to the one and only GEMPORT ID for now
-
- gem_entity_ids = [gem_port.entity_id for _, gem_port in self._gem_ports.items()] \
- if len(self._gem_ports) else [OmciNullPointer]
-
- frame = Ieee8021pMapperServiceProfileFrame(
- ieee_mapper_service_profile_entity_id, # 802.1p mapper Service Mapper Profile ID
- interwork_tp_pointers=gem_entity_ids # Interworking TP IDs BP: oldvalue self.gemid
- ).set()
- results = yield omci.send(frame)
-
- status = results.fields['omci_message'].fields['success_code']
- failed_attributes_mask = results.fields['omci_message'].fields['failed_attributes_mask']
- unsupported_attributes_mask = results.fields['omci_message'].fields['unsupported_attributes_mask']
- self.log.debug('set-8021p-mapper-service-profile', status=status,
- failed_attributes_mask=failed_attributes_mask,
- unsupported_attributes_mask=unsupported_attributes_mask)
-
- ################################################################################
- # Unlock UNI
- #
- # EntityID will be referenced by:
- # - MAC bridge port configuration data for the UNI side
- # References:
- # - Nothing
-
- attributes = dict(
- administrative_state=0 # 0 - Unlock
- )
- frame = PptpEthernetUniFrame(
- ethernet_uni_entity_id, # Entity ID
- attributes=attributes # See above
- ).set()
- results = yield omci.send(frame)
-
- status = results.fields['omci_message'].fields['success_code']
- failed_attributes_mask = results.fields['omci_message'].fields['failed_attributes_mask']
- unsupported_attributes_mask = results.fields['omci_message'].fields['unsupported_attributes_mask']
- self.log.debug('set-pptp-ethernet-uni', status=status,
- failed_attributes_mask=failed_attributes_mask,
- unsupported_attributes_mask=unsupported_attributes_mask)
-
- ################################################################################
- # Create Extended VLAN Tagging Operation config
- #
- # EntityID relates to the VLAN TCIS
- # References:
- # - VLAN TCIS from previously created VLAN Tagging filter data
- # - PPTP Ethernet UNI
- #
- # TODO: add entry here for additional UNI interfaces
-
- attributes = dict(
- association_type=2, # Assoc Type, PPTP Ethernet UNI
- associated_me_pointer=ethernet_uni_entity_id # Assoc ME, PPTP Entity Id
- )
-
- frame = ExtendedVlanTaggingOperationConfigurationDataFrame(
- vlan_config_entity_id,
- attributes=attributes
- ).create()
- results = yield omci.send(frame)
-
- status = results.fields['omci_message'].fields['success_code']
- error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
- self.log.debug('create-extended-vlan-tagging-operation-configuration-data', status=status, error_mask=error_mask)
-
- ################################################################################
- # Update Extended VLAN Tagging Operation Config Data
- #
- # Specifies the TPIDs in use and that operations in the downstream direction are
- # inverse to the operations in the upstream direction
- # TODO: Downstream mode may need to be modified once we work more on the flow rules
-
- attributes = dict(
- input_tpid=0x8100, # input TPID
- output_tpid=0x8100, # output TPID
- downstream_mode=0, # inverse of upstream
- )
- frame = ExtendedVlanTaggingOperationConfigurationDataFrame(
- vlan_config_entity_id,
- attributes=attributes
- ).set()
- results = yield omci.send(frame)
-
- status = results.fields['omci_message'].fields['success_code']
- failed_attributes_mask = results.fields['omci_message'].fields['failed_attributes_mask']
- unsupported_attributes_mask = results.fields['omci_message'].fields['unsupported_attributes_mask']
- self.log.debug('set-extended-vlan-tagging-operation-configuration-data', status=status,
- failed_attributes_mask=failed_attributes_mask,
- unsupported_attributes_mask=unsupported_attributes_mask)
-
- ################################################################################
- # Update Extended VLAN Tagging Operation Config Data
- #
- # parameters: Entity Id ( 0x900), Filter Inner Vlan Id(0x1000-4096,do not filter on Inner vid,
- # Treatment Inner Vlan Id : 2
-
- attributes = dict(
- received_frame_vlan_tagging_operation_table=
- VlanTaggingOperation(
- filter_outer_priority=15, # This entry is not a double-tag rule
- filter_outer_vid=4096, # Do not filter on the outer VID value
- filter_outer_tpid_de=0, # Do not filter on the outer TPID field
-
- filter_inner_priority=15, # This is a no-tag rule, ignore all other VLAN tag filter fields
- filter_inner_vid=0x1000, # Do not filter on the inner VID
- filter_inner_tpid_de=0, # Do not filter on inner TPID field
- filter_ether_type=0, # Do not filter on EtherType
-
- treatment_tags_to_remove=0, # Remove 0 tags
- treatment_outer_priority=15, # Do not add an outer tag
- treatment_outer_vid=0, # n/a
- treatment_outer_tpid_de=0, # n/a
-
- treatment_inner_priority=0, # Add an inner tag and insert this value as the priority
- treatment_inner_vid=cvid, # use this value as the VID in the inner VLAN tag
- treatment_inner_tpid_de=4 # set TPID = 0x8100
- )
- )
- frame = ExtendedVlanTaggingOperationConfigurationDataFrame(
- vlan_config_entity_id, # Entity ID BP: Oldvalue 0x202
- attributes=attributes # See above
- ).set()
- results = yield omci.send(frame)
-
- status = results.fields['omci_message'].fields['success_code']
- failed_attributes_mask = results.fields['omci_message'].fields['failed_attributes_mask']
- unsupported_attributes_mask = results.fields['omci_message'].fields['unsupported_attributes_mask']
- self.log.debug('set-extended-vlan-tagging-operation-configuration-data-untagged', status=status,
- failed_attributes_mask=failed_attributes_mask,
- unsupported_attributes_mask=unsupported_attributes_mask)
-
- # BP: This is for AT&T RG's
- #
- # TODO: CB: NOTE: TRY THIS ONCE OTHER SEQUENCES WORK
- #
- # Set AR - ExtendedVlanTaggingOperationConfigData
- # 514 - RxVlanTaggingOperationTable - add VLAN <cvid> to priority tagged pkts - c-vid
- # results = yield omci.send_set_extended_vlan_tagging_operation_vlan_configuration_data_single_tag(
- # 0x900, # Entity ID
- # 8, # Filter Inner Priority, do not filter on Inner Priority
- # 0, # Filter Inner VID, this will be 0 in CORD
- # 0, # Filter Inner TPID DE
- # 1, # Treatment tags, number of tags to remove
- # 8, # Treatment inner priority, copy Inner Priority
- # 2) # Treatment inner VID, this will be 2 in CORD
-
- # Set AR - ExtendedVlanTaggingOperationConfigData
- # 514 - RxVlanTaggingOperationTable - add VLAN <cvid> to priority tagged pkts - c-vid
- # results = yield omci.send_set_extended_vlan_tagging_operation_vlan_configuration_data_single_tag(
- # 0x200, # Entity ID
- # 8, # Filter Inner Priority
- # 0, # Filter Inner VID
- # 0, # Filter Inner TPID DE
- # 1, # Treatment tags to remove
- # 8, # Treatment inner priority
- # cvid) # Treatment inner VID
- #
- # Set AR - ExtendedVlanTaggingOperationConfigData
- # 514 - RxVlanTaggingOperationTable - add VLAN <cvid> to untagged pkts - c-vid
- #results = yield omci.send_set_extended_vlan_tagging_operation_vlan_configuration_data_untagged(
- # 0x100, # Entity ID BP: Oldvalue 0x202
- # 0x1000, # Filter Inner VID BP: Oldvalue 0x1000
- # cvid) # Treatment inner VID BP: cvid
-
- # success = results.fields['omci_message'].fields['success_code'] == 0
- # error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
-
- ###############################################################################
- # If here, we are done
- self._bridge_initialized = True
- device.reason = ''
- self._handler.adapter_agent.update_device(device)
-
- except TimeoutError as e:
- self.log.warn('rx-timeout', frame=frame)
- self._deferred = reactor.callLater(_STARTUP_RETRY_WAIT,
- self.resync_omci_settings)
- returnValue('retry-pending')
-
- except Exception as e:
- self.log.exception('omci-setup', e=e)
- device.reason = 'OMCI setup sequence failure: ' + e.message
- self._handler.adapter_agent.update_device(device)
-
- # Try again later
- self._deferred = reactor.callLater(_STARTUP_RETRY_WAIT,
- self.resync_omci_settings)
- else:
- self._deferred = reactor.callLater(_STARTUP_RETRY_WAIT,
- self.resync_omci_settings)
-
def add_tcont(self, tcont, reflow=False):
"""
Creates/ a T-CONT with the given alloc-id
@@ -706,11 +166,8 @@
self.log.info('add', tcont=tcont, reflow=reflow)
self._tconts[tcont.alloc_id] = tcont
- # only start setting sequence if there are at least one gem add
- if len(self._gem_ports) > 0 and self._bridge_initialized:
- self._cancel_resync_deferred()
- self._bridge_initialized = False
- self._resync_deferred = reactor.callLater(0, self.resync_omci_settings)
+ # TODO: Refactor once xPON goes away
+ self._handler.openomci.gem_or_tcont_added()
def update_tcont_td(self, alloc_id, new_td):
tcont = self._tconts.get(alloc_id)
@@ -739,8 +196,7 @@
try:
del self._tconts[alloc_id]
-
- results = yield tcont.remove_from_hardware(self._handler.omci)
+ results = yield tcont.remove_from_hardware(self._handler.openomci.omci_cc)
returnValue(results)
except Exception as e:
@@ -772,11 +228,8 @@
self.log.info('add', gem_port=gem_port, reflow=reflow)
self._gem_ports[gem_port.gem_id] = gem_port
- # assuming tcont was already added to start start settings sequence
- if self._bridge_initialized:
- self._cancel_resync_deferred()
- self._bridge_initialized = False
- self._resync_deferred = reactor.callLater(0, self.resync_omci_settings)
+ # TODO: Refactor once xPON goes away
+ self._handler.openomci.gem_or_tcont_added()
@inlineCallbacks
def remove_gem_id(self, gem_id):
@@ -793,84 +246,9 @@
try:
del self._gem_ports[gem_id]
-
- results = yield gem_port.remove_from_hardware(self._handler.omci)
+ results = yield gem_port.remove_from_hardware(self._handler.openomci.omci_cc)
returnValue(results)
except Exception as ex:
self.log.exception('gem-port-delete', e=ex)
raise
-
- def _subscribe_to_events(self):
- from voltha.extensions.omci.onu_device_entry import OnuDeviceEvents, \
- OnuDeviceEntry, IN_SYNC_KEY
- from voltha.extensions.omci.omci_cc import OMCI_CC, OmciCCRxEvents, \
- CONNECTED_KEY
-
- def in_sync_handler(_topic, msg):
- if self._in_sync_subscription is not None:
- try:
- in_sync = msg[IN_SYNC_KEY]
-
- if in_sync:
- # Only call this once as well (after PON enable)
- bus = self._onu_omci_device.event_bus
- bus.unsubscribe(self._in_sync_subscription)
- self._in_sync_subscription = None
-
- # Start up device_info load
- reactor.callLater(0, self._mib_in_sync)
-
- except Exception as e:
- self.log.exception('in-sync', e=e)
-
- def onu_is_reachable(_topic, msg):
- """
- Reach-ability change event
- :param _topic: (str) subscription topic, not used
- :param msg: (dict) 'connected' key holds True if reachable
- """
- if self._connectivity_subscription is not None:
- try:
- connected = msg[CONNECTED_KEY]
-
- # TODO: For now, only care about the first.
- # Later we could use this for a heartbeat, but may want some hysteresis
- # Cancel any 'reachable' subscriptions
- if connected:
- evt_bus = self._onu_omci_device.omci_cc.event_bus
- evt_bus.unsubscribe(self._connectivity_subscription)
- self._connectivity_subscription = None
- self._connected = True
-
- device = self._handler.adapter_agent.get_device(self._handler.device_id)
- device.oper_status = OperStatus.ACTIVE
- device.connect_status = ConnectStatus.REACHABLE
- self._handler.adapter_agent.update_device(device)
-
- except Exception as e:
- self.log.exception('onu-reachable', e=e)
-
- # OMCI MIB Database sync status
- bus = self._onu_omci_device.event_bus
- topic = OnuDeviceEntry.event_bus_topic(self._handler.device_id,
- OnuDeviceEvents.MibDatabaseSyncEvent)
- self._in_sync_subscription = bus.subscribe(topic, in_sync_handler)
-
- # OMCI-CC Connectivity Events (for reachbility/heartbeat)
- bus = self._onu_omci_device.omci_cc.event_bus
- topic = OMCI_CC.event_bus_topic(self._handler.device_id,
- OmciCCRxEvents.Connectivity)
- self._connectivity_subscription = bus.subscribe(topic, onu_is_reachable)
-
- def _unsubscribe_to_events(self):
- if self._in_sync_subscription is not None:
- bus = self._onu_omci_device.event_bus
- bus.unsubscribe(self._in_sync_subscription)
- self._in_sync_subscription = None
-
- if self._connectivity_subscription is not None:
- bus = self._onu_omci_device.omci_cc.event_bus
- bus.unsubscribe(self._connectivity_subscription)
- self._connectivity_subscription = None
-