PONSIM: PON simulator with real dataplane handling

This was needed because neither CPQD nor OVS can handle
both zero-tagged packets and 802.1ad (QinQ).

- extensive unittest proves ponsim functional correctness
  (for the common use-cases needed in the PON scenario)
- integrated with frameio and coupled with a rather
  simple gRPC NBI, ponsim can be operated from Voltha
  just like a real PON system
- posim_olt/_onu adapters added to Voltha to work on
  ponsim
- CLI can be used to preprovision and activate a PONSIM
  instance (e.g., preprovision_olt -t ponsim_olt -H localhost:50060)
- Some of olt-oftest:olt-complex testcases can be run on
  the ponsim device (in vagrant/Ubuntu environment),
  but there are some remaining issues to work out:
  - barrier calls in OF do not guaranty that the flow
    is already installed on the device. This is a generic
    issue, not just for ponsim.
  - the whole test framework is inconsistent about zero-
    tagged vs. untagged frames at the ONUs, while ponsim
    is rather pedantica and does exactly what was defined
    in the flows.

Change-Id: I0dd564c932416ae1566935492134cb5b08113bdc
diff --git a/voltha/core/adapter_agent.py b/voltha/core/adapter_agent.py
index 0c5448f..3bf8857 100644
--- a/voltha/core/adapter_agent.py
+++ b/voltha/core/adapter_agent.py
@@ -31,6 +31,7 @@
 from voltha.protos.voltha_pb2 import DeviceGroup, LogicalDevice, \
     LogicalPort, AdminState
 from voltha.registry import registry
+from voltha.core.flow_decomposer import OUTPUT
 
 
 @implementer(IAdapterAgent)
@@ -64,11 +65,11 @@
         try:
             adapter = self.adapter_cls(self, config)
             yield adapter.start()
+            self.adapter = adapter
+            self.adapter_node_proxy = self._update_adapter_node()
+            self._update_device_types()
         except Exception, e:
             self.log.exception(e)
-        self.adapter = adapter
-        self.adapter_node_proxy = self._update_adapter_node()
-        self._update_device_types()
         self.log.info('started')
         returnValue(self)
 
@@ -199,6 +200,10 @@
                 return i
             i += 1
 
+    def get_logical_device(self, logical_device_id):
+        return self.root_proxy.get('/logical_devices/{}'.format(
+            logical_device_id))
+
     def create_logical_device(self, logical_device):
         assert isinstance(logical_device, LogicalDevice)
 
@@ -210,8 +215,24 @@
         self._make_up_to_date('/logical_devices',
                               logical_device.id, logical_device)
 
+        self.event_bus.subscribe(
+            topic='packet-out:{}'.format(logical_device.id),
+            callback=lambda _, p: self.receive_packet_out(logical_device.id, p)
+        )
+
         return logical_device
 
+    def receive_packet_out(self, logical_device_id, ofp_packet_out):
+
+        def get_port_out(opo):
+            for action in opo.actions:
+                if action.type == OUTPUT:
+                    return action.output.port
+
+        out_port = get_port_out(ofp_packet_out)
+        frame = ofp_packet_out.data
+        self.adapter.receive_packet_out(logical_device_id, out_port, frame)
+
     def add_logical_port(self, logical_device_id, port):
         assert isinstance(port, LogicalPort)
         self._make_up_to_date(