[VOL-4585] openonu changes adapter for adding FTTB Subscriber Traffic flow

Change-Id: I13875233bf0ce5412e1a6b0237357a2d0f41d5a8
diff --git a/VERSION b/VERSION
index 6186652..b1b25a5 100755
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.2.2-dev278
+2.2.2
diff --git a/go.mod b/go.mod
index 7a1cdc3..97f00b6 100644
--- a/go.mod
+++ b/go.mod
@@ -16,7 +16,7 @@
 	github.com/google/gopacket v1.1.17
 	github.com/looplab/fsm v0.2.0
 	github.com/opencord/omci-lib-go/v2 v2.2.0
-	github.com/opencord/voltha-lib-go/v7 v7.1.5
+	github.com/opencord/voltha-lib-go/v7 v7.1.7
 	github.com/opencord/voltha-protos/v5 v5.2.2
 	github.com/stretchr/testify v1.7.0
 	google.golang.org/grpc v1.44.0
diff --git a/go.sum b/go.sum
index c14313a..61044c9 100644
--- a/go.sum
+++ b/go.sum
@@ -200,8 +200,8 @@
 github.com/onsi/gomega v1.14.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=
 github.com/opencord/omci-lib-go/v2 v2.2.0 h1:9eawwD1+oWHTzEv9Q/JeSN12N/3YSGKoj1dr2Pm434g=
 github.com/opencord/omci-lib-go/v2 v2.2.0/go.mod h1:o1S/jhDLHNikFU7uG2TR5UOM5KmKlqwLlVncXi0FBYQ=
-github.com/opencord/voltha-lib-go/v7 v7.1.5 h1:IdNDzcA8V8LXHVm/2dG9QJ1IqFO+kM1aCAC4By+3MEU=
-github.com/opencord/voltha-lib-go/v7 v7.1.5/go.mod h1:lnwlFfhDVMBg2siCv1CajB1fvfAU9Cs8VbB64LQ8zVg=
+github.com/opencord/voltha-lib-go/v7 v7.1.7 h1:EMdvxOa9MKiNn5giXqansl7EKc9uPCstU/1kplmqNxI=
+github.com/opencord/voltha-lib-go/v7 v7.1.7/go.mod h1:lnwlFfhDVMBg2siCv1CajB1fvfAU9Cs8VbB64LQ8zVg=
 github.com/opencord/voltha-protos/v5 v5.2.2 h1:1Bcgl+Fmp00ZxlDrHZdcbjpMgOwX6TnZmOTrYm9SbR8=
 github.com/opencord/voltha-protos/v5 v5.2.2/go.mod h1:ZGcyW79kQKIo7AySo1LRu613E6uiozixrCF0yNB/4x8=
 github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
diff --git a/internal/pkg/avcfg/omci_vlan_config.go b/internal/pkg/avcfg/omci_vlan_config.go
index 2e2408d..48353b9 100755
--- a/internal/pkg/avcfg/omci_vlan_config.go
+++ b/internal/pkg/avcfg/omci_vlan_config.go
@@ -83,6 +83,7 @@
 	cDoNotFilterEtherType uint32 = 0
 	cDoNotAddPrio         uint32 = 15
 	cCopyPrioFromInner    uint32 = 8
+	cCopyPrioFromOuter    uint32 = 9
 	//cDontCarePrio         uint32 = 0
 	cDontCareVid          uint32 = 0
 	cDontCareTpid         uint32 = 0
