[VOL-3437] Implement (incremental) flow config removal with according OMCI VLAN configuration and some further code corrections and smaller functional extensions -> version 0.1.13-dev135, now merged with [VOL-3586] und included correction for missing Techprofile configuration at disable/enable procedure

Signed-off-by: mpagenko <michael.pagenkopf@adtran.com>
Change-Id: I438a72867d5da83c505a30169d7d5aba8f8ee8c2
diff --git a/internal/pkg/onuadaptercore/device_handler.go b/internal/pkg/onuadaptercore/device_handler.go
index d5a49a8..054a0bb 100644
--- a/internal/pkg/onuadaptercore/device_handler.go
+++ b/internal/pkg/onuadaptercore/device_handler.go
@@ -330,7 +330,7 @@
 		// attention: deadline completion check and wg.Done is to be done in both routines
 		go dh.pOnuTP.configureUniTp(dctx, uniID, techProfMsg.Path, &wg)
 		go pDevEntry.updateOnuKvStore(dctx, &wg)
-		dh.waitForCompletion(cancel, &wg) //wait for background process to finish
+		dh.waitForCompletion(cancel, &wg, "TechProfDwld") //wait for background process to finish
 
 		return dh.combineErrorStrings(dh.pOnuTP.getTpProcessingErrorIndication(), pDevEntry.getKvProcessingErrorIndication())
 	}
@@ -387,7 +387,7 @@
 			cResourceGemPort, delGemPortMsg.GemPortId, &wg)
 		// Removal of the tcont/alloc id mapping represents the removal of the tech profile
 		go pDevEntry.updateOnuKvStore(dctx, &wg)
-		dh.waitForCompletion(cancel, &wg) //wait for background process to finish
+		dh.waitForCompletion(cancel, &wg, "GemDelete") //wait for background process to finish
 
 		return dh.combineErrorStrings(dh.pOnuTP.getTpProcessingErrorIndication(), pDevEntry.getKvProcessingErrorIndication())
 	}
@@ -443,7 +443,7 @@
 			cResourceTcont, delTcontMsg.AllocId, &wg)
 		// Removal of the tcont/alloc id mapping represents the removal of the tech profile
 		go pDevEntry.updateOnuKvStore(dctx, &wg)
-		dh.waitForCompletion(cancel, &wg) //wait for background process to finish
+		dh.waitForCompletion(cancel, &wg, "TContDelete") //wait for background process to finish
 
 		return dh.combineErrorStrings(dh.pOnuTP.getTpProcessingErrorIndication(), pDevEntry.getKvProcessingErrorIndication())
 	}
@@ -497,30 +497,28 @@
 //FlowUpdateIncremental removes and/or adds the flow changes on a given device
 func (dh *deviceHandler) FlowUpdateIncremental(apOfFlowChanges *openflow_13.FlowChanges,
 	apOfGroupChanges *openflow_13.FlowGroupChanges, apFlowMetaData *voltha.FlowMetadata) error {
-	logger.Debugw("FlowUpdateIncremental started", log.Fields{"deviceId": dh.deviceID})
+	logger.Debugw("FlowUpdateIncremental started", log.Fields{"device-id": dh.deviceID})
 
-	//Remove flows
+	var retError error = nil
+	//Remove flows (always remove flows first - remove old and add new with same cookie may be part of the same request)
 	if apOfFlowChanges.ToRemove != nil {
 		for _, flowItem := range apOfFlowChanges.ToRemove.Items {
-			logger.Debugw("incremental flow item remove", log.Fields{"deviceId": dh.deviceID,
-				"Item": flowItem})
-		}
-	}
-	if apOfFlowChanges.ToAdd != nil {
-		for _, flowItem := range apOfFlowChanges.ToAdd.Items {
 			if flowItem.GetCookie() == 0 {
-				logger.Debugw("incremental flow add - no cookie - ignore", log.Fields{
-					"deviceId": dh.deviceID})
+				logger.Warnw("flow-remove no cookie: ignore and continuing on checking further flows", log.Fields{
+					"device-id": dh.deviceID})
+				retError = fmt.Errorf("flow-remove no cookie, device-id %s", dh.deviceID)
 				continue
 			}
 			flowInPort := flow.GetInPort(flowItem)
 			if flowInPort == uint32(of.OfpPortNo_OFPP_INVALID) {
-				logger.Errorw("flow inPort invalid", log.Fields{"deviceID": dh.deviceID})
-				return fmt.Errorf("flow inPort invalid: %s", dh.deviceID)
+				logger.Warnw("flow-remove inPort invalid: ignore and continuing on checking further flows", log.Fields{"device-id": dh.deviceID})
+				retError = fmt.Errorf("flow-remove inPort invalid, device-id %s", dh.deviceID)
+				continue
+				//return fmt.Errorf("flow inPort invalid: %s", dh.deviceID)
 			} else if flowInPort == dh.ponPortNumber {
-				//this is some downstream flow
-				logger.Debugw("incremental flow ignore downstream", log.Fields{
-					"deviceId": dh.deviceID, "inPort": flowInPort})
+				//this is some downstream flow, not regarded as error, just ignored
+				logger.Debugw("flow-remove for downstream: ignore and continuing on checking further flows", log.Fields{
+					"device-id": dh.deviceID, "inPort": flowInPort})
 				continue
 			} else {
 				// this is the relevant upstream flow
@@ -528,23 +526,82 @@
 				if uniPort, exist := dh.uniEntityMap[flowInPort]; exist {
 					loUniPort = uniPort
 				} else {
-					logger.Errorw("flow inPort not found in UniPorts",
-						log.Fields{"deviceID": dh.deviceID, "inPort": flowInPort})
-					return fmt.Errorf("flow-parameter inPort %d not found in internal UniPorts", flowInPort)
+					logger.Warnw("flow-remove inPort not found in UniPorts: ignore and continuing on checking further flows",
+						log.Fields{"device-id": dh.deviceID, "inPort": flowInPort})
+					retError = fmt.Errorf("flow-remove inPort not found in UniPorts, inPort %d, device-id %s",
+						flowInPort, dh.deviceID)
+					continue
+					//return fmt.Errorf("flow-parameter inPort %d not found in internal UniPorts", flowInPort)
 				}
 				flowOutPort := flow.GetOutPort(flowItem)
-				logger.Debugw("incremental flow-add port indications", log.Fields{
-					"deviceId": dh.deviceID, "inPort": flowInPort, "outPort": flowOutPort,
+				logger.Debugw("flow-remove port indications", log.Fields{
+					"device-id": dh.deviceID, "inPort": flowInPort, "outPort": flowOutPort,
 					"uniPortName": loUniPort.name})
-				err := dh.addFlowItemToUniPort(flowItem, loUniPort)
-				//abort processing in error case
+				err := dh.removeFlowItemFromUniPort(flowItem, loUniPort)
+				//try next flow after processing error
 				if err != nil {
-					return err
+					logger.Warnw("flow-remove processing error: continuing on checking further flows",
+						log.Fields{"device-id": dh.deviceID, "error": err})
+					retError = err
+					continue
+					//return err
+				} else { // if last setting succeeds, overwrite possibly previously set error
+					retError = nil
 				}
 			}
 		}
 	}
-	return nil
+	if apOfFlowChanges.ToAdd != nil {
+		for _, flowItem := range apOfFlowChanges.ToAdd.Items {
+			if flowItem.GetCookie() == 0 {
+				logger.Debugw("incremental flow-add no cookie: ignore and continuing on checking further flows", log.Fields{
+					"device-id": dh.deviceID})
+				retError = fmt.Errorf("flow-add no cookie, device-id %s", dh.deviceID)
+				continue
+			}
+			flowInPort := flow.GetInPort(flowItem)
+			if flowInPort == uint32(of.OfpPortNo_OFPP_INVALID) {
+				logger.Warnw("flow-add inPort invalid: ignore and continuing on checking further flows", log.Fields{"device-id": dh.deviceID})
+				retError = fmt.Errorf("flow-add inPort invalid, device-id %s", dh.deviceID)
+				continue
+				//return fmt.Errorf("flow inPort invalid: %s", dh.deviceID)
+			} else if flowInPort == dh.ponPortNumber {
+				//this is some downstream flow
+				logger.Debugw("flow-add for downstream: ignore and continuing on checking further flows", log.Fields{
+					"device-id": dh.deviceID, "inPort": flowInPort})
+				continue
+			} else {
+				// this is the relevant upstream flow
+				var loUniPort *onuUniPort
+				if uniPort, exist := dh.uniEntityMap[flowInPort]; exist {
+					loUniPort = uniPort
+				} else {
+					logger.Warnw("flow-add inPort not found in UniPorts: ignore and continuing on checking further flows",
+						log.Fields{"device-id": dh.deviceID, "inPort": flowInPort})
+					retError = fmt.Errorf("flow-add inPort not found in UniPorts, inPort %d, device-id %s",
+						flowInPort, dh.deviceID)
+					continue
+					//return fmt.Errorf("flow-parameter inPort %d not found in internal UniPorts", flowInPort)
+				}
+				flowOutPort := flow.GetOutPort(flowItem)
+				logger.Debugw("flow-add port indications", log.Fields{
+					"device-id": dh.deviceID, "inPort": flowInPort, "outPort": flowOutPort,
+					"uniPortName": loUniPort.name})
+				err := dh.addFlowItemToUniPort(flowItem, loUniPort)
+				//try next flow after processing error
+				if err != nil {
+					logger.Warnw("flow-add processing error: continuing on checking further flows",
+						log.Fields{"device-id": dh.deviceID, "error": err})
+					retError = err
+					continue
+					//return err
+				} else { // if last setting succeeds, overwrite possibly previously set error
+					retError = nil
+				}
+			}
+		}
+	}
+	return retError
 }
 
 //disableDevice locks the ONU and its UNI/VEIP ports (admin lock via OMCI)
@@ -568,13 +625,40 @@
 			return
 		}
 
-		// disable UNI ports/ONU
-		// *** should generate UniDisableStateDone event - used to disable the port(s) on success
-		if dh.pLockStateFsm == nil {
-			dh.createUniLockFsm(true, UniDisableStateDone)
-		} else { //LockStateFSM already init
-			dh.pLockStateFsm.setSuccessEvent(UniDisableStateDone)
-			dh.runUniLockFsm(true)
+		if dh.deviceReason != "rebooting" {
+			// disable UNI ports/ONU
+			// *** should generate UniDisableStateDone event - used to disable the port(s) on success
+			if dh.pLockStateFsm == nil {
+				dh.createUniLockFsm(true, UniDisableStateDone)
+			} else { //LockStateFSM already init
+				dh.pLockStateFsm.setSuccessEvent(UniDisableStateDone)
+				dh.runUniLockFsm(true)
+			}
+		} else {
+			logger.Debugw("DeviceStateUpdate upon disable", log.Fields{"ConnectStatus": voltha.ConnectStatus_REACHABLE,
+				"OperStatus": voltha.OperStatus_UNKNOWN, "device-id": dh.deviceID})
+			if err := dh.coreProxy.DeviceStateUpdate(context.TODO(),
+				dh.deviceID, voltha.ConnectStatus_REACHABLE, voltha.OperStatus_UNKNOWN); err != nil {
+				//TODO with VOL-3045/VOL-3046: return the error and stop further processing
+				logger.Errorw("error-updating-device-state", log.Fields{"device-id": dh.deviceID, "error": err})
+			}
+
+			logger.Debugw("DeviceReasonUpdate upon re-enable", log.Fields{
+				"reason": "omci-admin-lock", "device-id": dh.deviceID})
+			// DeviceReason to update acc.to modified py code as per beginning of Sept 2020
+			if err := dh.coreProxy.DeviceReasonUpdate(context.TODO(), dh.deviceID, "omci-admin-lock"); err != nil {
+				//TODO with VOL-3045/VOL-3046: return the error and stop further processing
+				logger.Errorw("error-updating-reason-state", log.Fields{"device-id": dh.deviceID, "error": err})
+			}
+			dh.deviceReason = "omci-admin-lock"
+
+			//stop the device entry which resets the attached omciCC
+			pDevEntry := dh.getOnuDeviceEntry(false)
+			if pDevEntry == nil {
+				logger.Errorw("No valid OnuDevice -aborting", log.Fields{"device-id": dh.deviceID})
+				return
+			}
+			_ = pDevEntry.stop(context.TODO(), true) //stop deviceEntry with omciCC reset
 		}
 	}
 }
@@ -637,7 +721,7 @@
 		var wg sync.WaitGroup
 		wg.Add(1) // for the 1 go routine to finish
 		go dh.pOnuTP.configureUniTp(dctx, uniData.PersUniID, uniData.PersTpPath, &wg)
-		dh.waitForCompletion(cancel, &wg) //wait for background process to finish
+		dh.waitForCompletion(cancel, &wg, "TechProfReconcile") //wait for background process to finish
 
 		if err := dh.pOnuTP.getTpProcessingErrorIndication(); err != nil {
 			logger.Errorw(err.Error(), log.Fields{"device-id": dh.deviceID})
@@ -658,19 +742,22 @@
 		var exist bool
 		uniNo := mkUniPortNum(dh.pOnuIndication.GetIntfId(), dh.pOnuIndication.GetOnuId(), uint32(uniData.PersUniID))
 		if uniPort, exist = dh.uniEntityMap[uniNo]; !exist {
-			logger.Errorw("onuUniPort data not found!", log.Fields{"uniNo": uniNo, "deviceID": dh.deviceID})
+			logger.Errorw("onuUniPort data not found!", log.Fields{"uniNo": uniNo, "device-id": dh.deviceID})
 			return
 		}
 		for _, flowData := range uniData.PersFlowParams {
+			logger.Debugw("add flow with cookie slice", log.Fields{"device-id": dh.deviceID, "cookies": flowData.CookieSlice})
+			//the slice can be passed 'by value' here, - which internally passes its reference copy
 			if _, exist = dh.UniVlanConfigFsmMap[uniData.PersUniID]; exist {
-				if err := dh.UniVlanConfigFsmMap[uniData.PersUniID].SetUniFlowParams(flowData.TpID, uint16(flowData.MatchVid),
-					uint16(flowData.SetVid), uint8(flowData.SetPcp)); err != nil {
+				if err := dh.UniVlanConfigFsmMap[uniData.PersUniID].SetUniFlowParams(flowData.VlanRuleParams.TpID,
+					flowData.CookieSlice, uint16(flowData.VlanRuleParams.MatchVid), uint16(flowData.VlanRuleParams.SetVid),
+					uint8(flowData.VlanRuleParams.SetPcp)); err != nil {
 					logger.Errorw(err.Error(), log.Fields{"device-id": dh.deviceID})
 				}
-
 			} else {
-				if err := dh.createVlanFilterFsm(uniPort, flowData.TpID, uint16(flowData.MatchVid), uint16(flowData.SetVid),
-					uint8(flowData.SetPcp), OmciVlanFilterDone); err != nil {
+				if err := dh.createVlanFilterFsm(uniPort, flowData.VlanRuleParams.TpID, flowData.CookieSlice,
+					uint16(flowData.VlanRuleParams.MatchVid), uint16(flowData.VlanRuleParams.SetVid),
+					uint8(flowData.VlanRuleParams.SetPcp), OmciVlanFilterDone); err != nil {
 					logger.Errorw(err.Error(), log.Fields{"device-id": dh.deviceID})
 				}
 			}
@@ -706,7 +793,7 @@
 	var wg sync.WaitGroup
 	wg.Add(1) // for the 1 go routine to finish
 	go pDevEntry.deleteDataFromOnuKvStore(dctx, &wg)
-	dh.waitForCompletion(cancel, &wg) //wait for background process to finish
+	dh.waitForCompletion(cancel, &wg, "DeleteDevice") //wait for background process to finish
 
 	// TODO: further actions - stop metrics and FSMs, remove device ...
 	return pDevEntry.getKvProcessingErrorIndication()
@@ -723,6 +810,10 @@
 		logger.Errorw("error-rebooting-device", log.Fields{"device-id": dh.deviceID, "error": err})
 		return err
 	}
+
+	//transfer the possibly modified logical uni port state
+	dh.disableUniPortStateUpdate()
+
 	logger.Debugw("call DeviceStateUpdate upon reboot", log.Fields{"ConnectStatus": voltha.ConnectStatus_REACHABLE,
 		"OperStatus": voltha.OperStatus_DISCOVERED, "device-id": dh.deviceID})
 	if err := dh.coreProxy.DeviceStateUpdate(context.TODO(), dh.deviceID, voltha.ConnectStatus_REACHABLE,
@@ -736,7 +827,7 @@
 		logger.Errorw("error-updating-reason-state", log.Fields{"device-id": dh.deviceID, "error": err})
 		return err
 	}
-	dh.deviceReason = "rebooting-onu"
+	dh.deviceReason = "rebooting"
 	return nil
 }
 
@@ -792,7 +883,7 @@
 				   )
 	*/
 	if !dh.reconciling {
-		logger.Debugw("adding-pon-port", log.Fields{"deviceID": dh.deviceID, "ponPortNo": dh.ponPortNumber})
+		logger.Debugw("adding-pon-port", log.Fields{"device-id": dh.deviceID, "ponPortNo": dh.ponPortNumber})
 		var ponPortNo uint32 = 1
 		if dh.ponPortNumber != 0 {
 			ponPortNo = dh.ponPortNumber
@@ -907,7 +998,7 @@
 		// Synchronous call to update device state - this method is run in its own go routine
 		if err := dh.coreProxy.DeviceStateUpdate(ctx, dh.device.Id, voltha.ConnectStatus_REACHABLE,
 			voltha.OperStatus_ACTIVE); err != nil {
-			logger.Errorw("Failed to update device with OLT UP indication", log.Fields{"deviceID": dh.device.Id, "error": err})
+			logger.Errorw("Failed to update device with OLT UP indication", log.Fields{"device-id": dh.device.Id, "error": err})
 			return err
 		}
 		return nil
@@ -933,7 +1024,7 @@
 	/*
 		// Update the all ports state on that device to disable
 		if er := dh.coreProxy.PortsStateUpdate(ctx, cloned.Id, voltha.OperStatus_UNKNOWN); er != nil {
-			logger.Errorw("updating-ports-failed", log.Fields{"deviceID": device.Id, "error": er})
+			logger.Errorw("updating-ports-failed", log.Fields{"device-id": device.Id, "error": er})
 			return er
 		}
 
@@ -943,14 +1034,14 @@
 		dh.device = cloned
 
 		if er := dh.coreProxy.DeviceStateUpdate(ctx, cloned.Id, cloned.ConnectStatus, cloned.OperStatus); er != nil {
-			logger.Errorw("error-updating-device-state", log.Fields{"deviceID": device.Id, "error": er})
+			logger.Errorw("error-updating-device-state", log.Fields{"device-id": device.Id, "error": er})
 			return er
 		}
 
 		//get the child device for the parent device
 		onuDevices, err := dh.coreProxy.GetChildDevices(ctx, dh.device.Id)
 		if err != nil {
-			logger.Errorw("failed to get child devices information", log.Fields{"deviceID": dh.device.Id, "error": err})
+			logger.Errorw("failed to get child devices information", log.Fields{"device-id": dh.device.Id, "error": err})
 			return err
 		}
 		for _, onuDevice := range onuDevices.Items {
@@ -962,14 +1053,14 @@
 				"openolt", onuDevice.Type, onuDevice.Id, onuDevice.ProxyAddress.DeviceId, "")
 			if er != nil {
 				logger.Errorw("Failed to send inter-adapter-message", log.Fields{"OnuInd": onuInd,
-					"From Adapter": "openolt", "DevieType": onuDevice.Type, "DeviceID": onuDevice.Id})
+					"From Adapter": "openolt", "DevieType": onuDevice.Type, "device-id": onuDevice.Id})
 				//Do not return here and continue to process other ONUs
 			}
 		}
 		// * Discovered ONUs entries need to be cleared , since after OLT
 		//   is up, it starts sending discovery indications again* /
 		dh.discOnus = sync.Map{}
-		logger.Debugw("do-state-down-end", log.Fields{"deviceID": device.Id})
+		logger.Debugw("do-state-down-end", log.Fields{"device-id": device.Id})
 		return nil
 	*/
 	err = errors.New("device FSM: function not implemented yet")
@@ -1030,7 +1121,7 @@
 			dh.pOpenOnuAc.KVStorePort, dh.pOpenOnuAc.KVStoreType,
 			dh, dh.coreProxy, dh.AdapterProxy,
 			dh.pOpenOnuAc.pSupportedFsms) //nil as FSM pointer would yield deviceEntry internal defaults ...
-		onuTechProfProc := newOnuUniTechProf(ctx, dh.deviceID, dh)
+		onuTechProfProc := newOnuUniTechProf(ctx, dh)
 		//error treatment possible //TODO!!!
 		dh.setOnuDeviceEntry(deviceEntry, onuTechProfProc)
 		// fire deviceEntry ready event to spread to possibly waiting processing
@@ -1196,7 +1287,7 @@
 	if pMibUlFsm != nil {
 		if pMibUlFsm.Is(ulStDisabled) {
 			if err := pMibUlFsm.Event(ulEvStart); err != nil {
-				logger.Errorw("MibSyncFsm: Can't go to state starting", log.Fields{"deviceId": dh.deviceID, "err": err})
+				logger.Errorw("MibSyncFsm: Can't go to state starting", log.Fields{"device-id": dh.deviceID, "err": err})
 				return fmt.Errorf("can't go to state starting: %s", dh.deviceID)
 			}
 			logger.Debugw("MibSyncFsm", log.Fields{"state": string(pMibUlFsm.Current())})
@@ -1204,12 +1295,12 @@
 			//Determine if this ONU has ever synchronized
 			if true { //TODO: insert valid check
 				if err := pMibUlFsm.Event(ulEvResetMib); err != nil {
-					logger.Errorw("MibSyncFsm: Can't go to state resetting_mib", log.Fields{"deviceId": dh.deviceID, "err": err})
+					logger.Errorw("MibSyncFsm: Can't go to state resetting_mib", log.Fields{"device-id": dh.deviceID, "err": err})
 					return fmt.Errorf("can't go to state resetting_mib: %s", dh.deviceID)
 				}
 			} else {
 				if err := pMibUlFsm.Event(ulEvExamineMds); err != nil {
-					logger.Errorw("MibSyncFsm: Can't go to state examine_mds", log.Fields{"deviceId": dh.deviceID, "err": err})
+					logger.Errorw("MibSyncFsm: Can't go to state examine_mds", log.Fields{"device-id": dh.deviceID, "err": err})
 					return fmt.Errorf("can't go to examine_mds: %s", dh.deviceID)
 				}
 				logger.Debugw("state of MibSyncFsm", log.Fields{"state": string(pMibUlFsm.Current())})
@@ -1221,7 +1312,7 @@
 			}
 		} else {
 			logger.Errorw("wrong state of MibSyncFsm - want: disabled", log.Fields{"have": string(pMibUlFsm.Current()),
-				"deviceId": dh.deviceID})
+				"device-id": dh.deviceID})
 			return fmt.Errorf("wrong state of MibSyncFsm: %s", dh.deviceID)
 		}
 	} else {
@@ -1330,8 +1421,6 @@
 			_ = dh.pOnuTP.pAniConfigFsm.pAdaptFsm.pFsm.Event(aniEvReset)
 		}
 		for _, uniPort := range dh.uniEntityMap {
-			//reset the TechProfileConfig Done state for all (active) UNI's
-			dh.pOnuTP.setConfigDone(uniPort.uniID, false)
 			// reset the possibly existing VlanConfigFsm
 			if pVlanFilterFsm, exist := dh.UniVlanConfigFsmMap[uniPort.uniID]; exist {
 				//VlanFilterFsm exists and was already started
@@ -1355,7 +1444,7 @@
 			logger.Errorw("error-DeviceReasonUpdate to 'mibsync-complete'", log.Fields{
 				"device-id": dh.deviceID, "error": err})
 		} else {
-			logger.Infow("dev reason updated to 'MibSync complete'", log.Fields{"deviceID": dh.deviceID})
+			logger.Infow("dev reason updated to 'MibSync complete'", log.Fields{"device-id": dh.deviceID})
 		}
 	} else {
 		logger.Debugw("reconciling - don't notify core about DeviceReasonUpdate to mibsync-complete",
@@ -1414,13 +1503,13 @@
 	if pMibDlFsm != nil {
 		if pMibDlFsm.Is(dlStDisabled) {
 			if err := pMibDlFsm.Event(dlEvStart); err != nil {
-				logger.Errorw("MibDownloadFsm: Can't go to state starting", log.Fields{"deviceId": dh.deviceID, "err": err})
+				logger.Errorw("MibDownloadFsm: Can't go to state starting", log.Fields{"device-id": dh.deviceID, "err": err})
 				// maybe try a FSM reset and then again ... - TODO!!!
 			} else {
 				logger.Debugw("MibDownloadFsm", log.Fields{"state": string(pMibDlFsm.Current())})
 				// maybe use more specific states here for the specific download steps ...
 				if err := pMibDlFsm.Event(dlEvCreateGal); err != nil {
-					logger.Errorw("MibDownloadFsm: Can't start CreateGal", log.Fields{"deviceId": dh.deviceID, "err": err})
+					logger.Errorw("MibDownloadFsm: Can't start CreateGal", log.Fields{"device-id": dh.deviceID, "err": err})
 				} else {
 					logger.Debugw("state of MibDownloadFsm", log.Fields{"state": string(pMibDlFsm.Current())})
 					//Begin MIB data download (running autonomously)
@@ -1428,7 +1517,7 @@
 			}
 		} else {
 			logger.Errorw("wrong state of MibDownloadFsm - want: disabled", log.Fields{"have": string(pMibDlFsm.Current()),
-				"deviceId": dh.deviceID})
+				"device-id": dh.deviceID})
 			// maybe try a FSM reset and then again ... - TODO!!!
 		}
 		/***** Mib download started */
@@ -1520,7 +1609,6 @@
 		return
 	}
 	_ = pDevEntry.stop(context.TODO(), true) //stop deviceEntry with omciCC reset
-	//maybe some more sophisticated context treatment should be used here?
 }
 
 func (dh *deviceHandler) processUniEnableStateDoneEvent(devEvent OnuDeviceEvent) {
@@ -1735,7 +1823,7 @@
 	eventContext["device_id"] = aDeviceID
 	eventContext["registration_id"] = aDeviceID //py: string(device_id)??
 	logger.Debugw("prepare ONU_ACTIVATED event",
-		log.Fields{"DeviceId": aDeviceID, "EventContext": eventContext})
+		log.Fields{"device-id": aDeviceID, "EventContext": eventContext})
 
 	/* Populating device event body */
 	de.Context = eventContext
