def setUp(self):
        registry.register(
            'core',
            VolthaCore(instance_id=1,
                       core_store_id=1,
                       grpc_port=50060,
                       version="1",
                       log_level=LogLevel.INFO)).start()

        self.adapter_agent_ont = AdapterAgent("broadcom_onu",
                                              "BroadcomOnuAdapter")
        self.adapter_agent_olt = AdapterAgent("asfvolt16_olt",
                                              "Asfvolt16Adapter")

        # create and update the core with Broadcom ONU device type
        self.onu_device_type = DeviceType(id='broadcom_onu',
                                          vendor_id='BRCM',
                                          adapter='broadcom_onu',
                                          accepts_bulk_flow_update=True)

        # create and update the core with Broadcom ONU device type
        self.olt_device_type = DeviceType(id='asfvolt16_olt',
                                          vendor_id='Edgecore',
                                          adapter='asfvolt16_olt',
                                          accepts_bulk_flow_update=True)

        self.adapter_agent_ont._make_up_to_date('/device_types',
                                                'broadcom_onu',
                                                self.onu_device_type)
        self.adapter_agent_olt._make_up_to_date('/device_types',
                                                'asfvolt16_olt',
                                                self.olt_device_type)
Example #2
0
 def __init__(self,
              adapter_agent,
              config,
              device_handler_class,
              name,
              vendor,
              version,
              device_type,
              vendor_id,
              accepts_bulk_flow_update=True,
              accepts_add_remove_flow_updates=False):
     log.debug('Initializing adapter: {} {} {}'.format(
         vendor, name, version))
     self.adapter_agent = adapter_agent
     self.config = config
     self.name = name
     self.supported_device_types = [
         DeviceType(
             id=device_type,
             vendor_id=vendor_id,
             adapter=name,
             accepts_bulk_flow_update=accepts_bulk_flow_update,
             accepts_add_remove_flow_updates=accepts_add_remove_flow_updates
         )
     ]
     self.descriptor = Adapter(
         id=self.name,
         vendor=vendor,
         version=version,
         config=AdapterConfig(log_level=LogLevel.INFO))
     self.devices_handlers = dict()  # device_id -> Olt/OnuHandler()
     self.device_handler_class = device_handler_class
Example #3
0
class TellabsOpenomciOnuAdapter(BrcmOpenomciOnuAdapter):

    name = 'tellabs_openomci_onu'

    supported_device_types = [
        DeviceType(
            id=name,
            vendor_ids=['BFWS', 'TSLS', 'IPHO', 'SHGJ'],
            adapter=name,
            accepts_bulk_flow_update=True
        )
    ]

    def __init__(self, adapter_agent, config):
        super(TellabsOpenomciOnuAdapter, self).__init__(adapter_agent, config)
        
        self.descriptor = Adapter(
            id=self.name,
            vendor='Tellabs Inc.',
            version='0.1',
            config=AdapterConfig(log_level=LogLevel.INFO)
        )
        log.info('tellabs_openomci_onu.__init__', adapter=self.descriptor)

        self.broadcom_omci['mib-synchronizer']['database'] = MibDbExternal

    def device_types(self):
        return DeviceTypes(items=self.supported_device_types)

    def custom_me_entities(self):
        return onu_custom_me_entities()
Example #4
0
class BBSimOltAdapter(OpenoltAdapter):
    name = 'bbsimolt'

    supported_device_types = [
        DeviceType(id=name,
                   adapter=name,
                   accepts_bulk_flow_update=True,
                   accepts_direct_logical_flows_update=True)
    ]

    def __init__(self, adapter_agent, config):
        super(BBSimOltAdapter, self).__init__(adapter_agent, config)

        # overwrite the descriptor
        self.descriptor = Adapter(
            id=self.name,
            vendor='CORD',
            version='0.1',
            config=AdapterConfig(log_level=LogLevel.INFO))
        self.bbsim_id = 17  #TODO: This should be modified later

    def adopt_device(self, device):
        self.bbsim_id += 1
        log.info('adopt-device', device=device)

        support_classes = deepcopy(OpenOltDefaults)['support_classes']

        # Customize platform
        support_classes['platform'] = BBSimOltPlatform
        support_classes['flow_mgr'] = BBSimOltFlowMgr
        support_classes['alarm_mgr'] = BBSimOltAlarmMgr
        support_classes['stats_mgr'] = BBSimOltStatisticsMgr
        support_classes['bw_mgr'] = BBSimOltBW
        kwargs = {
            'support_classes': support_classes,
            'adapter_agent': self.adapter_agent,
            'device': device,
            'device_num': self.num_devices + 1,
            'dp_id': '00:00:00:00:00:' + hex(self.bbsim_id)[-2:]
        }
        try:
            self.devices[device.id] = BBSimOltDevice(**kwargs)
        except Exception as e:
            log.error('Failed to adopt BBSimOLT device', error=e)
            del self.devices[device.id]
            raise
        else:
            self.num_devices += 1

    def delete_device(self, device):
        self.bbsim_id -= 1
        super(BBSimOltAdapter, self).delete_device(device)
        self.num_devices -= 1
Example #5
0
class CigOpenomciOnuAdapter(BrcmOpenomciOnuAdapter):

    name = 'cig_openomci_onu'

    supported_device_types = [
        DeviceType(
            id=name,
            #vendor_ids=[],
            vendor_ids=['CIGG'],
            adapter=name,
            accepts_bulk_flow_update=True)
    ]

    def __init__(self, adapter_agent, config):
        super(CigOpenomciOnuAdapter, self).__init__(adapter_agent, config)
        # self.adapter_agent = adapter_agent
        # self.config = config
        self.descriptor = Adapter(
            id=self.name,
            vendor='CIG Tech',
            version='0.10',
            config=AdapterConfig(log_level=LogLevel.INFO))
        # self.devices_handlers = dict()

        # Customize OpenOMCI for CIG ONUs
        self._omci_support_cls = deepcopy(OpenOmciAgentDefaults)

        # self.broadcom_omci['mib-synchronizer']['state-machine'] = BrcmMibSynchronizer
        # self.broadcom_omci['mib-synchronizer']['database'] = MibDbVolatileDict
        # self.broadcom_omci['omci-capabilities']['tasks']['get-capabilities'] = BrcmCapabilitiesTask

        # self._omci_agent = OpenOMCIAgent(self.adapter_agent.core,
        #                                  support_classes=self.broadcom_omci)

        self._omci_agent = OpenOMCIAgent(
            self.adapter_agent.core, support_classes=self._omci_support_cls)
        # register for adapter messages
        # self.adapter_agent.register_for_inter_adapter_messages()

    def device_types(self):
        return DeviceTypes(items=self.supported_device_types)

    def adapter_descriptor(self):
        return self.descriptor

    def device_types(self):
        return DeviceTypes(items=self.supported_device_types)
Example #6
0
class TellabsAdapter(OpenoltAdapter):
    name = 'tellabs_olt'

    supported_device_types = [
        DeviceType(
            id=name,
            adapter=name,
            accepts_bulk_flow_update=True,
            accepts_direct_logical_flows_update=True
        )
    ]

    def __init__(self, adapter_agent, config):
        super(TellabsAdapter, self).__init__(adapter_agent, config)

        # overwrite the descriptor
        self.descriptor = Adapter(
            id=self.name,
            vendor='Tellabs Inc.',
            version='0.1',
            config=AdapterConfig(log_level=LogLevel.INFO)
        )

        log.info('tellabs_olt.__init__', adapter=self.descriptor)

    def adopt_device(self, device):
        log.info('adopt-device', device=device)

        support_classes = deepcopy(OpenOltDefaults)['support_classes']

        # Customize resource_mgr
        support_classes['resource_mgr'] = TellabsResourceManager

        kwargs = {
            'support_classes': support_classes,
            'adapter_agent': self.adapter_agent,
            'device': device,
            'device_num': self.num_devices + 1
        }
        try:
            self.devices[device.id] = OpenoltDevice(**kwargs)
        except Exception as e:
            log.error('Failed to adopt OpenOLT device', error=e)
            del self.devices[device.id]
            raise
        else:
            self.num_devices += 1
Example #7
0
class SimulatedOnuAdapter(object):

    name = 'simulated_onu'

    supported_device_types = [
        DeviceType(id='simulated_onu',
                   adapter=name,
                   accepts_bulk_flow_update=True)
    ]

    def __init__(self, adapter_agent, config):
        self.adapter_agent = adapter_agent
        self.config = config
        self.descriptor = Adapter(
            id=self.name,
            vendor='Voltha project',
            version='0.1',
            config=AdapterConfig(log_level=LogLevel.INFO))
        self.incoming_messages = DeferredQueue()

    def start(self):
        log.debug('starting')
        log.info('started')

    def stop(self):
        log.debug('stopping')
        log.info('stopped')

    def adapter_descriptor(self):
        return self.descriptor

    def device_types(self):
        return DeviceTypes(items=self.supported_device_types)

    def health(self):
        return HealthStatus(state=HealthStatus.HealthState.HEALTHY)

    def change_master_state(self, master):
        raise NotImplementedError()

    def adopt_device(self, device):
        # We kick of a simulated activation scenario
        reactor.callLater(0.2, self._simulate_device_activation, device)
        return device

    def reconcile_device(self, device):
        raise NotImplementedError()

    def abandon_device(self, device):
        raise NotImplementedError()

    def disable_device(self, device):
        device.oper_status = OperStatus.UNKNOWN
        self.adapter_agent.update_device(device)

    def reenable_device(self, device):
        raise NotImplementedError()

    def reboot_device(self, device):
        raise NotImplementedError()

    def download_image(self, device, request):
        raise NotImplementedError()

    def get_image_download_status(self, device, request):
        raise NotImplementedError()

    def cancel_image_download(self, device, request):
        raise NotImplementedError()

    def activate_image_update(self, device, request):
        raise NotImplementedError()

    def revert_image_update(self, device, request):
        raise NotImplementedError()

    def delete_device(self, device):
        raise NotImplementedError()

    def get_device_details(self, device):
        raise NotImplementedError()

    def update_pm_config(self, device, pm_configs):
        raise NotImplementedError()

    def self_test_device(self, device):
        log.info("run-self-test-on-device", device=device.id)
        result = SelfTestResponse(result=random.choice([
            SelfTestResponse.SUCCESS, SelfTestResponse.FAILURE,
            SelfTestResponse.NOT_SUPPORTED, SelfTestResponse.UNKNOWN_ERROR
        ]))
        return result

    @inlineCallbacks
    def _simulate_device_activation(self, device):

        # first we verify that we got parent reference and proxy info
        assert device.parent_id
        assert device.proxy_address.device_id
        assert device.proxy_address.channel_id

        # we pretend that we were able to contact the device and obtain
        # additional information about it
        device.vendor = 'simulated onu adapter'
        device.model = 'n/a'
        device.hardware_version = 'n/a'
        device.firmware_version = 'n/a'
        device.serial_number = uuid4().hex
        device.connect_status = ConnectStatus.REACHABLE

        image1 = Image(name="onu_candidate1",
                       version="1.0",
                       hash="1234567892",
                       install_datetime=datetime.datetime.utcnow().isoformat(),
                       is_active=True,
                       is_committed=True,
                       is_valid=True)
        image2 = Image(name="onu_candidate2",
                       version="1.0",
                       hash="1234567893",
                       install_datetime=datetime.datetime.utcnow().isoformat(),
                       is_active=False,
                       is_committed=False,
                       is_valid=True)

        device.images.image.extend([image1, image2])

        self.adapter_agent.update_device(device)

        # then shortly after we create some ports for the device
        yield asleep(0.05)
        uni_port = Port(port_no=2,
                        label='UNI facing Ethernet port',
                        type=Port.ETHERNET_UNI,
                        admin_state=AdminState.ENABLED,
                        oper_status=OperStatus.ACTIVE)
        self.adapter_agent.add_port(device.id, uni_port)
        self.adapter_agent.add_port(
            device.id,
            Port(port_no=1,
                 label='PON port',
                 type=Port.PON_ONU,
                 admin_state=AdminState.ENABLED,
                 oper_status=OperStatus.ACTIVE,
                 peers=[
                     Port.PeerPort(device_id=device.parent_id,
                                   port_no=device.parent_port_no)
                 ]))

        # TODO adding vports to the logical device shall be done by agent?
        # then we create the logical device port that corresponds to the UNI
        # port of the device
        yield asleep(0.05)

        # obtain logical device id
        parent_device = self.adapter_agent.get_device(device.parent_id)
        logical_device_id = parent_device.parent_id
        assert logical_device_id

        # we are going to use the proxy_address.channel_id as unique number
        # and name for the virtual ports, as this is guaranteed to be unique
        # in the context of the OLT port, so it is also unique in the context
        # of the logical device
        port_no = device.proxy_address.channel_id
        cap = OFPPF_1GB_FD | OFPPF_FIBER
        self.adapter_agent.add_logical_port(
            logical_device_id,
            LogicalPort(id=str(port_no),
                        ofp_port=ofp_port(port_no=port_no,
                                          hw_addr=mac_str_to_tuple(
                                              '00:00:00:00:00:%02x' % port_no),
                                          name='uni-{}'.format(port_no),
                                          config=0,
                                          state=OFPPS_LIVE,
                                          curr=cap,
                                          advertised=cap,
                                          peer=cap,
                                          curr_speed=OFPPF_1GB_FD,
                                          max_speed=OFPPF_1GB_FD),
                        device_id=device.id,
                        device_port_no=uni_port.port_no))

        # simulate a proxied message sending and receving a reply
        reply = yield self._simulate_message_exchange(device)

        # and finally update to "ACTIVE"
        device = self.adapter_agent.get_device(device.id)
        device.oper_status = OperStatus.ACTIVE
        self.adapter_agent.update_device(device)

    def update_flows_bulk(self, device, flows, groups):
        log.debug('bulk-flow-update',
                  device_id=device.id,
                  flows=flows,
                  groups=groups)

        # sample code that analyzes the incoming flow table
        assert len(groups.items) == 0, "Cannot yet deal with groups"

        for flow in flows.items:
            in_port = get_in_port(flow)
            assert in_port is not None

            if in_port == 2:

                # Downstream rule

                for field in get_ofb_fields(flow):
                    if field.type == ETH_TYPE:
                        _type = field.eth_type
                        pass  # construct ether type based condition here

                    elif field.type == IP_PROTO:
                        _proto = field.ip_proto
                        pass  # construct ip_proto based condition here

                    elif field.type == IN_PORT:
                        _port = field.port
                        pass  # construct in_port based condition here

                    elif field.type == VLAN_VID:
                        _vlan_vid = field.vlan_vid
                        pass  # construct VLAN ID based filter condition here

                    elif field.type == VLAN_PCP:
                        _vlan_pcp = field.vlan_pcp
                        pass  # construct VLAN PCP based filter condition here

                    # TODO
                    else:
                        raise NotImplementedError('field.type={}'.format(
                            field.type))

                for action in get_actions(flow):

                    if action.type == OUTPUT:
                        pass  # construct packet emit rule here

                    elif action.type == PUSH_VLAN:
                        if action.push.ethertype != 0x8100:
                            log.error('unhandled-ether-type',
                                      ethertype=action.push.ethertype)
                        pass  # construct vlan push command here

                    elif action.type == POP_VLAN:
                        pass  # construct vlan pop command here

                    elif action.type == SET_FIELD:
                        assert (action.set_field.field.oxm_class ==
                                ofp.OFPXMC_OPENFLOW_BASIC)
                        field = action.set_field.field.ofb_field
                        if field.type == VLAN_VID:
                            pass  # construct vlan_id set command here
                        else:
                            log.error('unsupported-action-set-field-type',
                                      field_type=field.type)

                    else:
                        log.error('unsupported-action-type',
                                  action_type=action.type)

                # final assembly of low level device flow rule and pushing it
                # down to device
                pass

            elif in_port == 1:

                # Upstream rule

                for field in get_ofb_fields(flow):
                    if field.type == ETH_TYPE:
                        _type = field.eth_type
                        pass  # construct ether type based condition here

                    elif field.type == IP_PROTO:
                        _proto = field.ip_proto
                        pass  # construct ip_proto based condition here

                    elif field.type == IN_PORT:
                        _port = field.port
                        pass  # construct in_port based condition here

                    elif field.type == VLAN_VID:
                        _vlan_vid = field.vlan_vid
                        pass  # construct VLAN ID based filter condition here

                    elif field.type == VLAN_PCP:
                        _vlan_pcp = field.vlan_pcp
                        pass  # construct VLAN PCP based filter condition here

                    elif field.type == IPV4_DST:
                        _ipv4_dst = field.ipv4_dst
                        pass  # construct IPv4 DST address based condition

                    elif field.type == UDP_SRC:
                        _udp_src = field.udp_src
                        pass  # construct UDP SRC based filter here

                    elif field.type == UDP_DST:
                        _udp_dst = field.udp_dst
                        pass  # construct UDP DST based filter here

                    # TODO
                    else:
                        raise NotImplementedError('field.type={}'.format(
                            field.type))

                for action in get_actions(flow):

                    if action.type == OUTPUT:
                        pass  # construct packet emit rule here

                    elif action.type == PUSH_VLAN:
                        if action.push.ethertype != 0x8100:
                            log.error('unhandled-ether-type',
                                      ethertype=action.push.ethertype)
                        pass  # construct vlan push command here

                    elif action.type == SET_FIELD:
                        assert (action.set_field.field.oxm_class ==
                                ofp.OFPXMC_OPENFLOW_BASIC)
                        field = action.set_field.field.ofb_field
                        if field.type == VLAN_VID:
                            pass  # construct vlan_id set command here
                        else:
                            log.error('unsupported-action-set-field-type',
                                      field_type=field.type)

                    else:
                        log.error('unsupported-action-type',
                                  action_type=action.type)

                # final assembly of low level device flow rule and pushing it
                # down to device
                pass

            else:
                raise Exception('Port should be 1 or 2 by our convention')

    def update_flows_incrementally(self, device, flow_changes, group_changes):
        raise NotImplementedError()

    def send_proxied_message(self, proxy_address, msg):
        raise NotImplementedError()

    def receive_proxied_message(self, proxy_address, msg):
        # just place incoming message to a list
        self.incoming_messages.put((proxy_address, msg))

    def create_interface(self, device, data):
        raise NotImplementedError()

    def update_interface(self, device, data):
        raise NotImplementedError()

    def remove_interface(self, device, data):
        raise NotImplementedError()

    def receive_onu_detect_state(self, device_id, state):
        raise NotImplementedError()

    def create_tcont(self, device, tcont_data, traffic_descriptor_data):
        raise NotImplementedError()

    def update_tcont(self, device, tcont_data, traffic_descriptor_data):
        raise NotImplementedError()

    def remove_tcont(self, device, tcont_data, traffic_descriptor_data):
        raise NotImplementedError()

    def create_gemport(self, device, data):
        raise NotImplementedError()

    def update_gemport(self, device, data):
        raise NotImplementedError()

    def remove_gemport(self, device, data):
        raise NotImplementedError()

    def create_multicast_gemport(self, device, data):
        raise NotImplementedError()

    def update_multicast_gemport(self, device, data):
        raise NotImplementedError()

    def remove_multicast_gemport(self, device, data):
        raise NotImplementedError()

    def create_multicast_distribution_set(self, device, data):
        raise NotImplementedError()

    def update_multicast_distribution_set(self, device, data):
        raise NotImplementedError()

    def remove_multicast_distribution_set(self, device, data):
        raise NotImplementedError()

    def suppress_alarm(self, filter):
        raise NotImplementedError()

    def unsuppress_alarm(self, filter):
        raise NotImplementedError()

    @inlineCallbacks
    def _simulate_message_exchange(self, device):

        # register for receiving async messages
        self.adapter_agent.register_for_proxied_messages(device.proxy_address)

        # reset incoming message queue
        while self.incoming_messages.pending:
            _ = yield self.incoming_messages.get()

        # construct message
        msg = 'test message'

        # send message
        self.adapter_agent.send_proxied_message(device.proxy_address, msg)

        # wait till we detect incoming message
        yield self.incoming_messages.get()

        # by returning we allow the device to be shown as active, which
        # indirectly verified that message passing works

    def receive_packet_out(self, logical_device_id, egress_port_no, msg):
        log.info('packet-out',
                 logical_device_id=logical_device_id,
                 egress_port_no=egress_port_no,
                 msg_len=len(msg))

    def receive_inter_adapter_message(self, msg):
        raise NotImplementedError()
Example #8
0
class AdtranOltAdapter(object):
    name = 'adtran_olt'

    supported_device_types = [
        DeviceType(
            id=name,
            adapter=name,
            accepts_bulk_flow_update=True,
            accepts_add_remove_flow_updates=False  # TODO: Support flow-mods
        )
    ]

    def __init__(self, adapter_agent, config):
        self.adapter_agent = adapter_agent
        self.config = config
        self.descriptor = Adapter(
            id=self.name,
            vendor='Adtran Inc.',
            version='0.17',
            config=AdapterConfig(log_level=LogLevel.INFO))
        log.debug('adtran_olt.__init__', adapter_agent=adapter_agent)
        self.devices_handlers = dict()  # device_id -> AdtranOltHandler()
        self.interface = registry('main').get_args().interface
        self.logical_device_id_to_root_device_id = dict()

    def start(self):
        """
        Called once after adapter instance is loaded. Can be used to async
        initialization.

        :return: (None or Deferred)
        """
        log.info('started', interface=self.interface)

    def stop(self):
        """
        Called once before adapter is unloaded. It can be used to perform
        any cleanup after the adapter.

        :return: (None or Deferred)
        """
        log.info('stopped', interface=self.interface)

    def adapter_descriptor(self):
        """
        Return the adapter descriptor object for this adapter.

        :return: voltha.Adapter grpc object (see voltha/protos/adapter.proto),
                 with adapter-specific information and config extensions.
        """
        log.debug('get descriptor', interface=self.interface)
        return self.descriptor

    def device_types(self):
        """
        Return list of device types supported by the adapter.

        :return: voltha.DeviceTypes protobuf object, with optional type
                 specific extensions.
        """
        log.debug('get device_types',
                  interface=self.interface,
                  items=self.supported_device_types)
        return DeviceTypes(items=self.supported_device_types)

    def health(self):
        """
        Return a 3-state health status using the voltha.HealthStatus message.

        :return: Deferred or direct return with voltha.HealthStatus message
        """
        log.debug('get health', interface=self.interface)
        return HealthStatus(state=HealthStatus.HealthState.HEALTHY)

    def change_master_state(self, master):
        """
        Called to indicate if plugin shall assume or lose master role. The
        master role can be used to perform functions that must be performed
        from a single point in the cluster. In single-node deployments of
        Voltha, the plugins are always in master role.

        :param master: (bool) True to indicate the mastership needs to be
                assumed; False to indicate that mastership needs to be abandoned.
        :return: (Deferred) which is fired by the adapter when mastership is
                assumed/dropped, respectively.
        """
        log.debug('change_master_state',
                  interface=self.interface,
                  master=master)
        raise NotImplementedError()

    def adopt_device(self, device):
        """
        Make sure the adapter looks after given device. Called when a device
        is provisioned top-down and needs to be activated by the adapter.

        :param device: A voltha.Device object, with possible device-type
                specific extensions. Such extensions shall be described as part of
                the device type specification returned by device_types().
        :return: (Deferred) Shall be fired to acknowledge device ownership.
        """
        log.info('adopt-device', device=device)
        kwargs = {'adapter': self, 'device-id': device.id}
        self.devices_handlers[device.id] = AdtranOltHandler(**kwargs)
        d = defer.Deferred()
        reactor.callLater(0,
                          self.devices_handlers[device.id].activate,
                          device,
                          done_deferred=d)
        return d

    def reconcile_device(self, device):
        """
        Make sure the adapter looks after given device. Called when this device has
        changed ownership from another Voltha instance to this one (typically, this
        occurs when the previous voltha instance went down).

        :param device: A voltha.Device object, with possible device-type specific
                       extensions. Such extensions shall be described as part of
                       the device type specification returned by device_types().
        :return: (Deferred) Shall be fired to acknowledge device ownership.
        """
        log.info('reconcile-device', device=device)
        kwargs = {'adapter': self, 'device-id': device.id}
        self.devices_handlers[device.id] = AdtranOltHandler(**kwargs)
        d = defer.Deferred()
        reactor.callLater(0,
                          self.devices_handlers[device.id].activate,
                          device,
                          done_deferred=d,
                          reconciling=True)
        return d

    def abandon_device(self, device):
        """
        Make sure the adapter no longer looks after device. This is called
        if device ownership is taken over by another Voltha instance.

        :param device: A Voltha.Device object.
        :return: (Deferred) Shall be fired to acknowledge abandonment.
        """
        log.info('abandon-device', device=device)
        raise NotImplementedError()

    def disable_device(self, device):
        """
        This is called when a previously enabled device needs to be disabled
        based on a NBI call.

        :param device: A Voltha.Device object.
        :return: (Deferred) Shall be fired to acknowledge disabling the device.
        """
        log.info('disable-device', device=device)
        handler = self.devices_handlers.get(device.id)
        if handler is not None:
            reactor.callLater(0, handler.disable)
            return device

    def reenable_device(self, device):
        """
        This is called when a previously disabled device needs to be enabled
        based on a NBI call.

        :param device: A Voltha.Device object.
        :return: (Deferred) Shall be fired to acknowledge re-enabling the device.
        """
        log.info('reenable-device', device=device)
        handler = self.devices_handlers.get(device.id)
        if handler is not None:
            d = defer.Deferred()
            reactor.callLater(0, handler.reenable, done_deferred=d)
            return d

    def reboot_device(self, device):
        """
        This is called to reboot a device based on a NBI call.  The admin state of the device
        will not change after the reboot

        :param device: A Voltha.Device object.
        :return: (Deferred) Shall be fired to acknowledge the reboot.
        """
        log.info('reboot_device', device=device)
        handler = self.devices_handlers.get(device.id)
        if handler is not None:
            reactor.callLater(0, handler.reboot)
            return device

    def download_image(self, device, request):
        """
        This is called to request downloading a specified image into the standby partition
        of a device based on a NBI call.

        :param device: A Voltha.Device object.
        :param request: A Voltha.ImageDownload object.
        :return: (Deferred) Shall be fired to acknowledge the download.
        """
        log.info('image_download', device=device, request=request)
        handler = self.devices_handlers.get(device.id)
        if handler is not None:
            return handler.start_download(device, request, defer.Deferred())

    def get_image_download_status(self, device, request):
        """
        This is called to inquire about a requested image download status based
        on a NBI call. The adapter is expected to update the DownloadImage DB object
        with the query result

        :param device: A Voltha.Device object.
        :param request: A Voltha.ImageDownload object.
        :return: (Deferred) Shall be fired to acknowledge
        """
        log.info('get_image_download', device=device, request=request)
        handler = self.devices_handlers.get(device.id)
        if handler is not None:
            return handler.download_status(device, request, defer.Deferred())

    def cancel_image_download(self, device, request):
        """
        This is called to cancel a requested image download
        based on a NBI call.  The admin state of the device will not
        change after the download.
        :param device: A Voltha.Device object.
        :param request: A Voltha.ImageDownload object.
        :return: (Deferred) Shall be fired to acknowledge
        """
        log.info('cancel_image_download', device=device)
        handler = self.devices_handlers.get(device.id)
        if handler is not None:
            return handler.cancel_download(device, request, defer.Deferred())

    def activate_image_update(self, device, request):
        """
        This is called to activate a downloaded image from
        a standby partition into active partition.
        Depending on the device implementation, this call
        may or may not cause device reboot.
        If no reboot, then a reboot is required to make the
        activated image running on device
        This call is expected to be non-blocking.
        :param device: A Voltha.Device object.
        :param request: A Voltha.ImageDownload object.
        :return: (Deferred) OperationResponse object.
        """
        log.info('activate_image_update', device=device, request=request)
        handler = self.devices_handlers.get(device.id)
        if handler is not None:
            return handler.activate_image(device, request, defer.Deferred())

    def revert_image_update(self, device, request):
        """
        This is called to deactivate the specified image at
        active partition, and revert to previous image at
        standby partition.
        Depending on the device implementation, this call
        may or may not cause device reboot.
        If no reboot, then a reboot is required to make the
        previous image running on device
        This call is expected to be non-blocking.
        :param device: A Voltha.Device object.
        :param request: A Voltha.ImageDownload object.
        :return: (Deferred) OperationResponse object.
        """
        log.info('revert_image_update', device=device, request=request)
        handler = self.devices_handlers.get(device.id)
        if handler is not None:
            return handler.revert_image(device, request, defer.Deferred())

    def self_test_device(self, device):
        """
        This is called to Self a device based on a NBI call.
        :param device: A Voltha.Device object.
        :return: Will return result of self test
        """
        from voltha.protos.voltha_pb2 import SelfTestResponse
        log.info('self-test-device', device=device.id)
        # TODO: Support self test?
        return SelfTestResponse(result=SelfTestResponse.NOT_SUPPORTED)

    def delete_device(self, device):
        """
        This is called to delete a device from the PON based on a NBI call.
        If the device is an OLT then the whole PON will be deleted.

        :param device: A Voltha.Device object.
        :return: (Deferred) Shall be fired to acknowledge the deletion.
        """
        log.info('delete-device', device=device)
        handler = self.devices_handlers.get(device.id)
        if handler is not None:
            reactor.callLater(0, handler.delete)
        return device

    def get_device_details(self, device):
        """
        This is called to get additional device details based on a NBI call.

        :param device: A Voltha.Device object.
        :return: (Deferred) Shall be fired to acknowledge the retrieval of
                            additional details.
        """
        log.debug('get_device_details', device=device)
        raise NotImplementedError()

    def update_flows_bulk(self, device, flows, groups):
        """
        Called after any flow table change, but only if the device supports
        bulk mode, which is expressed by the 'accepts_bulk_flow_update'
        capability attribute of the device type.

        :param device: A Voltha.Device object.
        :param flows: An openflow_v13.Flows object
        :param groups: An  openflow_v13.Flows object
        :return: (Deferred or None)
        """
        log.debug('bulk-flow-update',
                  device_id=device.id,
                  flows=flows,
                  groups=groups,
                  num_flows=len(flows.items))
        assert len(groups.items) == 0, "Cannot yet deal with groups"

        handler = self.devices_handlers.get(device.id)
        if handler is not None:
            return handler.update_flow_table(flows.items, device)

    def update_flows_incrementally(self, device, flow_changes, group_changes):
        """
        [This mode is not supported yet.]

        :param device: A Voltha.Device object.
        :param flow_changes:
        :param group_changes:
        :return:
        """
        log.debug('update_flows_incrementally',
                  device=device,
                  flow_changes=flow_changes,
                  group_changes=group_changes)
        raise NotImplementedError()

    def update_pm_config(self, device, pm_configs):
        """
        Called every time a request is made to change pm collection behavior
        :param device: A Voltha.Device object
        :param pm_configs: A Pms
        """
        log.debug('update_pm_config', device=device, pm_configs=pm_configs)
        handler = self.devices_handlers.get(device.id)
        if handler is not None:
            handler.update_pm_config(device, pm_configs)

    def send_proxied_message(self, proxy_address, msg):
        """
        Forward a msg to a child device of device, addressed by the given
        proxy_address=Device.ProxyAddress().

        :param proxy_address: Address info for the parent device
                to route the message to the child device. This was given to the
                child device by the parent device at the creation of the child
                device.
        :param msg: (str) The actual message to send.
        :return: (Deferred(None) or None) The return of this method should
                indicate that the message was successfully *sent*.
        """
        log.debug('send-proxied-message', proxy_address=proxy_address, msg=msg)
        handler = self.devices_handlers.get(proxy_address.device_id)
        if handler is not None:
            handler.send_proxied_message(proxy_address, msg)

    def receive_proxied_message(self, proxy_address, msg):
        """
        Pass an async message (arrived via a proxy) to this device.

        :param proxy_address: Address info for the parent device
                to route the message to the child device. This was given to the
                child device by the parent device at the creation of the child
                device. Note this is the proxy_address with which the adapter
                had to register prior to receiving proxied messages.
        :param msg: (str) The actual message received.
        :return: None
        """
        log.debug('receive_proxied_message',
                  proxy_address=proxy_address,
                  msg=msg)
        raise NotImplementedError()

    def receive_packet_out(self, logical_device_id, egress_port_no, msg):
        """
        Pass a packet_out message content to adapter so that it can forward it
        out to the device. This is only called on root devices.

        :param logical_device_id:
        :param egress_port_no: egress logical port number
        :param msg: actual message
        :return: None
        """
        log.debug('packet-out',
                  logical_device_id=logical_device_id,
                  egress_port_no=egress_port_no,
                  msg_len=len(msg))

        def ldi_to_di(ldi):
            di = self.logical_device_id_to_root_device_id.get(ldi)
            if di is None:
                logical_device = self.adapter_agent.get_logical_device(ldi)
                di = logical_device.root_device_id
                self.logical_device_id_to_root_device_id[ldi] = di
            return di

        device_id = ldi_to_di(logical_device_id)
        handler = self.devices_handlers.get(device_id)
        if handler is not None:
            handler.packet_out(egress_port_no, msg)

    def receive_inter_adapter_message(self, msg):
        """
        Called when the adapter receives a message that was sent to it directly
        from another adapter. An adapter may register for these messages by calling
        the register_for_inter_adapter_messages() method in the adapter agent.
        Note that it is the responsibility of the sending and receiving
        adapters to properly encode and decode the message.
        :param msg: The message contents.
        :return: None
        """
        log.info('rx_inter_adapter_msg')
        raise NotImplementedError()

    def suppress_alarm(self, filter):
        """
        Inform an adapter that all incoming alarms should be suppressed
        :param filter: A Voltha.AlarmFilter object.
        :return: (Deferred) Shall be fired to acknowledge the suppression.
        """
        log.info('suppress_alarm', filter=filter)
        raise NotImplementedError()

    def unsuppress_alarm(self, filter):
        """
        Inform an adapter that all incoming alarms should resume
        :param filter: A Voltha.AlarmFilter object.
        :return: (Deferred) Shall be fired to acknowledge the unsuppression.
        """
        log.info('unsuppress_alarm', filter=filter)
        raise NotImplementedError()

    # PON Mgnt APIs #
    def create_interface(self, device, data):
        """
        API to create various interfaces (only some PON interfaces as of now)
        in the devices
        """
        log.debug('create-interface', data=data)
        handler = self.devices_handlers.get(device.id)
        if handler is not None:
            handler.xpon_create(data)

    def update_interface(self, device, data):
        """
        API to update various interfaces (only some PON interfaces as of now)
        in the devices
        """
        log.debug('update-interface', data=data)
        handler = self.devices_handlers.get(device.id)
        if handler is not None:
            handler.xpon_update(data)

    def remove_interface(self, device, data):
        """
        API to delete various interfaces (only some PON interfaces as of now)
        in the devices
        """
        log.debug('remove-interface', data=data)
        handler = self.devices_handlers.get(device.id)
        if handler is not None:
            handler.xpon_remove(data)

    def receive_onu_detect_state(self, proxy_address, state):
        """
        Receive onu detect state in ONU adapter
        :param proxy_address: ONU device address
        :param state: ONU detect state (bool)
        :return: None
        """
        raise NotImplementedError()

    def create_tcont(self, device, tcont_data, traffic_descriptor_data):
        """
        API to create tcont object in the devices
        :param device: device id
        :param tcont_data: tcont data object
        :param traffic_descriptor_data: traffic descriptor data object
        :return: None
        """
        log.info('create-tcont',
                 tcont_data=tcont_data,
                 traffic_descriptor_data=traffic_descriptor_data)
        handler = self.devices_handlers.get(device.id)
        if handler is not None:
            handler.create_tcont(tcont_data, traffic_descriptor_data)

    def update_tcont(self, device, tcont_data, traffic_descriptor_data):
        """
        API to update tcont object in the devices
        :param device: device id
        :param tcont_data: tcont data object
        :param traffic_descriptor_data: traffic descriptor data object
        :return: None
        """
        log.info('update-tcont',
                 tcont_data=tcont_data,
                 traffic_descriptor_data=traffic_descriptor_data)
        handler = self.devices_handlers.get(device.id)
        if handler is not None:
            handler.update_tcont(tcont_data, traffic_descriptor_data)

    def remove_tcont(self, device, tcont_data, traffic_descriptor_data):
        """
        API to delete tcont object in the devices
        :param device: device id
        :param tcont_data: tcont data object
        :param traffic_descriptor_data: traffic descriptor data object
        :return: None
        """
        log.info('remove-tcont',
                 tcont_data=tcont_data,
                 traffic_descriptor_data=traffic_descriptor_data)
        handler = self.devices_handlers.get(device.id)
        if handler is not None:
            handler.remove_tcont(tcont_data, traffic_descriptor_data)

    def create_gemport(self, device, data):
        """
        API to create gemport object in the devices
        :param device: device id
        :param data: gemport data object
        :return: None
        """
        log.debug('create-gemport', data=data)
        handler = self.devices_handlers.get(device.id)
        if handler is not None:
            handler.xpon_create(data)

    def update_gemport(self, device, data):
        """
        API to update gemport object in the devices
        :param device: device id
        :param data: gemport data object
        :return: None
        """
        log.info('update-gemport', data=data)
        handler = self.devices_handlers.get(device.id)
        if handler is not None:
            handler.xpon_update(data)

    def remove_gemport(self, device, data):
        """
        API to delete gemport object in the devices
        :param device: device id
        :data: gemport data object
        :return: None
        """
        log.info('remove-gemport', data=data)
        handler = self.devices_handlers.get(device.id)
        if handler is not None:
            handler.xpon_remove(data)

    def create_multicast_gemport(self, device, data):
        """
        API to create multicast gemport object in the devices
        :param device: device id
        :data: multicast gemport data object
        :return: None
        """
        log.info('create-mcast-gemport', data=data)
        handler = self.devices_handlers.get(device.id)
        if handler is not None:
            handler.xpon_create(data)

    def update_multicast_gemport(self, device, data):
        """
        API to update  multicast gemport object in the devices
        :param device: device id
        :data: multicast gemport data object
        :return: None
        """
        log.info('update-mcast-gemport', data=data)
        handler = self.devices_handlers.get(device.id)
        if handler is not None:
            handler.xpon_update(data)

    def remove_multicast_gemport(self, device, data):
        """
        API to delete multicast gemport object in the devices
        :param device: device id
        :data: multicast gemport data object
        :return: None
        """
        log.info('remove-mcast-gemport', data=data)
        handler = self.devices_handlers.get(device.id)
        if handler is not None:
            handler.xpon_remove(data)

    def create_multicast_distribution_set(self, device, data):
        """
        API to create multicast distribution rule to specify
        the multicast VLANs that ride on the multicast gemport
        :param device: device id
        :data: multicast distribution data object
        :return: None
        """
        log.info('create-mcast-distribution-set', data=data)
        handler = self.devices_handlers.get(device.id)
        if handler is not None:
            handler.xpon_create(data)

    def update_multicast_distribution_set(self, device, data):
        """
        API to update multicast distribution rule to specify
        the multicast VLANs that ride on the multicast gemport
        :param device: device id
        :data: multicast distribution data object
        :return: None
        """
        log.info('update-mcast-distribution-set', data=data)
        handler = self.devices_handlers.get(device.id)
        if handler is not None:
            handler.xpon_update(data)

    def remove_multicast_distribution_set(self, device, data):
        """
        API to delete multicast distribution rule to specify
        the multicast VLANs that ride on the multicast gemport
        :param device: device id
        :data: multicast distribution data object
        :return: None
        """
        log.info('remove-mcast-distribution-set', data=data)
        handler = self.devices_handlers.get(device.id)
        if handler is not None:
            handler.xpon_remove(data)