@@ -188,7 +189,7 @@
 func NewUniVlanConfigFsm(ctx context.Context, apDeviceHandler cmn.IdeviceHandler, apOnuDeviceEntry cmn.IonuDeviceEntry, apDevOmciCC *cmn.OmciCC, apUniPort *cmn.OnuUniPort,
 	apUniTechProf *OnuUniTechProf, apOnuDB *devdb.OnuDeviceDB, aTechProfileID uint8,
 	aRequestEvent cmn.OnuDeviceEvent, aName string, aCommChannel chan cmn.Message, aAcceptIncrementalEvto bool,
-	aCookieSlice []uint64, aMatchVlan uint16, aMatchPcp uint8, aSetVlan uint16, aSetPcp uint8, lastFlowToRec bool, aMeter *of.OfpMeterConfig, respChan *chan error) *UniVlanConfigFsm {
+	aCookieSlice []uint64, aMatchVlan uint16, aMatchPcp uint8, aSetVlan uint16, aSetPcp uint8, innerCvlan uint16, lastFlowToRec bool, aMeter *of.OfpMeterConfig, respChan *chan error) *UniVlanConfigFsm {
 	instFsm := &UniVlanConfigFsm{
 		pDeviceHandler:              apDeviceHandler,
 		pOnuDeviceEntry:             apOnuDeviceEntry,
@@ -272,8 +273,7 @@
 		return nil
 	}
 
-	_ = instFsm.initUniFlowParams(ctx, aTechProfileID, aCookieSlice, aMatchVlan, aMatchPcp, aSetVlan, aSetPcp, aMeter, respChan)
-
+	_ = instFsm.initUniFlowParams(ctx, aTechProfileID, aCookieSlice, aMatchVlan, aMatchPcp, aSetVlan, aSetPcp, innerCvlan, aMeter, respChan)
 	logger.Debugw(ctx, "UniVlanConfigFsm created", log.Fields{"device-id": instFsm.deviceID,
 		"accIncrEvto": instFsm.acceptIncrementalEvtoOption})
 	return instFsm
@@ -281,13 +281,14 @@
 
 //initUniFlowParams is a simplified form of SetUniFlowParams() used for first flow parameters configuration
 func (oFsm *UniVlanConfigFsm) initUniFlowParams(ctx context.Context, aTpID uint8, aCookieSlice []uint64,
-	aMatchVlan uint16, aMatchPcp uint8, aSetVlan uint16, aSetPcp uint8, aMeter *of.OfpMeterConfig, respChan *chan error) error {
+	aMatchVlan uint16, aMatchPcp uint8, aSetVlan uint16, aSetPcp uint8, innerCvlan uint16, aMeter *of.OfpMeterConfig, respChan *chan error) error {
 	loRuleParams := cmn.UniVlanRuleParams{
-		TpID:     aTpID,
-		MatchVid: uint32(aMatchVlan),
-		MatchPcp: uint32(aMatchPcp),
-		SetVid:   uint32(aSetVlan),
-		SetPcp:   uint32(aSetPcp),
+		TpID:       aTpID,
+		MatchVid:   uint32(aMatchVlan),
+		MatchPcp:   uint32(aMatchPcp),
+		SetVid:     uint32(aSetVlan),
+		SetPcp:     uint32(aSetPcp),
+		InnerCvlan: innerCvlan,
 	}
 	// some automatic adjustments on the filter/treat parameters as not specifically configured/ensured by flow configuration parameters
 	loRuleParams.TagsToRemove = 1 //one tag to remove as default setting
@@ -398,21 +399,22 @@
 // ignore complexity by now
 // nolint: gocyclo
 func (oFsm *UniVlanConfigFsm) SetUniFlowParams(ctx context.Context, aTpID uint8, aCookieSlice []uint64,
-	aMatchVlan uint16, aMatchPcp uint8, aSetVlan uint16, aSetPcp uint8, lastFlowToReconcile bool, aMeter *of.OfpMeterConfig, respChan *chan error) error {
+	aMatchVlan uint16, aMatchPcp uint8, aSetVlan uint16, aSetPcp uint8, aInnerCvlan uint16, lastFlowToReconcile bool, aMeter *of.OfpMeterConfig, respChan *chan error) error {
 	if oFsm == nil {
 		logger.Error(ctx, "no valid UniVlanConfigFsm!")
 		return fmt.Errorf("no-valid-UniVlanConfigFsm")
 	}
 	loRuleParams := cmn.UniVlanRuleParams{
-		TpID:     aTpID,
-		MatchVid: uint32(aMatchVlan),
-		SetVid:   uint32(aSetVlan),
-		SetPcp:   uint32(aSetPcp),
+		TpID:       aTpID,
+		MatchVid:   uint32(aMatchVlan),
+		MatchPcp:   uint32(aMatchPcp),
+		SetVid:     uint32(aSetVlan),
+		SetPcp:     uint32(aSetPcp),
+		InnerCvlan: aInnerCvlan,
 	}
 	var err error
 	// some automatic adjustments on the filter/treat parameters as not specifically configured/ensured by flow configuration parameters
-	loRuleParams.TagsToRemove = 1            //one tag to remove as default setting
-	loRuleParams.MatchPcp = cPrioDoNotFilter // do not Filter on prio as default
+	loRuleParams.TagsToRemove = 1 //one tag to remove as default setting
 	if loRuleParams.SetVid == uint32(of.OfpVlanId_OFPVID_PRESENT) {
 		//then matchVlan is don't care and should be overwritten to 'transparent' here to avoid unneeded multiple flow entries
 		loRuleParams.MatchVid = uint32(of.OfpVlanId_OFPVID_PRESENT)
@@ -2232,7 +2234,8 @@
 	} //first flow element
 
 	oFsm.mutexFlowParams.RLock()
-	if oFsm.actualUniFlowParam.VlanRuleParams.SetVid == uint32(of.OfpVlanId_OFPVID_PRESENT) {
+	if oFsm.actualUniFlowParam.VlanRuleParams.SetVid == uint32(of.OfpVlanId_OFPVID_PRESENT) &&
+		uint32(oFsm.actualUniFlowParam.VlanRuleParams.InnerCvlan) == uint32(of.OfpVlanId_OFPVID_NONE) {
 		//transparent transmission required
 		oFsm.mutexFlowParams.RUnlock()
 		logger.Debugw(ctx, "UniVlanConfigFsm Tx Set::EVTOCD single tagged transparent rule", log.Fields{
@@ -2299,34 +2302,65 @@
 			matchVid := oFsm.actualUniFlowParam.VlanRuleParams.MatchVid
 			setPcp := oFsm.actualUniFlowParam.VlanRuleParams.SetPcp
 			setVid := oFsm.actualUniFlowParam.VlanRuleParams.SetVid
-			// this defines VID translation scenario: singletagged->singletagged (if not transparent)
-			logger.Debugw(ctx, "UniVlanConfigFsm Tx Set::EVTOCD single tagged translation rule", log.Fields{
-				"match-pcp": matchPcp, "match-vid": matchVid, "set-pcp": setPcp, "set-vid:": setVid, "device-id": oFsm.deviceID})
+			innerCvlan := oFsm.actualUniFlowParam.VlanRuleParams.InnerCvlan
 			sliceEvtocdRule := make([]uint8, 16)
-			// fill vlan tagging operation table bit fields using network=bigEndian order and using slice offset 0 as highest 'word'
-			binary.BigEndian.PutUint32(sliceEvtocdRule[cFilterOuterOffset:],
-				cPrioIgnoreTag<<cFilterPrioOffset| // Not an outer-tag rule
-					cDoNotFilterVid<<cFilterVidOffset| // Do not filter on outer vid
-					cDoNotFilterTPID<<cFilterTpidOffset) // Do not filter on outer TPID field
 
-			binary.BigEndian.PutUint32(sliceEvtocdRule[cFilterInnerOffset:],
-				oFsm.actualUniFlowParam.VlanRuleParams.MatchPcp<<cFilterPrioOffset| // either DNFonPrio or ignore tag (default) on innerVLAN
-					oFsm.actualUniFlowParam.VlanRuleParams.MatchVid<<cFilterVidOffset| // either DNFonVid or real filter VID
-					cDoNotFilterTPID<<cFilterTpidOffset| // Do not filter on inner TPID field
-					cDoNotFilterEtherType<<cFilterEtherTypeOffset) // Do not filter of EtherType
+			if uint32(oFsm.actualUniFlowParam.VlanRuleParams.InnerCvlan) == uint32(of.OfpVlanId_OFPVID_NONE) {
+				// this defines VID translation scenario: singletagged->singletagged (if not transparent)
+				logger.Debugw(ctx, "UniVlanConfigFsm Tx Set::EVTOCD single tagged translation rule", log.Fields{
+					"match-pcp": matchPcp, "match-vid": matchVid, "set-pcp": setPcp, "set-vid:": setVid, "device-id": oFsm.deviceID})
+				// fill vlan tagging operation table bit fields using network=bigEndian order and using slice offset 0 as highest 'word'
+				binary.BigEndian.PutUint32(sliceEvtocdRule[cFilterOuterOffset:],
+					cPrioIgnoreTag<<cFilterPrioOffset| // Not an outer-tag rule
+						cDoNotFilterVid<<cFilterVidOffset| // Do not filter on outer vid
+						cDoNotFilterTPID<<cFilterTpidOffset) // Do not filter on outer TPID field
 
-			binary.BigEndian.PutUint32(sliceEvtocdRule[cTreatOuterOffset:],
-				oFsm.actualUniFlowParam.VlanRuleParams.TagsToRemove<<cTreatTTROffset| // either 1 or 0
-					cDoNotAddPrio<<cTreatPrioOffset| // do not add outer tag
-					cDontCareVid<<cTreatVidOffset| // Outer VID don't care
-					cDontCareTpid<<cTreatTpidOffset) // Outer TPID field don't care
+				binary.BigEndian.PutUint32(sliceEvtocdRule[cFilterInnerOffset:],
+					oFsm.actualUniFlowParam.VlanRuleParams.MatchPcp<<cFilterPrioOffset| // either DNFonPrio or ignore tag (default) on innerVLAN
+						oFsm.actualUniFlowParam.VlanRuleParams.MatchVid<<cFilterVidOffset| // either DNFonVid or real filter VID
+						cDoNotFilterTPID<<cFilterTpidOffset| // Do not filter on inner TPID field
+						cDoNotFilterEtherType<<cFilterEtherTypeOffset) // Do not filter of EtherType
 
-			binary.BigEndian.PutUint32(sliceEvtocdRule[cTreatInnerOffset:],
-				oFsm.actualUniFlowParam.VlanRuleParams.SetPcp<<cTreatPrioOffset| // as configured in flow
-					oFsm.actualUniFlowParam.VlanRuleParams.SetVid<<cTreatVidOffset| //as configured in flow
-					cSetOutputTpidCopyDei<<cTreatTpidOffset) // Set TPID = 0x8100
+				binary.BigEndian.PutUint32(sliceEvtocdRule[cTreatOuterOffset:],
+					oFsm.actualUniFlowParam.VlanRuleParams.TagsToRemove<<cTreatTTROffset| // either 1 or 0
+						cDoNotAddPrio<<cTreatPrioOffset| // do not add outer tag
+						cDontCareVid<<cTreatVidOffset| // Outer VID don't care
+						cDontCareTpid<<cTreatTpidOffset) // Outer TPID field don't care
+
+				binary.BigEndian.PutUint32(sliceEvtocdRule[cTreatInnerOffset:],
+					oFsm.actualUniFlowParam.VlanRuleParams.SetPcp<<cTreatPrioOffset| // as configured in flow
+						oFsm.actualUniFlowParam.VlanRuleParams.SetVid<<cTreatVidOffset| //as configured in flow
+						cSetOutputTpidCopyDei<<cTreatTpidOffset) // Set TPID = 0x8100
+
+			} else {
+				//Double tagged case, if innerCvlan is 4096 then transparent, else match on the innerCvlan
+				//As of now only a match and no action can be done on the inner tag .
+				logger.Debugw(ctx, "UniVlanConfigFsm Tx Set::EVTOCD double tagged translation rule", log.Fields{
+					"match-pcp": matchPcp, "match-vid": matchVid, "set-pcp": setPcp, "set-vid:": setVid, "inner-cvlan:": innerCvlan, "device-id": oFsm.deviceID})
+				// fill vlan tagging operation table bit fields using network=bigEndian order and using slice offset 0 as highest 'word'
+				binary.BigEndian.PutUint32(sliceEvtocdRule[cFilterOuterOffset:],
+					oFsm.actualUniFlowParam.VlanRuleParams.MatchPcp<<cFilterPrioOffset| // either DNFonPrio or filter  priority
+						oFsm.actualUniFlowParam.VlanRuleParams.MatchVid<<cFilterVidOffset| // either DNFonVid or real filter VID
+						cDoNotFilterTPID<<cFilterTpidOffset) // Do not filter on outer TPID field
+
+				binary.BigEndian.PutUint32(sliceEvtocdRule[cFilterInnerOffset:],
+					cPrioDefaultFilter<<cFilterPrioOffset| // default inner-tag rule
+						uint32(innerCvlan)<<cFilterVidOffset| // transparent of innercvlan is 4096 or filter with innercvlan
+						cDoNotFilterTPID<<cFilterTpidOffset| // Do not filter on inner TPID field
+						cDoNotFilterEtherType<<cFilterEtherTypeOffset) // Do not filter of EtherType
+
+				binary.BigEndian.PutUint32(sliceEvtocdRule[cTreatOuterOffset:],
+					oFsm.actualUniFlowParam.VlanRuleParams.TagsToRemove<<cTreatTTROffset| // either 1 or 0
+						cCopyPrioFromOuter<<cTreatPrioOffset| // add tag and copy prio from outer from the received frame
+						setVid<<cTreatVidOffset| // Set VID
+						cDontCareTpid<<cTreatTpidOffset) // Outer TPID field don't care
+
+				binary.BigEndian.PutUint32(sliceEvtocdRule[cTreatInnerOffset:],
+					cDoNotAddPrio<<cTreatPrioOffset| // do not add inner tag
+						uint32(innerCvlan)<<cTreatVidOffset| //as configured in flow
+						cDontCareTpid<<cTreatTpidOffset) // Set TPID = 0x8100
+			}
 			oFsm.mutexFlowParams.RUnlock()
-
 			meParams := me.ParamData{
 				EntityID: evtocdID,
 				Attributes: me.AttributeValueMap{
@@ -2352,10 +2386,10 @@
 			//verify response
 			err = oFsm.waitforOmciResponse(ctx)
 			if err != nil {
-				logger.Errorw(ctx, "Evtocd set singletagged translation rule failed, aborting VlanConfig FSM!",
+				logger.Errorw(ctx, "Evtocd set rule failed, aborting VlanConfig FSM!",
 					log.Fields{"device-id": oFsm.deviceID})
 				_ = oFsm.PAdaptFsm.PFsm.Event(VlanEvReset)
-				return fmt.Errorf("evtocd set singletagged translation rule failed %s, error %s", oFsm.deviceID, err)
+				return fmt.Errorf("evtocd set rule failed %s, error %s", oFsm.deviceID, err)
 			}
 		} else {
 			//not transparent and not acceptIncrementalEvtoOption untagged/priotagged->singletagged
@@ -2566,26 +2600,49 @@
 		oFsm.mutexFlowParams.RLock()
 		if oFsm.acceptIncrementalEvtoOption {
 			oFsm.mutexFlowParams.RUnlock()
-			// this defines VID translation scenario: singletagged->singletagged (if not transparent)
-			logger.Debugw(ctx, "UniVlanConfigFsm Tx Set::EVTOCD clear single tagged translation rule", log.Fields{
-				"device-id": oFsm.deviceID, "match-vlan": aRuleParams.MatchVid})
 			sliceEvtocdRule := make([]uint8, 16)
-			// fill vlan tagging operation table bit fields using network=bigEndian order and using slice offset 0 as highest 'word'
-			binary.BigEndian.PutUint32(sliceEvtocdRule[cFilterOuterOffset:],
-				cPrioIgnoreTag<<cFilterPrioOffset| // Not an outer-tag rule
-					cDoNotFilterVid<<cFilterVidOffset| // Do not filter on outer vid
-					cDoNotFilterTPID<<cFilterTpidOffset) // Do not filter on outer TPID field
+			if uint32(aRuleParams.InnerCvlan) == uint32(of.OfpVlanId_OFPVID_NONE) {
 
-			binary.BigEndian.PutUint32(sliceEvtocdRule[cFilterInnerOffset:],
-				aRuleParams.MatchPcp<<cFilterPrioOffset| // either DNFonPrio or ignore tag (default) on innerVLAN
-					aRuleParams.MatchVid<<cFilterVidOffset| // either DNFonVid or real filter VID
-					cDoNotFilterTPID<<cFilterTpidOffset| // Do not filter on inner TPID field
-					cDoNotFilterEtherType<<cFilterEtherTypeOffset) // Do not filter of EtherType
+				// this defines VID translation scenario: singletagged->singletagged (if not transparent)
+				logger.Debugw(ctx, "UniVlanConfigFsm Tx Set::EVTOCD clear single tagged translation rule", log.Fields{
+					"device-id": oFsm.deviceID, "match-vlan": aRuleParams.MatchVid})
+				// fill vlan tagging operation table bit fields using network=bigEndian order and using slice offset 0 as highest 'word'
+				binary.BigEndian.PutUint32(sliceEvtocdRule[cFilterOuterOffset:],
+					cPrioIgnoreTag<<cFilterPrioOffset| // Not an outer-tag rule
+						cDoNotFilterVid<<cFilterVidOffset| // Do not filter on outer vid
+						cDoNotFilterTPID<<cFilterTpidOffset) // Do not filter on outer TPID field
 
-			// delete indication for the indicated Filter
-			binary.BigEndian.PutUint32(sliceEvtocdRule[cTreatOuterOffset:], 0xFFFFFFFF)
-			binary.BigEndian.PutUint32(sliceEvtocdRule[cTreatInnerOffset:], 0xFFFFFFFF)
+				binary.BigEndian.PutUint32(sliceEvtocdRule[cFilterInnerOffset:],
+					aRuleParams.MatchPcp<<cFilterPrioOffset| // either DNFonPrio or ignore tag (default) on innerVLAN
+						aRuleParams.MatchVid<<cFilterVidOffset| // either DNFonVid or real filter VID
+						cDoNotFilterTPID<<cFilterTpidOffset| // Do not filter on inner TPID field
+						cDoNotFilterEtherType<<cFilterEtherTypeOffset) // Do not filter of EtherType
 
+				// delete indication for the indicated Filter
+				binary.BigEndian.PutUint32(sliceEvtocdRule[cTreatOuterOffset:], 0xFFFFFFFF)
+				binary.BigEndian.PutUint32(sliceEvtocdRule[cTreatInnerOffset:], 0xFFFFFFFF)
+
+			} else {
+				// this defines VID translation scenario: dobletagged-doubletagged (if not transparent)
+				logger.Debugw(ctx, "UniVlanConfigFsm Tx Set::EVTOCD clear double tagged rule", log.Fields{
+					"device-id": oFsm.deviceID, "match-vlan": aRuleParams.MatchVid, "innerCvlan": aRuleParams.InnerCvlan})
+				sliceEvtocdRule := make([]uint8, 16)
+				// fill vlan tagging operation table bit fields using network=bigEndian order and using slice offset 0 as highest 'word'
+				binary.BigEndian.PutUint32(sliceEvtocdRule[cFilterOuterOffset:],
+					cPrioIgnoreTag<<cFilterPrioOffset| // Not an outer-tag rule
+						aRuleParams.MatchVid<<cFilterVidOffset| // Do not filter on outer vid
+						cDoNotFilterTPID<<cFilterTpidOffset) // Do not filter on outer TPID field
+
+				binary.BigEndian.PutUint32(sliceEvtocdRule[cFilterInnerOffset:],
+					cPrioIgnoreTag<<cFilterPrioOffset| // either DNFonPrio or ignore tag (default) on innerVLAN
+						cDoNotFilterVid<<cFilterVidOffset| // DNFonVid or ignore tag
+						cDoNotFilterTPID<<cFilterTpidOffset| // Do not filter on inner TPID field
+						cDoNotFilterEtherType<<cFilterEtherTypeOffset) // Do not filter of EtherType
+
+				// delete indication for the indicated Filter
+				binary.BigEndian.PutUint32(sliceEvtocdRule[cTreatOuterOffset:], 0xFFFFFFFF)
+				binary.BigEndian.PutUint32(sliceEvtocdRule[cTreatInnerOffset:], 0xFFFFFFFF)
+			}
 			meParams := me.ParamData{
 				EntityID: evtocdID,
 				Attributes: me.AttributeValueMap{
@@ -2611,8 +2668,10 @@
 			//verify response
 			err = oFsm.waitforOmciResponse(ctx)
 			if err != nil {
-				logger.Errorw(ctx, "Evtocd clear singletagged translation rule failed, aborting VlanConfig FSM!",
-					log.Fields{"device-id": oFsm.deviceID, "match-vlan": aRuleParams.MatchVid})
+				logger.Errorw(ctx, "Evtocd clear rule failed, aborting VlanConfig FSM!",
+					log.Fields{"device-id": oFsm.deviceID,
+						"match-vlan": aRuleParams.MatchVid,
+						"InnerCvlan": aRuleParams.InnerCvlan})
 				_ = oFsm.PAdaptFsm.PFsm.Event(VlanEvReset)
 				return
 			}
diff --git a/internal/pkg/common/defines.go b/internal/pkg/common/defines.go
index ba44367..c2eecbd 100755
--- a/internal/pkg/common/defines.go
+++ b/internal/pkg/common/defines.go
@@ -315,6 +315,7 @@
 	TagsToRemove uint32 `json:"tags_to_remove"`
 	SetVid       uint32 `json:"set_vid"`
 	SetPcp       uint32 `json:"set_pcp"`
+	InnerCvlan   uint16 `json:"inner_cvlan"`
 }
 
 // UniVlanFlowParams - TODO: add comment
diff --git a/internal/pkg/core/device_handler.go b/internal/pkg/core/device_handler.go
index b4574ae..d65b1b0 100755
--- a/internal/pkg/core/device_handler.go
+++ b/internal/pkg/core/device_handler.go
@@ -1119,14 +1119,13 @@
 		//the CookieSlice can be passed 'by value' here, - which internally passes its reference
 		if _, exist := dh.UniVlanConfigFsmMap[loUniID]; exist {
 			if err := dh.UniVlanConfigFsmMap[loUniID].SetUniFlowParams(ctx, flowData.VlanRuleParams.TpID,
-				flowData.CookieSlice, uint16(flowData.VlanRuleParams.MatchVid), uint8(flowData.VlanRuleParams.MatchPcp), uint16(flowData.VlanRuleParams.SetVid),
-				uint8(flowData.VlanRuleParams.SetPcp), lastFlowToReconcile, flowData.Meter, nil); err != nil {
+				flowData.CookieSlice, uint16(flowData.VlanRuleParams.MatchVid), uint8(flowData.VlanRuleParams.MatchPcp), uint16(flowData.VlanRuleParams.SetVid), uint8(flowData.VlanRuleParams.SetPcp), flowData.VlanRuleParams.InnerCvlan, lastFlowToReconcile, flowData.Meter, nil); err != nil {
 				logger.Errorw(ctx, err.Error(), log.Fields{"device-id": dh.DeviceID})
 			}
 		} else {
 			if err := dh.createVlanFilterFsm(ctx, apUniPort, flowData.VlanRuleParams.TpID, flowData.CookieSlice,
 				uint16(flowData.VlanRuleParams.MatchVid), uint8(flowData.VlanRuleParams.MatchPcp), uint16(flowData.VlanRuleParams.SetVid),
-				uint8(flowData.VlanRuleParams.SetPcp), cmn.OmciVlanFilterAddDone, lastFlowToReconcile, flowData.Meter, nil); err != nil {
+				uint8(flowData.VlanRuleParams.SetPcp), flowData.VlanRuleParams.InnerCvlan, cmn.OmciVlanFilterAddDone, lastFlowToReconcile, flowData.Meter, nil); err != nil {
 				logger.Errorw(ctx, err.Error(), log.Fields{"device-id": dh.DeviceID})
 			}
 		}
@@ -3261,8 +3260,9 @@
 	loTpID := uint8(flow.GetTechProfileIDFromWriteMetaData(ctx, metadata))
 	loCookie := apFlowItem.GetCookie()
 	loCookieSlice := []uint64{loCookie}
+	loInnerCvlan := flow.GetInnerTagFromWriteMetaData(ctx, metadata)
 	logger.Debugw(ctx, "flow-add base indications", log.Fields{"device-id": dh.DeviceID,
-		"TechProf-Id": loTpID, "cookie": loCookie})
+		"TechProf-Id": loTpID, "cookie": loCookie, "innerCvlan": loInnerCvlan})
 
 	dh.getFlowOfbFields(ctx, apFlowItem, &loMatchVlan, &loMatchPcp, &loIPProto)
 	/* TT related temporary workaround - should not be needed anymore
@@ -3276,7 +3276,8 @@
 	*/
 	dh.getFlowActions(ctx, apFlowItem, &loSetPcp, &loSetVlan)
 
-	if loSetVlan == uint16(of.OfpVlanId_OFPVID_NONE) && loMatchVlan != uint16(of.OfpVlanId_OFPVID_PRESENT) && (loMatchPcp == 8) {
+	if loSetVlan == uint16(of.OfpVlanId_OFPVID_NONE) && loMatchVlan != uint16(of.OfpVlanId_OFPVID_PRESENT) && (loMatchPcp == 8) &&
+		loInnerCvlan == uint16(of.OfpVlanId_OFPVID_NONE) {
 		logger.Errorw(ctx, "flow-add aborted - SetVlanId undefined, but MatchVid set", log.Fields{
 			"device-id": dh.DeviceID, "UniPort": apUniPort.PortNo,
 			"set_vid":   strconv.FormatInt(int64(loSetVlan), 16),
@@ -3313,7 +3314,7 @@
 		//  in order to allow for according flow removal lockVlanConfig may only be used with RLock here
 		// Also the error is returned to caller via response channel
 		_ = dh.UniVlanConfigFsmMap[apUniPort.UniID].SetUniFlowParams(ctx, loTpID, loCookieSlice,
-			loMatchVlan, loMatchPcp, loSetVlan, loSetPcp, false, meter, respChan)
+			loMatchVlan, loMatchPcp, loSetVlan, loSetPcp, loInnerCvlan, false, meter, respChan)
 		dh.lockVlanConfig.RUnlock()
 		dh.lockVlanAdd.Unlock() //re-admit new Add-flow-processing
 		return
@@ -3321,7 +3322,7 @@
 	dh.lockVlanConfig.RUnlock()
 	dh.lockVlanConfig.Lock() //createVlanFilterFsm should always be a non-blocking operation and requires r+w lock
 	err := dh.createVlanFilterFsm(ctx, apUniPort, loTpID, loCookieSlice,
-		loMatchVlan, loMatchPcp, loSetVlan, loSetPcp, cmn.OmciVlanFilterAddDone, false, meter, respChan)
+		loMatchVlan, loMatchPcp, loSetVlan, loSetPcp, loInnerCvlan, cmn.OmciVlanFilterAddDone, false, meter, respChan)
 	dh.lockVlanConfig.Unlock()
 	dh.lockVlanAdd.Unlock() //re-admit new Add-flow-processing
 	if err != nil {
@@ -3386,7 +3387,7 @@
 // if this function is called from possibly concurrent processes it must be mutex-protected from the caller!
 // precondition: dh.lockVlanConfig is locked by the caller!
 func (dh *deviceHandler) createVlanFilterFsm(ctx context.Context, apUniPort *cmn.OnuUniPort, aTpID uint8, aCookieSlice []uint64,
-	aMatchVlan uint16, aMatchPcp uint8, aSetVlan uint16, aSetPcp uint8, aDevEvent cmn.OnuDeviceEvent, lastFlowToReconcile bool, aMeter *of.OfpMeterConfig, respChan *chan error) error {
+	aMatchVlan uint16, aMatchPcp uint8, aSetVlan uint16, aSetPcp uint8, innerCvlan uint16, aDevEvent cmn.OnuDeviceEvent, lastFlowToReconcile bool, aMeter *of.OfpMeterConfig, respChan *chan error) error {
 	chVlanFilterFsm := make(chan cmn.Message, 2048)
 
 	pDevEntry := dh.GetOnuDeviceEntry(ctx, true)
@@ -3397,7 +3398,7 @@
 
 	pVlanFilterFsm := avcfg.NewUniVlanConfigFsm(ctx, dh, pDevEntry, pDevEntry.PDevOmciCC, apUniPort, dh.pOnuTP,
 		pDevEntry.GetOnuDB(), aTpID, aDevEvent, "UniVlanConfigFsm", chVlanFilterFsm,
-		dh.pOpenOnuAc.AcceptIncrementalEvto, aCookieSlice, aMatchVlan, aMatchPcp, aSetVlan, aSetPcp, lastFlowToReconcile, aMeter, respChan)
+		dh.pOpenOnuAc.AcceptIncrementalEvto, aCookieSlice, aMatchVlan, aMatchPcp, aSetVlan, aSetPcp, innerCvlan, lastFlowToReconcile, aMeter, respChan)
 	if pVlanFilterFsm != nil {
 		//dh.lockVlanConfig is locked (by caller) throughout the state transition to 'starting'
 		// to prevent unintended (ignored) events to be sent there (from parallel processing)
diff --git a/vendor/github.com/opencord/voltha-lib-go/v7/pkg/flows/flow_utils.go b/vendor/github.com/opencord/voltha-lib-go/v7/pkg/flows/flow_utils.go
index 1e50a63..46375fa 100644
--- a/vendor/github.com/opencord/voltha-lib-go/v7/pkg/flows/flow_utils.go
+++ b/vendor/github.com/opencord/voltha-lib-go/v7/pkg/flows/flow_utils.go
@@ -629,6 +629,22 @@
 	return innerTag
 }
 
+func GetInnerTagFromWriteMetaData(ctx context.Context, metadata uint64) uint16 {
+	/*
+			  Write metadata instruction value (metadata) is 8 bytes:
+		    	MS 2 bytes: C Tag
+		    	Next 2 bytes: Technology Profile Id
+		    	Next 4 bytes: Port number (uni or nni)
+		    	This is set in the ONOS OltPipeline as a write metadata instruction
+	*/
+	var innerTag uint16 = 0
+	if metadata != 0 {
+		innerTag = uint16((metadata >> 48) & 0xFFFF)
+		logger.Debugw(ctx, "Found  CVLAN from write metadate action", log.Fields{"c_vlan": innerTag})
+	}
+	return innerTag
+}
+
 //GetInnerTagFromMetaData retrieves the inner tag from the Metadata_ofp. The port number (UNI on ONU) is in the
 // lower 32-bits of Metadata_ofp and the inner_tag is in the upper 32-bits. This is set in the ONOS OltPipeline as
 //// a Metadata_ofp field
diff --git a/vendor/github.com/opencord/voltha-lib-go/v7/pkg/meters/meter_utils.go b/vendor/github.com/opencord/voltha-lib-go/v7/pkg/meters/meter_utils.go
index 56e8ecc..ed3db8b 100644
--- a/vendor/github.com/opencord/voltha-lib-go/v7/pkg/meters/meter_utils.go
+++ b/vendor/github.com/opencord/voltha-lib-go/v7/pkg/meters/meter_utils.go
@@ -29,14 +29,14 @@
 	switch meterBandSize := len(meterConfig.Bands); {
 	case meterBandSize == 1:
 		band := meterConfig.Bands[0]
-		if band.BurstSize == 0 { // GIR, tcont type 1
-			return &tp_pb.TrafficShapingInfo{Gir: band.Rate}, nil
+		if band.BurstSize == 0 { // GIR = PIR, Burst Size = 0, tcont type 1
+			return &tp_pb.TrafficShapingInfo{Pir: band.Rate, Gir: band.Rate}, nil
 		}
 		return &tp_pb.TrafficShapingInfo{Pir: band.Rate, Pbs: band.BurstSize}, nil // PIR, tcont type 4
 	case meterBandSize == 2:
 		firstBand, secondBand := meterConfig.Bands[0], meterConfig.Bands[1]
 		if firstBand.BurstSize == 0 && secondBand.BurstSize == 0 &&
-			firstBand.Rate == secondBand.Rate { // PIR == GIR, tcont type 1
+			firstBand.Rate == secondBand.Rate { // PIR = GIR, tcont type 1
 			return &tp_pb.TrafficShapingInfo{Pir: firstBand.Rate, Gir: secondBand.Rate}, nil
 		}
 		if firstBand.BurstSize > 0 && secondBand.BurstSize > 0 { // PIR, CIR, tcont type 2 or 3
diff --git a/vendor/modules.txt b/vendor/modules.txt
index ef39df0..94a4d19 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -138,7 +138,7 @@
 github.com/opencord/omci-lib-go/v2
 github.com/opencord/omci-lib-go/v2/generated
 github.com/opencord/omci-lib-go/v2/meframe
-# github.com/opencord/voltha-lib-go/v7 v7.1.5
+# github.com/opencord/voltha-lib-go/v7 v7.1.7
 ## explicit
 github.com/opencord/voltha-lib-go/v7/pkg/config
 github.com/opencord/voltha-lib-go/v7/pkg/db