@@ -1853,23 +1941,24 @@
 		switch field.Type {
 		case of.OxmOfbFieldTypes_OFPXMT_OFB_ETH_TYPE:
 			{
-				logger.Debugw("FlowAdd type EthType", log.Fields{"device-id": dh.deviceID,
+				logger.Debugw("flow type EthType", log.Fields{"device-id": dh.deviceID,
 					"EthType": strconv.FormatInt(int64(field.GetEthType()), 16)})
 			}
+		/* TT related temporary workaround - should not be needed anymore
 		case of.OxmOfbFieldTypes_OFPXMT_OFB_IP_PROTO:
 			{
 				*loIPProto = field.GetIpProto()
-				logger.Debugw("FlowAdd type IpProto", log.Fields{"device-id": dh.deviceID,
+				logger.Debugw("flow type IpProto", log.Fields{"device-id": dh.deviceID,
 					"IpProto": strconv.FormatInt(int64(*loIPProto), 16)})
 				if *loIPProto == 2 {
 					// some workaround for TT workflow at proto == 2 (IGMP trap) -> ignore the flow
 					// avoids installing invalid EVTOCD rule
-					logger.Debugw("FlowAdd type IpProto 2: TT workaround: ignore flow",
-						log.Fields{"device-id": dh.deviceID,
-							"IpProto": strconv.FormatInt(int64(*loIPProto), 16)})
+					logger.Debugw("flow type IpProto 2: TT workaround: ignore flow",
+						log.Fields{"device-id": dh.deviceID})
 					return
 				}
 			}
+		*/
 		case of.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID:
 			{
 				*loMatchVlan = uint16(field.GetVlanVid())
@@ -1878,38 +1967,38 @@
 					loMatchVlanMask == uint16(of.OfpVlanId_OFPVID_PRESENT)) {
 					*loMatchVlan = *loMatchVlan & 0xFFF // not transparent: copy only ID bits
 				}
-				logger.Debugw("FlowAdd field type", log.Fields{"device-id": dh.deviceID,
+				logger.Debugw("flow field type", log.Fields{"device-id": dh.deviceID,
 					"VID": strconv.FormatInt(int64(*loMatchVlan), 16)})
 			}
 		case of.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_PCP:
 			{
 				*loAddPcp = uint8(field.GetVlanPcp())
-				logger.Debugw("FlowAdd field type", log.Fields{"device-id": dh.deviceID,
+				logger.Debugw("flow field type", log.Fields{"device-id": dh.deviceID,
 					"PCP": loAddPcp})
 			}
 		case of.OxmOfbFieldTypes_OFPXMT_OFB_UDP_DST:
 			{
-				logger.Debugw("FlowAdd field type", log.Fields{"device-id": dh.deviceID,
+				logger.Debugw("flow field type", log.Fields{"device-id": dh.deviceID,
 					"UDP-DST": strconv.FormatInt(int64(field.GetUdpDst()), 16)})
 			}
 		case of.OxmOfbFieldTypes_OFPXMT_OFB_UDP_SRC:
 			{
-				logger.Debugw("FlowAdd field type", log.Fields{"device-id": dh.deviceID,
+				logger.Debugw("flow field type", log.Fields{"device-id": dh.deviceID,
 					"UDP-SRC": strconv.FormatInt(int64(field.GetUdpSrc()), 16)})
 			}
 		case of.OxmOfbFieldTypes_OFPXMT_OFB_IPV4_DST:
 			{
-				logger.Debugw("FlowAdd field type", log.Fields{"device-id": dh.deviceID,
+				logger.Debugw("flow field type", log.Fields{"device-id": dh.deviceID,
 					"IPv4-DST": field.GetIpv4Dst()})
 			}
 		case of.OxmOfbFieldTypes_OFPXMT_OFB_IPV4_SRC:
 			{
-				logger.Debugw("FlowAdd field type", log.Fields{"device-id": dh.deviceID,
+				logger.Debugw("flow field type", log.Fields{"device-id": dh.deviceID,
 					"IPv4-SRC": field.GetIpv4Src()})
 			}
 		case of.OxmOfbFieldTypes_OFPXMT_OFB_METADATA:
 			{
-				logger.Debugw("FlowAdd field type", log.Fields{"device-id": dh.deviceID,
+				logger.Debugw("flow field type", log.Fields{"device-id": dh.deviceID,
 					"Metadata": field.GetTableMetadata()})
 			}
 			/*
@@ -1928,32 +2017,32 @@
 		/* not used:
 		case of.OfpActionType_OFPAT_OUTPUT:
 			{
-				logger.Debugw("FlowAdd action type", log.Fields{"device-id": dh.deviceID,
+				logger.Debugw("flow action type", log.Fields{"device-id": dh.deviceID,
 					"Output": action.GetOutput()})
 			}
 		*/
 		case of.OfpActionType_OFPAT_PUSH_VLAN:
 			{
-				logger.Debugw("FlowAdd action type", log.Fields{"device-id": dh.deviceID,
+				logger.Debugw("flow action type", log.Fields{"device-id": dh.deviceID,
 					"PushEthType": strconv.FormatInt(int64(action.GetPush().Ethertype), 16)})
 			}
 		case of.OfpActionType_OFPAT_SET_FIELD:
 			{
 				pActionSetField := action.GetSetField()
 				if pActionSetField.Field.OxmClass != of.OfpOxmClass_OFPXMC_OPENFLOW_BASIC {
-					logger.Warnw("FlowAdd action SetField invalid OxmClass (ignored)", log.Fields{"device-id": dh.deviceID,
+					logger.Warnw("flow action SetField invalid OxmClass (ignored)", log.Fields{"device-id": dh.deviceID,
 						"OxcmClass": pActionSetField.Field.OxmClass})
 				}
 				if pActionSetField.Field.GetOfbField().Type == of.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID {
 					*loSetVlan = uint16(pActionSetField.Field.GetOfbField().GetVlanVid())
-					logger.Debugw("FlowAdd Set VLAN from SetField action", log.Fields{"device-id": dh.deviceID,
+					logger.Debugw("flow Set VLAN from SetField action", log.Fields{"device-id": dh.deviceID,
 						"SetVlan": strconv.FormatInt(int64(*loSetVlan), 16)})
 				} else if pActionSetField.Field.GetOfbField().Type == of.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_PCP {
 					*loSetPcp = uint8(pActionSetField.Field.GetOfbField().GetVlanPcp())
-					logger.Debugw("FlowAdd Set PCP from SetField action", log.Fields{"device-id": dh.deviceID,
+					logger.Debugw("flow Set PCP from SetField action", log.Fields{"device-id": dh.deviceID,
 						"SetPcp": *loSetPcp})
 				} else {
-					logger.Warnw("FlowAdd action SetField invalid FieldType", log.Fields{"device-id": dh.deviceID,
+					logger.Warnw("flow action SetField invalid FieldType", log.Fields{"device-id": dh.deviceID,
 						"Type": pActionSetField.Field.GetOfbField().Type})
 				}
 			}
@@ -1985,35 +2074,39 @@
 
 	metadata := flow.GetMetadataFromWriteMetadataAction(apFlowItem)
 	if metadata == 0 {
-		logger.Debugw("FlowAdd invalid metadata - abort",
+		logger.Debugw("flow-add invalid metadata - abort",
 			log.Fields{"device-id": dh.deviceID})
-		return fmt.Errorf("flowAdd invalid metadata: %s", dh.deviceID)
+		return fmt.Errorf("flow-add invalid metadata: %s", dh.deviceID)
 	}
 	loTpID := flow.GetTechProfileIDFromWriteMetaData(metadata)
-	logger.Debugw("FlowAdd TechProfileId", log.Fields{"device-id": dh.deviceID, "TP-Id": loTpID})
+	loCookie := apFlowItem.GetCookie()
+	loCookieSlice := []uint64{loCookie}
+	logger.Debugw("flow-add base indications", log.Fields{"device-id": dh.deviceID,
+		"TechProf-Id": loTpID, "cookie": loCookie})
 
 	dh.getFlowOfbFields(apFlowItem, &loMatchVlan, &loAddPcp, &loIPProto)
+	/* TT related temporary workaround - should not be needed anymore
 	if loIPProto == 2 {
 		// some workaround for TT workflow at proto == 2 (IGMP trap) -> ignore the flow
 		// avoids installing invalid EVTOCD rule
-		logger.Debugw("FlowAdd type IpProto 2: TT workaround: ignore flow",
-			log.Fields{"device-id": dh.deviceID,
-				"IpProto": strconv.FormatInt(int64(loIPProto), 16)})
+		logger.Debugw("flow-add type IpProto 2: TT workaround: ignore flow",
+			log.Fields{"device-id": dh.deviceID})
 		return nil
 	}
+	*/
 	dh.getFlowActions(apFlowItem, &loSetPcp, &loSetVlan)
 
 	if loSetVlan == uint16(of.OfpVlanId_OFPVID_NONE) && loMatchVlan != uint16(of.OfpVlanId_OFPVID_PRESENT) {
-		logger.Errorw("FlowAdd aborted - SetVlanId undefined, but MatchVid set", log.Fields{
+		logger.Errorw("flow-add aborted - SetVlanId undefined, but MatchVid set", log.Fields{
 			"device-id": dh.deviceID, "UniPort": apUniPort.portNo,
 			"set_vid":   strconv.FormatInt(int64(loSetVlan), 16),
 			"match_vid": strconv.FormatInt(int64(loMatchVlan), 16)})
 		//TODO!!: Use DeviceId within the error response to rwCore
 		//  likewise also in other error response cases to calling components as requested in [VOL-3458]
-		return fmt.Errorf("flowAdd Set/Match VlanId inconsistent: %s", dh.deviceID)
+		return fmt.Errorf("flow-add Set/Match VlanId inconsistent: %s", dh.deviceID)
 	}
 	if loSetVlan == uint16(of.OfpVlanId_OFPVID_NONE) && loMatchVlan == uint16(of.OfpVlanId_OFPVID_PRESENT) {
-		logger.Debugw("FlowAdd vlan-any/copy", log.Fields{"device-id": dh.deviceID})
+		logger.Debugw("flow-add vlan-any/copy", log.Fields{"device-id": dh.deviceID})
 		loSetVlan = loMatchVlan //both 'transparent' (copy any)
 	} else {
 		//looks like OMCI value 4097 (copyFromOuter - for Uni double tagged) is not supported here
@@ -2021,18 +2114,57 @@
 			// not set to transparent
 			loSetVlan &= 0x0FFF //mask VID bits as prerequisite for vlanConfigFsm
 		}
-		logger.Debugw("FlowAdd vlan-set", log.Fields{"device-id": dh.deviceID})
+		logger.Debugw("flow-add vlan-set", log.Fields{"device-id": dh.deviceID})
 	}
 	if _, exist := dh.UniVlanConfigFsmMap[apUniPort.uniID]; exist {
-		return dh.UniVlanConfigFsmMap[apUniPort.uniID].SetUniFlowParams(loTpID, loMatchVlan, loSetVlan, loSetPcp)
+		return dh.UniVlanConfigFsmMap[apUniPort.uniID].SetUniFlowParams(loTpID, loCookieSlice,
+			loMatchVlan, loSetVlan, loSetPcp)
 	}
-	return dh.createVlanFilterFsm(apUniPort,
-		loTpID, loMatchVlan, loSetVlan, loSetPcp, OmciVlanFilterDone)
+	return dh.createVlanFilterFsm(apUniPort, loTpID, loCookieSlice,
+		loMatchVlan, loSetVlan, loSetPcp, OmciVlanFilterDone)
+}
+
+//removeFlowItemFromUniPort parses the actual flow item to remove it from the UniPort
+func (dh *deviceHandler) removeFlowItemFromUniPort(apFlowItem *ofp.OfpFlowStats, apUniPort *onuUniPort) error {
+	//optimization and assumption: the flow cookie uniquely identifies the flow and with that the internal rule
+	//hence only the cookie is used here to find the relevant flow and possibly remove the rule
+	//no extra check is done on the rule parameters
+	//accordingly the removal is done only once - for the first found flow with that cookie, even though
+	// at flow creation is not assured, that the same cookie is not configured for different flows - just assumed
+	//additionally it is assumed here, that removal can only be done for one cookie per flow in a sequence (different
+	// from addFlow - where at reconcilement multiple cookies per flow ) can be configured in one sequence)
+	// - some possible 'delete-all' sequence would have be implemented separately (where the cookies are don't care anyway)
+	loCookie := apFlowItem.GetCookie()
+	logger.Debugw("flow-remove base indications", log.Fields{"device-id": dh.deviceID, "cookie": loCookie})
+
+	/* TT related temporary workaround - should not be needed anymore
+	for _, field := range flow.GetOfbFields(apFlowItem) {
+		if field.Type == of.OxmOfbFieldTypes_OFPXMT_OFB_IP_PROTO {
+			loIPProto := field.GetIpProto()
+			logger.Debugw("flow type IpProto", log.Fields{"device-id": dh.deviceID,
+				"IpProto": strconv.FormatInt(int64(loIPProto), 16)})
+			if loIPProto == 2 {
+				// some workaround for TT workflow on proto == 2 (IGMP trap) -> the flow was not added, no need to remove
+				logger.Debugw("flow-remove type IpProto 2: TT workaround: ignore flow",
+					log.Fields{"device-id": dh.deviceID})
+				return nil
+			}
+		}
+	} //for all OfbFields
+	*/
+
+	if _, exist := dh.UniVlanConfigFsmMap[apUniPort.uniID]; exist {
+		return dh.UniVlanConfigFsmMap[apUniPort.uniID].RemoveUniFlowParams(loCookie)
+	}
+	logger.Warnw("flow-remove called, but no flow is configured (no VlanConfigFsm)",
+		log.Fields{"device-id": dh.deviceID})
+	//but as we regard the flow as not existing = removed we respond just ok
+	return nil
 }
 
 // createVlanFilterFsm initializes and runs the VlanFilter FSM to transfer OMCI related VLAN config
-func (dh *deviceHandler) createVlanFilterFsm(apUniPort *onuUniPort,
-	aTpID uint16, aMatchVlan uint16, aSetVlan uint16, aSetPcp uint8, aDevEvent OnuDeviceEvent) error {
+func (dh *deviceHandler) createVlanFilterFsm(apUniPort *onuUniPort, aTpID uint16, aCookieSlice []uint64,
+	aMatchVlan uint16, aSetVlan uint16, aSetPcp uint8, aDevEvent OnuDeviceEvent) error {
 	chVlanFilterFsm := make(chan Message, 2048)
 
 	pDevEntry := dh.getOnuDeviceEntry(true)
@@ -2042,8 +2174,8 @@
 	}
 
 	pVlanFilterFsm := NewUniVlanConfigFsm(dh, pDevEntry.PDevOmciCC, apUniPort, dh.pOnuTP,
-		pDevEntry.pOnuDB, aTpID, aDevEvent, "UniVlanConfigFsm", dh.deviceID, chVlanFilterFsm,
-		dh.pOpenOnuAc.AcceptIncrementalEvto, aMatchVlan, aSetVlan, aSetPcp)
+		pDevEntry.pOnuDB, aTpID, aDevEvent, "UniVlanConfigFsm", chVlanFilterFsm,
+		dh.pOpenOnuAc.AcceptIncrementalEvto, aCookieSlice, aMatchVlan, aSetVlan, aSetPcp)
 	if pVlanFilterFsm != nil {
 		dh.UniVlanConfigFsmMap[apUniPort.uniID] = pVlanFilterFsm
 		pVlanFilterStatemachine := pVlanFilterFsm.pAdaptFsm.pFsm
@@ -2145,16 +2277,16 @@
 	wg.Add(1) // for the 1 go routine to finish
 
 	go pDevEntry.updateOnuKvStore(dctx, &wg)
-	dh.waitForCompletion(cancel, &wg) //wait for background process to finish
+	dh.waitForCompletion(cancel, &wg, "UpdateKvStore") //wait for background process to finish
 
 	return pDevEntry.getKvProcessingErrorIndication()
 }
 
-func (dh *deviceHandler) waitForCompletion(cancel context.CancelFunc, wg *sync.WaitGroup) {
+func (dh *deviceHandler) waitForCompletion(cancel context.CancelFunc, wg *sync.WaitGroup, aCallerIdent string) {
 	defer cancel() //ensure termination of context (may be pro forma)
 	wg.Wait()
-	logger.Debug("WaitGroup processing completed")
-
+	logger.Debugw("WaitGroup processing completed", log.Fields{
+		"device-id": dh.deviceID, "called from": aCallerIdent})
 }
 
 func (dh *deviceHandler) combineErrorStrings(errS ...error) error {
diff --git a/internal/pkg/onuadaptercore/omci_ani_config.go b/internal/pkg/onuadaptercore/omci_ani_config.go
index 4669751..70f172a 100644
--- a/internal/pkg/onuadaptercore/omci_ani_config.go
+++ b/internal/pkg/onuadaptercore/omci_ani_config.go
@@ -76,6 +76,8 @@
 
 //uniPonAniConfigFsm defines the structure for the state machine to config the PON ANI ports of ONU UNI ports via OMCI
 type uniPonAniConfigFsm struct {
+	pDeviceHandler           *deviceHandler
+	deviceID                 string
 	pOmciCC                  *omciCC
 	pOnuUniPort              *onuUniPort
 	pUniTechProf             *onuUniTechProf
@@ -84,7 +86,6 @@
 	requestEvent             OnuDeviceEvent
 	omciMIdsResponseReceived chan bool //separate channel needed for checking multiInstance OMCI message responses
 	pAdaptFsm                *AdapterFsm
-	aniConfigCompleted       bool
 	chSuccess                chan<- uint8
 	procStep                 uint8
 	chanSet                  bool
@@ -93,26 +94,28 @@
 	tcont0ID                 uint16
 	alloc0ID                 uint16
 	gemPortAttribsSlice      []ponAniGemPortAttribs
+	pLastTxMeInstance        *me.ManagedEntity
 }
 
 //newUniPonAniConfigFsm is the 'constructor' for the state machine to config the PON ANI ports of ONU UNI ports via OMCI
 func newUniPonAniConfigFsm(apDevOmciCC *omciCC, apUniPort *onuUniPort, apUniTechProf *onuUniTechProf,
 	apOnuDB *onuDeviceDB, aTechProfileID uint16, aRequestEvent OnuDeviceEvent, aName string,
-	aDeviceID string, aCommChannel chan Message) *uniPonAniConfigFsm {
+	apDeviceHandler *deviceHandler, aCommChannel chan Message) *uniPonAniConfigFsm {
 	instFsm := &uniPonAniConfigFsm{
-		pOmciCC:            apDevOmciCC,
-		pOnuUniPort:        apUniPort,
-		pUniTechProf:       apUniTechProf,
-		pOnuDB:             apOnuDB,
-		techProfileID:      aTechProfileID,
-		requestEvent:       aRequestEvent,
-		aniConfigCompleted: false,
-		chanSet:            false,
+		pDeviceHandler: apDeviceHandler,
+		deviceID:       apDeviceHandler.deviceID,
+		pOmciCC:        apDevOmciCC,
+		pOnuUniPort:    apUniPort,
+		pUniTechProf:   apUniTechProf,
+		pOnuDB:         apOnuDB,
+		techProfileID:  aTechProfileID,
+		requestEvent:   aRequestEvent,
+		chanSet:        false,
 	}
-	instFsm.pAdaptFsm = NewAdapterFsm(aName, aDeviceID, aCommChannel)
+	instFsm.pAdaptFsm = NewAdapterFsm(aName, instFsm.deviceID, aCommChannel)
 	if instFsm.pAdaptFsm == nil {
 		logger.Errorw("uniPonAniConfigFsm's AdapterFsm could not be instantiated!!", log.Fields{
-			"device-id": aDeviceID})
+			"device-id": instFsm.deviceID})
 		return nil
 	}
 
@@ -165,11 +168,11 @@
 	)
 	if instFsm.pAdaptFsm.pFsm == nil {
 		logger.Errorw("uniPonAniConfigFsm's Base FSM could not be instantiated!!", log.Fields{
-			"device-id": aDeviceID})
+			"device-id": instFsm.deviceID})
 		return nil
 	}
 
-	logger.Infow("uniPonAniConfigFsm created", log.Fields{"device-id": aDeviceID})
+	logger.Infow("uniPonAniConfigFsm created", log.Fields{"device-id": instFsm.deviceID})
 	return instFsm
 }
 
@@ -197,9 +200,9 @@
 		if tcontInstKeys := oFsm.pOnuDB.getSortedInstKeys(me.TContClassID); len(tcontInstKeys) > 0 {
 			oFsm.tcont0ID = tcontInstKeys[0]
 			logger.Debugw("Used TcontId:", log.Fields{"TcontId": strconv.FormatInt(int64(oFsm.tcont0ID), 16),
-				"device-id": oFsm.pAdaptFsm.deviceID})
+				"device-id": oFsm.deviceID})
 		} else {
-			logger.Warnw("No TCont instances found", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+			logger.Warnw("No TCont instances found", log.Fields{"device-id": oFsm.deviceID})
 		}
 		oFsm.alloc0ID = (*(oFsm.pUniTechProf.mapPonAniConfig[oFsm.pOnuUniPort.uniID]))[0].tcontParams.allocID
 		loGemPortAttribs := ponAniGemPortAttribs{}
@@ -232,30 +235,30 @@
 								if relatedPort == usQrelPortMask {
 									loGemPortAttribs.upQueueID = mgmtEntityID
 									logger.Debugw("UpQueue for GemPort found:", log.Fields{"gemPortID": loGemPortAttribs.gemPortID,
-										"upQueueID": strconv.FormatInt(int64(loGemPortAttribs.upQueueID), 16), "device-id": oFsm.pAdaptFsm.deviceID})
+										"upQueueID": strconv.FormatInt(int64(loGemPortAttribs.upQueueID), 16), "device-id": oFsm.deviceID})
 									usQueueFound = true
 								} else if (relatedPort&0xFFFFFF) == dsQrelPortMask && mgmtEntityID < 0x8000 {
 									loGemPortAttribs.downQueueID = mgmtEntityID
 									logger.Debugw("DownQueue for GemPort found:", log.Fields{"gemPortID": loGemPortAttribs.gemPortID,
-										"downQueueID": strconv.FormatInt(int64(loGemPortAttribs.downQueueID), 16), "device-id": oFsm.pAdaptFsm.deviceID})
+										"downQueueID": strconv.FormatInt(int64(loGemPortAttribs.downQueueID), 16), "device-id": oFsm.deviceID})
 									dsQueueFound = true
 								}
 								if usQueueFound && dsQueueFound {
 									break
 								}
 							} else {
-								logger.Warnw("Could not convert attribute value", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+								logger.Warnw("Could not convert attribute value", log.Fields{"device-id": oFsm.deviceID})
 							}
 						} else {
-							logger.Warnw("'RelatedPort' not found in meAttributes:", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+							logger.Warnw("'RelatedPort' not found in meAttributes:", log.Fields{"device-id": oFsm.deviceID})
 						}
 					} else {
 						logger.Warnw("No attributes available in DB:", log.Fields{"meClassID": me.PriorityQueueClassID,
-							"mgmtEntityID": mgmtEntityID, "device-id": oFsm.pAdaptFsm.deviceID})
+							"mgmtEntityID": mgmtEntityID, "device-id": oFsm.deviceID})
 					}
 				}
 			} else {
-				logger.Warnw("No PriorityQueue instances found", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+				logger.Warnw("No PriorityQueue instances found", log.Fields{"device-id": oFsm.deviceID})
 			}
 			loGemPortAttribs.direction = gemEntry.direction
 			loGemPortAttribs.qosPolicy = gemEntry.queueSchedPolicy
@@ -278,7 +281,7 @@
 
 func (oFsm *uniPonAniConfigFsm) enterConfigStartingState(e *fsm.Event) {
 	logger.Debugw("UniPonAniConfigFsm start", log.Fields{"in state": e.FSM.Current(),
-		"device-id": oFsm.pAdaptFsm.deviceID})
+		"device-id": oFsm.deviceID})
 	// in case the used channel is not yet defined (can be re-used after restarts)
 	if oFsm.omciMIdsResponseReceived == nil {
 		oFsm.omciMIdsResponseReceived = make(chan bool)
@@ -309,19 +312,19 @@
 func (oFsm *uniPonAniConfigFsm) enterCreatingDot1PMapper(e *fsm.Event) {
 	logger.Debugw("uniPonAniConfigFsm Tx Create::Dot1PMapper", log.Fields{
 		"EntitytId": strconv.FormatInt(int64(oFsm.mapperSP0ID), 16),
-		"in state":  e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
+		"in state":  e.FSM.Current(), "device-id": oFsm.deviceID})
 	meInstance := oFsm.pOmciCC.sendCreateDot1PMapper(context.TODO(), ConstDefaultOmciTimeout, true,
 		oFsm.mapperSP0ID, oFsm.pAdaptFsm.commChan)
 	//accept also nil as (error) return value for writing to LastTx
 	//  - this avoids misinterpretation of new received OMCI messages
-	oFsm.pOmciCC.pLastTxMeInstance = meInstance
+	oFsm.pLastTxMeInstance = meInstance
 }
 
 func (oFsm *uniPonAniConfigFsm) enterCreatingMBPCD(e *fsm.Event) {
 	logger.Debugw("uniPonAniConfigFsm Tx Create::MBPCD", log.Fields{
 		"EntitytId": strconv.FormatInt(int64(oFsm.macBPCD0ID), 16),
 		"TPPtr":     strconv.FormatInt(int64(oFsm.mapperSP0ID), 16),
-		"in state":  e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
+		"in state":  e.FSM.Current(), "device-id": oFsm.deviceID})
 	bridgePtr := macBridgeServiceProfileEID + uint16(oFsm.pOnuUniPort.macBpNo) //cmp also omci_cc.go::sendCreateMBServiceProfile
 	meParams := me.ParamData{
 		EntityID: oFsm.macBPCD0ID,
@@ -336,7 +339,7 @@
 		oFsm.pAdaptFsm.commChan, meParams)
 	//accept also nil as (error) return value for writing to LastTx
 	//  - this avoids misinterpretation of new received OMCI messages
-	oFsm.pOmciCC.pLastTxMeInstance = meInstance
+	oFsm.pLastTxMeInstance = meInstance
 
 }
 
@@ -344,7 +347,7 @@
 	logger.Debugw("uniPonAniConfigFsm Tx Set::Tcont", log.Fields{
 		"EntitytId": strconv.FormatInt(int64(oFsm.tcont0ID), 16),
 		"AllocId":   strconv.FormatInt(int64(oFsm.alloc0ID), 16),
-		"in state":  e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
+		"in state":  e.FSM.Current(), "device-id": oFsm.deviceID})
 	meParams := me.ParamData{
 		EntityID: oFsm.tcont0ID,
 		Attributes: me.AttributeValueMap{
@@ -355,34 +358,34 @@
 		oFsm.pAdaptFsm.commChan, meParams)
 	//accept also nil as (error) return value for writing to LastTx
 	//  - this avoids misinterpretation of new received OMCI messages
-	oFsm.pOmciCC.pLastTxMeInstance = meInstance
+	oFsm.pLastTxMeInstance = meInstance
 }
 
 func (oFsm *uniPonAniConfigFsm) enterCreatingGemNCTPs(e *fsm.Event) {
 	logger.Debugw("uniPonAniConfigFsm - start creating GemNWCtp loop", log.Fields{
-		"in state": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
+		"in state": e.FSM.Current(), "device-id": oFsm.deviceID})
 	go oFsm.performCreatingGemNCTPs()
 }
 
 func (oFsm *uniPonAniConfigFsm) enterCreatingGemIWs(e *fsm.Event) {
 	logger.Debugw("uniPonAniConfigFsm - start creating GemIwTP loop", log.Fields{
-		"in state": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
+		"in state": e.FSM.Current(), "device-id": oFsm.deviceID})
 	go oFsm.performCreatingGemIWs()
 }
 
 func (oFsm *uniPonAniConfigFsm) enterSettingPQs(e *fsm.Event) {
 	logger.Debugw("uniPonAniConfigFsm - start setting PrioQueue loop", log.Fields{
-		"in state": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
+		"in state": e.FSM.Current(), "device-id": oFsm.deviceID})
 	go oFsm.performSettingPQs()
 }
 
 func (oFsm *uniPonAniConfigFsm) enterSettingDot1PMapper(e *fsm.Event) {
 	logger.Debugw("uniPonAniConfigFsm Tx Set::.1pMapper with all PBits set", log.Fields{"EntitytId": 0x8042, /*cmp above*/
-		"toGemIw": 1024 /* cmp above */, "in state": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
+		"toGemIw": 1024 /* cmp above */, "in state": e.FSM.Current(), "device-id": oFsm.deviceID})
 
 	logger.Debugw("uniPonAniConfigFsm Tx Set::1pMapper", log.Fields{
 		"EntitytId": strconv.FormatInt(int64(oFsm.mapperSP0ID), 16),
-		"in state":  e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
+		"in state":  e.FSM.Current(), "device-id": oFsm.deviceID})
 
 	meParams := me.ParamData{
 		EntityID:   oFsm.mapperSP0ID,
@@ -400,13 +403,13 @@
 						loPrioGemPortArray[i] = gemPortAttribs.gemPortID //gemPortId=EntityID and unique
 					} else {
 						logger.Warnw("uniPonAniConfigFsm PrioString not unique", log.Fields{
-							"device-id": oFsm.pAdaptFsm.deviceID, "IgnoredGemPort": gemPortAttribs.gemPortID,
+							"device-id": oFsm.deviceID, "IgnoredGemPort": gemPortAttribs.gemPortID,
 							"SetGemPort": loPrioGemPortArray[i]})
 					}
 				}
 			} else {
 				logger.Warnw("uniPonAniConfigFsm PrioString evaluation error", log.Fields{
-					"device-id": oFsm.pAdaptFsm.deviceID, "GemPort": gemPortAttribs.gemPortID,
+					"device-id": oFsm.deviceID, "GemPort": gemPortAttribs.gemPortID,
 					"prioString": gemPortAttribs.pbitString, "position": i})
 			}
 
@@ -417,16 +420,17 @@
 		if value != 0 {
 			foundIwPtr = true
 			meAttribute := fmt.Sprintf("InterworkTpPointerForPBitPriority%d", index)
-			logger.Debugf("UniPonAniConfigFsm Set::1pMapper", log.Fields{
-				"IwPtr for Prio%d": strconv.FormatInt(int64(value), 16), "device-id": oFsm.pAdaptFsm.deviceID}, index)
 			meParams.Attributes[meAttribute] = value
-
+			logger.Debugw("UniPonAniConfigFsm Set::1pMapper", log.Fields{
+				"for Prio":  index,
+				"IwPtr":     strconv.FormatInt(int64(value), 16),
+				"device-id": oFsm.deviceID})
 		}
 	}
 
 	if !foundIwPtr {
 		logger.Errorw("UniPonAniConfigFsm no GemIwPtr found for .1pMapper - abort", log.Fields{
-			"device-id": oFsm.pAdaptFsm.deviceID})
+			"device-id": oFsm.deviceID})
 		//let's reset the state machine in order to release all resources now
 		pConfigAniStateAFsm := oFsm.pAdaptFsm
 		if pConfigAniStateAFsm != nil {
@@ -443,27 +447,32 @@
 		oFsm.pAdaptFsm.commChan, meParams)
 	//accept also nil as (error) return value for writing to LastTx
 	//  - this avoids misinterpretation of new received OMCI messages
-	oFsm.pOmciCC.pLastTxMeInstance = meInstance
+	oFsm.pLastTxMeInstance = meInstance
 }
 
 func (oFsm *uniPonAniConfigFsm) enterAniConfigDone(e *fsm.Event) {
+	logger.Debugw("uniPonAniConfigFsm send dh event notification recheck pending flow config", log.Fields{
+		"from_State": e.FSM.Current(), "device-id": oFsm.deviceID})
+	//use DeviceHandler event notification directly
+	oFsm.pDeviceHandler.deviceProcStatusUpdate(oFsm.requestEvent)
+	//store that the UNI related techProfile processing is done for the given Profile and Uni
+	oFsm.pUniTechProf.setConfigDone(oFsm.pOnuUniPort.uniID, true)
+	//if techProfile processing is done it must be checked, if some prior/parallel flow configuration is pending
+	go oFsm.pDeviceHandler.verifyUniVlanConfigRequest(oFsm.pOnuUniPort)
 
-	oFsm.aniConfigCompleted = true
-
-	//let's reset the state machine in order to release all resources now
-	pConfigAniStateAFsm := oFsm.pAdaptFsm
-	if pConfigAniStateAFsm != nil {
-		// obviously calling some FSM event here directly does not work - so trying to decouple it ...
-		go func(aPAFsm *AdapterFsm) {
-			if aPAFsm != nil && aPAFsm.pFsm != nil {
-				_ = aPAFsm.pFsm.Event(aniEvReset)
-			}
-		}(pConfigAniStateAFsm)
+	if oFsm.chanSet {
+		// indicate processing done to the caller
+		logger.Debugw("uniPonAniConfigFsm processingDone on channel", log.Fields{
+			"ProcessingStep": oFsm.procStep, "from_State": e.FSM.Current(), "device-id": oFsm.deviceID})
+		oFsm.chSuccess <- oFsm.procStep
+		oFsm.chanSet = false //reset the internal channel state
 	}
+
+	//the FSM is left active in this state as long as no specific reset or remove is requested from outside
 }
 
 func (oFsm *uniPonAniConfigFsm) enterResettingState(e *fsm.Event) {
-	logger.Debugw("uniPonAniConfigFsm resetting", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+	logger.Debugw("uniPonAniConfigFsm resetting", log.Fields{"device-id": oFsm.deviceID})
 
 	pConfigAniStateAFsm := oFsm.pAdaptFsm
 	if pConfigAniStateAFsm != nil {
@@ -486,90 +495,73 @@
 }
 
 func (oFsm *uniPonAniConfigFsm) enterDisabledState(e *fsm.Event) {
-	logger.Debugw("uniPonAniConfigFsm enters disabled state", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+	logger.Debugw("uniPonAniConfigFsm enters disabled state", log.Fields{"device-id": oFsm.deviceID})
+	oFsm.pLastTxMeInstance = nil
 
-	if oFsm.aniConfigCompleted {
-		logger.Debugw("uniPonAniConfigFsm send dh event notification", log.Fields{
-			"from_State": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
-		//use DeviceHandler event notification directly
-		oFsm.pOmciCC.pBaseDeviceHandler.deviceProcStatusUpdate(oFsm.requestEvent)
-		oFsm.aniConfigCompleted = false
-	}
-	//store that the UNI related techProfile processing is done for the given Profile and Uni
-	oFsm.pUniTechProf.setConfigDone(oFsm.pOnuUniPort.uniID, true)
-	//if techProfile processing is done it must be checked, if some prior/parallel flow configuration is pending
-	go oFsm.pOmciCC.pBaseDeviceHandler.verifyUniVlanConfigRequest(oFsm.pOnuUniPort)
-
-	if oFsm.chanSet {
-		// indicate processing done to the caller
-		logger.Debugw("uniPonAniConfigFsm processingDone on channel", log.Fields{
-			"ProcessingStep": oFsm.procStep, "from_State": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
-		oFsm.chSuccess <- oFsm.procStep
-		oFsm.chanSet = false //reset the internal channel state
-	}
-
+	//remove all TechProf related internal data to allow for new configuration (e.g. with disable/enable procedure)
+	oFsm.pUniTechProf.clearAniSideConfig(oFsm.pOnuUniPort.uniID)
 }
 
 func (oFsm *uniPonAniConfigFsm) processOmciAniMessages( /*ctx context.Context*/ ) {
-	logger.Debugw("Start uniPonAniConfigFsm Msg processing", log.Fields{"for device-id": oFsm.pAdaptFsm.deviceID})
+	logger.Debugw("Start uniPonAniConfigFsm Msg processing", log.Fields{"for device-id": oFsm.deviceID})
 loop:
 	for {
 		// case <-ctx.Done():
-		// 	logger.Info("MibSync Msg", log.Fields{"Message handling canceled via context for device-id": oFsm.pAdaptFsm.deviceID})
+		// 	logger.Info("MibSync Msg", log.Fields{"Message handling canceled via context for device-id": oFsm.deviceID})
 		// 	break loop
 		message, ok := <-oFsm.pAdaptFsm.commChan
 		if !ok {
-			logger.Info("UniPonAniConfigFsm Rx Msg - could not read from channel", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+			logger.Info("UniPonAniConfigFsm Rx Msg - could not read from channel", log.Fields{"device-id": oFsm.deviceID})
 			// but then we have to ensure a restart of the FSM as well - as exceptional procedure
 			_ = oFsm.pAdaptFsm.pFsm.Event(aniEvReset)
 			break loop
 		}
-		logger.Debugw("UniPonAniConfigFsm Rx Msg", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+		logger.Debugw("UniPonAniConfigFsm Rx Msg", log.Fields{"device-id": oFsm.deviceID})
 
 		switch message.Type {
 		case TestMsg:
 			msg, _ := message.Data.(TestMessage)
 			if msg.TestMessageVal == AbortMessageProcessing {
-				logger.Infow("UniPonAniConfigFsm abort ProcessMsg", log.Fields{"for device-id": oFsm.pAdaptFsm.deviceID})
+				logger.Infow("UniPonAniConfigFsm abort ProcessMsg", log.Fields{"for device-id": oFsm.deviceID})
 				break loop
 			}
-			logger.Warnw("UniPonAniConfigFsm unknown TestMessage", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID, "MessageVal": msg.TestMessageVal})
+			logger.Warnw("UniPonAniConfigFsm unknown TestMessage", log.Fields{"device-id": oFsm.deviceID, "MessageVal": msg.TestMessageVal})
 		case OMCI:
 			msg, _ := message.Data.(OmciMessage)
 			oFsm.handleOmciAniConfigMessage(msg)
 		default:
-			logger.Warn("UniPonAniConfigFsm Rx unknown message", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID,
+			logger.Warn("UniPonAniConfigFsm Rx unknown message", log.Fields{"device-id": oFsm.deviceID,
 				"message.Type": message.Type})
 		}
 
 	}
-	logger.Infow("End uniPonAniConfigFsm Msg processing", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+	logger.Infow("End uniPonAniConfigFsm Msg processing", log.Fields{"device-id": oFsm.deviceID})
 }
 
 func (oFsm *uniPonAniConfigFsm) handleOmciAniConfigCreateResponseMessage(msg OmciMessage) {
 	msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeCreateResponse)
 	if msgLayer == nil {
 		logger.Errorw("Omci Msg layer could not be detected for CreateResponse",
-			log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+			log.Fields{"device-id": oFsm.deviceID})
 		return
 	}
 	msgObj, msgOk := msgLayer.(*omci.CreateResponse)
 	if !msgOk {
 		logger.Errorw("Omci Msg layer could not be assigned for CreateResponse",
-			log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+			log.Fields{"device-id": oFsm.deviceID})
 		return
 	}
-	logger.Debugw("CreateResponse Data", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID, "data-fields": msgObj})
+	logger.Debugw("CreateResponse Data", log.Fields{"device-id": oFsm.deviceID, "data-fields": msgObj})
 	if msgObj.Result != me.Success {
 		logger.Errorw("Omci CreateResponse Error - later: drive FSM to abort state ?", log.Fields{"Error": msgObj.Result})
 		// possibly force FSM into abort or ignore some errors for some messages? store error for mgmt display?
 		return
 	}
-	if msgObj.EntityClass == oFsm.pOmciCC.pLastTxMeInstance.GetClassID() &&
-		msgObj.EntityInstance == oFsm.pOmciCC.pLastTxMeInstance.GetEntityID() {
+	if msgObj.EntityClass == oFsm.pLastTxMeInstance.GetClassID() &&
+		msgObj.EntityInstance == oFsm.pLastTxMeInstance.GetEntityID() {
 		// maybe we can use just the same eventName for different state transitions like "forward"
 		//   - might be checked, but so far I go for sure and have to inspect the concrete state events ...
-		switch oFsm.pOmciCC.pLastTxMeInstance.GetName() {
+		switch oFsm.pLastTxMeInstance.GetName() {
 		case "Ieee8021PMapperServiceProfile":
 			{ // let the FSM proceed ...
 				_ = oFsm.pAdaptFsm.pFsm.Event(aniEvRxDot1pmapCResp)
@@ -590,29 +582,29 @@
 	msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeSetResponse)
 	if msgLayer == nil {
 		logger.Errorw("UniPonAniConfigFsm - Omci Msg layer could not be detected for SetResponse",
-			log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+			log.Fields{"device-id": oFsm.deviceID})
 		return
 	}
 	msgObj, msgOk := msgLayer.(*omci.SetResponse)
 	if !msgOk {
 		logger.Errorw("UniPonAniConfigFsm - Omci Msg layer could not be assigned for SetResponse",
-			log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+			log.Fields{"device-id": oFsm.deviceID})
 		return
 	}
-	logger.Debugw("UniPonAniConfigFsm SetResponse Data", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID, "data-fields": msgObj})
+	logger.Debugw("UniPonAniConfigFsm SetResponse Data", log.Fields{"device-id": oFsm.deviceID, "data-fields": msgObj})
 	if msgObj.Result != me.Success {
 		logger.Errorw("UniPonAniConfigFsm - Omci SetResponse Error - later: drive FSM to abort state ?",
-			log.Fields{"device-id": oFsm.pAdaptFsm.deviceID, "Error": msgObj.Result})
+			log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
 		// possibly force FSM into abort or ignore some errors for some messages? store error for mgmt display?
 		return
 	}
-	if msgObj.EntityClass == oFsm.pOmciCC.pLastTxMeInstance.GetClassID() &&
-		msgObj.EntityInstance == oFsm.pOmciCC.pLastTxMeInstance.GetEntityID() {
+	if msgObj.EntityClass == oFsm.pLastTxMeInstance.GetClassID() &&
+		msgObj.EntityInstance == oFsm.pLastTxMeInstance.GetEntityID() {
 		//store the created ME into DB //TODO??? obviously the Python code does not store the config ...
 		// if, then something like:
 		//oFsm.pOnuDB.StoreMe(msgObj)
 
-		switch oFsm.pOmciCC.pLastTxMeInstance.GetName() {
+		switch oFsm.pLastTxMeInstance.GetName() {
 		case "TCont":
 			{ // let the FSM proceed ...
 				_ = oFsm.pAdaptFsm.pFsm.Event(aniEvRxTcontsResp)
@@ -630,7 +622,7 @@
 }
 
 func (oFsm *uniPonAniConfigFsm) handleOmciAniConfigMessage(msg OmciMessage) {
-	logger.Debugw("Rx OMCI UniPonAniConfigFsm Msg", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID,
+	logger.Debugw("Rx OMCI UniPonAniConfigFsm Msg", log.Fields{"device-id": oFsm.deviceID,
 		"msgType": msg.OmciMsg.MessageType})
 
 	switch msg.OmciMsg.MessageType {
@@ -647,7 +639,7 @@
 	default:
 		{
 			logger.Errorw("uniPonAniConfigFsm - Rx OMCI unhandled MsgType",
-				log.Fields{"omciMsgType": msg.OmciMsg.MessageType, "device-id": oFsm.pAdaptFsm.deviceID})
+				log.Fields{"omciMsgType": msg.OmciMsg.MessageType, "device-id": oFsm.deviceID})
 			return
 		}
 	}
@@ -659,7 +651,7 @@
 		logger.Debugw("uniPonAniConfigFsm Tx Create::GemNWCtp", log.Fields{
 			"EntitytId": strconv.FormatInt(int64(gemPortAttribs.gemPortID), 16),
 			"TcontId":   strconv.FormatInt(int64(oFsm.tcont0ID), 16),
-			"device-id": oFsm.pAdaptFsm.deviceID})
+			"device-id": oFsm.deviceID})
 		meParams := me.ParamData{
 			EntityID: gemPortAttribs.gemPortID, //unique, same as PortId
 			Attributes: me.AttributeValueMap{
@@ -676,20 +668,20 @@
 			oFsm.pAdaptFsm.commChan, meParams)
 		//accept also nil as (error) return value for writing to LastTx
 		//  - this avoids misinterpretation of new received OMCI messages
-		oFsm.pOmciCC.pLastTxMeInstance = meInstance
+		oFsm.pLastTxMeInstance = meInstance
 
 		//verify response
 		err := oFsm.waitforOmciResponse()
 		if err != nil {
 			logger.Errorw("GemNWCtp create failed, aborting AniConfig FSM!",
-				log.Fields{"device-id": oFsm.pAdaptFsm.deviceID, "GemIndex": gemIndex})
+				log.Fields{"device-id": oFsm.deviceID, "GemIndex": gemIndex})
 			_ = oFsm.pAdaptFsm.pFsm.Event(aniEvReset)
 			return
 		}
 	} //for all GemPorts of this T-Cont
 
 	// if Config has been done for all GemPort instances let the FSM proceed
-	logger.Debugw("GemNWCtp create loop finished", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+	logger.Debugw("GemNWCtp create loop finished", log.Fields{"device-id": oFsm.deviceID})
 	_ = oFsm.pAdaptFsm.pFsm.Event(aniEvRxGemntcpsResp)
 }
 
@@ -699,7 +691,7 @@
 		logger.Debugw("uniPonAniConfigFsm Tx Create::GemIwTp", log.Fields{
 			"EntitytId": strconv.FormatInt(int64(gemPortAttribs.gemPortID), 16),
 			"SPPtr":     strconv.FormatInt(int64(oFsm.mapperSP0ID), 16),
-			"device-id": oFsm.pAdaptFsm.deviceID})
+			"device-id": oFsm.deviceID})
 		meParams := me.ParamData{
 			EntityID: gemPortAttribs.gemPortID,
 			Attributes: me.AttributeValueMap{
@@ -714,20 +706,20 @@
 			oFsm.pAdaptFsm.commChan, meParams)
 		//accept also nil as (error) return value for writing to LastTx
 		//  - this avoids misinterpretation of new received OMCI messages
-		oFsm.pOmciCC.pLastTxMeInstance = meInstance
+		oFsm.pLastTxMeInstance = meInstance
 
 		//verify response
 		err := oFsm.waitforOmciResponse()
 		if err != nil {
 			logger.Errorw("GemIwTp create failed, aborting AniConfig FSM!",
-				log.Fields{"device-id": oFsm.pAdaptFsm.deviceID, "GemIndex": gemIndex})
+				log.Fields{"device-id": oFsm.deviceID, "GemIndex": gemIndex})
 			_ = oFsm.pAdaptFsm.pFsm.Event(aniEvReset)
 			return
 		}
 	} //for all GemPort's of this T-Cont
 
 	// if Config has been done for all GemPort instances let the FSM proceed
-	logger.Debugw("GemIwTp create loop finished", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+	logger.Debugw("GemIwTp create loop finished", log.Fields{"device-id": oFsm.deviceID})
 	_ = oFsm.pAdaptFsm.pFsm.Event(aniEvRxGemiwsResp)
 }
 
@@ -767,14 +759,14 @@
 			//StrictPrio indication
 			logger.Debugw("uniPonAniConfigFsm Tx Set::PrioQueue to StrictPrio", log.Fields{
 				"EntitytId": strconv.FormatInt(int64(queueIndex), 16),
-				"device-id": oFsm.pAdaptFsm.deviceID})
+				"device-id": oFsm.deviceID})
 			meParams.Attributes["TrafficSchedulerPointer"] = 0 //ensure T-Cont defined StrictPrio scheduling
 		} else {
 			//WRR indication
 			logger.Debugw("uniPonAniConfigFsm Tx Set::PrioQueue to WRR", log.Fields{
 				"EntitytId": strconv.FormatInt(int64(queueIndex), 16),
 				"Weight":    kv.Value,
-				"device-id": oFsm.pAdaptFsm.deviceID})
+				"device-id": oFsm.deviceID})
 			meParams.Attributes["TrafficSchedulerPointer"] = loTrafficSchedulerEID //ensure assignment of the relevant trafficScheduler
 			meParams.Attributes["Weight"] = uint8(kv.Value.(uint16))
 		}
@@ -782,13 +774,13 @@
 			oFsm.pAdaptFsm.commChan, meParams)
 		//accept also nil as (error) return value for writing to LastTx
 		//  - this avoids misinterpretation of new received OMCI messages
-		oFsm.pOmciCC.pLastTxMeInstance = meInstance
+		oFsm.pLastTxMeInstance = meInstance
 
 		//verify response
 		err := oFsm.waitforOmciResponse()
 		if err != nil {
 			logger.Errorw("PrioQueue set failed, aborting AniConfig FSM!",
-				log.Fields{"device-id": oFsm.pAdaptFsm.deviceID, "QueueId": strconv.FormatInt(int64(queueIndex), 16)})
+				log.Fields{"device-id": oFsm.deviceID, "QueueId": strconv.FormatInt(int64(queueIndex), 16)})
 			_ = oFsm.pAdaptFsm.pFsm.Event(aniEvReset)
 			return
 		}
@@ -801,7 +793,7 @@
 	} //for all upstream prioQueues
 
 	// if Config has been done for all PrioQueue instances let the FSM proceed
-	logger.Debugw("PrioQueue set loop finished", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+	logger.Debugw("PrioQueue set loop finished", log.Fields{"device-id": oFsm.deviceID})
 	_ = oFsm.pAdaptFsm.pFsm.Event(aniEvRxPrioqsResp)
 }
 
@@ -809,17 +801,17 @@
 	select {
 	// maybe be also some outside cancel (but no context modeled for the moment ...)
 	// case <-ctx.Done():
-	// 		logger.Infow("LockState-bridge-init message reception canceled", log.Fields{"for device-id": oFsm.pAdaptFsm.deviceID})
+	// 		logger.Infow("LockState-bridge-init message reception canceled", log.Fields{"for device-id": oFsm.deviceID})
 	case <-time.After(30 * time.Second): //3s was detected to be to less in 8*8 bbsim test with debug Info/Debug
-		logger.Warnw("UniPonAniConfigFsm multi entity timeout", log.Fields{"for device-id": oFsm.pAdaptFsm.deviceID})
-		return fmt.Errorf("uniPonAniConfigFsm multi entity timeout %s", oFsm.pAdaptFsm.deviceID)
+		logger.Warnw("UniPonAniConfigFsm multi entity timeout", log.Fields{"for device-id": oFsm.deviceID})
+		return fmt.Errorf("uniPonAniConfigFsm multi entity timeout %s", oFsm.deviceID)
 	case success := <-oFsm.omciMIdsResponseReceived:
 		if success {
 			logger.Debug("uniPonAniConfigFsm multi entity response received")
 			return nil
 		}
 		// should not happen so far
-		logger.Warnw("uniPonAniConfigFsm multi entity response error", log.Fields{"for device-id": oFsm.pAdaptFsm.deviceID})
-		return fmt.Errorf("uniPonAniConfigFsm multi entity responseError %s", oFsm.pAdaptFsm.deviceID)
+		logger.Warnw("uniPonAniConfigFsm multi entity response error", log.Fields{"for device-id": oFsm.deviceID})
+		return fmt.Errorf("uniPonAniConfigFsm multi entity responseError %s", oFsm.deviceID)
 	}
 }
diff --git a/internal/pkg/onuadaptercore/omci_cc.go b/internal/pkg/onuadaptercore/omci_cc.go
index d13efe0..185b96e 100644
--- a/internal/pkg/onuadaptercore/omci_cc.go
+++ b/internal/pkg/onuadaptercore/omci_cc.go
@@ -1561,3 +1561,49 @@
 		"Err": omciErr.GetError(), "device-id": oo.deviceID})
 	return nil
 }
+
+func (oo *omciCC) sendDeleteVtfd(ctx context.Context, timeout int, highPrio bool,
+	rxChan chan Message, aInstID uint16) *me.ManagedEntity {
+	tid := oo.getNextTid(highPrio)
+	logger.Debugw("send VTFD-Delete-msg:", log.Fields{"device-id": oo.deviceID,
+		"SequNo": strconv.FormatInt(int64(tid), 16),
+		"InstId": strconv.FormatInt(int64(aInstID), 16)})
+
+	meParams := me.ParamData{EntityID: aInstID}
+	meInstance, omciErr := me.NewVlanTaggingFilterData(meParams)
+	if omciErr.GetError() == nil {
+		omciLayer, msgLayer, err := omci.EncodeFrame(meInstance, omci.DeleteRequestType,
+			omci.TransactionID(tid))
+		if err != nil {
+			logger.Errorw("Cannot encode VTFD for delete", log.Fields{
+				"Err": err, "device-id": oo.deviceID})
+			//TODO!!: refactoring improvement requested, here as an example for [VOL-3457]:
+			//  return (dual format) error code that can be used at caller for immediate error treatment
+			//  (relevant to all used sendXX() methods and their error conditions)
+			return nil
+		}
+
+		pkt, err := serializeOmciLayer(omciLayer, msgLayer)
+		if err != nil {
+			logger.Errorw("Cannot serialize VTFD delete", log.Fields{
+				"Err": err, "device-id": oo.deviceID})
+			return nil
+		}
+
+		omciRxCallbackPair := callbackPair{
+			cbKey:   tid,
+			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse},
+		}
+		err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
+		if err != nil {
+			logger.Errorw("Cannot send VTFD delete", log.Fields{
+				"Err": err, "device-id": oo.deviceID})
+			return nil
+		}
+		logger.Debug("send VTFD-Delete-msg done")
+		return meInstance
+	}
+	logger.Errorw("Cannot generate VTFD Instance for delete", log.Fields{
+		"Err": omciErr.GetError(), "device-id": oo.deviceID})
+	return nil
+}
diff --git a/internal/pkg/onuadaptercore/omci_vlan_config.go b/internal/pkg/onuadaptercore/omci_vlan_config.go
index cda4905..b8605e0 100644
--- a/internal/pkg/onuadaptercore/omci_vlan_config.go
+++ b/internal/pkg/onuadaptercore/omci_vlan_config.go
@@ -25,6 +25,7 @@
 	"sync"
 	"time"
 
+	gp "github.com/google/gopacket"
 	"github.com/looplab/fsm"
 	"github.com/opencord/omci-lib-go"
 	me "github.com/opencord/omci-lib-go/generated"
@@ -36,7 +37,8 @@
 	// internal predefined values
 	cDefaultDownstreamMode = 0
 	cDefaultTpid           = 0x8100
-	cMaxAllowedFlows       = 12 //which might be under discussion, for the moment connected to limit of VLAN's within VTFD
+	cVtfdTableSize         = 12             //as per G.988
+	cMaxAllowedFlows       = cVtfdTableSize //which might be under discussion, for the moment connected to limit of VLAN's within VTFD
 )
 
 const (
@@ -75,21 +77,22 @@
 
 const (
 	// events of config PON ANI port FSM
-	vlanEvStart          = "vlanEvStart"
-	vlanEvWaitTechProf   = "vlanEvWaitTechProf"
-	vlanEvContinueConfig = "vlanEvContinueConfig"
-	vlanEvStartConfig    = "vlanEvStartConfig"
-	vlanEvRxConfigVtfd   = "vlanEvRxConfigVtfd"
-	vlanEvRxConfigEvtocd = "vlanEvRxConfigEvtocd"
-	vlanEvIncrFlowConfig = "vlanEvIncrFlowConfig"
-	//vlanEvCleanupConfig  = "vlanEvCleanupConfig"
-	//vlanEvRxCleanVtfd    = "vlanEvRxCleanVtfd"
-	//vlanEvRxCleanEvtocd  = "vlanEvRxCleanEvtocd"
+	vlanEvStart           = "vlanEvStart"
+	vlanEvWaitTechProf    = "vlanEvWaitTechProf"
+	vlanEvContinueConfig  = "vlanEvContinueConfig"
+	vlanEvStartConfig     = "vlanEvStartConfig"
+	vlanEvRxConfigVtfd    = "vlanEvRxConfigVtfd"
+	vlanEvRxConfigEvtocd  = "vlanEvRxConfigEvtocd"
+	vlanEvIncrFlowConfig  = "vlanEvIncrFlowConfig"
+	vlanEvRemFlowConfig   = "vlanEvRemFlowConfig"
+	vlanEvRemFlowDone     = "vlanEvRemFlowDone"
+	vlanEvFlowDataRemoved = "vlanEvFlowDataRemoved"
 	//vlanEvTimeoutSimple  = "vlanEvTimeoutSimple"
 	//vlanEvTimeoutMids    = "vlanEvTimeoutMids"
 	vlanEvReset   = "vlanEvReset"
 	vlanEvRestart = "vlanEvRestart"
 )
+
 const (
 	// states of config PON ANI port FSM
 	vlanStDisabled        = "vlanStDisabled"
@@ -99,15 +102,34 @@
 	vlanStConfigEvtocd    = "vlanStConfigEvtocd"
 	vlanStConfigDone      = "vlanStConfigDone"
 	vlanStConfigIncrFlow  = "vlanStConfigIncrFlow"
-	vlanStCleanEvtocd     = "vlanStCleanEvtocd"
-	vlanStCleanVtfd       = "vlanStCleanVtfd"
+	vlanStRemoveFlow      = "vlanStRemoveFlow"
 	vlanStCleanupDone     = "vlanStCleanupDone"
 	vlanStResetting       = "vlanStResetting"
 )
 
+type uniVlanRuleParams struct {
+	TpID         uint16 `json:"tp_id"`
+	MatchVid     uint32 `json:"match_vid"` //use uint32 types for allowing immediate bitshifting
+	MatchPcp     uint32 `json:"match_pcp"`
+	TagsToRemove uint32 `json:"tags_to_remove"`
+	SetVid       uint32 `json:"set_vid"`
+	SetPcp       uint32 `json:"set_pcp"`
+}
+
+type uniVlanFlowParams struct {
+	CookieSlice    []uint64          `json:"cookie_slice"`
+	VlanRuleParams uniVlanRuleParams `json:"vlan_rule_params"`
+}
+
+type uniRemoveVlanFlowParams struct {
+	cookie         uint64 //just the last cookie valid for removal
+	vlanRuleParams uniVlanRuleParams
+}
+
 //UniVlanConfigFsm defines the structure for the state machine to config the PON ANI ports of ONU UNI ports via OMCI
 type UniVlanConfigFsm struct {
 	pDeviceHandler              *deviceHandler
+	deviceID                    string
 	pOmciCC                     *omciCC
 	pOnuUniPort                 *onuUniPort
 	pUniTechProf                *onuUniTechProf
@@ -118,22 +140,27 @@
 	pAdaptFsm                   *AdapterFsm
 	acceptIncrementalEvtoOption bool
 	mutexFlowParams             sync.Mutex
-	uniFlowParamsSlice          []uniVlanFlowParams
+	uniVlanFlowParamsSlice      []uniVlanFlowParams
+	uniRemoveFlowsSlice         []uniRemoveVlanFlowParams
 	numUniFlows                 uint8 // expected number of flows should be less than 12
 	configuredUniFlow           uint8
+	numRemoveFlows              uint8
 	numVlanFilterEntries        uint8
-	vlanFilterList              [12]uint16
+	vlanFilterList              [cVtfdTableSize]uint16
 	vtfdID                      uint16
 	evtocdID                    uint16
+	pLastTxMeInstance           *me.ManagedEntity
 }
 
-//NewUniVlanConfigFsm is the 'constructor' for the state machine to config the PON ANI ports of ONU UNI ports via OMCI
-func NewUniVlanConfigFsm(apDeviceHandler *deviceHandler, apDevOmciCC *omciCC, apUniPort *onuUniPort, apUniTechProf *onuUniTechProf,
-	apOnuDB *onuDeviceDB, aTechProfileID uint16, aRequestEvent OnuDeviceEvent, aName string,
-	aDeviceID string, aCommChannel chan Message,
-	aAcceptIncrementalEvto bool, aMatchVlan uint16, aSetVlan uint16, aSetPcp uint8) *UniVlanConfigFsm {
+//NewUniVlanConfigFsm is the 'constructor' for the state machine to config the PON ANI ports
+//  of ONU UNI ports via OMCI
+func NewUniVlanConfigFsm(apDeviceHandler *deviceHandler, apDevOmciCC *omciCC, apUniPort *onuUniPort,
+	apUniTechProf *onuUniTechProf, apOnuDB *onuDeviceDB, aTechProfileID uint16,
+	aRequestEvent OnuDeviceEvent, aName string, aCommChannel chan Message, aAcceptIncrementalEvto bool,
+	aCookieSlice []uint64, aMatchVlan uint16, aSetVlan uint16, aSetPcp uint8) *UniVlanConfigFsm {
 	instFsm := &UniVlanConfigFsm{
 		pDeviceHandler:              apDeviceHandler,
+		deviceID:                    apDeviceHandler.deviceID,
 		pOmciCC:                     apDevOmciCC,
 		pOnuUniPort:                 apUniPort,
 		pUniTechProf:                apUniTechProf,
@@ -143,12 +170,13 @@
 		acceptIncrementalEvtoOption: aAcceptIncrementalEvto,
 		numUniFlows:                 0,
 		configuredUniFlow:           0,
+		numRemoveFlows:              0,
 	}
 
-	instFsm.pAdaptFsm = NewAdapterFsm(aName, aDeviceID, aCommChannel)
+	instFsm.pAdaptFsm = NewAdapterFsm(aName, instFsm.deviceID, aCommChannel)
 	if instFsm.pAdaptFsm == nil {
 		logger.Errorw("UniVlanConfigFsm's AdapterFsm could not be instantiated!!", log.Fields{
-			"device-id": aDeviceID})
+			"device-id": instFsm.deviceID})
 		return nil
 	}
 	instFsm.pAdaptFsm.pFsm = fsm.NewFSM(
@@ -162,6 +190,9 @@
 			{Name: vlanEvRxConfigEvtocd, Src: []string{vlanStConfigEvtocd, vlanStConfigIncrFlow},
 				Dst: vlanStConfigDone},
 			{Name: vlanEvIncrFlowConfig, Src: []string{vlanStConfigDone}, Dst: vlanStConfigIncrFlow},
+			{Name: vlanEvRemFlowConfig, Src: []string{vlanStConfigDone}, Dst: vlanStRemoveFlow},
+			{Name: vlanEvRemFlowDone, Src: []string{vlanStRemoveFlow}, Dst: vlanStCleanupDone},
+			{Name: vlanEvFlowDataRemoved, Src: []string{vlanStCleanupDone}, Dst: vlanStConfigDone},
 			/*
 				{Name: vlanEvTimeoutSimple, Src: []string{
 					vlanStCreatingDot1PMapper, vlanStCreatingMBPCD, vlanStSettingTconts, vlanStSettingDot1PMapper}, Dst: vlanStStarting},
@@ -171,7 +202,7 @@
 			// exceptional treatment for all states except vlanStResetting
 			{Name: vlanEvReset, Src: []string{vlanStStarting, vlanStWaitingTechProf,
 				vlanStConfigVtfd, vlanStConfigEvtocd, vlanStConfigDone, vlanStConfigIncrFlow,
-				vlanStCleanEvtocd, vlanStCleanVtfd, vlanStCleanupDone},
+				vlanStRemoveFlow, vlanStCleanupDone},
 				Dst: vlanStResetting},
 			// the only way to get to resource-cleared disabled state again is via "resseting"
 			{Name: vlanEvRestart, Src: []string{vlanStResetting}, Dst: vlanStDisabled},
@@ -183,8 +214,7 @@
 			("enter_" + vlanStConfigEvtocd):   func(e *fsm.Event) { instFsm.enterConfigEvtocd(e) },
 			("enter_" + vlanStConfigDone):     func(e *fsm.Event) { instFsm.enterVlanConfigDone(e) },
 			("enter_" + vlanStConfigIncrFlow): func(e *fsm.Event) { instFsm.enterConfigIncrFlow(e) },
-			("enter_" + vlanStCleanVtfd):      func(e *fsm.Event) { instFsm.enterCleanVtfd(e) },
-			("enter_" + vlanStCleanEvtocd):    func(e *fsm.Event) { instFsm.enterCleanEvtocd(e) },
+			("enter_" + vlanStRemoveFlow):     func(e *fsm.Event) { instFsm.enterRemoveFlow(e) },
 			("enter_" + vlanStCleanupDone):    func(e *fsm.Event) { instFsm.enterVlanCleanupDone(e) },
 			("enter_" + vlanStResetting):      func(e *fsm.Event) { instFsm.enterResetting(e) },
 			("enter_" + vlanStDisabled):       func(e *fsm.Event) { instFsm.enterDisabled(e) },
@@ -192,82 +222,172 @@
 	)
 	if instFsm.pAdaptFsm.pFsm == nil {
 		logger.Errorw("UniVlanConfigFsm's Base FSM could not be instantiated!!", log.Fields{
-			"device-id": aDeviceID})
+			"device-id": instFsm.deviceID})
 		return nil
 	}
 
-	_ = instFsm.SetUniFlowParams(aTechProfileID, aMatchVlan, aSetVlan, aSetPcp)
+	_ = instFsm.initUniFlowParams(aTechProfileID, aCookieSlice, aMatchVlan, aSetVlan, aSetPcp)
 
-	logger.Infow("UniVlanConfigFsm created", log.Fields{"device-id": aDeviceID,
+	logger.Infow("UniVlanConfigFsm created", log.Fields{"device-id": instFsm.deviceID,
 		"accIncrEvto": instFsm.acceptIncrementalEvtoOption})
 	return instFsm
 }
 
-//SetUniFlowParams verifies on existence of flow parameters to be configured
-// and appends a new flow if there is space
-func (oFsm *UniVlanConfigFsm) SetUniFlowParams(aTpID uint16, aMatchVlan uint16, aSetVlan uint16, aSetPcp uint8) error {
-	loFlowParams := uniVlanFlowParams{
+//initUniFlowParams is a simplified form of SetUniFlowParams() used for first flow parameters configuration
+func (oFsm *UniVlanConfigFsm) initUniFlowParams(aTpID uint16, aCookieSlice []uint64,
+	aMatchVlan uint16, aSetVlan uint16, aSetPcp uint8) error {
+	loRuleParams := uniVlanRuleParams{
 		TpID:     aTpID,
 		MatchVid: uint32(aMatchVlan),
 		SetVid:   uint32(aSetVlan),
 		SetPcp:   uint32(aSetPcp),
 	}
 	// some automatic adjustments on the filter/treat parameters as not specifically configured/ensured by flow configuration parameters
-	loFlowParams.TagsToRemove = 1            //one tag to remove as default setting
-	loFlowParams.MatchPcp = cPrioDoNotFilter // do not Filter on prio as default
+	loRuleParams.TagsToRemove = 1            //one tag to remove as default setting
+	loRuleParams.MatchPcp = cPrioDoNotFilter // do not Filter on prio as default
 
-	if loFlowParams.SetVid == uint32(of.OfpVlanId_OFPVID_PRESENT) {
+	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
-		loFlowParams.MatchVid = uint32(of.OfpVlanId_OFPVID_PRESENT)
+		loRuleParams.MatchVid = uint32(of.OfpVlanId_OFPVID_PRESENT)
 		//TODO!!: maybe be needed to be re-checked at flow deletion (but assume all flows are always deleted togehther)
 	} else {
 		if !oFsm.acceptIncrementalEvtoOption {
 			//then matchVlan is don't care and should be overwritten to 'transparent' here to avoid unneeded multiple flow entries
-			loFlowParams.MatchVid = uint32(of.OfpVlanId_OFPVID_PRESENT)
+			loRuleParams.MatchVid = uint32(of.OfpVlanId_OFPVID_PRESENT)
 		}
 	}
 
-	if loFlowParams.MatchVid == uint32(of.OfpVlanId_OFPVID_PRESENT) {
+	if loRuleParams.MatchVid == uint32(of.OfpVlanId_OFPVID_PRESENT) {
 		// no prio/vid filtering requested
-		loFlowParams.TagsToRemove = 0          //no tag pop action
-		loFlowParams.MatchPcp = cPrioIgnoreTag // no vlan tag filtering
-		if loFlowParams.SetPcp == cCopyPrioFromInner {
+		loRuleParams.TagsToRemove = 0          //no tag pop action
+		loRuleParams.MatchPcp = cPrioIgnoreTag // no vlan tag filtering
+		if loRuleParams.SetPcp == cCopyPrioFromInner {
 			//in case of no filtering and configured PrioCopy ensure default prio setting to 0
 			// which is required for stacking of untagged, but obviously also ensures prio setting for prio/singletagged
 			// might collide with NoMatchVid/CopyPrio(/setVid) setting
 			// this was some precondition setting taken over from py adapter ..
-			loFlowParams.SetPcp = 0
+			loRuleParams.SetPcp = 0
 		}
 	}
+
+	loFlowParams := uniVlanFlowParams{VlanRuleParams: loRuleParams}
+	loFlowParams.CookieSlice = make([]uint64, 0)
+	loFlowParams.CookieSlice = append(loFlowParams.CookieSlice, aCookieSlice...)
+
+	//no mutex protection is required for initial access and adding the first flow is always possible
+	oFsm.uniVlanFlowParamsSlice = make([]uniVlanFlowParams, 0)
+	oFsm.uniVlanFlowParamsSlice = append(oFsm.uniVlanFlowParamsSlice, loFlowParams)
+	logger.Debugw("first UniVlanConfigFsm flow added", log.Fields{
+		"Cookies":   oFsm.uniVlanFlowParamsSlice[0].CookieSlice,
+		"MatchVid":  strconv.FormatInt(int64(loRuleParams.MatchVid), 16),
+		"SetVid":    strconv.FormatInt(int64(loRuleParams.SetVid), 16),
+		"SetPcp":    loRuleParams.SetPcp,
+		"device-id": oFsm.deviceID})
+	oFsm.numUniFlows = 1
+	oFsm.uniRemoveFlowsSlice = make([]uniRemoveVlanFlowParams, 0) //initially nothing to remove
+
+	//permanently store flow config for reconcile case
+	if err := oFsm.pDeviceHandler.storePersUniFlowConfig(oFsm.pOnuUniPort.uniID,
+		&oFsm.uniVlanFlowParamsSlice); err != nil {
+		logger.Errorw(err.Error(), log.Fields{"device-id": oFsm.deviceID})
+		return err
+	}
+
+	return nil
+}
+
+//SetUniFlowParams verifies on existence of flow parameters to be configured,
+// optionally udates the cookie list or appends a new flow if there is space
+// if possible the FSM is trigggerd to start with the processing
+func (oFsm *UniVlanConfigFsm) SetUniFlowParams(aTpID uint16, aCookieSlice []uint64,
+	aMatchVlan uint16, aSetVlan uint16, aSetPcp uint8) error {
+	loRuleParams := uniVlanRuleParams{
+		TpID:     aTpID,
+		MatchVid: uint32(aMatchVlan),
+		SetVid:   uint32(aSetVlan),
+		SetPcp:   uint32(aSetPcp),
+	}
+	// 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
+
+	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)
+		//TODO!!: maybe be needed to be re-checked at flow deletion (but assume all flows are always deleted togehther)
+	} else {
+		if !oFsm.acceptIncrementalEvtoOption {
+			//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)
+		}
+	}
+
+	if loRuleParams.MatchVid == uint32(of.OfpVlanId_OFPVID_PRESENT) {
+		// no prio/vid filtering requested
+		loRuleParams.TagsToRemove = 0          //no tag pop action
+		loRuleParams.MatchPcp = cPrioIgnoreTag // no vlan tag filtering
+		if loRuleParams.SetPcp == cCopyPrioFromInner {
+			//in case of no filtering and configured PrioCopy ensure default prio setting to 0
+			// which is required for stacking of untagged, but obviously also ensures prio setting for prio/singletagged
+			// might collide with NoMatchVid/CopyPrio(/setVid) setting
+			// this was some precondition setting taken over from py adapter ..
+			loRuleParams.SetPcp = 0
+		}
+	}
+
 	flowEntryMatch := false
+	flowCookieModify := false
 	//mutex protection is required for possible concurrent access to FSM members
 	oFsm.mutexFlowParams.Lock()
 	defer oFsm.mutexFlowParams.Unlock()
-	for _, storedUniFlowParams := range oFsm.uniFlowParamsSlice {
-		if storedUniFlowParams == loFlowParams {
+	for flow, storedUniFlowParams := range oFsm.uniVlanFlowParamsSlice {
+		//TODO: Verify if using e.g. hashes for the structures here for comparison may generate
+		//  countable run time optimization (perhaps with including the hash in kvStore storage?)
+		if storedUniFlowParams.VlanRuleParams == loRuleParams {
 			flowEntryMatch = true
-			break
+			logger.Debugw("UniVlanConfigFsm flow setting - rule already exists", log.Fields{
+				"device-id": oFsm.deviceID})
+			var cookieMatch bool
+			for _, newCookie := range aCookieSlice { // for all cookies available in the arguments
+				cookieMatch = false
+				for _, cookie := range storedUniFlowParams.CookieSlice {
+					if cookie == newCookie {
+						logger.Debugw("UniVlanConfigFsm flow setting - and cookie already exists", log.Fields{
+							"device-id": oFsm.deviceID, "cookie": cookie})
+						cookieMatch = true
+						break //found new cookie - no further search for this requested cookie
+					}
+				}
+				if !cookieMatch {
+					logger.Debugw("UniVlanConfigFsm flow setting -adding new cookie", log.Fields{
+						"device-id": oFsm.deviceID, "cookie": newCookie})
+					//as range works with copies of the slice we have to write to the original slice!!
+					oFsm.uniVlanFlowParamsSlice[flow].CookieSlice = append(oFsm.uniVlanFlowParamsSlice[flow].CookieSlice,
+						newCookie)
+					flowCookieModify = true
+				}
+			} //for all new cookies
+			break // found rule - no further rule search
 		}
 	}
-	if flowEntryMatch {
-		logger.Debugw("UniVlanConfigFsm flow setting - flow already exists (ignore)", log.Fields{
-			"device-id": oFsm.pAdaptFsm.deviceID})
-	} else {
+	if !flowEntryMatch { //it is a new rule
 		if oFsm.numUniFlows < cMaxAllowedFlows {
-			oFsm.uniFlowParamsSlice = append(oFsm.uniFlowParamsSlice, loFlowParams)
+			loFlowParams := uniVlanFlowParams{VlanRuleParams: loRuleParams}
+			loFlowParams.CookieSlice = make([]uint64, 0)
+			loFlowParams.CookieSlice = append(loFlowParams.CookieSlice, aCookieSlice...)
+			oFsm.uniVlanFlowParamsSlice = append(oFsm.uniVlanFlowParamsSlice, loFlowParams)
+			logger.Debugw("UniVlanConfigFsm flow add", log.Fields{
+				"Cookies":  oFsm.uniVlanFlowParamsSlice[oFsm.numUniFlows].CookieSlice,
+				"MatchVid": strconv.FormatInt(int64(loRuleParams.MatchVid), 16),
+				"SetVid":   strconv.FormatInt(int64(loRuleParams.SetVid), 16),
+				"SetPcp":   loRuleParams.SetPcp, "numberofFlows": (oFsm.numUniFlows + 1),
+				"device-id": oFsm.deviceID})
+
 			oFsm.numUniFlows++
-			logger.Debugw("UniVlanConfigFsm flow added", log.Fields{
-				"MatchVid": strconv.FormatInt(int64(loFlowParams.MatchVid), 16),
-				"SetVid":   strconv.FormatInt(int64(loFlowParams.SetVid), 16),
-				"SetPcp":   loFlowParams.SetPcp, "numberofFlows": oFsm.numUniFlows,
-				"device-id": oFsm.pAdaptFsm.deviceID})
-
-			//permanently store flow config for reconcile case
-
-			if err := oFsm.pDeviceHandler.storePersUniFlowConfig(oFsm.pOnuUniPort.uniID, &oFsm.uniFlowParamsSlice); err != nil {
-				logger.Errorw(err.Error(), log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
-				return err
-			}
+			// note: theoretical it would be possible to clear the same rule from the remove slice
+			//  (for entries that have not yet been started with removal)
+			//  but that is getting quite complicated - maybe a future optimization in case it should prove reasonable
+			// anyway the precondition here is that the FSM checks for rules to delete first and adds new rules afterwards
 
 			pConfigVlanStateBaseFsm := oFsm.pAdaptFsm.pFsm
 			if pConfigVlanStateBaseFsm.Is(vlanStConfigDone) {
@@ -276,22 +396,124 @@
 				go func(a_pBaseFsm *fsm.FSM) {
 					_ = a_pBaseFsm.Event(vlanEvIncrFlowConfig)
 				}(pConfigVlanStateBaseFsm)
-			} // in all other states a new entry will be automatically considered later in that state or
-			// ignored as not anymore relevant
+			} // if not in the appropriate state a new entry will be automatically considered later
+			//   when the configDone state is reached
 		} else {
 			logger.Errorw("UniVlanConfigFsm flow limit exceeded", log.Fields{
-				"device-id": oFsm.pAdaptFsm.deviceID})
-			return fmt.Errorf(" UniVlanConfigFsm flow limit exceeded %s", oFsm.pAdaptFsm.deviceID)
+				"device-id": oFsm.deviceID, "flow-number": oFsm.numUniFlows})
+			return fmt.Errorf(" UniVlanConfigFsm flow limit exceeded %s", oFsm.deviceID)
+		}
+	} //new flow
+
+	if !flowEntryMatch || flowCookieModify { // some change was done to the flow entries
+		//permanently store flow config for reconcile case
+		if err := oFsm.pDeviceHandler.storePersUniFlowConfig(oFsm.pOnuUniPort.uniID, &oFsm.uniVlanFlowParamsSlice); err != nil {
+			logger.Errorw(err.Error(), log.Fields{"device-id": oFsm.deviceID})
+			return err
 		}
 	}
 	return nil
 }
 
+//RemoveUniFlowParams verifies on existence of flow cookie,
+// if found removes cookie from flow cookie list and if this is empty
+// initiates removal of the flow related configuration from the ONU (via OMCI)
+func (oFsm *UniVlanConfigFsm) RemoveUniFlowParams(aCookie uint64) error {
+	flowCookieMatch := false
+	//mutex protection is required for possible concurrent access to FSM members
+	oFsm.mutexFlowParams.Lock()
+	defer oFsm.mutexFlowParams.Unlock()
+	for flow, storedUniFlowParams := range oFsm.uniVlanFlowParamsSlice {
+		for i, cookie := range storedUniFlowParams.CookieSlice {
+			if cookie == aCookie {
+				logger.Debugw("UniVlanConfigFsm flow removal - cookie found", log.Fields{
+					"device-id": oFsm.deviceID, "cookie": cookie})
+				flowCookieMatch = true
+
+				//remove the cookie from the cookie slice and verify it is getting empty
+				if len(storedUniFlowParams.CookieSlice) == 1 {
+					logger.Debugw("UniVlanConfigFsm flow removal - full flow removal", log.Fields{
+						"device-id": oFsm.deviceID})
+					oFsm.numUniFlows--
+
+					//create a new element for the removeVlanFlow slice
+					loRemoveParams := uniRemoveVlanFlowParams{
+						vlanRuleParams: storedUniFlowParams.VlanRuleParams,
+						cookie:         storedUniFlowParams.CookieSlice[0],
+					}
+					oFsm.uniRemoveFlowsSlice = append(oFsm.uniRemoveFlowsSlice, loRemoveParams)
+
+					//and remove the actual element from the addVlanFlow slice
+					// oFsm.uniVlanFlowParamsSlice[flow].CookieSlice = nil //automatically done by garbage collector
+					if len(oFsm.uniVlanFlowParamsSlice) <= 1 {
+						oFsm.numUniFlows = 0              //no more flows
+						oFsm.configuredUniFlow = 0        //no more flows configured
+						oFsm.uniVlanFlowParamsSlice = nil //reset the slice
+						logger.Debugw("UniVlanConfigFsm flow removal - no more flows", log.Fields{
+							"device-id": oFsm.deviceID})
+					} else {
+						oFsm.numUniFlows--
+						if oFsm.configuredUniFlow > 0 {
+							oFsm.configuredUniFlow--
+							//TODO!! might be needed to consider still outstanding configure requests ..
+							//  so a flow at removal might still not be configured !?!
+						}
+						//cut off the requested flow by slicing out this element
+						oFsm.uniVlanFlowParamsSlice = append(
+							oFsm.uniVlanFlowParamsSlice[:flow], oFsm.uniVlanFlowParamsSlice[flow+1:]...)
+						logger.Debugw("UniVlanConfigFsm flow removal - specific flow removed from data", log.Fields{
+							"device-id": oFsm.deviceID})
+					}
+					//trigger the FSM to remove the relevant rule
+					pConfigVlanStateBaseFsm := oFsm.pAdaptFsm.pFsm
+					if pConfigVlanStateBaseFsm.Is(vlanStConfigDone) {
+						//have to re-trigger the FSM to proceed with outstanding incremental flow configuration
+						// calling some FSM event must be decoupled
+						go func(a_pBaseFsm *fsm.FSM) {
+							_ = a_pBaseFsm.Event(vlanEvRemFlowConfig)
+						}(pConfigVlanStateBaseFsm)
+					} // if not in the appropriate state a new entry will be automatically considered later
+					//   when the configDone state is reached
+				} else {
+					logger.Debugw("UniVlanConfigFsm flow removal - flow persists with other cookies", log.Fields{
+						"device-id": oFsm.deviceID})
+					//cut off the requested cookie by slicing out this element
+					oFsm.uniVlanFlowParamsSlice[flow].CookieSlice = append(
+						oFsm.uniVlanFlowParamsSlice[flow].CookieSlice[:i],
+						oFsm.uniVlanFlowParamsSlice[flow].CookieSlice[i+1:]...)
+					logger.Debugw("UniVlanConfigFsm flow removal - still valid cookies for this flow", log.Fields{
+						"device-id": oFsm.deviceID, "cookies": oFsm.uniVlanFlowParamsSlice[flow].CookieSlice})
+				}
+
+				//permanently store the modified flow config for reconcile case
+				if err := oFsm.pDeviceHandler.storePersUniFlowConfig(oFsm.pOnuUniPort.uniID, &oFsm.uniVlanFlowParamsSlice); err != nil {
+					logger.Errorw(err.Error(), log.Fields{"device-id": oFsm.deviceID})
+					return err
+				}
+
+				break //found the cookie - no further search for this requested cookie
+			}
+		}
+		if flowCookieMatch { //cookie already found: no need for further search in other flows
+			break
+		}
+	} //search all flows
+	if !flowCookieMatch { //some cookie remove-request for a cookie that does not exist in the FSM data
+		logger.Warnw("UniVlanConfigFsm flow removal - remove-cookie not found", log.Fields{
+			"device-id": oFsm.deviceID, "remove-cookie": aCookie})
+		// but accept the request with success as no such cookie (flow) does exist
+		return nil
+	} //unknown cookie
+
+	return nil
+}
+
 func (oFsm *UniVlanConfigFsm) enterConfigStarting(e *fsm.Event) {
 	logger.Debugw("UniVlanConfigFsm start", log.Fields{"in state": e.FSM.Current(),
-		"device-id": oFsm.pAdaptFsm.deviceID})
+		"device-id": oFsm.deviceID})
 
 	// this FSM is not intended for re-start, needs always new creation for a new run
+	// (self-destroying - compare enterDisabled())
 	oFsm.omciMIdsResponseReceived = make(chan bool)
 	// start go routine for processing of LockState messages
 	go oFsm.processOmciVlanMessages()
@@ -321,11 +543,11 @@
 func (oFsm *UniVlanConfigFsm) enterConfigVtfd(e *fsm.Event) {
 	//mutex protection is required for possible concurrent access to FSM members
 	oFsm.mutexFlowParams.Lock()
-	if oFsm.uniFlowParamsSlice[0].SetVid == uint32(of.OfpVlanId_OFPVID_PRESENT) {
+	if oFsm.uniVlanFlowParamsSlice[0].VlanRuleParams.SetVid == uint32(of.OfpVlanId_OFPVID_PRESENT) {
 		// meaning transparent setup - no specific VTFD setting required
 		oFsm.mutexFlowParams.Unlock()
 		logger.Debugw("UniVlanConfigFsm: no VTFD config required", log.Fields{
-			"in state": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
+			"in state": e.FSM.Current(), "device-id": oFsm.deviceID})
 		// let the FSM proceed ... (from within this state all internal pointers may be expected to be correct)
 		// obviously calling some FSM event here directly does not work - so trying to decouple it ...
 		pConfigVlanStateAFsm := oFsm.pAdaptFsm
@@ -335,10 +557,11 @@
 	} else {
 		logger.Debugw("UniVlanConfigFsm create VTFD", log.Fields{
 			"EntitytId": strconv.FormatInt(int64(oFsm.vtfdID), 16),
-			"in state":  e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
-		oFsm.vlanFilterList[0] = uint16(oFsm.uniFlowParamsSlice[0].SetVid) // setVid is assumed to be masked already by the caller to 12 bit
+			"in state":  e.FSM.Current(), "device-id": oFsm.deviceID})
+		// setVid is assumed to be masked already by the caller to 12 bit
+		oFsm.vlanFilterList[0] = uint16(oFsm.uniVlanFlowParamsSlice[0].VlanRuleParams.SetVid)
 		oFsm.mutexFlowParams.Unlock()
-		vtfdFilterList := make([]uint16, 12) //needed for parameter serialization
+		vtfdFilterList := make([]uint16, cVtfdTableSize) //needed for parameter serialization
 		vtfdFilterList[0] = oFsm.vlanFilterList[0]
 		oFsm.numVlanFilterEntries = 1
 		meParams := me.ParamData{
@@ -350,7 +573,7 @@
 			},
 		}
 		logger.Debugw("UniVlanConfigFsm sendcreate VTFD", log.Fields{
-			"in state": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
+			"in state": e.FSM.Current(), "device-id": oFsm.deviceID})
 		meInstance := oFsm.pOmciCC.sendCreateVtfdVar(context.TODO(), ConstDefaultOmciTimeout, true,
 			oFsm.pAdaptFsm.commChan, meParams)
 		//accept also nil as (error) return value for writing to LastTx
@@ -358,24 +581,31 @@
 		//TODO!!: refactoring improvement requested, here as an example for [VOL-3457]:
 		//  send shall return (dual format) error code that can be used here for immediate error treatment
 		//  (relevant to all used sendXX() methods in this (and other) FSM's)
-		oFsm.pOmciCC.pLastTxMeInstance = meInstance
+		oFsm.pLastTxMeInstance = meInstance
 	}
 }
 
 func (oFsm *UniVlanConfigFsm) enterConfigEvtocd(e *fsm.Event) {
 	logger.Debugw("UniVlanConfigFsm - start config EVTOCD loop", log.Fields{
-		"in state": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
+		"in state": e.FSM.Current(), "device-id": oFsm.deviceID})
 	go oFsm.performConfigEvtocdEntries(0)
 }
 
 func (oFsm *UniVlanConfigFsm) enterVlanConfigDone(e *fsm.Event) {
 	logger.Debugw("UniVlanConfigFsm - checking on more flows", log.Fields{
-		"in state": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
-	oFsm.configuredUniFlow++ // one (more) flow configured
+		"in state": e.FSM.Current(), "device-id": oFsm.deviceID})
+	pConfigVlanStateBaseFsm := oFsm.pAdaptFsm.pFsm
+	if len(oFsm.uniRemoveFlowsSlice) > 0 {
+		//some further flows are to be removed, removal always starts with the first element
+		// calling some FSM event must be decoupled
+		go func(a_pBaseFsm *fsm.FSM) {
+			_ = a_pBaseFsm.Event(vlanEvRemFlowConfig)
+		}(pConfigVlanStateBaseFsm)
+		return
+	}
 	if oFsm.numUniFlows > oFsm.configuredUniFlow {
 		//some further flows are to be configured
 		// calling some FSM event must be decoupled
-		pConfigVlanStateBaseFsm := oFsm.pAdaptFsm.pFsm
 		go func(a_pBaseFsm *fsm.FSM) {
 			_ = a_pBaseFsm.Event(vlanEvIncrFlowConfig)
 		}(pConfigVlanStateBaseFsm)
@@ -383,7 +613,7 @@
 	}
 
 	logger.Debugw("UniVlanConfigFsm - VLAN config done: send dh event notification", log.Fields{
-		"device-id": oFsm.pAdaptFsm.deviceID})
+		"device-id": oFsm.deviceID})
 	// it might appear that some flows are requested also after 'flowPushed' event has been generated ...
 	// state transition notification is checked in deviceHandler
 	if oFsm.pDeviceHandler != nil {
@@ -394,23 +624,24 @@
 func (oFsm *UniVlanConfigFsm) enterConfigIncrFlow(e *fsm.Event) {
 	logger.Debugw("UniVlanConfigFsm - start config further incremental flow", log.Fields{
 		"in state": e.FSM.Current(), "recent flow-number": (oFsm.configuredUniFlow),
-		"device-id": oFsm.pAdaptFsm.deviceID})
+		"device-id": oFsm.deviceID})
 	oFsm.mutexFlowParams.Lock()
 
-	if oFsm.uniFlowParamsSlice[oFsm.configuredUniFlow].SetVid == uint32(of.OfpVlanId_OFPVID_PRESENT) {
+	if oFsm.uniVlanFlowParamsSlice[oFsm.configuredUniFlow].VlanRuleParams.SetVid == uint32(of.OfpVlanId_OFPVID_PRESENT) {
 		// meaning transparent setup - no specific VTFD setting required
 		oFsm.mutexFlowParams.Unlock()
 		logger.Debugw("UniVlanConfigFsm: no VTFD config required", log.Fields{
-			"in state": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
+			"in state": e.FSM.Current(), "device-id": oFsm.deviceID})
 	} else {
 		if oFsm.numVlanFilterEntries == 0 {
 			//no VTFD yet created
 			logger.Debugw("UniVlanConfigFsm create VTFD", log.Fields{
 				"EntitytId": strconv.FormatInt(int64(oFsm.vtfdID), 16),
-				"in state":  e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
-			oFsm.vlanFilterList[0] = uint16(oFsm.uniFlowParamsSlice[oFsm.configuredUniFlow].SetVid) // setVid is assumed to be masked already by the caller to 12 bit
+				"in state":  e.FSM.Current(), "device-id": oFsm.deviceID})
+			// setVid is assumed to be masked already by the caller to 12 bit
+			oFsm.vlanFilterList[0] = uint16(oFsm.uniVlanFlowParamsSlice[oFsm.configuredUniFlow].VlanRuleParams.SetVid)
 			oFsm.mutexFlowParams.Unlock()
-			vtfdFilterList := make([]uint16, 12) //needed for parameter serialization
+			vtfdFilterList := make([]uint16, cVtfdTableSize) //needed for parameter serialization
 			vtfdFilterList[0] = oFsm.vlanFilterList[0]
 			oFsm.numVlanFilterEntries = 1
 			meParams := me.ParamData{
@@ -428,18 +659,18 @@
 			//TODO!!: refactoring improvement requested, here as an example for [VOL-3457]:
 			//  send shall return (dual format) error code that can be used here for immediate error treatment
 			//  (relevant to all used sendXX() methods in this (and other) FSM's)
-			oFsm.pOmciCC.pLastTxMeInstance = meInstance
+			oFsm.pLastTxMeInstance = meInstance
 		} else {
 			//VTFD already exists - just modify by 'set'
 			//TODO!!: but only if the VID is not already present, skipped by now to test basic working
 			logger.Debugw("UniVlanConfigFsm set VTFD", log.Fields{
 				"EntitytId": strconv.FormatInt(int64(oFsm.vtfdID), 16),
-				"in state":  e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
+				"in state":  e.FSM.Current(), "device-id": oFsm.deviceID})
 			// setVid is assumed to be masked already by the caller to 12 bit
 			oFsm.vlanFilterList[oFsm.numVlanFilterEntries] =
-				uint16(oFsm.uniFlowParamsSlice[oFsm.configuredUniFlow].SetVid)
+				uint16(oFsm.uniVlanFlowParamsSlice[oFsm.configuredUniFlow].VlanRuleParams.SetVid)
 			oFsm.mutexFlowParams.Unlock()
-			vtfdFilterList := make([]uint16, 12) //needed for parameter serialization
+			vtfdFilterList := make([]uint16, cVtfdTableSize) //needed for parameter serialization
 			for i := uint8(0); i <= oFsm.numVlanFilterEntries; i++ {
 				vtfdFilterList[i] = oFsm.vlanFilterList[i]
 			}
@@ -459,13 +690,13 @@
 			//TODO!!: refactoring improvement requested, here as an example for [VOL-3457]:
 			//  send shall return (dual format) error code that can be used here for immediate error treatment
 			//  (relevant to all used sendXX() methods in this (and other) FSM's)
-			oFsm.pOmciCC.pLastTxMeInstance = meInstance
+			oFsm.pLastTxMeInstance = meInstance
 		}
 		//verify response
 		err := oFsm.waitforOmciResponse()
 		if err != nil {
 			logger.Errorw("VTFD create/set failed, aborting VlanConfig FSM!",
-				log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+				log.Fields{"device-id": oFsm.deviceID})
 			_ = oFsm.pAdaptFsm.pFsm.Event(vlanEvReset)
 			return
 		}
@@ -473,37 +704,141 @@
 	go oFsm.performConfigEvtocdEntries(oFsm.configuredUniFlow)
 }
 
-func (oFsm *UniVlanConfigFsm) enterCleanVtfd(e *fsm.Event) {
-	logger.Debugw("UniVlanConfigFsm Tx Delete::VTFD", log.Fields{
-		/*"EntitytId": strconv.FormatInt(int64(oFsm.mapperSP0ID), 16),*/
-		"in state": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
-}
+func (oFsm *UniVlanConfigFsm) enterRemoveFlow(e *fsm.Event) {
+	oFsm.mutexFlowParams.Lock()
+	logger.Debugw("UniVlanConfigFsm - start removing the top remove-flow", log.Fields{
+		"in state": e.FSM.Current(), "with last cookie": oFsm.uniRemoveFlowsSlice[0].cookie,
+		"device-id": oFsm.deviceID})
 
-func (oFsm *UniVlanConfigFsm) enterCleanEvtocd(e *fsm.Event) {
-	logger.Debugw("UniVlanConfigFsm  cleanup EVTOCD", log.Fields{
-		/*"EntitytId": strconv.FormatInt(int64(oFsm.macBPCD0ID), 16),
-		"TPPtr":     strconv.FormatInt(int64(oFsm.mapperSP0ID), 16),*/
-		"in state": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
+	loVlanEntryClear := uint8(0)
+	loVlanEntryRmPos := uint8(0x80) //with indication 'invalid' in bit 7
+	//shallow copy is sufficient as no reference variables are used within struct
+	loRuleParams := oFsm.uniRemoveFlowsSlice[0].vlanRuleParams
+	oFsm.mutexFlowParams.Unlock()
+	logger.Debugw("UniVlanConfigFsm - remove-flow parameters are", log.Fields{
+		"match vid": loRuleParams.MatchVid, "match Pcp": loRuleParams.MatchPcp,
+		"set vid":   strconv.FormatInt(int64(loRuleParams.SetVid), 16),
+		"device-id": oFsm.deviceID})
+
+	if loRuleParams.SetVid == uint32(of.OfpVlanId_OFPVID_PRESENT) {
+		// meaning transparent setup - no specific VTFD setting required
+		logger.Debugw("UniVlanConfigFsm: no VTFD removal required for transparent flow", log.Fields{
+			"in state": e.FSM.Current(), "device-id": oFsm.deviceID})
+	} else {
+		vtfdFilterList := make([]uint16, cVtfdTableSize) //needed for parameter serialization and 're-copy'
+		if oFsm.numVlanFilterEntries == 1 {
+			//only one active VLAN entry (hopefully the SetVID we want to remove - should be, but not verified ..)
+			//  so we can just delete the VTFD entry
+			logger.Debugw("UniVlanConfigFsm: VTFD delete (no more vlan filters)",
+				log.Fields{"current vlan list": oFsm.vlanFilterList,
+					"in state": e.FSM.Current(), "device-id": oFsm.deviceID})
+			loVlanEntryClear = 1 //full VlanFilter clear request
+			meInstance := oFsm.pOmciCC.sendDeleteVtfd(context.TODO(), ConstDefaultOmciTimeout, true,
+				oFsm.pAdaptFsm.commChan, oFsm.vtfdID)
+			oFsm.pLastTxMeInstance = meInstance
+		} else {
+			//many VTFD already should exists - find and remove the one concerned by the actual remove rule
+			//  by updating the VTFD per set command with new valid list
+			logger.Debugw("UniVlanConfigFsm: VTFD removal of requested VLAN from the list on OMCI",
+				log.Fields{"current vlan list": oFsm.vlanFilterList,
+					"set-vlan": loRuleParams.SetVid, "device-id": oFsm.deviceID})
+			for i := uint8(0); i < oFsm.numVlanFilterEntries; i++ {
+				if loRuleParams.SetVid == uint32(oFsm.vlanFilterList[i]) {
+					loVlanEntryRmPos = i
+					break //abort search
+				}
+			}
+			if loVlanEntryRmPos < cVtfdTableSize {
+				//valid entry was found - to be eclipsed
+				loVlanEntryClear = 2 //VlanFilter remove request for a specific entry
+				for i := uint8(0); i < oFsm.numVlanFilterEntries; i++ {
+					if i < loVlanEntryRmPos {
+						vtfdFilterList[i] = oFsm.vlanFilterList[i] //copy original
+					} else if i < (cVtfdTableSize - 1) {
+						vtfdFilterList[i] = oFsm.vlanFilterList[i+1] //copy successor (including 0 elements)
+					} else {
+						vtfdFilterList[i] = 0 //set last byte if needed
+					}
+				}
+				logger.Debugw("UniVlanConfigFsm set VTFD", log.Fields{
+					"EntitytId":     strconv.FormatInt(int64(oFsm.vtfdID), 16),
+					"new vlan list": vtfdFilterList, "device-id": oFsm.deviceID})
+
+				meParams := me.ParamData{
+					EntityID: oFsm.vtfdID,
+					Attributes: me.AttributeValueMap{
+						"VlanFilterList":  vtfdFilterList,
+						"NumberOfEntries": (oFsm.numVlanFilterEntries - 1), //one element less
+					},
+				}
+				meInstance := oFsm.pOmciCC.sendSetVtfdVar(context.TODO(), ConstDefaultOmciTimeout, true,
+					oFsm.pAdaptFsm.commChan, meParams)
+				oFsm.pLastTxMeInstance = meInstance
+			} else {
+				logger.Warnw("UniVlanConfigFsm: requested VLAN for removal not found in list - ignore and continue (no VTFD set)",
+					log.Fields{"device-id": oFsm.deviceID})
+			}
+		}
+		if loVlanEntryClear > 0 {
+			//waiting on response
+			err := oFsm.waitforOmciResponse()
+			if err != nil {
+				logger.Errorw("VTFD delete/reset failed, aborting VlanConfig FSM!",
+					log.Fields{"device-id": oFsm.deviceID})
+				_ = oFsm.pAdaptFsm.pFsm.Event(vlanEvReset)
+				return
+			}
+
+			if loVlanEntryClear == 1 {
+				oFsm.vlanFilterList[0] = 0 //first entry is the only that can contain the previous only-one element
+				oFsm.numVlanFilterEntries = 0
+			} else if loVlanEntryClear == 2 {
+				// new VlanFilterList should be one entry smaller now - copy from last configured entry
+				// this loop now includes the 0 element on previous last valid entry
+				for i := uint8(0); i <= oFsm.numVlanFilterEntries; i++ {
+					oFsm.vlanFilterList[i] = vtfdFilterList[i]
+				}
+				oFsm.numVlanFilterEntries--
+			}
+		}
+	}
+
+	go oFsm.removeEvtocdEntries(loRuleParams)
 }
 
 func (oFsm *UniVlanConfigFsm) enterVlanCleanupDone(e *fsm.Event) {
-	logger.Debugw("UniVlanConfigFsm - VLAN cleanup done", log.Fields{
-		"in state": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
+	logger.Debugw("UniVlanConfigFsm - removing the removal data", log.Fields{
+		"in state": e.FSM.Current(), "device-id": oFsm.deviceID})
 
-	//let's reset the state machine in order to release all resources now
+	oFsm.mutexFlowParams.Lock()
+	if len(oFsm.uniRemoveFlowsSlice) <= 1 {
+		oFsm.uniRemoveFlowsSlice = nil //reset the slice
+		logger.Debugw("UniVlanConfigFsm flow removal - last remove-flow deleted", log.Fields{
+			"device-id": oFsm.deviceID})
+	} else {
+		//cut off the actual flow by slicing out the first element
+		oFsm.uniRemoveFlowsSlice = append(
+			oFsm.uniRemoveFlowsSlice[:0],
+			oFsm.uniRemoveFlowsSlice[1:]...)
+		logger.Debugw("UniVlanConfigFsm flow removal - specific flow deleted from data", log.Fields{
+			"device-id": oFsm.deviceID})
+	}
+	oFsm.mutexFlowParams.Unlock()
+
+	//return to the basic config verification state
 	pConfigVlanStateAFsm := oFsm.pAdaptFsm
 	if pConfigVlanStateAFsm != nil {
 		// obviously calling some FSM event here directly does not work - so trying to decouple it ...
 		go func(a_pAFsm *AdapterFsm) {
 			if a_pAFsm != nil && a_pAFsm.pFsm != nil {
-				_ = a_pAFsm.pFsm.Event(vlanEvReset)
+				_ = a_pAFsm.pFsm.Event(vlanEvFlowDataRemoved)
 			}
 		}(pConfigVlanStateAFsm)
 	}
 }
 
 func (oFsm *UniVlanConfigFsm) enterResetting(e *fsm.Event) {
-	logger.Debugw("UniVlanConfigFsm resetting", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+	logger.Debugw("UniVlanConfigFsm resetting", log.Fields{"device-id": oFsm.deviceID})
 
 	pConfigVlanStateAFsm := oFsm.pAdaptFsm
 	if pConfigVlanStateAFsm != nil {
@@ -526,7 +861,8 @@
 }
 
 func (oFsm *UniVlanConfigFsm) enterDisabled(e *fsm.Event) {
-	logger.Debugw("UniVlanConfigFsm enters disabled state", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+	logger.Debugw("UniVlanConfigFsm enters disabled state", log.Fields{"device-id": oFsm.deviceID})
+	oFsm.pLastTxMeInstance = nil
 	if oFsm.pDeviceHandler != nil {
 		//request removal of 'reference' in the Handler (completely clear the FSM)
 		go oFsm.pDeviceHandler.RemoveVlanFilterFsm(oFsm.pOnuUniPort)
@@ -534,107 +870,76 @@
 }
 
 func (oFsm *UniVlanConfigFsm) processOmciVlanMessages() { //ctx context.Context?
-	logger.Debugw("Start UniVlanConfigFsm Msg processing", log.Fields{"for device-id": oFsm.pAdaptFsm.deviceID})
+	logger.Debugw("Start UniVlanConfigFsm Msg processing", log.Fields{"for device-id": oFsm.deviceID})
 loop:
 	for {
 		// case <-ctx.Done():
-		// 	logger.Info("MibSync Msg", log.Fields{"Message handling canceled via context for device-id": oFsm.pAdaptFsm.deviceID})
+		// 	logger.Info("MibSync Msg", log.Fields{"Message handling canceled via context for device-id": oFsm.deviceID})
 		// 	break loop
 		message, ok := <-oFsm.pAdaptFsm.commChan
 		if !ok {
-			logger.Info("UniVlanConfigFsm Rx Msg - could not read from channel", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+			logger.Info("UniVlanConfigFsm Rx Msg - could not read from channel", log.Fields{"device-id": oFsm.deviceID})
 			// but then we have to ensure a restart of the FSM as well - as exceptional procedure
 			_ = oFsm.pAdaptFsm.pFsm.Event(vlanEvReset)
 			break loop
 		}
-		logger.Debugw("UniVlanConfigFsm Rx Msg", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+		logger.Debugw("UniVlanConfigFsm Rx Msg", log.Fields{"device-id": oFsm.deviceID})
 
 		switch message.Type {
 		case TestMsg:
 			msg, _ := message.Data.(TestMessage)
 			if msg.TestMessageVal == AbortMessageProcessing {
-				logger.Infow("UniVlanConfigFsm abort ProcessMsg", log.Fields{"for device-id": oFsm.pAdaptFsm.deviceID})
+				logger.Infow("UniVlanConfigFsm abort ProcessMsg", log.Fields{"for device-id": oFsm.deviceID})
 				break loop
 			}
-			logger.Warnw("UniVlanConfigFsm unknown TestMessage", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID, "MessageVal": msg.TestMessageVal})
+			logger.Warnw("UniVlanConfigFsm unknown TestMessage", log.Fields{"device-id": oFsm.deviceID, "MessageVal": msg.TestMessageVal})
 		case OMCI:
 			msg, _ := message.Data.(OmciMessage)
 			oFsm.handleOmciVlanConfigMessage(msg)
 		default:
-			logger.Warn("UniVlanConfigFsm Rx unknown message", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID,
+			logger.Warn("UniVlanConfigFsm Rx unknown message", log.Fields{"device-id": oFsm.deviceID,
 				"message.Type": message.Type})
 		}
 	}
-	logger.Infow("End UniVlanConfigFsm Msg processing", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+	logger.Infow("End UniVlanConfigFsm Msg processing", log.Fields{"device-id": oFsm.deviceID})
 }
 
 func (oFsm *UniVlanConfigFsm) handleOmciVlanConfigMessage(msg OmciMessage) {
-	logger.Debugw("Rx OMCI UniVlanConfigFsm Msg", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID,
+	logger.Debugw("Rx OMCI UniVlanConfigFsm Msg", log.Fields{"device-id": oFsm.deviceID,
 		"msgType": msg.OmciMsg.MessageType})
 
 	switch msg.OmciMsg.MessageType {
 	case omci.CreateResponseType:
-		{
-			msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeCreateResponse)
-			if msgLayer == nil {
-				logger.Errorw("Omci Msg layer could not be detected for CreateResponse",
-					log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+		{ // had to shift that to a method to cope with StaticCodeAnalysis restrictions :-(
+			if err := oFsm.handleOmciCreateResponseMessage(msg.OmciPacket); err != nil {
+				logger.Warnw("CreateResponse handling aborted", log.Fields{"err": err})
 				return
 			}
-			msgObj, msgOk := msgLayer.(*omci.CreateResponse)
-			if !msgOk {
-				logger.Errorw("Omci Msg layer could not be assigned for CreateResponse",
-					log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
-				return
-			}
-			logger.Debugw("CreateResponse Data", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID, "data-fields": msgObj})
-			if msgObj.Result != me.Success {
-				logger.Errorw("Omci CreateResponse Error - later: drive FSM to abort state ?", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID,
-					"Error": msgObj.Result})
-				// possibly force FSM into abort or ignore some errors for some messages? store error for mgmt display?
-				return
-			}
-			if msgObj.EntityClass == oFsm.pOmciCC.pLastTxMeInstance.GetClassID() &&
-				msgObj.EntityInstance == oFsm.pOmciCC.pLastTxMeInstance.GetEntityID() {
-				// maybe we can use just the same eventName for different state transitions like "forward"
-				//   - might be checked, but so far I go for sure and have to inspect the concrete state events ...
-				switch oFsm.pOmciCC.pLastTxMeInstance.GetName() {
-				case "VlanTaggingFilterData":
-					{
-						if oFsm.configuredUniFlow == 0 {
-							// Only if CreateResponse is received from first flow entry - let the FSM proceed ...
-							_ = oFsm.pAdaptFsm.pFsm.Event(vlanEvRxConfigVtfd)
-						} else { // let the MultiEntity config proceed by stopping the wait function
-							oFsm.omciMIdsResponseReceived <- true
-						}
-					}
-				}
-			}
 		} //CreateResponseType
 	case omci.SetResponseType:
-		{
+		{ //leave that here as direct code as most often used
 			msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeSetResponse)
 			if msgLayer == nil {
-				logger.Errorw("UniVlanConfigFsm - Omci Msg layer could not be detected for SetResponse",
-					log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+				logger.Errorw("Omci Msg layer could not be detected for SetResponse",
+					log.Fields{"device-id": oFsm.deviceID})
 				return
 			}
 			msgObj, msgOk := msgLayer.(*omci.SetResponse)
 			if !msgOk {
-				logger.Errorw("UniVlanConfigFsm - Omci Msg layer could not be assigned for SetResponse",
-					log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+				logger.Errorw("Omci Msg layer could not be assigned for SetResponse",
+					log.Fields{"device-id": oFsm.deviceID})
 				return
 			}
-			logger.Debugw("UniVlanConfigFsm SetResponse Data", log.Fields{"deviceId": oFsm.pAdaptFsm.deviceID, "data-fields": msgObj})
+			logger.Debugw("UniVlanConfigFsm SetResponse Data", log.Fields{"device-id": oFsm.deviceID, "data-fields": msgObj})
 			if msgObj.Result != me.Success {
-				logger.Errorw("UniVlanConfigFsm - Omci SetResponse Error - later: drive FSM to abort state ?",
-					log.Fields{"deviceId": oFsm.pAdaptFsm.deviceID, "Error": msgObj.Result})
+				logger.Errorw("UniVlanConfigFsm Omci SetResponse Error - later: drive FSM to abort state ?",
+					log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
 				// possibly force FSM into abort or ignore some errors for some messages? store error for mgmt display?
 				return
 			}
-			if msgObj.EntityClass == oFsm.pOmciCC.pLastTxMeInstance.GetClassID() &&
-				msgObj.EntityInstance == oFsm.pOmciCC.pLastTxMeInstance.GetEntityID() {
-				switch oFsm.pOmciCC.pLastTxMeInstance.GetName() {
+			if msgObj.EntityClass == oFsm.pLastTxMeInstance.GetClassID() &&
+				msgObj.EntityInstance == oFsm.pLastTxMeInstance.GetEntityID() {
+				switch oFsm.pLastTxMeInstance.GetName() {
 				case "VlanTaggingFilterData",
 					"ExtendedVlanTaggingOperationConfigurationData":
 					{ // let the MultiEntity config proceed by stopping the wait function
@@ -643,15 +948,98 @@
 				}
 			}
 		} //SetResponseType
+	case omci.DeleteResponseType:
+		{ // had to shift that to a method to cope with StaticCodeAnalysis restrictions :-(
+			if err := oFsm.handleOmciDeleteResponseMessage(msg.OmciPacket); err != nil {
+				logger.Warnw("DeleteResponse handling aborted", log.Fields{"err": err})
+				return
+			}
+		} //DeleteResponseType
 	default:
 		{
-			logger.Errorw("UniVlanConfigFsm - Rx OMCI unhandled MsgType",
-				log.Fields{"omciMsgType": msg.OmciMsg.MessageType, "deviceId": oFsm.pAdaptFsm.deviceID})
+			logger.Errorw("Rx OMCI unhandled MsgType",
+				log.Fields{"omciMsgType": msg.OmciMsg.MessageType, "device-id": oFsm.deviceID})
 			return
 		}
 	}
 }
 
+func (oFsm *UniVlanConfigFsm) handleOmciCreateResponseMessage(apOmciPacket *gp.Packet) error {
+	msgLayer := (*apOmciPacket).Layer(omci.LayerTypeCreateResponse)
+	if msgLayer == nil {
+		logger.Errorw("Omci Msg layer could not be detected for CreateResponse",
+			log.Fields{"device-id": oFsm.deviceID})
+		return fmt.Errorf("omci msg layer could not be detected for CreateResponse for device-id %x",
+			oFsm.deviceID)
+	}
+	msgObj, msgOk := msgLayer.(*omci.CreateResponse)
+	if !msgOk {
+		logger.Errorw("Omci Msg layer could not be assigned for CreateResponse",
+			log.Fields{"device-id": oFsm.deviceID})
+		return fmt.Errorf("omci msg layer could not be assigned for CreateResponse for device-id %x",
+			oFsm.deviceID)
+	}
+	logger.Debugw("UniVlanConfigFsm CreateResponse Data", log.Fields{"device-id": oFsm.deviceID, "data-fields": msgObj})
+	if msgObj.Result != me.Success {
+		logger.Errorw("Omci CreateResponse Error - later: drive FSM to abort state ?", log.Fields{"device-id": oFsm.deviceID,
+			"Error": msgObj.Result})
+		// possibly force FSM into abort or ignore some errors for some messages? store error for mgmt display?
+		return fmt.Errorf("omci CreateResponse Error for device-id %x",
+			oFsm.deviceID)
+	}
+	if msgObj.EntityClass == oFsm.pLastTxMeInstance.GetClassID() &&
+		msgObj.EntityInstance == oFsm.pLastTxMeInstance.GetEntityID() {
+		// to satisfy StaticCodeAnalysis I had to move the small processing into a separate method :-(
+		switch oFsm.pLastTxMeInstance.GetName() {
+		case "VlanTaggingFilterData":
+			{
+				if oFsm.pAdaptFsm.pFsm.Current() == vlanStConfigVtfd {
+					// Only if CreateResponse is received from first flow entry - let the FSM proceed ...
+					_ = oFsm.pAdaptFsm.pFsm.Event(vlanEvRxConfigVtfd)
+				} else { // let the MultiEntity config proceed by stopping the wait function
+					oFsm.omciMIdsResponseReceived <- true
+				}
+			}
+		}
+	}
+	return nil
+}
+
+func (oFsm *UniVlanConfigFsm) handleOmciDeleteResponseMessage(apOmciPacket *gp.Packet) error {
+	msgLayer := (*apOmciPacket).Layer(omci.LayerTypeDeleteResponse)
+	if msgLayer == nil {
+		logger.Errorw("UniVlanConfigFsm - Omci Msg layer could not be detected for DeleteResponse",
+			log.Fields{"device-id": oFsm.deviceID})
+		return fmt.Errorf("omci msg layer could not be detected for DeleteResponse for device-id %x",
+			oFsm.deviceID)
+	}
+	msgObj, msgOk := msgLayer.(*omci.DeleteResponse)
+	if !msgOk {
+		logger.Errorw("UniVlanConfigFsm - Omci Msg layer could not be assigned for DeleteResponse",
+			log.Fields{"device-id": oFsm.deviceID})
+		return fmt.Errorf("omci msg layer could not be assigned for DeleteResponse for device-id %x",
+			oFsm.deviceID)
+	}
+	logger.Debugw("UniVlanConfigFsm DeleteResponse Data", log.Fields{"device-id": oFsm.deviceID, "data-fields": msgObj})
+	if msgObj.Result != me.Success {
+		logger.Errorw("UniVlanConfigFsm - Omci DeleteResponse Error - later: drive FSM to abort state ?",
+			log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
+		// possibly force FSM into abort or ignore some errors for some messages? store error for mgmt display?
+		return fmt.Errorf("omci DeleteResponse Error for device-id %x",
+			oFsm.deviceID)
+	}
+	if msgObj.EntityClass == oFsm.pLastTxMeInstance.GetClassID() &&
+		msgObj.EntityInstance == oFsm.pLastTxMeInstance.GetEntityID() {
+		switch oFsm.pLastTxMeInstance.GetName() {
+		case "VlanTaggingFilterData":
+			{ // let the MultiEntity config proceed by stopping the wait function
+				oFsm.omciMIdsResponseReceived <- true
+			}
+		}
+	}
+	return nil
+}
+
 func (oFsm *UniVlanConfigFsm) performConfigEvtocdEntries(aFlowEntryNo uint8) {
 	if aFlowEntryNo == 0 {
 		// EthType set only at first flow element
@@ -660,7 +1048,7 @@
 		logger.Debugw("UniVlanConfigFsm Tx Set::EVTOCD", log.Fields{
 			"EntitytId":  strconv.FormatInt(int64(oFsm.evtocdID), 16),
 			"i/oEthType": strconv.FormatInt(int64(cDefaultTpid), 16),
-			"device-id":  oFsm.pAdaptFsm.deviceID})
+			"device-id":  oFsm.deviceID})
 		meParams := me.ParamData{
 			EntityID: oFsm.evtocdID,
 			Attributes: me.AttributeValueMap{
@@ -673,24 +1061,24 @@
 			oFsm.pAdaptFsm.commChan, meParams)
 		//accept also nil as (error) return value for writing to LastTx
 		//  - this avoids misinterpretation of new received OMCI messages
-		oFsm.pOmciCC.pLastTxMeInstance = meInstance
+		oFsm.pLastTxMeInstance = meInstance
 
 		//verify response
 		err := oFsm.waitforOmciResponse()
 		if err != nil {
 			logger.Errorw("Evtocd set TPID failed, aborting VlanConfig FSM!",
-				log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+				log.Fields{"device-id": oFsm.deviceID})
 			_ = oFsm.pAdaptFsm.pFsm.Event(vlanEvReset)
 			return
 		}
 	} //first flow element
 
 	oFsm.mutexFlowParams.Lock()
-	if oFsm.uniFlowParamsSlice[aFlowEntryNo].SetVid == uint32(of.OfpVlanId_OFPVID_PRESENT) {
+	if oFsm.uniVlanFlowParamsSlice[aFlowEntryNo].VlanRuleParams.SetVid == uint32(of.OfpVlanId_OFPVID_PRESENT) {
 		//transparent transmission required
 		oFsm.mutexFlowParams.Unlock()
 		logger.Debugw("UniVlanConfigFsm Tx Set::EVTOCD single tagged transparent rule", log.Fields{
-			"device-id": oFsm.pAdaptFsm.deviceID})
+			"device-id": oFsm.deviceID})
 		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:],
@@ -725,13 +1113,13 @@
 			oFsm.pAdaptFsm.commChan, meParams)
 		//accept also nil as (error) return value for writing to LastTx
 		//  - this avoids misinterpretation of new received OMCI messages
-		oFsm.pOmciCC.pLastTxMeInstance = meInstance
+		oFsm.pLastTxMeInstance = meInstance
 
 		//verify response
 		err := oFsm.waitforOmciResponse()
 		if err != nil {
 			logger.Errorw("Evtocd set transparent singletagged rule failed, aborting VlanConfig FSM!",
-				log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+				log.Fields{"device-id": oFsm.deviceID})
 			_ = oFsm.pAdaptFsm.pFsm.Event(vlanEvReset)
 			return
 		}
@@ -740,7 +1128,7 @@
 		if oFsm.acceptIncrementalEvtoOption {
 			// this defines VID translation scenario: singletagged->singletagged (if not transparent)
 			logger.Debugw("UniVlanConfigFsm Tx Set::EVTOCD single tagged translation rule", log.Fields{
-				"device-id": oFsm.pAdaptFsm.deviceID})
+				"device-id": oFsm.deviceID})
 			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:],
@@ -749,20 +1137,20 @@
 					cDoNotFilterTPID<<cFilterTpidOffset) // Do not filter on outer TPID field
 
 			binary.BigEndian.PutUint32(sliceEvtocdRule[cFilterInnerOffset:],
-				oFsm.uniFlowParamsSlice[aFlowEntryNo].MatchPcp<<cFilterPrioOffset| // either DNFonPrio or ignore tag (default) on innerVLAN
-					oFsm.uniFlowParamsSlice[aFlowEntryNo].MatchVid<<cFilterVidOffset| // either DNFonVid or real filter VID
+				oFsm.uniVlanFlowParamsSlice[aFlowEntryNo].VlanRuleParams.MatchPcp<<cFilterPrioOffset| // either DNFonPrio or ignore tag (default) on innerVLAN
+					oFsm.uniVlanFlowParamsSlice[aFlowEntryNo].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[cTreatOuterOffset:],
-				oFsm.uniFlowParamsSlice[aFlowEntryNo].TagsToRemove<<cTreatTTROffset| // either 1 or 0
+				oFsm.uniVlanFlowParamsSlice[aFlowEntryNo].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.uniFlowParamsSlice[aFlowEntryNo].SetPcp<<cTreatPrioOffset| // as configured in flow
-					oFsm.uniFlowParamsSlice[aFlowEntryNo].SetVid<<cTreatVidOffset| //as configured in flow
+				oFsm.uniVlanFlowParamsSlice[aFlowEntryNo].VlanRuleParams.SetPcp<<cTreatPrioOffset| // as configured in flow
+					oFsm.uniVlanFlowParamsSlice[aFlowEntryNo].VlanRuleParams.SetVid<<cTreatVidOffset| //as configured in flow
 					cSetOutputTpidCopyDei<<cTreatTpidOffset) // Set TPID = 0x8100
 			oFsm.mutexFlowParams.Unlock()
 
@@ -776,13 +1164,13 @@
 				oFsm.pAdaptFsm.commChan, meParams)
 			//accept also nil as (error) return value for writing to LastTx
 			//  - this avoids misinterpretation of new received OMCI messages
-			oFsm.pOmciCC.pLastTxMeInstance = meInstance
+			oFsm.pLastTxMeInstance = meInstance
 
 			//verify response
 			err := oFsm.waitforOmciResponse()
 			if err != nil {
 				logger.Errorw("Evtocd set singletagged translation rule failed, aborting VlanConfig FSM!",
-					log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+					log.Fields{"device-id": oFsm.deviceID})
 				_ = oFsm.pAdaptFsm.pFsm.Event(vlanEvReset)
 				return
 			}
@@ -791,7 +1179,7 @@
 			{ // just for local var's
 				// this defines stacking scenario: untagged->singletagged
 				logger.Debugw("UniVlanConfigFsm Tx Set::EVTOCD untagged->singletagged rule", log.Fields{
-					"device-id": oFsm.pAdaptFsm.deviceID})
+					"device-id": oFsm.deviceID})
 				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:],
@@ -814,7 +1202,7 @@
 				binary.BigEndian.PutUint32(sliceEvtocdRule[cTreatInnerOffset:],
 					0<<cTreatPrioOffset| // vlan prio set to 0
 						//   (as done in Py code, maybe better option would be setPcp here, which still could be 0?)
-						oFsm.uniFlowParamsSlice[aFlowEntryNo].SetVid<<cTreatVidOffset| // Outer VID don't care
+						oFsm.uniVlanFlowParamsSlice[aFlowEntryNo].VlanRuleParams.SetVid<<cTreatVidOffset| // Outer VID don't care
 						cSetOutputTpidCopyDei<<cTreatTpidOffset) // Set TPID = 0x8100
 
 				oFsm.mutexFlowParams.Unlock()
@@ -828,13 +1216,13 @@
 					oFsm.pAdaptFsm.commChan, meParams)
 				//accept also nil as (error) return value for writing to LastTx
 				//  - this avoids misinterpretation of new received OMCI messages
-				oFsm.pOmciCC.pLastTxMeInstance = meInstance
+				oFsm.pLastTxMeInstance = meInstance
 
 				//verify response
 				err := oFsm.waitforOmciResponse()
 				if err != nil {
 					logger.Errorw("Evtocd set untagged->singletagged rule failed, aborting VlanConfig FSM!",
-						log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+						log.Fields{"device-id": oFsm.deviceID})
 					_ = oFsm.pAdaptFsm.pFsm.Event(vlanEvReset)
 					return
 				}
@@ -842,7 +1230,7 @@
 			{ // just for local var's
 				// this defines 'stacking' scenario: priotagged->singletagged
 				logger.Debugw("UniVlanConfigFsm Tx Set::EVTOCD priotagged->singletagged rule", log.Fields{
-					"device-id": oFsm.pAdaptFsm.deviceID})
+					"device-id": oFsm.deviceID})
 				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:],
@@ -866,7 +1254,7 @@
 				binary.BigEndian.PutUint32(sliceEvtocdRule[cTreatInnerOffset:],
 					cCopyPrioFromInner<<cTreatPrioOffset| // vlan copy from PrioTag
 						//   (as done in Py code, maybe better option would be setPcp here, which still could be PrioCopy?)
-						oFsm.uniFlowParamsSlice[aFlowEntryNo].SetVid<<cTreatVidOffset| // Outer VID as configured
+						oFsm.uniVlanFlowParamsSlice[aFlowEntryNo].VlanRuleParams.SetVid<<cTreatVidOffset| // Outer VID as configured
 						cSetOutputTpidCopyDei<<cTreatTpidOffset) // Set TPID = 0x8100
 				oFsm.mutexFlowParams.Unlock()
 
@@ -880,13 +1268,13 @@
 					oFsm.pAdaptFsm.commChan, meParams)
 				//accept also nil as (error) return value for writing to LastTx
 				//  - this avoids misinterpretation of new received OMCI messages
-				oFsm.pOmciCC.pLastTxMeInstance = meInstance
+				oFsm.pLastTxMeInstance = meInstance
 
 				//verify response
 				err := oFsm.waitforOmciResponse()
 				if err != nil {
 					logger.Errorw("Evtocd set priotagged->singletagged rule failed, aborting VlanConfig FSM!",
-						log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+						log.Fields{"device-id": oFsm.deviceID})
 					_ = oFsm.pAdaptFsm.pFsm.Event(vlanEvReset)
 					return
 				}
@@ -895,25 +1283,226 @@
 	}
 
 	// if Config has been done for all GemPort instances let the FSM proceed
-	logger.Debugw("EVTOCD set loop finished", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+	logger.Debugw("EVTOCD set loop finished", log.Fields{"device-id": oFsm.deviceID})
+	oFsm.configuredUniFlow++ // one (more) flow configured
 	_ = oFsm.pAdaptFsm.pFsm.Event(vlanEvRxConfigEvtocd)
 }
 
+func (oFsm *UniVlanConfigFsm) removeEvtocdEntries(aRuleParams uniVlanRuleParams) {
+	// configured Input/Output TPID is not modified again - no influence if no filter is applied
+	if aRuleParams.SetVid == uint32(of.OfpVlanId_OFPVID_PRESENT) {
+		//transparent transmission was set
+		//perhaps the config is not needed for removal,
+		//  but the specific InnerTpid setting is removed in favor of the real default forwarding rule
+		logger.Debugw("UniVlanConfigFsm Tx Set::EVTOCD reset to default single tagged rule", log.Fields{
+			"device-id": oFsm.deviceID})
+		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:],
+			cPrioDefaultFilter<<cFilterPrioOffset| // default inner-tag rule
+				cDoNotFilterVid<<cFilterVidOffset| // Do not filter on inner vid
+				cDoNotFilterTPID<<cFilterTpidOffset| // Do not filter on inner TPID field
+				cDoNotFilterEtherType<<cFilterEtherTypeOffset) // Do not filter of EtherType
+
+		binary.BigEndian.PutUint32(sliceEvtocdRule[cTreatOuterOffset:],
+			0<<cTreatTTROffset| // Do not pop any tags
+				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:],
+			cDoNotAddPrio<<cTreatPrioOffset| // do not add inner tag
+				cDontCareVid<<cTreatVidOffset| // Outer VID don't care
+				cDontCareTpid<<cTreatTpidOffset) // copy TPID and DEI
+
+		meParams := me.ParamData{
+			EntityID: oFsm.evtocdID,
+			Attributes: me.AttributeValueMap{
+				"ReceivedFrameVlanTaggingOperationTable": sliceEvtocdRule,
+			},
+		}
+		meInstance := oFsm.pOmciCC.sendSetEvtocdVar(context.TODO(), ConstDefaultOmciTimeout, true,
+			oFsm.pAdaptFsm.commChan, meParams)
+		//accept also nil as (error) return value for writing to LastTx
+		//  - this avoids misinterpretation of new received OMCI messages
+		oFsm.pLastTxMeInstance = meInstance
+
+		//verify response
+		err := oFsm.waitforOmciResponse()
+		if err != nil {
+			logger.Errorw("Evtocd reset singletagged rule failed, aborting VlanConfig FSM!",
+				log.Fields{"device-id": oFsm.deviceID})
+			_ = oFsm.pAdaptFsm.pFsm.Event(vlanEvReset)
+			return
+		}
+	} else {
+		// according to py-code acceptIncrementalEvto program option decides upon stacking or translation scenario
+		if oFsm.acceptIncrementalEvtoOption {
+			// this defines VID translation scenario: singletagged->singletagged (if not transparent)
+			logger.Debugw("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
+
+			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)
+
+			meParams := me.ParamData{
+				EntityID: oFsm.evtocdID,
+				Attributes: me.AttributeValueMap{
+					"ReceivedFrameVlanTaggingOperationTable": sliceEvtocdRule,
+				},
+			}
+			meInstance := oFsm.pOmciCC.sendSetEvtocdVar(context.TODO(), ConstDefaultOmciTimeout, true,
+				oFsm.pAdaptFsm.commChan, meParams)
+			//accept also nil as (error) return value for writing to LastTx
+			//  - this avoids misinterpretation of new received OMCI messages
+			oFsm.pLastTxMeInstance = meInstance
+
+			//verify response
+			err := oFsm.waitforOmciResponse()
+			if err != nil {
+				logger.Errorw("Evtocd clear singletagged translation rule failed, aborting VlanConfig FSM!",
+					log.Fields{"device-id": oFsm.deviceID, "match-vlan": aRuleParams.MatchVid})
+				_ = oFsm.pAdaptFsm.pFsm.Event(vlanEvReset)
+				return
+			}
+		} else {
+			//not transparent and not acceptIncrementalEvtoOption: untagged/priotagged->singletagged
+			{ // just for local var's
+				// this defines stacking scenario: untagged->singletagged
+				//TODO!! in theory there could be different rules running in setting different PCP/VID'S
+				//  for untagged/priotagged, last rule wins (and remains the only one), maybe that should be
+				//  checked already at flow-add (and rejected) - to be observed if such is possible in Voltha
+				//  delete now assumes there is only one such rule!
+				logger.Debugw("UniVlanConfigFsm Tx Set::EVTOCD reset untagged rule to default", log.Fields{
+					"device-id": oFsm.deviceID})
+				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:],
+					cPrioIgnoreTag<<cFilterPrioOffset| // Not an inner-tag rule
+						cDoNotFilterVid<<cFilterVidOffset| // Do not filter on inner vid
+						cDoNotFilterTPID<<cFilterTpidOffset| // Do not filter on inner TPID field
+						cDoNotFilterEtherType<<cFilterEtherTypeOffset) // Do not filter of EtherType
+
+				binary.BigEndian.PutUint32(sliceEvtocdRule[cTreatOuterOffset:],
+					0<<cTreatTTROffset| // Do not pop any tags
+						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:],
+					cDoNotAddPrio<<cTreatPrioOffset| // do not add inner tag
+						cDontCareVid<<cTreatVidOffset| // Outer VID don't care
+						cDontCareTpid<<cTreatTpidOffset) // copy TPID and DEI
+
+				meParams := me.ParamData{
+					EntityID: oFsm.evtocdID,
+					Attributes: me.AttributeValueMap{
+						"ReceivedFrameVlanTaggingOperationTable": sliceEvtocdRule,
+					},
+				}
+				meInstance := oFsm.pOmciCC.sendSetEvtocdVar(context.TODO(), ConstDefaultOmciTimeout, true,
+					oFsm.pAdaptFsm.commChan, meParams)
+				//accept also nil as (error) return value for writing to LastTx
+				//  - this avoids misinterpretation of new received OMCI messages
+				oFsm.pLastTxMeInstance = meInstance
+
+				//verify response
+				err := oFsm.waitforOmciResponse()
+				if err != nil {
+					logger.Errorw("Evtocd reset untagged rule to default failed, aborting VlanConfig FSM!",
+						log.Fields{"device-id": oFsm.deviceID})
+					_ = oFsm.pAdaptFsm.pFsm.Event(vlanEvReset)
+					return
+				}
+			} // just for local var's
+			{ // just for local var's
+				// this defines 'stacking' scenario: priotagged->singletagged
+				logger.Debugw("UniVlanConfigFsm Tx Set::EVTOCD delete priotagged rule", log.Fields{
+					"device-id": oFsm.deviceID})
+				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:],
+					cPrioDoNotFilter<<cFilterPrioOffset| // Do not Filter on innerprio
+						0<<cFilterVidOffset| // filter on inner vid 0 (prioTagged)
+						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: oFsm.evtocdID,
+					Attributes: me.AttributeValueMap{
+						"ReceivedFrameVlanTaggingOperationTable": sliceEvtocdRule,
+					},
+				}
+				meInstance := oFsm.pOmciCC.sendSetEvtocdVar(context.TODO(), ConstDefaultOmciTimeout, true,
+					oFsm.pAdaptFsm.commChan, meParams)
+				//accept also nil as (error) return value for writing to LastTx
+				//  - this avoids misinterpretation of new received OMCI messages
+				oFsm.pLastTxMeInstance = meInstance
+
+				//verify response
+				err := oFsm.waitforOmciResponse()
+				if err != nil {
+					logger.Errorw("Evtocd delete priotagged rule failed, aborting VlanConfig FSM!",
+						log.Fields{"device-id": oFsm.deviceID})
+					_ = oFsm.pAdaptFsm.pFsm.Event(vlanEvReset)
+					return
+				}
+			} //just for local var's
+		}
+	}
+
+	// if Config has been done for all GemPort instances let the FSM proceed
+	logger.Debugw("EVTOCD filter remove loop finished", log.Fields{"device-id": oFsm.deviceID})
+	_ = oFsm.pAdaptFsm.pFsm.Event(vlanEvRemFlowDone)
+}
+
 func (oFsm *UniVlanConfigFsm) waitforOmciResponse() error {
 	select {
 	// maybe be also some outside cancel (but no context modeled for the moment ...)
 	// case <-ctx.Done():
-	// 		logger.Infow("LockState-bridge-init message reception canceled", log.Fields{"for device-id": oFsm.pAdaptFsm.deviceID})
+	// 		logger.Infow("LockState-bridge-init message reception canceled", log.Fields{"for device-id": oFsm.deviceID})
 	case <-time.After(30 * time.Second): //AS FOR THE OTHER OMCI FSM's
-		logger.Warnw("UniVlanConfigFsm multi entity timeout", log.Fields{"for device-id": oFsm.pAdaptFsm.deviceID})
-		return fmt.Errorf("uniVlanConfigFsm multi entity timeout %s", oFsm.pAdaptFsm.deviceID)
+		logger.Warnw("UniVlanConfigFsm multi entity timeout", log.Fields{"for device-id": oFsm.deviceID})
+		return fmt.Errorf("uniVlanConfigFsm multi entity timeout %s", oFsm.deviceID)
 	case success := <-oFsm.omciMIdsResponseReceived:
 		if success {
 			logger.Debug("UniVlanConfigFsm multi entity response received")
 			return nil
 		}
 		// should not happen so far
-		logger.Warnw("UniVlanConfigFsm multi entity response error", log.Fields{"for device-id": oFsm.pAdaptFsm.deviceID})
-		return fmt.Errorf("uniVlanConfigFsm multi entity responseError %s", oFsm.pAdaptFsm.deviceID)
+		logger.Warnw("UniVlanConfigFsm multi entity response error", log.Fields{"for device-id": oFsm.deviceID})
+		return fmt.Errorf("uniVlanConfigFsm multi entity responseError %s", oFsm.deviceID)
 	}
 }
diff --git a/internal/pkg/onuadaptercore/onu_device_entry.go b/internal/pkg/onuadaptercore/onu_device_entry.go
index df496a8..90ba235 100644
--- a/internal/pkg/onuadaptercore/onu_device_entry.go
+++ b/internal/pkg/onuadaptercore/onu_device_entry.go
@@ -195,19 +195,10 @@
 	isActive uint8
 }
 
-type uniVlanFlowParams struct {
-	TpID         uint16 `json:"tp_id"`
-	MatchVid     uint32 `json:"match_vid"` //use uint32 types for allowing immediate bitshifting
-	MatchPcp     uint32 `json:"match_pcp"`
-	TagsToRemove uint32 `json:"tags_to_revome"`
-	SetVid       uint32 `json:"set_vid"`
-	SetPcp       uint32 `json:"set_pcp"`
-}
-
 type uniPersConfig struct {
 	PersUniID      uint8               `json:"uni_id"`
 	PersTpPath     string              `json:"tp_path"`
-	PersFlowParams []uniVlanFlowParams `json:"flow_params"`
+	PersFlowParams []uniVlanFlowParams `json:"flow_params"` //as defined in omci_ani_config.go
 }
 
 type onuPersistentData struct {
@@ -486,7 +477,7 @@
 				}
 				logger.Debugw("RebootResponse data", log.Fields{"device-id": oo.deviceID, "data-fields": msgObj})
 				if msgObj.Result != me.Success {
-					logger.Errorw("Omci RebootResponse Error ", log.Fields{"device-id": oo.deviceID, "Error": msgObj.Result})
+					logger.Errorw("Omci RebootResponse result error", log.Fields{"device-id": oo.deviceID, "Error": msgObj.Result})
 					// possibly force FSM into abort or ignore some errors for some messages? store error for mgmt display?
 					return fmt.Errorf("omci RebootResponse result error indication %s for device %s",
 						msgObj.Result, oo.deviceID)
@@ -494,7 +485,7 @@
 				return nil
 			}
 		}
-		logger.Warnw("Reboot response error", log.Fields{"for device-id": oo.deviceID})
+		logger.Warnw("Reboot response message type error", log.Fields{"for device-id": oo.deviceID})
 		return fmt.Errorf("unexpected OmciResponse type received %s", oo.deviceID)
 	}
 }
diff --git a/internal/pkg/onuadaptercore/onu_uni_tp.go b/internal/pkg/onuadaptercore/onu_uni_tp.go
index d9578fe..e052684 100644
--- a/internal/pkg/onuadaptercore/onu_uni_tp.go
+++ b/internal/pkg/onuadaptercore/onu_uni_tp.go
@@ -85,8 +85,8 @@
 
 //onuUniTechProf structure holds information about the TechProfiles attached to Uni Ports of the ONU
 type onuUniTechProf struct {
-	deviceID                 string
 	baseDeviceHandler        *deviceHandler
+	deviceID                 string
 	tpProcMutex              sync.RWMutex
 	techProfileKVStore       *db.Backend
 	chTpConfigProcessingStep chan uint8
@@ -95,15 +95,16 @@
 	pAniConfigFsm            *uniPonAniConfigFsm
 	procResult               error //error indication of processing
 	mutexTPState             sync.Mutex
+	tpProfileExists          bool
 }
 
 //newOnuUniTechProf returns the instance of a OnuUniTechProf
 //(one instance per ONU/deviceHandler for all possible UNI's)
-func newOnuUniTechProf(ctx context.Context, aDeviceID string, aDeviceHandler *deviceHandler) *onuUniTechProf {
-	logger.Infow("init-OnuUniTechProf", log.Fields{"device-id": aDeviceID})
+func newOnuUniTechProf(ctx context.Context, aDeviceHandler *deviceHandler) *onuUniTechProf {
+	logger.Infow("init-OnuUniTechProf", log.Fields{"device-id": aDeviceHandler.deviceID})
 	var onuTP onuUniTechProf
-	onuTP.deviceID = aDeviceID
 	onuTP.baseDeviceHandler = aDeviceHandler
+	onuTP.deviceID = aDeviceHandler.deviceID
 	onuTP.tpProcMutex = sync.RWMutex{}
 	onuTP.chTpConfigProcessingStep = make(chan uint8)
 	onuTP.mapUniTpIndication = make(map[uint8]*tTechProfileIndication)
@@ -113,7 +114,7 @@
 	onuTP.techProfileKVStore = aDeviceHandler.setBackend(cBasePathTechProfileKVStore)
 	if onuTP.techProfileKVStore == nil {
 		logger.Errorw("Can't access techProfileKVStore - no backend connection to service",
-			log.Fields{"device-id": aDeviceID, "service": cBasePathTechProfileKVStore})
+			log.Fields{"device-id": aDeviceHandler.deviceID, "service": cBasePathTechProfileKVStore})
 	}
 
 	return &onuTP
@@ -147,7 +148,7 @@
 	aUniID uint8, aPathString string, wg *sync.WaitGroup) {
 	defer wg.Done() //always decrement the waitGroup on return
 	logger.Debugw("configure the Uni according to TpPath", log.Fields{
-		"device-id": onuTP.deviceID, "uniID": aUniID, "path": aPathString})
+		"device-id": onuTP.deviceID, "uni-id": aUniID, "path": aPathString})
 
 	if onuTP.techProfileKVStore == nil {
 		logger.Debug("techProfileKVStore not set - abort")
@@ -166,7 +167,7 @@
 	}
 	if pCurrentUniPort == nil {
 		logger.Errorw("TechProfile configuration aborted: requested uniID not found in PortDB",
-			log.Fields{"device-id": onuTP.deviceID, "uniID": aUniID})
+			log.Fields{"device-id": onuTP.deviceID, "uni-id": aUniID})
 		onuTP.procResult = fmt.Errorf("techProfile config aborted: requested uniID not found %d on %s",
 			aUniID, onuTP.deviceID)
 		return
@@ -195,8 +196,13 @@
 	go onuTP.readAniSideConfigFromTechProfile(ctx, aUniID, aPathString, processingStep)
 	if !onuTP.waitForTimeoutOrCompletion(ctx, onuTP.chTpConfigProcessingStep, processingStep) {
 		//timeout or error detected
+		if onuTP.tpProfileExists {
+			//ignore the internal error in case the new profile is already configured
+			// and abort the processing here
+			return
+		}
 		logger.Debugw("tech-profile related configuration aborted on read",
-			log.Fields{"device-id": onuTP.deviceID, "UniId": aUniID})
+			log.Fields{"device-id": onuTP.deviceID, "uni-id": aUniID})
 		onuTP.procResult = fmt.Errorf("techProfile config aborted: tech-profile read issue for %d on %s",
 			aUniID, onuTP.deviceID)
 		return
@@ -210,7 +216,7 @@
 			if !onuTP.waitForTimeoutOrCompletion(ctx, onuTP.chTpConfigProcessingStep, processingStep) {
 				//timeout or error detected
 				logger.Debugw("tech-profile related configuration aborted on set",
-					log.Fields{"device-id": onuTP.deviceID, "UniId": aUniID})
+					log.Fields{"device-id": onuTP.deviceID, "uni-id": aUniID})
 				onuTP.procResult = fmt.Errorf("techProfile config aborted: Omci AniSideConfig failed %d on %s",
 					aUniID, onuTP.deviceID)
 				//this issue here means that the AniConfigFsm has not finished successfully
@@ -222,14 +228,14 @@
 		} else {
 			// strange: UNI entry exists, but no ANI data, maybe such situation should be cleared up (if observed)
 			logger.Debugw("no Tcont/Gem data for this UNI found - abort", log.Fields{
-				"device-id": onuTP.deviceID, "uniID": aUniID})
+				"device-id": onuTP.deviceID, "uni-id": aUniID})
 			onuTP.procResult = fmt.Errorf("techProfile config aborted: no Tcont/Gem data found for this UNI %d on %s",
 				aUniID, onuTP.deviceID)
 			return
 		}
 	} else {
 		logger.Debugw("no PonAni data for this UNI found - abort", log.Fields{
-			"device-id": onuTP.deviceID, "uniID": aUniID})
+			"device-id": onuTP.deviceID, "uni-id": aUniID})
 		onuTP.procResult = fmt.Errorf("techProfile config aborted: no AniSide data found for this UNI %d on %s",
 			aUniID, onuTP.deviceID)
 		return