Example #9
0
class RubyAdapter(object):

    name = "microsemi_olt"

    supported_device_types = [
        DeviceType(
            id=name,
            adapter=name,
            accepts_bulk_flow_update=True
        )
    ]

    def __init__(self, adaptor_agent, config):
        self.adaptor_agent = adaptor_agent
        self.config = config
        self.olts = {}
        self.descriptor = Adapter(
            id=self.name,
            vendor='Microsemi / Celestica',
            version='0.1',
            config=AdapterConfig(log_level=LogLevel.INFO)
        )

        self.interface = registry('main').get_args().interface

    def start(self):
        log.info('starting')
        log.info('started')
        return self

    def stop(self):
        log.debug('stopping')
        for target in self.olts.keys():
            self._abandon(target)
        log.info('stopped')
        return self

    def adapter_descriptor(self):
        return self.descriptor

    def device_types(self):
        return DeviceTypes(items=self.supported_device_types)

    def health(self):
        return HealthStatus(state=HealthStatus.HealthState.HEALTHY)

    def change_master_state(self, master):
        raise NotImplementedError()

    def adopt_device(self, device):
        device_manager = DeviceManager(device, self.adaptor_agent)
        target = device.mac_address
        comm = PAS5211Communication(dst_mac=target, iface=self.interface)
        olt = OltStateMachine(iface=self.interface, comm=comm,
                              target=target, device=device_manager)
        activation = ActivationWatcher(iface=self.interface, comm=comm,
                                       target=target, device=device_manager)
        reactor.callLater(0, self._init_olt, olt, activation)

        log.info('adopted-device', device=device)
        self.olts[target] = (olt, activation)

    def abandon_device(self, device):
        self._abandon(device.mac_address)

    def deactivate_device(self, device):
        self._abandon(device.mac_address)

    def update_flows_bulk(self, device, flows, groups):
        log.debug('bulk-flow-update', device_id=device.id,
                  flows=flows, groups=groups)

    def send_proxied_message(self, proxy_address, msg):
        log.info('send-proxied-message', proxy_address=proxy_address, msg=msg)

    def receive_proxied_message(self, proxy_address, msg):
        raise NotImplementedError()

    def update_flows_incrementally(self, device, flow_changes, group_changes):
        raise NotImplementedError()

    def receive_packet_out(self, logical_device_id, egress_port_no, msg):
        log.info('packet-out', logical_device_id=logical_device_id,
                 egress_port_no=egress_port_no, msg_len=len(msg))

    ##
    # Private methods
    ##
    def _init_olt(self, olt, activation_watch):
        olt.runbg()
        activation_watch.runbg()

    def _abandon(self, target):
        olt, activation = self.olts[target]
        olt.stop()
        activation.stop()
        del self.olts[target]
Example #10
0
class OpenoltAdapter(object):
    name = 'openolt'

    supported_device_types = [
        DeviceType(id=name,
                   adapter=name,
                   accepts_bulk_flow_update=True,
                   accepts_direct_logical_flows_update=True)
    ]

    def __init__(self, adapter_agent, config):
        self.adapter_agent = adapter_agent
        self.config = config
        self.descriptor = Adapter(
            id=self.name,
            vendor='OLT white box vendor',
            version='0.1',
            config=AdapterConfig(log_level=LogLevel.INFO))
        log.debug('openolt.__init__', adapter_agent=adapter_agent)
        self.devices = dict()  # device_id -> OpenoltDevice()
        self.interface = registry('main').get_args().interface
        self.logical_device_id_to_root_device_id = dict()
        self.num_devices = 0

    def start(self):
        log.info('started', interface=self.interface)

    def stop(self):
        log.info('stopped', interface=self.interface)

    def adapter_descriptor(self):
        log.debug('get descriptor', interface=self.interface)
        return self.descriptor

    def device_types(self):
        log.debug('get device_types',
                  interface=self.interface,
                  items=self.supported_device_types)
        return DeviceTypes(items=self.supported_device_types)

    def health(self):
        log.debug('get health', interface=self.interface)
        raise NotImplementedError()

    def change_master_state(self, master):
        log.debug('change_master_state',
                  interface=self.interface,
                  master=master)
        raise NotImplementedError()

    def adopt_device(self, device):
        log.info('adopt-device', device=device)
        kwargs = {
            'adapter_agent': self.adapter_agent,
            'device': device,
            'device_num': self.num_devices + 1
        }
        try:
            self.devices[device.id] = OpenoltDevice(**kwargs)
        except Exception as e:
            log.error('Failed to adopt OpenOLT device', error=e)
            del self.devices[device.id]
            raise
        else:
            self.num_devices += 1

    def reconcile_device(self, device):
        log.info('reconcile-device', device=device)
        kwargs = {
            'adapter_agent': self.adapter_agent,
            'device': device,
            'device_num': self.num_devices + 1,
            'reconciliation': True
        }
        try:
            reconciled_device = OpenoltDevice(**kwargs)
            log.debug('reconciled-device-recreated',
                      device_id=reconciled_device.device_id)
            self.devices[device.id] = reconciled_device
        except Exception as e:
            log.error('Failed to reconcile OpenOLT device',
                      error=e,
                      exception_type=type(e).__name__)
            del self.devices[device.id]
            raise
        else:
            self.num_devices += 1
            # Invoke the children reconciliation which would setup the
            # basic children data structures
            self.adapter_agent.reconcile_child_devices(device.id)
            return device

    def abandon_device(self, device):
        log.info('abandon-device', device=device)
        raise NotImplementedError()

    def disable_device(self, device):
        log.info('disable-device', device=device)
        handler = self.devices[device.id]
        handler.disable()

    def reenable_device(self, device):
        log.info('reenable-device', device=device)
        handler = self.devices[device.id]
        handler.reenable()

    def reboot_device(self, device):
        log.info('reboot_device', device=device)
        handler = self.devices[device.id]
        handler.reboot()

    def download_image(self, device, request):
        log.info('image_download - Not implemented yet',
                 device=device,
                 request=request)
        raise NotImplementedError()

    def get_image_download_status(self, device, request):
        log.info('get_image_download - Not implemented yet',
                 device=device,
                 request=request)
        raise NotImplementedError()

    def cancel_image_download(self, device, request):
        log.info('cancel_image_download - Not implemented yet', device=device)
        raise NotImplementedError()

    def activate_image_update(self, device, request):
        log.info('activate_image_update - Not implemented yet',
                 device=device,
                 request=request)
        raise NotImplementedError()

    def revert_image_update(self, device, request):
        log.info('revert_image_update - Not implemented yet',
                 device=device,
                 request=request)
        raise NotImplementedError()

    def self_test_device(self, device):
        # from voltha.protos.voltha_pb2 import SelfTestResponse
        log.info('Not implemented yet')
        raise NotImplementedError()

    def delete_device(self, device):
        log.info('delete-device', device=device)
        handler = self.devices[device.id]
        handler.delete()
        del self.devices[device.id]
        del self.logical_device_id_to_root_device_id[device.parent_id]
        return device

    def get_device_details(self, device):
        log.debug('get_device_details', device=device)
        raise NotImplementedError()

    def update_flows_bulk(self, device, flows, groups):
        log.info('bulk-flow-update',
                 device_id=device.id,
                 number_of_flows=len(flows.items),
                 number_of_groups=len(groups.items))
        log.debug('flows and grousp details', flows=flows, groups=groups)
        assert len(groups.items) == 0, "Cannot yet deal with groups"
        handler = self.devices[device.id]
        return handler.update_flow_table(flows.items)

    def update_flows_incrementally(self, device, flow_changes, group_changes):
        log.debug('update_flows_incrementally',
                  device=device,
                  flow_changes=flow_changes,
                  group_changes=group_changes)
        log.info('This device does not allow this, therefore it is Not '
                 'implemented')
        raise NotImplementedError()

    def update_logical_flows(self, device_id, flows_to_add, flows_to_remove,
                             groups, device_rules_map):

        log.info('logical-flows-update',
                 flows_to_add=len(flows_to_add),
                 flows_to_remove=len(flows_to_remove))
        log.debug('logical-flows-details',
                  flows_to_add=flows_to_add,
                  flows_to_remove=flows_to_remove)
        assert len(groups) == 0, "Cannot yet deal with groups"
        handler = self.devices[device_id]
        handler.update_logical_flows(flows_to_add, flows_to_remove,
                                     device_rules_map)

    def update_pm_config(self, device, pm_configs):
        log.info('update_pm_config - Not implemented yet',
                 device=device,
                 pm_configs=pm_configs)
        raise NotImplementedError()

    def send_proxied_message(self, proxy_address, msg):
        log.debug('send-proxied-message', proxy_address=proxy_address, msg=msg)
        handler = self.devices[proxy_address.device_id]
        handler.send_proxied_message(proxy_address, msg)

    def receive_proxied_message(self, proxy_address, msg):
        log.debug('receive_proxied_message - Not implemented',
                  proxy_address=proxy_address,
                  msg=msg)
        raise NotImplementedError()

    def receive_packet_out(self, logical_device_id, egress_port_no, msg):
        log.debug('packet-out',
                  logical_device_id=logical_device_id,
                  egress_port_no=egress_port_no,
                  msg_len=len(msg))

        def ldi_to_di(ldi):
            di = self.logical_device_id_to_root_device_id.get(ldi)
            if di is None:
                logical_device = self.adapter_agent.get_logical_device(ldi)
                di = logical_device.root_device_id
                self.logical_device_id_to_root_device_id[ldi] = di
            return di

        try:
            device_id = ldi_to_di(logical_device_id)
            handler = self.devices[device_id]
            handler.packet_out(egress_port_no, msg)
        except Exception as e:
            log.error('packet-out:exception', e=e.message)

    def receive_inter_adapter_message(self, msg):
        log.info('rx_inter_adapter_msg - Not implemented')
        raise NotImplementedError()

    def suppress_alarm(self, filter):
        log.info('suppress_alarm - Not implemented yet', filter=filter)
        raise NotImplementedError()

    def unsuppress_alarm(self, filter):
        log.info('unsuppress_alarm - Not implemented yet', filter=filter)
        raise NotImplementedError()

    # PON Mgnt APIs #
    def create_interface(self, device, data):
        log.debug('create-interface - Not implemented - We do not use this',
                  data=data)
        raise NotImplementedError()

    def update_interface(self, device, data):
        log.debug('update-interface - Not implemented - We do not use this',
                  data=data)
        raise NotImplementedError()

    def remove_interface(self, device, data):
        log.debug('remove-interface - Not implemented - We do not use this',
                  data=data)
        raise NotImplementedError()

    def receive_onu_detect_state(self, proxy_address, state):
        log.debug(
            'receive-onu-detect-state - Not implemented - We do not '
            'use this',
            proxy_address=proxy_address,
            state=state)
        raise NotImplementedError()

    def create_tcont(self, device, tcont_data, traffic_descriptor_data):
        log.info('create-tcont - Not implemented - We do not use this',
                 tcont_data=tcont_data,
                 traffic_descriptor_data=traffic_descriptor_data)
        raise NotImplementedError()

    def update_tcont(self, device, tcont_data, traffic_descriptor_data):
        log.info('update-tcont - Not implemented - We do not use this',
                 tcont_data=tcont_data,
                 traffic_descriptor_data=traffic_descriptor_data)
        raise NotImplementedError()

    def remove_tcont(self, device, tcont_data, traffic_descriptor_data):
        log.info('remove-tcont - Not implemented - We do not use this',
                 tcont_data=tcont_data,
                 traffic_descriptor_data=traffic_descriptor_data)
        raise NotImplementedError()

    def create_gemport(self, device, data):
        log.info('create-gemport - Not implemented - We do not use this',
                 data=data)
        raise NotImplementedError()

    def update_gemport(self, device, data):
        log.info('update-gemport - Not implemented - We do not use this',
                 data=data)
        raise NotImplementedError()

    def remove_gemport(self, device, data):
        log.info('remove-gemport - Not implemented - We do not use this',
                 data=data)
        raise NotImplementedError()

    def create_multicast_gemport(self, device, data):
        log.info(
            'create-mcast-gemport  - Not implemented - We do not use '
            'this',
            data=data)
        raise NotImplementedError()

    def update_multicast_gemport(self, device, data):
        log.info(
            'update-mcast-gemport - Not implemented - We do not use '
            'this',
            data=data)
        raise NotImplementedError()

    def remove_multicast_gemport(self, device, data):
        log.info(
            'remove-mcast-gemport - Not implemented - We do not use '
            'this',
            data=data)
        raise NotImplementedError()

    def create_multicast_distribution_set(self, device, data):
        log.info(
            'create-mcast-distribution-set - Not implemented - We do '
            'not use this',
            data=data)
        raise NotImplementedError()

    def update_multicast_distribution_set(self, device, data):
        log.info(
            'update-mcast-distribution-set - Not implemented - We do '
            'not use this',
            data=data)
        raise NotImplementedError()

    def remove_multicast_distribution_set(self, device, data):
        log.info(
            'remove-mcast-distribution-set - Not implemented - We do '
            'not use this',
            data=data)
        raise NotImplementedError()

    def delete_child_device(self, parent_device_id, child_device):
        log.info('delete-child_device',
                 parent_device_id=parent_device_id,
                 child_device=child_device)
        handler = self.devices[parent_device_id]
        if handler is not None:
            handler.delete_child_device(child_device)
        else:
            log.error('Could not find matching handler',
                      looking_for_device_id=parent_device_id,
                      available_handlers=self.devices.keys())

    # This is currently not part of the Iadapter interface
    def collect_stats(self, device_id):
        log.info('collect_stats', device_id=device_id)
        handler = self.devices[device_id]
        if handler is not None:
            handler.trigger_statistics_collection()
        else:
            log.error('Could not find matching handler',
                      looking_for_device_id=device_id,
                      available_handlers=self.devices.keys())

    def simulate_alarm(self, device, request):
        log.info('simulate_alarm', device=device, request=request)

        if device.id not in self.devices:
            log.error("Device does not exist", device_id=device.id)
            return OperationResp(code=OperationResp.OPERATION_FAILURE,
                                 additional_info="Device %s does not exist" %
                                 device.id)

        handler = self.devices[device.id]

        handler.simulate_alarm(request)

        return OperationResp(code=OperationResp.OPERATION_SUCCESS)
Example #11
0
class TibitOnuAdapter(object):

    name = 'tibit_onu'

    supported_device_types = [
        DeviceType(id='tibit_onu', adapter=name, accepts_bulk_flow_update=True)
    ]

    def __init__(self, adapter_agent, config):
        self.adapter_agent = adapter_agent
        self.config = config
        self.descriptor = Adapter(
            id=self.name,
            vendor='Tibit Communications Inc.',
            version='0.1',
            config=AdapterConfig(log_level=LogLevel.INFO))
        self.incoming_messages = DeferredQueue()

    def start(self):
        log.debug('starting')
        log.info('started')

    def stop(self):
        log.debug('stopping')
        log.info('stopped')

    def adapter_descriptor(self):
        return self.descriptor

    def device_types(self):
        return DeviceTypes(items=self.supported_device_types)

    def health(self):
        return HealthStatus(state=HealthStatus.HealthState.HEALTHY)

    def change_master_state(self, master):
        raise NotImplementedError()

    def adopt_device(self, device):
        log.info('adopt-device', device=device)
        reactor.callLater(0.1, self._onu_device_activation, device)
        return device

    @inlineCallbacks
    def _onu_device_activation(self, device):
        # first we verify that we got parent reference and proxy info
        assert device.parent_id
        assert device.proxy_address.device_id
        assert device.proxy_address.channel_id

        # TODO: For now, pretend that we were able to contact the device and obtain
        # additional information about it.  Should add real message.
        device.vendor = 'Tibit Communications, Inc.'
        device.model = '10G GPON ONU'
        device.hardware_version = 'fa161020'
        device.firmware_version = '16.12.02'
        device.software_version = '1.0'
        device.serial_number = uuid4().hex
        device.connect_status = ConnectStatus.REACHABLE
        self.adapter_agent.update_device(device)

        # then shortly after we create some ports for the device
        uni_port = Port(port_no=2,
                        label='UNI facing Ethernet port',
                        type=Port.ETHERNET_UNI,
                        admin_state=AdminState.ENABLED,
                        oper_status=OperStatus.ACTIVE)
        self.adapter_agent.add_port(device.id, uni_port)
        self.adapter_agent.add_port(
            device.id,
            Port(port_no=1,
                 label='PON port',
                 type=Port.PON_ONU,
                 admin_state=AdminState.ENABLED,
                 oper_status=OperStatus.ACTIVE,
                 peers=[
                     Port.PeerPort(device_id=device.parent_id,
                                   port_no=device.parent_port_no)
                 ]))

        # TODO adding vports to the logical device shall be done by agent?
        # then we create the logical device port that corresponds to the UNI
        # port of the device

        # obtain logical device id
        parent_device = self.adapter_agent.get_device(device.parent_id)
        logical_device_id = parent_device.parent_id
        assert logical_device_id

        # we are going to use the proxy_address.channel_id as unique number
        # and name for the virtual ports, as this is guaranteed to be unique
        # in the context of the OLT port, so it is also unique in the context
        # of the logical device
        port_no = device.proxy_address.channel_id
        cap = OFPPF_10GB_FD | OFPPF_FIBER
        self.adapter_agent.add_logical_port(
            logical_device_id,
            LogicalPort(id=str(port_no),
                        ofp_port=ofp_port(port_no=port_no,
                                          hw_addr=mac_str_to_tuple(
                                              device.mac_address),
                                          name='uni-{}'.format(port_no),
                                          config=0,
                                          state=OFPPS_LIVE,
                                          curr=cap,
                                          advertised=cap,
                                          peer=cap,
                                          curr_speed=OFPPF_10GB_FD,
                                          max_speed=OFPPF_10GB_FD),
                        device_id=device.id,
                        device_port_no=uni_port.port_no))

        # simulate a proxied message sending and receving a reply
        reply = yield self._message_exchange(device)

        # and finally update to "ACTIVE"
        device = self.adapter_agent.get_device(device.id)
        device.oper_status = OperStatus.ACTIVE
        self.adapter_agent.update_device(device)

        self.start_kpi_collection(device.id)

    def abandon_device(self, device):
        raise NotImplementedError(0)

    def deactivate_device(self, device):
        raise NotImplementedError()

    def update_flows_bulk(self, device, flows, groups):
        log.info('########################################')
        log.info('bulk-flow-update',
                 device_id=device.id,
                 flows=flows,
                 groups=groups)
        assert len(groups.items) == 0, "Cannot yet deal with groups"

        Clause = {v: k for k, v in ClauseSubtypeEnum.iteritems()}
        Operator = {v: k for k, v in RuleOperatorEnum.iteritems()}

        for flow in flows.items:
            in_port = get_in_port(flow)
            assert in_port is not None

            precedence = 255 - min(flow.priority / 256, 255)

            if in_port == 2:
                log.info('#### Upstream Rule ####')
                dn_req = EOAMPayload(body=CablelabsOUI() /
                                     DPoEOpcode_SetRequest())

                for field in get_ofb_fields(flow):

                    if field.type == ETH_TYPE:
                        _type = field.eth_type
                        log.info('#### field.type == ETH_TYPE ####',
                                 field_type=_type)

                    elif field.type == IP_PROTO:
                        _proto = field.ip_proto
                        log.info('#### field.type == IP_PROTO ####')

                    elif field.type == IN_PORT:
                        _port = field.port
                        log.info('#### field.type == IN_PORT ####', port=_port)

                    elif field.type == VLAN_VID:
                        _vlan_vid = field.vlan_vid & 0xfff
                        log.info('#### field.type == VLAN_VID ####',
                                 vlan=_vlan_vid)

                    elif field.type == VLAN_PCP:
                        _vlan_pcp = field.vlan_pcp
                        log.info('#### field.type == VLAN_PCP ####',
                                 pcp=_vlan_pcp)

                    elif field.type == UDP_DST:
                        _udp_dst = field.udp_dst
                        log.info('#### field.type == UDP_DST ####')

                    elif field.type == IPV4_DST:
                        _ipv4_dst = field.ipv4_dst
                        log.info('#### field.type == IPV4_DST ####')

                    else:
                        log.info('#### field.type == NOT IMPLEMENTED!! ####')
                        raise NotImplementedError('field.type={}'.format(
                            field.type))

                for action in get_actions(flow):

                    if action.type == OUTPUT:
                        log.info('#### action.type == OUTPUT ####')

                    elif action.type == POP_VLAN:
                        log.info('#### action.type == POP_VLAN ####')

                    elif action.type == PUSH_VLAN:
                        log.info('#### action.type == PUSH_VLAN ####')
                        if action.push.ethertype != 0x8100:
                            log.error('unhandled-tpid',
                                      ethertype=action.push.ethertype)

                    elif action.type == SET_FIELD:
                        log.info('#### action.type == SET_FIELD ####')
                        assert (action.set_field.field.oxm_class ==
                                ofp.OFPXMC_OPENFLOW_BASIC)
                        field = action.set_field.field.ofb_field
                        if field.type == VLAN_VID:
                            pass
                        else:
                            log.error('unsupported-action-set-field-type',
                                      field_type=field.type)
                    else:
                        log.error('UNSUPPORTED-ACTION-TYPE',
                                  action_type=action.type)

            elif in_port == 1:
                log.info('#### Downstream Rule ####')

                #### Loop through fields again...

                for field in get_ofb_fields(flow):

                    if field.type == ETH_TYPE:
                        _type = field.eth_type
                        log.info('#### field.type == ETH_TYPE ####',
                                 in_port=in_port,
                                 match=_type)

                    elif field.type == IP_PROTO:
                        _proto = field.ip_proto
                        log.info('#### field.type == IP_PROTO ####',
                                 in_port=in_port,
                                 ip_proto=ip_proto)

                    elif field.type == IN_PORT:
                        _port = field.port
                        log.info('#### field.type == IN_PORT ####')

                    elif field.type == VLAN_VID:
                        _vlan_vid = field.vlan_vid & 0xfff
                        log.info('#### field.type == VLAN_VID ####')

                    elif field.type == VLAN_PCP:
                        _vlan_pcp = field.vlan_pcp
                        log.info('#### field.type == VLAN_PCP ####')

                    elif field.type == UDP_DST:
                        _udp_dst = field.udp_dst
                        log.info('#### field.type == UDP_DST ####')

                    elif field.type == IPV4_DST:
                        _ipv4_dst = field.ipv4_dst
                        log.info('#### field.type == IPV4_DST ####')
                        a = int(hex(_ipv4_dst)[2:4], 16)
                        b = int(hex(_ipv4_dst)[4:6], 16)
                        c = int(hex(_ipv4_dst)[6:8], 16)
                        d = int(hex(_ipv4_dst)[8:], 16)
                        dn_req = EOAMPayload(
                            body=CablelabsOUI() / DPoEOpcode_SetRequest() /
                            AddStaticMacAddress(
                                mac=mcastIp2McastMac('%d.%d.%d.%d' %
                                                     (a, b, c, d))))
                        # send message
                        log.info('ONU-send-proxied-message')
                        self.adapter_agent.send_proxied_message(
                            device.proxy_address, dn_req)

                    else:
                        raise NotImplementedError('field.type={}'.format(
                            field.type))

                for action in get_actions(flow):

                    if action.type == OUTPUT:
                        log.info('#### action.type == OUTPUT ####')

                    elif action.type == POP_VLAN:
                        log.info('#### action.type == POP_VLAN ####')

                    elif action.type == PUSH_VLAN:
                        log.info('#### action.type == PUSH_VLAN ####')
                        if action.push.ethertype != 0x8100:
                            log.error('unhandled-ether-type',
                                      ethertype=action.push.ethertype)

                    elif action.type == SET_FIELD:
                        log.info('#### action.type == SET_FIELD ####')
                        assert (action.set_field.field.oxm_class ==
                                ofp.OFPXMC_OPENFLOW_BASIC)
                        field = action.set_field.field.ofb_field
                        if field.type == VLAN_VID:
                            pass
                        else:
                            log.error('unsupported-action-set-field-type',
                                      field_type=field.type)

                    else:
                        log.error('UNSUPPORTED-ACTION-TYPE',
                                  action_type=action.type)

            else:
                raise Exception('Port should be 1 or 2 by our convention')

    def update_flows_incrementally(self, device, flow_changes, group_changes):
        raise NotImplementedError()

    def send_proxied_message(self, proxy_address, msg):
        raise NotImplementedError()

    def receive_proxied_message(self, proxy_address, msg):
        log.info('receive-proxied-message',
                 proxy_address=proxy_address,
                 msg=msg.show(dump=True))
        self.incoming_messages.put(msg)

    @inlineCallbacks
    def _message_exchange(self, device):

        # register for receiving async messages
        self.adapter_agent.register_for_proxied_messages(device.proxy_address)

        # reset incoming message queue
        while self.incoming_messages.pending:
            _ = yield self.incoming_messages.get()

        # construct message
        msg = EOAMPayload(body=CablelabsOUI() / DPoEOpcode_GetRequest() /
                          DeviceId())

        # send message
        log.info('ONU-send-proxied-message')
        self.adapter_agent.send_proxied_message(device.proxy_address, msg)

        # wait till we detect incoming message
        yield self.incoming_messages.get()

        # construct install of igmp query address
        msg = EOAMPayload(body=CablelabsOUI() / DPoEOpcode_SetRequest() /
                          AddStaticMacAddress(mac='01:00:5e:00:00:01'))

        # send message
        log.info('ONU-send-proxied-message')
        self.adapter_agent.send_proxied_message(device.proxy_address, msg)

        # wait till we detect incoming message
        yield self.incoming_messages.get()

        # by returning we allow the device to be shown as active, which
        # indirectly verified that message passing works

    def receive_packet_out(self, logical_device_id, egress_port_no, msg):
        log.info('packet-out',
                 logical_device_id=logical_device_id,
                 egress_port_no=egress_port_no,
                 msg_len=len(msg))

    def start_kpi_collection(self, device_id):
        """TMP Simulate periodic KPI metric collection from the device"""
        import random

        @inlineCallbacks  # pretend that we need to do async calls
        def _collect(device_id, prefix):

            try:
                # Step 1: gather metrics from device (pretend it here) - examples
                uni_port_metrics = yield dict(
                    tx_pkts=random.randint(0, 100),
                    rx_pkts=random.randint(0, 100),
                    tx_bytes=random.randint(0, 100000),
                    rx_bytes=random.randint(0, 100000),
                )
                pon_port_metrics = yield dict(
                    tx_pkts=uni_port_metrics['rx_pkts'],
                    rx_pkts=uni_port_metrics['tx_pkts'],
                    tx_bytes=uni_port_metrics['rx_bytes'],
                    rx_bytes=uni_port_metrics['tx_bytes'],
                )
                onu_metrics = yield dict(cpu_util=20 + 5 * random.random(),
                                         buffer_util=10 + 10 * random.random())

                # Step 2: prepare the KpiEvent for submission
                # we can time-stamp them here (or could use time derived from OLT
                ts = arrow.utcnow().timestamp
                kpi_event = KpiEvent(
                    type=KpiEventType.slice,
                    ts=ts,
                    prefixes={
                        # OLT-level
                        prefix:
                        MetricValuePairs(metrics=onu_metrics),
                        # OLT NNI port
                        prefix + '.nni':
                        MetricValuePairs(metrics=uni_port_metrics),
                        # OLT PON port
                        prefix + '.pon':
                        MetricValuePairs(metrics=pon_port_metrics)
                    })

                # Step 3: submit
                self.adapter_agent.submit_kpis(kpi_event)

            except Exception as e:
                log.exception('failed-to-submit-kpis', e=e)

        prefix = 'voltha.{}.{}'.format(self.name, device_id)
        lc = LoopingCall(_collect, device_id, prefix)
        lc.start(interval=15)  # TODO make this configurable
Example #12
0
class AdtranOltAdapter(object):
    name = 'adtran_olt'

    supported_device_types = [
        DeviceType(
            id=name,
            adapter=name,
            accepts_bulk_flow_update=True
        )
    ]

    def __init__(self, adapter_agent, config):
        self.adapter_agent = adapter_agent
        self.config = config
        self.descriptor = Adapter(
            id=self.name,
            vendor='Adtran Inc.',
            version='0.1',
            config=AdapterConfig(log_level=LogLevel.INFO)
        )
        log.debug('adtran_olt.__init__', adapter_agent=adapter_agent)
        self.devices_handlers = dict()  # device_id -> AdtranOltHandler()
        self.interface = registry('main').get_args().interface
        # self.logical_device_id_to_root_device_id = dict()

    def start(self):
        """
        Called once after adapter instance is loaded. Can be used to async
        initialization.

        :return: (None or Deferred)
        """
        log.debug('starting', interface=self.interface)
        log.info('started', interface=self.interface)

    def stop(self):
        """
        Called once before adapter is unloaded. It can be used to perform
        any cleanup after the adapter.

        :return: (None or Deferred)
        """
        log.debug('stopping', interface=self.interface)
        log.info('stopped', interface=self.interface)

    def adapter_descriptor(self):
        """
        Return the adapter descriptor object for this adapter.

        :return: voltha.Adapter grpc object (see voltha/protos/adapter.proto),
                 with adapter-specific information and config extensions.
        """
        log.debug('get descriptor', interface=self.interface)
        return self.descriptor

    def device_types(self):
        """
        Return list of device types supported by the adapter.

        :return: voltha.DeviceTypes protobuf object, with optional type
                 specific extensions.
        """
        log.debug('get device_types', interface=self.interface, items=self.supported_device_types)
        return DeviceTypes(items=self.supported_device_types)

    def health(self):
        """
        Return a 3-state health status using the voltha.HealthStatus message.

        :return: Deferred or direct return with voltha.HealthStatus message
        """
        log.debug('get health', interface=self.interface)
        return HealthStatus(state=HealthStatus.HealthState.HEALTHY)

    def change_master_state(self, master):
        """
        Called to indicate if plugin shall assume or lose master role. The
        master role can be used to perform functions that must be performed
        from a single point in the cluster. In single-node deployments of
        Voltha, the plugins are always in master role.

        :param master: (bool) True to indicate the mastership needs to be
                assumed; False to indicate that mastership needs to be abandoned.
        :return: (Deferred) which is fired by the adapter when mastership is
                assumed/dropped, respectively.
        """
        log.debug('change_master_state', interface=self.interface, master=master)
        raise NotImplementedError()

    def adopt_device(self, device):
        """
        Make sure the adapter looks after given device. Called when a device
        is provisioned top-down and needs to be activated by the adapter.

        :param device: A voltha.Device object, with possible device-type
                specific extensions. Such extensions shall be described as part of
                the device type specification returned by device_types().
        :return: (Deferred) Shall be fired to acknowledge device ownership.
        """
        log.info('adopt-device', device=device)
        self.devices_handlers[device.id] = AdtranOltHandler(self, device.id)
        reactor.callLater(0, self.devices_handlers[device.id].activate, device)
        return device

    def abandon_device(self, device):
        """
        Make sure the adapter no longer looks after device. This is called
        if device ownership is taken over by another Voltha instance.

        :param device: A Voltha.Device object.
        :return: (Deferred) Shall be fired to acknowledge abandonment.
        """
        log.info('abandon-device', device=device)
        handler = self.devices_handlers.pop(device.id)

        if handler is not None:
            reactor.callLater(0, handler.deactivate, device)

        return device

    def disable_device(self, device):
        """
        This is called when a previously enabled device needs to be disabled
        based on a NBI call.

        :param device: A Voltha.Device object.
        :return: (Deferred) Shall be fired to acknowledge disabling the device.
        """
        log.debug('disable_device', device=device)
        raise NotImplementedError()

    def reenable_device(self, device):
        """
        This is called when a previously disabled device needs to be enabled
        based on a NBI call.

        :param device: A Voltha.Device object.
        :return: (Deferred) Shall be fired to acknowledge re-enabling the device.
        """
        log.debug('reenable_device', device=device)
        raise NotImplementedError()

    def reboot_device(self, device):
        """
        This is called to reboot a device based on a NBI call.  The admin
        state of the device will not change after the reboot

        :param device: A Voltha.Device object.
        :return: (Deferred) Shall be fired to acknowledge the reboot.
        """
        log.info('reboot_device', device=device)
        raise NotImplementedError()

    def delete_device(self, device):
        """
        This is called to delete a device from the PON based on a NBI call.
        If the device is an OLT then the whole PON will be deleted.

        :param device: A Voltha.Device object.
        :return: (Deferred) Shall be fired to acknowledge the deletion.
        """
        log.info('delete_device', device=device)
        raise NotImplementedError()

    def get_device_details(self, device):
        """
        This is called to get additional device details based on a NBI call.

        :param device: A Voltha.Device object.
        :return: (Deferred) Shall be fired to acknowledge the retrieval of
                            additional details.
        """
        log.debug('get_device_details', device=device)
        raise NotImplementedError()

    def update_flows_bulk(self, device, flows, groups):
        """
        Called after any flow table change, but only if the device supports
        bulk mode, which is expressed by the 'accepts_bulk_flow_update'
        capability attribute of the device type.

        :param device: A Voltha.Device object.
        :param flows: An openflow_v13.Flows object
        :param groups: An  openflow_v13.Flows object
        :return: (Deferred or None)
        """
        log.info('bulk-flow-update', device_id=device.id, flows=flows,
                 groups=groups)
        assert len(groups.items) == 0, "Cannot yet deal with groups"
        raise NotImplementedError()
        handler = self.devices_handlers[device.id]
        return handler.update_flow_table(flows.items, device)

    def update_flows_incrementally(self, device, flow_changes, group_changes):
        """
        [This mode is not supported yet.]

        :param device: A Voltha.Device object.
        :param flow_changes:
        :param group_changes:
        :return:
        """
        log.debug('update_flows_incrementally', device=device, flow_changes=flow_changes,
                  group_changes=group_changes)
        raise NotImplementedError()

    def update_pm_config(self, device, pm_configs):
        """
        Called every time a request is made to change pm collection behavior
        :param device: A Voltha.Device object
        :param pm_configs: A Pms
        """
        log.debug('update_pm_config', device=device, pm_configs=pm_configs)
        raise NotImplementedError()

    def send_proxied_message(self, proxy_address, msg):
        """
        Forward a msg to a child device of device, addressed by the given
        proxy_address=Device.ProxyAddress().

        :param proxy_address: Address info for the parent device
                to route the message to the child device. This was given to the
                child device by the parent device at the creation of the child
                device.
        :param msg: (str) The actual message to send.
        :return: (Deferred(None) or None) The return of this method should
                indicate that the message was successfully *sent*.
        """
        log.info('send-proxied-message', proxy_address=proxy_address, msg=msg)
        handler = self.devices_handlers[proxy_address.device_id]
        handler.send_proxied_message(proxy_address, msg)

    def receive_proxied_message(self, proxy_address, msg):
        """
        Pass an async message (arrived via a proxy) to this device.

        :param proxy_address: Address info for the parent device
                to route the message to the child device. This was given to the
                child device by the parent device at the creation of the child
                device. Note this is the proxy_address with which the adapter
                had to register prior to receiving proxied messages.
        :param msg: (str) The actual message received.
        :return: None
        """
        log.debug('receive_proxied_message', proxy_address=proxy_address, msg=msg)
        raise NotImplementedError()

    def receive_packet_out(self, logical_device_id, egress_port_no, msg):
        """
        Pass a packet_out message content to adapter so that it can forward it
        out to the device. This is only called on root devices.

        :param logical_device_id:
        :param egress_port_no: egress logical port number
        :param msg: actual message
        :return: None
        """
        log.info('packet-out', logical_device_id=logical_device_id,
                 egress_port_no=egress_port_no, msg_len=len(msg))
        raise NotImplementedError()

    def receive_inter_adapter_message(self, msg):
        """
        Called when the adapter recieves a message that was sent to it directly
        from another adapter. An adapter may register for these messages by calling
        the register_for_inter_adapter_messages() method in the adapter agent.
        Note that it is the responsibility of the sending and receiving
        adapters to properly encode and decode the message.
        :param msg: The message contents.
        :return: None
        """
        log.info('rx_inter_adapter_msg')
        raise NotImplementedError()

    def suppress_alarm(self, filter):
        log.info('suppress_alarm', filter=filter)
        raise NotImplementedError()

    def unsuppress_alarm(self, filter):
        log.info('unsuppress_alarm', filter=filter)
        raise NotImplementedError()
