[VOL-3604] flow/techProfile handling after ONU reboot/down/disable must be revised -> version 0.1.13-dev137

Signed-off-by: mpagenko <michael.pagenkopf@adtran.com>
Change-Id: I8bd846170d62f15c3a83ce6b10911707e0cd6176
diff --git a/VERSION b/VERSION
index 86b9e51..52cd72d 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.1.13-dev136
+0.1.13-dev137
diff --git a/internal/pkg/onuadaptercore/device_handler.go b/internal/pkg/onuadaptercore/device_handler.go
index 414abaf..4dce9b5 100644
--- a/internal/pkg/onuadaptercore/device_handler.go
+++ b/internal/pkg/onuadaptercore/device_handler.go
@@ -127,12 +127,13 @@
 	//onus     sync.Map
 	//portStats          *OpenOltStatisticsMgr
 	//metrics            *pmmetrics.PmMetrics
-	stopCollector       chan bool
-	stopHeartbeatCheck  chan bool
-	activePorts         sync.Map
-	uniEntityMap        map[uint32]*onuUniPort
-	UniVlanConfigFsmMap map[uint8]*UniVlanConfigFsm
-	reconciling         bool
+	stopCollector              chan bool
+	stopHeartbeatCheck         chan bool
+	activePorts                sync.Map
+	uniEntityMap               map[uint32]*onuUniPort
+	UniVlanConfigFsmMap        map[uint8]*UniVlanConfigFsm
+	reconciling                bool
+	ReadyForSpecificOmciConfig bool
 }
 
 //newDeviceHandler creates a new device handler
@@ -158,6 +159,7 @@
 	dh.uniEntityMap = make(map[uint32]*onuUniPort)
 	dh.UniVlanConfigFsmMap = make(map[uint8]*UniVlanConfigFsm)
 	dh.reconciling = false
+	dh.ReadyForSpecificOmciConfig = false
 
 	// Device related state machine
 	dh.pDeviceStateFsm = fsm.NewFSM(
@@ -284,11 +286,14 @@
 			log.Fields{"device-id": dh.deviceID})
 		return fmt.Errorf("techProfile DLMsg request while onuTechProf instance not setup: %s", dh.deviceID)
 	}
-	if (dh.deviceReason == "stopping-openomci") || (dh.deviceReason == "omci-admin-lock") {
-		// I've seen cases for this request, where the device was already stopped
-		logger.Warnw("TechProf stopped: device-unreachable", log.Fields{"device-id": dh.deviceID})
-		return fmt.Errorf("device-unreachable: %s", dh.deviceID)
+	if !dh.ReadyForSpecificOmciConfig {
+		logger.Warnw("TechProf-set rejected: improper device state", log.Fields{"device-id": dh.deviceID,
+			"device-state": dh.deviceReason})
+		return fmt.Errorf("improper device state %s on device %s", dh.deviceReason, dh.deviceID)
 	}
+	//previous state test here was just this one, now extended for more states to reject the SetRequest:
+	// at least 'mib-downloaded' should be reached for processing of this specific ONU configuration
+	//  if (dh.deviceReason == "stopping-openomci") || (dh.deviceReason == "omci-admin-lock")
 
 	msgBody := msg.GetBody()
 	techProfMsg := &ic.InterAdapterTechProfileDownloadMessage{}
@@ -376,25 +381,21 @@
 	}
 	uniID := uint8(delGemPortMsg.UniId)
 