@@ -242,6 +248,7 @@
 	ctx context.Context, aUniID uint8, aPathString string, aProcessingStep uint8) {
 	var tpInst tp.TechProfile
 
+	onuTP.tpProfileExists = false
 	//store profile type and identifier for later usage within the OMCI identifier and possibly ME setup
 	//pathstring is defined to be in the form of <ProfType>/<profID>/<Interface/../Identifier>
 	subStringSlice := strings.Split(aPathString, "/")
@@ -251,18 +258,33 @@
 		onuTP.chTpConfigProcessingStep <- 0 //error indication
 		return
 	}
+	profID, err := strconv.ParseUint(subStringSlice[1], 10, 32)
+	if err != nil {
+		logger.Errorw("invalid ProfileId from path",
+			log.Fields{"ParseErr": err})
+		onuTP.chTpConfigProcessingStep <- 0 //error indication
+		return
+	}
 
-	//just some logical check to avoid unexpected behavior
 	//at this point it is assumed that a new TechProfile is assigned to the UNI
-	//expectation is that no TPIndication entry exists here, if yes,
-	//  then we throw a warning and remove it (and the possible ANIConfig) simply
-	//  note that the ONU config state may be ambivalent in such a case
-	//  also note, that the PonAniConfig map is not checked additionally
-	//    consistency to TPIndication is assumed
+	//expectation is that no TPIndication entry exists here, if exists and with the same TPId
+	//  then we throw a warning, set an internal error and abort with error,
+	//  which is later re-defined to success response to OLT adapter
+	//  if TPId has changed, current data is removed (note that the ONU config state may be
+	// 	  ambivalent in such a case)
 	if _, existTP := onuTP.mapUniTpIndication[aUniID]; existTP {
 		logger.Warnw("Some active profile entry at reading new TechProfile",
 			log.Fields{"path": aPathString, "device-id": onuTP.deviceID,
-				"UniId": aUniID, "wrongProfile": onuTP.mapUniTpIndication[aUniID].techProfileID})
+				"uni-id": aUniID, "wrongProfile": onuTP.mapUniTpIndication[aUniID].techProfileID})
+		if uint16(profID) == onuTP.mapUniTpIndication[aUniID].techProfileID {
+			// ProfId not changed - assume profile to be still the same
+			// anyway this should not appear after full support of profile (Gem/TCont) removal
+			logger.Warnw("New TechProfile already exists - aborting configuration",
+				log.Fields{"device-id": onuTP.deviceID})
+			onuTP.tpProfileExists = true
+			onuTP.chTpConfigProcessingStep <- 0 //error indication
+			return
+		}
 		//delete on the mapUniTpIndication map not needed, just overwritten later
 		//delete on the PonAniConfig map should be safe, even if not existing
 		delete(onuTP.mapPonAniConfig, aUniID)