Example #13
0
class CigOpenomciOnuAdapter(BrcmOpenomciOnuAdapter):

    name = 'cig_openomci_onu'

    supported_device_types = [
        DeviceType(
            id=name,
            #vendor_ids=[],
            vendor_ids=['CIGG'],
            adapter=name,
            accepts_bulk_flow_update=True)
    ]

    def __init__(self, adapter_agent, config):
        super(CigOpenomciOnuAdapter, self).__init__(adapter_agent, config)
        # self.adapter_agent = adapter_agent
        # self.config = config
        self.descriptor = Adapter(
            id=self.name,
            vendor='CIG Tech',
            version='0.10',
            config=AdapterConfig(log_level=LogLevel.INFO))
        # self.devices_handlers = dict()

        # Customize OpenOMCI for CIG ONUs
        self._omci_support_cls = deepcopy(OpenOmciAgentDefaults)

        # self.broadcom_omci['mib-synchronizer']['state-machine'] = BrcmMibSynchronizer
        # self.broadcom_omci['mib-synchronizer']['database'] = MibDbVolatileDict
        # self.broadcom_omci['omci-capabilities']['tasks']['get-capabilities'] = BrcmCapabilitiesTask

        # self._omci_agent = OpenOMCIAgent(self.adapter_agent.core,
        #                                  support_classes=self.broadcom_omci)

        self._omci_agent = OpenOMCIAgent(
            self.adapter_agent.core, support_classes=self._omci_support_cls)
        # register for adapter messages
        # self.adapter_agent.register_for_inter_adapter_messages()

    def device_types(self):
        return DeviceTypes(items=self.supported_device_types)

    def adapter_descriptor(self):
        return self.descriptor

    def device_types(self):
        return DeviceTypes(items=self.supported_device_types)

    def __download_image_success(self, image_download):
        log.debug("__download_image_success")

    def __download_image_fail(self, fail):
        log.debug("__download_image_fail", failure=fail)

    # TODO: Add callback to the defer to indicate download status
    def download_image(self, device, request):
        log.debug('download_image', device=device, request=request)
        onu_dev = self._omci_agent.get_device(device.id)
        d = onu_dev.do_onu_software_download(request)
        d.addCallbacks(self.__download_image_success,
                       self.__download_image_fail)
        # return d

    def get_image_download_status(self, device, request):
        log.debug('get_image_download_status', device=device, request=request)
        onu_dev = self._omci_agent.get_device(device.id)
        return onu_dev.get_image_download_status(
            request.name) if onu_dev else None

    def cancel_image_download(self, device, request):
        log.debug('cancel_image_download', device=device, request=request)
        onu_dev = self._omci_agent.get_device(device.id)
        onu_dev.cancel_onu_software_download(request.name)

    def activate_image_update(self, device, request):
        log.debug('activate_image_update', device=device, request=request)
        onu_dev = self._omci_agent.get_device(device.id)
        d = onu_dev.do_onu_image_activate(request.name)

    def revert_image_update(self, device, request):
        log.debug('revert_image_update', device=device, request=request)
Example #14
0
class SimulatedOltAdapter(object):

    name = 'simulated_olt'

    supported_device_types = [
        DeviceType(id='simulated_olt',
                   adapter=name,
                   accepts_bulk_flow_update=True)
    ]

    app = Klein()

    def __init__(self, adapter_agent, config):
        self.adapter_agent = adapter_agent
        self.config = config
        self.descriptor = Adapter(
            id=self.name,
            vendor='Voltha project',
            version='0.1',
            config=AdapterConfig(log_level=LogLevel.INFO))
        self.control_endpoint = None

    def start(self):
        log.debug('starting')

        # setup a basic web server for test control
        self.control_endpoint = endpoints.TCP4ServerEndpoint(reactor, 18880)
        self.control_endpoint.listen(self.get_test_control_site())

        # TODO tmp: populate some devices and logical devices
        # reactor.callLater(0, self._tmp_populate_stuff)
        log.info('started')

    def stop(self):
        log.debug('stopping')
        log.info('stopped')

    def adapter_descriptor(self):
        return self.descriptor

    def device_types(self):
        return DeviceTypes(items=self.supported_device_types)

    def health(self):
        return HealthStatus(state=HealthStatus.HealthState.HEALTHY)

    def change_master_state(self, master):
        raise NotImplementedError()

    def adopt_device(self, device):
        # We kick of a simulated activation scenario
        reactor.callLater(0.2, self._simulate_device_activation, device)
        return device

    def abandon_device(self, device):
        raise NotImplementedError()

    def deactivate_device(self, device):
        raise NotImplementedError()

    def _tmp_populate_stuff(self):
        """
        pretend that we discovered some devices and create:
        - devices
        - device ports for each
        - logical device
        - logical device ports
        """

        olt = Device(id='simulated_olt_1',
                     type='simulated_olt',
                     root=True,
                     vendor='simulated',
                     model='n/a',
                     hardware_version='n/a',
                     firmware_version='n/a',
                     software_version='1.0',
                     serial_number=uuid4().hex,
                     adapter=self.name,
                     oper_status=OperStatus.DISCOVERED)
        self.adapter_agent.add_device(olt)
        self.adapter_agent.add_port(
            olt.id, Port(port_no=1, label='pon', type=Port.PON_OLT))
        self.adapter_agent.add_port(
            olt.id, Port(port_no=2, label='eth', type=Port.ETHERNET_NNI))

        onu1 = Device(id='simulated_onu_1',
                      type='simulated_onu',
                      root=False,
                      parent_id=olt.id,
                      parent_port_no=1,
                      vendor='simulated',
                      model='n/a',
                      hardware_version='n/a',
                      firmware_version='n/a',
                      software_version='1.0',
                      serial_number=uuid4().hex,
                      adapter='simulated_onu',
                      oper_status=OperStatus.DISCOVERED,
                      vlan=101)
        self.adapter_agent.add_device(onu1)
        self.adapter_agent.add_port(
            onu1.id, Port(port_no=2, label='eth', type=Port.ETHERNET_UNI))
        self.adapter_agent.add_port(
            onu1.id,
            Port(port_no=1,
                 label='pon',
                 type=Port.PON_ONU,
                 peers=[Port.PeerPort(device_id=olt.id, port_no=1)]))

        onu2 = Device(id='simulated_onu_2',
                      type='simulated_onu',
                      root=False,
                      parent_id=olt.id,
                      parent_port_no=1,
                      vendor='simulated',
                      model='n/a',
                      hardware_version='n/a',
                      firmware_version='n/a',
                      software_version='1.0',
                      serial_number=uuid4().hex,
                      adapter='simulated_onu',
                      oper_status=OperStatus.DISCOVERED,
                      vlan=102)
        self.adapter_agent.add_device(onu2)
        self.adapter_agent.add_port(
            onu2.id, Port(port_no=2, label='eth', type=Port.ETHERNET_UNI))
        self.adapter_agent.add_port(
            onu2.id,
            Port(port_no=1,
                 label='pon',
                 type=Port.PON_ONU,
                 peers=[Port.PeerPort(device_id=olt.id, port_no=1)]))

        ld = LogicalDevice(
            id='simulated1',
            datapath_id=1,
            desc=ofp_desc(mfr_desc='cord project',
                          hw_desc='simualted pon',
                          sw_desc='simualted pon',
                          serial_num=uuid4().hex,
                          dp_desc='n/a'),
            switch_features=ofp_switch_features(
                n_buffers=256,  # TODO fake for now
                n_tables=2,  # TODO ditto
                capabilities=(  # TODO and ditto
                    OFPC_FLOW_STATS
                    | OFPC_TABLE_STATS
                    | OFPC_PORT_STATS
                    | OFPC_GROUP_STATS)),
            root_device_id=olt.id)
        self.adapter_agent.create_logical_device(ld)

        cap = OFPPF_1GB_FD | OFPPF_FIBER
        for port_no, name, device_id, device_port_no, root_port in [
            (1, 'onu1', onu1.id, 2, False), (2, 'onu2', onu2.id, 2, False),
            (129, 'olt1', olt.id, 2, True)
        ]:
            port = LogicalPort(id=name,
                               ofp_port=ofp_port(
                                   port_no=port_no,
                                   hw_addr=mac_str_to_tuple(
                                       '00:00:00:00:00:%02x' % port_no),
                                   name=name,
                                   config=0,
                                   state=OFPPS_LIVE,
                                   curr=cap,
                                   advertised=cap,
                                   peer=cap,
                                   curr_speed=OFPPF_1GB_FD,
                                   max_speed=OFPPF_1GB_FD),
                               device_id=device_id,
                               device_port_no=device_port_no,
                               root_port=root_port)
            self.adapter_agent.add_logical_port(ld.id, port)

        olt.parent_id = ld.id
        self.adapter_agent.update_device(olt)

    @inlineCallbacks
    def _simulate_device_activation(self, device):

        # first we pretend that we were able to contact the device and obtain
        # additional information about it
        device.root = True
        device.vendor = 'simulated'
        device.model = 'n/a'
        device.hardware_version = 'n/a'
        device.firmware_version = 'n/a'
        device.software_version = '1.0'
        device.serial_number = uuid4().hex
        device.connect_status = ConnectStatus.REACHABLE
        self.adapter_agent.update_device(device)

        # then shortly after we create some ports for the device
        yield asleep(0.05)
        nni_port = Port(port_no=2,
                        label='NNI facing Ethernet port',
                        type=Port.ETHERNET_NNI,
                        admin_state=AdminState.ENABLED,
                        oper_status=OperStatus.ACTIVE)
        self.adapter_agent.add_port(device.id, nni_port)
        self.adapter_agent.add_port(
            device.id,
            Port(port_no=1,
                 label='PON port',
                 type=Port.PON_OLT,
                 admin_state=AdminState.ENABLED,
                 oper_status=OperStatus.ACTIVE))

        # then shortly after we create the logical device with one port
        # that will correspond to the NNI port
        yield asleep(0.05)
        logical_device_id = uuid4().hex[:12]
        ld = LogicalDevice(
            # not setting id and datapth_id will let the adapter agent pick id
            desc=ofp_desc(mfr_desc='cord porject',
                          hw_desc='simualted pon',
                          sw_desc='simualted pon',
                          serial_num=uuid4().hex,
                          dp_desc='n/a'),
            switch_features=ofp_switch_features(
                n_buffers=256,  # TODO fake for now
                n_tables=2,  # TODO ditto
                capabilities=(  # TODO and ditto
                    OFPC_FLOW_STATS
                    | OFPC_TABLE_STATS
                    | OFPC_PORT_STATS
                    | OFPC_GROUP_STATS)),
            root_device_id=device.id)
        ld_initialized = self.adapter_agent.create_logical_device(ld)
        cap = OFPPF_1GB_FD | OFPPF_FIBER
        self.adapter_agent.add_logical_port(
            ld_initialized.id,
            LogicalPort(id='nni',
                        ofp_port=ofp_port(port_no=129,
                                          hw_addr=mac_str_to_tuple(
                                              '00:00:00:00:00:%02x' % 129),
                                          name='nni',
                                          config=0,
                                          state=OFPPS_LIVE,
                                          curr=cap,
                                          advertised=cap,
                                          peer=cap,
                                          curr_speed=OFPPF_1GB_FD,
                                          max_speed=OFPPF_1GB_FD),
                        device_id=device.id,
                        device_port_no=nni_port.port_no,
                        root_port=True))

        # and finally update to active
        device = self.adapter_agent.get_device(device.id)
        device.parent_id = ld_initialized.id
        device.oper_status = OperStatus.ACTIVE
        self.adapter_agent.update_device(device)

        # reactor.callLater(0.1, self._simulate_detection_of_onus, device.id)
        self.start_kpi_collection(device.id)

    @inlineCallbacks
    def _simulate_detection_of_onus(self, device_id):
        for i in xrange(1, 5):
            log.info('activate-olt-for-onu-{}'.format(i))
            vlan_id = self._olt_side_onu_activation(i)
            yield asleep(0.05)
            self.adapter_agent.child_device_detected(
                parent_device_id=device_id,
                parent_port_no=1,
                child_device_type='simulated_onu',
                proxy_address=Device.ProxyAddress(device_id=device_id,
                                                  channel_id=vlan_id),
                vlan=vlan_id)

    def _olt_side_onu_activation(self, seq):
        """
        This is where if this was a real OLT, the OLT-side activation for
        the new ONU should be performed. By the time we return, the OLT shall
        be able to provide tunneled (proxy) communication to the given ONU,
        using the returned information.
        """
        vlan_id = seq + 100
        return vlan_id

    def update_flows_bulk(self, device, flows, groups):
        log.debug('bulk-flow-update',
                  device_id=device.id,
                  flows=flows,
                  groups=groups)

        # sample code that analyzes the incoming flow table
        assert len(groups.items) == 0, "Cannot yet deal with groups"

        for flow in flows.items:
            in_port = get_in_port(flow)
            assert in_port is not None

            if in_port == 2:

                # Downstream rule

                for field in get_ofb_fields(flow):
                    if field.type == ETH_TYPE:
                        _type = field.eth_type
                        pass  # construct ether type based condition here

                    elif field.type == IP_PROTO:
                        _proto = field.ip_proto
                        pass  # construct ip_proto based condition here

                    elif field.type == IN_PORT:
                        _port = field.port
                        pass  # construct in_port based condition here

                    elif field.type == VLAN_VID:
                        _vlan_vid = field.vlan_vid
                        pass  # construct VLAN ID based filter condition here

                    elif field.type == VLAN_PCP:
                        _vlan_pcp = field.vlan_pcp
                        pass  # construct VLAN PCP based filter condition here

                    elif field.type == METADATA:
                        pass  # safe to ignore

                    # TODO
                    else:
                        raise NotImplementedError('field.type={}'.format(
                            field.type))

                for action in get_actions(flow):

                    if action.type == OUTPUT:
                        pass  # construct packet emit rule here

                    elif action.type == PUSH_VLAN:
                        if action.push.ethertype != 0x8100:
                            log.error('unhandled-ether-type',
                                      ethertype=action.push.ethertype)
                        pass  # construct vlan push command here

                    elif action.type == POP_VLAN:
                        pass  # construct vlan pop command here

                    elif action.type == SET_FIELD:
                        assert (action.set_field.field.oxm_class ==
                                ofp.OFPXMC_OPENFLOW_BASIC)
                        field = action.set_field.field.ofb_field
                        if field.type == VLAN_VID:
                            pass  # construct vlan_id set command here
                        else:
                            log.error('unsupported-action-set-field-type',
                                      field_type=field.type)

                    else:
                        log.error('unsupported-action-type',
                                  action_type=action.type)

                # final assembly of low level device flow rule and pushing it
                # down to device
                pass

            elif in_port == 1:

                # Upstream rule

                for field in get_ofb_fields(flow):

                    if field.type == ETH_TYPE:
                        _type = field.eth_type
                        pass  # construct ether type based condition here

                    elif field.type == IP_PROTO:
                        _proto = field.ip_proto
                        pass  # construct ip_proto based condition here

                    elif field.type == IN_PORT:
                        _port = field.port
                        pass  # construct in_port based condition here

                    elif field.type == VLAN_VID:
                        _vlan_vid = field.vlan_vid
                        pass  # construct VLAN ID based filter condition here

                    elif field.type == VLAN_PCP:
                        _vlan_pcp = field.vlan_pcp
                        pass  # construct VLAN PCP based filter condition here

                    elif field.type == UDP_SRC:
                        _udp_src = field.udp_src
                        pass  # construct UDP SRC based filter here

                    elif field.type == UDP_DST:
                        _udp_dst = field.udp_dst
                        pass  # construct UDP DST based filter here

                    # TODO
                    else:
                        raise NotImplementedError('field.type={}'.format(
                            field.type))

                for action in get_actions(flow):

                    if action.type == OUTPUT:
                        pass  # construct packet emit rule here

                    elif action.type == PUSH_VLAN:
                        if action.push.ethertype != 0x8100:
                            log.error('unhandled-ether-type',
                                      ethertype=action.push.ethertype)
                        pass  # construct vlan push command here

                    elif action.type == SET_FIELD:
                        assert (action.set_field.field.oxm_class ==
                                ofp.OFPXMC_OPENFLOW_BASIC)
                        field = action.set_field.field.ofb_field
                        if field.type == VLAN_VID:
                            pass  # construct vlan_id set command here
                        else:
                            log.error('unsupported-action-set-field-type',
                                      field_type=field.type)

                    else:
                        log.error('unsupported-action-type',
                                  action_type=action.type)

                # final assembly of low level device flow rule and pushing it
                # down to device
                pass

            else:
                raise Exception('Port should be 1 or 2 by our convention')

    def update_flows_incrementally(self, device, flow_changes, group_changes):
        raise NotImplementedError()

    def send_proxied_message(self, proxy_address, msg):
        log.info('send-proxied-message', proxy_address=proxy_address, msg=msg)
        # we mimic a response by sending the same message back in a short time
        reactor.callLater(0.2, self.adapter_agent.receive_proxied_message,
                          proxy_address, msg)

    def receive_proxied_message(self, proxy_address, msg):
        raise NotImplementedError()

    def receive_packet_out(self, logical_device_id, egress_port_no, msg):
        log.info('packet-out',
                 logical_device_id=logical_device_id,
                 egress_port_no=egress_port_no,
                 msg_len=len(msg))

    def start_kpi_collection(self, device_id):
        """Simulate periodic KPI metric collection from the device"""
        import random

        @inlineCallbacks  # pretend that we need to do async calls
        def _collect(device_id, prefix):

            try:
                # Step 1: gather metrics from device (pretend it here) - examples
                nni_port_metrics = yield dict(
                    tx_pkts=random.randint(0, 100),
                    rx_pkts=random.randint(0, 100),
                    tx_bytes=random.randint(0, 100000),
                    rx_bytes=random.randint(0, 100000),
                )
                pon_port_metrics = yield dict(
                    tx_pkts=nni_port_metrics['rx_pkts'],
                    rx_pkts=nni_port_metrics['tx_pkts'],
                    tx_bytes=nni_port_metrics['rx_bytes'],
                    rx_bytes=nni_port_metrics['tx_bytes'],
                )
                olt_metrics = yield dict(cpu_util=20 + 5 * random.random(),
                                         buffer_util=10 + 10 * random.random())

                # Step 2: prepare the KpiEvent for submission
                # we can time-stamp them here (or could use time derived from OLT
                ts = arrow.utcnow().timestamp
                kpi_event = KpiEvent(
                    type=KpiEventType.slice,
                    ts=ts,
                    prefixes={
                        # OLT-level
                        prefix:
                        MetricValuePairs(metrics=olt_metrics),
                        # OLT NNI port
                        prefix + '.nni':
                        MetricValuePairs(metrics=nni_port_metrics),
                        # OLT PON port
                        prefix + '.pon':
                        MetricValuePairs(metrics=pon_port_metrics)
                    })

                # Step 3: submit
                self.adapter_agent.submit_kpis(kpi_event)

            except Exception as e:
                log.exception('failed-to-submit-kpis', e=e)

        prefix = 'voltha.{}.{}'.format(self.name, device_id)
        lc = LoopingCall(_collect, device_id, prefix)
        lc.start(interval=15)  # TODO make this configurable

    # ~~~~~~~~~~~~~~~~~~~~ Embedded test Klein rest server ~~~~~~~~~~~~~~~~~~~~

    def get_test_control_site(self):
        return Site(self.app.resource())

    @app.route('/devices/<string:device_id>/detect_onus')
    def detect_onus(self, request, device_id):
        log.info('detect-onus', request=request, device_id=device_id)
        self._simulate_detection_of_onus(device_id)
        return '{"status": "OK"}'

    @app.route('/devices/<string:device_id>/test_eapol_in')
    def test_eapol_in(self, request, device_id):
        """Simulate a packet in message posted upstream"""
        log.info('test_eapol_in', request=request, device_id=device_id)
        eapol_start = str(
            Ether(src='00:11:22:33:44:55') / EAPOL(type=1, len=0) /
            Padding(load=42 * '\x00'))
        device = self.adapter_agent.get_device(device_id)
        self.adapter_agent.send_packet_in(logical_device_id=device.parent_id,
                                          logical_port_no=1,
                                          packet=eapol_start)
        return '{"status": "sent"}'
Example #15
0
class TibitOnuAdapter(object):

    name = 'tibit_onu'

    supported_device_types = [
        DeviceType(
            id='tibit_onu',
            adapter=name,
            accepts_bulk_flow_update=True
        )
    ]

    def __init__(self, adapter_agent, config):
        self.adapter_agent = adapter_agent
        self.config = config
        self.descriptor = Adapter(
            id=self.name,
            vendor='Tibit Communications Inc.',
            version='0.1',
            config=AdapterConfig(log_level=LogLevel.INFO)
        )
        self.incoming_messages = DeferredQueue()

    def start(self):
        log.debug('starting')
        log.info('started')

    def stop(self):
        log.debug('stopping')
        log.info('stopped')

    def adapter_descriptor(self):
        return self.descriptor

    def device_types(self):
        return DeviceTypes(items=self.supported_device_types)

    def health(self):
        return HealthStatus(state=HealthStatus.HealthState.HEALTHY)

    def change_master_state(self, master):
        raise NotImplementedError()

    def update_pm_config(self, device, pm_configs):
        raise NotImplementedError()

    def adopt_device(self, device):
        log.info('adopt-device', device=device)
        reactor.callLater(0.1, self._onu_device_activation, device)
        return device

    @inlineCallbacks
    def _onu_device_activation(self, device):
        # first we verify that we got parent reference and proxy info
        assert device.parent_id
        assert device.proxy_address.device_id
        assert device.proxy_address.channel_id

        # TODO: For now, pretend that we were able to contact the device and obtain
        # additional information about it.  Should add real message.
        device.vendor = 'Tibit Communications, Inc.'
        device.model = '10G GPON ONU'
        device.hardware_version = 'fa161020'
        device.firmware_version = '16.12.02'
        device.software_version = '1.0'
        device.serial_number = uuid4().hex
        device.connect_status = ConnectStatus.REACHABLE
        self.adapter_agent.update_device(device)

        # then shortly after we create some ports for the device
        uni_port = Port(
            port_no=2,
            label='UNI facing Ethernet port',
            type=Port.ETHERNET_UNI,
            admin_state=AdminState.ENABLED,
            oper_status=OperStatus.ACTIVE
        )
        self.adapter_agent.add_port(device.id, uni_port)
        self.adapter_agent.add_port(device.id, Port(
            port_no=1,
            label='PON port',
            type=Port.PON_ONU,
            admin_state=AdminState.ENABLED,
            oper_status=OperStatus.ACTIVE,
            peers=[
                Port.PeerPort(
                    device_id=device.parent_id,
                    port_no=device.parent_port_no
                )
            ]
        ))

        # TODO adding vports to the logical device shall be done by agent?
        # then we create the logical device port that corresponds to the UNI
        # port of the device

        # obtain logical device id
        parent_device = self.adapter_agent.get_device(device.parent_id)
        logical_device_id = parent_device.parent_id
        assert logical_device_id

        # we are going to use the proxy_address.channel_id as unique number
        # and name for the virtual ports, as this is guaranteed to be unique
        # in the context of the OLT port, so it is also unique in the context
        # of the logical device
        port_no = device.proxy_address.channel_id
        cap = OFPPF_10GB_FD | OFPPF_FIBER
        self.adapter_agent.add_logical_port(logical_device_id, LogicalPort(
            id=str(port_no),
            ofp_port=ofp_port(
                port_no=port_no,
                hw_addr=mac_str_to_tuple(device.mac_address),
                name='uni-{}'.format(port_no),
                config=0,
                state=OFPPS_LIVE,
                curr=cap,
                advertised=cap,
                peer=cap,
                curr_speed=OFPPF_10GB_FD,
                max_speed=OFPPF_10GB_FD
            ),
            device_id=device.id,
            device_port_no=uni_port.port_no
        ))

        # simulate a proxied message sending and receving a reply
        reply = yield self._message_exchange(device)

        # TODO - Need to add validation of reply and decide what to do upon failure

        # and finally update to "ACTIVE"
        device = self.adapter_agent.get_device(device.id)
        device.oper_status = OperStatus.ACTIVE
        self.adapter_agent.update_device(device)

        # TODO - Disable Stats Reporting for the moment
        #self.start_kpi_collection(device.id)

    def abandon_device(self, device):
        raise NotImplementedError(0
                                  )
    def disable_device(self, device):
        raise NotImplementedError()

    def reenable_device(self, device):
        raise NotImplementedError()

    def reboot_device(self, device):
        raise NotImplementedError()

    def delete_device(self, device):
        raise NotImplementedError()

    def get_device_details(self, device):
        raise NotImplementedError()

    @inlineCallbacks
    def update_flows_bulk(self, device, flows, groups):
        log.info('########################################')
        log.info('bulk-flow-update', device_id=device.id,
                 flows=flows, groups=groups)
        assert len(groups.items) == 0, "Cannot yet deal with groups"

        Clause = {v: k for k, v in ClauseSubtypeEnum.iteritems()}
        Operator = {v: k for k, v in RuleOperatorEnum.iteritems()}

        for flow in flows.items:
            in_port = get_in_port(flow)
            assert in_port is not None

            precedence = 255 - min(flow.priority / 256, 255)

            if in_port == 2:
                log.info('#### Upstream Rule ####')

                up_req = (
                    EOAMPayload() / EOAM_VendSpecificMsg(oui=CableLabs_OUI) /
                    EOAM_DpoeMsg(dpoe_opcode=0x03)
                    )

                #TODO - There is no body to the message above, is there ever an Upstream Rule

                for field in get_ofb_fields(flow):

                    if field.type == ETH_TYPE:
                        _type = field.eth_type
                        log.info('#### field.type == ETH_TYPE ####',field_type=_type)

                    elif field.type == IP_PROTO:
                        _proto = field.ip_proto
                        log.info('#### field.type == IP_PROTO ####')

                    elif field.type == IN_PORT:
                        _port = field.port
                        log.info('#### field.type == IN_PORT ####', port=_port)

                    elif field.type == VLAN_VID:
                        _vlan_vid = field.vlan_vid & 0xfff
                        log.info('#### field.type == VLAN_VID ####', vlan=_vlan_vid)

                    elif field.type == VLAN_PCP:
                        _vlan_pcp = field.vlan_pcp
                        log.info('#### field.type == VLAN_PCP ####', pcp=_vlan_pcp)

                    elif field.type == UDP_DST:
                        _udp_dst = field.udp_dst
                        log.info('#### field.type == UDP_DST ####')

                    elif field.type == IPV4_DST:
                        _ipv4_dst = field.ipv4_dst
                        log.info('#### field.type == IPV4_DST ####')

                    else:
                        log.info('#### field.type == NOT IMPLEMENTED!! ####')
                        raise NotImplementedError('field.type={}'.format(
                            field.type))

                for action in get_actions(flow):

                    if action.type == OUTPUT:
                        log.info('#### action.type == OUTPUT ####')

                    elif action.type == POP_VLAN:
                        log.info('#### action.type == POP_VLAN ####')

                    elif action.type == PUSH_VLAN:
                        log.info('#### action.type == PUSH_VLAN ####')
                        if action.push.ethertype != 0x8100:
                            log.error('unhandled-tpid',
                                      ethertype=action.push.ethertype)

                    elif action.type == SET_FIELD:
                        log.info('#### action.type == SET_FIELD ####')
                        assert (action.set_field.field.oxm_class ==
                                ofp.OFPXMC_OPENFLOW_BASIC)
                        field = action.set_field.field.ofb_field
                        if field.type == VLAN_VID:
                            pass
                        else:
                            log.error('unsupported-action-set-field-type',
                                      field_type=field.type)
                    else:
                        log.error('UNSUPPORTED-ACTION-TYPE',
                                  action_type=action.type)

            elif in_port == 1:
                log.info('#### Downstream Rule ####')

                #### Loop through fields again...

                for field in get_ofb_fields(flow):

                    if field.type == ETH_TYPE:
                        _type = field.eth_type
                        log.info('#### field.type == ETH_TYPE ####', in_port=in_port,
                                 match=_type)

                    elif field.type == IP_PROTO:
                        _proto = field.ip_proto
                        log.info('#### field.type == IP_PROTO ####', in_port=in_port,
                                 ip_proto=ip_proto)

                    elif field.type == IN_PORT:
                        _port = field.port
                        log.info('#### field.type == IN_PORT ####')

                    elif field.type == VLAN_VID:
                        _vlan_vid = field.vlan_vid & 0xfff
                        log.info('#### field.type == VLAN_VID ####')

                    elif field.type == VLAN_PCP:
                        _vlan_pcp = field.vlan_pcp
                        log.info('#### field.type == VLAN_PCP ####')

                    elif field.type == UDP_DST:
                        _udp_dst = field.udp_dst
                        log.info('#### field.type == UDP_DST ####')

                    elif field.type == IPV4_DST:
                        _ipv4_dst = field.ipv4_dst
                        log.info('#### field.type == IPV4_DST ####')
                        a = int(hex(_ipv4_dst)[2:4], 16)
                        b = int(hex(_ipv4_dst)[4:6], 16)
                        c = int(hex(_ipv4_dst)[6:8], 16)
                        d = int(hex(_ipv4_dst)[8:], 16)
                        dn_req = (
                            EOAMPayload() / EOAM_VendSpecificMsg(oui=CableLabs_OUI) /
                            EOAM_DpoeMsg(dpoe_opcode=0x03, body=AddStaticMacAddress(mac=mcastIp2McastMac('%d.%d.%d.%d' % (a,b,c,d)))
                            ))
                        
                        # send message

                        log.info('ONU-send-proxied-message to Set Static IP MCAST address for ONU: {}'.format(device.mac_address))
                        self.adapter_agent.send_proxied_message(device.proxy_address,
                                                                dn_req)

                        # Get and process the Set Response
                        ack = False
                        start_time = time.time()

                        # Loop until we have a set response or timeout
                        while not ack:
                            frame = yield self.incoming_messages.get()
                            #TODO - Need to add propoer timeout functionality
                            #if (time.time() - start_time) > TIBIT_MSG_WAIT_TIME or (frame is None):
                            #    break  # don't wait forever

                            respType = self._get_oam_msg_type(frame)
                            log.info('Received OAM Message 0x %s' % str(respType))

                            #Check that the message received is a Set Response
                            if (respType == RxedOamMsgTypeEnum["DPoE Set Response"]):
                                ack = True
                            else:
                                # Handle unexpected events/OMCI messages
                                self._check_resp(frame)

                        # Verify Set Response
                        if ack:
                            log.info('ONU-response received for Set Static IP MCAST address for ONU: {}'.format(device.mac_address))
                            (rc,branch,leaf,status) = self._check_set_resp(frame)
                            if (rc == True):
                                log.info('Set Response had no errors')
                            else:
                                log.info('Set Response had errors - Branch 0x{:X} Leaf 0x{:0>4X} {}'.format(branch, leaf, DPoEVariableResponseCodes[status]))

                    else:
                        raise NotImplementedError('field.type={}'.format(
                            field.type))

                for action in get_actions(flow):

                    if action.type == OUTPUT:
                        log.info('#### action.type == OUTPUT ####')

                    elif action.type == POP_VLAN:
                        log.info('#### action.type == POP_VLAN ####')

                    elif action.type == PUSH_VLAN:
                        log.info('#### action.type == PUSH_VLAN ####')
                        if action.push.ethertype != 0x8100:
                            log.error('unhandled-ether-type',
                                      ethertype=action.push.ethertype)

                    elif action.type == SET_FIELD:
                        log.info('#### action.type == SET_FIELD ####')
                        assert (action.set_field.field.oxm_class ==
                                ofp.OFPXMC_OPENFLOW_BASIC)
                        field = action.set_field.field.ofb_field
                        if field.type == VLAN_VID:
                            pass
                        else:
                            log.error('unsupported-action-set-field-type',
                                      field_type=field.type)

                    else:
                        log.error('UNSUPPORTED-ACTION-TYPE',
                                  action_type=action.type)

            else:
                raise Exception('Port should be 1 or 2 by our convention')

    def update_flows_incrementally(self, device, flow_changes, group_changes):
        raise NotImplementedError()

    def send_proxied_message(self, proxy_address, msg):
        raise NotImplementedError()

    def receive_proxied_message(self, proxy_address, msg):
        log.info('receive-proxied-message',
                  proxy_address=proxy_address, msg=msg.show(dump=True))
        self.incoming_messages.put(msg)


    @inlineCallbacks
    def _message_exchange(self, device):

        # register for receiving async messages
        self.adapter_agent.register_for_proxied_messages(device.proxy_address)

        # reset incoming message queue
        while self.incoming_messages.pending:
            _ = yield self.incoming_messages.get()

        # construct message
        msg = (
            EOAMPayload() / EOAM_VendSpecificMsg(oui=CableLabs_OUI) /
            EOAM_DpoeMsg(dpoe_opcode=0x01,body=DeviceId())
            )

        # send message
        log.info('ONU-send-proxied-message to Get Device Id for ONU: {}'.format(device.mac_address))

        self.adapter_agent.send_proxied_message(device.proxy_address, msg)

        # wait till we detect incoming message
        yield self.incoming_messages.get()

        log.info('ONU-response received for Get Device Id for ONU: {}'.format(device.mac_address))

        #TODO Add a timeout to the above, if we do not recieve a message

        #The above get request/ get response is done to verify the message exchange is
        #functioning correctly, there is nothing to store from the response

        # construct install of igmp query address
        msg = (
            EOAMPayload() / EOAM_VendSpecificMsg(oui=CableLabs_OUI) /
            EOAM_DpoeMsg(dpoe_opcode=0x03,body=AddStaticMacAddress(mac='01:00:5e:00:00:01')
            ))

        # send message
        log.info('ONU-send-proxied-message to Set Static IGMP MAC address for ONU: {}'.format(device.mac_address))
        self.adapter_agent.send_proxied_message(device.proxy_address, msg)

        # Get and process the Set Response
        ack = False
        start_time = time.time()

        # Loop until we have a set response or timeout
        while not ack:
            frame = yield self.incoming_messages.get()
            #TODO - Need to add propoer timeout functionality
            #if (time.time() - start_time) > TIBIT_MSG_WAIT_TIME or (frame is None):
            #    break  # don't wait forever

            respType = self._get_oam_msg_type(frame)
            log.info('Received OAM Message 0x %s' % str(respType))

            #Check that the message received is a Set Response
            if (respType == RxedOamMsgTypeEnum["DPoE Set Response"]):
                ack = True
            else:
                # Handle unexpected events/OMCI messages
                self._check_resp(frame)

        # Verify Set Response
        if ack:
            log.info('ONU-response received for Set Static IGMP MAC address for ONU: {}'.format(device.mac_address))
            (rc,branch,leaf,status) = self._check_set_resp(frame)
            if (rc == True):
                log.info('Set Response had no errors')
            else:
                log.info('Set Response had errors - Branch 0x{:X} Leaf 0x{:0>4X} {}'.format(branch, leaf, DPoEVariableResponseCodes[status]))

        # construct multicast LLID set
        # TODO - This is needed to support multicast traffic for GPON. This should only be done for a 
        #        a GPON ONU and the UnicastLink value needs to come from the OLT. This will work only for
        #        a single GPON ONU.
        msg = (
            EOAMPayload() / EOAM_VendSpecificMsg(oui=CableLabs_OUI) /
            EOAM_DpoeMsg(dpoe_opcode=0x06,body=MulticastRegisterSet(MulticastLink=0x10bc, UnicastLink=0x1008)
            ))

        # send message
        log.info('ONU-send-proxied-message to Set Static IGMP MAC address for ONU: {}'.format(device.mac_address))
        self.adapter_agent.send_proxied_message(device.proxy_address, msg)

        # The MulticastRegisterSet does not currently return a response. Just hope it worked.

        # by returning we allow the device to be shown as active, which
        # indirectly verified that message passing works

    def receive_packet_out(self, logical_device_id, egress_port_no, msg):
        log.info('packet-out', logical_device_id=logical_device_id,
                 egress_port_no=egress_port_no, msg_len=len(msg))

    def receive_inter_adapter_message(self, msg):
        raise NotImplementedError()

    def suppress_alarm(self, filter):
        raise NotImplementedError()

    def unsuppress_alarm(self, filter):
        raise NotImplementedError()

    def start_kpi_collection(self, device_id):

        """TMP Simulate periodic KPI metric collection from the device"""
        import random

        @inlineCallbacks  # pretend that we need to do async calls
        def _collect(device_id, prefix):

            try:
                # Step 1: gather metrics from device (pretend it here) - examples
                uni_port_metrics = yield dict(
                    tx_pkts=random.randint(0, 100),
                    rx_pkts=random.randint(0, 100),
                    tx_bytes=random.randint(0, 100000),
                    rx_bytes=random.randint(0, 100000),
                )
                pon_port_metrics = yield dict(
                    tx_pkts=uni_port_metrics['rx_pkts'],
                    rx_pkts=uni_port_metrics['tx_pkts'],
                    tx_bytes=uni_port_metrics['rx_bytes'],
                    rx_bytes=uni_port_metrics['tx_bytes'],
                )
                onu_metrics = yield dict(
                    cpu_util=20 + 5 * random.random(),
                    buffer_util=10 + 10 * random.random()
                )

                # Step 2: prepare the KpiEvent for submission
                # we can time-stamp them here (or could use time derived from OLT
                ts = arrow.utcnow().timestamp
                kpi_event = KpiEvent(
                    type=KpiEventType.slice,
                    ts=ts,
                    prefixes={
                        # OLT-level
                        prefix: MetricValuePairs(metrics=onu_metrics),
                        # OLT NNI port
                        prefix + '.nni': MetricValuePairs(metrics=uni_port_metrics),
                        # OLT PON port
                        prefix + '.pon': MetricValuePairs(metrics=pon_port_metrics)
                    }
                )

                # Step 3: submit
                self.adapter_agent.submit_kpis(kpi_event)

            except Exception as e:
                log.exception('failed-to-submit-kpis', e=e)

        prefix = 'voltha.{}.{}'.format(self.name, device_id)
        lc = LoopingCall(_collect, device_id, prefix)
        lc.start(interval=15)  # TODO make this configurable


