VOL-669: Openolt adapter - packet-out processing

Change-Id: I23cd0fa752771ae0c7d7c9ed457f06322e0c6bf6
diff --git a/voltha/adapters/openolt/openolt_device.py b/voltha/adapters/openolt/openolt_device.py
index 70161f2..35ef09f 100644
--- a/voltha/adapters/openolt/openolt_device.py
+++ b/voltha/adapters/openolt/openolt_device.py
@@ -21,7 +21,8 @@
 import time
 
 from twisted.internet import reactor
-from scapy.layers.l2 import Ether
+from scapy.layers.l2 import Ether, Dot1Q
+import binascii
 
 from voltha.protos.device_pb2 import Port, Device
 from voltha.protos.common_pb2 import OperStatus, AdminState, ConnectStatus
@@ -58,7 +59,7 @@
 
 Logical (OF) UNI port number
 
-    15             9                0
+     15            8                0
     +--+------------+----------------+
     |0 |  pon id    |    onu id      |
     +--+------------+----------------+
@@ -181,7 +182,7 @@
 
         if intf_oper_indication.type == "nni":
 
-            # FIXME - Ignore all nni ports except nni port 0
+            # FIXME - creating logical port for 2nd interface throws exception!
             if intf_oper_indication.intf_id != 0:
                 return
 
@@ -223,8 +224,14 @@
 	    self.log.info("onu activation in progress",
                 intf_id=onu_disc_indication.intf_id, onu_id=onu_id)
 
-    def mk_uni_port_num(self, intf_id, onu_id, uni_id):
-        return intf_id << 9 | onu_id << 3 | uni_id
+    def mk_uni_port_num(self, intf_id, onu_id):
+        return intf_id << 8 | onu_id
+
+    def onu_id_from_port_num(self, port_num):
+        return port_num & 0xFF
+
+    def intf_id_from_port_num(self, port_num):
+        return (port_num >> 8) & 0x7F
 
     def onu_indication(self, onu_indication):
 
@@ -255,7 +262,7 @@
         #
         # v_enet create (olt)
         #
-        uni_no = self.mk_uni_port_num(onu_indication.intf_id, onu_indication.onu_id, 0)
+        uni_no = self.mk_uni_port_num(onu_indication.intf_id, onu_indication.onu_id)
         uni_name = self.port_name(uni_no, Port.ETHERNET_UNI)
 	self.adapter_agent.add_port(
             self.device_id,
@@ -314,7 +321,7 @@
                 flow_id=pkt_indication.flow_id)
 
         onu_id = self.onu_id_from_gemport_id(pkt_indication.gemport_id)
-        logical_port_num = self.mk_uni_port_num(pkt_indication.intf_id, onu_id, 0)
+        logical_port_num = self.mk_uni_port_num(pkt_indication.intf_id, onu_id)
 
         pkt = Ether(pkt_indication.pkt)
         kw = dict(
@@ -324,7 +331,31 @@
         self.adapter_agent.send_packet_in(packet=str(pkt), **kw)
 
     def packet_out(self, egress_port, msg):
-        pass
+        pkt = Ether(msg)
+        self.log.info('packet out', egress_port=egress_port,
+                packet=str(pkt).encode("HEX"))
+
+        if pkt.haslayer(Dot1Q):
+            outer_shim = pkt.getlayer(Dot1Q)
+            if isinstance(outer_shim.payload, Dot1Q):
+                payload = (
+                    Ether(src=pkt.src, dst=pkt.dst, type=outer_shim.type) /
+                    outer_shim.payload
+                )
+            else:
+                payload = pkt
+        else:
+            payload = pkt
+
+        self.log.info('sending-packet-to-device', egress_port=egress_port,
+                packet=str(payload).encode("HEX"))
+
+        send_pkt = binascii.unhexlify(str(payload).encode("HEX"))
+
+        onu_pkt = openolt_pb2.OnuPacket(intf_id=intf_id_from_port_num(egress_port),
+                onu_id=onu_id_from_port_num(egress_port), pkt=send_pkt)
+
+        self.stub.OnuPacketOut(onu_packet)
 
     def activate_onu(self, intf_id, onu_id, serial_number):
 
diff --git a/voltha/adapters/openolt/protos/openolt.proto b/voltha/adapters/openolt/protos/openolt.proto
index 2d26d66..c9f6d98 100644
--- a/voltha/adapters/openolt/protos/openolt.proto
+++ b/voltha/adapters/openolt/protos/openolt.proto
@@ -32,6 +32,13 @@
         };
     }
 
+    rpc OnuPacketOut(OnuPacket) returns (Empty) {
+        option (google.api.http) = {
+          post: "/v1/OnuPacketOut"
+          body: "*"
+        };
+    }
+
     rpc FlowAdd(Flow) returns (Empty) {
         option (google.api.http) = {
           post: "/v1/FlowAdd"
@@ -106,6 +113,12 @@
     bytes pkt = 3;
 }
 
+message OnuPacket {
+    fixed32 intf_id = 1;
+    fixed32 onu_id = 2;
+    bytes pkt = 3;
+}
+
 message Classifier {
     fixed32 o_tpid = 1;
     fixed32 o_vid = 2;