@@ -272,18 +294,11 @@
 	}
 
 	onuTP.mapUniTpIndication[aUniID].techProfileType = subStringSlice[0]
-	profID, err := strconv.ParseUint(subStringSlice[1], 10, 32)
-	if err != nil {
-		logger.Errorw("invalid ProfileId from path",
-			log.Fields{"ParseErr": err})
-		onuTP.chTpConfigProcessingStep <- 0 //error indication
-		return
-	}
-
 	//note the limitation on ID range (probably even more limited) - based on usage within OMCI EntityID
 	onuTP.mapUniTpIndication[aUniID].techProfileID = uint16(profID)
+	onuTP.mapUniTpIndication[aUniID].techProfileConfigDone = false
 	logger.Debugw("tech-profile path indications",
-		log.Fields{"device-id": onuTP.deviceID, "UniId": aUniID,
+		log.Fields{"device-id": onuTP.deviceID, "uni-id": aUniID,
 			"profType": onuTP.mapUniTpIndication[aUniID].techProfileType,
 			"profID":   onuTP.mapUniTpIndication[aUniID].techProfileID})
 
@@ -318,7 +333,7 @@
 		return
 	}
 
-	//default start with 1Tcont1Gem profile, later extend for multi GemPerTcont and perhaps even  MultiTcontMultiGem
+	//default start with 1Tcont profile, later perhaps extend to MultiTcontMultiGem
 	localMapGemPortParams := make(map[uint16]*gemPortParamStruct)
 	localMapGemPortParams[0] = &gemPortParamStruct{}
 	localMapPonAniConfig := make(map[uint16]*tcontGemList)