# Methods for Get / Set  Response Processing from eoam_messages


    def _get_oam_msg_type(self, frame):

        respType = RxedOamMsgTypeEnum["Unknown"]
        recv_frame = frame

        if recv_frame.haslayer(EOAMPayload):
            if recv_frame.haslayer(EOAMEvent):
                recv_frame = RxedOamMsgTypeEnum["Event Notification"]
            elif recv_frame.haslayer(EOAM_OmciMsg):
                respType = RxedOamMsgTypeEnum["OMCI Message"]
            else:
                dpoeOpcode = 0x00
                if recv_frame.haslayer(EOAM_TibitMsg):
                    dpoeOpcode = recv_frame.getlayer(EOAM_TibitMsg).dpoe_opcode;
                elif recv_frame.haslayer(EOAM_DpoeMsg):
                    dpoeOpcode = recv_frame.getlayer(EOAM_DpoeMsg).dpoe_opcode;

                # Get Response
                if (dpoeOpcode == 0x02):
                    respType = RxedOamMsgTypeEnum["DPoE Get Response"]

                # Set Response
                elif (dpoeOpcode == 0x04):
                    respType = RxedOamMsgTypeEnum["DPoE Set Response"]

                # File Transfer ACK
                elif (dpoeOpcode == 0x09):
                    respType = RxedOamMsgTypeEnum["DPoE File Transfer"]
                else:
                    log.info('Unsupported DPoE Opcode {:0>2X}'.format(dpoeOpcode))
        else:
            log.info('Invalid OAM Header')

        return respType


    def _get_value_from_msg(self, frame, branch, leaf):
        retVal = False
        value = 0
        recv_frame = frame

        if recv_frame.haslayer(EOAMPayload):
            payload = recv_frame.payload
            if hasattr(payload, 'body'):
                loadstr = payload.body.load
                # Get a specific TLV value
                (retVal,bytesRead,value,retbranch,retleaf) = self._handle_get_value(loadstr, 0, branch, leaf)
            else:
                log.info('received frame has no payload')
        else:
            log.info('Invalid OAM Header')
        return retVal,value,


    def _handle_get_value(self, loadstr, startOfTlvs, queryBranch, queryLeaf):
        retVal = False;
        value = 0
        branch = 0
        leaf = 0
        bytesRead = startOfTlvs
        loadstrlen    = len(loadstr)

        while (bytesRead <= loadstrlen):
            (branch, leaf) = struct.unpack_from('>BH', loadstr, bytesRead)

            if (branch != 0):
                bytesRead += 3
                length = struct.unpack_from('>B', loadstr, bytesRead)[0]
                bytesRead += 1

                if (length == 1):
                    value = struct.unpack_from(">B", loadstr, bytesRead)[0]
                elif (length == 2):
                    value = struct.unpack_from(">H", loadstr, bytesRead)[0]
                elif (length == 4):
                    value = struct.unpack_from(">I", loadstr, bytesRead)[0]
                elif (length == 8):
                    value = struct.unpack_from(">Q", loadstr, bytesRead)[0]
                else:
                    if (length >= 0x80):
                        log.info('Branch 0x{:0>2X} Leaf 0x{:0>4X} {}'.format(branch, leaf, DPoEVariableResponseCodes[length]))
                        # Set length to zero so bytesRead doesn't get mistakenly incremented below
                        length = 0
                    else:
                        # Attributes with a length of zero are actually 128 bytes long
                        if (length == 0):
                            length = 128;
                        valStr = ">{}s".format(length)
                        value = struct.unpack_from(valStr, loadstr, bytesRead)[0]

                if (length > 0):
                    bytesRead += length

                if (branch != 0xD6):
                    if ( ((queryBranch == 0) and (queryLeaf == 0)) or
                         ((queryBranch == branch) and (queryLeaf == leaf)) ):
                        # Prevent zero-lengthed values from returning success
                        if (length > 0):
                            retVal = True;
                        break
            else:
                break

        if (retVal == False):
            value = 0

        return retVal,bytesRead,value,branch,leaf


    def _check_set_resp(self, frame):
        rc = False
        branch = 0
        leaf = 0
        status = 0
        recv_frame = frame
        if recv_frame.haslayer(EOAMPayload):
            payload = recv_frame.payload
            if hasattr(payload, 'body'):
                loadstr = payload.body.load
                # Get a specific TLV value
                (rc,branch,leaf,status) = self._check_set_resp_attrs(loadstr, 0)
            else:
                log.info('received frame has no payload')
        else:
            log.info('Invalid OAM Header')
        return rc,branch,leaf,status



    def _check_resp(self, frame):
        respType = RxedOamMsgTypeEnum["Unknown"]
        recv_frame = frame
        if recv_frame.haslayer(EOAMPayload):

            if recv_frame.haslayer(EOAMEvent):
                self.handle_oam_event(recv_frame)
            elif recv_frame.haslayer(EOAM_OmciMsg):
                 self.handle_omci(recv_frame)
            else:
                dpoeOpcode = 0x00
                if recv_frame.haslayer(EOAM_TibitMsg):
                    dpoeOpcode = recv_frame.getlayer(EOAM_TibitMsg).dpoe_opcode;
                elif recv_frame.haslayer(EOAM_DpoeMsg):
                    dpoeOpcode = recv_frame.getlayer(EOAM_DpoeMsg).dpoe_opcode;

                if hasattr(recv_frame, 'body'):
                    payload = recv_frame.payload
                    loadstr = payload.body.load

                # Get Response
                if (dpoeOpcode == 0x02):
                    # Get a specific TLV value
                    branch = 0xD7
                    leaf = 0x0006
                    (rc,bytesRead,value,retbranch,retleaf) = self._handle_get_value(loadstr, startOfTlvs, branch, leaf)
                    if (rc == True):
                        log.info('Branch 0x{:X} Leaf 0x{:0>4X}  value = {}'.format(branch, leaf, value))
                    else:
                        log.info('Branch 0x{:X} Leaf 0x{:0>4X}  no value'.format(branch, leaf))

                    # Walk through all TLV values
                    bytesRead = 0
                    rc = True
                    while(rc == True):
                        branch = 0
                        leaf = 0
                        (rc,bytesRead,value,branch,leaf) = self._handle_get_value(loadstr, bytesRead, branch, leaf)
                        if (rc == True):
                            log.info('Branch 0x{:0>2X} Leaf 0x{:0>4X}  value = {}'.format(branch, leaf, value))
                        elif (branch != 0):
                            log.info('Branch 0x{:0>2X} Leaf 0x{:0>4X}  no value'.format(branch, leaf))

                # Set Response
                elif (dpoeOpcode == 0x04):
                    (rc,branch,leaf,status) = self._check_set_resp_attrs(loadstr, 0)
                    if (rc == True):
                        log.info('Set Response had no errors')
                    else:
                        log.info('Branch 0x{:X} Leaf 0x{:0>4X} {}'.format(branch, leaf, DPoEVariableResponseCodes[status]))

                # File Transfer ACK
                elif (dpoeOpcode == 0x09):
                    rc = self._handle_fx_ack(loadstr, bytesRead, block_number)
                else:
                    log.info('Unsupported DPoE Opcode {:0>2X}'.format(dpoeOpcode))
        else:
            log.info('Invalid OAM Header')

        return respType    

    def _check_set_resp_attrs(self, loadstr, startOfTlvs):
        retVal = True;
        branch = 0
        leaf = 0
        length = 0
        bytesRead = startOfTlvs
        loadstrlen    = len(loadstr)

        while (bytesRead <= loadstrlen):
            (branch, leaf) = struct.unpack_from('>BH', loadstr, bytesRead)
#            print "Branch/Leaf        0x{:0>2X}/0x{:0>4X}".format(branch, leaf)

            if (branch != 0):
                bytesRead += 3
                length = struct.unpack_from('>B', loadstr, bytesRead)[0]
#                print "Length:            0x{:0>2X} ({})".format(length,length)
                bytesRead += 1

                if (length >= 0x80):
                    log.info('Branch 0x{:0>2X} Leaf 0x{:0>4X} {}'.format(branch, leaf, DPoEVariableResponseCodes[length]))
                    if (length > 0x80):
                        retVal = False;
                        break;
                else:
                    bytesRead += length

            else:
                break

        return retVal,branch,leaf,length

        
    def _handle_fx_ack(self, loadstr, startOfXfer, block_number):
        retVal = False
        (fx_opcode, acked_block, response_code) = struct.unpack_from('>BHB', loadstr, startOfXfer)

        #print "fx_opcode:      0x%x" % fx_opcode
        #print "acked_block:    0x%x" % acked_block
        #print "response_code:  0x%x" % response_code


        if (fx_opcode != 0x03):
            log.info('unexpected fx_opcode 0x%x (expected 0x03)' % fx_opcode)
        elif (acked_block != block_number):
            log.info('unexpected acked_block 0x%x (expected 0x%x)' % (acked_block, block_number))
        elif (response_code != 0):
            log.info('unexpected response_code 0x%x (expected 0x00)' % response_code)
        else:
            retVal = True;    
Example #16
0
class MapleOltAdapter(object):
    name = 'maple_olt'

    supported_device_types = [
        DeviceType(id=name, adapter=name, accepts_bulk_flow_update=True)
    ]

    def __init__(self, adapter_agent, config):
        self.adapter_agent = adapter_agent
        self.config = config
        self.descriptor = Adapter(
            id=self.name,
            vendor='Voltha project',
            version='0.4',
            config=AdapterConfig(log_level=LogLevel.INFO))
        self.devices_handlers = dict()  # device_id -> MapleOltHandler()
        self.logical_device_id_to_root_device_id = dict()

    def start(self):
        log.debug('starting')
        log.info('started')

    def stop(self):
        log.debug('stopping')
        log.info('stopped')

    def adapter_descriptor(self):
        return self.descriptor

    def device_types(self):
        return DeviceTypes(items=self.supported_device_types)

    def health(self):
        return HealthStatus(state=HealthStatus.HealthState.HEALTHY)

    def change_master_state(self, master):
        raise NotImplementedError()

    def adopt_device(self, device):
        self.devices_handlers[device.id] = MapleOltHandler(self, device.id)
        reactor.callLater(0, self.devices_handlers[device.id].activate, device)
        return device

    def abandon_device(self, device):
        raise NotImplementedError()

    def deactivate_device(self, device):
        raise NotImplementedError()

    def update_flows_bulk(self, device, flows, groups):
        log.info('bulk-flow-update',
                 device_id=device.id,
                 flows=flows,
                 groups=groups)
        assert len(groups.items) == 0, "Cannot yet deal with groups"
        handler = self.devices_handlers[device.id]
        return handler.update_flow_table(flows.items, device)

    def update_flows_incrementally(self, device, flow_changes, group_changes):
        raise NotImplementedError()

    def send_proxied_message(self, proxy_address, msg):
        log.info('send-proxied-message', proxy_address=proxy_address, msg=msg)
        handler = self.devices_handlers[proxy_address.device_id]
        handler.send_proxied_message(proxy_address, msg)

    def receive_proxied_message(self, proxy_address, msg):
        raise NotImplementedError()

    def receive_packet_out(self, logical_device_id, egress_port_no, msg):
        def ldi_to_di(ldi):
            di = self.logical_device_id_to_root_device_id.get(ldi)
            if di is None:
                logical_device = self.adapter_agent.get_logical_device(ldi)
                di = logical_device.root_device_id
                self.logical_device_id_to_root_device_id[ldi] = di
            return di

        device_id = ldi_to_di(logical_device_id)
        handler = self.devices_handlers[device_id]
        handler.packet_out(egress_port_no, msg)
Example #17
0
class RubyAdapter(object):

    name = "microsemi_olt"

    supported_device_types = [
        DeviceType(
            id=name,
            adapter=name,
            accepts_bulk_flow_update=True
        )
    ]

    def __init__(self, adaptor_agent, config):
        self.adaptor_agent = adaptor_agent
        self.config = config
        self.olts = {}
        self.descriptor = Adapter(
            id=self.name,
            vendor='Microsemi / Celestica',
            version='0.1',
            config=AdapterConfig(log_level=LogLevel.INFO)
        )

        self.interface = registry('main').get_args().interface

    def start(self):
        log.info('starting')
        log.info('started')
        return self

    def stop(self):
        log.debug('stopping')
        for target in self.olts.keys():
            self._abandon(target)
        log.info('stopped')
        return self

    def adapter_descriptor(self):
        return self.descriptor

    def device_types(self):
        return DeviceTypes(items=self.supported_device_types)

    def health(self):
        return HealthStatus(state=HealthStatus.HealthState.HEALTHY)

    def change_master_state(self, master):
        raise NotImplementedError()

    def adopt_device(self, device):
        device_manager = DeviceManager(device, self.adaptor_agent)
        target = device.mac_address
        comm = PAS5211Communication(dst_mac=target, iface=self.interface)
        olt = OltStateMachine(iface=self.interface, comm=comm,
                              target=target, device=device_manager)
        activation = ActivationWatcher(iface=self.interface, comm=comm,
                                       target=target, device=device_manager)
        reactor.callLater(0, self._init_olt, olt, activation)

        log.info('adopted-device', device=device)
        self.olts[target] = (olt, activation, comm)

    def reconcile_device(self, device):
        raise NotImplementedError()

    def abandon_device(self, device):
        self._abandon(device.mac_address)

    def disable_device(self, device):
        raise NotImplementedError()

    def reenable_device(self, device):
        raise NotImplementedError()

    def update_pm_config(self, device, pm_configs):
        raise NotImplementedError()

    def reboot_device(self, device):
        raise NotImplementedError()

    def download_image(self, device, request):
        raise NotImplementedError()

    def get_image_download_status(self, device, request):
        raise NotImplementedError()

    def cancel_image_download(self, device, request):
        raise NotImplementedError()

    def activate_image_update(self, device, request):
        raise NotImplementedError()

    def revert_image_update(self, device, request):
        raise NotImplementedError()

    def self_test_device(self, device):
        """
        This is called to Self a device based on a NBI call.
        :param device: A Voltha.Device object.
        :return: Will return result of self test
        """
        log.info('self-test-device', device=device.id)
        raise NotImplementedError()

    def delete_device(self, device):
        raise NotImplementedError()

    def get_device_details(self, device):
        raise NotImplementedError()

    def update_flows_bulk(self, device, flows, groups):
        log.debug('bulk-flow-update', device_id=device.id,
                  flows=flows, groups=groups)

    def create_interface(self, device, data):
        raise NotImplementedError()

    def update_interface(self, device, data):
        raise NotImplementedError()

    def remove_interface(self, device, data):
        raise NotImplementedError()

    def receive_onu_detect_state(self, device_id, state):
        raise NotImplementedError()

    def create_tcont(self, device, tcont_data, traffic_descriptor_data):
        raise NotImplementedError()

    def update_tcont(self, device, tcont_data, traffic_descriptor_data):
        raise NotImplementedError()

    def remove_tcont(self, device, tcont_data, traffic_descriptor_data):
        raise NotImplementedError()

    def create_gemport(self, device, data):
        raise NotImplementedError()

    def update_gemport(self, device, data):
        raise NotImplementedError()

    def remove_gemport(self, device, data):
        raise NotImplementedError()

    def create_multicast_gemport(self, device, data):
        raise NotImplementedError()

    def update_multicast_gemport(self, device, data):
        raise NotImplementedError()

    def remove_multicast_gemport(self, device, data):
        raise NotImplementedError()

    def create_multicast_distribution_set(self, device, data):
        raise NotImplementedError()

    def update_multicast_distribution_set(self, device, data):
        raise NotImplementedError()

    def remove_multicast_distribution_set(self, device, data):
        raise NotImplementedError()

    def send_proxied_message(self, proxy_address, msg):
        device = self.adaptor_agent.get_device(proxy_address.device_id)
        _, _, comm = self.olts[device.mac_address]
        if isinstance(msg, OmciFrame):
            log.info('send-omci-proxied-message', proxy_address=proxy_address, device=device)
            # TODO make this more efficient
            omci_proxy = OMCIProxy(proxy_address=proxy_address,
                                   msg=msg,
                                   adapter_agent=self.adaptor_agent,
                                   target=device.mac_address,
                                   comm=comm,
                                   iface=self.interface)
            omci_proxy.runbg()


        else:
            log.info('send-proxied-message', proxy_address=proxy_address)
            api_proxy = APIProxy(proxy_address=proxy_address,
                                 msg=msg,
                                 adapter_agent=self.adaptor_agent,
                                 target=device.mac_address,
                                 comm=comm,
                                 iface=self.interface)
            api_proxy.runbg()

    def receive_proxied_message(self, proxy_address, msg):
        raise NotImplementedError()

    def update_flows_incrementally(self, device, flow_changes, group_changes):
        raise NotImplementedError()

    def receive_packet_out(self, logical_device_id, egress_port_no, msg):
        log.info('packet-out', logical_device_id=logical_device_id,
                 egress_port_no=egress_port_no, msg_len=len(msg))

    def receive_inter_adapter_message(self, msg):
        raise NotImplementedError()

    def suppress_alarm(self, filter):
        raise NotImplementedError()

    def unsuppress_alarm(self, filter):
        raise NotImplementedError()

    ##
    # Private methods
    ##
    def _init_olt(self, olt, activation_watch):
        olt.runbg()
        activation_watch.runbg()

    def _abandon(self, target):
        olt, activation, _ = self.olts[target]
        olt.stop()
        activation.stop()
        del self.olts[target]
Example #18
0
class AdtranOnuAdapter(object):
    name = 'adtran_onu'
    version = '0.1'

    supported_device_types = [
        DeviceType(
            id=name,
            vendor_id='ADTN',
            adapter=name,
            accepts_bulk_flow_update=True
        )
    ]

    def __init__(self, adapter_agent, config):
        self.adapter_agent = adapter_agent
        self.config = config
        self.descriptor = Adapter(
            id=self.name,
            vendor='Adtran, Inc.',
            version=self.version,
            config=AdapterConfig(log_level=LogLevel.INFO)
        )
        self.devices_handlers = dict()  # device_id -> AdtranOnuHandler()

    def start(self):
        log.debug('starting')
        log.info('started')

    def stop(self):
        log.debug('stopping')
        log.info('stopped')

    def adapter_descriptor(self):
        return self.descriptor

    def device_types(self):
        return DeviceTypes(items=self.supported_device_types)

    def health(self):
        return HealthStatus(state=HealthStatus.HealthState.HEALTHY)

    def change_master_state(self, master):
        raise NotImplementedError()

    def adopt_device(self, device):
        log.info('adopt_device', device_id=device.id)
        self.devices_handlers[device.proxy_address.channel_id] = AdtranOnuHandler(self, device.id)
        reactor.callLater(0, self.devices_handlers[device.proxy_address.channel_id].activate, device)
        return device

    def reconcile_device(self, device):
        raise NotImplementedError()

    def abandon_device(self, device):
        raise NotImplementedError()

    def disable_device(self, device):
        raise NotImplementedError()

    def reenable_device(self, device):
        raise NotImplementedError()

    def reboot_device(self, device):
        raise NotImplementedError()

    def download_image(self, device, request):
        raise NotImplementedError()

    def get_image_download_status(self, device, request):
        raise NotImplementedError()

    def cancel_image_download(self, device, request):
        raise NotImplementedError()

    def activate_image_update(self, device, request):
        raise NotImplementedError()

    def revert_image_update(self, device, request):
        raise NotImplementedError()

    def self_test_device(self, device):
        raise NotImplementedError()

    def delete_device(self, device):
        raise NotImplementedError()

    def get_device_details(self, device):
        raise NotImplementedError()

    def update_pm_config(self, device, pm_configs):
        raise NotImplementedError()

    def update_flows_bulk(self, device, flows, groups):
        log.info('bulk-flow-update', device_id=device.id,
                 flows=flows, groups=groups)
        assert len(groups.items) == 0
        handler = self.devices_handlers[device.proxy_address.channel_id]
        return handler.update_flow_table(device, flows.items)

    def update_flows_incrementally(self, device, flow_changes, group_changes):
        raise NotImplementedError()

    def send_proxied_message(self, proxy_address, msg):
        log.info('send-proxied-message', proxy_address=proxy_address, msg=msg)

    def receive_proxied_message(self, proxy_address, msg):
        log.info('receive-proxied-message', proxy_address=proxy_address,
                 device_id=proxy_address.device_id, msg=hexify(msg))
        handler = self.devices_handlers[proxy_address.channel_id]
        handler.receive_message(msg)

    def receive_packet_out(self, logical_device_id, egress_port_no, msg):
        log.info('packet-out', logical_device_id=logical_device_id,
                 egress_port_no=egress_port_no, msg_len=len(msg))
        raise NotImplementedError()

    def receive_inter_adapter_message(self, msg):
        log.info('rx_inter_adapter_msg')
        raise NotImplementedError()

    def suppress_alarm(self, filter):
        log.info('suppress_alarm', filter=filter)
        raise NotImplementedError()

    def unsuppress_alarm(self, filter):
        log.info('unsuppress_alarm', filter=filter)
        raise NotImplementedError()

    def receive_onu_detect_state(self, device_id, state):
        """
        Receive onu detect state in ONU adapter
        :param proxy_address: ONU device address
        :param state: ONU detect state (bool)
        :return: None
        """
        raise NotImplementedError()

    # PON Mgnt APIs #
    def create_interface(self, device, data):
        """
        API to create various interfaces (only some PON interfaces as of now)
        in the devices
        """
        raise NotImplementedError()

    def update_interface(self, device, data):
        """
        API to update various interfaces (only some PON interfaces as of now)
        in the devices
        """
        raise NotImplementedError()

    def remove_interface(self, device, data):
        """
        API to delete various interfaces (only some PON interfaces as of now)
        in the devices
        """
        raise NotImplementedError()

    def create_tcont(self, device, tcont_data, traffic_descriptor_data):
        """
        API to create tcont object in the devices
        :param device: device id
        :tcont_data: tcont data object
        :traffic_descriptor_data: traffic descriptor data object
        :return: None
        """
        log.info('create-tcont', tcont_data=tcont_data,
                 traffic_descriptor_data=traffic_descriptor_data)
        raise NotImplementedError()

    def update_tcont(self, device, tcont_data, traffic_descriptor_data):
        """
        API to update tcont object in the devices
        :param device: device id
        :tcont_data: tcont data object
        :traffic_descriptor_data: traffic descriptor data object
        :return: None
        """
        log.info('update-tcont', tcont_data=tcont_data,
                 traffic_descriptor_data=traffic_descriptor_data)
        raise NotImplementedError()

    def remove_tcont(self, device, tcont_data, traffic_descriptor_data):
        """
        API to delete tcont object in the devices
        :param device: device id
        :tcont_data: tcont data object
        :traffic_descriptor_data: traffic descriptor data object
        :return: None
        """
        log.info('remove-tcont', tcont_data=tcont_data,
                 traffic_descriptor_data=traffic_descriptor_data)
        raise NotImplementedError()

    def create_gemport(self, device, data):
        """
        API to create gemport object in the devices
        :param device: device id
        :data: gemport data object
        :return: None
        """
        log.info('create-gemport', data=data)
        raise NotImplementedError()

    def update_gemport(self, device, data):
        """
        API to update gemport object in the devices
        :param device: device id
        :data: gemport data object
        :return: None
        """
        log.info('update-gemport', data=data)
        raise NotImplementedError()

    def remove_gemport(self, device, data):
        """
        API to delete gemport object in the devices
        :param device: device id
        :data: gemport data object
        :return: None
        """
        log.info('remove-gemport', data=data)
        raise NotImplementedError()

    def create_multicast_gemport(self, device, data):
        raise NotImplementedError()

    def update_multicast_gemport(self, device, data):
        raise NotImplementedError()

    def remove_multicast_gemport(self, device, data):
        raise NotImplementedError()

    def create_multicast_distribution_set(self, device, data):
        raise NotImplementedError()

    def update_multicast_distribution_set(self, device, data):
        raise NotImplementedError()

    def remove_multicast_distribution_set(self, device, data):
        raise NotImplementedError()
Example #19
0
class TibitOnuAdapter(object):

    name = 'tibit_onu'

    supported_device_types = [
        DeviceType(
            id='tibit_onu',
            adapter=name,
            accepts_bulk_flow_update=True
        )
    ]

    def __init__(self, adapter_agent, config):
        self.adapter_agent = adapter_agent
        self.config = config
        self.descriptor = Adapter(
            id=self.name,
            vendor='Tibit Communications Inc.',
            version='0.1',
            config=AdapterConfig(log_level=LogLevel.INFO)
        )
        self.incoming_messages = DeferredQueue()
        self.mode = "GPON"

    def start(self):
        log.debug('starting')
        log.info('started')

    def stop(self):
        log.debug('stopping')
        log.info('stopped')

    def adapter_descriptor(self):
        return self.descriptor

    def device_types(self):
        return DeviceTypes(items=self.supported_device_types)

    def health(self):
        return HealthStatus(state=HealthStatus.HealthState.HEALTHY)

    def change_master_state(self, master):
        raise NotImplementedError()

    def update_pm_config(self, device, pm_configs):
        raise NotImplementedError()

    def adopt_device(self, device):
        log.info('adopt-device', device=device)
        reactor.callLater(0.1, self._onu_device_activation, device)
        return device

    def reconcile_device(self, device):
        raise NotImplementedError()

    @inlineCallbacks
    def _onu_device_activation(self, device):
        # first we verify that we got parent reference and proxy info
        assert device.parent_id
        assert device.proxy_address.device_id
        assert device.proxy_address.channel_id

        # Device information will be updated later on
        device.vendor = 'Tibit Communications, Inc.'
        device.model = '10G GPON ONU'
        device.connect_status = ConnectStatus.REACHABLE
        self.adapter_agent.update_device(device)

        # then shortly after we create some ports for the device
        uni_port = Port(
            port_no=2,
            label='UNI facing Ethernet port',
            type=Port.ETHERNET_UNI,
            admin_state=AdminState.ENABLED,
            oper_status=OperStatus.ACTIVE
        )
        self.adapter_agent.add_port(device.id, uni_port)
        self.adapter_agent.add_port(device.id, Port(
            port_no=1,
            label='PON port',
            type=Port.PON_ONU,
            admin_state=AdminState.ENABLED,
            oper_status=OperStatus.ACTIVE,
            peers=[
                Port.PeerPort(
                    device_id=device.parent_id,
                    port_no=device.parent_port_no
                )
            ]
        ))

        # TODO adding vports to the logical device shall be done by agent?
        # then we create the logical device port that corresponds to the UNI
        # port of the device

        # obtain logical device id
        parent_device = self.adapter_agent.get_device(device.parent_id)
        logical_device_id = parent_device.parent_id
        assert logical_device_id

        # we are going to use the proxy_address.channel_id as unique number
        # and name for the virtual ports, as this is guaranteed to be unique
        # in the context of the OLT port, so it is also unique in the context
        # of the logical device
        port_no = device.proxy_address.channel_id
        cap = OFPPF_10GB_FD | OFPPF_FIBER
        self.adapter_agent.add_logical_port(logical_device_id, LogicalPort(
            id=str(port_no),
            ofp_port=ofp_port(
                port_no=port_no,
                hw_addr=mac_str_to_tuple(device.mac_address),
                name='uni-{}'.format(port_no),
                config=0,
                state=OFPPS_LIVE,
                curr=cap,
                advertised=cap,
                peer=cap,
                curr_speed=OFPPF_10GB_FD,
                max_speed=OFPPF_10GB_FD
            ),
            device_id=device.id,
            device_port_no=uni_port.port_no
        ))

        # simulate a proxied message sending and receving a reply
        reply = yield self._message_exchange(device)

        # TODO - Need to add validation of reply and decide what to do upon failure

        # and finally update to "ACTIVE"
        device = self.adapter_agent.get_device(device.id)
        device.oper_status = OperStatus.ACTIVE
        self.adapter_agent.update_device(device)

        # TODO - Disable Stats Reporting for the moment
        #self.start_kpi_collection(device.id)

    def abandon_device(self, device):
        raise NotImplementedError(0
                                  )
    def disable_device(self, device):
        log.info('disabling', device_id=device.id)

        # Disable all ports on that device
        self.adapter_agent.disable_all_ports(device.id)

        # Update the device operational status to UNKNOWN
        device.oper_status = OperStatus.UNKNOWN
        device.connect_status = ConnectStatus.UNREACHABLE
        self.adapter_agent.update_device(device)

        # Remove the uni logical port from the OLT, if still present
        parent_device = self.adapter_agent.get_device(device.parent_id)
        assert parent_device
        logical_device_id = parent_device.parent_id
        assert logical_device_id
        port_no = device.proxy_address.channel_id
#        port_id = 'uni-{}'.format(port_no)
        port_id = '{}'.format(port_no)
        try:
            port = self.adapter_agent.get_logical_port(logical_device_id,
                                                       port_id)
            self.adapter_agent.delete_logical_port(logical_device_id, port)
        except KeyError:
            log.info('logical-port-not-found', device_id=device.id,
                     portid=port_id)

        # Remove pon port from parent
        #self.adapter_agent.delete_port_reference_from_parent(device.id,
        #                                                     self.pon_port)

        # Just updating the port status may be an option as well
        # port.ofp_port.config = OFPPC_NO_RECV
        # yield self.adapter_agent.update_logical_port(logical_device_id,
        #                                             port)
        # Unregister for proxied message
        self.adapter_agent.unregister_for_proxied_messages(device.proxy_address)

        # TODO:
        # 1) Remove all flows from the device
        # 2) Remove the device from ponsim

        log.info('disabled', device_id=device.id)

        return device

    def reenable_device(self, device):
        log.info('re-enabling', device_id=device.id)

        # First we verify that we got parent reference and proxy info
        assert device.parent_id
        assert device.proxy_address.device_id
        assert device.proxy_address.channel_id

        # Re-register for proxied messages right away
        #self.proxy_address = device.proxy_address
        self.adapter_agent.register_for_proxied_messages(device.proxy_address)

        # Re-enable the ports on that device
        self.adapter_agent.enable_all_ports(device.id)

        # Add the pon port reference to the parent
        #self.adapter_agent.add_port_reference_to_parent(device.id,
        #                                                self.pon_port)

        # Update the connect status to REACHABLE
        device.connect_status = ConnectStatus.REACHABLE
        self.adapter_agent.update_device(device)

        # re-add uni port to logical device
        parent_device = self.adapter_agent.get_device(device.parent_id)
        logical_device_id = parent_device.parent_id
        assert logical_device_id
        port_no = device.proxy_address.channel_id
        cap = OFPPF_10GB_FD | OFPPF_FIBER
        self.adapter_agent.add_logical_port(logical_device_id, LogicalPort(
#            id='uni-{}'.format(port_no),
            id= str(port_no),
            ofp_port=ofp_port(
                port_no=port_no,
                hw_addr=mac_str_to_tuple(device.mac_address),
                name='uni-{}'.format(port_no),
                config=0,
                state=OFPPS_LIVE,
                curr=cap,
                advertised=cap,
                peer=cap,
                curr_speed=OFPPF_10GB_FD,
                max_speed=OFPPF_10GB_FD
            ),
            device_id=device.id,
            device_port_no=2
        ))

        device = self.adapter_agent.get_device(device.id)
        device.oper_status = OperStatus.ACTIVE
        self.adapter_agent.update_device(device)

        log.info('re-enabled', device_id=device.id)


    @inlineCallbacks
    def reboot_device(self, device):
        log.info('Rebooting ONU: {}'.format(device.mac_address))

        # Update the operational status to ACTIVATING and connect status to
        # UNREACHABLE
        previous_oper_status = device.oper_status
        previous_conn_status = device.connect_status
        device.oper_status = OperStatus.ACTIVATING
        device.connect_status = ConnectStatus.UNREACHABLE
        self.adapter_agent.update_device(device)

        msg = (
            EOAMPayload() / EOAM_VendSpecificMsg(oui=CableLabs_OUI) /
            EOAM_DpoeMsg(dpoe_opcode = Dpoe_Opcodes["Set Request"],
                         body=DeviceReset())/
            EndOfPDU()
            )

        action = "Device Reset"

        # send message
        log.info('ONU-send-proxied-message to {} for ONU: {}'.format(action, device.mac_address))
        self.adapter_agent.send_proxied_message(device.proxy_address, msg)

        rc = []
        yield self._handle_set_resp(device, action, rc)

        # Change the operational status back to its previous state.
        device.oper_status = previous_oper_status
        device.connect_status = previous_conn_status
        self.adapter_agent.update_device(device)

        log.info('ONU Rebooted: {}'.format(device.mac_address))

    def download_image(self, device, request):
        raise NotImplementedError()

    def get_image_download_status(self, device, request):
        raise NotImplementedError()

    def cancel_image_download(self, device, request):
        raise NotImplementedError()

    def activate_image_update(self, device, request):
        raise NotImplementedError()

    def revert_image_update(self, device, request):
        raise NotImplementedError()

    def self_test_device(self, device):
        """
        This is called to Self a device based on a NBI call.
        :param device: A Voltha.Device object.
        :return: Will return result of self test
        """
        log.info('self-test-device', device=device.id)
        raise NotImplementedError()

    def delete_device(self, device):
        log.info('deleting', device_id=device.id)

        # A delete request may be received when an OLT is disabled

        # TODO:
        # 1) Remove all flows from the device
        # 2) Remove the device from ponsim

        log.info('deleted', device_id=device.id)

    def get_device_details(self, device):
        raise NotImplementedError()

    @inlineCallbacks
    def update_flows_bulk(self, device, flows, groups):
        log.info('########################################')
        log.info('bulk-flow-update', device_id=device.id,
                 flows=flows, groups=groups)
        assert len(groups.items) == 0, "Cannot yet deal with groups"

        # Only do something if there are flows to program
        if (len(flows.items) > 0):
            # Clear the existing entries in the Static MAC Address Table
            yield self._send_clear_static_mac_table(device)

            # Re-add the IGMP Multicast Address
            yield self._send_igmp_mcast_addr(device)

        Clause = {v: k for k, v in ClauseSubtypeEnum.iteritems()}
        Operator = {v: k for k, v in RuleOperatorEnum.iteritems()}

        for flow in flows.items:
            in_port = get_in_port(flow)
            assert in_port is not None

            precedence = 255 - min(flow.priority / 256, 255)

            if in_port == 2:
                log.info('#### Upstream Rule ####')


                up_req = UserPortObject()
                up_req /= PortIngressRuleHeader(precedence=precedence)

                for field in get_ofb_fields(flow):

                    if field.type == ETH_TYPE:
                        _type = field.eth_type
                        log.info('#### field.type == ETH_TYPE ####',field_type=_type)

                    elif field.type == IP_PROTO:
                        _proto = field.ip_proto
                        log.info('#### field.type == IP_PROTO ####')

                    elif field.type == IN_PORT:
                        _port = field.port
                        log.info('#### field.type == IN_PORT ####', port=_port)

                    elif field.type == VLAN_VID:
                        _vlan_vid = field.vlan_vid & 0xfff
                        log.info('#### field.type == VLAN_VID ####', vlan=_vlan_vid)
                        up_req /= PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,
                                                                     operator=Operator['=='], match=_vlan_vid)

                    elif field.type == VLAN_PCP:
                        _vlan_pcp = field.vlan_pcp
                        log.info('#### field.type == VLAN_PCP ####', pcp=_vlan_pcp)

                    elif field.type == UDP_DST:
                        _udp_dst = field.udp_dst
                        log.info('#### field.type == UDP_DST ####', udp_dst=_udp_dst)

                    elif field.type == IPV4_DST:
                        _ipv4_dst = field.ipv4_dst
                        log.info('#### field.type == IPV4_DST ####', ipv4_dst=_ipv4_dst)

                    elif field.type == METADATA:
                        _metadata = field.table_metadata
                        log.info('#### field.type == METADATA ####', metadata=_metadata)

                    else:
                        log.info('#### field.type == NOT IMPLEMENTED!! ####')
                        raise NotImplementedError('field.type={}'.format(
                            field.type))

                for action in get_actions(flow):

                    if action.type == OUTPUT:
                        log.info('#### action.type == OUTPUT ####')
                        up_req /= PortIngressRuleResultInsert(fieldcode=Clause['C-VLAN Tag'])

                    elif action.type == POP_VLAN:
                        log.info('#### action.type == POP_VLAN ####')

                    elif action.type == PUSH_VLAN:
                        log.info('#### action.type == PUSH_VLAN ####')
                        up_req /= PortIngressRuleResultInsert(fieldcode=Clause['C-VLAN Tag'])
