[VOL-4553] openonuAdapterGo - reconciling with wrong MDS is not working in TT multi-UNI scenario

Change-Id: I3a49d3560c942168fbac53e0c503abfea785be23
diff --git a/VERSION b/VERSION
index ba053dd..f01dca1 100755
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.1.3-dev264
+2.2.0-dev265
diff --git a/internal/pkg/avcfg/omci_vlan_config.go b/internal/pkg/avcfg/omci_vlan_config.go
index 3194242..668d2c6 100755
--- a/internal/pkg/avcfg/omci_vlan_config.go
+++ b/internal/pkg/avcfg/omci_vlan_config.go
@@ -1327,15 +1327,15 @@
 		}(pConfigVlanStateBaseFsm)
 		return
 	}
+	if oFsm.lastFlowToReconcile {
+		//note: lastFlowToReconcile does not mean that this block may run only once within reconcilement here,
+		//  due to asynchronous event processing from SetUniFlowParams() it may be executed multiple times
+		logger.Debugw(ctx, "reconciling - flow processing finished", log.Fields{
+			"device-id": oFsm.deviceID, "uni-id": oFsm.pOnuUniPort.UniID})
+		oFsm.pDeviceHandler.SendChUniVlanConfigFinished(uint16(oFsm.pOnuUniPort.UniID))
+	}
 	if oFsm.pDeviceHandler.IsSkipOnuConfigReconciling() {
 		oFsm.ConfiguredUniFlow = oFsm.NumUniFlows
-		if oFsm.lastFlowToReconcile {
-			//note: lastFlowToReconcile does not mean that this block may run only once within reconcilement here,
-			//  due to asynchronous event processing from SetUniFlowParams() it may be executed multiple times
-			logger.Debugw(ctx, "reconciling - flow processing finished", log.Fields{
-				"device-id": oFsm.deviceID, "uni-id": oFsm.pOnuUniPort.UniID})
-			oFsm.pDeviceHandler.SendChUniVlanConfigFinished(uint16(oFsm.pOnuUniPort.UniID))
-		}
 		logger.Debugw(ctx, "reconciling - skip enterVlanConfigDone processing",
 			log.Fields{"NumUniFlows": oFsm.NumUniFlows, "ConfiguredUniFlow": oFsm.ConfiguredUniFlow, "device-id": oFsm.deviceID})
 		oFsm.mutexFlowParams.Unlock()
diff --git a/internal/pkg/core/device_handler.go b/internal/pkg/core/device_handler.go
index fb6d1ff..f74da5a 100755
--- a/internal/pkg/core/device_handler.go
+++ b/internal/pkg/core/device_handler.go
@@ -205,6 +205,8 @@
 	upgradeCanceled                bool
 	reconciling                    uint8
 	mutexReconcilingFlag           sync.RWMutex
+	reconcilingFirstPass           bool
+	mutexReconcilingFirstPassFlag  sync.RWMutex
 	reconcilingReasonUpdate        bool
 	mutexReconcilingReasonUpdate   sync.RWMutex
 	chUniVlanConfigReconcilingDone chan uint16 //channel to indicate that VlanConfig reconciling for a specific UNI has been finished
@@ -253,6 +255,7 @@
 	dh.UniVlanConfigFsmMap = make(map[uint8]*avcfg.UniVlanConfigFsm)
 	dh.reconciling = cNoReconciling
 	dh.reconcilingReasonUpdate = false
+	dh.reconcilingFirstPass = true
 	dh.chReconcilingFinished = make(chan bool)
 	dh.reconcileExpiryComplete = adapter.maxTimeoutReconciling //assumption is to have it as duration in s!
 	rECSeconds := int(dh.reconcileExpiryComplete / time.Second)
@@ -1042,30 +1045,25 @@
 		dh.stopReconciling(ctx, true, cWaitReconcileFlowNoActivity)
 		return
 	}