@@ -450,7 +465,7 @@
 	}
 	pAniCfgFsm := newUniPonAniConfigFsm(pDevEntry.PDevOmciCC, apCurrentUniPort, onuTP,
 		pDevEntry.pOnuDB, onuTP.mapUniTpIndication[aUniID].techProfileID, devEvent,
-		"AniConfigFsm", onuTP.deviceID, chAniConfigFsm)
+		"AniConfigFsm", onuTP.baseDeviceHandler, chAniConfigFsm)
 	if pAniCfgFsm != nil {
 		onuTP.pAniConfigFsm = pAniCfgFsm
 		onuTP.runAniConfigFsm(aProcessingStep)
@@ -488,6 +503,18 @@
 	}
 }
 
+// clearAniSideConfig deletes all internal TechProfile related data connected to the requested UniPort
+func (onuTP *onuUniTechProf) clearAniSideConfig(aUniID uint8) {
+	logger.Debugw("removing TpIndication and PonAniConfig data", log.Fields{
+		"device-id": onuTP.deviceID, "uni-id": aUniID})
+	//a mutex protection on the concerned data should not be needed here, as the config/write action should not
+	//  interfere with any read action or the initial write/config activity at start
+	//remove the TechProfile indications of this UNI, should be safe even if not existing
+	delete(onuTP.mapUniTpIndication, aUniID)
+	//delete on the PonAniConfig map of this UNI should be safe, even if not existing
+	delete(onuTP.mapPonAniConfig, aUniID)
+}
+
 // setConfigDone sets the requested techProfile config state (if possible)
 func (onuTP *onuUniTechProf) setConfigDone(aUniID uint8, aState bool) {
 	if _, existTP := onuTP.mapUniTpIndication[aUniID]; existTP {
diff --git a/internal/pkg/onuadaptercore/openonu.go b/internal/pkg/onuadaptercore/openonu.go
index ce33c8e..7056cd7 100644
--- a/internal/pkg/onuadaptercore/openonu.go
+++ b/internal/pkg/onuadaptercore/openonu.go
@@ -321,6 +321,10 @@
 		logger.Warnw("device disabled or offline - skipping flow-update", log.Fields{"ConnectStatus": device.ConnectStatus,
 			"AdminState": device.AdminState, "deviceId": device.Id})
 		return fmt.Errorf("non-matching device state: %s", device.Id)
+		//TODO!!: verify if some flow delete activity as observed in BBSIM tests after ONU-down indication
+		//  has some system impact on general behavior after ONU up again (as no flow is really removed here)
+		//  but it may only be related to following device_delete, which anyway should clear up all stuff
+		//  (testing needed with new device-enable [after device-delete] ...)
 	}
 
 	// For now, there is no support for group changes (as in the actual Py-adapter code)
diff --git a/internal/pkg/onuadaptercore/uniportadmin.go b/internal/pkg/onuadaptercore/uniportadmin.go
index 8a0428e..11a6b04 100644
--- a/internal/pkg/onuadaptercore/uniportadmin.go
+++ b/internal/pkg/onuadaptercore/uniportadmin.go
@@ -34,11 +34,13 @@
 //lockStateFsm defines the structure for the state machine to lock/unlock the ONU UNI ports via OMCI
 type lockStateFsm struct {
 	pDeviceHandler           *deviceHandler
+	deviceID                 string
 	pOmciCC                  *omciCC
 	adminState               bool
 	requestEvent             OnuDeviceEvent
 	omciLockResponseReceived chan bool //seperate channel needed for checking UNI port OMCi message responses
 	pAdaptFsm                *AdapterFsm
+	pLastTxMeInstance        *me.ManagedEntity
 }
 
 const (
@@ -67,14 +69,15 @@
 	aName string, apDeviceHandler *deviceHandler, aCommChannel chan Message) *lockStateFsm {
 	instFsm := &lockStateFsm{
 		pDeviceHandler: apDeviceHandler,
+		deviceID:       apDeviceHandler.deviceID,
 		pOmciCC:        apDevOmciCC,
 		adminState:     aAdminState,
 		requestEvent:   aRequestEvent,
 	}
-	instFsm.pAdaptFsm = NewAdapterFsm(aName, apDeviceHandler.deviceID, aCommChannel)
+	instFsm.pAdaptFsm = NewAdapterFsm(aName, instFsm.deviceID, aCommChannel)
 	if instFsm.pAdaptFsm == nil {
 		logger.Errorw("LockStateFsm's AdapterFsm could not be instantiated!!", log.Fields{
-			"device-id": apDeviceHandler.deviceID})
+			"device-id": instFsm.deviceID})
 		return nil
 	}
 	if aAdminState { //port locking requested
@@ -146,11 +149,11 @@
 	}
 	if instFsm.pAdaptFsm.pFsm == nil {
 		logger.Errorw("LockStateFsm's Base FSM could not be instantiated!!", log.Fields{
-			"device-id": apDeviceHandler.deviceID})
+			"device-id": instFsm.deviceID})
 		return nil
 	}
 
