[VOL-4010] openonuAdapterGo - investigate and resolve data race conditions
Change-Id: I8e957d8bd59b91db27ee4f303a5a222a8f83e8c4
diff --git a/internal/pkg/onuadaptercore/mib_download.go b/internal/pkg/onuadaptercore/mib_download.go
index 3a729a6..148291c 100644
--- a/internal/pkg/onuadaptercore/mib_download.go
+++ b/internal/pkg/onuadaptercore/mib_download.go
@@ -45,10 +45,12 @@
func (onuDeviceEntry *OnuDeviceEntry) enterCreatingGalState(ctx context.Context, e *fsm.Event) {
logger.Debugw(ctx, "MibDownload FSM", log.Fields{"Tx create::GAL Ethernet Profile in state": e.FSM.Current(), "device-id": onuDeviceEntry.deviceID})
+ onuDeviceEntry.PDevOmciCC.mutexPLastTxMeInstance.Lock()
meInstance, err := onuDeviceEntry.PDevOmciCC.sendCreateGalEthernetProfile(log.WithSpanFromContext(context.TODO(), ctx), onuDeviceEntry.pOpenOnuAc.omciTimeout, true)
//accept also nil as (error) return value for writing to LastTx
// - this avoids misinterpretation of new received OMCI messages
if err != nil {
+ onuDeviceEntry.PDevOmciCC.mutexPLastTxMeInstance.Unlock()
logger.Errorw(ctx, "GalEthernetProfile create failed, aborting MibDownload FSM!",
log.Fields{"device-id": onuDeviceEntry.deviceID})
pMibDlFsm := onuDeviceEntry.pMibDownloadFsm
@@ -60,15 +62,18 @@
return
}
onuDeviceEntry.PDevOmciCC.pLastTxMeInstance = meInstance
+ onuDeviceEntry.PDevOmciCC.mutexPLastTxMeInstance.Unlock()
}
func (onuDeviceEntry *OnuDeviceEntry) enterSettingOnu2gState(ctx context.Context, e *fsm.Event) {
logger.Debugw(ctx, "MibDownload FSM", log.Fields{"Tx Set::ONU2-G in state": e.FSM.Current(), "device-id": onuDeviceEntry.deviceID})
+ onuDeviceEntry.PDevOmciCC.mutexPLastTxMeInstance.Lock()
meInstance, err := onuDeviceEntry.PDevOmciCC.sendSetOnu2g(log.WithSpanFromContext(context.TODO(), ctx),
onuDeviceEntry.pOpenOnuAc.omciTimeout, true)
//accept also nil as (error) return value for writing to LastTx
// - this avoids misinterpretation of new received OMCI messages
if err != nil {
+ onuDeviceEntry.PDevOmciCC.mutexPLastTxMeInstance.Unlock()
logger.Errorw(ctx, "ONU2-G set failed, aborting MibDownload FSM!",
log.Fields{"device-id": onuDeviceEntry.deviceID})
pMibDlFsm := onuDeviceEntry.pMibDownloadFsm
@@ -80,6 +85,7 @@
return
}
onuDeviceEntry.PDevOmciCC.pLastTxMeInstance = meInstance
+ onuDeviceEntry.PDevOmciCC.mutexPLastTxMeInstance.Unlock()
}
func (onuDeviceEntry *OnuDeviceEntry) enterBridgeInitState(ctx context.Context, e *fsm.Event) {
@@ -163,94 +169,131 @@
logger.Debugw(ctx, "End MibDownload Msg processing", log.Fields{"for device-id": onuDeviceEntry.deviceID})
}
+func (onuDeviceEntry *OnuDeviceEntry) handleOmciMibDownloadCreateResponseMessage(ctx context.Context, msg OmciMessage) {
+ msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeCreateResponse)
+ if msgLayer == nil {
+ logger.Errorw(ctx, "Omci Msg layer could not be detected for CreateResponse", log.Fields{"device-id": onuDeviceEntry.deviceID})
+ return
+ }
+ msgObj, msgOk := msgLayer.(*omci.CreateResponse)
+ if !msgOk {
+ logger.Errorw(ctx, "Omci Msg layer could not be assigned for CreateResponse", log.Fields{"device-id": onuDeviceEntry.deviceID})
+ return
+ }
+ logger.Debugw(ctx, "CreateResponse Data", log.Fields{"device-id": onuDeviceEntry.deviceID, "data-fields": msgObj})
+ if msgObj.Result != me.Success && msgObj.Result != me.InstanceExists {
+ logger.Errorw(ctx, "Omci CreateResponse Error - later: drive FSM to abort state ?", log.Fields{"device-id": onuDeviceEntry.deviceID, "Error": msgObj.Result})
+ // possibly force FSM into abort or ignore some errors for some messages? store error for mgmt display?
+ return
+ }
+ // maybe there is a way of pushing the specific create response type generally to the FSM
+ // and let the FSM verify, if the response was according to current state
+ // and possibly store the element to DB and progress - maybe some future option ...
+ // but as that is not straightforward to me I insert the type checkes manually here
+ // and feed the FSM with only 'pre-defined' events ...
+
+ onuDeviceEntry.PDevOmciCC.mutexPLastTxMeInstance.RLock()
+ if onuDeviceEntry.PDevOmciCC.pLastTxMeInstance != nil {
+ if msgObj.EntityClass == onuDeviceEntry.PDevOmciCC.pLastTxMeInstance.GetClassID() &&
+ msgObj.EntityInstance == onuDeviceEntry.PDevOmciCC.pLastTxMeInstance.GetEntityID() {
+ //store the created ME into DB //TODO??? obviously the Python code does not store the config ...
+ // if, then something like:
+ //onuDeviceEntry.pOnuDB.StoreMe(msgObj)
+
+ // 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 onuDeviceEntry.PDevOmciCC.pLastTxMeInstance.GetName() {
+ case "GalEthernetProfile":
+ { // let the FSM proceed ...
+ onuDeviceEntry.PDevOmciCC.mutexPLastTxMeInstance.RUnlock()
+ _ = onuDeviceEntry.pMibDownloadFsm.pFsm.Event(dlEvRxGalResp)
+ }
+ case "MacBridgeServiceProfile",
+ "MacBridgePortConfigurationData",
+ "ExtendedVlanTaggingOperationConfigurationData":
+ { // let bridge init proceed by stopping the wait function
+ onuDeviceEntry.PDevOmciCC.mutexPLastTxMeInstance.RUnlock()
+ onuDeviceEntry.omciMessageReceived <- true
+ }
+ default:
+ {
+ logger.Warnw(ctx, "Unsupported ME name received!",
+ log.Fields{"ME name": onuDeviceEntry.PDevOmciCC.pLastTxMeInstance.GetName(), "device-id": onuDeviceEntry.deviceID})
+ onuDeviceEntry.PDevOmciCC.mutexPLastTxMeInstance.RUnlock()
+ }
+ }
+ } else {
+ onuDeviceEntry.PDevOmciCC.mutexPLastTxMeInstance.RUnlock()
+ }
+ } else {
+ onuDeviceEntry.PDevOmciCC.mutexPLastTxMeInstance.RUnlock()
+ logger.Errorw(ctx, "Pointer to last Tx MeInstance is nil!", log.Fields{"device-id": onuDeviceEntry.deviceID})
+ }
+}
+
+func (onuDeviceEntry *OnuDeviceEntry) handleOmciMibDownloadSetResponseMessage(ctx context.Context, msg OmciMessage) {
+ msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeSetResponse)
+ if msgLayer == nil {
+ logger.Errorw(ctx, "Omci Msg layer could not be detected for SetResponse", log.Fields{"device-id": onuDeviceEntry.deviceID})
+ return
+ }
+ msgObj, msgOk := msgLayer.(*omci.SetResponse)
+ if !msgOk {
+ logger.Errorw(ctx, "Omci Msg layer could not be assigned for SetResponse", log.Fields{"device-id": onuDeviceEntry.deviceID})
+ return
+ }
+ logger.Debugw(ctx, "SetResponse Data", log.Fields{"device-id": onuDeviceEntry.deviceID, "data-fields": msgObj})
+ if msgObj.Result != me.Success {
+ logger.Errorw(ctx, "Omci SetResponse Error - later: drive FSM to abort state ?", log.Fields{"device-id": onuDeviceEntry.deviceID,
+ "Error": msgObj.Result})
+ // possibly force FSM into abort or ignore some errors for some messages? store error for mgmt display?
+ return
+ }
+ // compare comments above for CreateResponse (apply also here ...)
+
+ onuDeviceEntry.PDevOmciCC.mutexPLastTxMeInstance.RLock()
+ if onuDeviceEntry.PDevOmciCC.pLastTxMeInstance != nil {
+ if msgObj.EntityClass == onuDeviceEntry.PDevOmciCC.pLastTxMeInstance.GetClassID() &&
+ msgObj.EntityInstance == onuDeviceEntry.PDevOmciCC.pLastTxMeInstance.GetEntityID() {
+ //store the created ME into DB //TODO??? obviously the Python code does not store the config ...
+ // if, then something like:
+ //onuDeviceEntry.pOnuDB.StoreMe(msgObj)
+
+ switch onuDeviceEntry.PDevOmciCC.pLastTxMeInstance.GetName() {
+ case "Onu2G":
+ { // let the FSM proceed ...
+ onuDeviceEntry.PDevOmciCC.mutexPLastTxMeInstance.RUnlock()
+ _ = onuDeviceEntry.pMibDownloadFsm.pFsm.Event(dlEvRxOnu2gResp)
+ }
+ //so far that was the only MibDownlad Set Element ...
+ default:
+ {
+ logger.Warnw(ctx, "Unsupported ME name received!",
+ log.Fields{"ME name": onuDeviceEntry.PDevOmciCC.pLastTxMeInstance.GetName(), "device-id": onuDeviceEntry.deviceID})
+ onuDeviceEntry.PDevOmciCC.mutexPLastTxMeInstance.RUnlock()
+ }
+
+ }
+ } else {
+ onuDeviceEntry.PDevOmciCC.mutexPLastTxMeInstance.RUnlock()
+ }
+ } else {
+ onuDeviceEntry.PDevOmciCC.mutexPLastTxMeInstance.RUnlock()
+ logger.Errorw(ctx, "Pointer to last Tx MeInstance is nil!", log.Fields{"device-id": onuDeviceEntry.deviceID})
+ }
+}
+
func (onuDeviceEntry *OnuDeviceEntry) handleOmciMibDownloadMessage(ctx context.Context, msg OmciMessage) {
logger.Debugw(ctx, "Rx OMCI MibDownload Msg", log.Fields{"device-id": onuDeviceEntry.deviceID,
"msgType": msg.OmciMsg.MessageType})
switch msg.OmciMsg.MessageType {
case omci.CreateResponseType:
- {
- msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeCreateResponse)
- if msgLayer == nil {
- logger.Errorw(ctx, "Omci Msg layer could not be detected for CreateResponse", log.Fields{"device-id": onuDeviceEntry.deviceID})
- return
- }
- msgObj, msgOk := msgLayer.(*omci.CreateResponse)
- if !msgOk {
- logger.Errorw(ctx, "Omci Msg layer could not be assigned for CreateResponse", log.Fields{"device-id": onuDeviceEntry.deviceID})
- return
- }
- logger.Debugw(ctx, "CreateResponse Data", log.Fields{"device-id": onuDeviceEntry.deviceID, "data-fields": msgObj})
- if msgObj.Result != me.Success && msgObj.Result != me.InstanceExists {
- logger.Errorw(ctx, "Omci CreateResponse Error - later: drive FSM to abort state ?", log.Fields{"device-id": onuDeviceEntry.deviceID, "Error": msgObj.Result})
- // possibly force FSM into abort or ignore some errors for some messages? store error for mgmt display?
- return
- }
- // maybe there is a way of pushing the specific create response type generally to the FSM
- // and let the FSM verify, if the response was according to current state
- // and possibly store the element to DB and progress - maybe some future option ...
- // but as that is not straightforward to me I insert the type checkes manually here
- // and feed the FSM with only 'pre-defined' events ...
- if msgObj.EntityClass == onuDeviceEntry.PDevOmciCC.pLastTxMeInstance.GetClassID() &&
- msgObj.EntityInstance == onuDeviceEntry.PDevOmciCC.pLastTxMeInstance.GetEntityID() {
- //store the created ME into DB //TODO??? obviously the Python code does not store the config ...
- // if, then something like:
- //onuDeviceEntry.pOnuDB.StoreMe(msgObj)
-
- // 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 onuDeviceEntry.PDevOmciCC.pLastTxMeInstance.GetName() {
- case "GalEthernetProfile":
- { // let the FSM proceed ...
- _ = onuDeviceEntry.pMibDownloadFsm.pFsm.Event(dlEvRxGalResp)
- }
- case "MacBridgeServiceProfile",
- "MacBridgePortConfigurationData",
- "ExtendedVlanTaggingOperationConfigurationData":
- { // let bridge init proceed by stopping the wait function
- onuDeviceEntry.omciMessageReceived <- true
- }
- }
- }
- } //CreateResponseType
+ onuDeviceEntry.handleOmciMibDownloadCreateResponseMessage(ctx, msg)
//TODO
// onuDeviceEntry.pMibDownloadFsm.pFsm.Event("rx_evtocd_resp")
-
case omci.SetResponseType:
- {
- msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeSetResponse)
- if msgLayer == nil {
- logger.Errorw(ctx, "Omci Msg layer could not be detected for SetResponse", log.Fields{"device-id": onuDeviceEntry.deviceID})
- return
- }
- msgObj, msgOk := msgLayer.(*omci.SetResponse)
- if !msgOk {
- logger.Errorw(ctx, "Omci Msg layer could not be assigned for SetResponse", log.Fields{"device-id": onuDeviceEntry.deviceID})
- return
- }
- logger.Debugw(ctx, "SetResponse Data", log.Fields{"device-id": onuDeviceEntry.deviceID, "data-fields": msgObj})
- if msgObj.Result != me.Success {
- logger.Errorw(ctx, "Omci SetResponse Error - later: drive FSM to abort state ?", log.Fields{"device-id": onuDeviceEntry.deviceID,
- "Error": msgObj.Result})
- // possibly force FSM into abort or ignore some errors for some messages? store error for mgmt display?
- return
- }
- // compare comments above for CreateResponse (apply also here ...)
- if msgObj.EntityClass == onuDeviceEntry.PDevOmciCC.pLastTxMeInstance.GetClassID() &&
- msgObj.EntityInstance == onuDeviceEntry.PDevOmciCC.pLastTxMeInstance.GetEntityID() {
- //store the created ME into DB //TODO??? obviously the Python code does not store the config ...
- // if, then something like:
- //onuDeviceEntry.pOnuDB.StoreMe(msgObj)
-
- switch onuDeviceEntry.PDevOmciCC.pLastTxMeInstance.GetName() {
- case "Onu2G":
- { // let the FSM proceed ...
- _ = onuDeviceEntry.pMibDownloadFsm.pFsm.Event(dlEvRxOnu2gResp)
- }
- //so far that was the only MibDownlad Set Element ...
- }
- }
- } //SetResponseType
+ onuDeviceEntry.handleOmciMibDownloadSetResponseMessage(ctx, msg)
default:
{
logger.Errorw(ctx, "Rx OMCI MibDownload unhandled MsgType", log.Fields{"device-id": onuDeviceEntry.deviceID,
@@ -266,14 +309,17 @@
"device-id": onuDeviceEntry.deviceID, "for PortNo": uniNo})
//create MBSP
+ onuDeviceEntry.PDevOmciCC.mutexPLastTxMeInstance.Lock()
meInstance, err := onuDeviceEntry.PDevOmciCC.sendCreateMBServiceProfile(
log.WithSpanFromContext(context.TODO(), ctx), uniPort, onuDeviceEntry.pOpenOnuAc.omciTimeout, true)
if err != nil {
+ onuDeviceEntry.PDevOmciCC.mutexPLastTxMeInstance.Unlock()
logger.Errorw(ctx, "MBServiceProfile create failed, aborting MibDownload FSM!", log.Fields{"device-id": onuDeviceEntry.deviceID})
_ = onuDeviceEntry.pMibDownloadFsm.pFsm.Event(dlEvReset)
return
}
onuDeviceEntry.PDevOmciCC.pLastTxMeInstance = meInstance
+ onuDeviceEntry.PDevOmciCC.mutexPLastTxMeInstance.Unlock()
//verify response
err = onuDeviceEntry.waitforOmciResponse(ctx, meInstance)
if err != nil {
@@ -284,15 +330,18 @@
}
//create MBPCD
+ onuDeviceEntry.PDevOmciCC.mutexPLastTxMeInstance.Lock()
meInstance, err = onuDeviceEntry.PDevOmciCC.sendCreateMBPConfigData(
log.WithSpanFromContext(context.TODO(), ctx), uniPort, onuDeviceEntry.pOpenOnuAc.omciTimeout, true)
if err != nil {
+ onuDeviceEntry.PDevOmciCC.mutexPLastTxMeInstance.Unlock()
logger.Errorw(ctx, "MBPConfigData create failed, aborting MibDownload FSM!",
log.Fields{"device-id": onuDeviceEntry.deviceID})
_ = onuDeviceEntry.pMibDownloadFsm.pFsm.Event(dlEvReset)
return
}
onuDeviceEntry.PDevOmciCC.pLastTxMeInstance = meInstance
+ onuDeviceEntry.PDevOmciCC.mutexPLastTxMeInstance.Unlock()
//verify response
err = onuDeviceEntry.waitforOmciResponse(ctx, meInstance)
if err != nil {
@@ -303,15 +352,18 @@
}
//create EVTOCD
+ onuDeviceEntry.PDevOmciCC.mutexPLastTxMeInstance.Lock()
meInstance, err = onuDeviceEntry.PDevOmciCC.sendCreateEVTOConfigData(
log.WithSpanFromContext(context.TODO(), ctx), uniPort, onuDeviceEntry.pOpenOnuAc.omciTimeout, true)
if err != nil {
+ onuDeviceEntry.PDevOmciCC.mutexPLastTxMeInstance.Unlock()
logger.Errorw(ctx, "EVTOConfigData create failed, aborting MibDownload FSM!",
log.Fields{"device-id": onuDeviceEntry.deviceID})
_ = onuDeviceEntry.pMibDownloadFsm.pFsm.Event(dlEvReset)
return
}
onuDeviceEntry.PDevOmciCC.pLastTxMeInstance = meInstance
+ onuDeviceEntry.PDevOmciCC.mutexPLastTxMeInstance.Unlock()
//verify response
err = onuDeviceEntry.waitforOmciResponse(ctx, meInstance)
if err != nil {