[VOL-3828] subscriber flow remove fails in ATT scenario due to adverse sequence of flow add/del, + slight changes for MDS check
Signed-off-by: mpagenko <michael.pagenkopf@adtran.com>
Change-Id: I9071896f5b6ab1f99f65847d46f94b351dec38a6
diff --git a/internal/pkg/onuadaptercore/device_handler.go b/internal/pkg/onuadaptercore/device_handler.go
index 0f86675..c55afd3 100644
--- a/internal/pkg/onuadaptercore/device_handler.go
+++ b/internal/pkg/onuadaptercore/device_handler.go
@@ -104,19 +104,19 @@
cL2PmFsm
)
-type idleCheckStruct struct {
- idleCheckFunc func(*deviceHandler, context.Context, string) bool
- idleState string
+type omciIdleCheckStruct struct {
+ omciIdleCheckFunc func(*deviceHandler, context.Context, usedOmciConfigFsms, string) bool
+ omciIdleState string
}
-var fsmIdleStateFuncMap = map[usedOmciConfigFsms]idleCheckStruct{
- cUploadFsm: {(*deviceHandler).mibUploadFsmInIdleState, cMibUlFsmIdleState},
- cDownloadFsm: {(*deviceHandler).mibDownloadFsmInIdleState, cMibDlFsmIdleState},
- cUniLockFsm: {(*deviceHandler).devUniLockFsmInIdleState, cUniFsmIdleState},
- cUniUnLockFsm: {(*deviceHandler).devUniUnlockFsmInIdleState, cUniFsmIdleState},
- cAniConfigFsm: {(*deviceHandler).devAniConfigFsmInIdleState, cAniFsmIdleState},
- cUniVlanConfigFsm: {(*deviceHandler).devUniVlanConfigFsmInIdleState, cVlanFsmIdleState},
- cL2PmFsm: {(*deviceHandler).l2PmFsmInIdleState, cL2PmFsmIdleState},
+var fsmOmciIdleStateFuncMap = map[usedOmciConfigFsms]omciIdleCheckStruct{
+ cUploadFsm: {(*deviceHandler).isFsmInOmciIdleStateDefault, cMibUlFsmIdleState},
+ cDownloadFsm: {(*deviceHandler).isFsmInOmciIdleStateDefault, cMibDlFsmIdleState},
+ cUniLockFsm: {(*deviceHandler).isFsmInOmciIdleStateDefault, cUniFsmIdleState},
+ cUniUnLockFsm: {(*deviceHandler).isFsmInOmciIdleStateDefault, cUniFsmIdleState},
+ cAniConfigFsm: {(*deviceHandler).isAniConfigFsmInOmciIdleState, cAniFsmIdleState},
+ cUniVlanConfigFsm: {(*deviceHandler).isUniVlanConfigFsmInOmciIdleState, cVlanFsmIdleState},
+ cL2PmFsm: {(*deviceHandler).isFsmInOmciIdleStateDefault, cL2PmFsmIdleState},
}
const (
@@ -200,7 +200,8 @@
stopAlarmManager chan bool
stopHeartbeatCheck chan bool
uniEntityMap map[uint32]*onuUniPort
- lockVlanConfig sync.Mutex
+ mutexKvStoreContext sync.Mutex
+ lockVlanConfig sync.RWMutex
UniVlanConfigFsmMap map[uint8]*UniVlanConfigFsm
reconciling bool
mutexReconcilingFlag sync.RWMutex
@@ -231,7 +232,7 @@
//dh.metrics = pmmetrics.NewPmMetrics(cloned.Id, pmmetrics.Frequency(150), pmmetrics.FrequencyOverride(false), pmmetrics.Grouped(false), pmmetrics.Metrics(pmNames))
//TODO initialize the support classes.
dh.uniEntityMap = make(map[uint32]*onuUniPort)
- dh.lockVlanConfig = sync.Mutex{}
+ dh.lockVlanConfig = sync.RWMutex{}
dh.UniVlanConfigFsmMap = make(map[uint8]*UniVlanConfigFsm)
dh.reconciling = false
dh.chReconcilingFinished = make(chan bool)
@@ -322,7 +323,6 @@
// with restricted output of 16(?) bytes would be ...omciMsg.Message[:16]
logger.Debugw(ctx, "inter-adapter-recv-omci", log.Fields{
"device-id": dh.deviceID, "RxOmciMessage": hex.EncodeToString(omciMsg.Message)})
- //receive_message(omci_msg.message)
pDevEntry := dh.getOnuDeviceEntry(ctx, true)
if pDevEntry != nil {
if pDevEntry.PDevOmciCC != nil {
@@ -848,7 +848,6 @@
}
pDevEntry.persUniConfigMutex.RLock()
defer pDevEntry.persUniConfigMutex.RUnlock()
-
if len(pDevEntry.sOnuPersistentData.PersUniConfig) == 0 {
logger.Debugw(ctx, "reconciling - no uni-configs have been stored before adapter restart - terminate reconcilement",
log.Fields{"device-id": dh.deviceID})
@@ -873,13 +872,16 @@
for _, flowData := range uniData.PersFlowParams {
logger.Debugw(ctx, "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
+ dh.lockVlanConfig.RLock()
if _, exist = dh.UniVlanConfigFsmMap[uniData.PersUniID]; exist {
if err := dh.UniVlanConfigFsmMap[uniData.PersUniID].SetUniFlowParams(ctx, flowData.VlanRuleParams.TpID,
flowData.CookieSlice, uint16(flowData.VlanRuleParams.MatchVid), uint16(flowData.VlanRuleParams.SetVid),
uint8(flowData.VlanRuleParams.SetPcp)); err != nil {
logger.Errorw(ctx, err.Error(), log.Fields{"device-id": dh.deviceID})
}
+ dh.lockVlanConfig.RUnlock()
} else {
+ dh.lockVlanConfig.RUnlock()
if err := dh.createVlanFilterFsm(ctx, uniPort, flowData.VlanRuleParams.TpID, flowData.CookieSlice,
uint16(flowData.VlanRuleParams.MatchVid), uint16(flowData.VlanRuleParams.SetVid),
uint8(flowData.VlanRuleParams.SetPcp), OmciVlanFilterAddDone); err != nil {
@@ -968,8 +970,6 @@
"device-id": dh.deviceID, "image-name": (*apImageDsc).Name})
//return success to comfort the core processing during integration
return nil
- // TODO!!: also verify error response behavior
- //return fmt.Errorf("onuSwUpgrade not yet implemented in deviceHandler: %s", dh.deviceID)
}
// deviceHandler methods that implement the adapters interface requests## end #########
@@ -1576,7 +1576,9 @@
}
for _, uniPort := range dh.uniEntityMap {
// reset the possibly existing VlanConfigFsm
+ dh.lockVlanConfig.RLock()
if pVlanFilterFsm, exist := dh.UniVlanConfigFsmMap[uniPort.uniID]; exist {
+ dh.lockVlanConfig.RUnlock()
//VlanFilterFsm exists and was already started
pVlanFilterStatemachine := pVlanFilterFsm.pAdaptFsm.pFsm
if pVlanFilterStatemachine != nil {
@@ -1586,6 +1588,8 @@
//and reset the UniVlanConfig FSM
_ = pVlanFilterStatemachine.Event(vlanEvReset)
}
+ } else {
+ dh.lockVlanConfig.RUnlock()
}
}
}
@@ -1850,7 +1854,7 @@
// attention: the device reason update is done based on ONU-UNI-Port related activity
// - which may cause some inconsistency
- if aDevEvent == OmciVlanFilterAddDone {
+ if aDevEvent == OmciVlanFilterAddDone || aDevEvent == OmciVlanFilterAddDoneNoKvStore {
if dh.deviceReason != drOmciFlowsPushed {
// 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
@@ -1865,9 +1869,16 @@
_ = dh.deviceReasonUpdate(ctx, drOmciFlowsDeleted, true)
}
}
- if err := dh.storePersistentData(ctx); err != nil {
- logger.Warnw(ctx, "store persistent data error - continue for now as there will be additional write attempts",
- log.Fields{"device-id": dh.deviceID, "err": err})
+
+ if aDevEvent == OmciVlanFilterAddDone || aDevEvent == OmciVlanFilterRemDone {
+ //events that request KvStore write
+ if err := dh.storePersistentData(ctx); err != nil {
+ logger.Warnw(ctx, "store persistent data error - continue for now as there will be additional write attempts",
+ log.Fields{"device-id": dh.deviceID, "err": err})
+ }
+ } else {
+ logger.Debugw(ctx, "OmciVlanFilter*Done* - write to KvStore not requested",
+ log.Fields{"device-id": dh.deviceID})
}
}
@@ -1902,7 +1913,7 @@
{
dh.processOmciAniConfigDoneEvent(ctx, devEvent)
}
- case OmciVlanFilterAddDone, OmciVlanFilterRemDone:
+ case OmciVlanFilterAddDone, OmciVlanFilterAddDoneNoKvStore, OmciVlanFilterRemDone, OmciVlanFilterRemDoneNoKvStore:
{
dh.processOmciVlanFilterDoneEvent(ctx, devEvent)
}
@@ -2296,13 +2307,15 @@
}
//mutex protection as the update_flow rpc maybe running concurrently for different flows, perhaps also activities
- dh.lockVlanConfig.Lock()
- defer dh.lockVlanConfig.Unlock()
+ dh.lockVlanConfig.RLock()
logger.Debugw(ctx, "flow-add got lock", log.Fields{"device-id": dh.deviceID})
if _, exist := dh.UniVlanConfigFsmMap[apUniPort.uniID]; exist {
- return dh.UniVlanConfigFsmMap[apUniPort.uniID].SetUniFlowParams(ctx, loTpID, loCookieSlice,
+ err := dh.UniVlanConfigFsmMap[apUniPort.uniID].SetUniFlowParams(ctx, loTpID, loCookieSlice,
loMatchVlan, loSetVlan, loSetPcp)
+ dh.lockVlanConfig.RUnlock()
+ return err
}
+ dh.lockVlanConfig.RUnlock()
return dh.createVlanFilterFsm(ctx, apUniPort, loTpID, loCookieSlice,
loMatchVlan, loSetVlan, loSetPcp, OmciVlanFilterAddDone)
}
@@ -2337,8 +2350,8 @@
*/
//mutex protection as the update_flow rpc maybe running concurrently for different flows, perhaps also activities
- dh.lockVlanConfig.Lock()
- defer dh.lockVlanConfig.Unlock()
+ dh.lockVlanConfig.RLock()
+ defer dh.lockVlanConfig.RUnlock()
if _, exist := dh.UniVlanConfigFsmMap[apUniPort.uniID]; exist {
return dh.UniVlanConfigFsmMap[apUniPort.uniID].RemoveUniFlowParams(ctx, loCookie)
}
@@ -2367,7 +2380,9 @@
pDevEntry.pOnuDB, aTpID, aDevEvent, "UniVlanConfigFsm", chVlanFilterFsm,
dh.pOpenOnuAc.AcceptIncrementalEvto, aCookieSlice, aMatchVlan, aSetVlan, aSetPcp)
if pVlanFilterFsm != nil {
+ dh.lockVlanConfig.Lock()
dh.UniVlanConfigFsmMap[apUniPort.uniID] = pVlanFilterFsm
+ dh.lockVlanConfig.Unlock()
pVlanFilterStatemachine := pVlanFilterFsm.pAdaptFsm.pFsm
if pVlanFilterStatemachine != nil {
if pVlanFilterStatemachine.Is(vlanStDisabled) {
@@ -2422,7 +2437,10 @@
//TODO!! verify and start pending flow configuration
//some pending config request my exist in case the UniVlanConfig FSM was already started - with internal data -
//but execution was set to 'on hold' as first the TechProfile config had to be applied
+
+ dh.lockVlanConfig.RLock()
if pVlanFilterFsm, exist := dh.UniVlanConfigFsmMap[apUniPort.uniID]; exist {
+ dh.lockVlanConfig.RUnlock()
//VlanFilterFsm exists and was already started (assumed to wait for TechProfile execution here)
pVlanFilterStatemachine := pVlanFilterFsm.pAdaptFsm.pFsm
if pVlanFilterStatemachine != nil {
@@ -2462,7 +2480,9 @@
logger.Debugw(ctx, "UniVlanConfigFsm StateMachine does not exist, no flow processing", log.Fields{
"device-id": dh.deviceID, "UniPort": apUniPort.portNo})
}
- } // else: nothing to do
+ } else {
+ dh.lockVlanConfig.RUnlock()
+ }
}
//RemoveVlanFilterFsm deletes the stored pointer to the VlanConfigFsm
@@ -2471,7 +2491,9 @@
logger.Debugw(ctx, "remove UniVlanConfigFsm StateMachine", log.Fields{
"device-id": dh.deviceID, "uniPort": apUniPort.portNo})
//save to do, even if entry dows not exist
+ dh.lockVlanConfig.Lock()
delete(dh.UniVlanConfigFsmMap, apUniPort.uniID)
+ dh.lockVlanConfig.Unlock()
}
//ProcessPendingTpDelete processes any pending TP delete (if available)
@@ -2503,10 +2525,30 @@
}
}
+//startWritingOnuDataToKvStore initiates the KVStore write of ONU persistent data
+func (dh *deviceHandler) startWritingOnuDataToKvStore(ctx context.Context, aPDevEntry *OnuDeviceEntry) error {
+ dh.mutexKvStoreContext.Lock() //this write routine may (could) be called with the same context,
+ defer dh.mutexKvStoreContext.Unlock() //this write routine may (could) be called with the same context,
+ // obviously then parallel processing on the cancel must be avoided
+ // deadline context to ensure completion of background routines waited for
+ //20200721: 10s proved to be less in 8*8 ONU test on local vbox machine with debug, might be further adapted
+ deadline := time.Now().Add(dh.pOpenOnuAc.maxTimeoutInterAdapterComm) //allowed run time to finish before execution
+ dctx, cancel := context.WithDeadline(context.Background(), deadline)
+
+ aPDevEntry.resetKvProcessingErrorIndication()
+ var wg sync.WaitGroup
+ wg.Add(1) // for the 1 go routine to finish
+
+ go aPDevEntry.updateOnuKvStore(log.WithSpanFromContext(dctx, ctx), &wg)
+ dh.waitForCompletion(ctx, cancel, &wg, "UpdateKvStore") //wait for background process to finish
+
+ return aPDevEntry.getKvProcessingErrorIndication()
+}
+
//storePersUniFlowConfig updates local storage of OnuUniFlowConfig and writes it into kv-store afterwards to have it
//available for potential reconcilement
-
-func (dh *deviceHandler) storePersUniFlowConfig(ctx context.Context, aUniID uint8, aUniVlanFlowParams *[]uniVlanFlowParams) error {
+func (dh *deviceHandler) storePersUniFlowConfig(ctx context.Context, aUniID uint8,
+ aUniVlanFlowParams *[]uniVlanFlowParams, aWriteToKvStore bool) error {
if dh.isReconciling() {
logger.Debugw(ctx, "reconciling - don't store persistent UniFlowConfig", log.Fields{"device-id": dh.deviceID})
@@ -2521,19 +2563,10 @@
}
pDevEntry.updateOnuUniFlowConfig(aUniID, aUniVlanFlowParams)
- // deadline context to ensure completion of background routines waited for
- //20200721: 10s proved to be less in 8*8 ONU test on local vbox machine with debug, might be further adapted
- deadline := time.Now().Add(dh.pOpenOnuAc.maxTimeoutInterAdapterComm) //allowed run time to finish before execution
- dctx, cancel := context.WithDeadline(context.Background(), deadline)
-
- pDevEntry.resetKvProcessingErrorIndication()
- var wg sync.WaitGroup
- wg.Add(1) // for the 1 go routine to finish
-
- go pDevEntry.updateOnuKvStore(log.WithSpanFromContext(dctx, ctx), &wg)
- dh.waitForCompletion(ctx, cancel, &wg, "UpdateKvStore") //wait for background process to finish
-
- return pDevEntry.getKvProcessingErrorIndication()
+ if aWriteToKvStore {
+ return dh.startWritingOnuDataToKvStore(ctx, pDevEntry)
+ }
+ return nil
}
func (dh *deviceHandler) waitForCompletion(ctx context.Context, cancel context.CancelFunc, wg *sync.WaitGroup, aCallerIdent string) {
@@ -2566,21 +2599,7 @@
logger.Warnw(ctx, "No valid OnuDevice", log.Fields{"device-id": dh.deviceID})
return fmt.Errorf("no valid OnuDevice: %s", dh.deviceID)
}
- deadline := time.Now().Add(dh.pOpenOnuAc.maxTimeoutInterAdapterComm) //allowed run time to finish before execution
- dctx, cancel := context.WithDeadline(context.Background(), deadline)
-
- pDevEntry.resetKvProcessingErrorIndication()
- var wg sync.WaitGroup
- wg.Add(1) // for the 1 go routine to finish
-
- go pDevEntry.updateOnuKvStore(dctx, &wg)
- dh.waitForCompletion(ctx, cancel, &wg, "UpdateKvStore") //wait for background process to finish
-
- if err := pDevEntry.getKvProcessingErrorIndication(); err != nil {
- logger.Warnw(ctx, "KV-processing error", log.Fields{"device-id": dh.deviceID, "err": err})
- return err
- }
- return nil
+ return dh.startWritingOnuDataToKvStore(ctx, pDevEntry)
}
func (dh *deviceHandler) combineErrorStrings(errS ...error) error {
@@ -2779,78 +2798,95 @@
return portStatus.getUniPortStatus(ctx, uniInfo.UniIndex)
}
-func (dh *deviceHandler) isFsmInState(ctx context.Context, pFsm *fsm.FSM, wantedState string) bool {
- var currentState string
- if pFsm != nil {
- currentState = pFsm.Current()
- if currentState == wantedState {
- return true
- }
- } else {
- logger.Warnw(ctx, "FSM not defined!", log.Fields{"wantedState": wantedState, "device-id": dh.deviceID})
+func (dh *deviceHandler) isFsmInOmciIdleState(ctx context.Context, pFsm *fsm.FSM, wantedState string) bool {
+ if pFsm == nil {
+ return true //FSM not active - so there is no activity on omci
}
- return false
+ return pFsm.Current() == wantedState
}
-func (dh *deviceHandler) mibUploadFsmInIdleState(ctx context.Context, idleState string) bool {
- return dh.isFsmInState(ctx, dh.pOnuOmciDevice.pMibUploadFsm.pFsm, idleState)
-}
-
-func (dh *deviceHandler) mibDownloadFsmInIdleState(ctx context.Context, idleState string) bool {
- return dh.isFsmInState(ctx, dh.pOnuOmciDevice.pMibDownloadFsm.pFsm, idleState)
-}
-
-func (dh *deviceHandler) devUniLockFsmInIdleState(ctx context.Context, idleState string) bool {
- return dh.isFsmInState(ctx, dh.pLockStateFsm.pAdaptFsm.pFsm, idleState)
-}
-
-func (dh *deviceHandler) devUniUnlockFsmInIdleState(ctx context.Context, idleState string) bool {
- return dh.isFsmInState(ctx, dh.pUnlockStateFsm.pAdaptFsm.pFsm, idleState)
-}
-
-func (dh *deviceHandler) devAniConfigFsmInIdleState(ctx context.Context, idleState string) bool {
- if dh.pOnuTP.pAniConfigFsm != nil {
- for _, v := range dh.pOnuTP.pAniConfigFsm {
- if !dh.isFsmInState(ctx, v.pAdaptFsm.pFsm, idleState) {
- return false
+func (dh *deviceHandler) isFsmInOmciIdleStateDefault(ctx context.Context, omciFsm usedOmciConfigFsms, wantedState string) bool {
+ var pFsm *fsm.FSM
+ //note/TODO!!: might be that access to all these specific FSM; pointers need a semaphore protection as well, cmp lockUpgradeFsm
+ switch omciFsm {
+ case cUploadFsm:
+ {
+ pFsm = dh.pOnuOmciDevice.pMibUploadFsm.pFsm
+ }
+ case cDownloadFsm:
+ {
+ pFsm = dh.pOnuOmciDevice.pMibDownloadFsm.pFsm
+ }
+ case cUniLockFsm:
+ {
+ pFsm = dh.pLockStateFsm.pAdaptFsm.pFsm
+ }
+ case cUniUnLockFsm:
+ {
+ pFsm = dh.pUnlockStateFsm.pAdaptFsm.pFsm
+ }
+ case cL2PmFsm:
+ {
+ if dh.pOnuMetricsMgr != nil && dh.pOnuMetricsMgr.pAdaptFsm != nil {
+ pFsm = dh.pOnuMetricsMgr.pAdaptFsm.pFsm
+ } else {
+ return true //FSM not active - so there is no activity on omci
}
}
- return true
- }
- logger.Warnw(ctx, "AniConfig FSM not defined!", log.Fields{"device-id": dh.deviceID})
- return false
-}
-
-func (dh *deviceHandler) devUniVlanConfigFsmInIdleState(ctx context.Context, idleState string) bool {
- if dh.UniVlanConfigFsmMap != nil {
- for _, v := range dh.UniVlanConfigFsmMap {
- if !dh.isFsmInState(ctx, v.pAdaptFsm.pFsm, idleState) {
- return false
- }
+ default:
+ {
+ logger.Errorw(ctx, "invalid stateMachine selected for idle check", log.Fields{
+ "device-id": dh.deviceID, "selectedFsm number": omciFsm})
+ return false //logical error in FSM check, do not not indicate 'idle' - we can't be sure
}
- return true
}
- logger.Warnw(ctx, "UniVlanConfig FSM not defined!", log.Fields{"device-id": dh.deviceID})
- return false
+ return dh.isFsmInOmciIdleState(ctx, pFsm, wantedState)
}
-func (dh *deviceHandler) l2PmFsmInIdleState(ctx context.Context, idleState string) bool {
- if dh.pOnuMetricsMgr != nil && dh.pOnuMetricsMgr.pAdaptFsm != nil && dh.pOnuMetricsMgr.pAdaptFsm.pFsm != nil {
- return dh.isFsmInState(ctx, dh.pOnuMetricsMgr.pAdaptFsm.pFsm, idleState)
- }
- logger.Warnw(ctx, "L2 PM FSM not defined!", log.Fields{"device-id": dh.deviceID})
- return false
-}
-
-func (dh *deviceHandler) allButCallingFsmInIdleState(ctx context.Context, callingFsm usedOmciConfigFsms) bool {
- for fsmName, fsmStruct := range fsmIdleStateFuncMap {
- if fsmName != callingFsm && !fsmStruct.idleCheckFunc(dh, ctx, fsmStruct.idleState) {
+func (dh *deviceHandler) isAniConfigFsmInOmciIdleState(ctx context.Context, omciFsm usedOmciConfigFsms, idleState string) bool {
+ for _, v := range dh.pOnuTP.pAniConfigFsm {
+ if !dh.isFsmInOmciIdleState(ctx, v.pAdaptFsm.pFsm, idleState) {
return false
}
}
return true
}
+func (dh *deviceHandler) isUniVlanConfigFsmInOmciIdleState(ctx context.Context, omciFsm usedOmciConfigFsms, idleState string) bool {
+ dh.lockVlanConfig.RLock()
+ defer dh.lockVlanConfig.RUnlock()
+ for _, v := range dh.UniVlanConfigFsmMap {
+ if !dh.isFsmInOmciIdleState(ctx, v.pAdaptFsm.pFsm, idleState) {
+ return false
+ }
+ }
+ return true //FSM not active - so there is no activity on omci
+}
+
+func (dh *deviceHandler) checkUserServiceExists(ctx context.Context) bool {
+ dh.lockVlanConfig.RLock()
+ defer dh.lockVlanConfig.RUnlock()
+ for _, v := range dh.UniVlanConfigFsmMap {
+ if v.pAdaptFsm.pFsm != nil {
+ if v.pAdaptFsm.pFsm.Is(cVlanFsmConfiguredState) {
+ return true //there is at least one VLAN FSM with some active configuration
+ }
+ }
+ }
+ return false //there is no VLAN FSM with some active configuration
+}
+
+func (dh *deviceHandler) checkAuditStartCondition(ctx context.Context, callingFsm usedOmciConfigFsms) bool {
+ for fsmName, fsmStruct := range fsmOmciIdleStateFuncMap {
+ if fsmName != callingFsm && !fsmStruct.omciIdleCheckFunc(dh, ctx, fsmName, fsmStruct.omciIdleState) {
+ return false
+ }
+ }
+ // a further check is done to identify, if at least some data traffic related configuration exists
+ // so that a user of this ONU could be 'online' (otherwise it makes no sense to check the MDS [with the intention to keep the user service up])
+ return dh.checkUserServiceExists(ctx)
+}
+
func (dh *deviceHandler) prepareReconcilingWithActiveAdapter(ctx context.Context) {
logger.Debugw(ctx, "prepare to reconcile the ONU with adapter using persistency data", log.Fields{"device-id": dh.device.Id})
if err := dh.resetFsms(ctx, false); err != nil {