-	logger.Infow("LockStateFsm created", log.Fields{"device-id": apDeviceHandler.deviceID})
+	logger.Infow("LockStateFsm created", log.Fields{"device-id": instFsm.deviceID})
 	return instFsm
 }
 
@@ -162,7 +165,7 @@
 
 func (oFsm *lockStateFsm) enterAdminStartingState(e *fsm.Event) {
 	logger.Debugw("LockStateFSM start", log.Fields{"in state": e.FSM.Current(),
-		"device-id": oFsm.pAdaptFsm.deviceID})
+		"device-id": oFsm.deviceID})
 	// in case the used channel is not yet defined (can be re-used after restarts)
 	if oFsm.omciLockResponseReceived == nil {
 		oFsm.omciLockResponseReceived = make(chan bool)
@@ -196,7 +199,7 @@
 		omciAdminState = 0
 	}
 	logger.Debugw("LockStateFSM Tx Set::ONU-G:admin", log.Fields{
-		"omciAdmin": omciAdminState, "in state": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
+		"omciAdmin": omciAdminState, "in state": e.FSM.Current(), "device-id": oFsm.deviceID})
 	requestedAttributes := me.AttributeValueMap{"AdministrativeState": omciAdminState}
 	meInstance := oFsm.pOmciCC.sendSetOnuGLS(context.TODO(), ConstDefaultOmciTimeout, true,
 		requestedAttributes, oFsm.pAdaptFsm.commChan)
