VOL-929 Packet out through openolt uplink

Change-Id: Iacbd75abcdebc80f675fbdfbb87f771ae5c95e9d
diff --git a/voltha/adapters/openolt/openolt_device.py b/voltha/adapters/openolt/openolt_device.py
index 5a0febb..8dfa42b 100644
--- a/voltha/adapters/openolt/openolt_device.py
+++ b/voltha/adapters/openolt/openolt_device.py
@@ -602,28 +602,49 @@
         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):
-                #If double tag, remove the outer tag
-                payload = (
-                    Ether(src=pkt.src, dst=pkt.dst, type=outer_shim.type) /
-                    outer_shim.payload
-                )
+
+        # Find port type
+        egress_port_type = self.port_type(egress_port)
+
+        if egress_port_type == Port.ETHERNET_UNI:
+
+            if pkt.haslayer(Dot1Q):
+                outer_shim = pkt.getlayer(Dot1Q)
+                if isinstance(outer_shim.payload, Dot1Q):
+                    # If double tag, remove the outer tag
+                    payload = (
+                        Ether(src=pkt.src, dst=pkt.dst, type=outer_shim.type) /
+                        outer_shim.payload
+                    )
+                else:
+                    payload = pkt
             else:
                 payload = pkt
+
+            send_pkt = binascii.unhexlify(str(payload).encode("HEX"))
+
+            self.log.info('sending-packet-to-ONU', egress_port=egress_port,
+                          intf_id=platform.intf_id_from_pon_port_no(egress_port),
+                          onu_id=platform.onu_id_from_port_num(egress_port),
+                        packet=str(payload).encode("HEX"))
+
+            onu_pkt = openolt_pb2.OnuPacket(intf_id=platform.intf_id_from_pon_port_no(egress_port),
+                    onu_id=platform.onu_id_from_port_num(egress_port), pkt=send_pkt)
+
+            self.stub.OnuPacketOut(onu_pkt)
+
+        elif egress_port_type == Port.ETHERNET_NNI:
+            self.log.info('sending-packet-to-uplink', egress_port=egress_port, packet=str(pkt).encode("HEX"))
+
+            send_pkt = binascii.unhexlify(str(pkt).encode("HEX"))
+
+            uplink_pkt = openolt_pb2.UplinkPacket(intf_id=platform.intf_id_from_nni_port_num(egress_port), pkt=send_pkt)
+
+            self.stub.UplinkPacketOut(uplink_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=platform.intf_id_from_pon_port_no(egress_port),
-                onu_id=platform.onu_id_from_port_num(egress_port), pkt=send_pkt)
-
-        self.stub.OnuPacketOut(onu_pkt)
+            self.log.warn('Packet-out-to-this-interface-type-not-implemented', egress_port=egress_port,
+                          port_type=egress_port_type)
 
     def send_proxied_message(self, proxy_address, msg):
         omci = openolt_pb2.OmciMsg(intf_id=proxy_address.channel_id, # intf_id
@@ -658,6 +679,15 @@
             else:
                 return "uni-{}".format(port_no)
 
+
+    def port_type(self, port_no):
+        ports = self.adapter_agent.get_ports(self.device_id)
+        for port in ports:
+            if port.port_no == port_no:
+                return port.type
+        return None
+
+
     def add_logical_port(self, port_no, intf_id, oper_state):
         self.log.info('adding-logical-port', port_no=port_no)
 
diff --git a/voltha/adapters/openolt/openolt_platform.py b/voltha/adapters/openolt/openolt_platform.py
index d289ccb..581c15d 100644
--- a/voltha/adapters/openolt/openolt_platform.py
+++ b/voltha/adapters/openolt/openolt_platform.py
@@ -120,9 +120,12 @@
 
 def intf_id_to_port_no(intf_id, intf_type):
     if intf_type is Port.ETHERNET_NNI:
-        # FIXME - Remove hardcoded '129'
-        return intf_id + 129
+        # FIXME - Remove hardcoded '128'
+        return intf_id + 128
     elif intf_type is Port.PON_OLT:
         return 0x2<<28 | intf_id
     else:
         raise Exception('Invalid port type')
+
+def intf_id_from_nni_port_num(port_num):
+    return port_num - 128
diff --git a/voltha/adapters/openolt/protos/openolt.proto b/voltha/adapters/openolt/protos/openolt.proto
index a7915c8..069a7bc 100644
--- a/voltha/adapters/openolt/protos/openolt.proto
+++ b/voltha/adapters/openolt/protos/openolt.proto
@@ -39,6 +39,13 @@
         };
     }
 
+    rpc UplinkPacketOut(UplinkPacket) returns (Empty) {
+        option (google.api.http) = {
+          post: "/v1/UplinkPacketOut"
+          body: "*"
+        };
+    }
+
     rpc FlowAdd(Flow) returns (Empty) {
         option (google.api.http) = {
           post: "/v1/FlowAdd"
@@ -131,6 +138,11 @@
     bytes pkt = 3;
 }
 
+message UplinkPacket {
+    fixed32 intf_id = 1;
+    bytes pkt = 2;
+}
+
 message Classifier {
     fixed32 o_tpid = 1;
     fixed32 o_vid = 2;
diff --git a/voltha/core/adapter_agent.py b/voltha/core/adapter_agent.py
index 951cc67..4e4a9e5 100644
--- a/voltha/core/adapter_agent.py
+++ b/voltha/core/adapter_agent.py
@@ -418,10 +418,13 @@
         self._make_up_to_date('/devices/{}/ports'.format(device_id),
                               port.port_no, port)
 
-    def get_ports(self, device_id, port_type):
+    def get_ports(self, device_id, port_type=None):
         # assert Port.PortType.DESCRIPTOR.values_by_name[port_type]
         ports = self.root_proxy.get('/devices/{}/ports'.format(device_id))
-        return [p for p in ports if p.type == port_type]
+        if port_type is None:
+            return ports
+        else:
+            return [p for p in ports if p.type == port_type]
 
     def delete_port(self, device_id, port):
         assert isinstance(port, Port)