#                        if action.push.ethertype != 0x8100:
#                            log.error('unhandled-tpid',
#                                      ethertype=action.push.ethertype)

                    elif action.type == SET_FIELD:
                        log.info('#### action.type == SET_FIELD ####')
                        assert (action.set_field.field.oxm_class ==
                                ofp.OFPXMC_OPENFLOW_BASIC)
                        field = action.set_field.field.ofb_field
                        if field.type == VLAN_VID:
                            log.info("#### action.field.vlan {} ####".format(field.vlan_vid & 0xfff))
                            up_req /= PortIngressRuleResultSet(
                                    fieldcode=Clause['C-VLAN Tag'], value=field.vlan_vid & 0xfff)
                        else:
                            log.error('unsupported-action-set-field-type',
                                      field_type=field.type)
                    else:
                        log.error('UNSUPPORTED-ACTION-TYPE',
                                  action_type=action.type)

                up_req /= PortIngressRuleTerminator()
                up_req /= AddPortIngressRule()

                msg = (
                    EOAMPayload() / EOAM_VendSpecificMsg(oui=CableLabs_OUI) /
                    EOAM_DpoeMsg(dpoe_opcode = Dpoe_Opcodes["Set Request"], body=up_req)/
                    EndOfPDU()
                )

                # send message
                action = "Set ONU US Rule"
                log.info('ONU-send-proxied-message to {} for ONU: {}'.format(action, device.mac_address))
                self.adapter_agent.send_proxied_message(device.proxy_address, msg)

                # Get and process the Set Response
                rc = []
                yield self._handle_set_resp(device, action, rc)


            elif in_port == 1:
                log.info('#### Downstream Rule ####')
                Is_MCast = False

                dn_req = PonPortObject()
                dn_req /= PortIngressRuleHeader(precedence=precedence)

                #### Loop through fields again...

                for field in get_ofb_fields(flow):

                    if field.type == ETH_TYPE:
                        _type = field.eth_type
                        log.info('#### field.type == ETH_TYPE ####', in_port=in_port,
                                 match=_type)

                    elif field.type == IP_PROTO:
                        _proto = field.ip_proto
                        log.info('#### field.type == IP_PROTO ####', in_port=in_port,
                                 ip_proto=_proto)

                    elif field.type == IN_PORT:
                        _port = field.port
                        log.info('#### field.type == IN_PORT ####')

                    elif field.type == VLAN_VID:
                        _vlan_vid = field.vlan_vid & 0xfff
                        log.info('#### field.type == VLAN_VID ####')

                    elif field.type == VLAN_PCP:
                        _vlan_pcp = field.vlan_pcp
                        log.info('#### field.type == VLAN_PCP ####')

                    elif field.type == UDP_DST:
                        _udp_dst = field.udp_dst
                        log.info('#### field.type == UDP_DST ####')

                    elif field.type == IPV4_DST:
                        _ipv4_dst = field.ipv4_dst
                        log.info('#### field.type == IPV4_DST ####')
                        a = int(hex(_ipv4_dst)[2:4], 16)
                        b = int(hex(_ipv4_dst)[4:6], 16)
                        c = int(hex(_ipv4_dst)[6:8], 16)
                        d = int(hex(_ipv4_dst)[8:], 16)
                        dn_req = AddStaticMacAddress(mac=mcastIp2McastMac('%d.%d.%d.%d' % (a,b,c,d)))
                        Is_MCast = True

                    else:
                        raise NotImplementedError('field.type={}'.format(
                            field.type))

                for action in get_actions(flow):

                    if action.type == OUTPUT:
                        log.info('#### action.type == OUTPUT ####')

                    elif action.type == POP_VLAN:
                        log.info('#### action.type == POP_VLAN ####')
                        dn_req /= PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,
                                                                     operator=Operator['=='], match=_vlan_vid)
                        dn_req /= PortIngressRuleResultReplace(fieldcode=Clause['C-VLAN Tag'])
                        dn_req /= PortIngressRuleResultSet(
                                fieldcode=Clause['C-VLAN Tag'], value=field.vlan_vid & 0xfff)

                    elif action.type == PUSH_VLAN:
                        log.info('#### action.type == PUSH_VLAN ####')
                        if action.push.ethertype != 0x8100:
                            log.error('unhandled-ether-type',
                                      ethertype=action.push.ethertype)

                    elif action.type == SET_FIELD:
                        log.info('#### action.type == SET_FIELD ####')
                        assert (action.set_field.field.oxm_class ==
                                ofp.OFPXMC_OPENFLOW_BASIC)
                        field = action.set_field.field.ofb_field
                        if field.type == VLAN_VID:
                            dn_req /= PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,
                                                                         operator=Operator['=='], match=_vlan_vid)
                            dn_req /= PortIngressRuleResultReplace(fieldcode=Clause['C-VLAN Tag'])
                            dn_req /= PortIngressRuleResultSet(
                                    fieldcode=Clause['C-VLAN Tag'], value=field.vlan_vid & 0xfff)
                        else:
                            log.error('unsupported-action-set-field-type',
                                      field_type=field.type)

                    else:
                        log.error('UNSUPPORTED-ACTION-TYPE',
                                  action_type=action.type)

                if Is_MCast is True:
                    action = "Set Static IP MCAST address"
                else:
                    dn_req /= PortIngressRuleTerminator()
                    dn_req /= AddPortIngressRule()
                    action = "Set ONU DS Rule"

                msg = (
                    EOAMPayload() / EOAM_VendSpecificMsg(oui=CableLabs_OUI) /
                    EOAM_DpoeMsg(dpoe_opcode = Dpoe_Opcodes["Set Request"], body=dn_req)/
                    EndOfPDU()
                )

                # send message
                log.info('ONU-send-proxied-message to {} for ONU: {}'.format(action, device.mac_address))
                self.adapter_agent.send_proxied_message(device.proxy_address, msg)

                # Get and process the Set Response
                rc = []
                yield self._handle_set_resp(device, action, rc)

            else:
                raise Exception('Port should be 1 or 2 by our convention')

        log.info('bulk-flow-update finished', device_id=device.id,
                 flows=flows, groups=groups)
        log.info('########################################')

    def update_flows_incrementally(self, device, flow_changes, group_changes):
        raise NotImplementedError()

    def send_proxied_message(self, proxy_address, msg):
        raise NotImplementedError()

    def receive_proxied_message(self, proxy_address, msg):
        log.info('receive-proxied-message',
                  proxy_address=proxy_address, msg=msg.show(dump=True))
        self.incoming_messages.put(msg)

    def create_interface(self, device, data):
        raise NotImplementedError()

    def update_interface(self, device, data):
        raise NotImplementedError()

    def remove_interface(self, device, data):
        raise NotImplementedError()

    def receive_onu_detect_state(self, device_id, state):
        raise NotImplementedError()

    def create_tcont(self, device, tcont_data, traffic_descriptor_data):
        raise NotImplementedError()

    def update_tcont(self, device, tcont_data, traffic_descriptor_data):
        raise NotImplementedError()

    def remove_tcont(self, device, tcont_data, traffic_descriptor_data):
        raise NotImplementedError()

    def create_gemport(self, device, data):
        raise NotImplementedError()

    def update_gemport(self, device, data):
        raise NotImplementedError()

    def remove_gemport(self, device, data):
        raise NotImplementedError()

    def create_multicast_gemport(self, device, data):
        raise NotImplementedError()

    def update_multicast_gemport(self, device, data):
        raise NotImplementedError()

    def remove_multicast_gemport(self, device, data):
        raise NotImplementedError()

    def create_multicast_distribution_set(self, device, data):
        raise NotImplementedError()

    def update_multicast_distribution_set(self, device, data):
        raise NotImplementedError()

    def remove_multicast_distribution_set(self, device, data):
        raise NotImplementedError()

    @inlineCallbacks
    def _message_exchange(self, device):

        # register for receiving async messages
        self.adapter_agent.register_for_proxied_messages(device.proxy_address)

        # reset incoming message queue
        while self.incoming_messages.pending:
            _ = yield self.incoming_messages.get()

        # send out ping frame to ONU device get device information
        ping_frame = (
            EOAMPayload() / EOAM_VendSpecificMsg(oui=CableLabs_OUI) /
            EOAM_DpoeMsg(dpoe_opcode=Dpoe_Opcodes["Get Request"],
                         body=VendorName() /
                              OnuMode() /
                              HardwareVersion() /
                              ManufacturerInfo()
                              ) /
            EndOfPDU()
            )

        log.info('ONU-send-proxied-message to Get Version Info for ONU: {}'.format(device.mac_address))
        self.adapter_agent.send_proxied_message(device.proxy_address, ping_frame)

        # Loop until we have a Get Response
        ack = False
        while not ack:
            frame = yield self.incoming_messages.get()

            respType = get_oam_msg_type(log, frame)

            if (respType == RxedOamMsgTypeEnum["DPoE Get Response"]):
                ack = True
            else:
                # Handle unexpected events/OMCI messages
                check_resp(log, frame)

        if ack:
            log.info('ONU-response received for Get Version Info for ONU: {}'.format(device.mac_address))

            self._process_ping_frame_response(device, frame)


        if self.mode.upper()[0] == "G":  # GPON

            hw_vers = int(device.hardware_version, 16)

            if hw_vers >= 0x170618:
                mcastLidx = 0x04bc
            elif hw_vers >= 0x170517:
                mcastLidx = 0x14bc
            else:
                mcastLidx = 0x10bc

            log.info("Using Multicast LIDX {:04X}".format(mcastLidx))

            # construct multicast LLID set
            msg = (
                EOAMPayload() / EOAM_VendSpecificMsg(oui=CableLabs_OUI) /
                EOAM_DpoeMsg(dpoe_opcode=Dpoe_Opcodes["Multicast Register"],body=MulticastRegisterSet(MulticastLink=mcastLidx, UnicastLink=0)
                ))

            # send message
            log.info('ONU-send-proxied-message to Multicast Register Set for ONU: {}'.format(device.mac_address))
            self.adapter_agent.send_proxied_message(device.proxy_address, msg)

            # The MulticastRegisterSet does not currently return a response. Just hope it worked.

        # by returning we allow the device to be shown as active, which
        # indirectly verified that message passing works

    def receive_packet_out(self, logical_device_id, egress_port_no, msg):
        log.info('packet-out', logical_device_id=logical_device_id,
                 egress_port_no=egress_port_no, msg_len=len(msg))

    def receive_inter_adapter_message(self, msg):
        raise NotImplementedError()

    def suppress_alarm(self, filter):
        raise NotImplementedError()

    def unsuppress_alarm(self, filter):
        raise NotImplementedError()

    def start_kpi_collection(self, device_id):

        """TMP Simulate periodic KPI metric collection from the device"""
        import random

        @inlineCallbacks  # pretend that we need to do async calls
        def _collect(device_id, prefix):

            try:
                # Step 1: gather metrics from device (pretend it here) - examples
                uni_port_metrics = yield dict(
                    tx_pkts=random.randint(0, 100),
                    rx_pkts=random.randint(0, 100),
                    tx_bytes=random.randint(0, 100000),
                    rx_bytes=random.randint(0, 100000),
                )
                pon_port_metrics = yield dict(
                    tx_pkts=uni_port_metrics['rx_pkts'],
                    rx_pkts=uni_port_metrics['tx_pkts'],
                    tx_bytes=uni_port_metrics['rx_bytes'],
                    rx_bytes=uni_port_metrics['tx_bytes'],
                )
                onu_metrics = yield dict(
                    cpu_util=20 + 5 * random.random(),
                    buffer_util=10 + 10 * random.random()
                )

                # Step 2: prepare the KpiEvent for submission
                # we can time-stamp them here (or could use time derived from OLT
                ts = arrow.utcnow().timestamp
                kpi_event = KpiEvent(
                    type=KpiEventType.slice,
                    ts=ts,
                    prefixes={
                        # OLT-level
                        prefix: MetricValuePairs(metrics=onu_metrics),
                        # OLT NNI port
                        prefix + '.nni': MetricValuePairs(metrics=uni_port_metrics),
                        # OLT PON port
                        prefix + '.pon': MetricValuePairs(metrics=pon_port_metrics)
                    }
                )

                # Step 3: submit
                self.adapter_agent.submit_kpis(kpi_event)

            except Exception as e:
                log.exception('failed-to-submit-kpis', e=e)

        prefix = 'voltha.{}.{}'.format(self.name, device_id)
        lc = LoopingCall(_collect, device_id, prefix)
        lc.start(interval=15)  # TODO make this configurable


# Methods for Get / Set  Response Processing from eoam_messages

    @inlineCallbacks
    def _send_igmp_mcast_addr(self, device):
        # construct install of igmp query address
        msg = (
            EOAMPayload() / EOAM_VendSpecificMsg(oui=CableLabs_OUI) /
            EOAM_DpoeMsg(dpoe_opcode=Dpoe_Opcodes["Set Request"],body=AddStaticMacAddress(mac='01:00:5e:00:00:01')
            ))

        action = "Set Static IGMP MAC address"

        # send message
        log.info('ONU-send-proxied-message to {} for ONU: {}'.format(action, device.mac_address))
        self.adapter_agent.send_proxied_message(device.proxy_address, msg)

        rc = []
        yield self._handle_set_resp(device, action, rc)


    @inlineCallbacks
    def _send_clear_static_mac_table(self, device):
        # construct install of igmp query address
        msg = (
            EOAMPayload() / EOAM_VendSpecificMsg(oui=CableLabs_OUI) /
            EOAM_DpoeMsg(dpoe_opcode=Dpoe_Opcodes["Set Request"],body=ClearStaticMacTable()
            ))

        action = "Clear Static MAC Table"

        # send message
        log.info('ONU-send-proxied-message to {} for ONU: {}'.format(action, device.mac_address))
        self.adapter_agent.send_proxied_message(device.proxy_address, msg)

        rc = []
        yield self._handle_set_resp(device, action, rc)


    @inlineCallbacks
    def _handle_set_resp(self, device, action, retcode):
        # Get and process the Set Response
        ack = False
        start_time = time.time()

        # Loop until we have a set response or timeout
        while not ack:
            frame = yield self.incoming_messages.get()
            #TODO - Need to add propoer timeout functionality
            #if (time.time() - start_time) > TIBIT_MSG_WAIT_TIME or (frame is None):
            #    break  # don't wait forever

            respType = get_oam_msg_type(log, frame)

            #Check that the message received is a Set Response
            if (respType == RxedOamMsgTypeEnum["DPoE Set Response"]):
                ack = True
            else:
                log.info('Received Unexpected OAM Message 0x{:X} while waiting for Set Resp for {}'.format(respType,action))
                # Handle unexpected events/OMCI messages
                check_resp(log, frame)

        # Verify Set Response
        rc = False
        if ack:
            (rc,branch,leaf,status) = check_set_resp(log, frame)
            if (rc is False):
                log.info('Set Response had errors - Branch 0x{:X} Leaf 0x{:0>4X} {}'.format(branch, leaf, DPoEVariableResponseCodes[status]))

        if (rc is True):
            log.info('ONU-response received for {} for ONU: {}'.format(action, device.mac_address))
        else:
            log.info('BAD ONU-response received for {} for ONU: {}'.format(action, device.mac_address))

        retcode.append(rc)

    def _process_ping_frame_response(self, device, frame):

        vendor = [0xD7, 0x0011]
        ponMode = [0xB7, 0x0105]
        hw_version = [0xD7, 0x0013]
        manufacturer =  [0xD7, 0x0006]
        branch_leaf_pairs = [vendor, ponMode, hw_version, manufacturer]

        for pair in branch_leaf_pairs:
            temp_pair = pair
            (rc, value) = (get_value_from_msg(log, frame, pair[0], pair[1]))
            temp_pair.append(rc)
            temp_pair.append(value)
            if rc:
                overall_rc = True
            else:
                log.info('Failed to get valid response for Branch 0x{:X} Leaf 0x{:0>4X} '.format(temp_pair[0], temp_pair[1]))
                ack = True

        if vendor[rc]:
            device.vendor = vendor.pop()
            if device.vendor.endswith(''):
                device.vendor = device.vendor[:-1]
        else:
            device.vendor = "UNKNOWN"

        # mode: 3 = EPON OLT, 7 = GPON OLT
        # mode: 2 = EPON ONU, 6 = GPON ONU
        if ponMode[rc]:
            value = ponMode.pop()
            mode = "UNKNOWN"
            self.mode = "UNKNOWN"

            if value == 6:
                mode = "10G GPON ONU"
                self.mode = "GPON"
            if value == 2:
                mode = "10G EPON ONU"
                self.mode = "EPON"
            if value == 1:
                mode = "10G Point to Point"
                self.mode = "Unsupported"

            device.model = mode

        else:
            device.model = "UNKNOWN"
            self.mode = "UNKNOWN"

        log.info("PON Mode is {}".format(self.mode))

        if hw_version[rc]:
            device.hardware_version = hw_version.pop()
            device.hardware_version = device.hardware_version.replace("FA","")
            if device.hardware_version.endswith(''):
                device.hardware_version = device.hardware_version[:-1]
        else:
            device.hardware_version = "UNKNOWN"

        if manufacturer[rc]:
            manu_value = manufacturer.pop()
            device.firmware_version = re.search('\Firmware: (.+?) ', manu_value).group(1)
            image_1 = Image(version = \
                                    re.search('\Build: (.+?) ', manu_value).group(1))
            device.images.image.extend([ image_1 ])
            device.serial_number = re.search('\Serial #: (.+?) ', manu_value).group(1)
        else:
            device.firmware_version = "UNKNOWN"
            image_1 = Image(version="UNKNOWN")
            device.images.image.extend([ image_1 ])
            device.serial_number = "UNKNOWN"

        device.connect_status = ConnectStatus.REACHABLE
Example #20
0
class DPoEOnuAdapter(object):

    name = 'dpoe_onu'

    supported_device_types = [
        DeviceType(id='dpoe_onu', adapter=name, accepts_bulk_flow_update=True)
    ]

    def __init__(self, adapter_agent, config):
        self.adapter_agent = adapter_agent
        self.config = config
        self.descriptor = Adapter(
            id=self.name,
            vendor='Sumitomo Electric, Inc.',
            version='0.1',
            config=AdapterConfig(log_level=LogLevel.INFO))
        self.incoming_messages = DeferredQueue()

    def start(self):
        log.debug('starting')
        log.info('started')

    def stop(self):
        log.debug('stopping')
        log.info('stopped')

    def adapter_descriptor(self):
        return self.descriptor

    def device_types(self):
        return DeviceTypes(items=self.supported_device_types)

    def health(self):
        return HealthStatus(state=HealthStatus.HealthState.HEALTHY)

    def change_master_state(self, master):
        raise NotImplementedError()

    def update_pm_config(self, device, pm_configs):
        raise NotImplementedError()

    def adopt_device(self, device):
        log.info('adopt-device', device=device)
        reactor.callLater(0.1, self._onu_device_activation, device)
        return device

    def reconcile_device(self, device):
        raise NotImplementedError()

    @inlineCallbacks
    def _onu_device_activation(self, device):
        # first we verify that we got parent reference and proxy info
        assert device.parent_id
        assert device.proxy_address.device_id
        assert device.proxy_address.channel_id

        # TODO: For now, pretend that we were able to contact the device and obtain
        # additional information about it.  Should add real message.
        device.vendor = 'Sumitomo Electric, Inc.'
        device.model = '10G EPON ONU'
        device.hardware_version = 'fa161020'
        device.firmware_version = '16.12.02'

        # There could be multiple software versions on the device (one active, other
        # standby etc.). Look for simulated_olt for example implementation.
        device.images.image.extend([Image(version="1.0")])
        device.serial_number = uuid4().hex
        device.connect_status = ConnectStatus.REACHABLE
        self.adapter_agent.update_device(device)

        # then shortly after we create some ports for the device
        uni_port = Port(port_no=2,
                        label='UNI facing Ethernet port',
                        type=Port.ETHERNET_UNI,
                        admin_state=AdminState.ENABLED,
                        oper_status=OperStatus.ACTIVE)
        self.adapter_agent.add_port(device.id, uni_port)
        self.adapter_agent.add_port(
            device.id,
            Port(port_no=1,
                 label='PON port',
                 type=Port.PON_ONU,
                 admin_state=AdminState.ENABLED,
                 oper_status=OperStatus.ACTIVE,
                 peers=[
                     Port.PeerPort(device_id=device.parent_id,
                                   port_no=device.parent_port_no)
                 ]))

        # TODO adding vports to the logical device shall be done by agent?
        # then we create the logical device port that corresponds to the UNI
        # port of the device

        # obtain logical device id
        parent_device = self.adapter_agent.get_device(device.parent_id)
        logical_device_id = parent_device.parent_id
        assert logical_device_id

        # we are going to use the proxy_address.channel_id as unique number
        # and name for the virtual ports, as this is guaranteed to be unique
        # in the context of the OLT port, so it is also unique in the context
        # of the logical device
        port_no = device.proxy_address.channel_id
        cap = OFPPF_10GB_FD | OFPPF_FIBER
        self.adapter_agent.add_logical_port(
            logical_device_id,
            LogicalPort(id=str(port_no),
                        ofp_port=ofp_port(port_no=port_no,
                                          hw_addr=mac_str_to_tuple(
                                              device.mac_address),
                                          name='uni-{}'.format(port_no),
                                          config=0,
                                          state=OFPPS_LIVE,
                                          curr=cap,
                                          advertised=cap,
                                          peer=cap,
                                          curr_speed=OFPPF_10GB_FD,
                                          max_speed=OFPPF_10GB_FD),
                        device_id=device.id,
                        device_port_no=uni_port.port_no))

        # simulate a proxied message sending and receving a reply
        reply = yield self._message_exchange(device)

        # and finally update to "ACTIVE"
        device = self.adapter_agent.get_device(device.id)
        device.oper_status = OperStatus.ACTIVE
        self.adapter_agent.update_device(device)

    def abandon_device(self, device):
        raise NotImplementedError(0)

    def disable_device(self, device):
        raise NotImplementedError()

    def reenable_device(self, device):
        raise NotImplementedError()

    def reboot_device(self, device):
        raise NotImplementedError()

    def download_image(self, device, request):
        raise NotImplementedError()

    def get_image_download_status(self, device, request):
        raise NotImplementedError()

    def cancel_image_download(self, device, request):
        raise NotImplementedError()

    def activate_image_update(self, device, request):
        raise NotImplementedError()

    def revert_image_update(self, device, request):
        raise NotImplementedError()

    def self_test_device(self, device):
        """
        This is called to Self a device based on a NBI call.
        :param device: A Voltha.Device object.
        :return: Will return result of self test
        """
        log.info('self-test-device', device=device.id)
        raise NotImplementedError()

    def delete_device(self, device):
        raise NotImplementedError()

    def get_device_details(self, device):
        raise NotImplementedError()

    def update_flows_bulk(self, device, flows, groups):
        log.info('########################################')
        log.info('bulk-flow-update',
                 device_id=device.id,
                 flows=flows,
                 groups=groups)
        assert len(groups.items) == 0, "Cannot yet deal with groups"

        Clause = {v: k for k, v in ClauseSubtypeEnum.iteritems()}
        Operator = {v: k for k, v in RuleOperatorEnum.iteritems()}

        for flow in flows.items:
            in_port = get_in_port(flow)
            assert in_port is not None

            precedence = 255 - min(flow.priority / 256, 255)

            if in_port == 2:
                log.info('#### Downstream Rule ####')
                dn_req = EOAMPayload(body=CablelabsOUI() /
                                     DPoEOpcode_SetRequest())

                for field in get_ofb_fields(flow):

                    if field.type == ETH_TYPE:
                        _type = field.eth_type
                        log.info('#### field.type == ETH_TYPE ####',
                                 field_type=_type)

                    elif field.type == IP_PROTO:
                        _proto = field.ip_proto
                        log.info('#### field.type == IP_PROTO ####')
                        pass  # construct ip_proto based condition here

                    elif field.type == IN_PORT:
                        _port = field.port
                        log.info('#### field.type == IN_PORT ####', port=_port)
                        pass  # construct in_port based condition here

                    elif field.type == VLAN_VID:
                        _vlan_vid = field.vlan_vid & 0xfff
                        log.info('#### field.type == VLAN_VID ####',
                                 vlan=_vlan_vid)

                    elif field.type == VLAN_PCP:
                        _vlan_pcp = field.vlan_pcp
                        log.info('#### field.type == VLAN_PCP ####',
                                 pcp=_vlan_pcp)
                        pass  # construct VLAN PCP based filter condition here

                    elif field.type == UDP_DST:
                        _udp_dst = field.udp_dst
                        log.info('#### field.type == UDP_DST ####')
                        pass  # construct UDP SDT based filter here

                    elif field.type == IPV4_DST:
                        _ipv4_dst = field.ipv4_dst
                        log.info('#### field.type == IPV4_DST ####')
                        pass

                    else:
                        log.info('#### field.type == NOT IMPLEMENTED!! ####')
                        raise NotImplementedError('field.type={}'.format(
                            field.type))

                for action in get_actions(flow):

                    if action.type == OUTPUT:
                        log.info('#### action.type == OUTPUT ####')

                    elif action.type == POP_VLAN:
                        log.info('#### action.type == POP_VLAN ####')
                        pass  # construct vlan pop command here

                    elif action.type == PUSH_VLAN:
                        log.info('#### action.type == PUSH_VLAN ####')
                        if action.push.ethertype != 0x8100:
                            log.error('unhandled-tpid',
                                      ethertype=action.push.ethertype)

                    elif action.type == SET_FIELD:
                        log.info('#### action.type == SET_FIELD ####')
                        assert (action.set_field.field.oxm_class ==
                                ofp.OFPXMC_OPENFLOW_BASIC)
                        field = action.set_field.field.ofb_field
                        if field.type == VLAN_VID:
                            pass
                        else:
                            log.error('unsupported-action-set-field-type',
                                      field_type=field.type)
                    else:
                        log.error('UNSUPPORTED-ACTION-TYPE',
                                  action_type=action.type)

                # send message
                log.info('ONU-send-proxied-message')
#                self.adapter_agent.send_proxied_message(device.proxy_address, dn_req)

            elif in_port == 1:
                # Upstream rule
                log.info('#### Upstream Rule ####')

                #### Loop through fields again...

                for field in get_ofb_fields(flow):

                    if field.type == ETH_TYPE:
                        _type = field.eth_type
                        log.info('#### field.type == ETH_TYPE ####',
                                 in_port=in_port,
                                 match=_type)

                    elif field.type == IP_PROTO:
                        _proto = field.ip_proto
                        log.info('#### field.type == IP_PROTO ####',
                                 in_port=in_port,
                                 ip_proto=ip_proto)

                    elif field.type == IN_PORT:
                        _port = field.port
                        log.info('#### field.type == IN_PORT ####')
                        pass  # construct in_port based condition here

                    elif field.type == VLAN_VID:
                        _vlan_vid = field.vlan_vid & 0xfff
                        log.info('#### field.type == VLAN_VID ####')

                    elif field.type == VLAN_PCP:
                        _vlan_pcp = field.vlan_pcp
                        log.info('#### field.type == VLAN_PCP ####')
                        pass  # construct VLAN PCP based filter condition here

                    elif field.type == UDP_DST:
                        _udp_dst = field.udp_dst
                        log.info('#### field.type == UDP_DST ####')

                    else:
                        raise NotImplementedError('field.type={}'.format(
                            field.type))

                for action in get_actions(flow):

                    if action.type == OUTPUT:
                        log.info('#### action.type == OUTPUT ####')

                    elif action.type == POP_VLAN:
                        log.info('#### action.type == POP_VLAN ####')
                        pass  # construct vlan pop command here

                    elif action.type == PUSH_VLAN:
                        log.info('#### action.type == PUSH_VLAN ####')
                        if action.push.ethertype != 0x8100:
                            log.error('unhandled-ether-type',
                                      ethertype=action.push.ethertype)

                    elif action.type == SET_FIELD:
                        log.info('#### action.type == SET_FIELD ####')
                        assert (action.set_field.field.oxm_class ==
                                ofp.OFPXMC_OPENFLOW_BASIC)
                        field = action.set_field.field.ofb_field
                        if field.type == VLAN_VID:
                            pass
                        else:
                            log.error('unsupported-action-set-field-type',
                                      field_type=field.type)

                    else:
                        log.error('UNSUPPORTED-ACTION-TYPE',
                                  action_type=action.type)

            else:
                raise Exception('Port should be 1 or 2 by our convention')

    def update_flows_incrementally(self, device, flow_changes, group_changes):
        raise NotImplementedError()

    def send_proxied_message(self, proxy_address, msg):
        raise NotImplementedError()

    def receive_proxied_message(self, proxy_address, msg):
        log.debug('receive-proxied-message',
                  proxy_address=proxy_address,
                  msg=msg)
        self.incoming_messages.put(msg)

    def create_interface(self, device, data):
        raise NotImplementedError()

    def update_interface(self, device, data):
        raise NotImplementedError()

    def remove_interface(self, device, data):
        raise NotImplementedError()

    def receive_onu_detect_state(self, device_id, state):
        raise NotImplementedError()

    def create_tcont(self, device, tcont_data, traffic_descriptor_data):
        raise NotImplementedError()

    def update_tcont(self, device, tcont_data, traffic_descriptor_data):
        raise NotImplementedError()

    def remove_tcont(self, device, tcont_data, traffic_descriptor_data):
        raise NotImplementedError()

    def create_gemport(self, device, data):
        raise NotImplementedError()

    def update_gemport(self, device, data):
        raise NotImplementedError()

    def remove_gemport(self, device, data):
        raise NotImplementedError()

    def create_multicast_gemport(self, device, data):
        raise NotImplementedError()

    def update_multicast_gemport(self, device, data):
        raise NotImplementedError()

    def remove_multicast_gemport(self, device, data):
        raise NotImplementedError()

    def create_multicast_distribution_set(self, device, data):
        raise NotImplementedError()

    def update_multicast_distribution_set(self, device, data):
        raise NotImplementedError()

    def remove_multicast_distribution_set(self, device, data):
        raise NotImplementedError()

    def suppress_alarm(self, filter):
        raise NotImplementedError()

    def unsuppress_alarm(self, filter):
        raise NotImplementedError()

    @inlineCallbacks
    def _message_exchange(self, device):

        # register for receiving async messages
        self.adapter_agent.register_for_proxied_messages(device.proxy_address)

        # reset incoming message queue
        while self.incoming_messages.pending:
            _ = yield self.incoming_messages.get()

        # construct message
        msg = EOAMPayload(body=CablelabsOUI() / DPoEOpcode_GetRequest() /
                          DeviceId())

        # send message
        log.info('ONU-send-proxied-message')
        self.adapter_agent.send_proxied_message(device.proxy_address, msg)

        # wait till we detect incoming message
        yield self.incoming_messages.get()

        # construct install of igmp query address
        msg = EOAMPayload(body=CablelabsOUI() / DPoEOpcode_SetRequest() /
                          AddStaticMacAddress(mac='01:00:5e:00:00:01'))

        # send message
        log.info('ONU-send-proxied-message')
        self.adapter_agent.send_proxied_message(device.proxy_address, msg)

        # wait till we detect incoming message
        yield self.incoming_messages.get()

        # construct install of igmp query address
        msg = EOAMPayload(body=CablelabsOUI() / DPoEOpcode_GetRequest() /
                          FirmwareInfo())

        # send message
        log.info('ONU-send-proxied-message')
        self.adapter_agent.send_proxied_message(device.proxy_address, msg)

        # wait till we detect incoming message
        yield self.incoming_messages.get()

        # by returning we allow the device to be shown as active, which
        # indirectly verified that message passing works

    def receive_packet_out(self, logical_device_id, egress_port_no, msg):
        log.info('packet-out',
                 logical_device_id=logical_device_id,
                 egress_port_no=egress_port_no,
                 msg_len=len(msg))

    def receive_inter_adapter_message(self, msg):
        raise NotImplementedError()