@@ -204,19 +207,19 @@
 	//  - this avoids misinterpretation of new received OMCI messages
 	//  we might already abort the processing with nil here, but maybe some auto-recovery may be tried
 	//  - may be improved later, for now we just handle it with the Rx timeout or missing next event (stick in state)
-	oFsm.pOmciCC.pLastTxMeInstance = meInstance
+	oFsm.pLastTxMeInstance = meInstance
 }
 
 func (oFsm *lockStateFsm) enterSettingUnisState(e *fsm.Event) {
 	logger.Infow("LockStateFSM - starting PPTP config loop", log.Fields{
-		"in state": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID, "LockState": oFsm.adminState})
+		"in state": e.FSM.Current(), "device-id": oFsm.deviceID, "LockState": oFsm.adminState})
 	go oFsm.performUniPortAdminSet()
 }
 
 func (oFsm *lockStateFsm) enterAdminDoneState(e *fsm.Event) {
-	logger.Debugw("LockStateFSM", log.Fields{"send notification to core in State": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
+	logger.Debugw("LockStateFSM", log.Fields{"send notification to core in State": e.FSM.Current(), "device-id": oFsm.deviceID})
 	//use DeviceHandler event notification directly, no need/support to update DeviceEntryState for lock/unlock
-	oFsm.pOmciCC.pBaseDeviceHandler.deviceProcStatusUpdate(oFsm.requestEvent)
+	oFsm.pDeviceHandler.deviceProcStatusUpdate(oFsm.requestEvent)
 
 	//let's reset the state machine in order to release all resources now
 	pLockStateAFsm := oFsm.pAdaptFsm
@@ -231,7 +234,7 @@
 }
 
 func (oFsm *lockStateFsm) enterResettingState(e *fsm.Event) {
-	logger.Debugw("LockStateFSM resetting", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+	logger.Debugw("LockStateFSM resetting", log.Fields{"device-id": oFsm.deviceID})
 	pLockStateAFsm := oFsm.pAdaptFsm
 	if pLockStateAFsm != nil {
 		// abort running message processing
@@ -250,75 +253,76 @@
 				_ = a_pAFsm.pFsm.Event(uniEvRestart)
 			}
 		}(pLockStateAFsm)
+		oFsm.pLastTxMeInstance = nil
 	}
 }
 
 func (oFsm *lockStateFsm) processOmciLockMessages( /*ctx context.Context*/ ) {
-	logger.Debugw("Start LockStateFsm Msg processing", log.Fields{"for device-id": oFsm.pAdaptFsm.deviceID})
+	logger.Debugw("Start LockStateFsm Msg processing", log.Fields{"for device-id": oFsm.deviceID})
 loop:
 	for {
 		// case <-ctx.Done():
-		// 	logger.Info("MibSync Msg", log.Fields{"Message handling canceled via context for device-id": oFsm.pAdaptFsm.deviceID})
+		// 	logger.Info("MibSync Msg", log.Fields{"Message handling canceled via context for device-id": oFsm.deviceID})
 		// 	break loop
 		message, ok := <-oFsm.pAdaptFsm.commChan
 		if !ok {
-			logger.Info("LockStateFsm Rx Msg - could not read from channel", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+			logger.Info("LockStateFsm Rx Msg - could not read from channel", log.Fields{"device-id": oFsm.deviceID})
 			// but then we have to ensure a restart of the FSM as well - as exceptional procedure
 			_ = oFsm.pAdaptFsm.pFsm.Event(uniEvRestart)
 			break loop
 		}
-		logger.Debugw("LockStateFsm Rx Msg", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+		logger.Debugw("LockStateFsm Rx Msg", log.Fields{"device-id": oFsm.deviceID})
 
 		switch message.Type {
 		case TestMsg:
 			msg, _ := message.Data.(TestMessage)
 			if msg.TestMessageVal == AbortMessageProcessing {
-				logger.Infow("LockStateFsm abort ProcessMsg", log.Fields{"for device-id": oFsm.pAdaptFsm.deviceID})
+				logger.Infow("LockStateFsm abort ProcessMsg", log.Fields{"for device-id": oFsm.deviceID})
 				break loop
 			}
-			logger.Warnw("LockStateFsm unknown TestMessage", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID, "MessageVal": msg.TestMessageVal})
+			logger.Warnw("LockStateFsm unknown TestMessage", log.Fields{"device-id": oFsm.deviceID, "MessageVal": msg.TestMessageVal})
 		case OMCI:
 			msg, _ := message.Data.(OmciMessage)
 			oFsm.handleOmciLockStateMessage(msg)
 		default:
-			logger.Warn("LockStateFsm Rx unknown message", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID,
+			logger.Warn("LockStateFsm Rx unknown message", log.Fields{"device-id": oFsm.deviceID,
 				"message.Type": message.Type})
 		}
 	}
-	logger.Infow("End LockStateFsm Msg processing", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+	logger.Infow("End LockStateFsm Msg processing", log.Fields{"device-id": oFsm.deviceID})
 }
 
 func (oFsm *lockStateFsm) handleOmciLockStateMessage(msg OmciMessage) {
-	logger.Debugw("Rx OMCI LockStateFsm Msg", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID,
+	logger.Debugw("Rx OMCI LockStateFsm Msg", log.Fields{"device-id": oFsm.deviceID,
 		"msgType": msg.OmciMsg.MessageType})
 
 	if msg.OmciMsg.MessageType == omci.SetResponseType {
 		msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeSetResponse)
 		if msgLayer == nil {
 			logger.Errorw("LockStateFsm - Omci Msg layer could not be detected for SetResponse",
-				log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+				log.Fields{"device-id": oFsm.deviceID})
 			return
 		}
 		msgObj, msgOk := msgLayer.(*omci.SetResponse)
 		if !msgOk {
 			logger.Errorw("LockStateFsm - Omci Msg layer could not be assigned for SetResponse",
-				log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+				log.Fields{"device-id": oFsm.deviceID})
 			return
 		}
-		logger.Debugw("LockStateFsm SetResponse Data", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID, "data-fields": msgObj})
+		logger.Debugw("LockStateFsm SetResponse Data", log.Fields{"device-id": oFsm.deviceID, "data-fields": msgObj})
 		if msgObj.Result != me.Success {
 			logger.Errorw("LockStateFsm - Omci SetResponse Error - later: drive FSM to abort state ?", log.Fields{"Error": msgObj.Result})
 			// possibly force FSM into abort or ignore some errors for some messages? store error for mgmt display?
 			return
 		}
 		// compare comments above for CreateResponse (apply also here ...)
-		if msgObj.EntityClass == oFsm.pOmciCC.pLastTxMeInstance.GetClassID() &&
-			msgObj.EntityInstance == oFsm.pOmciCC.pLastTxMeInstance.GetEntityID() {
+		if msgObj.EntityClass == oFsm.pLastTxMeInstance.GetClassID() &&
+			msgObj.EntityInstance == oFsm.pLastTxMeInstance.GetEntityID() {
 			//store the created ME into DB //TODO??? obviously the Python code does not store the config ...
 			// if, then something like:
 			//oFsm.pOnuDB.StoreMe(msgObj)
 
-			switch oFsm.pOmciCC.pLastTxMeInstance.GetName() {
+			switch oFsm.pLastTxMeInstance.GetName() {
 			case "OnuG":
 				{ // let the FSM proceed ...
 					_ = oFsm.pAdaptFsm.pFsm.Event(uniEvRxOnugResp)
@@ -345,20 +349,20 @@
 
 	for uniNo, uniPort := range oFsm.pOmciCC.pBaseDeviceHandler.uniEntityMap {
 		logger.Debugw("Setting PPTP admin state", log.Fields{
-			"device-id": oFsm.pAdaptFsm.deviceID, "for PortNo": uniNo})
+			"device-id": oFsm.deviceID, "for PortNo": uniNo})
 
 		var meInstance *me.ManagedEntity
 		if uniPort.portType == uniPPTP {
 			meInstance = oFsm.pOmciCC.sendSetUniGLS(context.TODO(), uniPort.entityID, ConstDefaultOmciTimeout,
 				true, requestedAttributes, oFsm.pAdaptFsm.commChan)
-			oFsm.pOmciCC.pLastTxMeInstance = meInstance
+			oFsm.pLastTxMeInstance = meInstance
 		} else if uniPort.portType == uniVEIP {
 			meInstance = oFsm.pOmciCC.sendSetVeipLS(context.TODO(), uniPort.entityID, ConstDefaultOmciTimeout,
 				true, requestedAttributes, oFsm.pAdaptFsm.commChan)
-			oFsm.pOmciCC.pLastTxMeInstance = meInstance
+			oFsm.pLastTxMeInstance = meInstance
 		} else {
 			logger.Warnw("Unsupported PPTP type - skip",
-				log.Fields{"device-id": oFsm.pAdaptFsm.deviceID, "Port": uniNo})
+				log.Fields{"device-id": oFsm.deviceID, "Port": uniNo})
 			continue
 		}
 
@@ -366,14 +370,14 @@
 		err := oFsm.waitforOmciResponse(meInstance)
 		if err != nil {
 			logger.Errorw("PPTP Admin State set failed, aborting LockState set!",
-				log.Fields{"device-id": oFsm.pAdaptFsm.deviceID, "Port": uniNo})
+				log.Fields{"device-id": oFsm.deviceID, "Port": uniNo})
 			_ = oFsm.pAdaptFsm.pFsm.Event(uniEvReset)
 			return
 		}
 	} //for all UNI ports
 	// if Config has been done for all UNI related instances let the FSM proceed
 	// while we did not check here, if there is some port at all - !?
-	logger.Infow("PPTP config loop finished", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+	logger.Infow("PPTP config loop finished", log.Fields{"device-id": oFsm.deviceID})
 	_ = oFsm.pAdaptFsm.pFsm.Event(uniEvRxUnisResp)
 }
 
@@ -381,17 +385,17 @@
 	select {
 	// maybe be also some outside cancel (but no context modeled for the moment ...)
 	// case <-ctx.Done():
-	// 		logger.Infow("LockState-bridge-init message reception canceled", log.Fields{"for device-id": oFsm.pAdaptFsm.deviceID})
+	// 		logger.Infow("LockState-bridge-init message reception canceled", log.Fields{"for device-id": oFsm.deviceID})
 	case <-time.After(30 * time.Second): //3s was detected to be to less in 8*8 bbsim test with debug Info/Debug
-		logger.Warnw("LockStateFSM uni-set timeout", log.Fields{"for device-id": oFsm.pAdaptFsm.deviceID})
-		return fmt.Errorf("lockStateFsm uni-set timeout for device-id %s", oFsm.pAdaptFsm.deviceID)
+		logger.Warnw("LockStateFSM uni-set timeout", log.Fields{"for device-id": oFsm.deviceID})
+		return fmt.Errorf("lockStateFsm uni-set timeout for device-id %s", oFsm.deviceID)
 	case success := <-oFsm.omciLockResponseReceived:
 		if success {
 			logger.Debug("LockStateFSM uni-set response received")
 			return nil
 		}
 		// should not happen so far
-		logger.Warnw("LockStateFSM uni-set response error", log.Fields{"for device-id": oFsm.pAdaptFsm.deviceID})
-		return fmt.Errorf("lockStateFsm uni-set responseError for device-id %s", oFsm.pAdaptFsm.deviceID)
+		logger.Warnw("LockStateFSM uni-set response error", log.Fields{"for device-id": oFsm.deviceID})
+		return fmt.Errorf("lockStateFsm uni-set responseError for device-id %s", oFsm.deviceID)
 	}
 }