blob: 71025195a8dde91a56eec38d77638e56e02c938d [file] [log] [blame]
#
# Copyright 2017 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
from pyvoltha.adapters.extensions.omci.omci_frame import OmciFrame
from pyvoltha.adapters.extensions.omci.omci_defs import *
from pyvoltha.adapters.extensions.omci.omci_entities import *
from pyvoltha.adapters.extensions.omci.omci_messages import *
# abbreviations
OP = EntityOperations
RC = ReasonCodes
class MockOnu(object):
"""
Minimal class that acts line an ONU. The Mock OLT handler will call into this
object with OMCI frames that it will respond to appropriately
"""
def __init__(self, serial_number, adapter_agent, handler_id):
self.serial_number = serial_number
self._adapter_agent = adapter_agent # TODO: Remove any unused attributes
self._handler_id = handler_id
self.mib_data_sync = 0 # Assume at reboot!
# NOTE: when creating response frames, use the basic method of constructing
# these frames as the encoding created is unit-tested elsewhere
self._omci_response = {
OP.Get.value: {
CircuitPack.class_id: {
257: OmciFrame(transaction_id=0, # Will get replaced
message_type=OmciGetResponse.message_id,
omci_message=OmciGetResponse(
entity_class=CircuitPack.class_id,
entity_id=0,
success_code=RC.Success.value,
attributes_mask=CircuitPack.mask_for('number_of_ports'),
data=OmciMaskedData('value',
entity_class=CircuitPack.class_id,
attributes_mask=CircuitPack.mask_for('number_of_ports'))
))
},
# Additional OMCI GET request responses here if needed
},
OP.GetNext.value: {},
OP.Create.value: {
# TODO: Create some OMCI CREATE request responses here.
# def send_create_gal_ethernet_profile(self,
# entity_id,
# max_gem_payload_size):
# frame = OmciFrame(
# transaction_id=self.get_tx_id(),
# message_type=OmciCreate.message_id,
# omci_message=OmciCreate(
# entity_class=GalEthernetProfile.class_id,
# entity_id=entity_id,
# data=dict(
# max_gem_payload_size=max_gem_payload_size
# )
# )
# )
# self.send_omci_message(frame)
},
OP.Set.value: {
# TODO: Create some OMCI SET request responses here.
# def send_set_admin_state(self,
# entity_id,
# admin_state):
# data = dict(
# administrative_state=admin_state
# )
# frame = OmciFrame(
# transaction_id=self.get_tx_id(),
# message_type=OmciSet.message_id,
# omci_message=OmciSet(
# entity_class=OntG.class_id,
# entity_id=entity_id,
# attributes_mask=OntG.mask_for(*data.keys()),
# data=data
# )
# )
# self.send_omci_message(frame)
},
OP.Delete.value: {
# TODO: Create some OMCI DELETE responses here.
},
OP.MibReset.value: {
OntData.class_id: {
0: OmciFrame(transaction_id=0, # Will get replaced
message_type=OmciMibResetResponse.message_id,
omci_message=OmciMibResetResponse(
entity_class=OntData.class_id,
entity_id=0,
success_code=RC.Success.value
))
}
},
OP.MibUpload.value: {
OntData.class_id: {
0: OmciFrame(transaction_id=0, # Will get replaced
message_type=OmciMibUploadResponse.message_id,
omci_message=OmciMibUploadResponse(
entity_class=OntData.class_id,
entity_id=0,
number_of_commands=3 # Should match list size for MibUploadNext below
))
}
},
# OP.MibUploadNext.value: {
# OntData.class_id: {
# 0: [
# OmciFrame(transaction_id=0,
# message_type=OmciMibUploadNextResponse.message_id,
# omci_message=OmciMibUploadNextResponse(
# entity_class=OntData.class_id,
# entity_id=0,
# object_entity_id=0, # TODO: Pick one
# object_attributes_mask=0, # TODO: Pick one
# object_data=None # TODO: Pick one
# )),
# OmciFrame(transaction_id=0,
# message_type=OmciMibUploadNextResponse.message_id,
# omci_message=OmciMibUploadNextResponse(
# entity_class=OntData.class_id,
# entity_id=0,
# object_entity_id=0, # TODO: Pick one
# object_attributes_mask=0, # TODO: Pick one
# object_data=None # TODO: Pick one
# )),
# OmciFrame(transaction_id=0,
# message_type=OmciMibUploadNextResponse.message_id,
# omci_message=OmciMibUploadNextResponse(
# entity_class=OntData.class_id,
# entity_id=0,
# object_entity_id=0, # TODO: Pick one
# object_attributes_mask=0, # TODO: Pick one
# object_data=None # TODO: Pick one
# )),
# ]
# }
# },
OP.Reboot.value: {
OntData.class_id: {
0: OmciFrame(transaction_id=0, # Will get replaced
message_type=OmciRebootResponse.message_id,
omci_message=OmciRebootResponse(
entity_class=OntG.class_id,
entity_id=0,
success_code=RC.Success.value
))
}
},
}
# TODO: Support Autonomous ONU messages as well
def tearDown(self):
"""Test case cleanup"""
pass
def _request_to_response_type(self, message_type):
return {
OP.Create.value: OmciCreateResponse,
OP.Delete.value: OmciDeleteResponse,
OP.Set.value: OmciSetResponse,
OP.Get.value: OmciGetResponse,
OP.GetNext.value: OmciGetNextResponse,
OP.MibUpload.value: OmciMibUploadResponse,
OP.MibUploadNext.value: OmciMibUploadNextResponse,
OP.MibReset.value: OmciMibResetResponse,
OP.Reboot.value: OmciRebootResponse,
}.get(message_type & 0x1F, None)
def rx_omci_frame(self, msg):
try:
frame = OmciFrame(msg.decode('hex'))
response = None
response_type = self._request_to_response_type(frame.fields['message_type'])
transaction_id = frame.fields['transaction_id']
omci_message = frame.fields.get('omci_message')
class_id = omci_message.fields.get('entity_class') \
if omci_message is not None else None
instance_id = omci_message.fields.get('entity_id') \
if omci_message is not None else None
# Look up hardcode responses based on class and instance ID. If found
# return the response, otherwise send back an error
if response_type is None:
status = RC.ProcessingError.value
elif class_id is None:
status = RC.UnknownEntity.value
elif instance_id is None:
status = RC.UnknownInstance.value
else:
status = RC.Success.value
try:
response_id = response_type.message_id & 0x1f
response = self._omci_response[response_id][class_id][instance_id]
if response_id == OP.MibUploadNext.value:
# Special case. Need to get requested entry
assert isinstance(response, list)
pass
pass
pass
pass
if isinstance(omci_message, OmciGetNext):
response = response[omci_message.fields['command_sequence_number']]
if isinstance(response, dict):
if response['failures'] > 0:
response['failures'] -= 1
return None
else: response = response['frame']
response.fields['transaction_id'] = transaction_id
if 'success_code' in response.fields['omci_message'].fields:
response.fields['omci_message'].fields['success_code'] = status
if status == RC.Success.value:
if response_type.message_id in [OmciCreateResponse.message_id,
OmciDeleteResponse.message_id,
OmciSetResponse.message_id]:
self.mib_data_sync += 1
if self.mib_data_sync > 255:
self.mib_data_sync = 1
elif response_type.message_id == OmciMibResetResponse.message_id:
self.mib_data_sync = 0
except KeyError as e:
bad_key = e.args[0]
if bad_key == class_id:
status = RC.UnknownEntity.value
elif bad_key == instance_id:
status = RC.UnknownInstance.value
else:
status = RC.ProcessingError.value
if status != RC.Success.value and \
response_type not in [OmciMibUploadResponse,
OmciMibUploadNextResponse]:
response = OmciFrame(transaction_id=transaction_id,
message_type=response_type.message_id,
omci_message=response_type(
entity_class=class_id,
entity_id=instance_id,
success_code=status
))
return response
except Exception as e:
pass
@property
def proxy_address(self, device_id='1'):
if self._proxy_address is None:
self._proxy_address = Device.ProxyAddress(
device_id=device_id,
channel_group_id=1,
channel_id=1,
channel_termination="XGSPON",
onu_id=20,
onu_session_id=1)
return self._proxy_address