-	if bTpModify := pDevEntry.updateOnuUniTpPath(uniID, ""); bTpModify {
-		// deadline context to ensure completion of background routines waited for
-		deadline := time.Now().Add(dh.pOpenOnuAc.maxTimeoutInterAdapterComm) //allowed run time to finish before execution
-		dctx, cancel := context.WithDeadline(context.Background(), deadline)
+	//a removal of some GemPort would never remove the complete TechProfile entry (done on T-Cont)
 
-		dh.pOnuTP.resetTpProcessingErrorIndication()
-		pDevEntry.resetKvProcessingErrorIndication()
+	// deadline context to ensure completion of background routines waited for
+	deadline := time.Now().Add(dh.pOpenOnuAc.maxTimeoutInterAdapterComm) //allowed run time to finish before execution
+	dctx, cancel := context.WithDeadline(context.Background(), deadline)
 
-		var wg sync.WaitGroup
-		wg.Add(2) // for the 2 go routines to finish
-		go pDevEntry.deleteTpResource(dctx, uniID, delGemPortMsg.TpPath,
-			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, "GemDelete") //wait for background process to finish
+	dh.pOnuTP.resetTpProcessingErrorIndication()
 
-		return dh.combineErrorStrings(dh.pOnuTP.getTpProcessingErrorIndication(), pDevEntry.getKvProcessingErrorIndication())
-	}
-	return nil
+	var wg sync.WaitGroup
+	wg.Add(1) // for the 1 go routine to finish
+	go dh.pOnuTP.deleteTpResource(dctx, uniID, delGemPortMsg.TpPath,
+		cResourceGemPort, delGemPortMsg.GemPortId, &wg)
+	dh.waitForCompletion(cancel, &wg, "GemDelete") //wait for background process to finish
+
+	return dh.pOnuTP.getTpProcessingErrorIndication()
 }
 
 func (dh *deviceHandler) processInterAdapterDeleteTcontReqMessage(
@@ -442,7 +443,7 @@
 
 		var wg sync.WaitGroup
 		wg.Add(2) // for the 2 go routines to finish
-		go pDevEntry.deleteTpResource(dctx, uniID, delTcontMsg.TpPath,
+		go dh.pOnuTP.deleteTpResource(dctx, uniID, delTcontMsg.TpPath,
 			cResourceTcont, delTcontMsg.AllocId, &wg)
 		// Removal of the tcont/alloc id mapping represents the removal of the tech profile
 		go pDevEntry.updateOnuKvStore(dctx, &wg)
@@ -534,7 +535,6 @@
 					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("flow-remove port indications", log.Fields{
@@ -586,6 +586,18 @@
 					continue
 					//return fmt.Errorf("flow-parameter inPort %d not found in internal UniPorts", flowInPort)
 				}
+				// let's still assume that we receive the flow-add only in some 'active' device state (as so far observed)
+				// if not, we just throw some error here to have an indication about that, if we really need to support that
+				//   then we would need to create some means to activate the internal stored flows
+				//   after the device gets active automatically (and still with its dependency to the TechProfile)
+				// for state checking compare also code here: processInterAdapterTechProfileDownloadReqMessage
+				// also abort for the other still possible flows here
+				if !dh.ReadyForSpecificOmciConfig {
+					logger.Warnw("flow-add rejected: improper device state", log.Fields{"device-id": dh.deviceID,
+						"last device-reason": dh.deviceReason})
+					return fmt.Errorf("improper device state on device %s", dh.deviceID)
+				}
+
 				flowOutPort := flow.GetOutPort(flowItem)
 				logger.Debugw("flow-add port indications", log.Fields{
 					"device-id": dh.deviceID, "inPort": flowInPort, "outPort": flowOutPort,
@@ -608,27 +620,21 @@
 }
 
 //disableDevice locks the ONU and its UNI/VEIP ports (admin lock via OMCI)
+//following are the expected device states after this activity:
+//Device Admin-State : down (on rwCore), Port-State: UNKNOWN, Conn-State: REACHABLE, Reason: omci-admin-lock
+// (Conn-State: REACHABLE might conflict with some previous ONU Down indication - maybe to be resolved later)
 func (dh *deviceHandler) disableDevice(device *voltha.Device) {
 	logger.Debugw("disable-device", log.Fields{"device-id": device.Id, "SerialNumber": device.SerialNumber})
 
 	//admin-lock reason can also be used uniquely for setting the DeviceState accordingly
+	//note that disableDevice sequences in some 'ONU active' state may yield also
+	// "tech...delete-success" or "omci-flow-deleted" according to further received requests in the end
 	// - inblock state checking to prevent possibly unneeded processing (on command repitition)
 	if dh.deviceReason != "omci-admin-lock" {
-		//running FSM's are stopped/reset here to avoid indirect stucking
-		// due to blocked OMCI transmission on disabled state
-		// but with possibly aborted FSM's there might be complications as the expected state
-		// after some re-enable would then be quite undefined
-		// maybe after re-enabling some additional checks would be required to possibly enforce new
-		// (reconcile-like) config (which would require some indication from 'aborted' FSM's first)
-		// for now let's assume no running FSM is active at this time point here ... -> TODO!!!
-		if err := dh.resetFsms(); err != nil {
-			logger.Errorw("error-disableDevice at FSM stop",
-				log.Fields{"device-id": dh.deviceID, "error": err})
-			// abort: system behavior is just unstable ...
-			return
-		}
+		//disable-device shall be just a UNi/ONU-G related admin state setting
+		//all other configurations/FSM's shall not be impacted and shall execute as required by the system
 
-		if dh.deviceReason != "rebooting" {
+		if dh.ReadyForSpecificOmciConfig {
 			// disable UNI ports/ONU
 			// *** should generate UniDisableStateDone event - used to disable the port(s) on success
 			if dh.pLockStateFsm == nil {
@@ -654,14 +660,6 @@
 				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
 		}
 	}
 }
@@ -670,6 +668,16 @@
 func (dh *deviceHandler) reEnableDevice(device *voltha.Device) {
 	logger.Debugw("reenable-device", log.Fields{"device-id": device.Id, "SerialNumber": device.SerialNumber})
 
+	//setting ReadyForSpecificOmciConfig here is just a workaround for BBSIM testing in the sequence
+	//  OnuSoftReboot-disable-enable, because BBSIM does not generate a new OnuIndication-Up event after SoftReboot
+	//  which is the assumption for real ONU's, where the ready-state is then set according to the following MibUpload/Download
+	//  for real ONU's that should have nearly no influence
+	//  Note that for real ONU's there is anyway a problematic situation with following sequence:
+	//		OnuIndication-Dw (or not active at all) (- disable) - enable: here already the LockFsm may run into timeout (no OmciResponse)
+	//      but that anyway is hopefully resolved by some OnuIndication-Up event (maybe to be tested)
+	//      one could also argue, that a device-enable should also enable attempts for specific omci configuration
+	dh.ReadyForSpecificOmciConfig = true //needed to allow subsequent flow/techProf config (on BBSIM)
+
 	// enable ONU/UNI ports
 	// *** should generate UniEnableStateDone event - used to disable the port(s) on success
 	if dh.pUnlockStateFsm == nil {
@@ -760,7 +768,7 @@
 			} else {
 				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 {
+					uint8(flowData.VlanRuleParams.SetPcp), OmciVlanFilterAddDone); err != nil {
 					logger.Errorw(err.Error(), log.Fields{"device-id": dh.deviceID})
 				}
 			}
@@ -831,6 +839,7 @@
 		return err
 	}
 	dh.deviceReason = "rebooting"
+	dh.ReadyForSpecificOmciConfig = false
 	return nil
 }
 
@@ -1327,6 +1336,7 @@
 
 func (dh *deviceHandler) updateInterface(onuind *oop.OnuIndication) error {
 	//state checking to prevent unneeded processing (eg. on ONU 'unreachable' and 'down')
+	// (but note that the deviceReason may also have changed to e.g. TechProf*Delete_Success in between)
 	if dh.deviceReason != "stopping-openomci" {
 		logger.Debugw("updateInterface-started - stopping-device", log.Fields{"device-id": dh.deviceID})
 		//stop all running FSM processing - make use of the DH-state as mirrored in the deviceReason
@@ -1361,14 +1371,16 @@
 
 		dh.disableUniPortStateUpdate()
 
+		dh.deviceReason = "stopping-openomci"
+		dh.ReadyForSpecificOmciConfig = false
+
 		if err := dh.coreProxy.DeviceReasonUpdate(context.TODO(), dh.deviceID, "stopping-openomci"); err != nil {
 			//TODO with VOL-3045/VOL-3046: return the error and stop further processing
-			logger.Errorw("error-DeviceReasonUpdate to 'stopping-openomci'",
+			logger.Errorw("error-DeviceReasonUpdate to stopping-openomci",
 				log.Fields{"device-id": dh.deviceID, "error": err})
 			// abort: system behavior is just unstable ...
 			return err
 		}
-		dh.deviceReason = "stopping-openomci"
 
 		logger.Debugw("call DeviceStateUpdate upon update interface", log.Fields{"ConnectStatus": voltha.ConnectStatus_UNREACHABLE,
 			"OperStatus": voltha.OperStatus_DISCOVERED, "device-id": dh.deviceID})
@@ -1444,10 +1456,10 @@
 		//initiate DevStateUpdate
 		if err := dh.coreProxy.DeviceReasonUpdate(context.TODO(), dh.deviceID, "discovery-mibsync-complete"); err != nil {
 			//TODO with VOL-3045/VOL-3046: return the error and stop further processing
-			logger.Errorw("error-DeviceReasonUpdate to 'mibsync-complete'", log.Fields{
+			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{"device-id": 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",
@@ -1549,10 +1561,10 @@
 	if !dh.reconciling {
 		if err := dh.coreProxy.DeviceReasonUpdate(context.TODO(), dh.deviceID, "initial-mib-downloaded"); err != nil {
 			//TODO with VOL-3045/VOL-3046: return the error and stop further processing
-			logger.Errorw("error-DeviceReasonUpdate to 'initial-mib-downloaded'",
+			logger.Errorw("error-DeviceReasonUpdate to initial-mib-downloaded",
 				log.Fields{"device-id": dh.deviceID, "error": err})
 		} else {
-			logger.Infow("dev reason updated to 'initial-mib-downloaded'", log.Fields{"device-id": dh.deviceID})
+			logger.Infow("dev reason updated to initial-mib-downloaded", log.Fields{"device-id": dh.deviceID})
 		}
 	} else {
 		logger.Debugw("reconciling - don't notify core about DeviceReasonUpdate to initial-mib-downloaded",
@@ -1560,6 +1572,7 @@
 	}
 	//set internal state anyway - as it was done
 	dh.deviceReason = "initial-mib-downloaded"
+	dh.ReadyForSpecificOmciConfig = true
 	// *** should generate UniUnlockStateDone event *****
 	if dh.pUnlockStateFsm == nil {
 		dh.createUniLockFsm(false, UniUnlockStateDone)
@@ -1593,7 +1606,7 @@
 		logger.Errorw("error-updating-device-state", log.Fields{"device-id": dh.deviceID, "error": err})
 	}
 
-	logger.Debugw("DeviceReasonUpdate upon re-enable", log.Fields{
+	logger.Debugw("DeviceReasonUpdate upon disable", 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 {
@@ -1604,14 +1617,6 @@
 
 	//transfer the modified logical uni port state
 	dh.disableUniPortStateUpdate()
-
-	//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
 }
 
 func (dh *deviceHandler) processUniEnableStateDoneEvent(devEvent OnuDeviceEvent) {
@@ -1637,59 +1642,92 @@
 }
 
 func (dh *deviceHandler) processOmciAniConfigDoneEvent(devEvent OnuDeviceEvent) {
-	logger.Debugw("OmciAniConfigDone event received", log.Fields{"device-id": dh.deviceID})
-	// attention: the device reason update is done based on ONU-UNI-Port related activity
-	//  - which may cause some inconsistency
-	if dh.deviceReason != "tech-profile-config-download-success" {
-		// which may be the case from some previous actvity on another UNI Port of the ONU
-		if !dh.reconciling {
-			if err := dh.coreProxy.DeviceReasonUpdate(context.TODO(), dh.deviceID, "tech-profile-config-download-success"); err != nil {
-				//TODO with VOL-3045/VOL-3046: return the error and stop further processing
-				logger.Errorw("error-DeviceReasonUpdate to 'tech-profile-config-download-success'",
-					log.Fields{"device-id": dh.deviceID, "error": err})
+	if devEvent == OmciAniConfigDone {
+		logger.Debugw("OmciAniConfigDone event received", log.Fields{"device-id": dh.deviceID})
+		// attention: the device reason update is done based on ONU-UNI-Port related activity
+		//  - which may cause some inconsistency
+		if dh.deviceReason != "tech-profile-config-download-success" {
+			// which may be the case from some previous actvity even on this UNI Port (but also other UNI ports)
+			if !dh.reconciling {
+				if err := dh.coreProxy.DeviceReasonUpdate(context.TODO(), dh.deviceID, "tech-profile-config-download-success"); err != nil {
+					//TODO with VOL-3045/VOL-3046: return the error and stop further processing
+					logger.Errorw("error-DeviceReasonUpdate to tech-profile-config-download-success",
+						log.Fields{"device-id": dh.deviceID, "error": err})
+				} else {
+					logger.Infow("update dev reason to tech-profile-config-download-success",
+						log.Fields{"device-id": dh.deviceID})
+				}
 			} else {
-				logger.Infow("update dev reason to 'tech-profile-config-download-success'",
+				logger.Debugw("reconciling - don't notify core about DeviceReasonUpdate to tech-profile-config-download-success",
 					log.Fields{"device-id": dh.deviceID})
 			}
-		} else {
-			logger.Debugw("reconciling - don't notify core about DeviceReasonUpdate to tech-profile-config-download-success",
-				log.Fields{"device-id": dh.deviceID})
+			//set internal state anyway - as it was done
+			dh.deviceReason = "tech-profile-config-download-success"
 		}
-		//set internal state anyway - as it was done
-		dh.deviceReason = "tech-profile-config-download-success"
-	}
-	if dh.reconciling {
-		go dh.reconcileDeviceFlowConfig()
+		if dh.reconciling {
+			go dh.reconcileDeviceFlowConfig()
+		}
+	} else { // should be the OmciAniResourceRemoved block
+		logger.Debugw("OmciAniResourceRemoved event received", log.Fields{"device-id": dh.deviceID})
+		// attention: the device reason update is done based on ONU-UNI-Port related activity
+		//  - which may cause some inconsistency
+		if dh.deviceReason != "tech-profile-config-delete-success" {
+			// which may be the case from some previous actvity even on this ONU port (but also other UNI ports)
+			if err := dh.coreProxy.DeviceReasonUpdate(context.TODO(), dh.deviceID, "tech-profile-config-delete-success"); err != nil {
+				//TODO with VOL-3045/VOL-3046: return the error and stop further processing
+				logger.Errorw("error-DeviceReasonUpdate to tech-profile-config-delete-success",
+					log.Fields{"device-id": dh.deviceID, "error": err})
+			} else {
+				logger.Infow("update dev reason to tech-profile-config-delete-success",
+					log.Fields{"device-id": dh.deviceID})
+			}
+			//set internal state anyway - as it was done
+			dh.deviceReason = "tech-profile-config-delete-success"
+		}
 	}
 }
 
-func (dh *deviceHandler) processOmciVlanFilterDoneEvent(devEvent OnuDeviceEvent) {
+func (dh *deviceHandler) processOmciVlanFilterDoneEvent(aDevEvent OnuDeviceEvent) {
 	logger.Debugw("OmciVlanFilterDone event received",
-		log.Fields{"device-id": dh.deviceID})
+		log.Fields{"device-id": dh.deviceID, "event": aDevEvent})
 	// attention: the device reason update is done based on ONU-UNI-Port related activity
 	//  - which may cause some inconsistency
-	//			yield self.core_proxy.device_reason_update(self.device_id, 'omci-flows-pushed')
 
-	if dh.deviceReason != "omci-flows-pushed" {
-		// which may be the case from some previous actvity on another UNI Port of the ONU
-		// or even some previous flow add activity on the same port
-		if !dh.reconciling {
-			if err := dh.coreProxy.DeviceReasonUpdate(context.TODO(), dh.deviceID, "omci-flows-pushed"); err != nil {
-				logger.Errorw("error-DeviceReasonUpdate to 'omci-flows-pushed'",
-					log.Fields{"device-id": dh.deviceID, "error": err})
+	if aDevEvent == OmciVlanFilterAddDone {
+		if dh.deviceReason != "omci-flows-pushed" {
+			// which may be the case from some previous actvity on another UNI Port of the ONU
+			// or even some previous flow add activity on the same port
+			if !dh.reconciling {
+				if err := dh.coreProxy.DeviceReasonUpdate(context.TODO(), dh.deviceID, "omci-flows-pushed"); err != nil {
+					logger.Errorw("error-DeviceReasonUpdate to omci-flows-pushed",
+						log.Fields{"device-id": dh.deviceID, "error": err})
+				} else {
+					logger.Infow("updated dev reason to omci-flows-pushed",
+						log.Fields{"device-id": dh.deviceID})
+				}
 			} else {
-				logger.Infow("updated dev reason to ''omci-flows-pushed'",
+				logger.Debugw("reconciling - don't notify core about DeviceReasonUpdate to omci-flows-pushed",
 					log.Fields{"device-id": dh.deviceID})
 			}
-		} else {
-			logger.Debugw("reconciling - don't notify core about DeviceReasonUpdate to omci-flows-pushed",
-				log.Fields{"device-id": dh.deviceID})
-		}
-		//set internal state anyway - as it was done
-		dh.deviceReason = "omci-flows-pushed"
+			//set internal state anyway - as it was done
+			dh.deviceReason = "omci-flows-pushed"
 
-		if dh.reconciling {
-			go dh.reconcileMetrics()
+			if dh.reconciling {
+				go dh.reconcileMetrics()
+			}
+		}
+	} else {
+		if dh.deviceReason != "omci-flows-deleted" {
+			//not relevant for reconcile
+			if err := dh.coreProxy.DeviceReasonUpdate(context.TODO(), dh.deviceID, "omci-flows-deleted"); err != nil {
+				logger.Errorw("error-DeviceReasonUpdate to omci-flows-deleted",
+					log.Fields{"device-id": dh.deviceID, "error": err})
+			} else {
+				logger.Infow("updated dev reason to omci-flows-deleted",
+					log.Fields{"device-id": dh.deviceID})
+			}
+			//set internal state anyway - as it was done
+			dh.deviceReason = "omci-flows-deleted"
 		}
 	}
 }
@@ -1704,32 +1742,26 @@
 	case MibDownloadDone:
 		{
 			dh.processMibDownloadDoneEvent(devEvent)
-
 		}
 	case UniUnlockStateDone:
 		{
 			dh.processUniUnlockStateDoneEvent(devEvent)
-
 		}
 	case UniEnableStateDone:
 		{
 			dh.processUniEnableStateDoneEvent(devEvent)
-
 		}
 	case UniDisableStateDone:
 		{
 			dh.processUniDisableStateDoneEvent(devEvent)
-
 		}
-	case OmciAniConfigDone:
+	case OmciAniConfigDone, OmciAniResourceRemoved:
 		{
 			dh.processOmciAniConfigDoneEvent(devEvent)
-
 		}
-	case OmciVlanFilterDone:
+	case OmciVlanFilterAddDone, OmciVlanFilterRemDone:
 		{
 			dh.processOmciVlanFilterDoneEvent(devEvent)
-
 		}
 	default:
 		{
@@ -2124,7 +2156,7 @@
 			loMatchVlan, loSetVlan, loSetPcp)
 	}
 	return dh.createVlanFilterFsm(apUniPort, loTpID, loCookieSlice,
-		loMatchVlan, loSetVlan, loSetPcp, OmciVlanFilterDone)
+		loMatchVlan, loSetVlan, loSetPcp, OmciVlanFilterAddDone)
 }
 
 //removeFlowItemFromUniPort parses the actual flow item to remove it from the UniPort
@@ -2136,7 +2168,7 @@
 	// 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)
+	// - some possible 'delete-all' sequence would have to 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})
 
@@ -2159,9 +2191,12 @@
 	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)",
+	logger.Debugw("flow-remove called, but no flow is configured (no VlanConfigFsm, flow already removed) ",
 		log.Fields{"device-id": dh.deviceID})
 	//but as we regard the flow as not existing = removed we respond just ok
+	// and treat the reason accordingly (which in the normal removal procedure is initiated by the FSM)
+	go dh.deviceProcStatusUpdate(OmciVlanFilterRemDone)
+
 	return nil
 }
 
@@ -2210,6 +2245,26 @@
 	return nil
 }
 
+//VerifyVlanConfigRequest checks on existence of a given uniPort
+// and starts verification of flow config based on that
+func (dh *deviceHandler) VerifyVlanConfigRequest(aUniID uint8) {
+	//ensure that the given uniID is available (configured) in the UniPort class (used for OMCI entities)
+	var pCurrentUniPort *onuUniPort
+	for _, uniPort := range dh.uniEntityMap {
+		// only if this port is validated for operState transfer
+		if uniPort.uniID == uint8(aUniID) {
+			pCurrentUniPort = uniPort
+			break //found - end search loop
+		}
+	}
+	if pCurrentUniPort == nil {
+		logger.Debugw("VerifyVlanConfig aborted: requested uniID not found in PortDB",
+			log.Fields{"device-id": dh.deviceID, "uni-id": aUniID})
+		return
+	}
+	dh.verifyUniVlanConfigRequest(pCurrentUniPort)
+}
+
 //verifyUniVlanConfigRequest checks on existence of flow configuration and starts it accordingly
 func (dh *deviceHandler) verifyUniVlanConfigRequest(apUniPort *onuUniPort) {
 	//TODO!! verify and start pending flow configuration
diff --git a/internal/pkg/onuadaptercore/omci_ani_config.go b/internal/pkg/onuadaptercore/omci_ani_config.go
index 70f172a..4c5f22f 100644
--- a/internal/pkg/onuadaptercore/omci_ani_config.go
+++ b/internal/pkg/onuadaptercore/omci_ani_config.go
@@ -552,30 +552,32 @@
 		return
 	}
 	logger.Debugw("CreateResponse Data", log.Fields{"device-id": oFsm.deviceID, "data-fields": msgObj})
-	if msgObj.Result != me.Success {
+	if msgObj.Result == me.Success || msgObj.Result == me.InstanceExists {
+		//if the result is ok or Instance already exists (latest needed at least as long as we do not clear the OMCI techProfile data)
+		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.pLastTxMeInstance.GetName() {
+			case "Ieee8021PMapperServiceProfile":
+				{ // let the FSM proceed ...
+					_ = oFsm.pAdaptFsm.pFsm.Event(aniEvRxDot1pmapCResp)
+				}
+			case "MacBridgePortConfigurationData":
+				{ // let the FSM proceed ...
+					_ = oFsm.pAdaptFsm.pFsm.Event(aniEvRxMbpcdResp)
+				}
+			case "GemPortNetworkCtp", "GemInterworkingTerminationPoint":
+				{ // let aniConfig Multi-Id processing proceed by stopping the wait function
+					oFsm.omciMIdsResponseReceived <- true
+				}
+			}
+		}
+	} else {
 		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.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.pLastTxMeInstance.GetName() {
-		case "Ieee8021PMapperServiceProfile":
-			{ // let the FSM proceed ...
-				_ = oFsm.pAdaptFsm.pFsm.Event(aniEvRxDot1pmapCResp)
-			}
-		case "MacBridgePortConfigurationData":
-			{ // let the FSM proceed ...
-				_ = oFsm.pAdaptFsm.pFsm.Event(aniEvRxMbpcdResp)
-			}
-		case "GemPortNetworkCtp", "GemInterworkingTerminationPoint":
-			{ // let aniConfig Multi-Id processing proceed by stopping the wait function
-				oFsm.omciMIdsResponseReceived <- true
-			}
-		}
-	}
 }
 
 func (oFsm *uniPonAniConfigFsm) handleOmciAniConfigSetResponseMessage(msg OmciMessage) {
diff --git a/internal/pkg/onuadaptercore/omci_cc.go b/internal/pkg/onuadaptercore/omci_cc.go
index 7b10d12..f53479f 100644
--- a/internal/pkg/onuadaptercore/omci_cc.go
+++ b/internal/pkg/onuadaptercore/omci_cc.go
@@ -1656,6 +1656,7 @@
 	return nil
 }
 
+// nolint: unused
 func (oo *omciCC) sendCreateMulticastGemIWTPVar(ctx context.Context, timeout int, highPrio bool,
 	rxChan chan Message, params ...me.ParamData) *me.ManagedEntity {
 	tid := oo.getNextTid(highPrio)
@@ -1694,6 +1695,7 @@
 	return nil
 }
 
+// nolint: unused
 func (oo *omciCC) sendCreateMulticastOperationProfileVar(ctx context.Context, timeout int, highPrio bool,
 	rxChan chan Message, params ...me.ParamData) *me.ManagedEntity {
 	tid := oo.getNextTid(highPrio)
@@ -1735,6 +1737,7 @@
 	return nil
 }
 
+// nolint: unused
 func (oo *omciCC) sendSetMulticastOperationProfileVar(ctx context.Context, timeout int, highPrio bool,
 	rxChan chan Message, params ...me.ParamData) *me.ManagedEntity {
 	tid := oo.getNextTid(highPrio)
@@ -1776,6 +1779,7 @@
 	return nil
 }
 
+// nolint: unused
 func (oo *omciCC) sendCreateMulticastSubConfigInfoVar(ctx context.Context, timeout int, highPrio bool,
 	rxChan chan Message, params ...me.ParamData) *me.ManagedEntity {
 	tid := oo.getNextTid(highPrio)
diff --git a/internal/pkg/onuadaptercore/omci_vlan_config.go b/internal/pkg/onuadaptercore/omci_vlan_config.go
index b8605e0..2fbc5db 100644
--- a/internal/pkg/onuadaptercore/omci_vlan_config.go
+++ b/internal/pkg/onuadaptercore/omci_vlan_config.go
@@ -84,6 +84,7 @@
 	vlanEvRxConfigVtfd    = "vlanEvRxConfigVtfd"
 	vlanEvRxConfigEvtocd  = "vlanEvRxConfigEvtocd"
 	vlanEvIncrFlowConfig  = "vlanEvIncrFlowConfig"
+	vlanEvRenew           = "vlanEvRenew"
 	vlanEvRemFlowConfig   = "vlanEvRemFlowConfig"
 	vlanEvRemFlowDone     = "vlanEvRemFlowDone"
 	vlanEvFlowDataRemoved = "vlanEvFlowDataRemoved"
@@ -150,6 +151,7 @@
 	vtfdID                      uint16
 	evtocdID                    uint16
 	pLastTxMeInstance           *me.ManagedEntity
+	requestEventOffset          uint8
 }
 
 //NewUniVlanConfigFsm is the 'constructor' for the state machine to config the PON ANI ports
@@ -190,6 +192,7 @@
 			{Name: vlanEvRxConfigEvtocd, Src: []string{vlanStConfigEvtocd, vlanStConfigIncrFlow},
 				Dst: vlanStConfigDone},
 			{Name: vlanEvIncrFlowConfig, Src: []string{vlanStConfigDone}, Dst: vlanStConfigIncrFlow},
+			{Name: vlanEvRenew, Src: []string{vlanStConfigIncrFlow}, Dst: vlanStStarting},
 			{Name: vlanEvRemFlowConfig, Src: []string{vlanStConfigDone}, Dst: vlanStRemoveFlow},
 			{Name: vlanEvRemFlowDone, Src: []string{vlanStRemoveFlow}, Dst: vlanStCleanupDone},
 			{Name: vlanEvFlowDataRemoved, Src: []string{vlanStCleanupDone}, Dst: vlanStConfigDone},
@@ -403,7 +406,25 @@
 				"device-id": oFsm.deviceID, "flow-number": oFsm.numUniFlows})
 			return fmt.Errorf(" UniVlanConfigFsm flow limit exceeded %s", oFsm.deviceID)
 		}
-	} //new flow
+	} else {
+		// no activity within the FSM for OMCI processing, the deviceReason may be updated immediately
+		if oFsm.numUniFlows == oFsm.configuredUniFlow {
+			//all requested rules really have been configured
+			// state transition notification is checked in deviceHandler
+			if oFsm.pDeviceHandler != nil {
+				//also the related TechProfile was already configured
+				logger.Debugw("UniVlanConfigFsm rule already set - send immediate add-success event for reason update", log.Fields{
+					"device-id": oFsm.deviceID})
+				go oFsm.pDeviceHandler.deviceProcStatusUpdate(oFsm.requestEvent)
+			}
+		} else {
+			//  avoid device reason update as the rule config connected to this flow may still be in progress
+			//  and the device reason should only be updated on success of rule config
+			logger.Debugw("UniVlanConfigFsm rule already set but configuration ongoing, suppress early add-success event for reason update",
+				log.Fields{"device-id": oFsm.deviceID,
+					"NumberofRules": oFsm.numUniFlows, "Configured rules": oFsm.configuredUniFlow})
+		}
+	}
 
 	if !flowEntryMatch || flowCookieModify { // some change was done to the flow entries
 		//permanently store flow config for reconcile case
@@ -475,20 +496,26 @@
 					} // 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{
+					// no activity within the FSM for OMCI processing, the deviceReason may be updated immediately
+					// state transition notification is checked in deviceHandler
+					if oFsm.pDeviceHandler != nil {
+						//making use of the add->remove successor enum assumption/definition
+						go oFsm.pDeviceHandler.deviceProcStatusUpdate(OnuDeviceEvent((uint8(oFsm.requestEvent) + 1)))
+					}
+					logger.Debugw("UniVlanConfigFsm flow removal - rule persists with still valid cookies", 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
+				if oFsm.pDeviceHandler != nil {
+					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
@@ -502,6 +529,12 @@
 		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
+		// no activity within the FSM for OMCI processing, the deviceReason may be updated immediately
+		// state transition notification is checked in deviceHandler
+		if oFsm.pDeviceHandler != nil {
+			//making use of the add->remove successor enum assumption/definition
+			go oFsm.pDeviceHandler.deviceProcStatusUpdate(OnuDeviceEvent((uint8(oFsm.requestEvent) + 1)))
+		}
 		return nil
 	} //unknown cookie
 
@@ -588,6 +621,7 @@
 func (oFsm *UniVlanConfigFsm) enterConfigEvtocd(e *fsm.Event) {
 	logger.Debugw("UniVlanConfigFsm - start config EVTOCD loop", log.Fields{
 		"in state": e.FSM.Current(), "device-id": oFsm.deviceID})
+	oFsm.requestEventOffset = 0 //0 offset for last flow-add activity
 	go oFsm.performConfigEvtocdEntries(0)
 }
 
@@ -617,7 +651,8 @@
 	// 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 {
-		oFsm.pDeviceHandler.deviceProcStatusUpdate(oFsm.requestEvent)
+		//making use of the add->remove successor enum assumption/definition
+		go oFsm.pDeviceHandler.deviceProcStatusUpdate(OnuDeviceEvent((uint8(oFsm.requestEvent) + oFsm.requestEventOffset)))
 	}
 }
 
@@ -627,6 +662,18 @@
 		"device-id": oFsm.deviceID})
 	oFsm.mutexFlowParams.Lock()
 
+	if oFsm.configuredUniFlow == 0 {
+		oFsm.mutexFlowParams.Unlock()
+		// this is a restart with a complete new flow, we can re-use the initial flow config control
+		// including the check, if the related techProfile is (still) available (probably also removed in between)
+		// calling some FSM event must be decoupled
+		pConfigVlanStateBaseFsm := oFsm.pAdaptFsm.pFsm
+		go func(a_pBaseFsm *fsm.FSM) {
+			_ = a_pBaseFsm.Event(vlanEvRenew)
+		}(pConfigVlanStateBaseFsm)
+		return
+	}
+
 	if oFsm.uniVlanFlowParamsSlice[oFsm.configuredUniFlow].VlanRuleParams.SetVid == uint32(of.OfpVlanId_OFPVID_PRESENT) {
 		// meaning transparent setup - no specific VTFD setting required
 		oFsm.mutexFlowParams.Unlock()
@@ -697,10 +744,14 @@
 		if err != nil {
 			logger.Errorw("VTFD create/set failed, aborting VlanConfig FSM!",
 				log.Fields{"device-id": oFsm.deviceID})
-			_ = oFsm.pAdaptFsm.pFsm.Event(vlanEvReset)
+			pConfigVlanStateBaseFsm := oFsm.pAdaptFsm.pFsm
+			go func(a_pBaseFsm *fsm.FSM) {
+				_ = a_pBaseFsm.Event(vlanEvReset)
+			}(pConfigVlanStateBaseFsm)
 			return
 		}
 	}
+	oFsm.requestEventOffset = 0 //0 offset for last flow-add activity
 	go oFsm.performConfigEvtocdEntries(oFsm.configuredUniFlow)
 }
 
@@ -710,6 +761,8 @@
 		"in state": e.FSM.Current(), "with last cookie": oFsm.uniRemoveFlowsSlice[0].cookie,
 		"device-id": oFsm.deviceID})
 
+	pConfigVlanStateBaseFsm := oFsm.pAdaptFsm.pFsm
+	loAllowSpecificOmciConfig := oFsm.pDeviceHandler.ReadyForSpecificOmciConfig
 	loVlanEntryClear := uint8(0)
 	loVlanEntryRmPos := uint8(0x80) //with indication 'invalid' in bit 7
 	//shallow copy is sufficient as no reference variables are used within struct
@@ -732,10 +785,15 @@
 			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
+			loVlanEntryClear = 1           //full VlanFilter clear request
+			if loAllowSpecificOmciConfig { //specific OMCI config is expected to work acc. to the device state
+				meInstance := oFsm.pOmciCC.sendDeleteVtfd(context.TODO(), ConstDefaultOmciTimeout, true,
+					oFsm.pAdaptFsm.commChan, oFsm.vtfdID)
+				oFsm.pLastTxMeInstance = meInstance
+			} else {
+				logger.Debugw("UniVlanConfigFsm delete VTFD OMCI handling skipped based on device state", log.Fields{
+					"device-id": oFsm.deviceID, "device-state": oFsm.pDeviceHandler.deviceReason})
+			}
 		} 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
@@ -764,29 +822,39 @@
 					"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
-					},
+				if loAllowSpecificOmciConfig { //specific OMCI config is expected to work acc. to the device state
+					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.Debugw("UniVlanConfigFsm set VTFD OMCI handling skipped based on device state", log.Fields{
+						"device-id": oFsm.deviceID, "device-state": oFsm.pDeviceHandler.deviceReason})
 				}
-				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 loAllowSpecificOmciConfig { //specific OMCI config is expected to work acc. to the device state
+				//waiting on response
+				err := oFsm.waitforOmciResponse()
+				if err != nil {
+					logger.Errorw("VTFD delete/reset failed, aborting VlanConfig FSM!",
+						log.Fields{"device-id": oFsm.deviceID})
+					// calling some FSM event must be decoupled
+					go func(a_pBaseFsm *fsm.FSM) {
+						_ = a_pBaseFsm.Event(vlanEvReset)
+					}(pConfigVlanStateBaseFsm)
+					return
+				}
 			}
 
 			if loVlanEntryClear == 1 {
@@ -803,7 +871,17 @@
 		}
 	}
 
-	go oFsm.removeEvtocdEntries(loRuleParams)
+	if loAllowSpecificOmciConfig { //specific OMCI config is expected to work acc. to the device state
+		go oFsm.removeEvtocdEntries(loRuleParams)
+	} else {
+		// OMCI processing is not done, expectation is to have the ONU in some basic config state accordingly
+		logger.Debugw("UniVlanConfigFsm remove EVTOCD OMCI handling skipped based on device state", log.Fields{
+			"device-id": oFsm.deviceID})
+		// calling some FSM event must be decoupled
+		go func(a_pBaseFsm *fsm.FSM) {
+			_ = a_pBaseFsm.Event(vlanEvRemFlowDone)
+		}(pConfigVlanStateBaseFsm)
+	}
 }
 
 func (oFsm *UniVlanConfigFsm) enterVlanCleanupDone(e *fsm.Event) {
@@ -825,6 +903,7 @@
 	}
 	oFsm.mutexFlowParams.Unlock()
 
+	oFsm.requestEventOffset = 1 //offset 1 for last flow-remove activity
 	//return to the basic config verification state
 	pConfigVlanStateAFsm := oFsm.pAdaptFsm
 	if pConfigVlanStateAFsm != nil {
@@ -1282,7 +1361,7 @@
 		}
 	}
 
-	// if Config has been done for all GemPort instances let the FSM proceed
+	// if Config has been done for all EVTOCD entries let the FSM proceed
 	logger.Debugw("EVTOCD set loop finished", log.Fields{"device-id": oFsm.deviceID})
 	oFsm.configuredUniFlow++ // one (more) flow configured
 	_ = oFsm.pAdaptFsm.pFsm.Event(vlanEvRxConfigEvtocd)
@@ -1483,7 +1562,7 @@
 		}
 	}
 
