OnuUpgrade: Use download state only for image download (revert activity progress indication on activate/commit),
consistent state indication on abort, improval of software download abortion
Signed-off-by: mpagenko <michael.pagenkopf@adtran.com>
Change-Id: I2ca6e22662bc3bbede355176fbb4b2171add3f35
diff --git a/internal/pkg/core/device_handler.go b/internal/pkg/core/device_handler.go
index 22f08f8..537533c 100755
--- a/internal/pkg/core/device_handler.go
+++ b/internal/pkg/core/device_handler.go
@@ -1315,28 +1315,25 @@
pDeviceImageState.ImageState.Version = aVersion
dh.lockUpgradeFsm.RLock()
if dh.pOnuUpradeFsm != nil {
- if aVersion == dh.pOnuUpradeFsm.GetImageVersion(ctx) {
- // so then we cancel the upgrade operation
- // but before we still request the actual ImageState (which should not change with the cancellation)
- pDeviceImageState.ImageState.ImageState = dh.pOnuUpradeFsm.GetSpecificImageState(ctx)
- dh.lockUpgradeFsm.RUnlock()
- pDeviceImageState.ImageState.DownloadState = voltha.ImageState_DOWNLOAD_CANCELLED
- pDeviceImageState.ImageState.Reason = voltha.ImageState_CANCELLED_ON_REQUEST
+ dh.lockUpgradeFsm.RUnlock()
+ // so then we cancel the upgrade operation
+ // but before we still request the actual upgrade states (which should not change with the cancellation)
+ pImageState := dh.pOnuUpradeFsm.GetImageStates(ctx, aImageIdentifier, aVersion)
+ pDeviceImageState.ImageState.DownloadState = pImageState.DownloadState
+ pDeviceImageState.ImageState.Reason = voltha.ImageState_CANCELLED_ON_REQUEST
+ pDeviceImageState.ImageState.ImageState = pImageState.ImageState
+ if pImageState.DownloadState != voltha.ImageState_DOWNLOAD_UNKNOWN {
+ //so here the imageIdentifier or version equals to what is used in the upgrade FSM
dh.pOnuUpradeFsm.CancelProcessing(ctx, true, voltha.ImageState_CANCELLED_ON_REQUEST) //complete abort
- } else { //nothing to cancel, states unknown
- dh.lockUpgradeFsm.RUnlock()
- pDeviceImageState.ImageState.DownloadState = voltha.ImageState_DOWNLOAD_UNKNOWN
- pDeviceImageState.ImageState.Reason = voltha.ImageState_NO_ERROR
- pDeviceImageState.ImageState.ImageState = voltha.ImageState_IMAGE_UNKNOWN
- }
+ } //nothing to cancel (upgrade FSM for different image stays alive)
} else {
+ dh.lockUpgradeFsm.RUnlock()
// if no upgrade is ongoing, nothing is canceled and accordingly the states of the requested image are unknown
// reset also the dh handler LastUpgradeImageState (not relevant anymore/cleared)
(*dh.pLastUpgradeImageState).DownloadState = voltha.ImageState_DOWNLOAD_UNKNOWN
(*dh.pLastUpgradeImageState).Reason = voltha.ImageState_NO_ERROR
(*dh.pLastUpgradeImageState).ImageState = voltha.ImageState_IMAGE_UNKNOWN
(*dh.pLastUpgradeImageState).Version = "" //reset to 'no (relevant) upgrade done' (like initial state)
- dh.lockUpgradeFsm.RUnlock()
pDeviceImageState.ImageState.DownloadState = voltha.ImageState_DOWNLOAD_UNKNOWN
pDeviceImageState.ImageState.Reason = voltha.ImageState_NO_ERROR
pDeviceImageState.ImageState.ImageState = voltha.ImageState_IMAGE_UNKNOWN
@@ -2638,8 +2635,8 @@
return fmt.Errorf(fmt.Sprintf("OnuSwUpgradeFSM could not be started for device-id: %s", dh.device.Id))
}
/***** LockStateFSM started */
- //reset the last stored upgrade states
- (*dh.pLastUpgradeImageState).DownloadState = voltha.ImageState_DOWNLOAD_STARTED //already with updated state
+ //reset the last stored upgrade states (which anyway should be don't care as long as the newly created FSM exists)
+ (*dh.pLastUpgradeImageState).DownloadState = voltha.ImageState_DOWNLOAD_UNKNOWN
(*dh.pLastUpgradeImageState).Reason = voltha.ImageState_NO_ERROR
(*dh.pLastUpgradeImageState).ImageState = voltha.ImageState_IMAGE_UNKNOWN
logger.Debugw(ctx, "OnuSwUpgradeFSM started", log.Fields{
diff --git a/internal/pkg/swupg/omci_onu_upgrade.go b/internal/pkg/swupg/omci_onu_upgrade.go
index dbcb141..43ad621 100755
--- a/internal/pkg/swupg/omci_onu_upgrade.go
+++ b/internal/pkg/swupg/omci_onu_upgrade.go
@@ -49,7 +49,39 @@
//cOmciDownloadCompleteTimeout = 5400 //in s for the complete timeout (may be better scale to image size/ noOfWindows)
)
-// events of config PON ANI port FSM
+// tEndSwDlResponseResult - Response result from EndSwDownload as used in channel indication
+type tUpgradePhase uint8
+
+const (
+ // undefined phase
+ cUpgradeUndefined tUpgradePhase = iota
+ // downloading image
+ cUpgradeDownloading
+ // image downloaded
+ cUpgradeDownloaded
+ // activating image
+ cUpgradeActivating
+ // image activated
+ cUpgradeActivated
+ // committing image
+ cUpgradeCommitting
+ // image committed
+ cUpgradeCommitted
+)
+
+// tEndSwDlResponseResult - Response result from EndSwDownload as used in channel indication
+type tEndSwDlResponseResult uint8
+
+const (
+ // response success
+ cEndSwDlResponseSuccess tEndSwDlResponseResult = iota
+ // response busy (repeat)
+ cEndSwDlResponseBusy
+ // response error or abort waiting for response
+ cEndSwDlResponseAbort
+)
+
+// upgrade FSM related events
const (
UpgradeEvStart = "UpgradeEvStart"
UpgradeEvDisable = "UpgradeEvDisable"
@@ -77,7 +109,7 @@
UpgradeEvAbortSwDownload = "UpgradeEvAbortSwDownload"
)
-// states of config PON ANI port FSM
+// upgrade FSM related states
const (
UpgradeStDisabled = "UpgradeStDisabled"
UpgradeStStarting = "UpgradeStStarting"
@@ -130,6 +162,7 @@
downloadToOnuTimeout4MB time.Duration //timeout for downloading the image to the ONU for a 4MB image slice
omciSectionInterleaveDelay time.Duration //DownloadSectionInterleave delay in milliseconds
delayEndSwDl bool //flag to provide a delay between last section and EndSwDl
+ repeatAbort bool //flag to indicate if OMCI EndSwDownload (abort) is to be repeated
pLastTxMeInstance *me.ManagedEntity
waitCountEndSwDl uint8 //number, how often is waited for EndSwDl at maximum
waitDelayEndSwDl time.Duration //duration, how long is waited before next request on EndSwDl
@@ -147,11 +180,13 @@
mutexAbortRequest sync.RWMutex
abortRequested voltha.ImageState_ImageFailureReason
conditionalCancelRequested bool
+ upgradePhase tUpgradePhase
volthaDownloadState voltha.ImageState_ImageDownloadState
volthaDownloadReason voltha.ImageState_ImageFailureReason
volthaImageState voltha.ImageState_ImageActivationState
+ downloadReasonCached voltha.ImageState_ImageFailureReason
isEndSwDlOpen bool
- chReceiveAbortEndSwDlResponse chan bool
+ chReceiveAbortEndSwDlResponse chan tEndSwDlResponseResult
}
//NewOnuUpgradeFsm is the 'constructor' for the state machine to config the PON ANI ports
@@ -171,7 +206,8 @@
downloadToOnuTimeout4MB: apDeviceHandler.GetDlToOnuTimeout4M(),
waitCountEndSwDl: cWaitCountEndSwDl,
waitDelayEndSwDl: cWaitDelayEndSwDlSeconds,
- volthaDownloadState: voltha.ImageState_DOWNLOAD_STARTED, //if FSM created we can assume that the download (to adapter) really started
+ upgradePhase: cUpgradeUndefined,
+ volthaDownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
volthaDownloadReason: voltha.ImageState_NO_ERROR,
volthaImageState: voltha.ImageState_IMAGE_UNKNOWN,
abortRequested: voltha.ImageState_NO_ERROR,
@@ -179,7 +215,7 @@
instFsm.chReceiveExpectedResponse = make(chan bool)
instFsm.chAdapterDlReady = make(chan bool)
instFsm.chOnuDlReady = make(chan bool)
- instFsm.chReceiveAbortEndSwDlResponse = make(chan bool)
+ instFsm.chReceiveAbortEndSwDlResponse = make(chan tEndSwDlResponseResult)
instFsm.PAdaptFsm = cmn.NewAdapterFsm(aName, instFsm.deviceID, aCommChannel)
if instFsm.PAdaptFsm == nil {
@@ -224,7 +260,7 @@
{Name: UpgradeEvReset, Src: []string{UpgradeStStarting, UpgradeStWaitingAdapterDL, UpgradeStPreparingDL, UpgradeStDLSection,
UpgradeStVerifyWindow, UpgradeStDLSection, UpgradeStFinalizeDL, UpgradeStWaitEndDL, UpgradeStCheckImageName,
UpgradeStWaitForActivate,
- UpgradeStCommitSw, UpgradeStCheckCommitted},
+ UpgradeStCommitSw, UpgradeStCheckCommitted, UpgradeStAbortingDL},
Dst: UpgradeStResetting},
{Name: UpgradeEvAbort, Src: []string{UpgradeStStarting, UpgradeStWaitingAdapterDL, UpgradeStPreparingDL, UpgradeStDLSection,
UpgradeStVerifyWindow, UpgradeStDLSection, UpgradeStFinalizeDL, UpgradeStWaitEndDL, UpgradeStCheckImageName,
@@ -313,8 +349,7 @@
oFsm.imageVersion = apImageRequest.Image.Version
oFsm.activateImage = apImageRequest.ActivateOnSuccess
oFsm.commitImage = apImageRequest.CommitOnSuccess
- //TODO: currently straightforward options activate and commit are expected to be set and (unconditionally) done
- // for separate handling of these options the FSM must accordingly branch from the concerned states - later
+ oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_STARTED //state change indication for download request
oFsm.mutexUpgradeParams.Unlock()
_ = pBaseFsm.Event(UpgradeEvAdapterDownload) //no need to call the FSM event in background here
return nil
@@ -329,11 +364,11 @@
// called from 'new' API Activate_onu_image
func (oFsm *OnuUpgradeFsm) SetActivationParamsRunning(ctx context.Context,
aImageIdentifier string, aCommit bool) error {
+ logger.Debugw(ctx, "OnuUpgradeFsm activate/commit parameter setting", log.Fields{
+ "device-id": oFsm.deviceID, "image-id": aImageIdentifier, "commit": aCommit})
oFsm.mutexUpgradeParams.Lock()
//set activate/commit independent from state, if FSM is already beyond concerned states, then it does not matter anyway
// (as long as the Imageidentifier is correct)
- logger.Debugw(ctx, "OnuUpgradeFsm activate/commit parameter setting", log.Fields{
- "device-id": oFsm.deviceID, "image-id": aImageIdentifier, "commit": aCommit})
if aImageIdentifier != oFsm.imageIdentifier {
logger.Errorw(ctx, "OnuUpgradeFsm abort: mismatching upgrade image", log.Fields{
"device-id": oFsm.deviceID, "request-image": aImageIdentifier, "fsm-image": oFsm.imageIdentifier})
@@ -343,18 +378,16 @@
}
oFsm.activateImage = true
oFsm.commitImage = aCommit
+ oFsm.mutexUpgradeParams.Unlock()
var pBaseFsm *fsm.FSM = nil
if oFsm.PAdaptFsm != nil {
pBaseFsm = oFsm.PAdaptFsm.PFsm
}
if pBaseFsm != nil {
if pBaseFsm.Is(UpgradeStWaitForActivate) {
- oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_STARTED //better choice would be 'UpgradeState=Started'
- oFsm.mutexUpgradeParams.Unlock()
logger.Debugw(ctx, "OnuUpgradeFsm finish waiting for activate", log.Fields{"device-id": oFsm.deviceID})
_ = pBaseFsm.Event(UpgradeEvRequestActivate) //no need to call the FSM event in background here
} else {
- oFsm.mutexUpgradeParams.Unlock()
logger.Debugw(ctx, "OnuUpgradeFsm not (yet?) waiting for activate", log.Fields{
"device-id": oFsm.deviceID, "current FsmState": pBaseFsm.Current()})
}
@@ -382,8 +415,7 @@
oFsm.activateImage = true
oFsm.commitImage = aCommit
// indicate start of the upgrade activity
- oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_STARTED //better choice would be 'UpgradeState=Started'
- oFsm.volthaImageState = voltha.ImageState_IMAGE_INACTIVE //as simply applied for inactive image
+ oFsm.volthaImageState = voltha.ImageState_IMAGE_ACTIVATING //state change indication for activate request
oFsm.mutexUpgradeParams.Unlock()
//directly request the FSM to activate the image
_ = pBaseFsm.Event(UpgradeEvRequestActivate) //no need to call the FSM event in background here
@@ -413,7 +445,6 @@
oFsm.deviceID))
}
oFsm.commitImage = true
- oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_STARTED //better choice would be 'UpgradeState=Started'
oFsm.mutexUpgradeParams.Unlock()
var pBaseFsm *fsm.FSM = nil
if oFsm.PAdaptFsm != nil {
@@ -447,8 +478,7 @@
oFsm.InactiveImageMeID = aActiveImageID //upgrade state machines inactive ImageId is the new active ImageId
oFsm.imageVersion = aImageVersion
oFsm.commitImage = true
- oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_STARTED //better choice would be 'UpgradeState=Started'
- oFsm.volthaImageState = voltha.ImageState_IMAGE_ACTIVE //as simply applied for active image
+ oFsm.volthaImageState = voltha.ImageState_IMAGE_COMMITTING //state change indication for activate request
oFsm.mutexUpgradeParams.Unlock()
//directly request the FSM to commit the image
_ = pBaseFsm.Event(UpgradeEvCommitSw) //no need to call the FSM event in background here
@@ -499,11 +529,8 @@
func (oFsm *OnuUpgradeFsm) SetImageStateActive(ctx context.Context) {
oFsm.mutexUpgradeParams.Lock()
defer oFsm.mutexUpgradeParams.Unlock()
+ oFsm.upgradePhase = cUpgradeActivated
oFsm.volthaImageState = voltha.ImageState_IMAGE_ACTIVE
- if !oFsm.commitImage {
- //if commit is not additionally set, regard the upgrade activity as successful
- oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_SUCCEEDED //better choice would be 'UpgradeState=Succeeded'
- }
}
//GetImageVersion delivers image-version of the running upgrade
@@ -535,31 +562,28 @@
// in any case (even if it might be automatically requested by above cancellation of waiting) ensure resetting the FSM
// specific here: See definition of state changes: some states are excluded from reset for possible later commit
- PAdaptFsm := oFsm.PAdaptFsm
- if PAdaptFsm != nil {
+ pAdaptFsm := oFsm.PAdaptFsm
+ if pAdaptFsm != nil {
// calling FSM events in background to avoid blocking of the caller
go func(aPAFsm *cmn.AdapterFsm) {
if aPAFsm.PFsm != nil {
if aPAFsm.PFsm.Is(UpgradeStWaitEndDL) {
oFsm.chReceiveExpectedResponse <- false //which aborts the FSM in WaitEndDL state
+ } else if aPAFsm.PFsm.Is(UpgradeStAbortingDL) {
+ oFsm.chReceiveAbortEndSwDlResponse <- cEndSwDlResponseAbort //abort waiting on EndDownloadResponse
}
- // in case of state-conditional request the
var err error
if abCompleteAbort {
+ // in case of unconditional abort request the ImageState is set immediately
oFsm.mutexUpgradeParams.Lock()
//any previous lingering conditional cancelRequest is superseded by this abortion
oFsm.conditionalCancelRequested = false
- if aReason == voltha.ImageState_CANCELLED_ON_REQUEST {
- oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_CANCELLED
- } else {
- oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
- }
oFsm.volthaDownloadReason = aReason
oFsm.mutexUpgradeParams.Unlock()
err = aPAFsm.PFsm.Event(UpgradeEvAbort) //as unconditional default FSM cancellation
} else {
- //at conditional request the image states are set when reaching the reset state
+ //at conditional abort request the image states are set when reaching the reset state
oFsm.conditionalCancelRequested = true
err = aPAFsm.PFsm.Event(UpgradeEvReset) //as state-conditional default FSM cleanup
}
@@ -569,7 +593,7 @@
"device-id": oFsm.deviceID, "error": err})
}
} //else the FSM seems already to be in some released state
- }(PAdaptFsm)
+ }(pAdaptFsm)
}
}
@@ -606,9 +630,7 @@
fileLen, err = oFsm.pDownloadManager.getImageBufferLen(ctx, oFsm.pImageDsc.Name, oFsm.pImageDsc.LocalDir)
}
if err != nil || fileLen > int64(cMaxUint32) {
- oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
oFsm.volthaDownloadReason = voltha.ImageState_UNKNOWN_ERROR //something like 'LOCAL_FILE_ERROR' would be better (proto)
- oFsm.volthaImageState = voltha.ImageState_IMAGE_UNKNOWN
oFsm.mutexUpgradeParams.Unlock()
logger.Errorw(ctx, "OnuUpgradeFsm abort: problems getting image buffer length", log.Fields{
"device-id": oFsm.deviceID, "error": err, "length": fileLen})
@@ -628,9 +650,7 @@
oFsm.imageBuffer, err = oFsm.pDownloadManager.getDownloadImageBuffer(ctx, oFsm.pImageDsc.Name, oFsm.pImageDsc.LocalDir)
}
if err != nil {
- oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
oFsm.volthaDownloadReason = voltha.ImageState_UNKNOWN_ERROR //something like 'LOCAL_FILE_ERROR' would be better (proto)
- oFsm.volthaImageState = voltha.ImageState_IMAGE_UNKNOWN
oFsm.mutexUpgradeParams.Unlock()
logger.Errorw(ctx, "OnuUpgradeFsm abort: can't get image buffer", log.Fields{
"device-id": oFsm.deviceID, "error": err})
@@ -671,7 +691,7 @@
if err != nil {
logger.Errorw(ctx, "StartSwDl abort: can't send section", log.Fields{
"device-id": oFsm.deviceID, "error": err})
- oFsm.abortOnOmciError(ctx, true, voltha.ImageState_IMAGE_UNKNOWN) //no ImageState update
+ oFsm.abortOnOmciError(ctx, true)
return
}
oFsm.isEndSwDlOpen = true
@@ -687,6 +707,7 @@
var downloadSection []byte
FramePrint := false //default no printing of downloadSection frames
oFsm.mutexUpgradeParams.Lock()
+ oFsm.upgradePhase = cUpgradeDownloading //start of downloading image to ONU
if oFsm.nextDownloadSectionsAbsolute == 0 {
//debug print of first section frame
FramePrint = true
@@ -697,11 +718,7 @@
oFsm.mutexAbortRequest.RLock()
// this way out of the section download loop on abort request
if oFsm.abortRequested != voltha.ImageState_NO_ERROR {
- if oFsm.abortRequested == voltha.ImageState_CANCELLED_ON_REQUEST {
- oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_CANCELLED
- } else {
- oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
- }
+ //states are updated when entering the reset state ...
oFsm.volthaDownloadReason = oFsm.abortRequested
oFsm.mutexAbortRequest.RUnlock()
oFsm.mutexUpgradeParams.Unlock()
@@ -724,7 +741,6 @@
logger.Errorw(ctx, "OnuUpgradeFsm buffer error: exceeded length", log.Fields{
"device-id": oFsm.deviceID, "bufferStartOffset": bufferStartOffset,
"bufferEndOffset": bufferEndOffset, "imageLength": oFsm.imageLength})
- oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
oFsm.volthaDownloadReason = voltha.ImageState_UNKNOWN_ERROR //something like 'LOCAL_FILE_ERROR' would be better (proto)
oFsm.mutexUpgradeParams.Unlock()
//logical error -- reset the FSM
@@ -754,7 +770,7 @@
if err != nil {
logger.Errorw(ctx, "DlSection abort: can't send section", log.Fields{
"device-id": oFsm.deviceID, "section absolute": oFsm.nextDownloadSectionsAbsolute, "error": err})
- oFsm.abortOnOmciError(ctx, true, voltha.ImageState_IMAGE_UNKNOWN) //no ImageState update
+ oFsm.abortOnOmciError(ctx, true)
return
}
oFsm.mutexUpgradeParams.Lock()
@@ -802,7 +818,6 @@
if pBaseFsm == nil {
logger.Errorw(ctx, "EndSwDl abort: BaseFsm invalid", log.Fields{"device-id": oFsm.deviceID})
oFsm.mutexUpgradeParams.Lock()
- oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
oFsm.volthaDownloadReason = voltha.ImageState_UNKNOWN_ERROR
oFsm.mutexUpgradeParams.Unlock()
// Can't call FSM Event directly, decoupling it
@@ -814,11 +829,10 @@
err := oFsm.pOmciCC.SendEndSoftwareDownload(log.WithSpanFromContext(context.Background(), ctx), oFsm.pDeviceHandler.GetOmciTimeout(), false,
oFsm.PAdaptFsm.CommChan, oFsm.InactiveImageMeID, oFsm.origImageLength, oFsm.imageCRC)
- oFsm.isEndSwDlOpen = false // also to be reset in case of OMCI error, as further send attempts would not make sense
if err != nil {
logger.Errorw(ctx, "EndSwDl abort: can't send section", log.Fields{
"device-id": oFsm.deviceID, "error": err})
- oFsm.abortOnOmciError(ctx, true, voltha.ImageState_IMAGE_UNKNOWN) //no ImageState update
+ oFsm.abortOnOmciError(ctx, true)
return
}
// go waiting for the EndSwDLResponse and check, if the ONU is ready for activation
@@ -841,7 +855,7 @@
return
}
oFsm.mutexUpgradeParams.Lock()
- oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
+ oFsm.isEndSwDlOpen = false //no need to additionally request abort of download (already finished)
oFsm.volthaDownloadReason = voltha.ImageState_IMAGE_REFUSED_BY_ONU //something like 'END_DOWNLOAD_TIMEOUT' would be better (proto)
oFsm.mutexUpgradeParams.Unlock()
go func(a_pAFsm *cmn.AdapterFsm) {
@@ -870,6 +884,7 @@
return
case success := <-oFsm.chReceiveExpectedResponse:
logger.Debugw(ctx, "WaitEndDl stop wait timer", log.Fields{"device-id": oFsm.deviceID})
+ oFsm.isEndSwDlOpen = false //no request to abort of download (already finished or immediate abort)
pBaseFsm := oFsm.PAdaptFsm
if pBaseFsm == nil {
logger.Errorw(ctx, "WaitEndDl abort: BaseFsm invalid", log.Fields{
@@ -900,7 +915,7 @@
return
}
//timer was aborted
- oFsm.abortOnOmciError(ctx, true, voltha.ImageState_IMAGE_UNKNOWN) //no ImageState update
+ oFsm.abortOnOmciError(ctx, true)
return
}
}
@@ -915,7 +930,7 @@
if err != nil {
logger.Errorw(ctx, "OnuUpgradeFsm get Software Image ME result error",
log.Fields{"device-id": oFsm.deviceID, "Error": err})
- oFsm.abortOnOmciError(ctx, true, voltha.ImageState_IMAGE_UNKNOWN) //no ImageState update
+ oFsm.abortOnOmciError(ctx, true)
return
}
oFsm.pLastTxMeInstance = meInstance
@@ -930,10 +945,11 @@
if err != nil {
logger.Errorw(ctx, "ActivateSw abort: can't send activate frame", log.Fields{
"device-id": oFsm.deviceID, "error": err})
- oFsm.abortOnOmciError(ctx, true, voltha.ImageState_IMAGE_ACTIVATION_ABORTED)
+ oFsm.abortOnOmciError(ctx, true)
return
}
oFsm.mutexUpgradeParams.Lock()
+ oFsm.upgradePhase = cUpgradeActivating //start of image activation for ONU
oFsm.volthaImageState = voltha.ImageState_IMAGE_ACTIVATING
oFsm.mutexUpgradeParams.Unlock()
}
@@ -951,13 +967,14 @@
logger.Infow(ctx, "OnuUpgradeFsm commit SW", log.Fields{
"device-id": oFsm.deviceID, "me-id": inactiveImageID}) //more efficient activeImageID with above check
oFsm.volthaImageState = voltha.ImageState_IMAGE_COMMITTING
+ oFsm.upgradePhase = cUpgradeCommitting //start of image commitment for ONU
oFsm.mutexUpgradeParams.Unlock()
err := oFsm.pOmciCC.SendCommitSoftware(log.WithSpanFromContext(context.Background(), ctx), oFsm.pDeviceHandler.GetOmciTimeout(), false,
oFsm.PAdaptFsm.CommChan, inactiveImageID) //more efficient activeImageID with above check
if err != nil {
logger.Errorw(ctx, "CommitSw abort: can't send commit sw frame", log.Fields{
"device-id": oFsm.deviceID, "error": err})
- oFsm.abortOnOmciError(ctx, true, voltha.ImageState_IMAGE_COMMIT_ABORTED)
+ oFsm.abortOnOmciError(ctx, true)
return
}
return
@@ -971,9 +988,7 @@
}
oFsm.mutexUpgradeParams.Lock()
oFsm.conditionalCancelRequested = false //any lingering conditional cancelRequest is superseded by this error
- oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
oFsm.volthaDownloadReason = voltha.ImageState_CANCELLED_ON_ONU_STATE
- oFsm.volthaImageState = voltha.ImageState_IMAGE_COMMIT_ABORTED
oFsm.mutexUpgradeParams.Unlock()
//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
pBaseFsm := oFsm.PAdaptFsm
@@ -992,7 +1007,7 @@
if err != nil {
logger.Errorw(ctx, "OnuUpgradeFsm get Software Image ME result error",
log.Fields{"device-id": oFsm.deviceID, "Error": err})
- oFsm.abortOnOmciError(ctx, true, voltha.ImageState_IMAGE_COMMIT_ABORTED)
+ oFsm.abortOnOmciError(ctx, true)
return
}
oFsm.pLastTxMeInstance = meInstance
@@ -1001,13 +1016,7 @@
func (oFsm *OnuUpgradeFsm) enterResetting(ctx context.Context, e *fsm.Event) {
logger.Debugw(ctx, "OnuUpgradeFsm resetting", log.Fields{"device-id": oFsm.deviceID})
- // if the reset was conditionally requested
- if oFsm.conditionalCancelRequested {
- oFsm.mutexUpgradeParams.Lock()
- oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
- oFsm.volthaDownloadReason = voltha.ImageState_CANCELLED_ON_ONU_STATE
- oFsm.mutexUpgradeParams.Unlock()
- }
+ oFsm.stateUpdateOnReset(ctx)
// in case the download-to-ONU timer is still running - cancel it
//use non-blocking channel (to be independent from receiver state)
@@ -1020,6 +1029,12 @@
if pConfigUpgradeStateAFsm != nil {
var nextEvent string
if oFsm.isEndSwDlOpen {
+ if oFsm.repeatAbort {
+ oFsm.delayEndSwDl = true //run next abort with delay
+ } else { //initial request
+ oFsm.delayEndSwDl = false //run next abort with no delay
+ oFsm.waitCountEndSwDl = cWaitCountEndSwDl //init for possible repetitions
+ }
nextEvent = UpgradeEvAbortSwDownload
} else {
nextEvent = UpgradeEvRestart
@@ -1036,6 +1051,15 @@
func (oFsm *OnuUpgradeFsm) enterAbortingDL(ctx context.Context, e *fsm.Event) {
logger.Debugw(ctx, "OnuUpgradeFsm aborting download to ONU", log.Fields{"device-id": oFsm.deviceID})
+ oFsm.mutexUpgradeParams.RLock()
+ if oFsm.delayEndSwDl {
+ oFsm.mutexUpgradeParams.RUnlock()
+ //give the ONU some time for image discard activities
+ time.Sleep(cOmciEndSwDlDelaySeconds * time.Second)
+ } else {
+ oFsm.mutexUpgradeParams.RUnlock()
+ }
+
pBaseFsm := oFsm.PAdaptFsm
if pBaseFsm == nil {
logger.Errorw(ctx, "OnuUpgradeFsm aborting download: BaseFsm invalid", log.Fields{"device-id": oFsm.deviceID})
@@ -1045,8 +1069,6 @@
err := oFsm.pOmciCC.SendEndSoftwareDownload(log.WithSpanFromContext(context.Background(), ctx), oFsm.pDeviceHandler.GetOmciTimeout(), false,
oFsm.PAdaptFsm.CommChan, oFsm.InactiveImageMeID, 0, 0xFFFFFFFF)
- oFsm.isEndSwDlOpen = false // also to be reset in case of OMCI error, as further send attempts would not make sense
-
if err != nil {
logger.Errorw(ctx, "OnuUpgradeFsm aborting download: can't send EndSwDl request", log.Fields{"device-id": oFsm.deviceID})
// Can't call FSM Event directly, decoupling it
@@ -1066,15 +1088,58 @@
}
}(pBaseFsm)
return
- case <-oFsm.chReceiveAbortEndSwDlResponse:
- logger.Debug(ctx, "OnuUpgradeFsm aborting download: response received")
+ case response := <-oFsm.chReceiveAbortEndSwDlResponse:
+ logger.Debugw(ctx, "OnuUpgradeFsm aborting download: response received",
+ log.Fields{"device-id": oFsm.deviceID, "response": response})
+ //had to shift processing to separate function due to SCA complexity
+ if oFsm.abortingDlEvaluateResponse(ctx, pBaseFsm, response) {
+ return //event sent from function already
+ }
go func(a_pAFsm *cmn.AdapterFsm) {
if a_pAFsm != nil && a_pAFsm.PFsm != nil {
_ = a_pAFsm.PFsm.Event(UpgradeEvRestart)
}
}(pBaseFsm)
return
- }
+ } //select
+}
+
+//abortingDlEvaluateResponse waits for a channel indication with decision to proceed the FSM processing
+func (oFsm *OnuUpgradeFsm) abortingDlEvaluateResponse(ctx context.Context,
+ pBaseFsm *cmn.AdapterFsm, aResponseResult tEndSwDlResponseResult) bool {
+ switch aResponseResult {
+ case cEndSwDlResponseBusy: // indication for device busy, needs repetition
+ if oFsm.waitCountEndSwDl == 0 {
+ logger.Errorw(ctx, "aborting download: max limit of EndSwDl reached", log.Fields{
+ "device-id": oFsm.deviceID})
+ go func(a_pAFsm *cmn.AdapterFsm) {
+ if a_pAFsm != nil && a_pAFsm.PFsm != nil {
+ _ = a_pAFsm.PFsm.Event(UpgradeEvRestart) //give up and let FSM terminate
+ }
+ }(pBaseFsm)
+ } else {
+ logger.Debugw(ctx, "aborting download: re-trigger sending abort SwDl", log.Fields{
+ "device-id": oFsm.deviceID, "counter": oFsm.waitCountEndSwDl})
+ oFsm.waitCountEndSwDl--
+ oFsm.repeatAbort = true //repeated request in next round
+ go func(a_pAFsm *cmn.AdapterFsm) {
+ if a_pAFsm != nil && a_pAFsm.PFsm != nil {
+ _ = a_pAFsm.PFsm.Event(UpgradeEvReset) //which then re-triggers sending AbortSwDL
+ }
+ }(pBaseFsm)
+ }
+ return true
+ case cEndSwDlResponseSuccess: // indication for success response
+ logger.Infow(ctx, "aborting download: success response, terminating FSM", log.Fields{
+ "device-id": oFsm.deviceID})
+ case cEndSwDlResponseAbort: // indication for request to abort waiting for response
+ logger.Infow(ctx, "aborting download: request to abort waiting, terminating FSM", log.Fields{
+ "device-id": oFsm.deviceID})
+ default:
+ logger.Errorw(ctx, "aborting download: unknown channel indication, terminating FSM", log.Fields{
+ "device-id": oFsm.deviceID})
+ } //switch
+ return false
}
func (oFsm *OnuUpgradeFsm) enterRestarting(ctx context.Context, e *fsm.Event) {
@@ -1126,7 +1191,7 @@
if !ok {
logger.Info(ctx, "OnuUpgradeFsm Rx Msg - could not read from channel", log.Fields{"device-id": oFsm.deviceID})
// but then we have to ensure a restart of the FSM as well - as exceptional procedure
- oFsm.abortOnOmciError(ctx, true, voltha.ImageState_IMAGE_UNKNOWN) //no ImageState update
+ oFsm.abortOnOmciError(ctx, true)
break loop
}
logger.Debugw(ctx, "OnuUpgradeFsm Rx Msg", log.Fields{"device-id": oFsm.deviceID})
@@ -1150,7 +1215,6 @@
logger.Infow(ctx, "End OnuUpgradeFsm Msg processing", log.Fields{"device-id": oFsm.deviceID})
}
-//nolint: gocyclo
func (oFsm *OnuUpgradeFsm) handleOmciOnuUpgradeMessage(ctx context.Context, msg cmn.OmciMessage) {
logger.Debugw(ctx, "Rx OMCI OnuUpgradeFsm Msg", log.Fields{"device-id": oFsm.deviceID,
"msgType": msg.OmciMsg.MessageType})
@@ -1158,196 +1222,17 @@
switch msg.OmciMsg.MessageType {
case omci.StartSoftwareDownloadResponseType:
{
- msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeStartSoftwareDownloadResponse)
- if msgLayer == nil {
- logger.Errorw(ctx, "Omci Msg layer could not be detected for StartSwDlResponse",
- log.Fields{"device-id": oFsm.deviceID})
- oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
- return
- }
- msgObj, msgOk := msgLayer.(*omci.StartSoftwareDownloadResponse)
- if !msgOk {
- logger.Errorw(ctx, "Omci Msg layer could not be assigned for StartSwDlResponse",
- log.Fields{"device-id": oFsm.deviceID})
- oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
- return
- }
- logger.Debugw(ctx, "OnuUpgradeFsm StartSwDlResponse data", log.Fields{
- "device-id": oFsm.deviceID, "data-fields": msgObj})
- if msgObj.Result != me.Success {
- logger.Errorw(ctx, "OnuUpgradeFsm StartSwDlResponse result error - later: drive FSM to abort state ?",
- log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
- oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
- return
- }
-
- oFsm.mutexUpgradeParams.Lock()
- if msgObj.EntityInstance == oFsm.InactiveImageMeID {
- logger.Debugw(ctx, "Expected StartSwDlResponse received", log.Fields{"device-id": oFsm.deviceID})
- if msgObj.WindowSize != oFsm.omciDownloadWindowSizeLimit {
- // also response WindowSize = 0 is a valid number for used Window size 1
- logger.Debugw(ctx, "different StartSwDlResponse window size requested by ONU", log.Fields{
- "acceptedOnuWindowSizeLimit": msgObj.WindowSize, "device-id": oFsm.deviceID})
- oFsm.omciDownloadWindowSizeLimit = msgObj.WindowSize
- }
- oFsm.noOfWindows = oFsm.noOfSections / uint32(oFsm.omciDownloadWindowSizeLimit+1)
- if oFsm.noOfSections%uint32(oFsm.omciDownloadWindowSizeLimit+1) > 0 {
- oFsm.noOfWindows++
- }
- logger.Debugw(ctx, "OnuUpgradeFsm will use", log.Fields{
- "windows": oFsm.noOfWindows, "sections": oFsm.noOfSections,
- "at WindowSizeLimit": oFsm.omciDownloadWindowSizeLimit})
- oFsm.nextDownloadSectionsAbsolute = 0
- oFsm.nextDownloadSectionsWindow = 0
- oFsm.nextDownloadWindow = 0
-
- oFsm.mutexUpgradeParams.Unlock()
- _ = oFsm.PAdaptFsm.PFsm.Event(UpgradeEvRxStartSwDownload)
- return
- }
- oFsm.mutexUpgradeParams.Unlock()
- logger.Errorw(ctx, "OnuUpgradeFsm StartSwDlResponse wrong ME instance: try again (later)?",
- log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
- oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
+ oFsm.handleRxStartSwDownloadResponse(ctx, msg)
return
} //StartSoftwareDownloadResponseType
case omci.DownloadSectionResponseType:
{
- msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeDownloadSectionResponse)
- if msgLayer == nil {
- logger.Errorw(ctx, "Omci Msg layer could not be detected for DlSectionResponse",
- log.Fields{"device-id": oFsm.deviceID, "omci-message": msg.OmciMsg})
- oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
- return
- }
- msgObj, msgOk := msgLayer.(*omci.DownloadSectionResponse)
- if !msgOk {
- logger.Errorw(ctx, "Omci Msg layer could not be assigned for DlSectionResponse",
- log.Fields{"device-id": oFsm.deviceID})
- oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
- return
- }
- logger.Debugw(ctx, "OnuUpgradeFsm DlSectionResponse Data", log.Fields{
- "device-id": oFsm.deviceID, "data-fields": msgObj})
- if msgObj.Result != me.Success {
- logger.Errorw(ctx, "OnuUpgradeFsm DlSectionResponse result error - later: repeat window once?", //TODO!!!
- log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
- oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
- return
- }
- oFsm.mutexUpgradeParams.Lock()
- if msgObj.EntityInstance == oFsm.InactiveImageMeID {
- sectionNumber := msgObj.SectionNumber
- logger.Infow(ctx, "DlSectionResponse received", log.Fields{
- "window section-number": sectionNumber, "window": oFsm.nextDownloadWindow, "device-id": oFsm.deviceID})
-
- oFsm.nextDownloadWindow++
- if oFsm.nextDownloadWindow >= oFsm.noOfWindows {
- if sectionNumber != oFsm.omciDownloadWindowSizeLast {
- logger.Errorw(ctx, "OnuUpgradeFsm DlSectionResponse section error last window - later: repeat window once?", //TODO!!!
- log.Fields{"device-id": oFsm.deviceID, "actual section": sectionNumber,
- "expected section": oFsm.omciDownloadWindowSizeLast})
- oFsm.mutexUpgradeParams.Unlock()
- oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
- return
- }
- oFsm.delayEndSwDl = true //ensure a delay for the EndSwDl message
- //CRC computation for all data bytes of the file
- imageCRC := crc32a.Checksum(oFsm.imageBuffer[:int(oFsm.origImageLength)]) //store internal for multiple usage
- //revert the retrieved CRC Byte Order (seems not to deliver NetworkByteOrder)
- var byteSlice []byte = make([]byte, 4)
- binary.LittleEndian.PutUint32(byteSlice, uint32(imageCRC))
- oFsm.imageCRC = binary.BigEndian.Uint32(byteSlice)
- oFsm.mutexUpgradeParams.Unlock()
- _ = oFsm.PAdaptFsm.PFsm.Event(UpgradeEvEndSwDownload)
- return
- }
- if sectionNumber != oFsm.omciDownloadWindowSizeLimit {
- logger.Errorw(ctx, "OnuUpgradeFsm DlSectionResponse section error - later: repeat window once?", //TODO!!!
- log.Fields{"device-id": oFsm.deviceID, "actual-section": sectionNumber,
- "expected section": oFsm.omciDownloadWindowSizeLimit})
- oFsm.mutexUpgradeParams.Unlock()
- oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
- return
- }
- oFsm.nextDownloadSectionsWindow = 0
- oFsm.mutexUpgradeParams.Unlock()
- _ = oFsm.PAdaptFsm.PFsm.Event(UpgradeEvContinueNextWindow)
- return
- }
- oFsm.mutexUpgradeParams.Unlock()
- logger.Errorw(ctx, "OnuUpgradeFsm Omci StartSwDlResponse wrong ME instance: try again (later)?",
- log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
- oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
+ oFsm.handleRxSwSectionResponse(ctx, msg)
return
} //DownloadSectionResponseType
case omci.EndSoftwareDownloadResponseType:
{
- if oFsm.PAdaptFsm.PFsm.Is(UpgradeStAbortingDL) {
- // calling FSM events in background to avoid blocking of the caller
- go func(aPAFsm *cmn.AdapterFsm) {
- oFsm.chReceiveAbortEndSwDlResponse <- true
- }(oFsm.PAdaptFsm)
- return
- }
- msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeEndSoftwareDownloadResponse)
- if msgLayer == nil {
- logger.Errorw(ctx, "Omci Msg layer could not be detected for EndSwDlResponse",
- log.Fields{"device-id": oFsm.deviceID})
- oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
- return
- }
- msgObj, msgOk := msgLayer.(*omci.EndSoftwareDownloadResponse)
- if !msgOk {
- logger.Errorw(ctx, "Omci Msg layer could not be assigned for EndSwDlResponse",
- log.Fields{"device-id": oFsm.deviceID})
- oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
- return
- }
- logger.Debugw(ctx, "OnuUpgradeFsm EndSwDlResponse data", log.Fields{
- "device-id": oFsm.deviceID, "data-fields": msgObj})
- if msgObj.Result != me.Success {
- if msgObj.Result == me.DeviceBusy {
- //ONU indicates it is still processing the image - let the FSM just wait and then repeat the request
- logger.Debugw(ctx, "OnuUpgradeFsm EndSwDlResponse busy: waiting before sending new request", log.Fields{
- "device-id": oFsm.deviceID})
- return
- }
- logger.Errorw(ctx, "OnuUpgradeFsm EndSwDlResponse result error - later: drive FSM to abort state ?",
- log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
- oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
- return
- }
- oFsm.mutexUpgradeParams.Lock()
- if msgObj.EntityInstance == oFsm.InactiveImageMeID {
- //EndSwDownloadSuccess is used to indicate 'DOWNLOAD_SUCCEEDED'
- oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_SUCCEEDED
- if !oFsm.useAPIVersion43 {
- //in the older API version the image version check was not possible
- // - assume new loaded image as valid-inactive immediately
- oFsm.volthaImageState = voltha.ImageState_IMAGE_INACTIVE
- oFsm.mutexUpgradeParams.Unlock()
- //use non-blocking channel (to be independent from receiver state)
- select {
- //use non-blocking channel to indicate that the download to ONU was successful
- case oFsm.chOnuDlReady <- true:
- default:
- }
- } else {
- oFsm.mutexUpgradeParams.Unlock()
- }
- logger.Debugw(ctx, "Expected EndSwDlResponse received", log.Fields{"device-id": oFsm.deviceID})
- //use non-blocking channel to let the FSM proceed from the waitState
- select {
- case oFsm.chReceiveExpectedResponse <- true:
- default:
- }
- return
- }
- oFsm.mutexUpgradeParams.Unlock()
- logger.Errorw(ctx, "OnuUpgradeFsm StartSwDlResponse wrong ME instance: try again (later)?",
- log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
- oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
+ oFsm.handleRxEndSwDownloadResponse(ctx, msg)
return
} //EndSoftwareDownloadResponseType
case omci.ActivateSoftwareResponseType:
@@ -1356,14 +1241,14 @@
if msgLayer == nil {
logger.Errorw(ctx, "Omci Msg layer could not be detected for ActivateSw",
log.Fields{"device-id": oFsm.deviceID})
- oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_ACTIVATION_ABORTED)
+ oFsm.abortOnOmciError(ctx, false)
return
}
msgObj, msgOk := msgLayer.(*omci.ActivateSoftwareResponse)
if !msgOk {
logger.Errorw(ctx, "Omci Msg layer could not be assigned for ActivateSw",
log.Fields{"device-id": oFsm.deviceID})
- oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_ACTIVATION_ABORTED)
+ oFsm.abortOnOmciError(ctx, false)
return
}
logger.Debugw(ctx, "OnuUpgradeFsm ActivateSwResponse data", log.Fields{
@@ -1371,7 +1256,7 @@
if msgObj.Result != me.Success {
logger.Errorw(ctx, "OnuUpgradeFsm ActivateSwResponse result error - later: drive FSM to abort state ?",
log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
- oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_ACTIVATION_ABORTED)
+ oFsm.abortOnOmciError(ctx, false)
return
}
oFsm.mutexUpgradeParams.Lock()
@@ -1390,7 +1275,7 @@
oFsm.mutexUpgradeParams.Unlock()
logger.Errorw(ctx, "OnuUpgradeFsm ActivateSwResponse wrong ME instance: abort",
log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
- oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_ACTIVATION_ABORTED)
+ oFsm.abortOnOmciError(ctx, false)
return
} //ActivateSoftwareResponseType
case omci.CommitSoftwareResponseType:
@@ -1399,20 +1284,20 @@
if msgLayer == nil {
logger.Errorw(ctx, "Omci Msg layer could not be detected for CommitResponse",
log.Fields{"device-id": oFsm.deviceID})
- oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_COMMIT_ABORTED)
+ oFsm.abortOnOmciError(ctx, false)
return
}
msgObj, msgOk := msgLayer.(*omci.CommitSoftwareResponse)
if !msgOk {
logger.Errorw(ctx, "Omci Msg layer could not be assigned for CommitResponse",
log.Fields{"device-id": oFsm.deviceID})
- oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_COMMIT_ABORTED)
+ oFsm.abortOnOmciError(ctx, false)
return
}
if msgObj.Result != me.Success {
logger.Errorw(ctx, "OnuUpgradeFsm SwImage CommitResponse result error - later: drive FSM to abort state ?",
log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
- oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_COMMIT_ABORTED)
+ oFsm.abortOnOmciError(ctx, false)
return
}
oFsm.mutexUpgradeParams.RLock()
@@ -1426,167 +1311,12 @@
oFsm.mutexUpgradeParams.RUnlock()
logger.Errorw(ctx, "OnuUpgradeFsm SwImage CommitResponse wrong ME instance: abort",
log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
- oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_COMMIT_ABORTED)
+ oFsm.abortOnOmciError(ctx, false)
return
} //CommitSoftwareResponseType
case omci.GetResponseType:
{
- msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeGetResponse)
- if msgLayer == nil {
- logger.Errorw(ctx, "Omci Msg layer could not be detected for SwImage GetResponse",
- log.Fields{"device-id": oFsm.deviceID})
- oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_COMMIT_ABORTED)
- return
- }
- msgObj, msgOk := msgLayer.(*omci.GetResponse)
- if !msgOk {
- logger.Errorw(ctx, "Omci Msg layer could not be assigned for SwImage GetResponse",
- log.Fields{"device-id": oFsm.deviceID})
- oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_COMMIT_ABORTED)
- return
- }
- logger.Debugw(ctx, "OnuUpgradeFsm SwImage GetResponse data", log.Fields{
- "device-id": oFsm.deviceID, "data-fields": msgObj})
- if msgObj.EntityClass == oFsm.pLastTxMeInstance.GetClassID() &&
- msgObj.EntityInstance == oFsm.pLastTxMeInstance.GetEntityID() {
- if msgObj.Result != me.Success {
- logger.Errorw(ctx, "OnuUpgradeFsm SwImage GetResponse result error - later: drive FSM to abort state ?",
- log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
- oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_COMMIT_ABORTED)
- return
- }
- } else {
- logger.Warnw(ctx, "OnuUpgradeFsm SwImage unexpected Entity GetResponse data - ignore",
- log.Fields{"device-id": oFsm.deviceID})
- return
- }
-
- meAttributes := msgObj.Attributes
- imageIsCommitted := meAttributes["IsCommitted"].(uint8)
- imageIsActive := meAttributes["IsActive"].(uint8)
- imageVersion := cmn.TrimStringFromMeOctet(meAttributes["Version"])
- logger.Debugw(ctx, "OnuUpgradeFsm - GetResponse Data for SoftwareImage",
- log.Fields{"device-id": oFsm.deviceID, "entityID": msgObj.EntityInstance,
- "version": imageVersion, "isActive": imageIsActive, "isCommitted": imageIsCommitted})
-
- if oFsm.PAdaptFsm.PFsm.Current() == UpgradeStCheckImageName {
- //image name check after EndSwDownload, this state (and block) can only be taken if APIVersion43 is used
- oFsm.mutexUpgradeParams.Lock()
- if msgObj.EntityInstance == oFsm.InactiveImageMeID && imageIsActive == cmn.SwIsInactive &&
- imageIsCommitted == cmn.SwIsUncommitted {
- if imageVersion != oFsm.imageVersion {
- //new stored inactive version indicated on OMCI from ONU is not the expected version
- logger.Errorw(ctx, "OnuUpgradeFsm SwImage GetResponse version indication not matching requested upgrade",
- log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance,
- "onu-version": imageVersion, "expected-version": oFsm.imageVersion})
- oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED //not the expected image was downloaded
- oFsm.volthaDownloadReason = voltha.ImageState_CANCELLED_ON_ONU_STATE //something like 'UNEXPECTED_VERSION' would be better - proto def
- oFsm.volthaImageState = voltha.ImageState_IMAGE_UNKNOWN //something like 'DOWNLOADED' would be better - proto def
- oFsm.mutexUpgradeParams.Unlock()
- //stop the running ONU download timer
- //use non-blocking channel (to be independent from receiver state)
- select {
- //use channel to indicate that the download response waiting shall be aborted for this device (channel)
- case oFsm.chOnuDlReady <- false:
- default:
- }
- // TODO!!!: error treatment?
- //TODO!!!: possibly send event information for aborted upgrade (aborted by wrong version)?
- _ = oFsm.PAdaptFsm.PFsm.Event(UpgradeEvAbort)
- return
- }
- //with APIVersion43 this is the point to consider the newly loaded image as valid (and inactive)
- oFsm.volthaImageState = voltha.ImageState_IMAGE_INACTIVE
- //store the new inactive version to onuSwImageIndications (to keep them in sync)
- oFsm.pDevEntry.ModifySwImageInactiveVersion(ctx, oFsm.imageVersion)
- //proceed within upgrade FSM
- if oFsm.activateImage {
- //immediate activation requested
- oFsm.mutexUpgradeParams.Unlock()
- logger.Debugw(ctx, "OnuUpgradeFsm - expected ONU image version indicated by the ONU, continue with activation",
- log.Fields{"device-id": oFsm.deviceID})
- _ = oFsm.PAdaptFsm.PFsm.Event(UpgradeEvRequestActivate)
- } else {
- //have to wait on explicit activation request
- // but a previously requested download activity (without activation) was successful here
- oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_SUCCEEDED
- oFsm.mutexUpgradeParams.Unlock()
- logger.Infow(ctx, "OnuUpgradeFsm - expected ONU image version indicated by the ONU, wait for activate request",
- log.Fields{"device-id": oFsm.deviceID})
- _ = oFsm.PAdaptFsm.PFsm.Event(UpgradeEvWaitForActivate)
- }
- //use non-blocking channel (to be independent from receiver state)
- select {
- //use non-blocking channel to indicate that the download to ONU was successful
- case oFsm.chOnuDlReady <- true:
- default:
- }
- return
- }
- //not the expected image/image state
- oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
- oFsm.volthaDownloadReason = voltha.ImageState_CANCELLED_ON_ONU_STATE
- oFsm.volthaImageState = voltha.ImageState_IMAGE_UNKNOWN //real image state not known
- oFsm.mutexUpgradeParams.Unlock()
- logger.Errorw(ctx, "OnuUpgradeFsm SwImage GetResponse indications not matching requested upgrade",
- log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
- // TODO!!!: error treatment?
- //TODO!!!: possibly send event information for aborted upgrade (aborted by ONU state indication)?
- _ = oFsm.PAdaptFsm.PFsm.Event(UpgradeEvAbort)
- return
- }
-
- //assumed only relevant state here is UpgradeStCheckCommitted
- oFsm.mutexUpgradeParams.Lock()
- oFsm.conditionalCancelRequested = false //getting here any set (conditional) cancelRequest is not relevant anymore
- if msgObj.EntityInstance == oFsm.InactiveImageMeID && imageIsActive == cmn.SwIsActive {
- //a check on the delivered image version is not done, the ONU delivered version might be different from what might have been
- // indicated in the download image version string (version must be part of the image content itself)
- // so checking that might be quite unreliable
- //but with new API this was changed, assumption is that omci image version is known at download request and exactly that is used
- // in all the API references, so it can and should be checked here now
- if oFsm.useAPIVersion43 {
- if imageVersion != oFsm.imageVersion {
- //new active version indicated on OMCI from ONU is not the expected version
- logger.Errorw(ctx, "OnuUpgradeFsm image-version not matching the requested upgrade",
- log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance,
- "onu-version": imageVersion, "expected-version": oFsm.imageVersion})
- // TODO!!!: error treatment?
- //TODO!!!: possibly send event information for aborted upgrade (aborted by wrong version)?
- oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED //not the expected image was committed
- oFsm.volthaDownloadReason = voltha.ImageState_CANCELLED_ON_ONU_STATE //something like 'UNEXPECTED_VERSION' would be better - proto def
- oFsm.volthaImageState = voltha.ImageState_IMAGE_UNKNOWN //expected image not known
- oFsm.mutexUpgradeParams.Unlock()
- _ = oFsm.PAdaptFsm.PFsm.Event(UpgradeEvAbort)
- return
- }
- logger.Debugw(ctx, "OnuUpgradeFsm - expected ONU image version indicated by the ONU",
- log.Fields{"device-id": oFsm.deviceID})
- }
- if imageIsCommitted == cmn.SwIsCommitted {
- oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_SUCCEEDED
- oFsm.volthaImageState = voltha.ImageState_IMAGE_COMMITTED
- //store the new commit flag to onuSwImageIndications (to keep them in sync)
- oFsm.pDevEntry.ModifySwImageActiveCommit(ctx, imageIsCommitted)
- logger.Infow(ctx, "requested SW image committed, releasing OnuUpgrade", log.Fields{"device-id": oFsm.deviceID})
- //deviceProcStatusUpdate not used anymore,
- // replaced by transferring the last (more) upgrade state information within RemoveOnuUpgradeFsm
- oFsm.mutexUpgradeParams.Unlock()
- //releasing the upgrade FSM on success
- _ = oFsm.PAdaptFsm.PFsm.Event(UpgradeEvAbort)
- return
- }
- //if not committed, abort upgrade as failed. There is no implementation here that would trigger this test again
- }
- oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
- oFsm.volthaDownloadReason = voltha.ImageState_CANCELLED_ON_ONU_STATE
- oFsm.volthaImageState = voltha.ImageState_IMAGE_COMMIT_ABORTED
- oFsm.mutexUpgradeParams.Unlock()
- logger.Errorw(ctx, "OnuUpgradeFsm SwImage GetResponse indications not matching requested upgrade",
- log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
- // TODO!!!: error treatment?
- //TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
- _ = oFsm.PAdaptFsm.PFsm.Event(UpgradeEvAbort)
+ oFsm.handleRxSwGetResponse(ctx, msg)
return
} //GetResponseType
default:
@@ -1598,17 +1328,379 @@
}
}
-//abortOnOmciError aborts the upgrade processing with OMCI_TRANSFER_ERROR indication
-func (oFsm *OnuUpgradeFsm) abortOnOmciError(ctx context.Context, aAsync bool,
- aImageState voltha.ImageState_ImageActivationState) {
+func (oFsm *OnuUpgradeFsm) handleRxStartSwDownloadResponse(ctx context.Context, msg cmn.OmciMessage) {
+ msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeStartSoftwareDownloadResponse)
+ if msgLayer == nil {
+ logger.Errorw(ctx, "Omci Msg layer could not be detected for StartSwDlResponse",
+ log.Fields{"device-id": oFsm.deviceID})
+ oFsm.abortOnOmciError(ctx, false)
+ return
+ }
+ msgObj, msgOk := msgLayer.(*omci.StartSoftwareDownloadResponse)
+ if !msgOk {
+ logger.Errorw(ctx, "Omci Msg layer could not be assigned for StartSwDlResponse",
+ log.Fields{"device-id": oFsm.deviceID})
+ oFsm.abortOnOmciError(ctx, false)
+ return
+ }
+ logger.Debugw(ctx, "OnuUpgradeFsm StartSwDlResponse data", log.Fields{
+ "device-id": oFsm.deviceID, "data-fields": msgObj})
+ if msgObj.Result != me.Success {
+ logger.Errorw(ctx, "OnuUpgradeFsm StartSwDlResponse result error - later: drive FSM to abort state ?",
+ log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
+ oFsm.abortOnOmciError(ctx, false)
+ return
+ }
+
+ oFsm.mutexUpgradeParams.Lock()
+ if msgObj.EntityInstance == oFsm.InactiveImageMeID {
+ logger.Debugw(ctx, "Expected StartSwDlResponse received", log.Fields{"device-id": oFsm.deviceID})
+ if msgObj.WindowSize != oFsm.omciDownloadWindowSizeLimit {
+ // also response WindowSize = 0 is a valid number for used Window size 1
+ logger.Debugw(ctx, "different StartSwDlResponse window size requested by ONU", log.Fields{
+ "acceptedOnuWindowSizeLimit": msgObj.WindowSize, "device-id": oFsm.deviceID})
+ oFsm.omciDownloadWindowSizeLimit = msgObj.WindowSize
+ }
+ oFsm.noOfWindows = oFsm.noOfSections / uint32(oFsm.omciDownloadWindowSizeLimit+1)
+ if oFsm.noOfSections%uint32(oFsm.omciDownloadWindowSizeLimit+1) > 0 {
+ oFsm.noOfWindows++
+ }
+ logger.Debugw(ctx, "OnuUpgradeFsm will use", log.Fields{
+ "windows": oFsm.noOfWindows, "sections": oFsm.noOfSections,
+ "at WindowSizeLimit": oFsm.omciDownloadWindowSizeLimit})
+ oFsm.nextDownloadSectionsAbsolute = 0
+ oFsm.nextDownloadSectionsWindow = 0
+ oFsm.nextDownloadWindow = 0
+
+ oFsm.mutexUpgradeParams.Unlock()
+ _ = oFsm.PAdaptFsm.PFsm.Event(UpgradeEvRxStartSwDownload)
+ return
+ }
+ oFsm.mutexUpgradeParams.Unlock()
+ logger.Errorw(ctx, "OnuUpgradeFsm StartSwDlResponse wrong ME instance: try again (later)?",
+ log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
+ oFsm.abortOnOmciError(ctx, false)
+} //handleRxStartSwDownloadResponse
+
+func (oFsm *OnuUpgradeFsm) handleRxSwSectionResponse(ctx context.Context, msg cmn.OmciMessage) {
+ msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeDownloadSectionResponse)
+ if msgLayer == nil {
+ logger.Errorw(ctx, "Omci Msg layer could not be detected for DlSectionResponse",
+ log.Fields{"device-id": oFsm.deviceID, "omci-message": msg.OmciMsg})
+ oFsm.abortOnOmciError(ctx, false)
+ return
+ }
+ msgObj, msgOk := msgLayer.(*omci.DownloadSectionResponse)
+ if !msgOk {
+ logger.Errorw(ctx, "Omci Msg layer could not be assigned for DlSectionResponse",
+ log.Fields{"device-id": oFsm.deviceID})
+ oFsm.abortOnOmciError(ctx, false)
+ return
+ }
+ logger.Debugw(ctx, "OnuUpgradeFsm DlSectionResponse Data", log.Fields{
+ "device-id": oFsm.deviceID, "data-fields": msgObj})
+ if msgObj.Result != me.Success {
+ logger.Errorw(ctx, "OnuUpgradeFsm DlSectionResponse result error - later: repeat window once?", //TODO!!!
+ log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
+ oFsm.abortOnOmciError(ctx, false)
+ return
+ }
+ oFsm.mutexUpgradeParams.Lock()
+ if msgObj.EntityInstance == oFsm.InactiveImageMeID {
+ sectionNumber := msgObj.SectionNumber
+ logger.Infow(ctx, "DlSectionResponse received", log.Fields{
+ "window section-number": sectionNumber, "window": oFsm.nextDownloadWindow, "device-id": oFsm.deviceID})
+
+ oFsm.nextDownloadWindow++
+ if oFsm.nextDownloadWindow >= oFsm.noOfWindows {
+ if sectionNumber != oFsm.omciDownloadWindowSizeLast {
+ logger.Errorw(ctx, "OnuUpgradeFsm DlSectionResponse section error last window - later: repeat window once?", //TODO!!!
+ log.Fields{"device-id": oFsm.deviceID, "actual section": sectionNumber,
+ "expected section": oFsm.omciDownloadWindowSizeLast})
+ oFsm.mutexUpgradeParams.Unlock()
+ oFsm.abortOnOmciError(ctx, false)
+ return
+ }
+ oFsm.delayEndSwDl = true //ensure a delay for the EndSwDl message
+ //CRC computation for all data bytes of the file
+ imageCRC := crc32a.Checksum(oFsm.imageBuffer[:int(oFsm.origImageLength)]) //store internal for multiple usage
+ //revert the retrieved CRC Byte Order (seems not to deliver NetworkByteOrder)
+ var byteSlice []byte = make([]byte, 4)
+ binary.LittleEndian.PutUint32(byteSlice, uint32(imageCRC))
+ oFsm.imageCRC = binary.BigEndian.Uint32(byteSlice)
+ oFsm.mutexUpgradeParams.Unlock()
+ _ = oFsm.PAdaptFsm.PFsm.Event(UpgradeEvEndSwDownload)
+ return
+ }
+ if sectionNumber != oFsm.omciDownloadWindowSizeLimit {
+ logger.Errorw(ctx, "OnuUpgradeFsm DlSectionResponse section error - later: repeat window once?", //TODO!!!
+ log.Fields{"device-id": oFsm.deviceID, "actual-section": sectionNumber,
+ "expected section": oFsm.omciDownloadWindowSizeLimit})
+ oFsm.mutexUpgradeParams.Unlock()
+ oFsm.abortOnOmciError(ctx, false)
+ return
+ }
+ oFsm.nextDownloadSectionsWindow = 0
+ oFsm.mutexUpgradeParams.Unlock()
+ _ = oFsm.PAdaptFsm.PFsm.Event(UpgradeEvContinueNextWindow)
+ return
+ }
+ oFsm.mutexUpgradeParams.Unlock()
+ logger.Errorw(ctx, "OnuUpgradeFsm Omci StartSwDlResponse wrong ME instance: try again (later)?",
+ log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
+ oFsm.abortOnOmciError(ctx, false)
+} //handleRxSwSectionResponse
+
+func (oFsm *OnuUpgradeFsm) handleRxEndSwDownloadResponse(ctx context.Context, msg cmn.OmciMessage) {
+ inAbortingState := oFsm.PAdaptFsm.PFsm.Is(UpgradeStAbortingDL)
+
+ msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeEndSoftwareDownloadResponse)
+ if msgLayer == nil {
+ logger.Errorw(ctx, "Omci Msg layer could not be detected for EndSwDlResponse",
+ log.Fields{"device-id": oFsm.deviceID})
+ if !inAbortingState {
+ oFsm.abortOnOmciError(ctx, false)
+ } //else using error log and wait for another response or 'aborting' state timeout
+ return
+ }
+ msgObj, msgOk := msgLayer.(*omci.EndSoftwareDownloadResponse)
+ if !msgOk {
+ logger.Errorw(ctx, "Omci Msg layer could not be assigned for EndSwDlResponse",
+ log.Fields{"device-id": oFsm.deviceID})
+ if !inAbortingState {
+ oFsm.abortOnOmciError(ctx, false)
+ } //else using error log and wait for another response or 'aborting' state timeout
+ return
+ }
+ logger.Debugw(ctx, "OnuUpgradeFsm EndSwDlResponse data", log.Fields{
+ "device-id": oFsm.deviceID, "data-fields": msgObj})
+ if msgObj.Result != me.Success {
+ if msgObj.Result == me.DeviceBusy {
+ //ONU indicates it is still processing the image - let the FSM just wait and then repeat the request
+ logger.Debugw(ctx, "OnuUpgradeFsm EndSwDlResponse busy: waiting before sending new request", log.Fields{
+ "device-id": oFsm.deviceID})
+ if inAbortingState {
+ //if the EndSwDl was requested from state AbortingDL then use channel to indicate ONU busy/repeat indication
+ oFsm.chReceiveAbortEndSwDlResponse <- cEndSwDlResponseBusy //repeat abort request
+ }
+ oFsm.mutexUpgradeParams.Lock()
+ oFsm.downloadReasonCached = oFsm.volthaDownloadReason //copy for later reconstruction
+ oFsm.volthaDownloadReason = voltha.ImageState_DEVICE_BUSY
+ oFsm.mutexUpgradeParams.Unlock()
+ return
+ }
+ logger.Errorw(ctx, "OnuUpgradeFsm EndSwDlResponse result error - later: drive FSM to abort state ?",
+ log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
+ if inAbortingState {
+ //if the EndSwDl was requested from state AbortingDL and response is error indication
+ // that would be quite strange ONU behavior, no resolution from OnuAdapter, just let the FSM go on to disabled
+ oFsm.chReceiveAbortEndSwDlResponse <- cEndSwDlResponseAbort //error indication to abort waiting on EndDownloadResponse
+ } //else using error log and wait for another response or 'aborting' state timeout
+ return
+ }
+ oFsm.mutexUpgradeParams.Lock()
+ if msgObj.EntityInstance == oFsm.InactiveImageMeID {
+ logger.Debugw(ctx, "Expected EndSwDlResponse received", log.Fields{"device-id": oFsm.deviceID})
+ if oFsm.volthaDownloadReason == voltha.ImageState_DEVICE_BUSY { //was temporary on busy
+ oFsm.volthaDownloadReason = oFsm.downloadReasonCached //recapture from mirror
+ }
+ if inAbortingState {
+ oFsm.mutexUpgradeParams.Unlock()
+ //if the EndSwDl was requested from state AbortingDL then use channel to indicate abort acceptance
+ oFsm.chReceiveAbortEndSwDlResponse <- cEndSwDlResponseSuccess //success
+ return
+ }
+ if !oFsm.useAPIVersion43 {
+ //in the older API version the image version check was not possible
+ // - assume new loaded image as valid-inactive immediately
+ oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_SUCCEEDED
+ oFsm.volthaImageState = voltha.ImageState_IMAGE_INACTIVE
+ oFsm.mutexUpgradeParams.Unlock()
+ //use non-blocking channel (to be independent from receiver state)
+ select {
+ //use non-blocking channel to indicate that the download to ONU was successful
+ case oFsm.chOnuDlReady <- true:
+ default:
+ }
+ } else {
+ oFsm.mutexUpgradeParams.Unlock()
+ }
+ //use asynchronous channel sending to let the FSM proceed
+ select {
+ case oFsm.chReceiveExpectedResponse <- true:
+ default:
+ }
+ return
+ }
+ oFsm.mutexUpgradeParams.Unlock()
+ logger.Errorw(ctx, "OnuUpgradeFsm StartSwDlResponse wrong ME instance: ignoring",
+ log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
+ // no state abort in case of unexpected ImageId, just keep waiting for the correct one
+} //handleRxEndSwDownloadResponse
+
+func (oFsm *OnuUpgradeFsm) handleRxSwGetResponse(ctx context.Context, msg cmn.OmciMessage) {
+ msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeGetResponse)
+ if msgLayer == nil {
+ logger.Errorw(ctx, "Omci Msg layer could not be detected for SwImage GetResponse",
+ log.Fields{"device-id": oFsm.deviceID})
+ oFsm.abortOnOmciError(ctx, false)
+ return
+ }
+ msgObj, msgOk := msgLayer.(*omci.GetResponse)
+ if !msgOk {
+ logger.Errorw(ctx, "Omci Msg layer could not be assigned for SwImage GetResponse",
+ log.Fields{"device-id": oFsm.deviceID})
+ oFsm.abortOnOmciError(ctx, false)
+ return
+ }
+ logger.Debugw(ctx, "OnuUpgradeFsm SwImage GetResponse data", log.Fields{
+ "device-id": oFsm.deviceID, "data-fields": msgObj})
+ if msgObj.EntityClass == oFsm.pLastTxMeInstance.GetClassID() &&
+ msgObj.EntityInstance == oFsm.pLastTxMeInstance.GetEntityID() {
+ if msgObj.Result != me.Success {
+ logger.Errorw(ctx, "OnuUpgradeFsm SwImage GetResponse result error - later: drive FSM to abort state ?",
+ log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
+ oFsm.abortOnOmciError(ctx, false)
+ return
+ }
+ } else {
+ logger.Warnw(ctx, "OnuUpgradeFsm SwImage unexpected Entity GetResponse data - ignore",
+ log.Fields{"device-id": oFsm.deviceID})
+ return
+ }
+
+ meAttributes := msgObj.Attributes
+ imageIsCommitted := meAttributes["IsCommitted"].(uint8)
+ imageIsActive := meAttributes["IsActive"].(uint8)
+ imageVersion := cmn.TrimStringFromMeOctet(meAttributes["Version"])
+ logger.Debugw(ctx, "OnuUpgradeFsm - GetResponse Data for SoftwareImage",
+ log.Fields{"device-id": oFsm.deviceID, "entityID": msgObj.EntityInstance,
+ "version": imageVersion, "isActive": imageIsActive, "isCommitted": imageIsCommitted})
+
+ if oFsm.PAdaptFsm.PFsm.Current() == UpgradeStCheckImageName {
+ //image name check after EndSwDownload, this state (and block) can only be taken if APIVersion43 is used
+ oFsm.verifyOnuSwStatusAfterDownload(ctx, msgObj.EntityInstance, imageVersion, imageIsActive, imageIsCommitted)
+ return
+ }
+
+ //assumed only relevant state here is upgradeStCheckCommitted
+ oFsm.mutexUpgradeParams.Lock()
+ oFsm.conditionalCancelRequested = false //getting here any set (conditional) cancelRequest is not relevant anymore
+ if msgObj.EntityInstance == oFsm.InactiveImageMeID && imageIsActive == cmn.SwIsActive {
+ //a check on the delivered image version is not done, the ONU delivered version might be different from what might have been
+ // indicated in the download image version string (version must be part of the image content itself)
+ // so checking that might be quite unreliable
+ //but with new API this was changed, assumption is that omci image version is known at download request and exactly that is used
+ // in all the API references, so it can and should be checked here now
+ if oFsm.useAPIVersion43 {
+ if imageVersion != oFsm.imageVersion {
+ //new active version indicated on OMCI from ONU is not the expected version
+ logger.Errorw(ctx, "OnuUpgradeFsm image-version not matching the requested upgrade",
+ log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance,
+ "onu-version": imageVersion, "expected-version": oFsm.imageVersion})
+ // TODO!!!: error treatment?
+ //TODO!!!: possibly send event information for aborted upgrade (aborted by wrong version)?
+ oFsm.volthaDownloadReason = voltha.ImageState_CANCELLED_ON_ONU_STATE //something like 'UNEXPECTED_VERSION' would be better - proto def
+ oFsm.mutexUpgradeParams.Unlock()
+ _ = oFsm.PAdaptFsm.PFsm.Event(UpgradeEvAbort)
+ return
+ }
+ logger.Debugw(ctx, "OnuUpgradeFsm - expected ONU image version indicated by the ONU",
+ log.Fields{"device-id": oFsm.deviceID})
+ }
+ if imageIsCommitted == cmn.SwIsCommitted {
+ oFsm.upgradePhase = cUpgradeCommitted
+ oFsm.volthaImageState = voltha.ImageState_IMAGE_COMMITTED
+ //store the new commit flag to onuSwImageIndications (to keep them in sync)
+ oFsm.pDevEntry.ModifySwImageActiveCommit(ctx, imageIsCommitted)
+ logger.Infow(ctx, "requested SW image committed, releasing OnuUpgrade", log.Fields{"device-id": oFsm.deviceID})
+ //deviceProcStatusUpdate not used anymore,
+ // replaced by transferring the last (more) upgrade state information within removeOnuUpgradeFsm
+ oFsm.mutexUpgradeParams.Unlock()
+ //releasing the upgrade FSM on success
+ _ = oFsm.PAdaptFsm.PFsm.Event(UpgradeEvAbort)
+ return
+ }
+ //if not committed, abort upgrade as failed. There is no implementation here that would trigger this test again
+ }
+ oFsm.volthaDownloadReason = voltha.ImageState_CANCELLED_ON_ONU_STATE
+ oFsm.mutexUpgradeParams.Unlock()
+ logger.Errorw(ctx, "OnuUpgradeFsm SwImage GetResponse indications not matching requested upgrade",
+ log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
+ // TODO!!!: error treatment?
+ //TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
+ _ = oFsm.PAdaptFsm.PFsm.Event(UpgradeEvAbort)
+} //handleRxSwGetResponse
+
+func (oFsm *OnuUpgradeFsm) verifyOnuSwStatusAfterDownload(ctx context.Context, aInstanceID uint16,
+ aImageVersion string, aImageIsActive uint8, aImageIsCommitted uint8) {
+ oFsm.mutexUpgradeParams.Lock()
+ if aInstanceID == oFsm.InactiveImageMeID && aImageIsActive == cmn.SwIsInactive &&
+ aImageIsCommitted == cmn.SwIsUncommitted {
+ if aImageVersion != oFsm.imageVersion {
+ //new stored inactive version indicated on OMCI from ONU is not the expected version
+ logger.Errorw(ctx, "OnuUpgradeFsm SwImage GetResponse version indication not matching requested upgrade",
+ log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": aInstanceID,
+ "onu-version": aImageVersion, "expected-version": oFsm.imageVersion})
+ //download state is set when entering the reset state
+ oFsm.volthaDownloadReason = voltha.ImageState_CANCELLED_ON_ONU_STATE //something like 'UNEXPECTED_VERSION' would be better - proto def
+ oFsm.mutexUpgradeParams.Unlock()
+ //stop the running ONU download timer
+ //use non-blocking channel (to be independent from receiver state)
+ select {
+ //use channel to indicate that the download response waiting shall be aborted for this device (channel)
+ case oFsm.chOnuDlReady <- false:
+ default:
+ }
+ // TODO!!!: error treatment?
+ //TODO!!!: possibly send event information for aborted upgrade (aborted by wrong version)?
+ _ = oFsm.PAdaptFsm.PFsm.Event(UpgradeEvAbort)
+ return
+ }
+ //with APIVersion43 this is the point to consider the newly loaded image as valid (and inactive)
+ oFsm.upgradePhase = cUpgradeDownloaded
+ oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_SUCCEEDED
+ oFsm.volthaImageState = voltha.ImageState_IMAGE_INACTIVE
+ //store the new inactive version to onuSwImageIndications (to keep them in sync)
+ oFsm.pDevEntry.ModifySwImageInactiveVersion(ctx, oFsm.imageVersion)
+ //proceed within upgrade FSM
+ if oFsm.activateImage {
+ //immediate activation requested
+ oFsm.mutexUpgradeParams.Unlock()
+ logger.Debugw(ctx, "OnuUpgradeFsm - expected ONU image version indicated by the ONU, continue with activation",
+ log.Fields{"device-id": oFsm.deviceID})
+ _ = oFsm.PAdaptFsm.PFsm.Event(UpgradeEvRequestActivate)
+ } else {
+ //have to wait on explicit activation request
+ oFsm.mutexUpgradeParams.Unlock()
+ logger.Infow(ctx, "OnuUpgradeFsm - expected ONU image version indicated by the ONU, wait for activate request",
+ log.Fields{"device-id": oFsm.deviceID})
+ _ = oFsm.PAdaptFsm.PFsm.Event(UpgradeEvWaitForActivate)
+ }
+ //use non-blocking channel (to be independent from receiver state)
+ select {
+ //use non-blocking channel to indicate that the download to ONU was successful
+ case oFsm.chOnuDlReady <- true:
+ default:
+ }
+ return
+ }
+ //not the expected image/image state
+ oFsm.volthaDownloadReason = voltha.ImageState_CANCELLED_ON_ONU_STATE
+ oFsm.mutexUpgradeParams.Unlock()
+ logger.Errorw(ctx, "OnuUpgradeFsm SwImage GetResponse indications not matching requested upgrade",
+ log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": aInstanceID})
+ // TODO!!!: error treatment?
+ //TODO!!!: possibly send event information for aborted upgrade (aborted by ONU state indication)?
+ _ = oFsm.PAdaptFsm.PFsm.Event(UpgradeEvAbort)
+} //verifyOnuSwStatusAfterDownload
+
+//abortOnOmciError aborts the upgrade processing with evAbort
+// asynchronous/synchronous based on parameter aAsync
+func (oFsm *OnuUpgradeFsm) abortOnOmciError(ctx context.Context, aAsync bool) {
oFsm.mutexUpgradeParams.Lock()
oFsm.conditionalCancelRequested = false //any conditional cancelRequest is superseded by this abortion
- oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
oFsm.volthaDownloadReason = voltha.ImageState_OMCI_TRANSFER_ERROR
- if aImageState != voltha.ImageState_IMAGE_UNKNOWN {
- // update image state only in case some explicite state is given (otherwise the existing state is used)
- oFsm.volthaImageState = aImageState
- }
oFsm.mutexUpgradeParams.Unlock()
//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
if oFsm.PAdaptFsm != nil {
@@ -1654,10 +1746,8 @@
oFsm.isWaitingForAdapterDlResponse = false
oFsm.mutexIsAwaitingAdapterDlResponse.Unlock()
oFsm.mutexUpgradeParams.Lock()
- oFsm.conditionalCancelRequested = false //any conditional cancelRequest is superseded by this abortion
- oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
+ oFsm.conditionalCancelRequested = false //any conditional cancelRequest is superseded by this abortion
oFsm.volthaDownloadReason = voltha.ImageState_UNKNOWN_ERROR //something like 'DOWNLOAD_TO_ADAPTER_TIMEOUT' would be better (proto)
- oFsm.volthaImageState = voltha.ImageState_IMAGE_UNKNOWN //something like 'IMAGE_DOWNLOAD_ABORTED' would be better (proto)
oFsm.mutexUpgradeParams.Unlock()
//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
if oFsm.PAdaptFsm != nil && oFsm.PAdaptFsm.PFsm != nil {
@@ -1708,7 +1798,7 @@
logger.Warnw(ctx, "OnuUpgradeFsm Waiting-ONU-download timeout", log.Fields{
"for device-id": oFsm.deviceID, "image-id": oFsm.imageIdentifier, "timeout": downloadToOnuTimeout})
//the upgrade process has to be aborted
- oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_UNKNOWN) //no ImageState update
+ oFsm.abortOnOmciError(ctx, false)
return
case success := <-aWaitChannel:
@@ -1723,3 +1813,40 @@
return
}
}
+
+//stateUpdateOnReset writes the download and/or image state on entering the reset state according to FSM internal indications
+func (oFsm *OnuUpgradeFsm) stateUpdateOnReset(ctx context.Context) {
+ oFsm.mutexUpgradeParams.Lock()
+ defer oFsm.mutexUpgradeParams.Unlock()
+ if !oFsm.conditionalCancelRequested {
+ switch oFsm.upgradePhase {
+ case cUpgradeUndefined, cUpgradeDownloading: //coming from downloading
+ //make sure the download state is only changed in case the device has still been downloading
+ if oFsm.volthaDownloadReason == voltha.ImageState_CANCELLED_ON_REQUEST {
+ // indication for termination on request
+ oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_CANCELLED
+ } else if oFsm.volthaDownloadReason != voltha.ImageState_NO_ERROR {
+ // indication for termination on failure
+ oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
+ }
+ //reset the image state from Downloading in this case
+ oFsm.volthaImageState = voltha.ImageState_IMAGE_UNKNOWN //something like 'IMAGE_DOWNLOAD_ABORTED' would be better (proto)
+ //in all other upgrade phases the last set download state remains valid
+ case cUpgradeActivating:
+ //reset the image state from Activating in this case
+ oFsm.volthaImageState = voltha.ImageState_IMAGE_ACTIVATION_ABORTED
+ case cUpgradeCommitting: // indication for request to abort waiting for response
+ //reset the image state from Activating in this case
+ oFsm.volthaImageState = voltha.ImageState_IMAGE_COMMIT_ABORTED
+ //default: in all other upgrade phases keep the last set imageState
+ } //switch
+ } else {
+ //when reaching reset state with conditional cancel that can only result from ONU related problems
+ // (mostly ONU down indication) - derived from resetFsms call
+ // and it can only be related to the downloading-to-ONU phase (no need to check that additionally)
+ oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
+ oFsm.volthaDownloadReason = voltha.ImageState_CANCELLED_ON_ONU_STATE
+ //reset the image state from Downloading in this case
+ oFsm.volthaImageState = voltha.ImageState_IMAGE_UNKNOWN //something like 'IMAGE_DOWNLOAD_ABORTED' would be better (proto)
+ }
+}