VOL-700: OpenOMCI MIB Database CLI/NBI (REST) implementation
Change-Id: Ib53530ad99854ecae2424cf01944baeeb731ce02
diff --git a/cli/main.py b/cli/main.py
index 544b774..7674182 100755
--- a/cli/main.py
+++ b/cli/main.py
@@ -30,6 +30,7 @@
from cli.device import DeviceCli
from cli.xpon import XponCli
+from cli.omci import OmciCli
from cli.alarm_filters import AlarmFiltersCli
from cli.logical_device import LogicalDeviceCli
from cli.table import print_pb_list_as_table
@@ -277,6 +278,15 @@
sub = XponCli(self.get_channel, device_id)
sub.cmdloop()
+ def do_omci(self, line):
+ """omci <device_ID> - Enter OMCI level command mode"""
+
+ device_id = line.strip() or self.default_device_id
+ if not device_id:
+ raise Exception('<device-id> parameter needed')
+ sub = OmciCli(device_id, self.get_stub)
+ sub.cmdloop()
+
def do_pdb(self, line):
"""Launch PDB debug prompt in CLI (for CLI development)"""
from pdb import set_trace
@@ -348,7 +358,7 @@
break
self.poutput('waiting for device to be enabled...')
sleep(.5)
- except Exception as e:
+ except Exception as e:
self.poutput('Error enabling {}. Error:{}'.format(device_id, e))
complete_activate_olt = complete_device
diff --git a/cli/omci.py b/cli/omci.py
new file mode 100644
index 0000000..146f296
--- /dev/null
+++ b/cli/omci.py
@@ -0,0 +1,356 @@
+#!/usr/bin/env python
+#
+# 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.
+#
+
+"""
+OpenOMCI level CLI commands
+"""
+from optparse import make_option
+from cmd2 import Cmd, options
+from datetime import datetime
+from google.protobuf.empty_pb2 import Empty
+from cli.table import print_pb_list_as_table
+from voltha.protos import third_party
+from voltha.protos import voltha_pb2
+from voltha.protos.omci_mib_db_pb2 import MibDeviceData, MibClassData, \
+ MibInstanceData
+from os import linesep
+
+_ = third_party
+
+
+class OmciCli(Cmd):
+ CREATED_KEY = 'created'
+ MODIFIED_KEY = 'modified'
+ MDS_KEY = 'mib_data_sync'
+ LAST_SYNC_KEY = 'last_mib_sync'
+ VERSION_KEY = 'version'
+ DEVICE_ID_KEY = 'device_id'
+ CLASS_ID_KEY = 'class_id'
+ INSTANCE_ID_KEY = 'instance_id'
+ ATTRIBUTES_KEY = 'attributes'
+ TIME_FORMAT = '%Y%m%d-%H%M%S.%f'
+ ME_KEY = 'managed_entities'
+ MSG_TYPE_KEY = 'message_types'
+
+ MSG_TYPE_TO_NAME = {
+ 4: 'Create',
+ 5: 'Create Complete',
+ 6: 'Delete',
+ 8: 'Set',
+ 9: 'Get',
+ 10: 'Get Complete',
+ 11: 'Get All Alarms',
+ 12: 'Get All Alarms Next',
+ 13: 'Mib Upload',
+ 14: 'Mib Upload Next',
+ 15: 'Mib Reset',
+ 16: 'Alarm Notification',
+ 17: 'Attribute Value Change',
+ 18: 'Test',
+ 19: 'Start Software Download',
+ 20: 'Download Section',
+ 21: 'End Software Download',
+ 22: 'Activate Software',
+ 23: 'Commit Software',
+ 24: 'Synchronize Time',
+ 25: 'Reboot',
+ 26: 'Get Next',
+ 27: 'Test Result',
+ 28: 'Get Current Data',
+ 29: 'Set Table'
+ }
+
+ def __init__(self, device_id, get_stub):
+ Cmd.__init__(self)
+ self.get_stub = get_stub
+ self.device_id = device_id
+ self.prompt = '(' + self.colorize(
+ self.colorize('omci {}'.format(device_id), 'green'),
+ 'bold') + ') '
+
+ def cmdloop(self, intro=None):
+ self._cmdloop()
+
+ do_exit = Cmd.do_quit
+
+ def do_quit(self, line):
+ return self._STOP_AND_EXIT
+
+ def get_device_mib(self, device_id, depth=-1):
+ stub = self.get_stub()
+
+ try:
+ res = stub.GetMibDeviceData(voltha_pb2.ID(id=device_id),
+ metadata=(('get-depth', str(depth)), ))
+ except Exception as e:
+ pass
+
+ return res
+
+ def help_show_mib(self):
+ self.poutput('show_mib [-d <device-id>] [-c <class-id> [-i <instance-id>]]' +
+ linesep + '-d: <device-id> ONU Device ID' +
+ linesep + '-c: <class-id> Managed Entity Class ID' +
+ linesep + '-i: <instance-id> ME Instance ID')
+
+ @options([
+ make_option('-d', '--device-id', action="store", dest='device_id', type='string',
+ help='ONU Device ID', default=None),
+ make_option('-c', '--class-id', action="store", dest='class_id',
+ type='int', help='Managed Entity Class ID', default=None),
+ make_option('-i', '--instance-id', action="store", dest='instance_id',
+ type='int', help='ME Instance ID', default=None)
+ ])
+ def do_show_mib(self, _line, opts):
+ """
+ Show OMCI MIB Database Information
+ """
+ device_id = opts.device_id or self.device_id
+
+ if opts.class_id is not None and not 1 <= opts.class_id <= 0xFFFF:
+ self.poutput(self.colorize('Error: ', 'red') +
+ self.colorize('Class ID must be 1..65535', 'blue'))
+ return
+
+ if opts.instance_id is not None and opts.class_id is None:
+ self.poutput(self.colorize('Error: ', 'red') +
+ self.colorize('Class ID required if specifying an Instance ID',
+ 'blue'))
+ return
+
+ if opts.instance_id is not None and not 0 <= opts.instance_id <= 0xFFFF:
+ self.poutput(self.colorize('Error: ', 'red') +
+ self.colorize('Instance ID must be 0..65535', 'blue'))
+ return
+
+ try:
+ mib_db = self.get_device_mib(device_id, depth=-1)
+
+ except Exception: # UnboundLocalError if Device ID not found in DB
+ self.poutput(self.colorize('Failed to get MIB database for ONU {}'
+ .format(device_id), 'red'))
+ return
+
+ mib = self._device_to_dict(mib_db)
+
+ self.poutput('OpenOMCI MIB Database for ONU {}'.format(device_id))
+
+ if opts.class_id is None and opts.instance_id is None:
+ self.poutput('Version : {}'.format(mib[OmciCli.VERSION_KEY]))
+ self.poutput('Created : {}'.format(mib[OmciCli.CREATED_KEY]))
+ self.poutput('Last In-Sync Time : {}'.format(mib[OmciCli.LAST_SYNC_KEY]))
+ self.poutput('MIB Data Sync Value: {}'.format(mib[OmciCli.MDS_KEY]))
+
+ class_ids = [k for k in mib.iterkeys()
+ if isinstance(k, int) and
+ (opts.class_id is None or opts.class_id == k)]
+ class_ids.sort()
+
+ if len(class_ids) == 0 and opts.class_id is not None:
+ self.poutput(self.colorize('Class ID {} not found in MIB Database'
+ .format(opts.class_id), 'red'))
+ return
+
+ for cls_id in class_ids:
+ class_data = mib[cls_id]
+ self.poutput(' ----------------------------------------------')
+ self.poutput(' Class ID: {0} - ({0:#x})'.format(cls_id))
+
+ inst_ids = [k for k in class_data.iterkeys()
+ if isinstance(k, int) and
+ (opts.instance_id is None or opts.instance_id == k)]
+ inst_ids.sort()
+
+ if len(inst_ids) == 0 and opts.instance_id is not None:
+ self.poutput(self.colorize('Instance ID {} of Class ID {} not ' +
+ 'found in MIB Database'.
+ format(opts.instance_id, opts.class_id),
+ 'red'))
+ return
+
+ for inst_id in inst_ids:
+ inst_data = class_data[inst_id]
+ self.poutput(' Instance ID: {0} - ({0:#x})'.format(inst_id))
+ self.poutput(' Created : {}'.format(inst_data[OmciCli.CREATED_KEY]))
+ self.poutput(' Modified : {}'.format(inst_data[OmciCli.MODIFIED_KEY]))
+
+ attributes = inst_data[OmciCli.ATTRIBUTES_KEY]
+ attr_names = attributes.keys()
+ attr_names.sort()
+ max_len = max([len(attr) for attr in attr_names])
+
+ for attr in attr_names:
+ name = self._cleanup_attribute_name(attr).ljust(max_len)
+ value = attributes[attr]
+ try:
+ ivalue = int(value)
+ self.poutput(' {0}: {1} - ({1:#x})'.format(name, ivalue))
+
+ except ValueError:
+ self.poutput(' {}: {}'.format(name, value))
+
+ if inst_id is not inst_ids[-1]:
+ self.poutput(linesep)
+
+ def _cleanup_attribute_name(self, attr):
+ """Change underscore to space and capitalize first character"""
+ return ' '.join([v[0].upper() + v[1:] for v in attr.split('_')])
+
+ def _instance_to_dict(self, instance):
+ if not isinstance(instance, MibInstanceData):
+ raise TypeError('{} is not of type MibInstanceData'.format(type(instance)))
+
+ data = {
+ OmciCli.INSTANCE_ID_KEY: instance.instance_id,
+ OmciCli.CREATED_KEY: self._string_to_time(instance.created),
+ OmciCli.MODIFIED_KEY: self._string_to_time(instance.modified),
+ OmciCli.ATTRIBUTES_KEY: dict()
+ }
+ for attribute in instance.attributes:
+ data[OmciCli.ATTRIBUTES_KEY][attribute.name] = str(attribute.value)
+
+ return data
+
+ def _class_to_dict(self, val):
+ if not isinstance(val, MibClassData):
+ raise TypeError('{} is not of type MibClassData'.format(type(val)))
+
+ data = {
+ OmciCli.CLASS_ID_KEY: val.class_id,
+ }
+ for instance in val.instances:
+ data[instance.instance_id] = self._instance_to_dict(instance)
+ return data
+
+ def _device_to_dict(self, val):
+ if not isinstance(val, MibDeviceData):
+ raise TypeError('{} is not of type MibDeviceData'.format(type(val)))
+
+ data = {
+ OmciCli.DEVICE_ID_KEY: val.device_id,
+ OmciCli.CREATED_KEY: self._string_to_time(val.created),
+ OmciCli.LAST_SYNC_KEY: self._string_to_time(val.last_sync_time),
+ OmciCli.MDS_KEY: val.mib_data_sync,
+ OmciCli.VERSION_KEY: val.version,
+ OmciCli.ME_KEY: dict(),
+ OmciCli.MSG_TYPE_KEY: set()
+ }
+ for class_data in val.classes:
+ data[class_data.class_id] = self._class_to_dict(class_data)
+
+ for managed_entity in val.managed_entities:
+ data[OmciCli.ME_KEY][managed_entity.class_id] = managed_entity.name
+
+ for msg_type in val.message_types:
+ data[OmciCli.MSG_TYPE_KEY].add(msg_type.message_type)
+
+ return data
+
+ def _string_to_time(self, time):
+ return datetime.strptime(time, OmciCli.TIME_FORMAT) if len(time) else None
+
+ def help_show_me(self):
+ self.poutput('show_me [-d <device-id>]' +
+ linesep + '-d: <device-id> ONU Device ID')
+
+ @options([
+ make_option('-d', '--device-id', action="store", dest='device_id', type='string',
+ help='ONU Device ID', default=None),
+ ])
+ def do_show_me(self, _line, opts):
+ """ Show supported OMCI Managed Entities"""
+
+ device_id = opts.device_id or self.device_id
+
+ try:
+ mib_db = self.get_device_mib(device_id, depth=1)
+ mib = self._device_to_dict(mib_db)
+
+ except Exception: # UnboundLocalError if Device ID not found in DB
+ self.poutput(self.colorize('Failed to get supported ME information for ONU {}'
+ .format(device_id), 'red'))
+ return
+
+ class_ids = [class_id for class_id in mib[OmciCli.ME_KEY].keys()]
+ class_ids.sort()
+
+ self.poutput('Supported Managed Entities for ONU {}'.format(device_id))
+ for class_id in class_ids:
+ self.poutput(' {0} - ({0:#x}): {1}'.format(class_id,
+ mib[OmciCli.ME_KEY][class_id]))
+
+ def help_show_msg_types(self):
+ self.poutput('show_msg_types [-d <device-id>]' +
+ linesep + '-d: <device-id> ONU Device ID')
+
+ @options([
+ make_option('-d', '--device-id', action="store", dest='device_id', type='string',
+ help='ONU Device ID', default=None),
+ ])
+ def do_show_msg_types(self, _line, opts):
+ """ Show supported OMCI Message Types"""
+ device_id = opts.device_id or self.device_id
+
+ try:
+ mib_db = self.get_device_mib(device_id, depth=1)
+ mib = self._device_to_dict(mib_db)
+
+ except Exception: # UnboundLocalError if Device ID not found in DB
+ self.poutput(self.colorize('Failed to get supported Message Types for ONU {}'
+ .format(device_id), 'red'))
+ return
+
+ msg_types = [msg_type for msg_type in mib[OmciCli.MSG_TYPE_KEY]]
+ msg_types.sort()
+
+ self.poutput('Supported Message Types for ONU {}'.format(device_id))
+ for msg_type in msg_types:
+ self.poutput(' {0} - ({0:#x}): {1}'.
+ format(msg_type,
+ OmciCli.MSG_TYPE_TO_NAME.get(msg_type, 'Unknown')))
+
+ def get_devices(self):
+ stub = self.get_stub()
+ res = stub.ListDevices(Empty())
+ return res.items
+
+ def do_devices(self, line):
+ """List devices registered in Voltha reduced for OMCI menu"""
+ devices = self.get_devices()
+ omit_fields = {
+ 'adapter',
+ 'model',
+ 'hardware_version',
+ 'images',
+ 'firmware_version',
+ 'serial_number',
+ 'vlan',
+ 'root',
+ 'extra_args',
+ 'proxy_address',
+ }
+ print_pb_list_as_table('Devices:', devices, omit_fields, self.poutput)
+
+ def help_devices(self):
+ self.poutput('TODO: Provide some help')
+
+ def poutput(self, msg):
+ """Convenient shortcut for self.stdout.write(); adds newline if necessary."""
+ if msg:
+ self.stdout.write(msg)
+ if msg[-1] != '\n':
+ self.stdout.write('\n')
diff --git a/voltha/core/global_handler.py b/voltha/core/global_handler.py
index bfaaf04..ee7901a 100644
--- a/voltha/core/global_handler.py
+++ b/voltha/core/global_handler.py
@@ -1741,3 +1741,21 @@
else:
log.debug('grpc-success-response', response=response)
returnValue(response)
+
+ @twisted_async
+ @inlineCallbacks
+ def GetMibDeviceData(self, request, context):
+ log.info('grpc-request', request=request)
+ response = yield self.dispatcher.dispatch('GetMibDeviceData',
+ request,
+ context,
+ id=request.id)
+ log.debug('grpc-response', response=response)
+ if isinstance(response, DispatchError):
+ log.warn('grpc-error-response', error=response.error_code)
+ context.set_details('Device \'{}\' error'.format(request.id))
+ context.set_code(response.error_code)
+ returnValue(MibDeviceData())
+ else:
+ log.debug('grpc-success-response', response=response)
+ returnValue(response)
diff --git a/voltha/core/local_handler.py b/voltha/core/local_handler.py
index 55a0cfc..7f5d2ad 100644
--- a/voltha/core/local_handler.py
+++ b/voltha/core/local_handler.py
@@ -36,6 +36,7 @@
from voltha.protos.common_pb2 import OperationResp
from voltha.protos.bbf_fiber_base_pb2 import AllMulticastDistributionSetData, AllMulticastGemportsConfigData
from voltha.registry import registry
+from voltha.protos.omci_mib_db_pb2 import MibDeviceData
from requests.api import request
from common.utils.asleep import asleep
@@ -1332,3 +1333,25 @@
current=self.subscriber)
return self.subscriber
+
+ @twisted_async
+ def GetMibDeviceData(self, request, context):
+ log.info('grpc-request', request=request)
+
+ depth = int(dict(context.invocation_metadata()).get('get-depth', -1))
+
+ if '/' in request.id:
+ context.set_details(
+ 'Malformed device id \'{}\''.format(request.id))
+ context.set_code(StatusCode.INVALID_ARGUMENT)
+ return MibDeviceData()
+
+ try:
+ return self.root.get('/omci_mibs/' + request.id, depth=depth)
+
+ except KeyError:
+ context.set_details(
+ 'OMCI MIB for Device \'{}\' not found'.format(request.id))
+ context.set_code(StatusCode.NOT_FOUND)
+ return MibDeviceData()
+
diff --git a/voltha/extensions/omci/database/mib_db_api.py b/voltha/extensions/omci/database/mib_db_api.py
index 38f5061..eb93323 100644
--- a/voltha/extensions/omci/database/mib_db_api.py
+++ b/voltha/extensions/omci/database/mib_db_api.py
@@ -30,6 +30,8 @@
CLASS_ID_KEY = 'class_id'
INSTANCE_ID_KEY = 'instance_id'
ATTRIBUTES_KEY = 'attributes'
+ME_KEY = 'managed_entities'
+MSG_TYPE_KEY = 'message_types'
class DatabaseStateError(Exception):
@@ -223,3 +225,21 @@
:return: (int) The Value or None if not found
"""
raise NotImplementedError('Implement this in your derive class')
+
+ def update_supported_managed_entities(self, device_id, managed_entities):
+ """
+ Update the supported OMCI Managed Entities for this device
+
+ :param device_id: (str) ONU Device ID
+ :param managed_entities: (set) Managed Entity class IDs
+ """
+ raise NotImplementedError('Implement this in your derive class')
+
+ def update_supported_message_types(self, device_id, msg_types):
+ """
+ Update the supported OMCI Managed Entities for this device
+
+ :param device_id: (str) ONU Device ID
+ :param msg_types: (set) Message Type values (ints)
+ """
+ raise NotImplementedError('Implement this in your derive class')
diff --git a/voltha/extensions/omci/database/mib_db_dict.py b/voltha/extensions/omci/database/mib_db_dict.py
index 663ce36..ae2f3a5 100644
--- a/voltha/extensions/omci/database/mib_db_dict.py
+++ b/voltha/extensions/omci/database/mib_db_dict.py
@@ -82,7 +82,9 @@
CREATED_KEY: now,
LAST_SYNC_KEY: None,
MDS_KEY: 0,
- VERSION_KEY: MibDbVolatileDict.CURRENT_VERSION
+ VERSION_KEY: MibDbVolatileDict.CURRENT_VERSION,
+ ME_KEY: dict(),
+ MSG_TYPE_KEY: set()
}
def remove(self, device_id):
@@ -125,7 +127,9 @@
CREATED_KEY: device_db[CREATED_KEY],
LAST_SYNC_KEY: device_db[LAST_SYNC_KEY],
MDS_KEY: 0,
- VERSION_KEY: MibDbVolatileDict.CURRENT_VERSION
+ VERSION_KEY: MibDbVolatileDict.CURRENT_VERSION,
+ ME_KEY: device_db[ME_KEY],
+ MSG_TYPE_KEY: device_db[MSG_TYPE_KEY]
}
def save_mib_data_sync(self, device_id, value):
@@ -430,3 +434,47 @@
except Exception as e:
pass
+
+ def update_supported_managed_entities(self, device_id, managed_entities):
+ """
+ Update the supported OMCI Managed Entities for this device
+
+ :param device_id: (str) ONU Device ID
+ :param managed_entities: (set) Managed Entity class IDs
+ """
+ now = datetime.utcnow()
+ try:
+ device_db = self._data[device_id]
+
+ entities = {class_id: self._managed_entity_to_name(device_id, class_id)
+ for class_id in managed_entities}
+
+ device_db[ME_KEY] = entities
+ self._modified = now
+
+ except Exception as e:
+ self.log.error('set-me-failure', e=e)
+ raise
+
+ def _managed_entity_to_name(self, device_id, class_id):
+ me_map = self._omci_agent.get_device(device_id).me_map
+ entity = me_map.get(class_id)
+
+ return entity.__name__ if entity is not None else 'UnknownManagedEntity'
+
+ def update_supported_message_types(self, device_id, msg_types):
+ """
+ Update the supported OMCI Managed Entities for this device
+
+ :param device_id: (str) ONU Device ID
+ :param msg_types: (set) Message Type values (ints)
+ """
+ now = datetime.utcnow()
+ try:
+ msg_type_set = {msg_type.value for msg_type in msg_types}
+ self._data[device_id][MSG_TYPE_KEY] = msg_type_set
+ self._modified = now
+
+ except Exception as e:
+ self.log.error('set-me-failure', e=e)
+ raise
diff --git a/voltha/extensions/omci/database/mib_db_ext.py b/voltha/extensions/omci/database/mib_db_ext.py
index c1b84dd..0c8b179 100644
--- a/voltha/extensions/omci/database/mib_db_ext.py
+++ b/voltha/extensions/omci/database/mib_db_ext.py
@@ -15,7 +15,7 @@
#
from mib_db_api import *
from voltha.protos.omci_mib_db_pb2 import MibInstanceData, MibClassData, \
- MibDeviceData, MibAttributeData
+ MibDeviceData, MibAttributeData, MessageType, ManagedEntity
from voltha.extensions.omci.omci_entities import *
from scapy.fields import StrField, FieldListField
@@ -838,9 +838,77 @@
CREATED_KEY: self._string_to_time(val.created),
LAST_SYNC_KEY: self._string_to_time(val.last_sync_time),
MDS_KEY: val.mib_data_sync,
- VERSION_KEY: val.version
+ VERSION_KEY: val.version,
+ ME_KEY: dict(),
+ MSG_TYPE_KEY: set()
}
for class_data in val.classes:
data[class_data.class_id] = self._class_to_dict(val.device_id,
class_data)
+ for managed_entity in val.managed_entities:
+ data[ME_KEY][managed_entity.class_id] = managed_entity.name
+
+ for msg_type in val.message_types:
+ data[MSG_TYPE_KEY].add(msg_type.message_type)
+
return data
+
+ def _managed_entity_to_name(self, device_id, class_id):
+ me_map = self._omci_agent.get_device(device_id).me_map
+ entity = me_map.get(class_id)
+
+ return entity.__name__ if entity is not None else 'UnknownManagedEntity'
+
+ def update_supported_managed_entities(self, device_id, managed_entities):
+ """
+ Update the supported OMCI Managed Entities for this device
+ :param device_id: (str) ONU Device ID
+ :param managed_entities: (set) Managed Entity class IDs
+ """
+ try:
+ me_list = [ManagedEntity(class_id=class_id,
+ name=self._managed_entity_to_name(device_id,
+ class_id))
+ for class_id in managed_entities]
+
+ device_proxy = self._device_proxy(device_id)
+ data = device_proxy.get(depth=0)
+
+ now = datetime.utcnow()
+ data.managed_entities.extend(me_list)
+
+ # Update
+ self._root_proxy.update(MibDbExternal.DEVICE_PATH.format(device_id),
+ data)
+ self._modified = now
+ self.log.debug('save-me-list-complete', device_id=device_id)
+
+ except Exception as e:
+ self.log.exception('add-me-failure', e=e, me_list=managed_entities)
+ raise
+
+ def update_supported_message_types(self, device_id, msg_types):
+ """
+ Update the supported OMCI Managed Entities for this device
+ :param device_id: (str) ONU Device ID
+ :param msg_types: (set) Message Type values (ints)
+ """
+ try:
+ msg_type_list = [MessageType(message_type=msg_type.value)
+ for msg_type in msg_types]
+
+ device_proxy = self._device_proxy(device_id)
+ data = device_proxy.get(depth=0)
+
+ now = datetime.utcnow()
+ data.message_types.extend(msg_type_list)
+
+ # Update
+ self._root_proxy.update(MibDbExternal.DEVICE_PATH.format(device_id),
+ data)
+ self._modified = now
+ self.log.debug('save-msg-types-complete', device_id=device_id)
+
+ except Exception as e:
+ self.log.exception('add-msg-types-failure', e=e, msg_types=msg_types)
+ raise
diff --git a/voltha/extensions/omci/onu_device_entry.py b/voltha/extensions/omci/onu_device_entry.py
index 9e3915d..6a5497d 100644
--- a/voltha/extensions/omci/onu_device_entry.py
+++ b/voltha/extensions/omci/onu_device_entry.py
@@ -31,6 +31,8 @@
ACTIVE_KEY = 'active'
IN_SYNC_KEY = 'in-sync'
LAST_IN_SYNC_KEY = 'last-in-sync-time'
+SUPPORTED_MESSAGE_ENTITY_KEY = 'managed-entities'
+SUPPORTED_MESSAGE_TYPES_KEY = 'message-type'
class OnuDeviceEvents(IntEnum):
@@ -296,7 +298,11 @@
"""
topic = OnuDeviceEntry.event_bus_topic(self.device_id,
OnuDeviceEvents.OmciCapabilitiesEvent)
- self.event_bus.publish(topic=topic, msg=None)
+ msg = {
+ SUPPORTED_MESSAGE_ENTITY_KEY: self.omci_capabilities.supported_managed_entities,
+ SUPPORTED_MESSAGE_TYPES_KEY: self.omci_capabilities.supported_message_types
+ }
+ self.event_bus.publish(topic=topic, msg=msg)
def delete(self):
"""
diff --git a/voltha/extensions/omci/state_machines/mib_sync.py b/voltha/extensions/omci/state_machines/mib_sync.py
index 3e1bad1..854daf2 100644
--- a/voltha/extensions/omci/state_machines/mib_sync.py
+++ b/voltha/extensions/omci/state_machines/mib_sync.py
@@ -22,10 +22,13 @@
AttributeAccess
from voltha.extensions.omci.omci_cc import OmciCCRxEvents, OMCI_CC, TX_REQUEST_KEY, \
RX_RESPONSE_KEY
+from voltha.extensions.omci.onu_device_entry import OnuDeviceEvents, OnuDeviceEntry, \
+ SUPPORTED_MESSAGE_ENTITY_KEY, SUPPORTED_MESSAGE_TYPES_KEY
from voltha.extensions.omci.omci_entities import OntData
from common.event_bus import EventBusClient
RxEvent = OmciCCRxEvents
+DevEvent = OnuDeviceEvents
OP = EntityOperations
RC = ReasonCodes
AA = AttributeAccess
@@ -121,24 +124,31 @@
self._attr_diffs = None
self._event_bus = EventBusClient()
- self._subscriptions = { # RxEvent.enum -> Subscription Object
+ self._omci_cc_subscriptions = { # RxEvent.enum -> Subscription Object
RxEvent.MIB_Reset: None,
RxEvent.AVC_Notification: None,
RxEvent.MIB_Upload: None,
RxEvent.MIB_Upload_Next: None,
RxEvent.Create: None,
RxEvent.Delete: None,
- RxEvent.Set: None
+ RxEvent.Set: None,
}
- self._sub_mapping = {
+ self._omci_cc_sub_mapping = {
RxEvent.MIB_Reset: self.on_mib_reset_response,
RxEvent.AVC_Notification: self.on_avc_notification,
RxEvent.MIB_Upload: self.on_mib_upload_response,
RxEvent.MIB_Upload_Next: self.on_mib_upload_next_response,
RxEvent.Create: self.on_create_response,
RxEvent.Delete: self.on_delete_response,
- RxEvent.Set: self.on_set_response
+ RxEvent.Set: self.on_set_response,
}
+ self._onu_dev_subscriptions = { # DevEvent.enum -> Subscription Object
+ DevEvent.OmciCapabilitiesEvent: None
+ }
+ self._onu_dev_sub_mapping = {
+ DevEvent.OmciCapabilitiesEvent: self.on_capabilities_event
+ }
+
# Statistics and attributes
# TODO: add any others if it will support problem diagnosis
@@ -147,7 +157,8 @@
transitions=transitions,
initial=initial_state,
queued=True,
- name='{}'.format(self.__class__.__name__))
+ name='{}-{}'.format(self.__class__.__name__,
+ device_id))
def _cancel_deferred(self):
d1, self._deferred = self._deferred, None
@@ -223,11 +234,16 @@
task.stop()
# Drop Response and Autonomous notification subscriptions
- for event, sub in self._subscriptions.iteritems():
+ for event, sub in self._omci_cc_subscriptions.iteritems():
if sub is not None:
- self._subscriptions[event] = None
+ self._omci_cc_subscriptions[event] = None
self._device.omci_cc.event_bus.unsubscribe(sub)
+ for event, sub in self._onu_dev_subscriptions.iteritems():
+ if sub is not None:
+ self._onu_dev_subscriptions[event] = None
+ self._device.event_bus.unsubscribe(sub)
+
# TODO: Stop and remove any currently running or scheduled tasks
# TODO: Anything else?
@@ -262,15 +278,27 @@
# Set up Response and Autonomous notification subscriptions
try:
- for event, sub in self._sub_mapping.iteritems():
- if self._subscriptions[event] is None:
- self._subscriptions[event] = \
+ for event, sub in self._omci_cc_sub_mapping.iteritems():
+ if self._omci_cc_subscriptions[event] is None:
+ self._omci_cc_subscriptions[event] = \
self._device.omci_cc.event_bus.subscribe(
topic=OMCI_CC.event_bus_topic(self._device_id, event),
callback=sub)
except Exception as e:
- self.log.exception('subscription-setup', e=e)
+ self.log.exception('omci-cc-subscription-setup', e=e)
+
+ # Set up ONU device subscriptions
+ try:
+ for event, sub in self._onu_dev_sub_mapping.iteritems():
+ if self._onu_dev_subscriptions[event] is None:
+ self._onu_dev_subscriptions[event] = \
+ self._device.event_bus.subscribe(
+ topic=OnuDeviceEntry.event_bus_topic(self._device_id, event),
+ callback=sub)
+
+ except Exception as e:
+ self.log.exception('dev-subscription-setup', e=e)
# Determine if this ONU has ever synchronized
if self.is_new_onu:
@@ -465,6 +493,10 @@
# MDS value if different. Also remember that setting the MDS on
# the ONU to 'n' is a set command and it will be 'n+1' after the
# set.
+ #
+ # TODO: Also look into attributes covered by AVC and treat appropriately
+ # since may have missed the AVC
+
self._deferred = reactor.callLater(0, self.success)
else:
self._deferred = reactor.callLater(0, self.diffs_found)
@@ -493,7 +525,7 @@
response = msg[RX_RESPONSE_KEY]
# Check if expected in current mib_sync state
- if self.state != 'uploading' or self._subscriptions[RxEvent.MIB_Reset] is None:
+ if self.state != 'uploading' or self._omci_cc_subscriptions[RxEvent.MIB_Reset] is None:
self.log.error('rx-in-invalid-state', state=self.state)
else:
@@ -525,7 +557,7 @@
"""
self.log.debug('on-avc-notification', state=self.state)
- if self._subscriptions[RxEvent.AVC_Notification]:
+ if self._omci_cc_subscriptions[RxEvent.AVC_Notification]:
try:
notification = msg[RX_RESPONSE_KEY]
@@ -568,7 +600,7 @@
"""
self.log.debug('on-mib-upload-next-response', state=self.state)
- if self._subscriptions[RxEvent.MIB_Upload]:
+ if self._omci_cc_subscriptions[RxEvent.MIB_Upload]:
# Check if expected in current mib_sync state
if self.state == 'resynchronizing':
# The resync task handles this
@@ -587,7 +619,7 @@
"""
self.log.debug('on-mib-upload-next-response', state=self.state)
- if self._subscriptions[RxEvent.MIB_Upload_Next]:
+ if self._omci_cc_subscriptions[RxEvent.MIB_Upload_Next]:
try:
if self.state == 'resynchronizing':
# The resync task handles this
@@ -632,7 +664,7 @@
"""
self.log.debug('on-create-response', state=self.state)
- if self._subscriptions[RxEvent.Create]:
+ if self._omci_cc_subscriptions[RxEvent.Create]:
if self.state in ['disabled', 'uploading']:
self.log.error('rx-in-invalid-state', state=self.state)
return
@@ -717,7 +749,7 @@
"""
self.log.debug('on-delete-response', state=self.state)
- if self._subscriptions[RxEvent.Delete]:
+ if self._omci_cc_subscriptions[RxEvent.Delete]:
if self.state in ['disabled', 'uploading']:
self.log.error('rx-in-invalid-state', state=self.state)
return
@@ -758,7 +790,7 @@
"""
self.log.debug('on-set-response', state=self.state)
- if self._subscriptions[RxEvent.Set]:
+ if self._omci_cc_subscriptions[RxEvent.Set]:
if self.state in ['disabled', 'uploading']:
self.log.error('rx-in-invalid-state', state=self.state)
try:
@@ -791,6 +823,16 @@
pass # NOP
except Exception as e:
self.log.exception('set', e=e)
+ def on_capabilities_event(self, _topic, msg):
+ """
+ Process a OMCI capabilties event
+ :param _topic: (str) OnuDeviceEntry Capabilities event
+ :param msg: (dict) Message Entities & Message Types supported
+ """
+ self._database.update_supported_managed_entities(self.device_id,
+ msg[SUPPORTED_MESSAGE_ENTITY_KEY])
+ self._database.update_supported_message_types(self.device_id,
+ msg[SUPPORTED_MESSAGE_TYPES_KEY])
def _status_to_text(self, success_code):
return {
diff --git a/voltha/extensions/omci/state_machines/omci_onu_capabilities.py b/voltha/extensions/omci/state_machines/omci_onu_capabilities.py
index f288929..291999f 100644
--- a/voltha/extensions/omci/state_machines/omci_onu_capabilities.py
+++ b/voltha/extensions/omci/state_machines/omci_onu_capabilities.py
@@ -84,7 +84,8 @@
transitions=transitions,
initial=initial_state,
queued=True,
- name='{}'.format(self.__class__.__name__))
+ name='{}-{}'.format(self.__class__.__name__,
+ device_id))
def _cancel_deferred(self):
d1, self._deferred = self._deferred, None
diff --git a/voltha/protos/omci_mib_db.proto b/voltha/protos/omci_mib_db.proto
index 1c518c8..89d2e65 100644
--- a/voltha/protos/omci_mib_db.proto
+++ b/voltha/protos/omci_mib_db.proto
@@ -43,6 +43,15 @@
[(voltha.child_node) = {key: "instance_id"}];
}
+message ManagedEntity {
+ uint32 class_id = 1 [(voltha.access) = READ_ONLY];
+ string name = 2 [(voltha.access) = READ_ONLY];
+}
+
+message MessageType {
+ uint32 message_type = 1 [(voltha.access) = READ_ONLY];
+}
+
message MibDeviceData {
string device_id = 1 [(voltha.access) = READ_ONLY];
string created = 2;
@@ -52,4 +61,8 @@
repeated MibClassData classes = 6
[(voltha.child_node) = {key: "class_id"}];
+
+ repeated ManagedEntity managed_entities = 7;
+ repeated MessageType message_types = 8;
}
+
diff --git a/voltha/protos/voltha.proto b/voltha/protos/voltha.proto
index 7f5a08f..b106289 100644
--- a/voltha/protos/voltha.proto
+++ b/voltha/protos/voltha.proto
@@ -949,6 +949,13 @@
post: "/api/v1/devices/{id}/self_test"
};
}
+
+ // OpenOMCI MIB information
+ rpc GetMibDeviceData(ID) returns(omci.MibDeviceData) {
+ option (google.api.http) = {
+ get: "/api/v1/openomci/{id}/mib"
+ };
+ }
}
/*
@@ -1677,4 +1684,11 @@
}
rpc Subscribe(OfAgentSubscriber) returns (OfAgentSubscriber) {}
+
+ // OpenOMCI MIB information
+ rpc GetMibDeviceData(ID) returns(omci.MibDeviceData) {
+ option (google.api.http) = {
+ get: "/api/v1/openomci/{id}/mib"
+ };
+ }
}