-	// if Config has been done for all GemPort instances let the FSM proceed
+	// if Config has been done for all EVTOCD entries let the FSM proceed
 	logger.Debugw("EVTOCD filter remove loop finished", log.Fields{"device-id": oFsm.deviceID})
 	_ = oFsm.pAdaptFsm.pFsm.Event(vlanEvRemFlowDone)
 }
diff --git a/internal/pkg/onuadaptercore/onu_device_entry.go b/internal/pkg/onuadaptercore/onu_device_entry.go
index 27c0865..ad683b0 100644
--- a/internal/pkg/onuadaptercore/onu_device_entry.go
+++ b/internal/pkg/onuadaptercore/onu_device_entry.go
@@ -118,29 +118,33 @@
 	// Events of interest to Device Adapters and OpenOMCI State Machines
 
 	// DeviceStatusInit - default start state
-	DeviceStatusInit OnuDeviceEvent = 0
+	DeviceStatusInit OnuDeviceEvent = iota
 	// MibDatabaseSync - MIB database sync (upload done)
-	MibDatabaseSync OnuDeviceEvent = 1
+	MibDatabaseSync
 	// OmciCapabilitiesDone - OMCI ME and message type capabilities known
-	OmciCapabilitiesDone OnuDeviceEvent = 2
+	OmciCapabilitiesDone
 	// MibDownloadDone - // MIB download done
