VOL-3616: Support for API to retrieve information about UNI of an ONU
Change-Id: Iaf6f8147278cc0cbb084b66d7400ce84a0b18ae4
diff --git a/python/adapters/brcm_openomci_onu/brcm_openomci_onu_adapter.py b/python/adapters/brcm_openomci_onu/brcm_openomci_onu_adapter.py
index c261501..d68e72b 100644
--- a/python/adapters/brcm_openomci_onu/brcm_openomci_onu_adapter.py
+++ b/python/adapters/brcm_openomci_onu/brcm_openomci_onu_adapter.py
@@ -23,7 +23,7 @@
from __future__ import absolute_import
import structlog
from twisted.internet import reactor
-from twisted.internet.defer import inlineCallbacks
+from twisted.internet.defer import inlineCallbacks, returnValue
from zope.interface import implementer
@@ -41,7 +41,7 @@
from brcm_openomci_onu_handler import BrcmOpenomciOnuHandler
from omci.brcm_capabilities_task import BrcmCapabilitiesTask
from copy import deepcopy
-
+from voltha_protos.extensions_pb2 import SingleGetValueResponse, GetValueResponse
@implementer(IAdapterInterface)
class BrcmOpenomciOnuAdapter(object):
@@ -305,3 +305,23 @@
handler = self.devices_handlers[device.id]
result = handler.start_omci_test_action(device, uuid)
return result
+
+ @inlineCallbacks
+ def single_get_value_request(self, request):
+ """
+ :param request: A request to get a specific attribute of a device, of type SingleGetValueRequest
+ :return:
+ """
+ self.log.info('single-get-value-request', request=request)
+ handler = self.devices_handlers[request.targetId]
+ get_value_req = request.request
+ if get_value_req.HasField("uniInfo"):
+ result = yield handler.get_uni_status(get_value_req)
+ self.log.debug('single-get-value-result', res=result)
+ returnValue(result)
+ else:
+ self.log.debug('invalid-request')
+ errresult = SingleGetValueResponse()
+ errresult.response.status = GetValueResponse.ERROR
+ errresult.response.errReason = GetValueResponse.UNSUPPORTED
+ returnValue(errresult)
diff --git a/python/adapters/brcm_openomci_onu/brcm_openomci_onu_handler.py b/python/adapters/brcm_openomci_onu/brcm_openomci_onu_handler.py
index abb73a8..07d967e 100755
--- a/python/adapters/brcm_openomci_onu/brcm_openomci_onu_handler.py
+++ b/python/adapters/brcm_openomci_onu/brcm_openomci_onu_handler.py
@@ -34,6 +34,7 @@
from omci.brcm_tp_delete_task import BrcmTpDeleteTask
from omci.brcm_tp_setup_task import BrcmTpSetupTask
from omci.brcm_uni_lock_task import BrcmUniLockTask
+from omci.brcm_uni_status import BrcmUniStatusTask
from omci.brcm_vlan_filter_task import BrcmVlanFilterTask
from onu_gem_port import OnuGemPort
from onu_tcont import OnuTCont
@@ -55,7 +56,7 @@
from pyvoltha.common.tech_profile.tech_profile import TechProfile
from pyvoltha.common.utils.registry import registry
from twisted.internet import reactor
-from twisted.internet.defer import inlineCallbacks, returnValue
+from twisted.internet.defer import inlineCallbacks, returnValue, DeferredQueue
from uni_port import RESERVED_TRANSPARENT_VLAN
from uni_port import UniPort, UniType
from voltha_protos.common_pb2 import OperStatus, ConnectStatus, AdminState
@@ -66,6 +67,7 @@
from voltha_protos.openflow_13_pb2 import OFPXMC_OPENFLOW_BASIC
from voltha_protos.openolt_pb2 import OnuIndication
from voltha_protos.voltha_pb2 import TestResponse
+from voltha_protos.extensions_pb2 import SingleGetValueResponse, GetValueResponse
OP = EntityOperations
RC = ReasonCodes
@@ -97,6 +99,8 @@
self._tp = dict() # tp_id -> technology profile definition in KV Store.
self._reconciling = False
self.olt_serial_number = ""
+ self.uni_status_response_queue = DeferredQueue()
+ self._results = SingleGetValueResponse()
# Persisted onu configuration needed in case of reconciliation.
self._onu_persisted_state = {
@@ -2069,7 +2073,6 @@
def onu_deleted_event(self):
self.log.debug('onu-deleted-event')
try:
- device = yield self.core_proxy.get_device(self.device_id)
olt_serial_number = self.olt_serial_number
raised_ts = arrow.utcnow().timestamp
intf_id = self._onu_persisted_state.get('intf_id')
@@ -2137,3 +2140,29 @@
**kwargs_omci_test_action)
test_request.perform_test_omci()
return (TestResponse(result=TestResponse.SUCCESS))
+
+ @inlineCallbacks
+ def get_uni_status(self, request):
+ """
+ :param request:
+ :return:
+ """
+ for uni in self.uni_ports:
+ self.log.debug('uni-id-and-uni-index',uni_id = uni.uni_id, uni_idx=request.uniInfo.uniIndex)
+ if uni.uni_id == request.uniInfo.uniIndex:
+ task = BrcmUniStatusTask(self.omci_agent, self.device_id, request, uni.entity_id, self.uni_status_response_queue)
+ self._deferred = self._onu_omci_device.task_runner.queue_task(task)
+ try:
+ self._results = yield self.uni_status_response_queue.get()
+ self.log.debug('uni-status-response',res=self._results)
+ except Exception as e:
+ self.log.exception("failed-dequeueing-received-message", e=e)
+ self._results.response.status = GetValueResponse.ERROR
+ self._results.response.errReason = GetValueResponse.UNSUPPORTED
+ finally:
+ task.stop()
+ returnValue(self._results)
+ self.log.error('uni-not-found', uni_idx=request.uniInfo.uniIndex)
+ self._results.response.status = GetValueResponse.ERROR
+ self._results.response.errReason = GetValueResponse.UNSUPPORTED
+ returnValue(self._results)
diff --git a/python/adapters/brcm_openomci_onu/omci/brcm_uni_status.py b/python/adapters/brcm_openomci_onu/omci/brcm_uni_status.py
new file mode 100644
index 0000000..dd61b7e
--- /dev/null
+++ b/python/adapters/brcm_openomci_onu/omci/brcm_uni_status.py
@@ -0,0 +1,188 @@
+#
+# 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 __future__ import absolute_import
+import structlog
+from pyvoltha.adapters.extensions.omci.tasks.task import Task
+from twisted.internet import reactor
+from twisted.internet.defer import inlineCallbacks, failure, returnValue, DeferredQueue
+from pyvoltha.adapters.extensions.omci.omci_defs import ReasonCodes, EntityOperations
+from pyvoltha.adapters.extensions.omci.omci_me import OntGFrame
+from pyvoltha.adapters.extensions.omci.omci_me import PptpEthernetUniFrame, VeipUniFrame
+from voltha_protos.extensions_pb2 import SingleGetValueResponse, GetValueResponse, GetOnuUniInfoResponse
+
+RC = ReasonCodes
+OP = EntityOperations
+
+
+class BrcmUniStatusTask(Task):
+ """
+ Get the status of the UNI Port
+ """
+ task_priority = Task.DEFAULT_PRIORITY + 20
+ name = "Broadcom UNI Status Task"
+
+ def __init__(self, omci_agent, device_id, get_val_req, entity_id, msg_queue, priority=task_priority):
+ """
+ Class initialization
+
+ :param omci_agent: (OmciAdapterAgent) OMCI Adapter agent
+ :param device_id: (str) ONU Device ID
+ :param get_val_req: (voltha_pb2.SingleGetValueResponse)
+ :param priority: (int) OpenOMCI Task priority (0..255) 255 is the highest
+ """
+ super(BrcmUniStatusTask, self).__init__(BrcmUniStatusTask.name,
+ omci_agent,
+ device_id,
+ priority=priority,
+ exclusive=True)
+
+ self.log = structlog.get_logger(device_id=device_id,
+ name=BrcmUniStatusTask.name,
+ task_id=self._task_id)
+
+ self._device = omci_agent.get_device(device_id)
+ self._req = get_val_req
+ self._results = SingleGetValueResponse()
+ self._local_deferred = None
+ self._config = self._device.configuration
+ self._entity_id = entity_id
+ self.uni_status_response_queue = msg_queue
+
+ self.log.info("get-uni-staus-deviceid",deviceid=device_id)
+
+ def cancel_deferred(self):
+ super(BrcmUniStatusTask, 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 UNI/PPTP Get Status Task
+ """
+ super(BrcmUniStatusTask, self).start()
+ self._local_deferred = reactor.callLater(0, self.perform_get_uni_status)
+ def stop(self):
+ self.cancel_deferred()
+ super(BrcmUniStatusTask, self).stop()
+
+
+ @inlineCallbacks
+ def perform_get_uni_status(self):
+ """
+ Perform the Get UNI Status
+ """
+ self.log.info('get-uni-status-uni-index-is ',uni_index=self._req.uniInfo.uniIndex)
+
+
+ try:
+ pptp_list = sorted(self._config.pptp_entities) if self._config.pptp_entities else []
+ pptp_items = ['administrative_state', 'operational_state', 'config_ind', 'max_frame_size', 'sensed_type', 'bridged_ip_ind']
+ for entity_id in pptp_list:
+ self.log.info('entity-id',entity_id)
+ msg = PptpEthernetUniFrame(self._entity_id, attributes=pptp_items)
+ yield self._send_omci_msg(msg)
+ except Exception as e:
+ self._results.response.status = GetValueResponse.ERROR
+ self._results.response.errReason = GetValueResponse.REASON_UNDEFINED
+ self.log.exception('get-uni-status', e=e)
+ finally:
+ self.log.info('uni-status-response',self._results)
+ yield self.uni_status_response_queue.put(self._results)
+
+ @inlineCallbacks
+ def _send_omci_msg(self, me_message):
+ frame = me_message.get()
+ results = yield self._device.omci_cc.send(frame)
+ if self._check_status_and_state(results, 'get-uni-status'):
+ omci_msg = results.fields['omci_message'].fields
+ self._results.response.status = GetValueResponse.OK
+ self._collect_uni_admin_state(results)
+ self._collect_uni_operational_state(results)
+ self._collect_uni_config_ind(results)
+ else:
+ self._results.response.status = GetValueResponse.ERROR
+ self._results.response.errReason = GetValueResponse.UNSUPPORTED
+
+ def _collect_uni_admin_state(self, results):
+ omci_msg = results.fields['omci_message'].fields
+ admin_state = omci_msg.get("data").get("administrative_state")
+ if admin_state == 0 :
+ self._results.response.uniInfo.admState = GetOnuUniInfoResponse.UNLOCKED
+ elif admin_state == 1 :
+ self._results.response.uniInfo.admState = GetOnuUniInfoResponse.LOCKED
+ else:
+ self._results.response.uniInfo.admState = GetOnuUniInfoResponse.ADMSTATE_UNDEFINED
+
+ def _collect_uni_operational_state(self, results):
+ self.log.info('collect-uni-oper-state')
+ omci_msg = results.fields['omci_message'].fields
+ oper_state=omci_msg.get("data").get("operational_state")
+ if oper_state == 0 :
+ self._results.response.uniInfo.operState = GetOnuUniInfoResponse.ENABLED
+ elif oper_state == 1 :
+ self._results.response.uniInfo.operState = GetOnuUniInfoResponse.DISABLED
+ else:
+ self._results.response.uniInfo.operState = GetOnuUniInfoResponse.OPERSTATE_UNDEFINED
+
+ def _collect_uni_config_ind(self, results):
+ config_ind_map = {0:GetOnuUniInfoResponse.UNKOWN,
+ 1:GetOnuUniInfoResponse.TEN_BASE_T_FDX,
+ 2:GetOnuUniInfoResponse.HUNDRED_BASE_T_FDX,
+ 3:GetOnuUniInfoResponse.GIGABIT_ETHERNET_FDX,
+ 4:GetOnuUniInfoResponse.TEN_G_ETHERNET_FDX,
+ 17:GetOnuUniInfoResponse.TEN_BASE_T_HDX,
+ 18:GetOnuUniInfoResponse.HUNDRED_BASE_T_HDX,
+ 19:GetOnuUniInfoResponse.GIGABIT_ETHERNET_HDX,
+ }
+ self.log.info('collect-config-ind')
+ omci_msg = results.fields['omci_message'].fields
+ config_ind =omci_msg.get("data").get("config_ind", GetOnuUniInfoResponse.UNKOWN)
+ self._results.response.uniInfo.configInd = config_ind_map.get(config_ind, GetOnuUniInfoResponse.UNKOWN)
+
+ def _check_status_and_state(self, results, operation=''):
+ """
+ Check the results of an OMCI response. An exception is thrown
+ if the task was cancelled or an error was detected.
+
+ :param results: (OmciFrame) OMCI Response frame
+ :param operation: (str) what operation was being performed
+ :return: True if successful, False if the entity existed (already created)
+ """
+ omci_msg = results.fields['omci_message'].fields
+ status = omci_msg['success_code']
+ error_mask = omci_msg.get('parameter_error_attributes_mask', 'n/a')
+ failed_mask = omci_msg.get('failed_attributes_mask', 'n/a')
+ unsupported_mask = omci_msg.get('unsupported_attributes_mask', 'n/a')
+
+ self.log.debug("omci-response", operation=operation,
+ omci_msg=omci_msg, status=status,
+ error_mask=error_mask, failed_mask=failed_mask,
+ unsupported_mask=unsupported_mask)
+
+ self.strobe_watchdog()
+ if status == RC.Success:
+ return True
+ else:
+ self.log.info("omci-reponse-failed", status, "error-mask-is",
+ error_mask, "failed-mask-is ", failed_mask, "unsupported-mask-is ", unsupported_mask)
+ return False
+