Maple OLT and Broadcom ONU adapter skeletons
Change-Id: I09729d17a3be221a64f3261a039dd9809a1ad65b
diff --git a/voltha/adapters/broadcom_onu/broadcom_onu.py b/voltha/adapters/broadcom_onu/broadcom_onu.py
new file mode 100644
index 0000000..4ddeeb5
--- /dev/null
+++ b/voltha/adapters/broadcom_onu/broadcom_onu.py
@@ -0,0 +1,217 @@
+#
+# Copyright 2016 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+"""
+Mock device adapter for testing.
+"""
+from uuid import uuid4
+
+import structlog
+from twisted.internet import reactor
+from twisted.internet.defer import inlineCallbacks, DeferredQueue
+from zope.interface import implementer
+
+from common.utils.asleep import asleep
+from voltha.adapters.interface import IAdapterInterface
+from voltha.core.logical_device_agent import mac_str_to_tuple
+from voltha.protos.adapter_pb2 import Adapter, AdapterConfig
+from voltha.protos.device_pb2 import DeviceType, DeviceTypes, Device, Port
+from voltha.protos.health_pb2 import HealthStatus
+from voltha.protos.common_pb2 import LogLevel, OperStatus, ConnectStatus, \
+ AdminState
+from voltha.protos.logical_device_pb2 import LogicalDevice, LogicalPort
+from voltha.protos.openflow_13_pb2 import ofp_desc, ofp_port, OFPPF_1GB_FD, \
+ OFPPF_FIBER, OFPPS_LIVE, ofp_switch_features, OFPC_PORT_STATS, \
+ OFPC_GROUP_STATS, OFPC_TABLE_STATS, OFPC_FLOW_STATS
+
+log = structlog.get_logger()
+
+
+@implementer(IAdapterInterface)
+class BroadcomOnuAdapter(object):
+
+ name = 'broadcom_onu'
+
+ supported_device_types = [
+ DeviceType(
+ id='broadcom_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 abandon_device(self, device):
+ raise NotImplementedError()
+
+ def deactivate_device(self, device):
+ raise NotImplementedError()
+
+ @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 = 'Broadcom'
+ device.model = 'to be filled'
+ device.hardware_version = 'to be filled'
+ device.firmware_version = 'to be filled'
+ device.software_version = 'to be filled'
+ 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)
+ uni_port = Port(
+ port_no=0,
+ 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)
+
+ 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))
+
+ @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