-	MibDownloadDone OnuDeviceEvent = 3
+	MibDownloadDone
 	// UniLockStateDone - Uni ports admin set to lock
-	UniLockStateDone OnuDeviceEvent = 4
+	UniLockStateDone
 	// UniUnlockStateDone - Uni ports admin set to unlock
-	UniUnlockStateDone OnuDeviceEvent = 5
+	UniUnlockStateDone
 	// UniDisableStateDone - Uni ports admin set to lock based on device disable
-	UniDisableStateDone OnuDeviceEvent = 6
+	UniDisableStateDone
 	// UniEnableStateDone - Uni ports admin set to unlock based on device re-enable
-	UniEnableStateDone OnuDeviceEvent = 7
+	UniEnableStateDone
 	// PortLinkUp - Port link state change
-	PortLinkUp OnuDeviceEvent = 8
+	PortLinkUp
 	// PortLinkDw - Port link state change
-	PortLinkDw OnuDeviceEvent = 9
+	PortLinkDw
 	// OmciAniConfigDone -  AniSide config according to TechProfile done
-	OmciAniConfigDone OnuDeviceEvent = 10
-	// OmciVlanFilterDone - Omci Vlan config according to flowConfig done
-	OmciVlanFilterDone OnuDeviceEvent = 11
+	OmciAniConfigDone
+	// OmciAniResourceRemoved - AniSide TechProfile related resource (Gem/TCont) removed
+	OmciAniResourceRemoved // needs to be the successor of OmciAniConfigDone!
+	// OmciVlanFilterAddDone - Omci Vlan config done according to flow-add
+	OmciVlanFilterAddDone
+	// OmciVlanFilterRemDone - Omci Vlan config done according to flow-remove
+	OmciVlanFilterRemDone // needs to be the successor of OmciVlanFilterAddDone!
 	// Add other events here as needed (alarms separate???)
 )
 