Example #21
0
class BrcmOpenomciOnuAdapter(object):

    name = 'brcm_openomci_onu'

    supported_device_types = [
        DeviceType(id=name,
                   vendor_ids=[
                       'OPEN', 'ALCL', 'BRCM', 'TWSH', 'ALPH', 'ISKT', 'SFAA',
                       'BBSM'
                   ],
                   adapter=name,
                   accepts_bulk_flow_update=True)
    ]

    def __init__(self, adapter_agent, config):
        log.debug('function-entry', config=config)
        self.adapter_agent = adapter_agent
        self.config = config
        self.descriptor = Adapter(
            id=self.name,
            vendor='Voltha project',
            version='0.50',
            config=AdapterConfig(log_level=LogLevel.INFO))
        self.devices_handlers = dict()

        # Customize OpenOMCI for Broadcom ONUs
        self.broadcom_omci = deepcopy(OpenOmciAgentDefaults)

        self.broadcom_omci['mib-synchronizer'][
            'state-machine'] = BrcmMibSynchronizer
        self.broadcom_omci['omci-capabilities']['tasks'][
            'get-capabilities'] = BrcmCapabilitiesTask

        # Defer creation of omci agent to a lazy init that allows subclasses to override support classes

        # register for adapter messages
        self.adapter_agent.register_for_inter_adapter_messages()

    def custom_me_entities(self):
        return None

    @property
    def omci_agent(self):
        if not hasattr(self, '_omci_agent') or self._omci_agent is None:
            log.debug('creating-omci-agent')
            self._omci_agent = OpenOMCIAgent(
                self.adapter_agent.core, support_classes=self.broadcom_omci)
        return self._omci_agent

    def start(self):
        log.debug('starting')
        self.omci_agent.start()
        log.info('started')

    def stop(self):
        log.debug('stopping')

        omci, self._omci_agent = self._omci_agent, None
        if omci is not None:
            self._omci_agent.stop()

        log.info('stopped')

    def adapter_descriptor(self):
        return self.descriptor

    def device_types(self):
        return DeviceTypes(items=self.supported_device_types)

    def health(self):
        return HealthStatus(state=HealthStatus.HealthState.HEALTHY)

    def change_master_state(self, master):
        raise NotImplementedError()

    def adopt_device(self, device):
        log.info('adopt_device', device_id=device.id)
        self.devices_handlers[device.id] = BrcmOpenomciOnuHandler(
            self, device.id)
        reactor.callLater(0, self.devices_handlers[device.id].activate, device)
        return device

    def reconcile_device(self, device):
        log.info('reconcile-device', device_id=device.id)
        self.devices_handlers[device.id] = BrcmOpenomciOnuHandler(
            self, device.id)
        reactor.callLater(0, self.devices_handlers[device.id].reconcile,
                          device)

    def abandon_device(self, device):
        raise NotImplementedError()

    def disable_device(self, device):
        log.info('disable-onu-device', device_id=device.id)
        if device.id in self.devices_handlers:
            handler = self.devices_handlers[device.id]
            if handler is not None:
                handler.disable(device)

    def reenable_device(self, device):
        log.info('reenable-onu-device', device_id=device.id)
        if device.id in self.devices_handlers:
            handler = self.devices_handlers[device.id]
            if handler is not None:
                handler.reenable(device)

    def reboot_device(self, device):
        log.info('reboot-device', device_id=device.id)
        if device.id in self.devices_handlers:
            handler = self.devices_handlers[device.id]
            if handler is not None:
                handler.reboot()

    def download_image(self, device, request):
        raise NotImplementedError()

    def get_image_download_status(self, device, request):
        raise NotImplementedError()

    def cancel_image_download(self, device, request):
        raise NotImplementedError()

    def activate_image_update(self, device, request):
        raise NotImplementedError()

    def revert_image_update(self, device, request):
        raise NotImplementedError()

    def self_test_device(self, device):
        """
        This is called to Self a device based on a NBI call.
        :param device: A Voltha.Device object.
        :return: Will return result of self test
        """
        log.info('self-test-device - Not implemented yet', device=device.id)
        raise NotImplementedError()

    def delete_device(self, device):
        log.info('delete-device', device_id=device.id)
        if device.id in self.devices_handlers:
            handler = self.devices_handlers[device.id]
            if handler is not None:
                handler.delete(device)
            del self.devices_handlers[device.id]
        return

    def get_device_details(self, device):
        raise NotImplementedError()

    # TODO(smbaker): When BrcmOpenomciOnuAdapter is updated to inherit from OnuAdapter, this function can be deleted
    def update_pm_config(self, device, pm_config):
        log.info("adapter-update-pm-config",
                 device=device,
                 pm_config=pm_config)
        handler = self.devices_handlers[device.id]
        handler.update_pm_config(device, pm_config)

    def update_flows_bulk(self, device, flows, groups):
        '''
        log.info('bulk-flow-update', device_id=device.id,
                  flows=flows, groups=groups)
        '''
        assert len(groups.items) == 0
        handler = self.devices_handlers[device.id]
        return handler.update_flow_table(device, flows.items)

    def update_flows_incrementally(self, device, flow_changes, group_changes):
        raise NotImplementedError()

    def send_proxied_message(self, proxy_address, msg):
        log.debug('send-proxied-message', proxy_address=proxy_address, msg=msg)

    def receive_proxied_message(self, proxy_address, msg):
        log.debug('receive-proxied-message',
                  proxy_address=proxy_address,
                  device_id=proxy_address.device_id,
                  msg=hexify(msg))
        # Device_id from the proxy_address is the olt device id. We need to
        # get the onu device id using the port number in the proxy_address
        device = self.adapter_agent. \
            get_child_device_with_proxy_address(proxy_address)
        if device:
            handler = self.devices_handlers[device.id]
            handler.receive_message(msg)

    def receive_packet_out(self, logical_device_id, egress_port_no, msg):
        log.info('packet-out',
                 logical_device_id=logical_device_id,
                 egress_port_no=egress_port_no,
                 msg_len=len(msg))

    def receive_inter_adapter_message(self, msg):
        log.debug('receive_inter_adapter_message', msg=msg)
        proxy_address = msg['proxy_address']
        assert proxy_address is not None
        # Device_id from the proxy_address is the olt device id. We need to
        # get the onu device id using the port number in the proxy_address
        device = self.adapter_agent. \
            get_child_device_with_proxy_address(proxy_address)
        if device:
            handler = self.devices_handlers[device.id]
            handler.event_messages.put(msg)
        else:
            log.error("device-not-found")

    def create_interface(self, device, data):
        log.debug('create-interface', device_id=device.id)
        if device.id in self.devices_handlers:
            handler = self.devices_handlers[device.id]
            if handler is not None:
                handler.create_interface(data)

    def update_interface(self, device, data):
        log.debug('update-interface', device_id=device.id)
        if device.id in self.devices_handlers:
            handler = self.devices_handlers[device.id]
            if handler is not None:
                handler.update_interface(data)

    def remove_interface(self, device, data):
        log.debug('remove-interface', device_id=device.id)
        if device.id in self.devices_handlers:
            handler = self.devices_handlers[device.id]
            if handler is not None:
                handler.remove_interface(data)

    def receive_onu_detect_state(self, device_id, state):
        raise NotImplementedError()

    def create_tcont(self, device, tcont_data, traffic_descriptor_data):
        log.debug('create-tcont', device_id=device.id)
        if device.id in self.devices_handlers:
            handler = self.devices_handlers[device.id]
            if handler is not None:
                handler.create_tcont(tcont_data, traffic_descriptor_data)

    def update_tcont(self, device, tcont_data, traffic_descriptor_data):
        raise NotImplementedError()

    def remove_tcont(self, device, tcont_data, traffic_descriptor_data):
        log.debug('remove-tcont', device_id=device.id)
        if device.id in self.devices_handlers:
            handler = self.devices_handlers[device.id]
            if handler is not None:
                handler.remove_tcont(tcont_data, traffic_descriptor_data)

    def create_gemport(self, device, data):
        log.debug('create-gemport', device_id=device.id)
        if device.id in self.devices_handlers:
            handler = self.devices_handlers[device.id]
            if handler is not None:
                handler.create_gemport(data)

    def update_gemport(self, device, data):
        raise NotImplementedError()

    def remove_gemport(self, device, data):
        log.debug('remove-gemport', device_id=device.id)
        if device.id in self.devices_handlers:
            handler = self.devices_handlers[device.id]
            if handler is not None:
                handler.remove_gemport(data)

    def create_multicast_gemport(self, device, data):
        log.debug('create-multicast-gemport', device_id=device.id)
        if device.id in self.devices_handlers:
            handler = self.devices_handlers[device.id]
            if handler is not None:
                handler.create_multicast_gemport(data)

    def update_multicast_gemport(self, device, data):
        raise NotImplementedError()

    def remove_multicast_gemport(self, device, data):
        raise NotImplementedError()

    def create_multicast_distribution_set(self, device, data):
        raise NotImplementedError()

    def update_multicast_distribution_set(self, device, data):
        raise NotImplementedError()

    def remove_multicast_distribution_set(self, device, data):
        raise NotImplementedError()

    def suppress_alarm(self, filter):
        raise NotImplementedError()

    def unsuppress_alarm(self, filter):
        raise NotImplementedError()
Example #22
0
class PmcsOnu(object):

    name = 'pmcs_onu'

    supported_device_types = [
        DeviceType(id=name, adapter=name, accepts_bulk_flow_update=True)
    ]

    def __init__(self, adapter_agent, config):
        self.adapter_agent = adapter_agent
        self.config = config
        self.descriptor = Adapter(
            id=self.name,
            vendor='PMCS',
            version='0.1',
            config=AdapterConfig(log_level=LogLevel.INFO))
        self.incoming_messages = DeferredQueue()
        self.trangen = sequence_generator(1)

    def start(self):
        log.debug('starting')
        log.info('started')

    def stop(self):
        log.debug('stopping')
        log.info('stopped')

    def adapter_descriptor(self):
        return self.descriptor

    def device_types(self):
        return DeviceTypes(items=self.supported_device_types)

    def health(self):
        return HealthStatus(state=HealthStatus.HealthState.HEALTHY)

    def change_master_state(self, master):
        raise NotImplementedError()

    def adopt_device(self, device):
        log.info('adopt-device', device=device)
        reactor.callLater(0.1, self._onu_device_activation, device)
        return device

    def abandon_device(self, device):
        raise NotImplementedError()

    def disable_device(self, device):
        raise NotImplementedError()

    def reenable_device(self, device):
        raise NotImplementedError()

    def reboot_device(self, device):
        raise NotImplementedError()

    def delete_device(self, device):
        raise NotImplementedError()

    def get_device_details(self, device):
        raise NotImplementedError()

    def deactivate_device(self, device):
        raise NotImplementedError()

    def update_pm_config(self, device, pm_configs):
        raise NotImplementedError()

    def update_flows_bulk(self, device, flows, groups):
        log.info('bulk-flow-update',
                 device_id=device.id,
                 flows=flows,
                 groups=groups)

    def update_flows_incrementally(self, device, flow_changes, group_changes):
        raise NotImplementedError()

    def send_proxied_message(self, proxy_address, msg):
        log.info('send-proxied-message', proxy_address=proxy_address, msg=msg)

    def receive_proxied_message(self, proxy_address, msg):
        log.info('receive-proxied-message',
                 proxy_address=proxy_address,
                 device_id=proxy_address.device_id)
        self.incoming_messages.put(msg)

    def receive_packet_out(self, logical_device_id, egress_port_no, msg):
        log.info('packet-out',
                 logical_device_id=logical_device_id,
                 egress_port_no=egress_port_no,
                 msg_len=len(msg))

    @inlineCallbacks
    def _onu_device_activation(self, device):
        # first we verify that we got parent reference and proxy info
        assert device.parent_id
        assert device.proxy_address.device_id
        assert device.proxy_address.channel_id == 0

        device.model = 'GPON ONU'
        device.hardware_version = 'tbd'
        device.firmware_version = 'tbd'
        device.software_version = 'tbd'

        device.connect_status = ConnectStatus.REACHABLE

        self.adapter_agent.update_device(device)

        uni_port = Port(
            port_no=1000,  # FIXME It becomes the alloc_id
            label="{} ONU".format('PMCS'),
            type=Port.ETHERNET_UNI,
            admin_state=AdminState.ENABLED,
            oper_status=OperStatus.ACTIVE)
        self.adapter_agent.add_port(device.id, uni_port)

        pon_port = Port(port_no=1,
                        label='PON port',
                        type=Port.PON_ONU,
                        admin_state=AdminState.ENABLED,
                        oper_status=OperStatus.ACTIVE,
                        peers=[
                            Port.PeerPort(device_id=device.parent_id,
                                          port_no=device.parent_port_no)
                        ])

        self.adapter_agent.add_port(device.id, pon_port)

        # obtain logical device id
        parent_device = self.adapter_agent.get_device(device.parent_id)
        logical_device_id = parent_device.parent_id
        assert logical_device_id

        # we are going to use the proxy_address.channel_id as unique number
        # and name for the virtual ports, as this is guaranteed to be unique
        # in the context of the OLT port, so it is also unique in the context
        # of the logical device
        port_no = device.proxy_address.channel_id  # FIXME this may need to be fixed
        cap = OFPPF_1GB_FD | OFPPF_FIBER
        self.adapter_agent.add_logical_port(
            logical_device_id,
            LogicalPort(id=str(port_no),
                        ofp_port=ofp_port(port_no=port_no,
                                          hw_addr=mac_str_to_tuple(
                                              device.serial_number)[2:8],
                                          name='uni-{}'.format(port_no),
                                          config=0,
                                          state=OFPPS_LIVE,
                                          curr=cap,
                                          advertised=cap,
                                          peer=cap,
                                          curr_speed=OFPPF_1GB_FD,
                                          max_speed=OFPPF_1GB_FD),
                        device_id=device.id,
                        device_port_no=uni_port.port_no))

        yield self._initialize_onu(device)

        # and finally update to "ACTIVE"
        device = self.adapter_agent.get_device(device.id)
        device.oper_status = OperStatus.ACTIVE
        self.adapter_agent.update_device(device)

    @inlineCallbacks
    def _initialize_onu(self, device):
        device = self.adapter_agent.get_device(device.id)
        self.adapter_agent.register_for_proxied_messages(device.proxy_address)
        log.debug("INIT", device=device)
        # DO things to the ONU
        # |###[ OmciFrame ]###
        #     |  transaction_id= 1
        #     |  message_type= 79
        #     |  omci      = 10
        #     |  \omci_message\
        #     |   |###[ OmciMibReset ]###
        #     |   |  entity_class= 2
        #     |   |  entity_id = 0
        #     |  omci_trailer= 40

        # OmciMibReset

        msg = OmciMibReset(entity_class=2, entity_id=0)
        frame = OmciFrame(transaction_id=self.trangen.next(),
                          message_type=OmciMibReset.message_id,
                          omci_message=msg)

        self.adapter_agent.send_proxied_message(device.proxy_address, frame)

        response = yield self.incoming_messages.get()

        if OmciMibResetResponse not in response:
            log.error("Failed to perform a MIB reset for {}".format(
                device.proxy_address))
            return

        # ###[ PAS5211Dot3 ]###
        #   dst       = 00:0c:d5:00:01:00
        #   src       = 90:e2:ba:82:f9:77
        #   len       = 22
        # ###[ PAS5211FrameHeader ]###
        #      part      = 1
        #      total_parts= 1
        #      size      = 16
        #      magic_number= 0x1234abcd
        # ###[ PAS5211MsgHeader ]###
        #         sequence_number= 51
        #         opcode    = 0x3009
        #         event_type= 0
        #         channel_id= 0
        #         onu_id    = 0
        #         onu_session_id= 1
        # ###[ PAS5211GetOnuAllocs ]###
        #            nothing   = 0
        # ###[ Raw ]###
        #               load      = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

        msg = PAS5211GetOnuAllocs()
        self.adapter_agent.send_proxied_message(device.proxy_address, msg)

        response = yield self.incoming_messages.get()

        if PAS5211GetOnuAllocsResponse not in response:
            log.error("Failed to get alloc ids for {}".format(
                device.proxy_address))
            return

        #  ###[ PAS5211Dot3 ]###
        #   dst       = 00:0c:d5:00:01:00
        #   src       = 90:e2:ba:82:f9:77
        #   len       = 30
        # ###[ PAS5211FrameHeader ]###
        #      part      = 1
        #      total_parts= 1
        #      size      = 24
        #      magic_number= 0x1234abcd
        # ###[ PAS5211MsgHeader ]###
        #         sequence_number= 52
        #         opcode    = 0x3007
        #         event_type= 0
        #         channel_id= 0
        #         onu_id    = -1
        #         onu_session_id= -1
        # ###[ PAS5211GetSnInfo ]###
        #            serial_number= 'PMCS\xd5b\x84\xac'
        # ###[ Raw ]###
        #               load      = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

        msg = PAS5211GetSnInfo(serial_number=device.serial_number)
        self.adapter_agent.send_proxied_message(device.proxy_address, msg)

        response = yield self.incoming_messages.get()

        if PAS5211GetSnInfoResponse not in response:
            log.error("Failed to get serial number info for {}".format(
                device.proxy_address))
            return

        # ###[ PAS5211Dot3 ]###
        #   dst       = 00:0c:d5:00:01:00
        #   src       = 90:e2:ba:82:f9:77
        #   len       = 22
        # ###[ PAS5211FrameHeader ]###
        #      part      = 1
        #      total_parts= 1
        #      size      = 16
        #      magic_number= 0x1234abcd
        # ###[ PAS5211MsgHeader ]###
        #         sequence_number= 53
        #         opcode    = 0x3074
        #         event_type= 0
        #         channel_id= 0
        #         onu_id    = -1
        #         onu_session_id= -1
        # ###[ PAS5211GetOnusRange ]###
        #            nothing   = 0
        # ###[ Raw ]###
        #               load      = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

        msg = PAS5211GetOnusRange()
        self.adapter_agent.send_proxied_message(device.proxy_address, msg)

        response = yield self.incoming_messages.get()

        if PAS5211GetOnusRangeResponse not in response:
            log.error("Failed to get ONU Range for {}".format(
                device.proxy_address))
            return

        #  |  ###[ OmciFrame ]###
        # | transaction_id = 2
        # | message_type = 72
        # | omci = 10
        # |   \omci_message \
        #      | |  ###[ OmciSet ]###
        # | | entity_class = 262
        # | | entity_id = 32769
        # | | attributes_mask = 32768
        # | | data = {'alloc_id': 1000}
        # | omci_trailer = 40

        # OmciSet
        # TODO: maskdata
        msg = OmciSet(entity_class=262,
                      entity_id=32769,
                      attributes_mask=32768,
                      data=dict(alloc_id=1000))
        frame = OmciFrame(transaction_id=self.trangen.next(),
                          message_type=OmciSet.message_id,
                          omci_message=msg)
        self.adapter_agent.send_proxied_message(device.proxy_address, frame)

        response = yield self.incoming_messages.get()

        if OmciSetResponse not in response:
            log.error("Failed to set alloc id for {}".format(
                device.proxy_address))
            return

        # length = 44
        # port_type = 0
        # port_id = 0
        # management_frame = 1
        # \frame \
        #  |  ###[ OmciFrame ]###
        # | transaction_id = 3
        # | message_type = 68
        # | omci = 10
        # |   \omci_message \
        #      | |  ###[ OmciCreate ]###
        # | | entity_class = 45
        # | | entity_id = 1
        # | | data = {'max_age': 5120, 'hello_time': 512, 'priority': 32768, 'port_bridging_ind': 0,
        #             'spanning_tree_ind': 0, 'unknown_mac_address_discard': 0, 'mac_learning_depth': 128,
        #             'learning_ind': 0, 'forward_delay': 3840}
        # | |  ###[ Raw ]###
        # | | load = '\x00\x00\x00\n\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
        # | omci_trailer = 40

        # Found in method: pmc_omci_mac_bridge_sp_me_create from: PMC_OFAL.c
        # Params
        #   - priority: The bridge priority set on the LAN card
        #   - max_age: The maximum age for an entry in the spanning tree listing
        #   - hello_time: The time interval between hello packets
        #   - forward_delay: The time that the bridge on the Ethernet card in the ONT retains a packet before forwarding it
        #   - unknown_mac_address_discard: frames with unknown destination addresses will be forwarded to all allowed ports

        msg = OmciCreate(entity_class=45,
                         entity_id=1,
                         data=dict(max_age=5120,
                                   hello_time=512,
                                   priority=32768,
                                   port_bridging_ind=PON_FALSE,
                                   spanning_tree_ind=PON_FALSE,
                                   unknown_mac_address_discard=0,
                                   mac_learning_depth=128,
                                   learning_ind=PON_FALSE,
                                   forward_delay=3840))
        frame = OmciFrame(transaction_id=self.trangen.next(),
                          message_type=OmciCreate.message_id,
                          omci_message=msg)
        self.adapter_agent.send_proxied_message(device.proxy_address, frame)

        response = yield self.incoming_messages.get()

        if OmciCreateResponse not in response:
            log.error("Failed to set parameter on {}".format(
                device.proxy_address))
            return

        # |###[ OmciFrame ]###
        #     |  transaction_id= 4
        #     |  message_type= 68
        #     |  omci      = 10
        #     |  \omci_message\
        #     |   |###[ OmciCreate ]###
        #     |   |  entity_class= 47
        #     |   |  entity_id = 0
        #     |   |  data      = {'tp_pointer': 257, 'encapsulation_methods': 1, 'port_num': 0, 'port_priority': 10, 'tp_type': 1, 'port_path_cost': 100, 'port_spanning_tree_in': 0, 'lan_fcs_ind': 0, 'bridge_id_pointer': 1}
        #     |  omci_trailer= 40

        # Found in method: pmc_omci_mac_bridge_pcd_me_create from: PMC_OFAL.c
        # Params
        #   - port_path_cost: The cost contribution of the port to the path cost towards the spanning tree root bridge
        #   - bridge_id_pointer: MAC bridge controlling the port
        msg = OmciCreate(
            entity_class=47,
            entity_id=0,
            data=dict(
                tp_pointer=257,
                encapsulation_methods=OMCI_MAC_BRIDGE_PCD_ENCAP_METHOD_LLC,
                port_num=0,
                port_priority=10,
                tp_type=1,
                port_path_cost=100,
                port_spanning_tree_in=PON_FALSE,
                lan_fcs_ind=OMCI_MAC_BRIDGE_PCD_LANFCS_FORWARDED,
                bridge_id_pointer=1))

        frame = OmciFrame(transaction_id=self.trangen.next(),
                          message_type=OmciCreate.message_id,
                          omci_message=msg)

        self.adapter_agent.send_proxied_message(device.proxy_address, frame)

        response = yield self.incoming_messages.get()

        if OmciCreateResponse not in response:
            log.error("Failed to set info for {}".format(device.proxy_address))
            return

        # |###[ OmciFrame ]###
        # |  transaction_id= 5
        # |  message_type= 68
        # |  omci      = 10
        # |  \omci_message\
        # |   |###[ OmciCreate ]###
        # |   |  entity_class= 171
        # |   |  entity_id = 0
        # |   |  data      = {'association_type': 2, 'associated_me_pointer': 257}
        # |  omci_trailer= 40

        # Found in method: pmc_omci_evto_create from: PMC_OFAL.c
        msg = OmciCreate(
            entity_class=171,
            entity_id=0,
            data=dict(association_type=
                      OMCI_EX_VLAN_TAG_OCD_ASSOCIATION_TYPE_PPTP_ETH_UNI,
                      associated_me_pointer=257))

        frame = OmciFrame(transaction_id=self.trangen.next(),
                          message_type=OmciCreate.message_id,
                          omci_message=msg)

        self.adapter_agent.send_proxied_message(device.proxy_address, frame)

        response = yield self.incoming_messages.get()

        if OmciCreateResponse not in response:
            log.error("Failed to set association info for {}".format(
                device.proxy_address))
            return

        # |###[ OmciFrame ]###
        # |  transaction_id= 6
        # |  message_type= 72
        # |  omci      = 10
        # |  \omci_message\
        # |   |###[ OmciSet ]###
        # |   |  entity_class= 171
        # |   |  entity_id = 0
        # |   |  attributes_mask= 47616
        # |   |  data      = {'association_type': 2, 'input_tpid': 33024, 'associated_me_pointer': 257, 'downstream_mode': 0, 'output_tpid': 33024}
        # |  omci_trailer= 40

        # Found in method: pmc_omci_evto_set from: PMC_OFAL.c
        msg = OmciSet(
            entity_class=171,
            entity_id=0,
            attributes_mask=47616,
            data=dict(association_type=
                      OMCI_EX_VLAN_TAG_OCD_ASSOCIATION_TYPE_PPTP_ETH_UNI,
                      input_tpid=33024,
                      associated_me_pointer=257,
                      downstream_mode=OMCI_EX_VLAN_TAG_OCD_DS_MODE_US_INVERSE,
                      output_tpid=33024))

        frame = OmciFrame(transaction_id=self.trangen.next(),
                          message_type=OmciSet.message_id,
                          omci_message=msg)

        self.adapter_agent.send_proxied_message(device.proxy_address, frame)

        response = yield self.incoming_messages.get()

        if OmciSetResponse not in response:
            log.error("Failed to set association tpid info for {}".format(
                device.proxy_address))
            return

        # |###[ OmciFrame ]###
        # |  transaction_id= 7
        # |  message_type= 68
        # |  omci      = 10
        # |  \omci_message\
        # |   |###[ OmciCreate ]###
        # |   |  entity_class= 130
        # |   |  entity_id = 1
        # |   |  data      = {'tp_pointer': 65535, 'unmarked_frame_option': 1, 'interwork_tp_pointer_for_p_bit_priority_6': 65535,
        #          'interwork_tp_pointer_for_p_bit_priority_7': 65535, 'interwork_tp_pointer_for_p_bit_priority_4': 65535,
        #           'interwork_tp_pointer_for_p_bit_priority_5': 65535, 'interwork_tp_pointer_for_p_bit_priority_2': 65535,
        #           'interwork_tp_pointer_for_p_bit_priority_3': 65535, 'interwork_tp_pointer_for_p_bit_priority_0': 65535,
        #           'interwork_tp_pointer_for_p_bit_priority_1': 65535, 'tp_type': 0, 'default_p_bit_marking': 0}
        # |  omci_trailer= 40

        # Found in method: pmc_omci_8021p_msp_me_create from: PMC_OFAL.c
        msg = OmciCreate(
            entity_class=130,
            entity_id=1,
            data=dict(
                tp_pointer=65535,
                unmarked_frame_option=OMCI_8021P_MSP_UNMARKED_FRAME_TAG_FRAME,
                interwork_tp_pointer_for_p_bit_priority_6=65535,
                interwork_tp_pointer_for_p_bit_priority_7=65535,
                interwork_tp_pointer_for_p_bit_priority_4=65535,
                interwork_tp_pointer_for_p_bit_priority_5=65535,
                interwork_tp_pointer_for_p_bit_priority_2=65535,
                interwork_tp_pointer_for_p_bit_priority_3=65535,
                interwork_tp_pointer_for_p_bit_priority_0=65535,
                interwork_tp_pointer_for_p_bit_priority_1=65535,
                tp_type=OMCI_8021P_MSP_TP_TYPE_NULL,
                default_p_bit_marking=0))

        frame = OmciFrame(transaction_id=self.trangen.next(),
                          message_type=OmciCreate.message_id,
                          omci_message=msg)

        self.adapter_agent.send_proxied_message(device.proxy_address, frame)

        response = yield self.incoming_messages.get()

        if OmciCreateResponse not in response:
            log.error("Failed to set interwork info for {}".format(
                device.proxy_address))
            return

        # |###[ OmciFrame ]###
        # |  transaction_id= 8
        # |  message_type= 68
        # |  omci      = 10
        # |  \omci_message\
        # |   |###[ OmciCreate ]###
        # |   |  entity_class= 130
        # |   |  entity_id = 1
        # |   |  data      = {'tp_pointer': 1, 'encapsulation_methods': 1, 'port_num': 1, 'port_priority': 3, 'tp_type': 5, 'port_path_cost': 32, 'port_spanning_tree_in': 1, 'lan_fcs_ind': 0, 'bridge_id_pointer': 1}
        # |  omci_trailer= 40

        # Found in method: pmc_omci_mac_bridge_pcd_me_create from: PMC_OFAL.c
        # Params
        #   - port_path_cost: The cost contribution of the port to the path cost towards the spanning tree root bridge
        #   - bridge_id_pointer: MAC bridge controlling the port
        msg = OmciCreate(
            entity_class=130,
            entity_id=1,
            data=dict(
                tp_pointer=1,
                encapsulation_methods=OMCI_MAC_BRIDGE_PCD_ENCAP_METHOD_LLC,
                port_num=1,
                port_priority=3,
                tp_type=5,
                port_path_cost=32,
                port_spanning_tree_in=PON_TRUE,
                lan_fcs_ind=OMCI_MAC_BRIDGE_PCD_LANFCS_FORWARDED,
                bridge_id_pointer=1))

        frame = OmciFrame(transaction_id=self.trangen.next(),
                          message_type=OmciCreate.message_id,
                          omci_message=msg)

        self.adapter_agent.send_proxied_message(self, device.proxy_address,
                                                frame)

        response = yield self.incoming_messages.get()

        if OmciCreateResponse not in response:
            log.error("Failed to set encap info for {}".format(
                device.proxy_address))
            return

        # |###[ OmciFrame ]###
        # |  transaction_id= 9
        # |  message_type= 68
        # |  omci      = 10
        # |  \omci_message\
        # |   |###[ OmciCreate ]###
        # |   |  entity_class= 268
        # |   |  entity_id = 1
        # |   |  data      = {'priority_queue_pointer_downstream': 0, 'direction': 3, 'tcont_pointer': 32769, 'traffic_descriptor_profile_pointer': 0, 'traffic_management_pointer_upstream': 4, 'port_id': 1000}
        # |  omci_trailer= 40

        # Found in method: pmc_omci_gem_nctp_create from: PMC_OFAL.c
        msg = OmciCreate(entity_class=268,
                         entity_id=1,
                         data=dict(priority_queue_pointer_downstream=0,
                                   direction=GEM_DIR_BIDIRECT,
                                   tcont_pointer=32769,
                                   traffic_descriptor_profile_pointer=0,
                                   traffic_management_pointer_upstream=4,
                                   port_id=1000))

        frame = OmciFrame(transaction_id=self.trangen.next(),
                          message_type=OmciCreate.message_id,
                          omci_message=msg)

        self.adapter_agent.send_proxied_message(device.proxy_address, frame)

        response = yield self.incoming_messages.get()

        if OmciCreateResponse not in response:
            log.error("Failed to priority queue for {}".format(
                device.proxy_address))
            return

        # |###[ OmciFrame ]###
        # |  transaction_id= 10
        # |  message_type= 68
        # |  omci      = 10
        # |  \omci_message\
        # |   |###[ OmciCreate ]###
        # |   |  entity_class= 266
        # |   |  entity_id = 1
        # |   |  data      = {'gem_port_network_ctp_pointer': 1, 'gal_profile_pointer': 0, 'service_profile_pointer': 1, 'interworking_option': 5, 'interworking_tp_pointer': 0}
        # |  omci_trailer= 40

        # Found in method: pmc_omci_gem_iwtp_me_create from: PMC_OFAL.c
        # Params
        #   - gem_port_network_ctp_pointer: An instance identifier of the GEM Port Network CTP that is associated with this GEM Interworking Termination Point
        #   - service_profile_pointer: The service profile type and a pointer to the instance of a service profile
        #   - interworking_tp_pointer: Used for in the case of Circuit Emulation Services and 802.1p mapper service
        #   - gal_profile_pointer: A pointer to an instance of the GAL Profile

        msg = OmciCreate(
            entity_class=266,
            entity_id=1,
            data=dict(gem_port_network_ctp_pointer=1,
                      gal_profile_pointer=0,
                      service_profile_pointer=1,
                      interworking_option=OMCI_GEM_IWTP_IW_OPT_8021P_MAPPER,
                      interworking_tp_pointer=0))

        frame = OmciFrame(transaction_id=self.trangen.next(),
                          message_type=OmciCreate.message_id,
                          omci_message=msg)

        self.adapter_agent.send_proxied_message(device.proxy_address, frame)

        response = yield self.incoming_messages.get()

        if OmciCreateResponse not in response:
            log.error("Failed to set gem info for {}".format(
                device.proxy_address))
            return
