VOL-3347 GEM ports kept for packet-outs should be in  pon-onu-uni-vlan-pbit  basis instead of per pon-onu-uni basis.

Change-Id: I7e9ca29295d28d97908a99ba8c34c4c9b52046c4
diff --git a/internal/pkg/core/openolt_flowmgr.go b/internal/pkg/core/openolt_flowmgr.go
index 520ee7a..f2fec23 100644
--- a/internal/pkg/core/openolt_flowmgr.go
+++ b/internal/pkg/core/openolt_flowmgr.go
@@ -3045,7 +3045,7 @@
 			logicalPortNum = MkUniPortNum(ctx, packetIn.IntfId, onuID, uniID)
 		}
 		// Store the gem port through which the packet_in came. Use the same gem port for packet_out
-		f.UpdateGemPortForPktIn(ctx, packetIn.IntfId, onuID, logicalPortNum, packetIn.GemportId)
+		f.UpdateGemPortForPktIn(ctx, packetIn.IntfId, onuID, logicalPortNum, packetIn.GemportId, packetIn.Pkt)
 	} else if packetIn.IntfType == "nni" {
 		logicalPortNum = IntfIDToPortNo(packetIn.IntfId, voltha.Port_ETHERNET_NNI)
 	}
@@ -3059,13 +3059,17 @@
 }
 
 //GetPacketOutGemPortID returns gemPortId
-func (f *OpenOltFlowMgr) GetPacketOutGemPortID(ctx context.Context, intfID uint32, onuID uint32, portNum uint32) (uint32, error) {
+func (f *OpenOltFlowMgr) GetPacketOutGemPortID(ctx context.Context, intfID uint32, onuID uint32, portNum uint32, packet []byte) (uint32, error) {
 	var gemPortID uint32
-	var err error
+
+	ctag, priority, err := getCTagFromPacket(ctx, packet)
+	if err != nil {
+		return 0, err
+	}
 
 	f.onuGemInfoLock.RLock()
 	defer f.onuGemInfoLock.RUnlock()
-	pktInkey := rsrcMgr.PacketInInfoKey{IntfID: intfID, OnuID: onuID, LogicalPort: portNum}
+	pktInkey := rsrcMgr.PacketInInfoKey{IntfID: intfID, OnuID: onuID, LogicalPort: portNum, VlanID: ctag, Priority: priority}
 	var ok bool
 	gemPortID, ok = f.packetInGemPort[pktInkey]
 	if ok {
@@ -3077,7 +3081,7 @@
 		return gemPortID, nil
 	}
 	//If gem is not found in cache try to get it from kv store, if found in kv store, update the cache and return.
-	gemPortID, err = f.resourceMgr.GetGemPortFromOnuPktIn(ctx, intfID, onuID, portNum)
+	gemPortID, err = f.resourceMgr.GetGemPortFromOnuPktIn(ctx, pktInkey)
 	if err == nil {
 		if gemPortID != 0 {
 			f.packetInGemPort[pktInkey] = gemPortID
@@ -3818,12 +3822,18 @@
 }
 
 // UpdateGemPortForPktIn updates gemport for packet-in in to the cache and to the kv store as well.
-func (f *OpenOltFlowMgr) UpdateGemPortForPktIn(ctx context.Context, intfID uint32, onuID uint32, logicalPort uint32, gemPort uint32) {
+func (f *OpenOltFlowMgr) UpdateGemPortForPktIn(ctx context.Context, intfID uint32, onuID uint32, logicalPort uint32, gemPort uint32, pkt []byte) {
+	cTag, priority, err := getCTagFromPacket(ctx, pkt)
+	if err != nil {
+		logger.Errorw(ctx, "unable-to-update-gem-port-for-packet-in",
+			log.Fields{"intfID": intfID, "onuID": onuID, "logicalPort": logicalPort, "gemPort": gemPort, "err": err})
+		return
+	}
+	pktInkey := rsrcMgr.PacketInInfoKey{IntfID: intfID, OnuID: onuID, LogicalPort: logicalPort, VlanID: cTag, Priority: priority}
 
 	f.onuGemInfoLock.Lock()
 	defer f.onuGemInfoLock.Unlock()
 
-	pktInkey := rsrcMgr.PacketInInfoKey{IntfID: intfID, OnuID: onuID, LogicalPort: logicalPort}
 	lookupGemPort, ok := f.packetInGemPort[pktInkey]
 	if ok {
 		if lookupGemPort == gemPort {
@@ -3845,6 +3855,33 @@
 
 }
 
+//getCTagFromPacket retrieves and returns c-tag and priority value from a packet.
+func getCTagFromPacket(ctx context.Context, packet []byte) (uint16, uint8, error) {
+	if packet == nil || len(packet) < 18 {
+		log.Error("unable-get-c-tag-from-the-packet--invalid-packet-length ")
+		return 0, 0, errors.New("invalid packet length")
+	}
+	outerEthType := (uint16(packet[12]) << 8) | uint16(packet[13])
+	innerEthType := (uint16(packet[16]) << 8) | uint16(packet[17])
+
+	var index int8
+	if outerEthType == 0x8100 {
+		if innerEthType == 0x8100 {
+			// q-in-q 802.1ad or 802.1q double tagged packet.
+			// get the inner vlanId
+			index = 18
+		} else {
+			index = 14
+		}
+		priority := (packet[index] >> 5) & 0x7
+		//13 bits composes vlanId value
+		vlan := ((uint16(packet[index]) << 8) & 0x0fff) | uint16(packet[index+1])
+		return vlan, priority, nil
+	}
+	logger.Debugf(ctx, "No vlanId found in the packet. Returning zero as c-tag")
+	return 0, 0, nil
+}
+
 // AddUniPortToOnuInfo adds uni port to the onugem info both in cache and kvstore.
 func (f *OpenOltFlowMgr) AddUniPortToOnuInfo(ctx context.Context, intfID uint32, onuID uint32, portNum uint32) {