@@ -646,8 +650,28 @@
 				return true
 			}
 			//entry already exists
-			logger.Debugw("UniTp path already exists", log.Fields{"device-id": oo.deviceID, "uniID": aUniID, "path": aPathString})
-			return false
+			if aPathString == "" {
+				//no active TechProfile
+				logger.Debugw("UniTp path has already been removed - no AniSide config to be removed", log.Fields{
+					"device-id": oo.deviceID, "uniID": aUniID})
+				// attention 201105: this block is at the moment entered for each of subsequent GemPortDeletes and TContDelete
+				//   as the path is already cleared with the first GemPort - this will probably change with the upcoming real
+				//   TechProfile removal (still TODO), but anyway the reasonUpdate initiated here should not harm overall behavior
+				go oo.baseDeviceHandler.deviceProcStatusUpdate(OmciAniResourceRemoved)
+				// no flow config pending on 'remove' so far
+			} else {
+				//the given TechProfile already exists and is assumed to be active - update devReason as if the config has been done here
+				//was needed e.g. in voltha POD Tests:Validate authentication on a disabled ONU
+				//  (as here the TechProfile has not been removed with the disable-device before the new enable-device)
+				logger.Debugw("UniTp path already exists - TechProfile supposed to be active", log.Fields{
+					"device-id": oo.deviceID, "uniID": aUniID, "path": aPathString})
+				//no deviceReason update (deviceProcStatusUpdate) here to ensure 'omci_flows_pushed' state within disable/enable procedure of ATT scenario
+				//  (during which the flows are removed/re-assigned but the techProf is left active)
+				//and as the TechProfile is regarded as active we have to verify, if some flow configuration still waits on it
+				//  (should not be the case, but should not harm or be more robust ...)
+				go oo.baseDeviceHandler.VerifyVlanConfigRequest(aUniID)
+			}
+			return false //indicate 'no change' - nothing more to do, TechProf inter-adapter message is return with success anyway here
 		}
 	}
 	//no entry exists for uniId