Example #23
0
class SimulatedOltAdapter(object):
    name = 'simulated_olt'

    supported_device_types = [
        DeviceType(id='simulated_olt',
                   adapter=name,
                   accepts_bulk_flow_update=True)
    ]

    app = Klein()

    def __init__(self, adapter_agent, config):
        self.adapter_agent = adapter_agent
        self.config = config
        self.descriptor = Adapter(
            id=self.name,
            vendor='Voltha project',
            version='0.1',
            config=AdapterConfig(log_level=LogLevel.INFO))
        self.control_endpoint = None
        # Faked PM metrics for testing PM functionality
        self.pm_metrics = None

    def start(self):
        log.debug('starting')

        # setup a basic web server for test control
        self.control_endpoint = endpoints.TCP4ServerEndpoint(reactor, 18880)
        self.control_endpoint.listen(self.get_test_control_site())

        # TODO tmp: populate some devices and logical devices
        # reactor.callLater(0, self._tmp_populate_stuff)
        log.info('started')

    def stop(self):
        log.debug('stopping')
        log.info('stopped')

    def adapter_descriptor(self):
        return self.descriptor

    def device_types(self):
        return DeviceTypes(items=self.supported_device_types)

    def health(self):
        return HealthStatus(state=HealthStatus.HealthState.HEALTHY)

    def change_master_state(self, master):
        raise NotImplementedError()

    def adopt_device(self, device):
        # We kick of a simulated activation scenario
        reactor.callLater(0.2, self._simulate_device_activation, device)
        return device

    def reconcile_device(self, device):
        raise NotImplementedError()

    def abandon_device(self, device):
        raise NotImplementedError()

    def disable_device(self, device):
        raise NotImplementedError()

    def reenable_device(self, device):
        raise NotImplementedError()

    def reboot_device(self, device):
        raise NotImplementedError()

    def delete_device(self, device):
        raise NotImplementedError()

    def download_image(self, device, request):
        log.info('download-image', device=device, request=request)
        try:
            # initiate requesting software download to device
            log.info('device.image_downloads', img_dnld=device.image_downloads)
            pass
        except Exception as e:
            log.exception(e.message)

    def get_image_download_status(self, device, request):
        log.info('get-image-download-status', device=device,\
                request=request)
        try:
            download_completed = False
            # initiate query for progress of download to device
            request.state = random.choice([
                ImageDownload.DOWNLOAD_SUCCEEDED,
                ImageDownload.DOWNLOAD_STARTED, ImageDownload.DOWNLOAD_FAILED
            ])
            if request.state != ImageDownload.DOWNLOAD_STARTED:
                download_completed = True
            request.downloaded_bytes = random.choice(range(1024, 65536))
            # update status based on query output
            self.adapter_agent.update_image_download(request)
            if download_completed == True:
                # restore admin state to enabled
                device.admin_state = AdminState.ENABLED
                self.adapter_agent.update_device(device)
                # TODO:
                # the device admin state will also restore
                # when adapter receiving event notification
                # this will be handled in event handler
        except Exception as e:
            log.exception(e.message)

    def cancel_image_download(self, device, request):
        log.info('cancel-sw-download', device=device, request=request)
        try:
            # intiate cancelling software download to device
            # at success delete image download record
            self.adapter_agent.delete_image_download(request)
            # restore admin state to enabled
            device.admin_state = AdminState.ENABLED
            self.adapter_agent.update_device(device)
        except Exception as e:
            log.exception(e.message)

    def activate_image_update(self, device, request):
        log.info('activate-image-update', device=device, request=request)
        try:
            # initiate activating software update to device
            # at succcess, update image state
            request.image_state = ImageDownload.IMAGE_ACTIVE
            self.adapter_agent.update_image_download(request)
            # restore admin state to enabled
            device.admin_state = AdminState.ENABLED
            self.adapter_agent.update_device(device)
        except Exception as e:
            log.exception(e.message)

    def revert_image_update(self, device, request):
        log.info('revert-image-updade', device=device, request=request)
        try:
            # initiate reverting software update to device
            # at succcess, update image state
            request.image_state = ImageDownload.IMAGE_INACTIVE
            self.adapter_agent.update_image_download(request)
            # restore admin state to enabled
            device.admin_state = AdminState.ENABLED
            self.adapter_agent.update_device(device)
        except Exception as e:
            log.exception(e.message)

    def get_device_details(self, device):
        raise NotImplementedError()

    def update_pm_config(self, device, pm_config):
        log.info("adapter-update-pm-config",
                 device=device,
                 pm_config=pm_config)
        self.pm_metrics.update(pm_config)

    def self_test_device(self, device):
        log.info("run-self-test-on-device", device=device.id)
        result = SelfTestResponse(result=random.choice([
            SelfTestResponse.SUCCESS, SelfTestResponse.FAILURE,
            SelfTestResponse.NOT_SUPPORTED, SelfTestResponse.UNKNOWN_ERROR
        ]))
        return result

    def _tmp_populate_stuff(self):
        """
        pretend that we discovered some devices and create:
        - devices
        - device ports for each
        - logical device
        - logical device ports
        """

        olt = Device(id='simulated_olt_1',
                     type='simulated_olt',
                     root=True,
                     vendor='simulated',
                     model='n/a',
                     hardware_version='n/a',
                     firmware_version='n/a',
                     software_version='1.0',
                     serial_number=uuid4().hex,
                     adapter=self.name,
                     oper_status=OperStatus.DISCOVERED)
        self.adapter_agent.add_device(olt)
        self.adapter_agent.add_port(
            olt.id, Port(port_no=1, label='pon', type=Port.PON_OLT))
        self.adapter_agent.add_port(
            olt.id, Port(port_no=2, label='eth', type=Port.ETHERNET_NNI))

        onu1 = Device(id='simulated_onu_1',
                      type='simulated_onu',
                      root=False,
                      parent_id=olt.id,
                      parent_port_no=1,
                      vendor='simulated',
                      model='n/a',
                      hardware_version='n/a',
                      firmware_version='n/a',
                      software_version='1.0',
                      serial_number=uuid4().hex,
                      adapter='simulated_onu',
                      oper_status=OperStatus.DISCOVERED,
                      vlan=101)
        self.adapter_agent.add_device(onu1)
        self.adapter_agent.add_port(
            onu1.id, Port(port_no=2, label='eth', type=Port.ETHERNET_UNI))
        self.adapter_agent.add_port(
            onu1.id,
            Port(port_no=1,
                 label='pon',
                 type=Port.PON_ONU,
                 peers=[Port.PeerPort(device_id=olt.id, port_no=1)]))

        onu2 = Device(id='simulated_onu_2',
                      type='simulated_onu',
                      root=False,
                      parent_id=olt.id,
                      parent_port_no=1,
                      vendor='simulated',
                      model='n/a',
                      hardware_version='n/a',
                      firmware_version='n/a',
                      software_version='1.0',
                      serial_number=uuid4().hex,
                      adapter='simulated_onu',
                      oper_status=OperStatus.DISCOVERED,
                      vlan=102)
        self.adapter_agent.add_device(onu2)
        self.adapter_agent.add_port(
            onu2.id, Port(port_no=2, label='eth', type=Port.ETHERNET_UNI))
        self.adapter_agent.add_port(
            onu2.id,
            Port(port_no=1,
                 label='pon',
                 type=Port.PON_ONU,
                 peers=[Port.PeerPort(device_id=olt.id, port_no=1)]))

        ld = LogicalDevice(
            id='simulated1',
            datapath_id=1,
            desc=ofp_desc(mfr_desc='cord project',
                          hw_desc='simualted pon',
                          sw_desc='simualted pon',
                          serial_num=uuid4().hex,
                          dp_desc='n/a'),
            switch_features=ofp_switch_features(
                n_buffers=256,  # TODO fake for now
                n_tables=2,  # TODO ditto
                capabilities=(  # TODO and ditto
                    OFPC_FLOW_STATS
                    | OFPC_TABLE_STATS
                    | OFPC_PORT_STATS
                    | OFPC_GROUP_STATS)),
            root_device_id=olt.id)
        self.adapter_agent.create_logical_device(ld)

        cap = OFPPF_1GB_FD | OFPPF_FIBER
        for port_no, name, device_id, device_port_no, root_port in [
            (1, 'onu1', onu1.id, 2, False), (2, 'onu2', onu2.id, 2, False),
            (129, 'olt1', olt.id, 2, True)
        ]:
            port = LogicalPort(id=name,
                               ofp_port=ofp_port(
                                   port_no=port_no,
                                   hw_addr=mac_str_to_tuple(
                                       '00:00:00:00:00:%02x' % port_no),
                                   name=name,
                                   config=0,
                                   state=OFPPS_LIVE,
                                   curr=cap,
                                   advertised=cap,
                                   peer=cap,
                                   curr_speed=OFPPF_1GB_FD,
                                   max_speed=OFPPF_1GB_FD),
                               device_id=device_id,
                               device_port_no=device_port_no,
                               root_port=root_port)
            self.adapter_agent.add_logical_port(ld.id, port)

        olt.parent_id = ld.id
        self.adapter_agent.update_device(olt)

    @inlineCallbacks
    def _simulate_device_activation(self, device):

        # first we pretend that we were able to contact the device and obtain
        # additional information about it
        device.root = True
        device.vendor = 'simulated'
        device.model = 'n/a'
        device.hardware_version = 'n/a'
        device.firmware_version = 'n/a'
        device.serial_number = uuid4().hex
        device.connect_status = ConnectStatus.REACHABLE

        image1 = Image(name="olt_candidate1",
                       version="1.0",
                       hash="",
                       install_datetime=datetime.datetime.utcnow().isoformat(),
                       is_active=True,
                       is_committed=True,
                       is_valid=True)

        image2 = Image(name="olt_candidate2",
                       version="1.0",
                       hash="",
                       install_datetime=datetime.datetime.utcnow().isoformat(),
                       is_active=False,
                       is_committed=False,
                       is_valid=True)

        device.images.image.extend([image1, image2])

        self.adapter_agent.update_device(device)

        # Now set the initial PM configuration for this device
        self.pm_metrics = AdapterPmMetrics(device)
        pm_config = self.pm_metrics.make_proto()
        log.info("initial-pm-config", pm_config=pm_config)
        self.adapter_agent.update_device_pm_config(pm_config, init=True)

        # then shortly after we create some ports for the device
        yield asleep(0.05)
        nni_port = Port(port_no=2,
                        label='NNI facing Ethernet port',
                        type=Port.ETHERNET_NNI,
                        admin_state=AdminState.ENABLED,
                        oper_status=OperStatus.ACTIVE)
        self.adapter_agent.add_port(device.id, nni_port)
        self.adapter_agent.add_port(
            device.id,
            Port(port_no=1,
                 label='PON port',
                 type=Port.PON_OLT,
                 admin_state=AdminState.ENABLED,
                 oper_status=OperStatus.ACTIVE))

        # then shortly after we create the logical device with one port
        # that will correspond to the NNI port
        yield asleep(0.05)
        logical_device_id = uuid4().hex[:12]
        ld = LogicalDevice(
            # not setting id and datapth_id will let the adapter agent pick id
            desc=ofp_desc(mfr_desc='cord porject',
                          hw_desc='simualted pon',
                          sw_desc='simualted pon',
                          serial_num=uuid4().hex,
                          dp_desc='n/a'),
            switch_features=ofp_switch_features(
                n_buffers=256,  # TODO fake for now
                n_tables=2,  # TODO ditto
                capabilities=(  # TODO and ditto
                    OFPC_FLOW_STATS
                    | OFPC_TABLE_STATS
                    | OFPC_PORT_STATS
                    | OFPC_GROUP_STATS)),
            root_device_id=device.id)
        ld_initialized = self.adapter_agent.create_logical_device(ld)
        cap = OFPPF_1GB_FD | OFPPF_FIBER
        self.adapter_agent.add_logical_port(
            ld_initialized.id,
            LogicalPort(id='nni',
                        ofp_port=ofp_port(port_no=129,
                                          hw_addr=mac_str_to_tuple(
                                              '00:00:00:00:00:%02x' % 129),
                                          name='nni',
                                          config=0,
                                          state=OFPPS_LIVE,
                                          curr=cap,
                                          advertised=cap,
                                          peer=cap,
                                          curr_speed=OFPPF_1GB_FD,
                                          max_speed=OFPPF_1GB_FD),
                        device_id=device.id,
                        device_port_no=nni_port.port_no,
                        root_port=True))

        # and finally update to active
        device = self.adapter_agent.get_device(device.id)
        device.parent_id = ld_initialized.id
        device.oper_status = OperStatus.ACTIVE
        self.adapter_agent.update_device(device)

        reactor.callLater(0.1, self._simulate_detection_of_onus, device.id)
        self.start_kpi_collection(device.id)

        self.start_alarm_simulation(device.id)

    @inlineCallbacks
    def _simulate_detection_of_onus(self, device_id):
        try:
            for i in xrange(1, 5):
                log.info('activate-olt-for-onu-{}'.format(i))
                vlan_id = self._olt_side_onu_activation(i)
                yield asleep(0.05)
                self.adapter_agent.child_device_detected(
                    parent_device_id=device_id,
                    parent_port_no=1,
                    child_device_type='simulated_onu',
                    proxy_address=Device.ProxyAddress(device_id=device_id,
                                                      channel_id=vlan_id),
                    admin_state=AdminState.ENABLED,
                    vlan=vlan_id)
        except Exception as e:
            log.exception('error', e=e)

    def _olt_side_onu_activation(self, seq):
        """
        This is where if this was a real OLT, the OLT-side activation for
        the new ONU should be performed. By the time we return, the OLT shall
        be able to provide tunneled (proxy) communication to the given ONU,
        using the returned information.
        """
        vlan_id = seq + 100
        return vlan_id

    #def update_pm_collection(self, device, pm_collection_config):
    # This is where the metrics to be collected are configured and where
    # the sampling frequency is set.
    #TODO: Here.
    #    pass

    def update_flows_bulk(self, device, flows, groups):
        log.debug('bulk-flow-update',
                  device_id=device.id,
                  flows=flows,
                  groups=groups)

        # sample code that analyzes the incoming flow table
        assert len(groups.items) == 0, "Cannot yet deal with groups"

        for flow in flows.items:
            in_port = get_in_port(flow)
            assert in_port is not None

            if in_port == 2:

                # Downstream rule

                for field in get_ofb_fields(flow):
                    if field.type == ETH_TYPE:
                        _type = field.eth_type
                        pass  # construct ether type based condition here

                    elif field.type == IP_PROTO:
                        _proto = field.ip_proto
                        pass  # construct ip_proto based condition here

                    elif field.type == IN_PORT:
                        _port = field.port
                        pass  # construct in_port based condition here

                    elif field.type == VLAN_VID:
                        _vlan_vid = field.vlan_vid
                        pass  # construct VLAN ID based filter condition here

                    elif field.type == VLAN_PCP:
                        _vlan_pcp = field.vlan_pcp
                        pass  # construct VLAN PCP based filter condition here

                    elif field.type == METADATA:
                        pass  # safe to ignore

                    # TODO
                    else:
                        raise NotImplementedError('field.type={}'.format(
                            field.type))

                for action in get_actions(flow):

                    if action.type == OUTPUT:
                        pass  # construct packet emit rule here

                    elif action.type == PUSH_VLAN:
                        if action.push.ethertype != 0x8100:
                            log.error('unhandled-ether-type',
                                      ethertype=action.push.ethertype)
                        pass  # construct vlan push command here

                    elif action.type == POP_VLAN:
                        pass  # construct vlan pop command here

                    elif action.type == SET_FIELD:
                        assert (action.set_field.field.oxm_class ==
                                ofp.OFPXMC_OPENFLOW_BASIC)
                        field = action.set_field.field.ofb_field
                        if field.type == VLAN_VID:
                            pass  # construct vlan_id set command here
                        else:
                            log.error('unsupported-action-set-field-type',
                                      field_type=field.type)

                    else:
                        log.error('unsupported-action-type',
                                  action_type=action.type)

                # final assembly of low level device flow rule and pushing it
                # down to device
                pass

            elif in_port == 1:

                # Upstream rule

                for field in get_ofb_fields(flow):

                    if field.type == ETH_TYPE:
                        _type = field.eth_type
                        pass  # construct ether type based condition here

                    elif field.type == IP_PROTO:
                        _proto = field.ip_proto
                        pass  # construct ip_proto based condition here

                    elif field.type == IN_PORT:
                        _port = field.port
                        pass  # construct in_port based condition here

                    elif field.type == VLAN_VID:
                        _vlan_vid = field.vlan_vid
                        pass  # construct VLAN ID based filter condition here

                    elif field.type == VLAN_PCP:
                        _vlan_pcp = field.vlan_pcp
                        pass  # construct VLAN PCP based filter condition here

                    elif field.type == UDP_SRC:
                        _udp_src = field.udp_src
                        pass  # construct UDP SRC based filter here

                    elif field.type == UDP_DST:
                        _udp_dst = field.udp_dst
                        pass  # construct UDP DST based filter here

                    # TODO
                    else:
                        raise NotImplementedError('field.type={}'.format(
                            field.type))

                for action in get_actions(flow):

                    if action.type == OUTPUT:
                        pass  # construct packet emit rule here

                    elif action.type == PUSH_VLAN:
                        if action.push.ethertype != 0x8100:
                            log.error('unhandled-ether-type',
                                      ethertype=action.push.ethertype)
                        pass  # construct vlan push command here

                    elif action.type == SET_FIELD:
                        assert (action.set_field.field.oxm_class ==
                                ofp.OFPXMC_OPENFLOW_BASIC)
                        field = action.set_field.field.ofb_field
                        if field.type == VLAN_VID:
                            pass  # construct vlan_id set command here
                        else:
                            log.error('unsupported-action-set-field-type',
                                      field_type=field.type)

                    else:
                        log.error('unsupported-action-type',
                                  action_type=action.type)

                # final assembly of low level device flow rule and pushing it
                # down to device
                pass

            else:
                raise Exception('Port should be 1 or 2 by our convention')

    def update_flows_incrementally(self, device, flow_changes, group_changes):
        raise NotImplementedError()

    def send_proxied_message(self, proxy_address, msg):
        log.info('send-proxied-message', proxy_address=proxy_address, msg=msg)
        # we mimic a response by sending the same message back in a short time
        reactor.callLater(0.2, self.adapter_agent.receive_proxied_message,
                          proxy_address, msg)

    def receive_proxied_message(self, proxy_address, msg):
        raise NotImplementedError()

    def receive_packet_out(self, logical_device_id, egress_port_no, msg):
        log.info('packet-out',
                 logical_device_id=logical_device_id,
                 egress_port_no=egress_port_no,
                 msg_len=len(msg))

    def receive_inter_adapter_message(self, msg):
        raise NotImplementedError()

    def suppress_alarm(self, filter):
        raise NotImplementedError()

    def unsuppress_alarm(self, filter):
        raise NotImplementedError()

    def start_kpi_collection(self, device_id):
        """Simulate periodic KPI metric collection from the device"""
        import random

        @inlineCallbacks  # pretend that we need to do async calls
        def _collect(device_id, prefix):

            try:
                # Step 1: gather metrics from device (pretend it here) - examples
                # upgraded the metrics to include packet statistics for
                # testing.
                nni_port_metrics = self.pm_metrics.collect_nni_metrics()
                pon_port_metrics = self.pm_metrics.collect_pon_metrics()

                olt_metrics = yield dict(cpu_util=20 + 5 * random.random(),
                                         buffer_util=10 + 10 * random.random())

                # Step 2: prepare the KpiEvent for submission
                # we can time-stamp them here (or could use time derived from OLT
                ts = arrow.utcnow().timestamp
                kpi_event = KpiEvent(
                    type=KpiEventType.slice,
                    ts=ts,
                    prefixes={
                        # OLT-level
                        prefix:
                        MetricValuePairs(metrics=olt_metrics),
                        # OLT NNI port
                        prefix + '.nni':
                        MetricValuePairs(metrics=nni_port_metrics),
                        # OLT PON port
                        prefix + '.pon':
                        MetricValuePairs(metrics=pon_port_metrics)
                    })

                # Step 3: submit
                self.adapter_agent.submit_kpis(kpi_event)

            except Exception as e:
                log.exception('failed-to-submit-kpis', e=e)

        self.pm_metrics.start_collector(self.name, device_id, _collect)
        #prefix = 'voltha.{}.{}'.format(self.name, device_id)
        #lc = LoopingCall(_collect, device_id, prefix)
        #lc.start(interval=15)  # TODO make this configurable

    def start_alarm_simulation(self, device_id):
        """Simulate periodic device alarms"""
        import random

        def _generate_alarm(device_id):

            try:
                # Randomly choose values for each enum types
                severity = random.choice(
                    list(v for k, v in AlarmEventSeverity.DESCRIPTOR.
                         enum_values_by_name.items()))

                state = random.choice(
                    list(v for k, v in AlarmEventState.DESCRIPTOR.
                         enum_values_by_name.items()))

                type = random.choice(
                    list(
                        v for k, v in
                        AlarmEventType.DESCRIPTOR.enum_values_by_name.items()))

                category = random.choice(
                    list(v for k, v in AlarmEventCategory.DESCRIPTOR.
                         enum_values_by_name.items()))

                description = "Simulated alarm - " \
                              "device:{} " \
                              "type:{} " \
                              "severity:{} " \
                              "state:{} " \
                              "category:{}".format(device_id,
                                                   type.name,
                                                   severity.name,
                                                   state.name,
                                                   category.name)

                current_context = {}
                for key, value in self.__dict__.items():
                    current_context[key] = str(value)

                alarm_event = self.adapter_agent.create_alarm(
                    resource_id=device_id,
                    type=type.number,
                    category=category.number,
                    severity=severity.number,
                    state=state.number,
                    description=description,
                    context=current_context)

                self.adapter_agent.submit_alarm(device_id, alarm_event)

            except Exception as e:
                log.exception('failed-to-submit-alarm', e=e)

        alarm_lc = LoopingCall(_generate_alarm, device_id)
        alarm_lc.start(30)

    def create_interface(self, device, data):
        raise NotImplementedError()

    def update_interface(self, device, data):
        raise NotImplementedError()

    def remove_interface(self, device, data):
        raise NotImplementedError()

    def receive_onu_detect_state(self, device_id, state):
        raise NotImplementedError()

    def create_tcont(self, device, tcont_data, traffic_descriptor_data):
        raise NotImplementedError()

    def update_tcont(self, device, tcont_data, traffic_descriptor_data):
        raise NotImplementedError()

    def remove_tcont(self, device, tcont_data, traffic_descriptor_data):
        raise NotImplementedError()

    def create_gemport(self, device, data):
        raise NotImplementedError()

    def update_gemport(self, device, data):
        raise NotImplementedError()

    def remove_gemport(self, device, data):
        raise NotImplementedError()

    def create_multicast_gemport(self, device, data):
        raise NotImplementedError()

    def update_multicast_gemport(self, device, data):
        raise NotImplementedError()

    def remove_multicast_gemport(self, device, data):
        raise NotImplementedError()

    def create_multicast_distribution_set(self, device, data):
        raise NotImplementedError()

    def update_multicast_distribution_set(self, device, data):
        raise NotImplementedError()

    def remove_multicast_distribution_set(self, device, data):
        raise NotImplementedError()

    # ~~~~~~~~~~~~~~~~~~~~ Embedded test Klein rest server ~~~~~~~~~~~~~~~~~~~~

    def get_test_control_site(self):
        return Site(self.app.resource())

    @app.route('/devices/<string:device_id>/detect_onus')
    def detect_onus(self, request, device_id):
        log.info('detect-onus', request=request, device_id=device_id)
        self._simulate_detection_of_onus(device_id)
        return '{"status": "OK"}'

    @app.route('/devices/<string:device_id>/test_eapol_in')
    def test_eapol_in(self, request, device_id):
        """Simulate a packet in message posted upstream"""
        log.info('test_eapol_in', request=request, device_id=device_id)
        eapol_start = str(
            Ether(src='00:11:22:33:44:55') / EAPOL(type=1, len=0) /
            Padding(load=42 * '\x00'))
        device = self.adapter_agent.get_device(device_id)
        self.adapter_agent.send_packet_in(logical_device_id=device.parent_id,
                                          logical_port_no=1,
                                          packet=eapol_start)
        return '{"status": "sent"}'
Example #24
0
class RubyAdapterHandler(object):

    name = "microsemi_olt"

    supported_device_types = [
        DeviceType(id=name, adapter=name, accepts_bulk_flow_update=True)
    ]

    def __init__(self, adaptor_agent, config, descriptor):
        self.adaptor_agent = adaptor_agent
        self.config = config
        self.descriptor = descriptor
        self.device = None
        self.device_manager = None
        self.comm = None
        self.activation = None
        self.olt = None
        self.ports = dict()
        self.last_iteration_ports = []
        self.interface = registry('main').get_args().interface
        self.flow_queue = DeferredQueue()

    def stop(self):
        log.debug('stopping')
        self._abandon(self.target)
        log.info('stopped')
        return self

    def activate(self, device):
        log.debug('activate-device', device=device)
        self.last_iteration_ports = []
        self.device = device
        self.device_manager = DeviceManager(device, self.adaptor_agent)
        self.target = device.mac_address
        self.comm = PAS5211Communication(dst_mac=self.target,
                                         iface=self.interface)

        self.olt = OltStateMachine(iface=self.interface,
                                   comm=self.comm,
                                   target=self.target,
                                   device=self.device_manager)
        self.activation = ActivationWatcher(iface=self.interface,
                                            comm=self.comm,
                                            target=self.target,
                                            device=self.device_manager,
                                            olt_adapter=self)

        reactor.callLater(0, self.wait_for_flow_events, device)

        self.olt.runbg()
        self.activation.runbg()

    def reboot_device(self, device):
        try:
            log.debug('reboot-device', device=device)
            # Stop ONUS ...
            self.device_manager.update_child_devices_state(
                admin_state=AdminState.DISABLED)
            # ... and then delete them!
            self.device_manager.delete_all_child_devices
            # Wait 10s to reboot OLT
            reactor.callLater(10, self.reboot_olt, device)
        except Exception as e:
            log.exception('reboot-olt-exception', e=e)

    def reboot_olt(self, device):
        try:
            # Stop OLT...
            self.device_manager.delete_logical_device()
            self.olt.stop()
            self.activation.stop()
            # ... and start again! ONUS will activate from events got from OLT
            self.last_iteration_ports = []
            self.ports.clear()
            self.activate(device)
        except Exception as e:
            log.exception('reboot-olt-exception', e=e)

    def abandon_device(self, device):
        self._abandon(self.target)

    def get_port_list(self, flows):
        port_list = []
        for flow in flows:
            _in_port = fd.get_in_port(flow)
            if _in_port not in (0, PMC_UPSTREAM_PORT):
                if _in_port not in port_list:
                    port_list.append(_in_port)
                    log.debug('field-type-in-port',
                              in_port=_in_port,
                              port_list=port_list)
        return port_list

    def get_svlan(self, port, flows):
        svlan_id = None
        for flow in flows:
            _in_port = fd.get_in_port(flow)
            if _in_port == PMC_UPSTREAM_PORT:
                log.debug('svlan-port-match')
                metadata = fd.get_metadata(flow)
                if metadata:
                    if metadata == port:
                        svlan_id = self.get_vlan(flow) & 0xfff
                        log.debug('SVLAN found:{}'.format(svlan_id))

        return svlan_id

    def get_cvlan(self, svlan_id, port, flows):
        cvlan_id = None
        # Look for cvlan ...
        for flow in flows:
            _in_port = fd.get_in_port(flow)
            if _in_port == port:
                log.debug('cvlan-port-match')
                for action in fd.get_actions(flow):
                    if action.type == fd.SET_FIELD:
                        vlan = action.set_field.field.ofb_field.vlan_vid & 0xfff
                        if vlan == svlan_id:
                            cvlan_id = self.get_vlan(flow) & 0xfff
                            log.debug('CVLAN found:{}'.format(cvlan_id))
        return cvlan_id

    def get_uplink_bandwidth(self, cvlan_id, svlan_id, port, flows):
        bandwidth = None
        # Look for cvlan ...
        for flow in flows:
            _in_port = fd.get_in_port(flow)
            if _in_port == port:
                log.debug('uplink-bandwidth-port-match')
                for action in fd.get_actions(flow):
                    if action.type == fd.SET_FIELD:
                        vlan = action.set_field.field.ofb_field.vlan_vid & 0xfff
                        if vlan == svlan_id:
                            bandwidth = fd.get_metadata(flow)
                            if bandwidth:
                                log.debug(
                                    'Bandwidth found:{}'.format(bandwidth))
        return bandwidth

    def get_downlink_bandwidth(self, cvlan_id, svlan_id, port, flows):
        return None

    def update_flow_table(self, device, flows):
        try:
            self.flow_queue.put({'flows': flows})
        except Exception as e:
            log.debug('flow-enqueue-exception', e=e)

    @inlineCallbacks
    def wait_for_flow_events(self, device):
        log.debug('wait-for-flow-events', device=device)

        event = yield self.flow_queue.get()
        flows = event.get('flows')

        try:
            cvlan_id = None
            svlan_id = None

            log.debug('wait-for-flow-events-flow', device=device)

            # Look for ports mentioned in flows received ...
            port_list = self.get_port_list(flows.items)

            log.debug("list-ports", port_list=port_list)

            new_ports = set(port_list) - set(self.last_iteration_ports)
            log.debug("new-ports", new_ports=new_ports)

            disconnected_ports = set(
                self.last_iteration_ports) - set(port_list)
            log.debug("disconnected-ports",
                      disconnected_ports=disconnected_ports)

            # For those new ports, check if we can proceed with flow installation...
            for port in new_ports:
                # Got svlan for that port ...
                svlan_id = self.get_svlan(port, flows.items)

                # ... look for the corresponding cvlan...
                if svlan_id:
                    cvlan_id = self.get_cvlan(svlan_id, port, flows.items)

                # Both vlan found!
                if svlan_id and cvlan_id:

                    # Get bandwidths from flow info...
                    uplink_bandwidth = self.get_uplink_bandwidth(
                        cvlan_id, svlan_id, port, flows.items)
                    if uplink_bandwidth == None:
                        uplink_bandwidth = SLA_be_bw_gros

                    downlink_bandwidth = self.get_downlink_bandwidth(
                        cvlan_id, svlan_id, port, flows.items)
                    if downlink_bandwidth == None:
                        if uplink_bandwidth == None:
                            downlink_bandwidth = SLA_be_bw_gros
                        else:
                            downlink_bandwidth = uplink_bandwidth

                    onu_id = self.ports[port]['onu_id']
                    onu_session_id = self.ports[port]['onu_session_id']
                    port_id = 1000 + 16 * onu_id
                    alloc_id = port_id
                    channel_id = port / 32

                    # Check if flow is already installed, if so, continue with next port
                    if self.ports[port].get('cvlan') and self.ports[port].get(
                            'svlan'):
                        if self.ports[port].get('svlan') == svlan_id:
                            # Flow already installed
                            if self.ports[port].get('cvlan') == cvlan_id:
                                continue
                            # We have new VLANs so we reinstall!
                            else:
                                self.reinstall_flows_sequence(
                                    device, onu_id, svlan_id, cvlan_id,
                                    port_id, alloc_id, onu_session_id,
                                    channel_id, uplink_bandwidth,
                                    downlink_bandwidth)
                        else:
                            # New installation...
                            self.install_flows_sequence(
                                device, onu_id, svlan_id, cvlan_id, port_id,
                                alloc_id, onu_session_id, channel_id,
                                uplink_bandwidth, downlink_bandwidth)
                    else:
                        # New installation...
                        self.install_flows_sequence(device, onu_id, svlan_id,
                                                    cvlan_id, port_id,
                                                    alloc_id, onu_session_id,
                                                    channel_id,
                                                    uplink_bandwidth,
                                                    downlink_bandwidth)

                    self.ports[port]['svlan'] = svlan_id
                    self.ports[port]['cvlan'] = cvlan_id

                else:
                    # Finally, it is an incomplete port, so we remove from port list
                    try:
                        port_list.remove(port)
                    except Exception as e:
                        log.debug('remove-non-existing-port', e=e)

            # For those ports without flows, uninstall them
            for port in disconnected_ports:

                onu_id = self.ports[port]['onu_id']
                onu_session_id = self.ports[port]['onu_session_id']
                port_id = 1000 + 16 * onu_id
                alloc_id = port_id
                channel_id = port / 32

                if self.ports[port].get('cvlan') and self.ports[port].get(
                        'svlan'):
                    self.uninstall_flows_sequence(device, onu_id, port_id,
                                                  alloc_id, onu_session_id,
                                                  channel_id)
                    self.ports[port]['svlan'] = None
                    self.ports[port]['cvlan'] = None

            self.last_iteration_ports = port_list
            log.debug('last-iteration-ports', ports=self.last_iteration_ports)

        except Exception as e:
            log.exception('failed-to-olt-update-flow-table', e=e)

        reactor.callLater(0, self.wait_for_flow_events, device)

    def get_vlan(self, flow):
        for field in fd.get_ofb_fields(flow):
            if field.type == fd.VLAN_VID:
                return field.vlan_vid
        return None

    def reinstall_flows_sequence(self, device, onu_id, svlan, cvlan, port_id,
                                 alloc_id, onu_session_id, channel_id,
                                 uplink_bandwidth, downlink_bandwidth):
        log.debug('init-flow-reinstallaton')
        try:
            olt = OltReinstallFlowStateMachine(
                iface=self.interface,
                comm=self.comm,
                target=self.target,
                device=self.device_manager,
                onu_id=onu_id,
                channel_id=channel_id,
                port_id=port_id,
                onu_session_id=onu_session_id,
                alloc_id=alloc_id,
                svlan_id=svlan,
                cvlan_id=cvlan,
                uplink_bandwidth=uplink_bandwidth,
                downlink_bandwidth=downlink_bandwidth)
            olt.runbg()
        except Exception as e:
            log.exception('failed-to-launch-reinstall-flow', e=e)

    def install_flows_sequence(self, device, onu_id, svlan, cvlan, port_id,
                               alloc_id, onu_session_id, channel_id,
                               uplink_bandwidth, downlink_bandwidth):
        log.debug('init-flow-installaton')
        try:
            olt = OltInstallFlowStateMachine(
                iface=self.interface,
                comm=self.comm,
                target=self.target,
                device=self.device_manager,
                onu_id=onu_id,
                channel_id=channel_id,
                port_id=port_id,
                onu_session_id=onu_session_id,
                alloc_id=alloc_id,
                svlan_id=svlan,
                cvlan_id=cvlan,
                uplink_bandwidth=uplink_bandwidth,
                downlink_bandwidth=downlink_bandwidth)
            olt.runbg()
        except Exception as e:
            log.exception('failed-to-launch-install-flow', e=e)

    def uninstall_flows_sequence(self, device, onu_id, port_id, alloc_id,
                                 onu_session_id, channel_id):
        log.debug('init-flow-deinstallaton')
        try:
            olt = OltRemoveFlowStateMachine(iface=self.interface,
                                            comm=self.comm,
                                            target=self.target,
                                            device=self.device_manager,
                                            onu_id=onu_id,
                                            channel_id=channel_id,
                                            port_id=port_id,
                                            onu_session_id=onu_session_id,
                                            alloc_id=alloc_id)
            olt.runbg()
        except Exception as e:
            log.exception('failed-to-launch-deinstallaton-flow', e=e)

    def _abandon(self, target):
        self.olt.stop()
        self.activation.stop()

    # Method exposed to Activation Watcher to get onu info from Activation
    def add_onu_info(self, port, onu_id, onu_session_id):
        existing_port = self.ports.get(port)
        if existing_port:
            existing_port['onu_id'] = onu_id
            existing_port['onu_session_id'] = onu_session_id
        else:
            self.ports[port] = {
                'onu_id': onu_id,
                'onu_session_id': onu_session_id
            }

    def send_proxied_message(self, proxy_address, msg):
        log.debug("send-proxied-message-olt-handler",
                  proxy_address=proxy_address)

        if isinstance(msg, OmciFrame):
            omci_proxy = OMCIProxy(proxy_address=proxy_address,
                                   msg=msg,
                                   adapter_agent=self.adaptor_agent,
                                   target=self.device.mac_address,
                                   comm=self.comm,
                                   iface=self.interface)
            omci_proxy.runbg()

        else:
            api_proxy = APIProxy(proxy_address=proxy_address,
                                 msg=msg,
                                 adapter_agent=self.adaptor_agent,
                                 target=self.device.mac_address,
                                 comm=self.comm,
                                 iface=self.interface)
            api_proxy.runbg()
Example #25
0
class PmcsOnu(object):

    name = 'pmcs_onu'

    supported_device_types = [
        DeviceType(
            id=name,
            adapter=name,
            accepts_bulk_flow_update=True
        )
    ]

    def __init__(self, adapter_agent, config):
        self.adapter_agent = adapter_agent
        self.config = config
        self.descriptor = Adapter(
            id=self.name,
            vendor='PMCS',
            version='0.1',
            config=AdapterConfig(log_level=LogLevel.INFO)
        )

    def start(self):
        log.debug('starting')
        log.info('started')

    def stop(self):
        log.debug('stopping')
        log.info('stopped')

    def adapter_descriptor(self):
        return self.descriptor

    def device_types(self):
        return DeviceTypes(items=self.supported_device_types)

    def health(self):
        return HealthStatus(state=HealthStatus.HealthState.HEALTHY)

    def change_master_state(self, master):
        raise NotImplementedError()

    def adopt_device(self, device):
        return device

    def abandon_device(self, device):
        raise NotImplementedError()

    def deactivate_device(self, device):
        raise NotImplementedError()

    def update_flows_bulk(self, device, flows, groups):
        log.info('bulk-flow-update', device_id=device.id,
                  flows=flows, groups=groups)

    def update_flows_incrementally(self, device, flow_changes, group_changes):
        raise NotImplementedError()

    def send_proxied_message(self, proxy_address, msg):
        log.info('send-proxied-message', proxy_address=proxy_address, msg=msg)

    def receive_proxied_message(self, proxy_address, msg):
        log.info('receive-proxied-message', proxy_address=proxy_address,
                 device_id=proxy_address.device_id, msg=msg)

    def receive_packet_out(self, logical_device_id, egress_port_no, msg):
        log.info('packet-out', logical_device_id=logical_device_id,
                 egress_port_no=egress_port_no, msg_len=len(msg))
Example #26
0
class RubyAdapter(object):

    name = "microsemi_olt"

    supported_device_types = [
        DeviceType(id=name, adapter=name, accepts_bulk_flow_update=True)
    ]

    def __init__(self, adaptor_agent, config):
        self.adaptor_agent = adaptor_agent
        self.config = config
        self.device_handlers = dict()
        self.descriptor = Adapter(
            id=self.name,
            vendor='Microsemi / Celestica',
            version='0.2',
            config=AdapterConfig(log_level=LogLevel.INFO))

    def start(self):
        log.debug('starting')
        log.info('started')
        return self

    def stop(self):
        log.debug('stopping')
        for handler in self.device_handlers:
            handler.stop()
        log.info('stopped')
        return self

    def adapter_descriptor(self):
        return self.descriptor

    def device_types(self):
        return DeviceTypes(items=self.supported_device_types)

    def health(self):
        return HealthStatus(state=HealthStatus.HealthState.HEALTHY)

    def change_master_state(self, master):
        raise NotImplementedError()

    def adopt_device(self, device):
        log.debug('adopt-device', device=device)
        self.device_handlers[device.id] = RubyAdapterHandler(
            self.adaptor_agent, self.config, self.descriptor)
        reactor.callLater(0, self.device_handlers[device.id].activate, device)

    def reconcile_device(self, device):
        raise NotImplementedError()

    def abandon_device(self, device):
        self.stop()

    def disable_device(self, device):
        raise NotImplementedError()

    def reenable_device(self, device):
        raise NotImplementedError()

    def update_pm_config(self, device, pm_configs):
        raise NotImplementedError()

    def reboot_device(self, device):
        log.debug('reboot-device', device=device)
        device_handler = self.device_handlers[device.id]
        reactor.callLater(0, device_handler.reboot_device, device)

    def create_tcont(self, device, tcont_data, traffic_descriptor_data):
        raise NotImplementedError()

    def update_tcont(self, device, tcont_data, traffic_descriptor_data):
        raise NotImplementedError()

    def remove_tcont(self, device, tcont_data, traffic_descriptor_data):
        raise NotImplementedError()

    def create_gemport(self, device, data):
        raise NotImplementedError()

    def update_gemport(self, device, data):
        raise NotImplementedError()

    def remove_gemport(self, device, data):
        raise NotImplementedError()

    def create_multicast_gemport(self, device, data):
        raise NotImplementedError()

    def update_multicast_gemport(self, device, data):
        raise NotImplementedError()

    def remove_multicast_gemport(self, device, data):
        raise NotImplementedError()

    def create_multicast_distribution_set(self, device, data):
        raise NotImplementedError()

    def update_multicast_distribution_set(self, device, data):
        raise NotImplementedError()

    def remove_multicast_distribution_set(self, device, data):
        raise NotImplementedError()

    def download_image(self, device, request):
        raise NotImplementedError()

    def get_image_download_status(self, device, request):
        raise NotImplementedError()

    def cancel_image_download(self, device, request):
        raise NotImplementedError()

    def activate_image_update(self, device, request):
        raise NotImplementedError()

    def revert_image_update(self, device, request):
        raise NotImplementedError()

    def self_test_device(self, device):
        log.debug('self-test-device', device=device.id)
        raise NotImplementedError()

    def delete_device(self, device):
        raise NotImplementedError()

    def get_device_details(self, device):
        raise NotImplementedError()

    def update_flows_bulk(self, device, flows, groups):
        try:
            log.debug('olt-bulk-flow-update',
                      device_id=device.id,
                      flows=flows,
                      groups=groups)

            handler = self.device_handlers[device.id]
            if handler:
                handler.update_flow_table(device, flows)
            else:
                log.debug("No handler found for device {}".format(device.id))

        except Exception as e:
            log.exception('failed-olt-bulk-flow-update', e=e)

    def create_interface(self, device, data):
        raise NotImplementedError()

    def update_interface(self, device, data):
        raise NotImplementedError()

    def remove_interface(self, device, data):
        raise NotImplementedError()

    def receive_onu_detect_state(self, device_id, state):
        raise NotImplementedError()

    def send_proxied_message(self, proxy_address, msg):
        log.debug("send-proxied-message-olt", proxy_address=proxy_address)
        device = self.adaptor_agent.get_device(proxy_address.device_id)
        self.device_handlers[device.id].send_proxied_message(
            proxy_address, msg)

    def receive_proxied_message(self, proxy_address, msg):
        log.debug("receive-proxied-message-olt-handler",
                  proxy_address=proxy_address)
        raise NotImplementedError()

    def update_flows_incrementally(self, device, flow_changes, group_changes):
        raise NotImplementedError()

    def receive_packet_out(self, logical_device_id, egress_port_no, msg):
        log.debug('packet-out',
                  logical_device_id=logical_device_id,
                  egress_port_no=egress_port_no,
                  msg_len=len(msg))

    def receive_inter_adapter_message(self, msg):
        raise NotImplementedError()

    def suppress_alarm(self, filter):
        raise NotImplementedError()

    def unsuppress_alarm(self, filter):
        raise NotImplementedError()
