[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/VERSION b/VERSION
index e8ea05d..4da242d 100755
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.2.4
+1.2.5-dev167
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 {
diff --git a/internal/pkg/onuadaptercore/mib_sync.go b/internal/pkg/onuadaptercore/mib_sync.go
index eb7dce6..0fcf7f9 100644
--- a/internal/pkg/onuadaptercore/mib_sync.go
+++ b/internal/pkg/onuadaptercore/mib_sync.go
@@ -269,10 +269,10 @@
func (oo *OnuDeviceEntry) enterAuditingState(ctx context.Context, e *fsm.Event) {
logger.Debugw(ctx, "MibSync FSM", log.Fields{"Start MibAudit processing in State": e.FSM.Current(), "device-id": oo.deviceID})
- if oo.baseDeviceHandler.allButCallingFsmInIdleState(ctx, cUploadFsm) {
+ if oo.baseDeviceHandler.checkAuditStartCondition(ctx, cUploadFsm) {
oo.requestMdsValue(ctx)
} else {
- logger.Debugw(ctx, "MibSync FSM", log.Fields{"Configuration is ongoing - skip auditing!": e.FSM.Current(), "device-id": oo.deviceID})
+ logger.Debugw(ctx, "MibSync FSM", log.Fields{"Configuration is ongoing or missing - skip auditing!": e.FSM.Current(), "device-id": oo.deviceID})
go func() {
_ = oo.pMibUploadFsm.pFsm.Event(ulEvSuccess)
}()
@@ -281,10 +281,10 @@
func (oo *OnuDeviceEntry) enterReAuditingState(ctx context.Context, e *fsm.Event) {
logger.Debugw(ctx, "MibSync FSM", log.Fields{"Start retest MdsValue processing in State": e.FSM.Current(), "device-id": oo.deviceID})
- if oo.baseDeviceHandler.allButCallingFsmInIdleState(ctx, cUploadFsm) {
+ if oo.baseDeviceHandler.checkAuditStartCondition(ctx, cUploadFsm) {
oo.requestMdsValue(ctx)
} else {
- logger.Debugw(ctx, "MibSync FSM", log.Fields{"Configuration is ongoing - skip re-auditing!": e.FSM.Current(), "device-id": oo.deviceID})
+ logger.Debugw(ctx, "MibSync FSM", log.Fields{"Configuration is ongoing or missing - skip re-auditing!": e.FSM.Current(), "device-id": oo.deviceID})
go func() {
_ = oo.pMibUploadFsm.pFsm.Event(ulEvSuccess)
}()
diff --git a/internal/pkg/onuadaptercore/omci_vlan_config.go b/internal/pkg/onuadaptercore/omci_vlan_config.go
index 6725098..cfec8e8 100644
--- a/internal/pkg/onuadaptercore/omci_vlan_config.go
+++ b/internal/pkg/onuadaptercore/omci_vlan_config.go
@@ -36,6 +36,7 @@
const (
// internal predefined values
+ cWaitForCookieDeletion = 3 //seconds
cDefaultDownstreamMode = 0
cDefaultTpid = 0x8100
cVtfdTableSize = 12 //as per G.988
@@ -43,6 +44,14 @@
)
const (
+ // internal offsets for requestEvent according to definition in onu_device_entry::OnuDeviceEvent
+ cDeviceEventOffsetAddWithKvStore = 0 //OmciVlanFilterAddDone - OmciVlanFilterAddDone cannot use because of lint
+ cDeviceEventOffsetAddNoKvStore = OmciVlanFilterAddDoneNoKvStore - OmciVlanFilterAddDone
+ cDeviceEventOffsetRemoveWithKvStore = OmciVlanFilterRemDone - OmciVlanFilterAddDone
+ cDeviceEventOffsetRemoveNoKvStore = OmciVlanFilterRemDoneNoKvStore - OmciVlanFilterAddDone
+)
+
+const (
// bit mask offsets for EVTOCD VlanTaggingOperationTable related to 32 bits (4 bytes)
cFilterPrioOffset = 28
cFilterVidOffset = 15
@@ -110,7 +119,8 @@
vlanStCleanupDone = "vlanStCleanupDone"
vlanStResetting = "vlanStResetting"
)
-const cVlanFsmIdleState = vlanStConfigDone
+const cVlanFsmIdleState = vlanStConfigDone // state where no OMCI activity is done (for a longer time)
+const cVlanFsmConfiguredState = vlanStConfigDone // state that indicates that at least some valid user related VLAN configuration should exist
type uniVlanRuleParams struct {
TpID uint8 `json:"tp_id"`
@@ -145,6 +155,7 @@
acceptIncrementalEvtoOption bool
clearPersistency bool
mutexFlowParams sync.RWMutex
+ chCookieDeleted chan bool //channel to indicate that a specificly indicated cookie was deleted
actualUniVlanConfigRule uniVlanRuleParams
uniVlanFlowParamsSlice []uniVlanFlowParams
uniRemoveFlowsSlice []uniRemoveVlanFlowParams
@@ -157,6 +168,8 @@
pLastTxMeInstance *me.ManagedEntity
requestEventOffset uint8
TpIDWaitingFor uint8
+ //cookie value that indicates that a rule to add is delayed by waiting for deletion of some other existing rule with the same cookie
+ delayNewRuleCookie uint64
}
//NewUniVlanConfigFsm is the 'constructor' for the state machine to config the PON ANI ports
@@ -298,7 +311,7 @@
//permanently store flow config for reconcile case
if err := oFsm.pDeviceHandler.storePersUniFlowConfig(ctx, oFsm.pOnuUniPort.uniID,
- &oFsm.uniVlanFlowParamsSlice); err != nil {
+ &oFsm.uniVlanFlowParamsSlice, true); err != nil {
logger.Errorw(ctx, err.Error(), log.Fields{"device-id": oFsm.deviceID})
return err
}
@@ -365,9 +378,9 @@
flowEntryMatch := false
flowCookieModify := false
+ requestAppendRule := 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 {
//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?)
@@ -387,18 +400,41 @@
}
}
if !cookieMatch {
- logger.Debugw(ctx, "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
+ delayedCookie := oFsm.delayNewRuleForCookie(ctx, aCookieSlice)
+ if delayedCookie != 0 {
+ //a delay for adding the cookie to this rule is requested
+ // take care of the mutex which is already locked here, need to unlock/lock accordingly to prevent deadlock in suspension
+ oFsm.mutexFlowParams.Unlock()
+ oFsm.suspendNewRule(ctx)
+ flowCookieModify, requestAppendRule = oFsm.reviseFlowConstellation(ctx, delayedCookie, loRuleParams)
+ oFsm.mutexFlowParams.Lock()
+ } else {
+ logger.Debugw(ctx, "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 { //it is a new rule
+ oFsm.mutexFlowParams.Unlock()
+
+ if !flowEntryMatch { //it is (was) a new rule
+ delayedCookie := oFsm.suspendIfRequiredNewRule(ctx, aCookieSlice)
+ requestAppendRule = true //default assumption here is that rule is to be appended
+ flowCookieModify = true //and that the the flow data base is to be updated
+ if delayedCookie != 0 { //it was suspended
+ flowCookieModify, requestAppendRule = oFsm.reviseFlowConstellation(ctx, delayedCookie, loRuleParams)
+ }
+ }
+ kvStoreWrite := false //default setting is to not write to kvStore immediately - will be done on FSM execution finally
+ if requestAppendRule {
+ oFsm.mutexFlowParams.Lock()
+ defer oFsm.mutexFlowParams.Unlock()
if oFsm.numUniFlows < cMaxAllowedFlows {
loFlowParams := uniVlanFlowParams{VlanRuleParams: loRuleParams}
loFlowParams.CookieSlice = make([]uint64, 0)
@@ -458,6 +494,7 @@
}
} else {
// no activity within the FSM for OMCI processing, the deviceReason may be updated immediately
+ kvStoreWrite = true // ensure actual data write to kvStore immediately (no FSM activity)
if oFsm.numUniFlows == oFsm.configuredUniFlow {
//all requested rules really have been configured
// state transition notification is checked in deviceHandler
@@ -465,7 +502,8 @@
//also the related TechProfile was already configured
logger.Debugw(ctx, "UniVlanConfigFsm rule already set - send immediate add-success event for reason update", log.Fields{
"device-id": oFsm.deviceID})
- go oFsm.pDeviceHandler.deviceProcStatusUpdate(ctx, oFsm.requestEvent)
+ // success indication without the need to write to kvStore (done already below with updated data from storePersUniFlowConfig())
+ go oFsm.pDeviceHandler.deviceProcStatusUpdate(ctx, OnuDeviceEvent(oFsm.requestEvent+cDeviceEventOffsetAddNoKvStore))
}
} else {
// avoid device reason update as the rule config connected to this flow may still be in progress
@@ -476,9 +514,10 @@
}
}
- if !flowEntryMatch || flowCookieModify { // some change was done to the flow entries
+ if flowCookieModify { // some change was done to the flow entries
//permanently store flow config for reconcile case
- if err := oFsm.pDeviceHandler.storePersUniFlowConfig(ctx, oFsm.pOnuUniPort.uniID, &oFsm.uniVlanFlowParamsSlice); err != nil {
+ if err := oFsm.pDeviceHandler.storePersUniFlowConfig(ctx, oFsm.pOnuUniPort.uniID,
+ &oFsm.uniVlanFlowParamsSlice, kvStoreWrite); err != nil {
logger.Errorw(ctx, err.Error(), log.Fields{"device-id": oFsm.deviceID})
return err
}
@@ -486,21 +525,111 @@
return nil
}
+// VOL-3828 flow config sequence workaround ########### start ##########
+func (oFsm *UniVlanConfigFsm) delayNewRuleForCookie(ctx context.Context, aCookieSlice []uint64) uint64 {
+ //assumes mutexFlowParams.Lock() protection from caller!
+ if oFsm.delayNewRuleCookie == 0 && len(aCookieSlice) == 1 {
+ // if not already waiting, limitation for this workaround is to just have one overlapping cookie/rule
+ // suspend check is done only of there is only one cookie in the request
+ // background: more elements only expected in reconcile use case, where no conflicting sequence is to be expected
+ newCookie := aCookieSlice[0]
+ for _, storedUniFlowParams := range oFsm.uniVlanFlowParamsSlice {
+ for _, cookie := range storedUniFlowParams.CookieSlice {
+ if cookie == newCookie {
+ logger.Debugw(ctx, "UniVlanConfigFsm flow setting - new cookie still exists for some rule", log.Fields{
+ "device-id": oFsm.deviceID, "cookie": cookie, "exists with SetVlan": storedUniFlowParams.VlanRuleParams.SetVid})
+ oFsm.delayNewRuleCookie = newCookie
+ return newCookie //found new cookie in some existing rule
+ }
+ } // for all stored cookies of the actual inspected rule
+ } //for all rules
+ }
+ return 0 //no delay requested
+}
+func (oFsm *UniVlanConfigFsm) suspendNewRule(ctx context.Context) {
+ oFsm.mutexFlowParams.RLock()
+ logger.Infow(ctx, "Need to suspend adding this rule as long as the cookie is still connected to some other rule", log.Fields{
+ "device-id": oFsm.deviceID, "cookie": oFsm.delayNewRuleCookie})
+ oFsm.mutexFlowParams.RUnlock()
+ select {
+ case <-oFsm.chCookieDeleted:
+ logger.Infow(ctx, "resume adding this rule after having deleted cookie in some other rule", log.Fields{
+ "device-id": oFsm.deviceID, "cookie": oFsm.delayNewRuleCookie})
+ case <-time.After(time.Duration(cWaitForCookieDeletion) * time.Second):
+ logger.Errorw(ctx, "timeout waiting for deletion of cookie in some other rule, just try to continue", log.Fields{
+ "device-id": oFsm.deviceID, "cookie": oFsm.delayNewRuleCookie})
+ }
+ oFsm.mutexFlowParams.Lock()
+ oFsm.delayNewRuleCookie = 0
+ oFsm.mutexFlowParams.Unlock()
+}
+func (oFsm *UniVlanConfigFsm) suspendIfRequiredNewRule(ctx context.Context, aCookieSlice []uint64) uint64 {
+ oFsm.mutexFlowParams.Lock()
+ delayedCookie := oFsm.delayNewRuleForCookie(ctx, aCookieSlice)
+ oFsm.mutexFlowParams.Unlock()
+
+ if delayedCookie != 0 {
+ oFsm.suspendNewRule(ctx)
+ }
+ return delayedCookie
+}
+
+//returns flowModified, RuleAppendRequest
+func (oFsm *UniVlanConfigFsm) reviseFlowConstellation(ctx context.Context, aCookie uint64, aUniVlanRuleParams uniVlanRuleParams) (bool, bool) {
+ flowEntryMatch := false
+ oFsm.mutexFlowParams.Lock()
+ defer oFsm.mutexFlowParams.Unlock()
+ for flow, storedUniFlowParams := range oFsm.uniVlanFlowParamsSlice {
+ if storedUniFlowParams.VlanRuleParams == aUniVlanRuleParams {
+ flowEntryMatch = true
+ logger.Debugw(ctx, "UniVlanConfigFsm flow revise - rule already exists", log.Fields{
+ "device-id": oFsm.deviceID})
+ cookieMatch := false
+ for _, cookie := range storedUniFlowParams.CookieSlice {
+ if cookie == aCookie {
+ logger.Debugw(ctx, "UniVlanConfigFsm flow revise - 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(ctx, "UniVlanConfigFsm flow revise -adding new cookie", log.Fields{
+ "device-id": oFsm.deviceID, "cookie": aCookie})
+ //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,
+ aCookie)
+ return true, false //flowModified, NoRuleAppend
+ }
+ break // found rule - no further rule search
+ }
+ }
+ if !flowEntryMatch { //it is a new rule
+ return true, true //flowModified, RuleAppend
+ }
+ return false, false //flowNotModified, NoRuleAppend
+}
+
+// VOL-3828 flow config sequence workaround ########### end ##########
+
//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(ctx context.Context, aCookie uint64) error {
+ var deletedCookie uint64
flowCookieMatch := false
//mutex protection is required for possible concurrent access to FSM members
oFsm.mutexFlowParams.Lock()
defer oFsm.mutexFlowParams.Unlock()
+remove_loop:
for flow, storedUniFlowParams := range oFsm.uniVlanFlowParamsSlice {
for i, cookie := range storedUniFlowParams.CookieSlice {
if cookie == aCookie {
logger.Debugw(ctx, "UniVlanConfigFsm flow removal - cookie found", log.Fields{
"device-id": oFsm.deviceID, "cookie": cookie})
flowCookieMatch = true
-
+ deletedCookie = aCookie
+ kvStoreWrite := false //default setting is to not write to kvStore immediately - will be done on FSM execution finally
//remove the cookie from the cookie slice and verify it is getting empty
if len(storedUniFlowParams.CookieSlice) == 1 {
logger.Debugw(ctx, "UniVlanConfigFsm flow removal - full flow removal", log.Fields{
@@ -509,7 +638,7 @@
//create a new element for the removeVlanFlow slice
loRemoveParams := uniRemoveVlanFlowParams{
vlanRuleParams: storedUniFlowParams.VlanRuleParams,
- cookie: storedUniFlowParams.CookieSlice[0],
+ cookie: aCookie,
}
oFsm.uniRemoveFlowsSlice = append(oFsm.uniRemoveFlowsSlice, loRemoveParams)
@@ -537,22 +666,8 @@
oFsm.uniVlanFlowParamsSlice[:flow], oFsm.uniVlanFlowParamsSlice[flow+1:]...)
//here we have to check, if there are still other flows referencing to the actual ProfileId
// before we can request that this profile gets deleted before a new flow add is allowed
- tpIDInOtherFlows := false
- for _, tpUniFlowParams := range oFsm.uniVlanFlowParamsSlice {
- if tpUniFlowParams.VlanRuleParams.TpID == usedTpID {
- tpIDInOtherFlows = true
- break // search loop can be left
- }
- }
- if tpIDInOtherFlows {
- logger.Debugw(ctx, "UniVlanConfigFsm tp-id used in deleted flow is still used in other flows", log.Fields{
- "device-id": oFsm.deviceID, "tp-id": usedTpID})
- } else {
- logger.Debugw(ctx, "UniVlanConfigFsm tp-id used in deleted flow is not used anymore", log.Fields{
- "device-id": oFsm.deviceID, "tp-id": usedTpID})
- //request that this profile gets deleted before a new flow add is allowed
- oFsm.pUniTechProf.setProfileToDelete(oFsm.pOnuUniPort.uniID, usedTpID, true)
- }
+ // (needed to extract to function due to lint complexity)
+ oFsm.updateTechProfileToDelete(ctx, usedTpID)
logger.Debugw(ctx, "UniVlanConfigFsm flow removal - specific flow removed from data", log.Fields{
"device-id": oFsm.deviceID})
}
@@ -576,29 +691,34 @@
oFsm.uniVlanFlowParamsSlice[flow].CookieSlice[:i],
oFsm.uniVlanFlowParamsSlice[flow].CookieSlice[i+1:]...)
// no activity within the FSM for OMCI processing, the deviceReason may be updated immediately
+ kvStoreWrite = true // ensure actual data write to kvStore immediately (no FSM activity)
// 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(ctx, OnuDeviceEvent(uint8(oFsm.requestEvent)+1))
+ // success indication without the need to write to kvStore (done already below with updated data from storePersUniFlowConfig())
+ go oFsm.pDeviceHandler.deviceProcStatusUpdate(ctx, OnuDeviceEvent(oFsm.requestEvent+cDeviceEventOffsetRemoveNoKvStore))
}
logger.Debugw(ctx, "UniVlanConfigFsm flow removal - rule persists with still valid cookies", log.Fields{
"device-id": oFsm.deviceID, "cookies": oFsm.uniVlanFlowParamsSlice[flow].CookieSlice})
+ if deletedCookie == oFsm.delayNewRuleCookie {
+ //the delayedNewCookie is the one that is currently deleted, but the rule still exist with other cookies
+ //as long as there are further cookies for this rule indicate there is still some cookie to be deleted
+ //simply use the first one
+ oFsm.delayNewRuleCookie = oFsm.uniVlanFlowParamsSlice[flow].CookieSlice[0]
+ logger.Debugw(ctx, "UniVlanConfigFsm remaining cookie awaited for deletion before new rule add", log.Fields{
+ "device-id": oFsm.deviceID, "cookie": oFsm.delayNewRuleCookie})
+ }
}
-
//permanently store the modified flow config for reconcile case
if oFsm.pDeviceHandler != nil {
- if err := oFsm.pDeviceHandler.storePersUniFlowConfig(ctx, oFsm.pOnuUniPort.uniID, &oFsm.uniVlanFlowParamsSlice); err != nil {
+ if err := oFsm.pDeviceHandler.storePersUniFlowConfig(ctx, oFsm.pOnuUniPort.uniID,
+ &oFsm.uniVlanFlowParamsSlice, kvStoreWrite); err != nil {
logger.Errorw(ctx, err.Error(), log.Fields{"device-id": oFsm.deviceID})
return err
}
}
-
- break //found the cookie - no further search for this requested cookie
+ break remove_loop //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(ctx, "UniVlanConfigFsm flow removal - remove-cookie not found", log.Fields{
@@ -607,8 +727,8 @@
// 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(ctx, OnuDeviceEvent(uint8(oFsm.requestEvent)+1))
+ // success indication without the need to write to kvStore (no change)
+ go oFsm.pDeviceHandler.deviceProcStatusUpdate(ctx, OnuDeviceEvent(oFsm.requestEvent+cDeviceEventOffsetRemoveNoKvStore))
}
return nil
} //unknown cookie
@@ -616,6 +736,27 @@
return nil
}
+func (oFsm *UniVlanConfigFsm) updateTechProfileToDelete(ctx context.Context, usedTpID uint8) {
+ //here we have to check, if there are still other flows referencing to the actual ProfileId
+ // before we can request that this profile gets deleted before a new flow add is allowed
+ tpIDInOtherFlows := false
+ for _, tpUniFlowParams := range oFsm.uniVlanFlowParamsSlice {
+ if tpUniFlowParams.VlanRuleParams.TpID == usedTpID {
+ tpIDInOtherFlows = true
+ break // search loop can be left
+ }
+ }
+ if tpIDInOtherFlows {
+ logger.Debugw(ctx, "UniVlanConfigFsm tp-id used in deleted flow is still used in other flows", log.Fields{
+ "device-id": oFsm.deviceID, "tp-id": usedTpID})
+ } else {
+ logger.Debugw(ctx, "UniVlanConfigFsm tp-id used in deleted flow is not used anymore", log.Fields{
+ "device-id": oFsm.deviceID, "tp-id": usedTpID})
+ //request that this profile gets deleted before a new flow add is allowed
+ oFsm.pUniTechProf.setProfileToDelete(oFsm.pOnuUniPort.uniID, usedTpID, true)
+ }
+}
+
func (oFsm *UniVlanConfigFsm) enterConfigStarting(ctx context.Context, e *fsm.Event) {
logger.Debugw(ctx, "UniVlanConfigFsm start", log.Fields{"in state": e.FSM.Current(),
"device-id": oFsm.deviceID})
@@ -623,6 +764,7 @@
// 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)
+ oFsm.chCookieDeleted = make(chan bool)
// start go routine for processing of LockState messages
go oFsm.processOmciVlanMessages(ctx)
//let the state machine run forward from here directly
@@ -727,7 +869,7 @@
func (oFsm *UniVlanConfigFsm) enterConfigEvtocd(ctx context.Context, e *fsm.Event) {
logger.Debugw(ctx, "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
+ oFsm.requestEventOffset = uint8(cDeviceEventOffsetAddWithKvStore) //0 offset for last flow-add activity
go func() {
//using the first element in the slice because it's the first flow per definition here
errEvto := oFsm.performConfigEvtocdEntries(ctx, 0)
@@ -756,7 +898,7 @@
oFsm.mutexFlowParams.RLock()
defer oFsm.mutexFlowParams.RUnlock()
- logger.Debugw(ctx, "UniVlanConfigFsm - checking on more flows", log.Fields{
+ logger.Infow(ctx, "UniVlanConfigFsm config done - checking on more flows", log.Fields{
"in state": e.FSM.Current(), "device-id": oFsm.deviceID,
"overall-uni-rules": oFsm.numUniFlows, "configured-uni-rules": oFsm.configuredUniFlow})
pConfigVlanStateAFsm := oFsm.pAdaptFsm
@@ -918,7 +1060,7 @@
return
}
}
- oFsm.requestEventOffset = 0 //0 offset for last flow-add activity
+ oFsm.requestEventOffset = uint8(cDeviceEventOffsetAddWithKvStore) //0 offset for last flow-add activity
go func() {
tpID := oFsm.actualUniVlanConfigRule.TpID
errEvto := oFsm.performConfigEvtocdEntries(ctx, oFsm.configuredUniFlow)
@@ -1076,10 +1218,12 @@
} else {
logger.Warnw(ctx, "UniVlanConfigFsm - tp id not available", log.Fields{"device-id": oFsm.deviceID})
}
- logger.Debugw(ctx, "UniVlanConfigFsm - removing the removal data", log.Fields{
- "in state": e.FSM.Current(), "device-id": oFsm.deviceID})
-
oFsm.mutexFlowParams.Lock()
+ deletedCookie := oFsm.uniRemoveFlowsSlice[0].cookie
+ logger.Debugw(ctx, "UniVlanConfigFsm - removing the removal data", log.Fields{
+ "in state": e.FSM.Current(), "device-id": oFsm.deviceID,
+ "removed cookie": deletedCookie, "waitForDeleteCookie": oFsm.delayNewRuleCookie})
+
if len(oFsm.uniRemoveFlowsSlice) <= 1 {
oFsm.uniRemoveFlowsSlice = nil //reset the slice
logger.Debugw(ctx, "UniVlanConfigFsm flow removal - last remove-flow deleted", log.Fields{
@@ -1094,7 +1238,7 @@
}
oFsm.mutexFlowParams.Unlock()
- oFsm.requestEventOffset = 1 //offset 1 for last flow-remove activity
+ oFsm.requestEventOffset = uint8(cDeviceEventOffsetRemoveWithKvStore) //offset for last flow-remove activity (with kvStore request)
//return to the basic config verification state
pConfigVlanStateAFsm := oFsm.pAdaptFsm
if pConfigVlanStateAFsm != nil {
@@ -1108,6 +1252,15 @@
oFsm.mutexFlowParams.RLock()
noOfFlowRem := len(oFsm.uniRemoveFlowsSlice)
+ if deletedCookie == oFsm.delayNewRuleCookie {
+ // flush the channel CookieDeleted to ensure it is not lingering from some previous (aborted) activity
+ select {
+ case <-oFsm.chCookieDeleted:
+ logger.Debug(ctx, "flushed CookieDeleted")
+ default:
+ }
+ oFsm.chCookieDeleted <- true // let the waiting AddFlow thread continue
+ }
oFsm.mutexFlowParams.RUnlock()
// If all pending flow removes are completed and TP ID is valid, processing any pending TP delete
if noOfFlowRem == 0 && tpID > 0 {
@@ -1154,11 +1307,15 @@
//permanently remove possibly stored persistent data
if len(oFsm.uniVlanFlowParamsSlice) > 0 {
var emptySlice = make([]uniVlanFlowParams, 0)
- _ = oFsm.pDeviceHandler.storePersUniFlowConfig(ctx, oFsm.pOnuUniPort.uniID, &emptySlice) //ignore errors
+ _ = oFsm.pDeviceHandler.storePersUniFlowConfig(ctx, oFsm.pOnuUniPort.uniID, &emptySlice, true) //ignore errors
}
} else {
logger.Debugw(ctx, "UniVlanConfigFsm persistency data not cleared", log.Fields{"device-id": oFsm.deviceID})
}
+ if oFsm.delayNewRuleCookie != 0 {
+ // looks like the waiting AddFlow is stuck
+ oFsm.chCookieDeleted <- true // let the waiting AddFlow thread continue/treminate
+ }
oFsm.mutexFlowParams.RUnlock()
//request removal of 'reference' in the Handler (completely clear the FSM and its data)
go oFsm.pDeviceHandler.RemoveVlanFilterFsm(ctx, oFsm.pOnuUniPort)
diff --git a/internal/pkg/onuadaptercore/onu_device_entry.go b/internal/pkg/onuadaptercore/onu_device_entry.go
index e01de18..816ebcd 100644
--- a/internal/pkg/onuadaptercore/onu_device_entry.go
+++ b/internal/pkg/onuadaptercore/onu_device_entry.go
@@ -146,10 +146,14 @@
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 - Omci Vlan config done according to flow-add with request to write kvStore
OmciVlanFilterAddDone
- // OmciVlanFilterRemDone - Omci Vlan config done according to flow-remove
- OmciVlanFilterRemDone // needs to be the successor of OmciVlanFilterAddDone!
+ // OmciVlanFilterAddDoneNoKvStore - Omci Vlan config done according to flow-add without writing kvStore
+ OmciVlanFilterAddDoneNoKvStore // needs to be the successor of OmciVlanFilterAddDone!
+ // OmciVlanFilterRemDone - Omci Vlan config done according to flow-remove with request to write kvStore
+ OmciVlanFilterRemDone // needs to be the successor of OmciVlanFilterAddDoneNoKvStore!
+ // OmciVlanFilterRemDoneNoKvStore - Omci Vlan config done according to flow-remove without writing kvStore
+ OmciVlanFilterRemDoneNoKvStore // needs to be the successor of OmciVlanFilterRemDone!
// Add other events here as needed (alarms separate???)
)