@@ -664,25 +688,6 @@
 	return true
 }
 
-// deleteTpResource removes Resources from the ONU's specified Uni
-func (oo *OnuDeviceEntry) deleteTpResource(ctx context.Context,
-	aUniID uint8, aPathString string, aResource resourceEntry, aEntryID uint32,
-	wg *sync.WaitGroup) {
-	defer wg.Done()
-	logger.Debugw("this would remove TP resources from ONU's UNI", log.Fields{
-		"device-id": oo.deviceID, "uniID": aUniID, "path": aPathString, "Resource": aResource})
-	//TODO!!!
-	//delete the given resource from ONU OMCI config and data base - as background routine
-	/*
-		var processingStep uint8 = 1 // used to synchronize the different processing steps with chTpConfigProcessingStep
-		go onuTp.deleteAniResource(ctx, processingStep)
-		if !onuTP.waitForTimeoutOrCompletion(ctx, chTpConfigProcessingStep, processingStep) {
-			//timeout or error detected
-			return
-		}
-	*/
-}
-
 func (oo *OnuDeviceEntry) updateOnuUniFlowConfig(aUniID uint8, aUniVlanFlowParams *[]uniVlanFlowParams) {
 
 	for k, v := range oo.sOnuPersistentData.PersUniConfig {
diff --git a/internal/pkg/onuadaptercore/onu_uni_tp.go b/internal/pkg/onuadaptercore/onu_uni_tp.go
index e052684..97b4dbd 100644
--- a/internal/pkg/onuadaptercore/onu_uni_tp.go
+++ b/internal/pkg/onuadaptercore/onu_uni_tp.go
@@ -474,6 +474,45 @@
 	}
 }
 
