| # |
| # 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 scapy.automaton import ATMT |
| import structlog |
| from voltha.adapters.microsemi_olt.BaseOltAutomaton import BaseOltAutomaton |
| from voltha.adapters.microsemi_olt.PAS5211 import PAS5211EventOnuActivation, PAS5211MsgGetActivationAuthMode, \ |
| PAS5211MsgGetActivationAuthModeResponse, PON_ACTIVATION_AUTH_AUTO, PON_ENABLE, PAS5211MsgSetOnuOmciPortId, \ |
| PAS5211MsgSetOnuOmciPortIdResponse, PAS5211MsgSendFrame, PON_PORT_PON, PAS5211MsgSendFrameResponse |
| from voltha.extensions.omci.omci_entities import CircuitPack |
| from voltha.extensions.omci.omci_frame import OmciFrame |
| from voltha.extensions.omci.omci_messages import OmciGet, OmciGetResponse |
| from voltha.protos.common_pb2 import AdminState |
| from voltha.protos.common_pb2 import OperStatus |
| from voltha.protos.device_pb2 import Port |
| |
| log = structlog.get_logger() |
| _verbose = False |
| |
| def hexstring(string): |
| return ":".join("{:02x}".format(ord(c)) for c in string) |
| |
| class ActivationManager(BaseOltAutomaton): |
| |
| onu_id = None |
| serial_number = None |
| onu_session_id = None |
| port_id = None |
| channel_id = None |
| |
| def parse_args(self, debug=0, store=0, **kwargs): |
| self.onu_id = kwargs.pop('onu_id') |
| self.serial_number = kwargs.pop('serial_number') |
| self.onu_session_id = kwargs.pop('onu_session_id') |
| self.port_id = self.onu_id |
| self.channel_id = kwargs.pop('channel_id') |
| |
| if self.onu_id is None or self.serial_number is None or \ |
| self.onu_session_id is None or self.channel_id is None: |
| raise ValueError('ONU is not well defined') |
| |
| BaseOltAutomaton.parse_args(self, debug=debug, store=store, **kwargs) |
| |
| """ |
| States |
| """ |
| |
| @ATMT.state(initial=1) |
| def got_activation_event(self): |
| pass |
| |
| @ATMT.state() |
| def wait_get_auth_mode(self): |
| pass |
| |
| @ATMT.state() |
| def got_auth_mode(self): |
| pass |
| |
| @ATMT.state() |
| def wait_omci_port_id(self): |
| pass |
| |
| @ATMT.state() |
| def got_omci_port_id(self): |
| pass |
| |
| @ATMT.state() |
| def wait_send_frame(self): |
| pass |
| |
| @ATMT.state() |
| def wait_omci_get(self): |
| pass |
| |
| @ATMT.state(final=1) |
| def end(self): |
| pass |
| |
| @ATMT.state(error=1) |
| def error(self): |
| pass |
| |
| """ |
| Utility Methods |
| """ |
| |
| def create_port(self, vendor): |
| port = Port(port_no=self.port_id, |
| label="{} ONU".format(vendor), |
| type=Port.ETHERNET_UNI, |
| admin_state=AdminState.ENABLED, |
| oper_status=OperStatus.ACTIVE |
| ) |
| self.device.add_port(port) |
| |
| def px(self, pkt): |
| return self.p(pkt, channel_id=self.channel_id, |
| onu_id=self.onu_id, onu_session_id=self.onu_session_id) |
| |
| def error(self, msg): |
| log.error(msg) |
| raise self.error() |
| |
| """ |
| Transitions |
| """ |
| |
| # Transition from got_activation_event |
| @ATMT.condition(got_activation_event) |
| def send_get_activation_auth_mode(self): |
| auth_mode = PAS5211MsgGetActivationAuthMode() |
| self.send(self.p(auth_mode)) |
| raise self.wait_get_auth_mode() |
| |
| # Transitions from wait_get_auth_mode |
| @ATMT.timeout(wait_get_auth_mode, 3) |
| def timeout_get_auth_mode(self): |
| self.error('Could not get auth mode for OLT {}; dropping activation event for {}' |
| .format(self.target, hexstring(self.serial_number))) |
| |
| @ATMT.receive_condition(wait_get_auth_mode) |
| def wait_for_get_auth_mode(self, pkt): |
| if PAS5211MsgGetActivationAuthModeResponse in pkt: |
| if pkt.mode == PON_ACTIVATION_AUTH_AUTO: |
| raise self.got_auth_mode() |
| else: |
| # TODO There may be something that can be done here. |
| # See line 2497 of PAS_onu_mode_change_thread.c |
| log.error('Got unknown auth mode {}; dropping activation event'.format(pkt.mode)) |
| raise self.end() |
| |
| # Transitions from got auth_mode |
| @ATMT.condition(got_auth_mode) |
| def send_omci_port_id(self): |
| omci_port_id = PAS5211MsgSetOnuOmciPortId(port_id=self.port_id, activate=PON_ENABLE) |
| self.send(self.px(omci_port_id)) |
| raise self.wait_omci_port_id() |
| |
| # Transitions from wait_omci_port_id |
| @ATMT.timeout(wait_omci_port_id, 3) |
| def timeout_omci_port_id(self): |
| self.error('Could not set omci port id for OLT {}; dropping activation event for {}' |
| .format(self.target, hexstring(self.serial_number))) |
| |
| @ATMT.receive_condition(wait_omci_port_id) |
| def wait_for_omci_port_id(self, pkt): |
| if pkt.opcode == PAS5211MsgSetOnuOmciPortIdResponse.opcode and \ |
| pkt.onu_id == self.onu_id and pkt.onu_session_id == self.onu_session_id and \ |
| pkt.channel_id == self.channel_id: |
| raise self.got_omci_port_id() |
| |
| # Transitions from got_omci_port_id |
| @ATMT.condition(got_omci_port_id) |
| def send_omci_identity_frame(self): |
| # attr_mask |= OMCI_ATTR_BIT(OMCI_CIRCUIT_PACK_ATTR_VENDOR_ID); |
| #message.attributes_mask = 2048 |
| |
| # Entity_id |
| # equip_ind = OMCI_CIRCUIT_PACK_INTEGRATED_EQUIPMENT; |
| # slot_id = 257; |
| # entity_instance = ((equip_ind<<8) | slot_id |
| message = OmciGet(entity_class=CircuitPack.class_id, entity_id = 257, |
| attributes_mask=2048) |
| #TODO fix transaction id |
| frame = OmciFrame(transaction_id=0, message_type=OmciGet.message_id, |
| omci_message=message) |
| omci_frame = PAS5211MsgSendFrame(port_type=PON_PORT_PON, port_id=self.port_id, |
| management_frame=PON_ENABLE, frame=frame) |
| |
| self.send(self.px(omci_frame)) |
| |
| raise self.wait_send_frame() |
| |
| # Transitions from wait_send_frame |
| @ATMT.timeout(wait_send_frame, 3) |
| def timeout_send_frame(self): |
| self.error('Could not send omci to OLT {}; dropping activation event for {}' |
| .format(self.target, hexstring(self.serial_number))) |
| |
| @ATMT.receive_condition(wait_send_frame) |
| def wait_for_send_frame(self, pkt): |
| if PAS5211MsgSendFrameResponse in pkt: |
| raise self.wait_omci_get() |
| |
| # Transitions from wait_omci_get |
| @ATMT.timeout(wait_omci_get, 3) |
| def timeout_send_frame(self): |
| self.error('Did not receive omci get event from OLT {}; dropping activation event for {}' |
| .format(self.target, hexstring(self.serial_number))) |
| |
| @ATMT.receive_condition(wait_omci_get) |
| def wait_for_omci_get(self, pkt): |
| if OmciGetResponse in pkt: |
| vendor = pkt['OmciGetResponse'].data['vendor_id'] |
| log.info("Activated {} ONT".format(vendor)) |
| self.create_port(vendor) |
| |
| self.device.onu_detected( |
| parent_port_no=self.channel_id, |
| child_device_type='%s_onu' % vendor.lower(), |
| onu_id=self.port_id, |
| ) |
| |
| raise self.end() |
| |
| |
| class ActivationWatcher(BaseOltAutomaton): |
| |
| """ |
| States |
| """ |
| |
| @ATMT.state(initial=1) |
| def wait_onu_activation_event(self): |
| pass |
| |
| """ |
| Transitions |
| """ |
| |
| # Transitions from wait_onu_activation_event |
| @ATMT.receive_condition(wait_onu_activation_event) |
| def wait_for_onu_activation_event(self, pkt): |
| if PAS5211EventOnuActivation in pkt: |
| log.info('{} activated'.format(hexstring(pkt.serial_number))) |
| onu_activation = ActivationManager(iface=self.iface, target=self.target, comm=self.comm, |
| onu_id=pkt.onu_id, serial_number=pkt.serial_number, |
| onu_session_id=pkt.onu_session_id, |
| channel_id=pkt.channel_id, device=self.device) |
| onu_activation.runbg() |
| raise self.wait_onu_activation_event() |