-
-	if dh.IsSkipOnuConfigReconciling() {
-		//only with 'SkipOnuConfig' we need to wait for all finished-signals
-		//  from vlanConfig processing of all UNI's.
-		logger.Debugw(ctx, "reconciling flows - waiting on ready indication of requested UNIs", log.Fields{
-			"device-id": dh.DeviceID, "expiry": dh.reconcileExpiryVlanConfig})
-		if executed := loWaitGroupWTO.WaitTimeout(dh.reconcileExpiryVlanConfig); executed {
-			logger.Debugw(ctx, "reconciling flows for all UNI's has been finished in time",
-				log.Fields{"device-id": dh.DeviceID})
-			dh.stopReconciling(ctx, true, cWaitReconcileFlowAbortOnSuccess)
-			if pDevEntry != nil {
-				pDevEntry.SendChReconcilingFlowsFinished(ctx, true)
-			}
-		} else {
-			logger.Errorw(ctx, "reconciling - timeout waiting for reconciling flows for all UNI's to be finished!",
-				log.Fields{"device-id": dh.DeviceID})
-			dh.stopReconciling(ctx, false, cWaitReconcileFlowAbortOnError)
-			if pDevEntry != nil {
-				pDevEntry.SendChReconcilingFlowsFinished(ctx, false)
-			}
-			return
+	logger.Debugw(ctx, "reconciling flows - waiting on ready indication of requested UNIs", log.Fields{
+		"device-id": dh.DeviceID, "expiry": dh.reconcileExpiryVlanConfig})
+	if executed := loWaitGroupWTO.WaitTimeout(dh.reconcileExpiryVlanConfig); executed {
+		logger.Debugw(ctx, "reconciling flows for all UNI's has been finished in time",
+			log.Fields{"device-id": dh.DeviceID})
+		dh.stopReconciling(ctx, true, cWaitReconcileFlowAbortOnSuccess)
+		if pDevEntry != nil {
+			pDevEntry.SendChReconcilingFlowsFinished(ctx, true)
 		}
-		_ = dh.ReasonUpdate(ctx, cmn.DrOmciFlowsPushed, dh.IsReconcilingReasonUpdate())
+	} else {
+		logger.Errorw(ctx, "reconciling - timeout waiting for reconciling flows for all UNI's to be finished!",
+			log.Fields{"device-id": dh.DeviceID})
+		dh.stopReconciling(ctx, false, cWaitReconcileFlowAbortOnError)
+		if pDevEntry != nil {
+			pDevEntry.SendChReconcilingFlowsFinished(ctx, false)
+		}
+		return
 	}
+	_ = dh.ReasonUpdate(ctx, cmn.DrOmciFlowsPushed, dh.IsReconcilingReasonUpdate())
 }
 
 func (dh *deviceHandler) updateReconcileFlowConfig(ctx context.Context, apUniPort *cmn.OnuUniPort,
@@ -1075,28 +1073,24 @@
 	lastFlowToReconcile := false
 	loUniID := apUniPort.UniID
 	for _, flowData := range aPersFlowParam {
-		if dh.IsSkipOnuConfigReconciling() {
-			if !(*apFlowsFound) {
-				*apFlowsFound = true
-				syncChannel := make(chan struct{})
-				// start go routine with select() on reconciling vlan config channel before
-				// starting vlan config reconciling process to prevent loss of any signal
-				// this routine just collects all the received 'flow-reconciled' signals - possibly from different UNI's
-				go dh.waitOnUniVlanConfigReconcilingReady(ctx, syncChannel, apWaitGroup)
-				//block until the wait routine is really blocked on channel input
-				//  in order to prevent to early ready signal from VlanConfig processing
-				<-syncChannel
-			}
-			if flowsProcessed == len(aPersFlowParam)-1 {
-				var uniAdded bool
-				lastFlowToReconcile = true
-				if aUniVlanConfigEntries, uniAdded = dh.appendIfMissing(aUniVlanConfigEntries, loUniID); uniAdded {
-					apWaitGroup.Add(1) //increment the waiting group
-				}
+		if !(*apFlowsFound) {
+			*apFlowsFound = true
+			syncChannel := make(chan struct{})
+			// start go routine with select() on reconciling vlan config channel before
+			// starting vlan config reconciling process to prevent loss of any signal
+			// this routine just collects all the received 'flow-reconciled' signals - possibly from different UNI's
+			go dh.waitOnUniVlanConfigReconcilingReady(ctx, syncChannel, apWaitGroup)
+			//block until the wait routine is really blocked on channel input
+			//  in order to prevent to early ready signal from VlanConfig processing
+			<-syncChannel
+		}
+		if flowsProcessed == len(aPersFlowParam)-1 {
+			var uniAdded bool
+			lastFlowToReconcile = true
+			if aUniVlanConfigEntries, uniAdded = dh.appendIfMissing(aUniVlanConfigEntries, loUniID); uniAdded {
+				apWaitGroup.Add(1) //increment the waiting group
 			}
 		}
-		// note for above block: also lastFlowToReconcile (as parameter to flow config below)
-		//   is only relevant in the vlanConfig processing for IsSkipOnuConfigReconciling = true
 		logger.Debugw(ctx, "reconciling - add flow with cookie slice", log.Fields{
 			"device-id": dh.DeviceID, "uni-id": loUniID,
 			"flowsProcessed": flowsProcessed, "cookies": flowData.CookieSlice})
@@ -1205,11 +1199,6 @@
 	}
 }
 
-func (dh *deviceHandler) reconcileEnd(ctx context.Context) {
-	logger.Debugw(ctx, "reconciling - completed!", log.Fields{"device-id": dh.DeviceID})
-	dh.stopReconciling(ctx, true, cWaitReconcileFlowNoActivity)
-}
-
 func (dh *deviceHandler) deleteDevicePersistencyData(ctx context.Context) error {
 	logger.Debugw(ctx, "delete device persistency data", log.Fields{"device-id": dh.DeviceID})
 
@@ -2408,7 +2397,7 @@
 		pDevEntry.MutexPersOnuConfig.RUnlock()
 		logger.Debugw(ctx, "reconciling - uni-ports were disabled by admin before adapter restart - keep the ports locked",
 			log.Fields{"device-id": dh.DeviceID})
-		go dh.ReconcileDeviceTechProf(ctx)
+		dh.ReconcileDeviceTechProf(ctx)
 		// reconcilement will be continued after ani config is done
 	} else {
 		pDevEntry.MutexPersOnuConfig.RUnlock()
@@ -2444,7 +2433,7 @@
 	} else {
 		logger.Debugw(ctx, "reconciling - don't notify core that onu went to active but trigger tech profile config",
 			log.Fields{"device-id": dh.DeviceID})
-		go dh.ReconcileDeviceTechProf(ctx)
+		dh.ReconcileDeviceTechProf(ctx)
 		// reconcilement will be continued after ani config is done
 	}
 }
@@ -2540,7 +2529,15 @@
 			_ = dh.ReasonUpdate(ctx, cmn.DrTechProfileConfigDownloadSuccess, !dh.IsReconciling() || dh.IsReconcilingReasonUpdate())
 		}
 		if dh.IsReconciling() {
-			go dh.ReconcileDeviceFlowConfig(ctx)
+			// during reconciling with OMCI configuration in TT multi-UNI scenario, OmciAniConfigDone is reached several times
+			// therefore it must be ensured that reconciling of flow config is only started on the first pass of this code position
+			dh.mutexReconcilingFirstPassFlag.Lock()
+			if dh.reconcilingFirstPass {
+				logger.Debugw(ctx, "reconciling - OmciAniConfigDone first pass, start flow processing", log.Fields{"device-id": dh.DeviceID})
+				dh.reconcilingFirstPass = false
+				go dh.ReconcileDeviceFlowConfig(ctx)
+			}
+			dh.mutexReconcilingFirstPassFlag.Unlock()
 		}
 	} else { // should be the OmciAniResourceRemoved block
 		logger.Debugw(ctx, "OmciAniResourceRemoved event received", log.Fields{"device-id": dh.DeviceID})
@@ -2564,9 +2561,6 @@
 			// which may be the case from some previous activity on another UNI Port of the ONU
 			// or even some previous flow add activity on the same port
 			_ = dh.ReasonUpdate(ctx, cmn.DrOmciFlowsPushed, !dh.IsReconciling() || dh.IsReconcilingReasonUpdate())
-			if dh.IsReconciling() {
-				go dh.reconcileEnd(ctx)
-			}
 		}
 	} else {
 		if dh.getDeviceReason() != cmn.DrOmciFlowsDeleted {
@@ -4066,6 +4060,7 @@
 			dh.reconciling = cNoReconciling
 			dh.mutexReconcilingFlag.Unlock()
 			dh.SetReconcilingReasonUpdate(false)
+			dh.SetReconcilingFirstPass(true)
 
 			if onuDevEntry := dh.GetOnuDeviceEntry(ctx, true); onuDevEntry == nil {
 				logger.Errorw(ctx, "No valid OnuDevice", log.Fields{"device-id": dh.DeviceID})
@@ -4109,6 +4104,12 @@
 	return dh.reconciling == cSkipOnuConfigReconciling
 }
 
+func (dh *deviceHandler) SetReconcilingFirstPass(value bool) {
+	dh.mutexReconcilingFirstPassFlag.Lock()
+	dh.reconcilingFirstPass = value
+	dh.mutexReconcilingFirstPassFlag.Unlock()
+}
+
 func (dh *deviceHandler) SetReconcilingReasonUpdate(value bool) {
 	dh.mutexReconcilingReasonUpdate.Lock()
 	dh.reconcilingReasonUpdate = value