+// deleteTpResource removes Resources from the ONU's specified Uni
+func (onuTP *onuUniTechProf) deleteTpResource(ctx context.Context,
+	aUniID uint8, aPathString string, aResource resourceEntry, aEntryID uint32,
+	wg *sync.WaitGroup) {
+	defer wg.Done()
+	logger.Debugw("this would remove TP resources from ONU's UNI", log.Fields{
+		"device-id": onuTP.deviceID, "uniID": aUniID, "path": aPathString, "Resource": aResource})
+	if cResourceTcont == aResource {
+		//the TechProfile indicated by path is considered for removal
+		//  by now we do not clear the OMCI related configuration (to be done later)
+		//  so we use this position here just to remove the internal stored profile data
+		//    (needed for checking the existence of the TechProfile after some profile delete)
+		//  at the oment we only admit 1 TechProfile (T-Cont), so by now we can just remove the only existing TechProfile
+		//  TODO: To be updated with multi-T-Cont implementation
+		logger.Debugw("DeleteTcont clears the existing internal profile", log.Fields{
+			"device-id": onuTP.deviceID, "uniID": aUniID, "path": aPathString, "Resource": aResource})
+		onuTP.clearAniSideConfig(aUniID)
+		// reset also the FSM in order to admit a new OMCI configuration in case a new profile is created
+		// FSM stop maybe encapsulated as OnuTP method - perhaps later in context of module splitting
+		if onuTP.pAniConfigFsm != nil {
+			_ = onuTP.pAniConfigFsm.pAdaptFsm.pFsm.Event(aniEvReset)
+		}
+
+		//TODO!!! - the real processing could look like that (for starting the removal, where the clearAniSideConfig is done implicitly):
+		//delete the given resource from ONU OMCI config and data base - as background routine
+		/*
+			var processingStep uint8 = 1 // used to synchronize the different processing steps with chTpConfigProcessingStep
+			go onuTp.deleteAniResource(ctx, processingStep)
+			if !onuTP.waitForTimeoutOrCompletion(ctx, chTpConfigProcessingStep, processingStep) {
+				//timeout or error detected
+				return
+			}
+		*/
+	}
+	//if implemented, the called FSM would generate an adequate event if config has been done,
+	//  by now we just stimulate this event here as 'done' - TODO!!: to be removed after full implementation
+	go onuTP.baseDeviceHandler.deviceProcStatusUpdate(OmciAniResourceRemoved)
+}
+
 // runAniConfigFsm starts the AniConfig FSM to transfer the OMCI related commands for  ANI side configuration
 func (onuTP *onuUniTechProf) runAniConfigFsm(aProcessingStep uint8) {
 	/*  Uni related ANI config procedure -
diff --git a/internal/pkg/onuadaptercore/openonu.go b/internal/pkg/onuadaptercore/openonu.go
index 7056cd7..2d1ea5a 100644
--- a/internal/pkg/onuadaptercore/openonu.go
+++ b/internal/pkg/onuadaptercore/openonu.go
@@ -315,34 +315,28 @@
 //Update_flows_incrementally updates (add/remove) the flows on a given device
 func (oo *OpenONUAC) Update_flows_incrementally(device *voltha.Device,
 	flows *openflow_13.FlowChanges, groups *openflow_13.FlowGroupChanges, flowMetadata *voltha.FlowMetadata) error {
-	// no point in pushing omci flows if the device isn't reachable
-	if device.ConnectStatus != voltha.ConnectStatus_REACHABLE ||
-		device.AdminState != voltha.AdminState_ENABLED {
-		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] ...)
-	}
+
+	//flow config is relayed to handler even if the device might be in some 'inactive' state
+	// let the handler or related FSM's decide, what to do with the modified flow state info
+	// at least the flow-remove must be done in respect to internal data, while OMCI activity might not be needed here
 
 	// For now, there is no support for group changes (as in the actual Py-adapter code)
+	//   but processing is continued for flowUpdate possibly also set in the request
 	if groups.ToAdd != nil && groups.ToAdd.Items != nil {
-		logger.Debugw("Update-flow-incr: group add not supported (ignored)", log.Fields{"deviceId": device.Id})
+		logger.Warnw("Update-flow-incr: group add not supported (ignored)", log.Fields{"device-id": device.Id})
 	}
 	if groups.ToRemove != nil && groups.ToRemove.Items != nil {
-		logger.Debugw("Update-flow-incr: group remove not supported (ignored)", log.Fields{"deviceId": device.Id})
+		logger.Warnw("Update-flow-incr: group remove not supported (ignored)", log.Fields{"device-id": device.Id})
 	}
 	if groups.ToUpdate != nil && groups.ToUpdate.Items != nil {
-		logger.Debugw("Update-flow-incr: group update not supported (ignored)", log.Fields{"deviceId": device.Id})
+		logger.Warnw("Update-flow-incr: group update not supported (ignored)", log.Fields{"device-id": device.Id})
 	}
 
 	if handler := oo.getDeviceHandler(device.Id); handler != nil {
 		err := handler.FlowUpdateIncremental(flows, groups, flowMetadata)
 		return err
 	}
-	logger.Warnw("no handler found for incremental flow update", log.Fields{"deviceId": device.Id})
+	logger.Warnw("no handler found for incremental flow update", log.Fields{"device-id": device.Id})
 	return fmt.Errorf(fmt.Sprintf("handler-not-found-%s", device.Id))
 }