VOL-4625: Support for FTTB flows in openolt adapter

Change-Id: Icdf3c66f310f68101e8a84ef272ed38b849d77bf
diff --git a/internal/pkg/core/openolt_flowmgr.go b/internal/pkg/core/openolt_flowmgr.go
index 8b24630..06ad2c0 100644
--- a/internal/pkg/core/openolt_flowmgr.go
+++ b/internal/pkg/core/openolt_flowmgr.go
@@ -91,6 +91,8 @@
 	EthType = "eth_type"
 	//EthDst constant
 	EthDst = "eth_dst"
+	//EthSrc constant
+	EthSrc = "eth_src"
 	//TPID constant
 	TPID = "tpid"
 	//IPProto constant
@@ -978,28 +980,38 @@
 }
 
 func (f *OpenOltFlowMgr) addUpstreamDataPathFlow(ctx context.Context, flowContext *flowContext) error {
-	flowContext.classifier[PacketTagType] = SingleTag // FIXME: This hardcoding needs to be removed.
+	flowContext.classifier[PacketTagType] = SingleTag
+	// extract the cvid/inner-vid from the write metadata
+	writeMetadata := flows.GetMetadataFromWriteMetadataAction(ctx, flowContext.logicalFlow)
+	if writeMetadata != 0 {
+		// Writemetadata field is 8 bytes
+		// cvid is on the outer most two bytes of the write metadata
+		cvid := (writeMetadata & 0xffff000000000000) >> 48
+		// if the cvid does not match the classifier vlan, then this indicates it is a double tagged packet
+		if cvid != flowContext.classifier[VlanVid] && cvid != 0 {
+			flowContext.classifier[PacketTagType] = DoubleTag
+		}
+	}
 	logger.Debugw(ctx, "adding-upstream-data-flow",
 		log.Fields{
 			"uplinkClassifier": flowContext.classifier,
 			"uplinkAction":     flowContext.action})
 	return f.addSymmetricDataPathFlow(ctx, flowContext, Upstream)
-	/* TODO: Install Secondary EAP on the subscriber vlan */
 }
 
 func (f *OpenOltFlowMgr) addDownstreamDataPathFlow(ctx context.Context, flowContext *flowContext) error {
 	downlinkClassifier := flowContext.classifier
 	downlinkAction := flowContext.action
-
-	// TODO: For now mark the PacketTagType as SingleTag when OLT is transparent to VLAN
-	// Per some deployment models, it is also possible that ONU operates on double tagged packets,
-	// so this hardcoding of SingeTag packet-tag-type may be problem for such deployment models.
-	// Need a better way for detection of packet tag type from OpenFlow message.
-	if _, ok := downlinkClassifier[VlanVid]; !ok {
-		downlinkClassifier[PacketTagType] = SingleTag
-	} else {
-		downlinkClassifier[PacketTagType] = DoubleTag
-		downlinkAction[PopVlan] = true
+	// default to single tag. If we detect an inner cvid from write-metadata, then we mark the PacketTagType as DoubleTag
+	downlinkClassifier[PacketTagType] = SingleTag
+	// extract the cvid/inner-vid from the write metadata
+	writeMetadata := flows.GetMetadataFromWriteMetadataAction(ctx, flowContext.logicalFlow)
+	if writeMetadata != 0 {
+		// Writemetadata field is 8 bytes
+		// cvid is on the outer most two bytes of the write metadata
+		if cvid := (writeMetadata & 0xffff000000000000) >> 48; cvid != 0 {
+			downlinkClassifier[PacketTagType] = DoubleTag
+		}
 	}
 	logger.Debugw(ctx, "adding-downstream-data-flow",
 		log.Fields{
@@ -1022,10 +1034,14 @@
 		}
 	}
 
-	// vlan_vid is a uint32.  must be type asserted as such or conversion fails
-	dlClVid, ok := downlinkClassifier[VlanVid].(uint32)
-	if ok {
-		downlinkAction[VlanVid] = dlClVid & 0xfff
+	// If Pop Vlan action is specified, set the vlan to be popped from the classifier vlan match field.
+	// The matched vlan is the one that is getting popped.
+	if val, ok := downlinkAction[PopVlan]; ok && val.(bool) {
+		// vlan_vid is a uint32.  must be type asserted as such or conversion fails
+		dlClVid, ok := downlinkClassifier[VlanVid].(uint32)
+		if ok {
+			downlinkAction[VlanVid] = dlClVid & 0xfff
+		}
 	}
 
 	return f.addSymmetricDataPathFlow(ctx, flowContext, Downstream)
@@ -1464,6 +1480,7 @@
 	classifier.DstIp, _ = classifierInfo[Ipv4Dst].(uint32)
 	classifier.SrcIp, _ = classifierInfo[Ipv4Src].(uint32)
 	classifier.DstMac, _ = classifierInfo[EthDst].([]uint8)
+	classifier.SrcMac, _ = classifierInfo[EthSrc].([]uint8)
 	if pktTagType, ok := classifierInfo[PacketTagType].(string); ok {
 		classifier.PktTagType = pktTagType
 
@@ -1483,28 +1500,38 @@
 	var action openoltpb2.Action
 	action.Cmd = &actionCmd
 	if _, ok := actionInfo[PopVlan]; ok {
+		// Pop outer vid
 		action.Cmd.RemoveOuterTag = true
 		if _, ok := actionInfo[VlanPcp]; ok {
+			// Remark inner pbit
 			action.Cmd.RemarkInnerPbits = true
 			action.IPbits = actionInfo[VlanPcp].(uint32)
 			if _, ok := actionInfo[VlanVid]; ok {
+				// Remark inner vid
 				action.Cmd.TranslateInnerTag = true
 				action.IVid = actionInfo[VlanVid].(uint32)
 			}
 		}
 	} else if _, ok := actionInfo[PushVlan]; ok {
+		// push outer vid
 		action.OVid = actionInfo[VlanVid].(uint32)
 		action.Cmd.AddOuterTag = true
 		if _, ok := actionInfo[VlanPcp]; ok {
+			// translate outer pbit
 			action.OPbits = actionInfo[VlanPcp].(uint32)
 			action.Cmd.RemarkOuterPbits = true
 			if _, ok := classifierInfo[VlanVid]; ok {
+				// translate inner vid
 				action.IVid = classifierInfo[VlanVid].(uint32)
 				action.Cmd.TranslateInnerTag = true
 			}
 		}
 	} else if _, ok := actionInfo[TrapToHost]; ok {
 		action.Cmd.TrapToHost = actionInfo[TrapToHost].(bool)
+	} else if _, ok := actionInfo[VlanVid]; ok {
+		// Translate outer vid
+		action.Cmd.TranslateOuterTag = true
+		action.OVid = actionInfo[VlanVid].(uint32)
 	}
 	// When OLT is transparent to vlans no-action is valid.
 	/*
@@ -2965,7 +2992,10 @@
 			logger.Debug(ctx, "field-type-eth-type", log.Fields{"classifierInfo[ETH_TYPE]": classifierInfo[EthType].(uint32)})
 		} else if field.Type == flows.ETH_DST {
 			classifierInfo[EthDst] = field.GetEthDst()
-			logger.Debug(ctx, "field-type-eth-type", log.Fields{"classifierInfo[ETH_DST]": classifierInfo[EthDst].([]uint8)})
+			logger.Debug(ctx, "field-type-eth-dst", log.Fields{"classifierInfo[ETH_DST]": classifierInfo[EthDst].([]uint8)})
+		} else if field.Type == flows.ETH_SRC {
+			classifierInfo[EthSrc] = field.GetEthSrc()
+			logger.Debug(ctx, "field-type-eth-src", log.Fields{"classifierInfo[ETH_SRC]": classifierInfo[EthSrc].([]uint8)})
 		} else if field.Type == flows.IP_PROTO {
 			classifierInfo[IPProto] = field.GetIpProto()
 			logger.Debug(ctx, "field-type-ip-proto", log.Fields{"classifierInfo[IP_PROTO]": classifierInfo[IPProto].(uint32)})