Example #27
0
class BroadcomOnuAdapter(object):

    name = 'broadcom_onu'

    supported_device_types = [
        DeviceType(id=name, adapter=name, accepts_bulk_flow_update=True)
    ]

    def __init__(self, adapter_agent, config):
        self.adapter_agent = adapter_agent
        self.config = config
        self.descriptor = Adapter(
            id=self.name,
            vendor='Voltha project',
            version='0.4',
            config=AdapterConfig(log_level=LogLevel.INFO))
        self.devices_handlers = dict()  # device_id -> BroadcomOnuHandler()

    def start(self):
        log.debug('starting')
        log.info('started')

    def stop(self):
        log.debug('stopping')
        log.info('stopped')

    def adapter_descriptor(self):
        return self.descriptor

    def device_types(self):
        return DeviceTypes(items=self.supported_device_types)

    def health(self):
        return HealthStatus(state=HealthStatus.HealthState.HEALTHY)

    def change_master_state(self, master):
        raise NotImplementedError()

    def adopt_device(self, device):
        log.info('adopt_device', device_id=device.id)
        self.devices_handlers[
            device.proxy_address.channel_id] = BroadcomOnuHandler(
                self, device.id)
        reactor.callLater(
            0, self.devices_handlers[device.proxy_address.channel_id].activate,
            device)
        return device

    def abandon_device(self, device):
        raise NotImplementedError()

    def disable_device(self, device):
        raise NotImplementedError()

    def reenable_device(self, device):
        raise NotImplementedError()

    def reboot_device(self, device):
        raise NotImplementedError()

    def delete_device(self, device):
        raise NotImplementedError()

    def get_device_details(self, device):
        raise NotImplementedError()

    def update_pm_config(self, device, pm_configs):
        raise NotImplementedError()

    def update_flows_bulk(self, device, flows, groups):
        log.info('bulk-flow-update',
                 device_id=device.id,
                 flows=flows,
                 groups=groups)
        assert len(groups.items) == 0
        handler = self.devices_handlers[device.proxy_address.channel_id]
        return handler.update_flow_table(device, flows.items)

    def update_flows_incrementally(self, device, flow_changes, group_changes):
        raise NotImplementedError()

    def send_proxied_message(self, proxy_address, msg):
        log.info('send-proxied-message', proxy_address=proxy_address, msg=msg)

    def receive_proxied_message(self, proxy_address, msg):
        log.info('receive-proxied-message',
                 proxy_address=proxy_address,
                 device_id=proxy_address.device_id,
                 msg=hexify(msg))
        handler = self.devices_handlers[proxy_address.channel_id]
        handler.receive_message(msg)

    def receive_packet_out(self, logical_device_id, egress_port_no, msg):
        log.info('packet-out',
                 logical_device_id=logical_device_id,
                 egress_port_no=egress_port_no,
                 msg_len=len(msg))
Example #28
0
class TibitOltAdapter(object):

    name = 'tibit_olt'

    supported_device_types = [
        DeviceType(
            id='tibit_olt',
            adapter=name,
            accepts_bulk_flow_update=True
        )
    ]

    def __init__(self, adapter_agent, config):
        self.adapter_agent = adapter_agent
        self.config = config
        self.descriptor = Adapter(
            id=self.name,
            vendor='Tibit Communications Inc.',
            version='0.1',
            config=AdapterConfig(log_level=LogLevel.INFO)
        )
        self.interface = registry('main').get_args().interface
        self.io_port = None
        self.incoming_queues = {}  # OLT mac_address -> DeferredQueue()
        self.device_ids = {}  # OLT mac_address -> device_id
        self.vlan_to_device_ids = {}  # c-vid -> (device_id, logical_device_id)

    def start(self):
        log.debug('starting', interface=self.interface)
        log.info('started', interface=self.interface)

    def stop(self):
        log.debug('stopping')
        if self.io_port is not None:
            registry('frameio').close_port(self.io_port)
        log.info('stopped')

    def adapter_descriptor(self):
        return self.descriptor

    def device_types(self):
        return DeviceTypes(items=self.supported_device_types)

    def health(self):
        return HealthStatus(state=HealthStatus.HealthState.HEALTHY)

    def change_master_state(self, master):
        raise NotImplementedError()

    def adopt_device(self, device):
        log.info('adopt-device', device=device)
        self._activate_io_port()
        reactor.callLater(0, self._launch_device_activation, device)

    def _activate_io_port(self):
        if self.io_port is None:
            self.io_port = registry('frameio').open_port(
                self.interface, self._rcv_io, is_tibit_frame)

    @inlineCallbacks
    def _launch_device_activation(self, device):
        try:
            log.debug('launch_dev_activation')
            # prepare receive queue
            self.incoming_queues[device.mac_address] = DeferredQueue(size=100)

            # add mac_address to device_ids table
            olt_mac = device.mac_address
            self.device_ids[olt_mac] = device.id

            # send out ping to OLT device
            ping_frame = self._make_ping_frame(mac_address=olt_mac)
            self.io_port.send(ping_frame)

            # wait till we receive a response
            ## TODO add timeout mechanism so we can signal if we cannot reach
            ##device
            while True:
                response = yield self.incoming_queues[olt_mac].get()
                # verify response and if not the expected response
                if 1: # TODO check if it is really what we expect, and wait if not
                    break

        except Exception as e:
            log.exception('launch device failed', e=e)

        # if we got response, we can fill out the device info, mark the device
        # reachable
        jdev = json.loads(response.payload.payload.body.load)
        device.root = True
        device.vendor = 'Tibit Communications, Inc.'
        device.model = jdev.get('results', {}).get('device', 'DEVICE_UNKNOWN')
        device.hardware_version = jdev['results']['datecode']
        device.firmware_version = jdev['results']['firmware']
        device.software_version = jdev['results']['modelversion']
        device.serial_number = jdev['results']['manufacturer']

        device.connect_status = ConnectStatus.REACHABLE
        self.adapter_agent.update_device(device)

        # then shortly after we create some ports for the device
        log.info('create-port')
        nni_port = Port(
            port_no=2,
            label='NNI facing Ethernet port',
            type=Port.ETHERNET_NNI,
            admin_state=AdminState.ENABLED,
            oper_status=OperStatus.ACTIVE
        )
        self.adapter_agent.add_port(device.id, nni_port)
        self.adapter_agent.add_port(device.id, Port(
            port_no=1,
            label='PON port',
            type=Port.PON_OLT,
            admin_state=AdminState.ENABLED,
            oper_status=OperStatus.ACTIVE
        ))

        log.info('create-logical-device')
        # then shortly after we create the logical device with one port
        # that will correspond to the NNI port
        ld = LogicalDevice(
            desc=ofp_desc(
                mfr_desc=device.vendor,
                hw_desc=jdev['results']['device'],
                sw_desc=jdev['results']['firmware'],
                serial_num=uuid4().hex,
                dp_desc='n/a'
            ),
            switch_features=ofp_switch_features(
                n_buffers=256,  # TODO fake for now
                n_tables=2,  # TODO ditto
                capabilities=(  # TODO and ditto
                    OFPC_FLOW_STATS
                    | OFPC_TABLE_STATS
                    | OFPC_PORT_STATS
                    | OFPC_GROUP_STATS
                )
            ),
            root_device_id=device.id
        )
        ld_initialized = self.adapter_agent.create_logical_device(ld)
        cap = OFPPF_10GB_FD | OFPPF_FIBER
        self.adapter_agent.add_logical_port(ld_initialized.id, LogicalPort(
            id='nni',
            ofp_port=ofp_port(
                port_no=0,
                hw_addr=mac_str_to_tuple(device.mac_address),
                name='nni',
                config=0,
                state=OFPPS_LIVE,
                curr=cap,
                advertised=cap,
                peer=cap,
                curr_speed=OFPPF_10GB_FD,
                max_speed=OFPPF_10GB_FD
            ),
            device_id=device.id,
            device_port_no=nni_port.port_no,
            root_port=True
        ))

        # and finally update to active
        device = self.adapter_agent.get_device(device.id)
        device.parent_id = ld_initialized.id
        device.oper_status = OperStatus.ACTIVE
        self.adapter_agent.update_device(device)

        # Just transitioned to ACTIVE, wait a tenth of second
        # before checking for ONUs
        reactor.callLater(0.1, self._detect_onus, device)

    @inlineCallbacks
    def _detect_onus(self, device):
        # send out get 'links' to the OLT device
        olt_mac = device.mac_address
        links_frame = self._make_links_frame(mac_address=olt_mac)
        self.io_port.send(links_frame)
        while True:
            response = yield self.incoming_queues[olt_mac].get()
            # verify response and if not the expected response
            if 1: # TODO check if it is really what we expect, and wait if not
                break

        jdev = json.loads(response.payload.payload.body.load)
        onu_mac = ''
        for macid in jdev['results']:
            if macid['macid'] is None:
                log.info('MAC ID is NONE %s' % str(macid['macid']))
            elif macid['macid'][:6].upper() == SUMITOMO_ELECTRIC_INDUSTRIES_OUI:
                onu_mac = macid['macid']
                log.info('SUMITOMO mac address %s' % str(macid['macid']))
                log.info('activate-olt-for-onu-%s' % onu_mac)
                # Convert from string to colon separated form
                onu_mac = ':'.join(s.encode('hex') for s in onu_mac.decode('hex'))
                vlan_id = self._olt_side_onu_activation(int(macid['macid'][-4:-2], 16))
                self.adapter_agent.child_device_detected(
                    parent_device_id=device.id,
                    parent_port_no=1,
                    child_device_type='dpoe_onu',
                    mac_address = onu_mac,
                    proxy_address=Device.ProxyAddress(
                        device_id=device.id,
                        channel_id=vlan_id
                        ),
                        vlan=vlan_id
                    )

            else:
                onu_mac = '000c' + macid.get('macid', 'e2000000')[4:]
                log.info('activate-olt-for-onu-%s' % onu_mac)
                # Convert from string to colon separated form
                onu_mac = ':'.join(s.encode('hex') for s in onu_mac.decode('hex'))
                vlan_id = self._olt_side_onu_activation(int(macid['macid'][-4:-2], 16))
                self.adapter_agent.child_device_detected(
                    parent_device_id=device.id,
                    parent_port_no=1,
                    child_device_type='tibit_onu',
                    mac_address = onu_mac,
                    proxy_address=Device.ProxyAddress(
                        device_id=device.id,
                        channel_id=vlan_id
                        ),
                        vlan=vlan_id
                    )

            # also record the vlan_id -> (device_id, logical_device_id, linkid) for
            # later use.  The linkid is the macid returned.
            self.vlan_to_device_ids[vlan_id] = (device.id, device.parent_id, macid.get('macid', 0))

        # Give the ONUs a chance to arrive before starting metric collection
        reactor.callLater(5.0, self.start_kpi_collection, device.id)

    def _olt_side_onu_activation(self, serial):
        """
        This is where if this was a real OLT, the OLT-side activation for
        the new ONU should be performed. By the time we return, the OLT shall
        be able to provide tunneled (proxy) communication to the given ONU,
        using the returned information.
        """
        vlan_id = serial + 200
        return vlan_id

    def _rcv_io(self, port, frame):

        log.info('frame-received', frame=hexify(frame))

        # make into frame to extract source mac
        response = Ether(frame)

        if response.haslayer(Dot1Q):

            # All OAM responses from the OLT should have a TIBIT_MGMT_VLAN.
            # Responses from the ONUs should have a TIBIT_MGMT_VLAN followed by a ONU CTAG
            # All packet-in frames will have the TIBIT_PACKET_IN_VLAN.
            if response.getlayer(Dot1Q).type == 0x8100:

                if response.getlayer(Dot1Q).vlan == TIBIT_PACKET_IN_VLAN:

                    inner_tag_and_rest = response.payload.payload

                    if isinstance(inner_tag_and_rest, Dot1Q):

                        cvid = inner_tag_and_rest.vlan

                        frame = Ether(src=response.src,
                                      dst=response.dst,
                                      type=inner_tag_and_rest.type) /\
                                      inner_tag_and_rest.payload

                        _, logical_device_id = self.vlan_to_device_ids.get(cvid)
                        if logical_device_id is None:
                            log.error('invalid-cvid', cvid=cvid)
                        else:
                            self.adapter_agent.send_packet_in(
                                logical_device_id=logical_device_id,
                                logical_port_no=cvid,  # C-VID encodes port no
                                packet=str(frame))

                    else:
                        log.error('packet-in-single-tagged',
                                  frame=hexify(response))

                else:
                    ## Mgmt responses received from the ONU
                    ## Since the type of the first layer is 0x8100,
                    ## then the frame must have an inner tag layer
                    olt_mac = response.src
                    device_id = self.device_ids[olt_mac]
                    channel_id = response[Dot1Q:2].vlan
                    log.info('received_channel_id', channel_id=channel_id,
                             device_id=device_id)

                    proxy_address=Device.ProxyAddress(
                        device_id=device_id,
                        channel_id=channel_id
                        )
                    # pop dot1q header(s)
                    msg = response.payload.payload
                    self.adapter_agent.receive_proxied_message(proxy_address, msg)

            else:
                ## Mgmt responses received from the OLT
                ## enqueue incoming parsed frame to right device
                log.info('received-dot1q-not-8100')
                self.incoming_queues[response.src].put(response)

    def _make_ping_frame(self, mac_address):
        # Create a json packet
        json_operation_str = '{\"operation\":\"version\"}'
        frame = Ether(dst=mac_address)/Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY)/TBJSON(data='json %s' % json_operation_str)
        return str(frame)

    def _make_links_frame(self, mac_address):
        # Create a json packet
        json_operation_str = '{\"operation\":\"links\"}'
        frame = Ether(dst=mac_address)/Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY)/TBJSON(data='json %s' % json_operation_str)
        return str(frame)

    def _make_stats_frame(self, mac_address, itype, link):
        # Create a json packet
        json_operation_str = ('{\"operation\":\"stats\",\"parameters\":{\"itype\":\"%s\",\"iinst\",\"0\",\"macid\":\"%s\"}}' % (itype, link))
        frame = Ether(dst=mac_address)/Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY)/TBJSON(data='json %s' % json_operation_str)
        return str(frame)

    def abandon_device(self, device):
        raise NotImplementedError(0
                                  )
    def deactivate_device(self, device):
        raise NotImplementedError()

    def update_flows_bulk(self, device, flows, groups):
        log.info('########################################')
        log.info('bulk-flow-update', device_id=device.id,
                 flows=flows, groups=groups)
        assert len(groups.items) == 0, "Cannot yet deal with groups"

        # extract ONU VID
        vid_from_device_id = {v[0]: k for k,v in self.vlan_to_device_ids.iteritems()}
        ONU_VID = vid_from_device_id[device.id]

        Clause = {v: k for k, v in ClauseSubtypeEnum.iteritems()}
        Operator = {v: k for k, v in RuleOperatorEnum.iteritems()}

        for flow in flows.items:

            try:
                in_port = get_in_port(flow)
                assert in_port is not None

                precedence = 255 - min(flow.priority / 256, 255)

                if in_port == 2:
                    log.info('#### Downstream Rule ####')
                    dn_req = NetworkToNetworkPortObject()
                    dn_req /= PortIngressRuleHeader(precedence=precedence)

                    for field in get_ofb_fields(flow):

                        if field.type == ETH_TYPE:
                            _type = field.eth_type
                            log.info('#### field.type == ETH_TYPE ####')
                            dn_req /= PortIngressRuleClauseMatchLength02(
                                fieldcode=Clause['L2 Type/Len'],
                                operator=Operator['=='],
                                match=_type)

                        elif field.type == IP_PROTO:
                            _proto = field.ip_proto
                            log.info('#### field.type == IP_PROTO ####')

                        elif field.type == IN_PORT:
                            _port = field.port
                            log.info('#### field.type == IN_PORT ####', port=_port)

                        elif field.type == VLAN_VID:
                            _vlan_vid = field.vlan_vid & 0xfff
                            log.info('#### field.type == VLAN_VID ####', vlan=_vlan_vid)
                            dn_req /= PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,
                                                                         operator=Operator['=='], match=_vlan_vid)
                            if (_vlan_vid != 140):
                                dn_req /= PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=1,
                                                                             operator=Operator['=='], match=ONU_VID)

                        elif field.type == VLAN_PCP:
                            _vlan_pcp = field.vlan_pcp
                            log.info('#### field.type == VLAN_PCP ####', pcp=_vlan_pcp)

                        elif field.type == UDP_DST:
                            _udp_dst = field.udp_dst
                            log.info('#### field.type == UDP_DST ####')

                        elif field.type == UDP_SRC:
                            _udp_src = field.udp_src
                            log.info('#### field.type == UDP_SRC ####')

                        elif field.type == IPV4_DST:
                            _ipv4_dst = field.ipv4_dst
                            log.info('#### field.type == IPV4_DST ####')

                        elif field.type == METADATA:
                            log.info('#### field.type == METADATA ####')
                            pass

                        else:
                            raise NotImplementedError('field.type={}'.format(
                                field.type))

                    for action in get_actions(flow):

                        if action.type == OUTPUT:
                            log.info('#### action.type == OUTPUT ####')
                            dn_req /= PortIngressRuleResultForward()
                            serial = ONU_VID - 200
                            link = (0xe222 << 16) | (serial << 8)
                            dn_req /= PortIngressRuleResultOLTQueue(unicastvssn="TBIT",
                                                                    unicastlink=link)

                        elif action.type == POP_VLAN:
                            log.info('#### action.type == POP_VLAN ####')
                            dn_req /= PortIngressRuleResultDelete(fieldcode=Clause['S-VLAN Tag'])

                        elif action.type == PUSH_VLAN:
                            log.info('#### action.type == PUSH_VLAN ####')
                            if action.push.ethertype != 0x8100:
                                log.error('unhandled-tpid',
                                          ethertype=action.push.ethertype)
                                dn_req /= PortIngressRuleResultInsert(fieldcode=Clause['C-VLAN Tag'])

                        elif action.type == SET_FIELD:
                            log.info('#### action.type == SET_FIELD ####')
                            assert (action.set_field.field.oxm_class ==
                                    ofp.OFPXMC_OPENFLOW_BASIC)
                            field = action.set_field.field.ofb_field
                            if field.type == VLAN_VID:
                                dn_req /= PortIngressRuleResultSet(
                                    fieldcode=Clause['C-VLAN Tag'], value=field.vlan_vid & 0xfff)
                            else:
                                log.error('unsupported-action-set-field-type',
                                          field_type=field.type)
                        else:
                            log.error('UNSUPPORTED-ACTION-TYPE',
                                      action_type=action.type)

                    dn_req /= PortIngressRuleTerminator()
                    dn_req /= AddPortIngressRule()

                    msg = (
                        Ether(dst=device.mac_address) /
                        Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY) /
                        EOAMPayload(
                            body=CablelabsOUI() / DPoEOpcode_SetRequest() / dn_req)
                    )

                    self.io_port.send(str(msg))

                elif in_port == 1:
                    # Upstream rule
                    log.info('#### Upstream Rule ####')

                    field_match_vlan_upstream_with_link = False
                    up_req_link = PortIngressRuleHeader(precedence=precedence)

                    up_req_pon = PonPortObject()
                    up_req_pon /= PortIngressRuleHeader(precedence=precedence)

                    for field in get_ofb_fields(flow):

                        if field.type == ETH_TYPE:
                            _type = field.eth_type
                            log.info('#### field.type == ETH_TYPE ####', in_port=in_port,
                                     match=_type)
                            up_req_pon /= PortIngressRuleClauseMatchLength02(
                                fieldcode=Clause['L2 Type/Len'],
                                operator=Operator['=='],
                                match=_type)

                            up_req_link /= PortIngressRuleClauseMatchLength02(
                                fieldcode=Clause['L2 Type/Len'],
                                operator=Operator['=='],
                                match=_type)

                        elif field.type == IP_PROTO:
                            _proto = field.ip_proto
                            log.info('#### field.type == IP_PROTO ####', in_port=in_port,
                                     ip_proto=_proto)

                            up_req_pon /= PortIngressRuleClauseMatchLength01(
                                fieldcode=Clause['IPv4/IPv6 Protocol Type'],
                                operator=Operator['=='], match=_proto)

                            up_req_link /= PortIngressRuleClauseMatchLength01(
                                fieldcode=Clause['IPv4/IPv6 Protocol Type'],
                                operator=Operator['=='], match=_proto)

                        elif field.type == IN_PORT:
                            _port = field.port
                            log.info('#### field.type == IN_PORT ####')

                        elif field.type == VLAN_VID:
                            _vlan_vid = field.vlan_vid & 0xfff
                            log.info('#### field.type == VLAN_VID ####')
                            up_req_pon /= PortIngressRuleClauseMatchLength02(
                                fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,
                                operator=Operator['=='], match=_vlan_vid)

                            serial = _vlan_vid - 200
                            link = (0xe222 << 16) | (serial << 8)
                            up_req_link /= OLTUnicastLogicalLink(unicastvssn='TBIT', unicastlink=link)

                            up_req_link /= PortIngressRuleClauseMatchLength02(
                                fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,
                                operator=Operator['=='], match=_vlan_vid)
                            field_match_vlan_upstream_with_link = True


                        elif field.type == VLAN_PCP:
                            _vlan_pcp = field.vlan_pcp
                            log.info('#### field.type == VLAN_PCP ####')

                        elif field.type == UDP_DST:
                            _udp_dst = field.udp_dst
                            log.info('#### field.type == UDP_DST ####')
                            up_req_pon /= (PortIngressRuleClauseMatchLength02(fieldcode=Clause['TCP/UDP source port'],
                                                                              operator=Operator['=='], match=0x0044)/
                                           PortIngressRuleClauseMatchLength02(fieldcode=Clause['TCP/UDP destination port'],
                                                                              operator=Operator['=='], match=0x0043))

                        elif field.type == UDP_SRC:
                            _udp_src = field.udp_src
                            log.info('#### field.type == UDP_SRC ####')

                        else:
                            raise NotImplementedError('field.type={}'.format(
                                field.type))

                    for action in get_actions(flow):

                        if action.type == OUTPUT:
                            log.info('#### action.type == OUTPUT ####')
                            up_req_pon /= PortIngressRuleResultForward()
                            up_req_link /= PortIngressRuleResultForward()

                        elif action.type == POP_VLAN:
                            log.info('#### action.type == POP_VLAN ####')

                        elif action.type == PUSH_VLAN:
                            log.info('#### action.type == PUSH_VLAN ####')
                            if action.push.ethertype != 0x8100:
                                log.error('unhandled-ether-type',
                                          ethertype=action.push.ethertype)
                            if field_match_vlan_upstream_with_link == True:
                                up_req_link /= PortIngressRuleResultInsert(fieldcode=Clause['C-VLAN Tag'],
                                                                      fieldinstance=1)
                            else:
                                up_req_pon /= PortIngressRuleResultInsert(fieldcode=Clause['C-VLAN Tag'],
                                                                      fieldinstance=0)

                        elif action.type == SET_FIELD:
                            log.info('#### action.type == SET_FIELD ####')
                            assert (action.set_field.field.oxm_class ==
                                    ofp.OFPXMC_OPENFLOW_BASIC)
                            field = action.set_field.field.ofb_field
                            if field.type == VLAN_VID:
                                if field_match_vlan_upstream_with_link == True:
                                    up_req_link /=(PortIngressRuleResultCopy(fieldcode=Clause['C-VLAN Tag'])/
                                                   PortIngressRuleResultReplace(fieldcode=Clause['C-VLAN Tag']))

                                up_req_pon /= PortIngressRuleResultSet(
                                    fieldcode=Clause['C-VLAN Tag'], value=field.vlan_vid & 0xfff)
                                up_req_link /= PortIngressRuleResultSet(
                                    fieldcode=Clause['C-VLAN Tag'], value=field.vlan_vid & 0xfff)
                            else:
                                log.error('unsupported-action-set-field-type',
                                          field_type=field.type)

                        else:
                            log.error('UNSUPPORTED-ACTION-TYPE',
                                      action_type=action.type)

                    if (field_match_vlan_upstream_with_link == True):
                        up_req = up_req_link
                    else:
                        up_req = up_req_pon

                    up_req /= PortIngressRuleTerminator()
                    up_req /= AddPortIngressRule()

                    msg = (
                        Ether(dst=device.mac_address) /
                        Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY) /
                        EOAMPayload(
                            body=CablelabsOUI() / DPoEOpcode_SetRequest() / up_req)
                    )

                    self.io_port.send(str(msg))

                else:
                    raise Exception('Port should be 1 or 2 by our convention')

            except Exception, e:
                log.exception('failed-to-install-flow', e=e, flow=flow)
Example #29
0
class OpenoltAdapter(object):
    name = 'openolt'

    supported_device_types = [
        DeviceType(id=name, adapter=name, accepts_bulk_flow_update=True)
    ]

    def __init__(self, adapter_agent, config):
        self.adapter_agent = adapter_agent
        self.config = config
        self.descriptor = Adapter(
            id=self.name,
            vendor='OLT white box vendor',
            version='0.1',
            config=AdapterConfig(log_level=LogLevel.INFO))
        log.debug('openolt.__init__', adapter_agent=adapter_agent)
        self.devices = dict()  # device_id -> OpenoltDevice()
        self.interface = registry('main').get_args().interface
        self.logical_device_id_to_root_device_id = dict()

    def start(self):
        log.info('started', interface=self.interface)

    def stop(self):
        log.info('stopped', interface=self.interface)

    def adapter_descriptor(self):
        log.debug('get descriptor', interface=self.interface)
        return self.descriptor

    def device_types(self):
        log.debug('get device_types',
                  interface=self.interface,
                  items=self.supported_device_types)
        return DeviceTypes(items=self.supported_device_types)

    def health(self):
        log.debug('get health', interface=self.interface)
        raise NotImplementedError()

    def change_master_state(self, master):
        log.debug('change_master_state',
                  interface=self.interface,
                  master=master)
        raise NotImplementedError()

    def adopt_device(self, device):
        log.info('adopt-device', device=device)
        kwargs = {'adapter_agent': self.adapter_agent, 'device': device}
        try:
            self.devices[device.id] = OpenoltDevice(**kwargs)
        except Exception as e:
            log.error('Failed to adopt OpenOLT device', error=e)
            del self.devices[device.id]
            raise

    def reconcile_device(self, device):
        log.info('reconcile-device', device=device)
        raise NotImplementedError()

    def abandon_device(self, device):
        log.info('abandon-device', device=device)
        raise NotImplementedError()

    def disable_device(self, device):
        log.info('disable-device', device=device)
        raise NotImplementedError()

    def reenable_device(self, device):
        log.info('reenable-device', device=device)
        raise NotImplementedError()

    def reboot_device(self, device):
        log.info('reboot_device', device=device)
        raise NotImplementedError()

    def download_image(self, device, request):
        log.info('image_download', device=device, request=request)
        raise NotImplementedError()

    def get_image_download_status(self, device, request):
        log.info('get_image_download', device=device, request=request)
        raise NotImplementedError()

    def cancel_image_download(self, device, request):
        log.info('cancel_image_download', device=device)
        raise NotImplementedError()

    def activate_image_update(self, device, request):
        log.info('activate_image_update', device=device, request=request)
        raise NotImplementedError()

    def revert_image_update(self, device, request):
        log.info('revert_image_update', device=device, request=request)
        raise NotImplementedError()

    def self_test_device(self, device):
        from voltha.protos.voltha_pb2 import SelfTestResponse
        raise NotImplementedError()

    def delete_device(self, device):
        log.info('delete-device', device=device)
        raise NotImplementedError()

    def get_device_details(self, device):
        log.debug('get_device_details', device=device)
        raise NotImplementedError()

    def update_flows_bulk(self, device, flows, groups):
        log.info('bulk-flow-update',
                 device_id=device.id,
                 flows=flows,
                 groups=groups)
        assert len(groups.items) == 0, "Cannot yet deal with groups"
        handler = self.devices[device.id]
        return handler.update_flow_table(flows.items)

    def update_flows_incrementally(self, device, flow_changes, group_changes):
        log.debug('update_flows_incrementally',
                  device=device,
                  flow_changes=flow_changes,
                  group_changes=group_changes)
        raise NotImplementedError()

    def update_pm_config(self, device, pm_configs):
        log.debug('update_pm_config', device=device, pm_configs=pm_configs)
        raise NotImplementedError()

    def send_proxied_message(self, proxy_address, msg):
        log.debug('send-proxied-message', proxy_address=proxy_address, msg=msg)
        handler = self.devices[proxy_address.device_id]
        handler.send_proxied_message(proxy_address, msg)

    def receive_proxied_message(self, proxy_address, msg):
        log.debug('receive_proxied_message',
                  proxy_address=proxy_address,
                  msg=msg)
        raise NotImplementedError()

    def receive_packet_out(self, logical_device_id, egress_port_no, msg):
        log.debug('packet-out',
                  logical_device_id=logical_device_id,
                  egress_port_no=egress_port_no,
                  msg_len=len(msg))
        raise NotImplementedError()

    def receive_inter_adapter_message(self, msg):
        log.info('rx_inter_adapter_msg')
        raise NotImplementedError()

    def suppress_alarm(self, filter):
        log.info('suppress_alarm', filter=filter)
        raise NotImplementedError()

    def unsuppress_alarm(self, filter):
        log.info('unsuppress_alarm', filter=filter)
        raise NotImplementedError()

    # PON Mgnt APIs #
    def create_interface(self, device, data):
        log.debug('create-interface', data=data)
        raise NotImplementedError()

    def update_interface(self, device, data):
        log.debug('update-interface', data=data)
        raise NotImplementedError()

    def remove_interface(self, device, data):
        log.debug('remove-interface', data=data)
        raise NotImplementedError()

    def receive_onu_detect_state(self, proxy_address, state):
        log.debug('receive-onu-detect-state', data=data)
        raise NotImplementedError()

    def create_tcont(self, device, tcont_data, traffic_descriptor_data):
        log.info('create-tcont',
                 tcont_data=tcont_data,
                 traffic_descriptor_data=traffic_descriptor_data)
        raise NotImplementedError()

    def update_tcont(self, device, tcont_data, traffic_descriptor_data):
        log.info('update-tcont',
                 tcont_data=tcont_data,
                 traffic_descriptor_data=traffic_descriptor_data)
        raise NotImplementedError()

    def remove_tcont(self, device, tcont_data, traffic_descriptor_data):
        log.info('remove-tcont',
                 tcont_data=tcont_data,
                 traffic_descriptor_data=traffic_descriptor_data)
        raise NotImplementedError()

    def create_gemport(self, device, data):
        log.info('create-gemport', data=data)
        raise NotImplementedError()

    def update_gemport(self, device, data):
        log.info('update-gemport', data=data)
        raise NotImplementedError()

    def remove_gemport(self, device, data):
        log.info('remove-gemport', data=data)
        raise NotImplementedError()

    def create_multicast_gemport(self, device, data):
        log.info('create-mcast-gemport', data=data)
        raise NotImplementedError()

    def update_multicast_gemport(self, device, data):
        log.info('update-mcast-gemport', data=data)
        raise NotImplementedError()

    def remove_multicast_gemport(self, device, data):
        log.info('remove-mcast-gemport', data=data)
        raise NotImplementedError()

    def create_multicast_distribution_set(self, device, data):
        log.info('create-mcast-distribution-set', data=data)
        raise NotImplementedError()

    def update_multicast_distribution_set(self, device, data):
        log.info('update-mcast-distribution-set', data=data)
        raise NotImplementedError()

    def remove_multicast_distribution_set(self, device, data):
        log.info('remove-mcast-distribution-set', data=data)
        raise NotImplementedError()
Example #30
0
class PonSimOltAdapter(object):
    name = 'ponsim_olt'

    supported_device_types = [
        DeviceType(
            id=name,
            adapter=name,
            accepts_bulk_flow_update=True
        )
    ]

    def __init__(self, adapter_agent, config):
        self.adapter_agent = adapter_agent
        self.config = config
        self.descriptor = Adapter(
            id=self.name,
            vendor='Voltha project',
            version='0.4',
            config=AdapterConfig(log_level=LogLevel.INFO)
        )
        self.devices_handlers = dict()  # device_id -> PonSimOltHandler()
        self.logical_device_id_to_root_device_id = dict()

    def start(self):
        log.debug('starting')
        log.info('started')

    def stop(self):
        """
        This method is called when this device instance is no longer
        required,  which means there is a request to remove this device.
        :return:
        """
        log.debug('stopping')
        log.info('stopped')

    def adapter_descriptor(self):
        return self.descriptor

    def device_types(self):
        return DeviceTypes(items=self.supported_device_types)

    def health(self):
        return HealthStatus(state=HealthStatus.HealthState.HEALTHY)

    def change_master_state(self, master):
        raise NotImplementedError()

    def update_pm_config(self, device, pm_config):
        log.info("adapter-update-pm-config", device=device,
                 pm_config=pm_config)
        handler = self.devices_handlers[device.id]
        handler.update_pm_config(device, pm_config)

    def adopt_device(self, device):
        self.devices_handlers[device.id] = PonSimOltHandler(self, device.id)
        reactor.callLater(0, self.devices_handlers[device.id].activate, device)
        return device

    def abandon_device(self, device):
        raise NotImplementedError()

    def disable_device(self, device):
        log.info('disable-device', device_id=device.id)
        reactor.callLater(0, self.devices_handlers[device.id].disable)
        return device

    def reenable_device(self, device):
        log.info('reenable-device', device_id=device.id)
        reactor.callLater(0, self.devices_handlers[device.id].reenable)
        return device

    def reboot_device(self, device):
        log.info('reboot-device', device_id=device.id)
        reactor.callLater(0, self.devices_handlers[device.id].reboot)
        return device

    def delete_device(self, device):
        log.info('delete-device', device_id=device.id)
        reactor.callLater(0, self.devices_handlers[device.id].delete)
        return device

    def get_device_details(self, device):
        raise NotImplementedError()

    def update_flows_bulk(self, device, flows, groups):
        log.info('bulk-flow-update', device_id=device.id,
                 flows=flows, groups=groups)
        assert len(groups.items) == 0
        handler = self.devices_handlers[device.id]
        return handler.update_flow_table(flows.items)

    def update_flows_incrementally(self, device, flow_changes, group_changes):
        raise NotImplementedError()

    def send_proxied_message(self, proxy_address, msg):
        log.info('send-proxied-message', proxy_address=proxy_address, msg=msg)
        handler = self.devices_handlers[proxy_address.device_id]
        handler.send_proxied_message(proxy_address, msg)

    def receive_proxied_message(self, proxy_address, msg):
        raise NotImplementedError()

    def receive_packet_out(self, logical_device_id, egress_port_no, msg):
        def ldi_to_di(ldi):
            di = self.logical_device_id_to_root_device_id.get(ldi)
            if di is None:
                logical_device = self.adapter_agent.get_logical_device(ldi)
                di = logical_device.root_device_id
                self.logical_device_id_to_root_device_id[ldi] = di
            return di

        device_id = ldi_to_di(logical_device_id)
        handler = self.devices_handlers[device_id]
        handler.packet_out(egress_port_no, msg)

    def receive_inter_adapter_message(self, msg):
        raise NotImplementedError()

    def suppress_alarm(self, filter):
        raise NotImplementedError()

    def unsuppress_alarm(self, filter):
        raise NotImplementedError()