| # |
| # 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. |
| # |
| """ |
| OMCI Message support |
| """ |
| from voltha.extensions.omci.omci import * |
| |
| # abbreviations |
| OP = EntityOperations |
| |
| |
| class MEFrame(object): |
| """Base class to help simplify Frame Creation""" |
| def __init__(self, entity_class, entity_id, data): |
| assert issubclass(entity_class, EntityClass), \ |
| "'{}' must be a subclass of MEFrame".format(entity_class) |
| self.check_type(entity_id, int) |
| |
| if not 0 <= entity_id <= 0xFFFF: |
| raise ValueError('entity_id should be 0..65535') |
| |
| self._class = entity_class |
| self._entity_id = entity_id |
| self.data = data |
| |
| # TODO: add a required attributes check list for various operations |
| # that each derive class can set as required. Then check these |
| # in the appropriate operation method in this class and assert |
| # if something is missing |
| |
| def __str__(self): |
| return '{}: Entity_ID: {}, Data: {}'.\ |
| format(type(self.entity_class), self._entity_id, self.data) |
| |
| @staticmethod |
| def check_type(param, types): |
| if not isinstance(param, types): |
| raise TypeError("param '{}' should be a {}".format(param, types)) |
| |
| @property |
| def entity_class(self): |
| """ |
| The Entity Class for this ME |
| :return: (EntityClass) Entity class |
| """ |
| return self._class |
| |
| @property |
| def entity_id(self): |
| """ |
| The Entity ID for this ME frame |
| :return: (int) Entity ID (0..0xFFFF) |
| """ |
| return self._entity_id |
| |
| def create(self): |
| """ |
| Create a Create request frame for this ME |
| :return: (OmciFrame) OMCI Frame |
| """ |
| assert OP.Create in self.entity_class.mandatory_operations, \ |
| "Set not allowed for '{}'".format(self.entity_class) |
| assert hasattr(self.entity_class, 'class_id'), 'class_id required for Create actions' |
| assert hasattr(self, 'entity_id'), 'entity_id required for Create actions' |
| assert hasattr(self, 'data'), 'data required for Create actions' |
| |
| data = getattr(self, 'data') |
| MEFrame.check_type(data, dict) |
| assert len(data) > 0, 'No attributes supplied' |
| |
| return OmciFrame( |
| transaction_id=None, |
| message_type=OmciCreate.message_id, |
| omci_message=OmciCreate( |
| entity_class=getattr(self.entity_class, 'class_id'), |
| entity_id=getattr(self, 'entity_id'), |
| data=data |
| )) |
| |
| def delete(self): |
| """ |
| Create a Delete request frame for this ME |
| :return: (OmciFrame) OMCI Frame |
| """ |
| assert OP.Delete in self.entity_class.mandatory_operations, \ |
| "Delete not allowed for '{}'".format(self.entity_class) |
| |
| return OmciFrame( |
| transaction_id=None, |
| message_type=OmciGet.message_id, |
| omci_message=OmciGet( |
| entity_class=getattr(self.entity_class, 'class_id'), |
| entity_id=getattr(self, 'entity_id') |
| )) |
| |
| def set(self): |
| """ |
| Create a Set request frame for this ME |
| :return: (OmciFrame) OMCI Frame |
| """ |
| assert OP.Set in self.entity_class.mandatory_operations, \ |
| "Set not allowed for '{}'".format(self.entity_class) |
| assert hasattr(self, 'data'), 'data required for Set actions' |
| |
| data = getattr(self, 'data') |
| MEFrame.check_type(data, dict) |
| assert len(data) > 0, 'No attributes supplied' |
| |
| return OmciFrame( |
| transaction_id=None, |
| message_type=OmciSet.message_id, |
| omci_message=OmciSet( |
| entity_class=getattr(self.entity_class, 'class_id'), |
| entity_id=getattr(self, 'entity_id'), |
| attributes_mask=self.entity_class.mask_for(*data.keys()), |
| data=data |
| )) |
| |
| def get(self): |
| """ |
| Create a Get request frame for this ME |
| :return: (OmciFrame) OMCI Frame |
| """ |
| assert OP.Get in self.entity_class.mandatory_operations, \ |
| "Get not allowed for '{}'".format(self.entity_class) |
| assert hasattr(self, 'data'), 'data required for Get actions' |
| |
| data = getattr(self, 'data') |
| MEFrame.check_type(data, (list, set, dict)) |
| assert len(data) > 0, 'No attributes supplied' |
| |
| mask_set = data.keys() if isinstance(data, dict) else data |
| |
| return OmciFrame( |
| transaction_id=None, |
| message_type=OmciGet.message_id, |
| omci_message=OmciGet( |
| entity_class=getattr(self.entity_class, 'class_id'), |
| entity_id=getattr(self, 'entity_id'), |
| attributes_mask=self.entity_class.mask_for(*mask_set) |
| )) |
| |
| @staticmethod |
| def _attr_to_data(attributes): |
| """ |
| Convert an object into the 'data' set or dictionary for get/set/create/delete |
| requests. |
| |
| This method takes a 'string', 'list', or 'set' for get requests and |
| converts it to a 'set' of attributes. |
| |
| For create/set requests a dictionary of attribute/value pairs is required |
| |
| :param attributes: (basestring, list, set, dict) attributes. For gets |
| a string, list, set, or dict can be provided. For create/set |
| operations, a dictionary should be provided. For delete |
| the attributes may be None since they are ignored. |
| |
| :return: (set, dict) set for get/deletes, dict for create/set |
| """ |
| if isinstance(attributes, basestring): |
| # data = [str(attributes)] |
| data = set() |
| data.add(str(attributes)) |
| |
| elif isinstance(attributes, list): |
| assert all(isinstance(attr, basestring) for attr in attributes),\ |
| 'attribute list must be strings' |
| data = {str(attr) for attr in attributes} |
| assert len(data) == len(attributes), 'Attributes were not unique' |
| |
| elif isinstance(attributes, set): |
| assert all(isinstance(attr, basestring) for attr in attributes),\ |
| 'attribute set must be strings' |
| data = {str(attr) for attr in attributes} |
| |
| elif isinstance(attributes, (dict, type(None))): |
| data = attributes |
| |
| else: |
| raise TypeError("Unsupported attributes type '{}'".format(type(attributes))) |
| |
| return data |
| |
| |
| class CardholderFrame(MEFrame): |
| """ |
| This managed entity represents fixed equipment slot configuration |
| for the ONU |
| """ |
| def __init__(self, single, slot_number, attributes): |
| """ |
| :param single:(bool) True if the ONU is a single piece of integrated equipment, |
| False if the ONU contains pluggable equipment modules |
| :param slot_number: (int) slot number (0..254) |
| |
| :param attributes: (basestring, list, set, dict) attributes. For gets |
| a string, list, or set can be provided. For create/set |
| operations, a dictionary should be provided, for |
| deletes None may be specified. |
| """ |
| # Validate |
| MEFrame.check_type(single, bool) |
| MEFrame.check_type(slot_number, int) |
| if not 0 <= slot_number <= 254: |
| raise ValueError('slot_number should be 0..254') |
| |
| entity_id = 256 + slot_number if single else slot_number |
| |
| super(CardholderFrame, self).__init__(Cardholder, entity_id, |
| MEFrame._attr_to_data(attributes)) |
| |
| |
| class CircuitPackFrame(MEFrame): |
| """ |
| This managed entity models a real or virtual circuit pack that is equipped in |
| a real or virtual ONU slot. |
| """ |
| def __init__(self, entity_id, attributes): |
| """ |
| :param entity_id: (int) This attribute uniquely identifies each instance of |
| this managed entity. Its value is the same as that |
| of the cardholder managed entity containing this |
| circuit pack instance. (0..65535) |
| |
| :param attributes: (basestring, list, set, dict) attributes. For gets |
| a string, list, or set can be provided. For create/set |
| operations, a dictionary should be provided, for |
| deletes None may be specified. |
| """ |
| super(CircuitPackFrame, self).__init__(CircuitPack, entity_id, |
| MEFrame._attr_to_data(attributes)) |
| |
| |
| class IpHostConfigDataFrame(MEFrame): |
| """ |
| The IP host config data configures IPv4 based services offered on the ONU. |
| """ |
| def __init__(self, entity_id, attributes): |
| """ |
| :param entity_id: (int) This attribute uniquely identifies each instance of |
| this managed entity. (0..65535) |
| |
| :param attributes: (basestring, list, set, dict) attributes. For gets |
| a string, list, or set can be provided. For create/set |
| operations, a dictionary should be provided, for |
| deletes None may be specified. |
| """ |
| super(IpHostConfigDataFrame, self).__init__(IpHostConfigData, |
| entity_id, |
| MEFrame._attr_to_data(attributes)) |
| |
| |
| class GemInterworkingTpFrame(MEFrame): |
| """ |
| An instance of this managed entity represents a point in the ONU where the |
| interworking of a bearer service (usually Ethernet) to the GEM layer takes |
| place. |
| """ |
| def __init__(self, entity_id, |
| gem_port_network_ctp_pointer=None, |
| interworking_option=None, |
| service_profile_pointer=None, |
| interworking_tp_pointer=None, |
| gal_profile_pointer=None, |
| attributes=None): |
| """ |
| :param entity_id: (int) This attribute uniquely identifies each instance of |
| this managed entity. (0..65535) |
| |
| :param gem_port_network_ctp_pointer: (int) This attribute points to an instance of |
| the GEM port network CTP. (0..65535) |
| |
| :param interworking_option: (int) This attribute identifies the type |
| of non-GEM function that is being interworked. |
| The options are: |
| 0 Circuit-emulated TDM |
| 1 MAC bridged LAN |
| 2 Reserved |
| 3 Reserved |
| 4 Video return path |
| 5 IEEE 802.1p mapper |
| 6 Downstream broadcast |
| 7 MPLS PW TDM service |
| |
| :param service_profile_pointer: (int) This attribute points to an instance of |
| a service profile. |
| CES service profile if interworking option = 0 |
| MAC bridge service profile if interworking option = 1 |
| Video return path service profile if interworking option = 4 |
| IEEE 802.1p mapper service profile if interworking option = 5 |
| Null pointer if interworking option = 6 |
| CES service profile if interworking option = 7 |
| |
| :param interworking_tp_pointer: (int) This attribute is used for the circuit |
| emulation service and IEEE 802.1p mapper |
| service without a MAC bridge. |
| |
| :param gal_profile_pointer: (int) This attribute points to an instance of |
| a service profile. |
| |
| :param attributes: (basestring, list, set, dict) additional ME attributes. |
| not specifically specified as a parameter. For gets |
| a string, list, or set can be provided. For create/set |
| operations, a dictionary should be provided, for |
| deletes None may be specified.. |
| """ |
| # Validate |
| self.check_type(gem_port_network_ctp_pointer, [int, type(None)]) |
| self.check_type(interworking_option, [int, type(None)]) |
| self.check_type(service_profile_pointer, [int, type(None)]) |
| self.check_type(interworking_tp_pointer, [int, type(None)]) |
| self.check_type(gal_profile_pointer, [int, type(None)]) |
| |
| if gem_port_network_ctp_pointer is not None and not 0 <= gem_port_network_ctp_pointer <= 0xFFFE: # TODO: Verify max |
| raise ValueError('gem_port_network_ctp_pointer should be 0..0xFFFE') |
| |
| if interworking_option is not None and not 0 <= interworking_option <= 7: |
| raise ValueError('interworking_option should be 0..7') |
| |
| if service_profile_pointer is not None and not 0 <= service_profile_pointer <= 0xFFFE: # TODO: Verify max |
| raise ValueError('service_profile_pointer should be 0..0xFFFE') |
| |
| if interworking_tp_pointer is not None and not 0 <= interworking_tp_pointer <= 0xFFFE: # TODO: Verify max |
| raise ValueError('interworking_tp_pointer should be 0..0xFFFE') |
| |
| if gal_profile_pointer is not None and not 0 <= gal_profile_pointer <= 0xFFFE: # TODO: Verify max |
| raise ValueError('gal_profile_pointer should be 0..0xFFFE') |
| |
| data = MEFrame._attr_to_data(attributes) |
| |
| if gem_port_network_ctp_pointer is not None or \ |
| interworking_option is not None or \ |
| service_profile_pointer is not None or \ |
| interworking_tp_pointer is not None or \ |
| gal_profile_pointer is not None: |
| |
| data = data or dict() |
| |
| if gem_port_network_ctp_pointer is not None: |
| data[gem_port_network_ctp_pointer] = gem_port_network_ctp_pointer |
| |
| if interworking_option is not None: |
| data[interworking_option] = interworking_option |
| |
| if service_profile_pointer is not None: |
| data[service_profile_pointer] = service_profile_pointer |
| |
| if interworking_tp_pointer is not None: |
| data[interworking_tp_pointer] = interworking_tp_pointer |
| |
| if gal_profile_pointer is not None: |
| data[gal_profile_pointer] = gal_profile_pointer |
| |
| super(GemInterworkingTpFrame, self).__init__(GemInterworkingTp, |
| entity_id, |
| data) |
| |
| |
| class GemPortNetworkCtpFrame(MEFrame): |
| """ |
| This managed entity represents the termination of a GEM port on an ONU. |
| """ |
| def __init__(self, entity_id, port_id=None, tcont_id=None, |
| direction=None, upstream_tm=None, attributes=None): |
| """ |
| :param entity_id: (int) This attribute uniquely identifies each instance of |
| this managed entity. (0..65535) |
| |
| :param port_id: (int) This attribute is the port-ID of the GEM port associated |
| with this CTP |
| |
| :param tcont_id: (int) This attribute points to a T-CONT instance |
| |
| :param direction: (string) Data direction. Valid values are: |
| 'upstream' - UNI-to-ANI |
| 'downstream' - ANI-to-UNI |
| 'bi-directional' - guess :-) |
| |
| :param upstream_tm: (int) If the traffic management option attribute in |
| the ONU-G ME is 0 (priority controlled) or 2 |
| (priority and rate controlled), this pointer |
| specifies the priority queue ME serving this GEM |
| port network CTP. If the traffic management |
| option attribute is 1 (rate controlled), this |
| attribute redundantly points to the T-CONT serving |
| this GEM port network CTP. |
| |
| :param attributes: (basestring, list, set, dict) additional ME attributes. |
| not specifically specified as a parameter. For gets |
| a string, list, or set can be provided. For create/set |
| operations, a dictionary should be provided, for |
| deletes None may be specified. |
| """ |
| _directions = {"upstream": 1, "downstream": 2, "bi-directional": 3} |
| |
| # Validate |
| self.check_type(port_id, [int, type(None)]) |
| self.check_type(tcont_id, [int, type(None)]) |
| self.check_type(direction, [basestring, type(None)]) |
| self.check_type(upstream_tm, [int, type(None)]) |
| |
| if port_id is not None and not 0 <= port_id <= 0xFFFE: # TODO: Verify max |
| raise ValueError('port_id should be 0..0xFFFE') |
| |
| if tcont_id is not None and not 0 <= tcont_id <= 0xFFFE: # TODO: Verify max |
| raise ValueError('tcont_id should be 0..0xFFFE') |
| |
| if direction is not None and str(direction).lower() not in _directions: |
| raise ValueError('direction should one of {}'.format(_directions.keys())) |
| |
| if upstream_tm is not None and not 0 <= upstream_tm <= 0xFFFE: # TODO: Verify max |
| raise ValueError('upstream_tm should be 0..0xFFFE') |
| |
| data = MEFrame._attr_to_data(attributes) |
| |
| if port_id is not None or tcont_id is not None or\ |
| direction is not None or upstream_tm is not None: |
| |
| data = data or dict() |
| |
| if port_id is not None: |
| data[port_id] = port_id |
| if tcont_id is not None: |
| data[tcont_id] = tcont_id |
| if direction is not None: |
| data[direction] = direction |
| if upstream_tm is not None: |
| data[upstream_tm] = upstream_tm |
| |
| super(GemPortNetworkCtpFrame, self).__init__(GemPortNetworkCtp, |
| entity_id, |
| data) |
| |
| |
| class Ieee8021pMapperServiceProfileFrame(MEFrame): |
| """ |
| This managed entity associates the priorities of IEEE 802.1p [IEEE |
| 802.1D] priority tagged frames with specific connections. |
| """ |
| def __init__(self, entity_id, tp_pointer=None, interwork_tp_pointers=None): |
| """ |
| :param entity_id: (int) This attribute uniquely identifies each instance of |
| this managed entity. (0..65535) |
| |
| :param tp_pointer: (int) This attribute points to an instance of the |
| associated termination point. (0..65535) |
| |
| :param interwork_tp_pointers: (list) List of 1 to 8 interworking termination |
| point IDs. The first entry is assigned |
| got p-bit priority 0. If less than 8 IDs |
| are provided, the last ID is used for |
| the remaining items. |
| """ |
| if tp_pointer is None and interwork_tp_pointers is None: |
| data = dict( |
| tp_pointer=OmciNullPointer, |
| interwork_tp_pointer_for_p_bit_priority_0=OmciNullPointer, |
| interwork_tp_pointer_for_p_bit_priority_1=OmciNullPointer, |
| interwork_tp_pointer_for_p_bit_priority_2=OmciNullPointer, |
| interwork_tp_pointer_for_p_bit_priority_3=OmciNullPointer, |
| interwork_tp_pointer_for_p_bit_priority_4=OmciNullPointer, |
| interwork_tp_pointer_for_p_bit_priority_5=OmciNullPointer, |
| interwork_tp_pointer_for_p_bit_priority_6=OmciNullPointer, |
| interwork_tp_pointer_for_p_bit_priority_7=OmciNullPointer |
| ) |
| else: |
| self.check_type(tp_pointer, [list, type(None)]) |
| self.check_type(interwork_tp_pointers, [list, type(None)]) |
| |
| data = dict() |
| |
| if tp_pointer is not None: |
| data[tp_pointer] = tp_pointer |
| |
| if interwork_tp_pointers is not None: |
| assert all(isinstance(tp, int) and 0 <= tp <= 0xFFFF |
| for tp in interwork_tp_pointers),\ |
| 'Interworking TP IDs must be 0..0xFFFF' |
| assert 1 <= len(interwork_tp_pointers) <= 8, \ |
| 'Invalid number of Interworking TP IDs. Must be 1..8' |
| |
| data = dict() |
| for pbit in range(0, len(interwork_tp_pointers)): |
| data['interwork_tp_pointer_for_p_bit_priority_'.format(pbit)] = \ |
| interwork_tp_pointers[pbit] |
| |
| for pbit in range(len(interwork_tp_pointers), 7): |
| data['interwork_tp_pointer_for_p_bit_priority_'.format(pbit)] = \ |
| interwork_tp_pointers[len(interwork_tp_pointers) - 1] |
| |
| super(Ieee8021pMapperServiceProfileFrame, self).__init__(Ieee8021pMapperServiceProfile, |
| entity_id, |
| data) |
| |
| |
| class MacBridgePortConfigurationDataFrame(MEFrame): |
| """ |
| This managed entity represents the ONU as equipment. |
| """ |
| def __init__(self, entity_id, bridge_id_pointer=None, port_num=None, |
| tp_type=None, tp_pointer=None, attributes=None): |
| """ |
| :param entity_id: (int) This attribute uniquely identifies each instance of |
| this managed entity. (0..65535) |
| |
| :param bridge_id_pointer: (int) This attribute points to an instance of the |
| MAC bridge service profile. (0..65535) |
| |
| :param port_num: (int) This attribute is the bridge port number. (0..255) |
| |
| :param tp_type: (int) This attribute identifies the type of termination point |
| associated with this MAC bridge port. Valid values are: |
| 1 Physical path termination point Ethernet UNI |
| 2 Interworking VCC termination point |
| 3 IEEE 802.1p mapper service profile |
| 4 IP host config data or IPv6 host config data |
| 5 GEM interworking termination point |
| 6 Multicast GEM interworking termination point |
| 7 Physical path termination point xDSL UNI part 1 |
| 8 Physical path termination point VDSL UNI |
| 9 Ethernet flow termination point |
| 10 Reserved |
| 11 Virtual Ethernet interface point |
| 12 Physical path termination point MoCA UNI |
| |
| :param tp_pointer: (int) This attribute points to the termination point |
| associated with this MAC bridge por. (0..65535) |
| |
| :param attributes: (basestring, list, set, dict) additional ME attributes. |
| not specifically specified as a parameter. For gets |
| a string, list, or set can be provided. For create/set |
| operations, a dictionary should be provided, for |
| deletes None may be specified. |
| """ |
| # Validate |
| self.check_type(bridge_id_pointer, [int, type(None)]) |
| self.check_type(port_num, [int, type(None)]) |
| self.check_type(tp_type, [int, type(None)]) |
| self.check_type(tp_pointer, [int, type(None)]) |
| |
| if bridge_id_pointer is not None and not 0 <= bridge_id_pointer <= 0xFFFE: # TODO: Verify max |
| raise ValueError('bridge_id_pointer should be 0..0xFFFE') |
| |
| if port_num is not None and not 0 <= port_num <= 255: |
| raise ValueError('port_num should be 0..255') # TODO: Verify min,max |
| |
| if tp_type is not None and not 1 <= tp_type <= 12: |
| raise ValueError('service_profile_pointer should be 1..12') |
| |
| if tp_pointer is not None and not 0 <= tp_pointer <= 0xFFFE: # TODO: Verify max |
| raise ValueError('interworking_tp_pointer should be 0..0xFFFE') |
| |
| data = MEFrame._attr_to_data(attributes) |
| |
| if bridge_id_pointer is not None or \ |
| port_num is not None or \ |
| tp_type is not None or \ |
| tp_pointer is not None: |
| |
| data = data or dict() |
| |
| if bridge_id_pointer is not None: |
| data[bridge_id_pointer] = bridge_id_pointer |
| |
| if port_num is not None: |
| data[port_num] = port_num |
| |
| if tp_type is not None: |
| data[tp_type] = tp_type |
| |
| if tp_pointer is not None: |
| data[tp_pointer] = tp_pointer |
| |
| super(MacBridgePortConfigurationDataFrame, self).\ |
| __init__(MacBridgePortConfigurationData, entity_id, data) |
| |
| |
| class OntGFrame(MEFrame): |
| """ |
| This managed entity represents the ONU as equipment. |
| """ |
| def __init__(self, attributes): |
| """ |
| :param attributes: (basestring, list, set, dict) attributes. For gets |
| a string, list, or set can be provided. For create/set |
| operations, a dictionary should be provided, for |
| deletes None may be specified. |
| """ |
| super(OntGFrame, self).__init__(OntG, 0, |
| MEFrame._attr_to_data(attributes)) |
| |
| |
| class Ont2GFrame(MEFrame): |
| """ |
| This managed entity contains additional attributes associated with a PON ONU. |
| """ |
| def __init__(self, attributes): |
| """ |
| :param attributes: (basestring, list, set, dict) attributes. For gets |
| a string, list, or set can be provided. For create/set |
| operations, a dictionary should be provided, for |
| deletes None may be specified. |
| """ |
| # Only one managed entity instance (Entity ID=0) |
| super(Ont2GFrame, self).__init__(Ont2G, 0, |
| MEFrame._attr_to_data(attributes)) |
| |
| |
| class PptpEthernetUniFrame(MEFrame): |
| """ |
| This managed entity represents the point at an Ethernet UNI where the physical path |
| terminates and Ethernet physical level functions are performed. |
| """ |
| def __init__(self, entity_id, attributes): |
| """ |
| :param entity_id: (int) This attribute uniquely identifies each instance of |
| this managed entity. (0..65535) |
| |
| :param attributes: (basestring, list, set, dict) attributes. For gets |
| a string, list, or set can be provided. For create/set |
| operations, a dictionary should be provided, for |
| deletes None may be specified. |
| """ |
| super(PptpEthernetUniFrame, self).__init__(PptpEthernetUni, entity_id, |
| MEFrame._attr_to_data(attributes)) |
| |
| |
| class SoftwareImageFrame(MEFrame): |
| """ |
| This managed entity models an executable software image stored in the ONU. |
| """ |
| def __init__(self, entity_id): |
| """ |
| :param entity_id: (int) This attribute uniquely identifies each instance of |
| this managed entity. (0..65535) |
| """ |
| super(SoftwareImageFrame, self).__init__(SoftwareImage, entity_id, None) |
| |
| |
| class TcontFrame(MEFrame): |
| """ |
| An instance of the traffic container managed entity T-CONT represents a |
| logical connection group associated with a G-PON PLOAM layer alloc-ID. |
| """ |
| def __init__(self, entity_id, alloc_id=None, policy=None): |
| """ |
| :param entity_id: (int) This attribute uniquely identifies each instance of |
| this managed entity. (0..65535) |
| |
| :param alloc_id: (int) This attribute links the T-CONT with the alloc-ID |
| assigned by the OLT in the assign_alloc-ID PLOAM |
| message (0..0xFFF) |
| |
| :param policy: (int) This attribute indicates the T-CONT's traffic scheduling |
| policy. Valid values: |
| 0 - Null |
| 1 - Strict priority |
| 2 - WRR - Weighted round robin |
| """ |
| # Validate |
| self.check_type(alloc_id, [int, type(None)]) |
| self.check_type(policy, [int, type(None)]) |
| |
| if alloc_id is not None and not 0 <= alloc_id <= 0xFFF: |
| raise ValueError('alloc_id should be 0..0xFFF') |
| |
| if policy is not None and not 0 <= policy <= 2: |
| raise ValueError('policy should be 0..2') |
| |
| if alloc_id is None and policy is None: |
| data = None |
| else: |
| data = dict() |
| |
| if alloc_id is not None: |
| data[alloc_id] = alloc_id |
| |
| if policy is not None: |
| data[policy] = policy |
| |
| super(TcontFrame, self).__init__(Tcont, entity_id, data) |
| |
| |
| class VlanTaggingFilterDataFrame(MEFrame): |
| """ |
| An instance of this managed entity represents a point in the ONU where the |
| interworking of a bearer service (usually Ethernet) to the GEM layer takes |
| place. |
| """ |
| def __init__(self, entity_id, vlan_tcis=None, forward_operation=None): |
| """ |
| :param entity_id: (int) This attribute uniquely identifies each instance of |
| this managed entity. (0..65535) |
| |
| :param vlan_tcis: (list) This attribute is a list of provisioned TCI values |
| for the bridge port. (0..0xFFFF) |
| |
| :param forward_operation: (int) What to do. See ITU spec for more information |
| |
| """ |
| # Validate |
| self.check_type(vlan_tcis, [list, type(None)]) |
| self.check_type(forward_operation, [int, type(None)]) |
| |
| if forward_operation is not None and not 0 <= forward_operation <= 0x21: |
| raise ValueError('forward_operation should be 0..0x21') |
| |
| if vlan_tcis is None and forward_operation is None: |
| data = None |
| else: |
| data = dict() |
| |
| if vlan_tcis is not None: |
| assert all(isinstance(tci, int) and 0 <= tci <= 0xFFFF |
| for tci in vlan_tcis), "VLAN TCI's are 0..0xFFFF" |
| for index in range(0, len(vlan_tcis)): |
| data['vlan_filter_{}'.format(index)] = vlan_tcis[index] |
| data['number_of_entries'] = len(vlan_tcis) |
| |
| if forward_operation is not None: |
| data[forward_operation] = forward_operation |
| |
| super(VlanTaggingFilterDataFrame, self).__init__(VlanTaggingFilterData, |
| entity_id, |
| data) |
| |
| |
| # TODO: Wednesday - Start with send_create_extended_vlan_tagging_operation_configuration_data |