blob: 7842717c58b8041714a992436c088bb4f2072d59 [file] [log] [blame]
mpagenko80622a52021-02-09 16:53:23 +00001/*
2 * Copyright 2020-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//Package adaptercoreonu provides the utility for onu devices, flows and statistics
18package adaptercoreonu
19
20import (
21 "context"
22 "fmt"
23 "strconv"
24 "time"
25
26 "github.com/boguslaw-wojcik/crc32a"
27 "github.com/looplab/fsm"
28 "github.com/opencord/omci-lib-go"
29 me "github.com/opencord/omci-lib-go/generated"
30 "github.com/opencord/voltha-lib-go/v4/pkg/log"
31 "github.com/opencord/voltha-protos/v4/go/voltha"
32)
33
34const cMaxUint32 = ^uint32(0)
35
36const (
37 // internal predefined values - some off them should later be configurable (perhaps with theses as defaults)
38 cOmciDownloadSectionSize = 31 //in bytes
39 cOmciDownloadWindowSizeLimit = 31 //in sections for window offset (windowSize(32)-1)
40 //cOmciDownloadWindowRetryMax = 2 // max attempts for a specific window
41 cOmciSectionInterleaveMilliseconds = 100 //DownloadSection interleave time in milliseconds
42 cOmciEndSwDlDelaySeconds = 1 //End Software Download delay after last section (may be also configurable?)
43 //cOmciDownloadCompleteTimeout = 5400 //in s for the complete timeout (may be better scale to image size/ noOfWindows)
44)
45
46const (
47 // events of config PON ANI port FSM
48 upgradeEvStart = "upgradeEvStart"
49 upgradeEvPrepareSwDownload = "upgradeEvPrepareSwDownload"
50 upgradeEvRxStartSwDownload = "upgradeEvRxStartSwDownload"
51 upgradeEvWaitWindowAck = "upgradeEvWaitWindowAck"
52 upgradeEvContinueNextWindow = "upgradeEvContinueNextWindow"
53 upgradeEvEndSwDownload = "upgradeEvEndSwDownload"
54 upgradeEvRequestActivate = "upgradeEvRequestActivate"
55 upgradeEvWaitForCommit = "upgradeEvWaitForCommit"
56 upgradeEvCommitSw = "upgradeEvCommitSw"
57
58 //upgradeEvTimeoutSimple = "upgradeEvTimeoutSimple"
59 //upgradeEvTimeoutMids = "upgradeEvTimeoutMids"
60 upgradeEvReset = "upgradeEvReset"
61 upgradeEvAbort = "upgradeEvAbort"
62 upgradeEvRestart = "upgradeEvRestart"
63)
64
65const (
66 // states of config PON ANI port FSM
67 upgradeStDisabled = "upgradeStDisabled"
68 upgradeStStarting = "upgradeStStarting"
69 upgradeStPreparingDL = "upgradeStPreparingDL"
70 upgradeStDLSection = "upgradeStDLSection"
71 upgradeStVerifyWindow = "upgradeStVerifyWindow"
72 upgradeStFinalizeDL = "upgradeStFinalizeDL"
73 upgradeStRequestingActivate = "upgradeStRequestingActivate"
74 upgradeStWaitForCommit = "upgradeStWaitForCommit"
75 upgradeStCommitSw = "upgradeStCommitSw"
76 upgradeStResetting = "upgradeStResetting"
77)
78
79//required definition for IdleState detection for activities on OMCI
80const cOnuUpgradeFsmIdleState = upgradeStWaitForCommit
81
82//OnuUpgradeFsm defines the structure for the state machine to config the PON ANI ports of ONU UNI ports via OMCI
83type OnuUpgradeFsm struct {
84 pDeviceHandler *deviceHandler
85 pDownloadManager *adapterDownloadManager
86 deviceID string
87 pOmciCC *omciCC
88 pOnuDB *onuDeviceDB
89 requestEvent OnuDeviceEvent
90 //omciMIdsResponseReceived chan bool //seperate channel needed for checking multiInstance OMCI message responses
91 pAdaptFsm *AdapterFsm
92 pImageDsc *voltha.ImageDownload
93 imageBuffer []byte
94 origImageLength uint32 //as also limited by OMCI
95 imageLength uint32 //including last bytes padding
96 omciDownloadWindowSizeLimit uint8 //windowSize-1
97 noOfSections uint32 //uint32 range for sections should be sufficient for very long images
98 nextDownloadSectionsAbsolute uint32 //number of next section to download in overall image
99 nextDownloadSectionsWindow uint8 //number of next section to download within current window
100 noOfWindows uint32 //uint32 range for windows should be sufficient for very long images
101 nextDownloadWindow uint32 //number of next window to download
102 inactiveImageMeID uint16 //ME-ID of the inactive image
103 omciSectionInterleaveMilliseconds time.Duration //DownloadSectionInterleave delay in milliseconds
104 delayEndSwDl bool //flag to provide a delay between last section and EndSwDl
105}
106
107//NewOnuUpgradeFsm is the 'constructor' for the state machine to config the PON ANI ports
108// of ONU UNI ports via OMCI
109func NewOnuUpgradeFsm(ctx context.Context, apDeviceHandler *deviceHandler,
110 apDevOmciCC *omciCC, apOnuDB *onuDeviceDB,
111 aRequestEvent OnuDeviceEvent, aName string, aCommChannel chan Message) *OnuUpgradeFsm {
112 instFsm := &OnuUpgradeFsm{
113 pDeviceHandler: apDeviceHandler,
114 deviceID: apDeviceHandler.deviceID,
115 pOmciCC: apDevOmciCC,
116 pOnuDB: apOnuDB,
117 requestEvent: aRequestEvent,
118 omciDownloadWindowSizeLimit: cOmciDownloadWindowSizeLimit,
119 omciSectionInterleaveMilliseconds: cOmciSectionInterleaveMilliseconds,
120 }
121
122 instFsm.pAdaptFsm = NewAdapterFsm(aName, instFsm.deviceID, aCommChannel)
123 if instFsm.pAdaptFsm == nil {
124 logger.Errorw(ctx, "OnuUpgradeFsm's AdapterFsm could not be instantiated!!", log.Fields{
125 "device-id": instFsm.deviceID})
126 return nil
127 }
128 instFsm.pAdaptFsm.pFsm = fsm.NewFSM(
129 upgradeStDisabled,
130 fsm.Events{
131 {Name: upgradeEvStart, Src: []string{upgradeStDisabled}, Dst: upgradeStStarting},
132 {Name: upgradeEvPrepareSwDownload, Src: []string{upgradeStStarting}, Dst: upgradeStPreparingDL},
133 {Name: upgradeEvRxStartSwDownload, Src: []string{upgradeStPreparingDL}, Dst: upgradeStDLSection},
134 {Name: upgradeEvWaitWindowAck, Src: []string{upgradeStDLSection}, Dst: upgradeStVerifyWindow},
135 {Name: upgradeEvContinueNextWindow, Src: []string{upgradeStVerifyWindow}, Dst: upgradeStDLSection},
136 {Name: upgradeEvEndSwDownload, Src: []string{upgradeStVerifyWindow}, Dst: upgradeStFinalizeDL},
137 {Name: upgradeEvRequestActivate, Src: []string{upgradeStFinalizeDL}, Dst: upgradeStRequestingActivate},
138 {Name: upgradeEvWaitForCommit, Src: []string{upgradeStRequestingActivate}, Dst: upgradeStWaitForCommit},
139 {Name: upgradeEvCommitSw, Src: []string{upgradeStStarting, upgradeStWaitForCommit},
140 Dst: upgradeStCommitSw},
141
142 /*
143 {Name: upgradeEvTimeoutSimple, Src: []string{
144 upgradeStCreatingDot1PMapper, upgradeStCreatingMBPCD, upgradeStSettingTconts, upgradeStSettingDot1PMapper}, Dst: upgradeStStarting},
145 {Name: upgradeEvTimeoutMids, Src: []string{
146 upgradeStCreatingGemNCTPs, upgradeStCreatingGemIWs, upgradeStSettingPQs}, Dst: upgradeStStarting},
147 */
148 // exceptional treatments
149 {Name: upgradeEvReset, Src: []string{upgradeStStarting, upgradeStPreparingDL, upgradeStDLSection,
150 upgradeStVerifyWindow, upgradeStDLSection, upgradeStFinalizeDL, upgradeStRequestingActivate,
151 upgradeStCommitSw}, //upgradeStWaitForCommit is not reset (later perhaps also not upgradeStWaitActivate)
152 Dst: upgradeStResetting},
153 {Name: upgradeEvAbort, Src: []string{upgradeStStarting, upgradeStPreparingDL, upgradeStDLSection,
154 upgradeStVerifyWindow, upgradeStDLSection, upgradeStFinalizeDL, upgradeStRequestingActivate,
155 upgradeStWaitForCommit, upgradeStCommitSw},
156 Dst: upgradeStResetting},
157 {Name: upgradeEvRestart, Src: []string{upgradeStResetting}, Dst: upgradeStDisabled},
158 },
159 fsm.Callbacks{
160 "enter_state": func(e *fsm.Event) { instFsm.pAdaptFsm.logFsmStateChange(ctx, e) },
161 "enter_" + upgradeStStarting: func(e *fsm.Event) { instFsm.enterStarting(ctx, e) },
162 "enter_" + upgradeStPreparingDL: func(e *fsm.Event) { instFsm.enterPreparingDL(ctx, e) },
163 "enter_" + upgradeStDLSection: func(e *fsm.Event) { instFsm.enterDownloadSection(ctx, e) },
164 "enter_" + upgradeStVerifyWindow: func(e *fsm.Event) { instFsm.enterVerifyWindow(ctx, e) },
165 "enter_" + upgradeStFinalizeDL: func(e *fsm.Event) { instFsm.enterFinalizeDL(ctx, e) },
166 "enter_" + upgradeStRequestingActivate: func(e *fsm.Event) { instFsm.enterActivateSw(ctx, e) },
167 "enter_" + upgradeStCommitSw: func(e *fsm.Event) { instFsm.enterCommitSw(ctx, e) },
168 "enter_" + upgradeStResetting: func(e *fsm.Event) { instFsm.enterResetting(ctx, e) },
169 "enter_" + upgradeStDisabled: func(e *fsm.Event) { instFsm.enterDisabled(ctx, e) },
170 },
171 )
172 if instFsm.pAdaptFsm.pFsm == nil {
173 logger.Errorw(ctx, "OnuUpgradeFsm's Base FSM could not be instantiated!!", log.Fields{
174 "device-id": instFsm.deviceID})
175 return nil
176 }
177
178 logger.Debugw(ctx, "OnuUpgradeFsm created", log.Fields{"device-id": instFsm.deviceID})
179 return instFsm
180}
181
182//SetDownloadParams configures the needed parameters for a specific download to the ONU
183func (oFsm *OnuUpgradeFsm) SetDownloadParams(ctx context.Context, apImageDsc *voltha.ImageDownload,
184 apDownloadManager *adapterDownloadManager) error {
185 pBaseFsm := oFsm.pAdaptFsm.pFsm
186 if pBaseFsm != nil && pBaseFsm.Is(upgradeStStarting) {
187 logger.Debugw(ctx, "OnuUpgradeFsm Parameter setting", log.Fields{
188 "device-id": oFsm.deviceID, "image-description": apImageDsc})
189 oFsm.pImageDsc = apImageDsc
190 oFsm.pDownloadManager = apDownloadManager
191
192 go func(aPBaseFsm *fsm.FSM) {
193 // let the upgrade FSm proceed to PreparinDL
194 _ = aPBaseFsm.Event(upgradeEvPrepareSwDownload)
195 }(pBaseFsm)
196 return nil
197 }
198 logger.Errorw(ctx, "OnuUpgradeFsm abort: invalid FSM base pointer or state", log.Fields{
199 "device-id": oFsm.deviceID})
200 return fmt.Errorf(fmt.Sprintf("OnuUpgradeFsm abort: invalid FSM base pointer or state for device-id: %s", oFsm.deviceID))
201}
202
203func (oFsm *OnuUpgradeFsm) enterStarting(ctx context.Context, e *fsm.Event) {
204 logger.Debugw(ctx, "OnuUpgradeFsm start", log.Fields{"in state": e.FSM.Current(),
205 "device-id": oFsm.deviceID})
206
207 // start go routine for processing of LockState messages
208 go oFsm.processOmciUpgradeMessages(ctx)
209}
210
211func (oFsm *OnuUpgradeFsm) enterPreparingDL(ctx context.Context, e *fsm.Event) {
212 logger.Debugw(ctx, "OnuUpgradeFsm prepare Download to Onu", log.Fields{"in state": e.FSM.Current(),
213 "device-id": oFsm.deviceID})
214
215 fileLen, err := oFsm.pDownloadManager.getImageBufferLen(ctx, oFsm.pImageDsc.Name, oFsm.pImageDsc.LocalDir)
216 if err != nil || fileLen > int64(cMaxUint32) {
217 logger.Errorw(ctx, "OnuUpgradeFsm abort: problems getting image buffer length", log.Fields{
218 "device-id": oFsm.deviceID, "error": err, "length": fileLen})
219 pBaseFsm := oFsm.pAdaptFsm
220 // Can't call FSM Event directly, decoupling it
221 go func(a_pAFsm *AdapterFsm) {
222 _ = a_pAFsm.pFsm.Event(vlanEvReset)
223 }(pBaseFsm)
224 return
225 }
226
227 oFsm.imageBuffer = make([]byte, fileLen)
228 oFsm.imageBuffer, err = oFsm.pDownloadManager.getDownloadImageBuffer(ctx, oFsm.pImageDsc.Name, oFsm.pImageDsc.LocalDir)
229 if err != nil {
230 logger.Errorw(ctx, "OnuUpgradeFsm abort: can't get image buffer", log.Fields{
231 "device-id": oFsm.deviceID, "error": err})
232 pBaseFsm := oFsm.pAdaptFsm
233 // Can't call FSM Event directly, decoupling it
234 go func(a_pAFsm *AdapterFsm) {
235 _ = a_pAFsm.pFsm.Event(vlanEvReset)
236 }(pBaseFsm)
237 return
238 }
239
240 oFsm.noOfSections = uint32(fileLen / cOmciDownloadSectionSize)
241 if fileLen%cOmciDownloadSectionSize > 0 {
242 bufferPadding := make([]byte, cOmciDownloadSectionSize-uint32(fileLen%cOmciDownloadSectionSize))
243 //expand the imageBuffer to exactly fit multiples of cOmciDownloadSectionSize with padding
244 oFsm.imageBuffer = append(oFsm.imageBuffer[:fileLen], bufferPadding...)
245 oFsm.noOfSections++
246 }
247 oFsm.origImageLength = uint32(fileLen)
248 oFsm.imageLength = uint32(len(oFsm.imageBuffer))
249 oFsm.inactiveImageMeID = uint16(1) //just to start with, must be detected from upload data or even determined per new request?
250
251 logger.Infow(ctx, "OnuUpgradeFsm starts with StartSwDl values", log.Fields{
252 "MeId": oFsm.inactiveImageMeID, "windowSizeLimit": oFsm.omciDownloadWindowSizeLimit,
253 "ImageSize": oFsm.imageLength, "original file size": fileLen})
254 //"NumberOfCircuitPacks": oFsm.numberCircuitPacks, "CircuitPacks MeId": 0}) //parallel circuit packs download not supported
255 err = oFsm.pOmciCC.sendStartSoftwareDownload(log.WithSpanFromContext(context.TODO(), ctx), ConstDefaultOmciTimeout, false,
256 oFsm.pAdaptFsm.commChan, oFsm.inactiveImageMeID, oFsm.omciDownloadWindowSizeLimit, oFsm.origImageLength)
257 if err != nil {
258 logger.Errorw(ctx, "StartSwDl abort: can't send section", log.Fields{
259 "device-id": oFsm.deviceID, "error": err})
260 //TODO!!!: define some more sophisticated error treatment with some repetition, for now just reset the FSM
261 pBaseFsm := oFsm.pAdaptFsm
262 // Can't call FSM Event directly, decoupling it
263 go func(a_pAFsm *AdapterFsm) {
264 _ = a_pAFsm.pFsm.Event(vlanEvReset)
265 }(pBaseFsm)
266 return
267 }
268}
269
270func (oFsm *OnuUpgradeFsm) enterDownloadSection(ctx context.Context, e *fsm.Event) {
271 logger.Debugw(ctx, "OnuUpgradeFsm start downloading sections", log.Fields{
272 "device-id": oFsm.deviceID, "absolute window": oFsm.nextDownloadWindow})
273
274 var windowAckRequest uint8 = 0
275 var bufferStartOffset uint32
276 var bufferEndOffset uint32
277 var downloadSection []byte
278 framePrint := false //default no printing of downloadSection frames
279 if oFsm.nextDownloadSectionsAbsolute == 0 {
280 //debug print of first section frame
281 framePrint = true
282 }
283
284 for {
285 bufferStartOffset = oFsm.nextDownloadSectionsAbsolute * cOmciDownloadSectionSize
286 bufferEndOffset = bufferStartOffset + cOmciDownloadSectionSize - 1 //for representing cOmciDownloadSectionSizeLimit values
287 logger.Debugw(ctx, "DlSection values are", log.Fields{
288 "DlSectionNoAbsolute": oFsm.nextDownloadSectionsAbsolute,
289 "DlSectionWindow": oFsm.nextDownloadSectionsWindow,
290 "startOffset": bufferStartOffset, "endOffset": bufferEndOffset})
291 if bufferStartOffset+1 > oFsm.imageLength || bufferEndOffset+1 > oFsm.imageLength { //should never occur in this state
292 logger.Errorw(ctx, "OnuUpgradeFsm buffer error: exceeded length", log.Fields{
293 "device-id": oFsm.deviceID, "bufferStartOffset": bufferStartOffset,
294 "bufferEndOffset": bufferEndOffset, "imageLength": oFsm.imageLength})
295 //logical error -- reset the FSM
296 pBaseFsm := oFsm.pAdaptFsm
297 // Can't call FSM Event directly, decoupling it
298 go func(a_pAFsm *AdapterFsm) {
299 _ = a_pAFsm.pFsm.Event(vlanEvReset)
300 }(pBaseFsm)
301 return
302 }
303 downloadSection = oFsm.imageBuffer[bufferStartOffset : bufferEndOffset+1]
304 if oFsm.nextDownloadSectionsWindow == oFsm.omciDownloadWindowSizeLimit {
305 windowAckRequest = 1
306 logger.Debugw(ctx, "DlSection expect Response for complete window", log.Fields{
307 "device-id": oFsm.deviceID, "in window": oFsm.nextDownloadWindow})
308 }
309 if oFsm.nextDownloadSectionsAbsolute+1 >= oFsm.noOfSections {
310 windowAckRequest = 1
311 framePrint = true //debug print of last frame
312 logger.Debugw(ctx, "DlSection expect Response for last window (section)", log.Fields{
313 "device-id": oFsm.deviceID, "DlSectionNoAbsolute": oFsm.nextDownloadSectionsAbsolute})
314 }
315 err := oFsm.pOmciCC.sendDownloadSection(log.WithSpanFromContext(context.TODO(), ctx), ConstDefaultOmciTimeout, false,
316 oFsm.pAdaptFsm.commChan, oFsm.inactiveImageMeID, windowAckRequest, oFsm.nextDownloadSectionsWindow, downloadSection, framePrint)
317 if err != nil {
318 logger.Errorw(ctx, "DlSection abort: can't send section", log.Fields{
319 "device-id": oFsm.deviceID, "error": err})
320 //TODO!!!: define some more sophisticated error treatment with some repetition, for now just reset the FSM
321 pBaseFsm := oFsm.pAdaptFsm
322 // Can't call FSM Event directly, decoupling it
323 go func(a_pAFsm *AdapterFsm) {
324 _ = a_pAFsm.pFsm.Event(vlanEvReset)
325 }(pBaseFsm)
326 return
327 }
328
329 oFsm.nextDownloadSectionsAbsolute++ //always increase the absolute section counter after having sent one
330 if windowAckRequest == 1 {
331 pBaseFsm := oFsm.pAdaptFsm
332 // Can't call FSM Event directly, decoupling it
333 go func(a_pAFsm *AdapterFsm) {
334 _ = a_pAFsm.pFsm.Event(upgradeEvWaitWindowAck) //state transition to upgradeStVerifyWindow
335 }(pBaseFsm)
336 return
337 }
338 framePrint = false //for the next Section frame (if wanted, can be enabled in logic before sendXXX())
339 oFsm.nextDownloadSectionsWindow++ //increase the window related section counter only if not in the last section
340 if oFsm.omciSectionInterleaveMilliseconds > 0 {
341 //ensure a defined intersection-time-gap to leave space for further processing, other ONU's ...
342 time.Sleep(oFsm.omciSectionInterleaveMilliseconds * time.Millisecond)
343 }
344 }
345}
346
347func (oFsm *OnuUpgradeFsm) enterVerifyWindow(ctx context.Context, e *fsm.Event) {
348 logger.Debugw(ctx, "OnuUpgradeFsm verify DL window ack", log.Fields{
349 "for window": oFsm.nextDownloadWindow, "device-id": oFsm.deviceID})
350}
351
352func (oFsm *OnuUpgradeFsm) enterFinalizeDL(ctx context.Context, e *fsm.Event) {
353 imageCRC := crc32a.Checksum(oFsm.imageBuffer[:int(oFsm.origImageLength)]) //ITU I.363.5 crc
354 logger.Infow(ctx, "OnuUpgradeFsm finalize DL", log.Fields{
355 "device-id": oFsm.deviceID, "crc": strconv.FormatInt(int64(imageCRC), 16), "delay": oFsm.delayEndSwDl})
356
357 if oFsm.delayEndSwDl {
358 //give the ONU some time for image evaluation (hoping it does not base that on first EndSwDl itself)
359 // should not be set in case this state is used for real download abort (not yet implemented)
360 time.Sleep(cOmciEndSwDlDelaySeconds * time.Second)
361 }
362
363 err := oFsm.pOmciCC.sendEndSoftwareDownload(log.WithSpanFromContext(context.TODO(), ctx), ConstDefaultOmciTimeout, false,
364 oFsm.pAdaptFsm.commChan, oFsm.inactiveImageMeID, oFsm.origImageLength, imageCRC)
365 if err != nil {
366 logger.Errorw(ctx, "EndSwDl abort: can't send section", log.Fields{
367 "device-id": oFsm.deviceID, "error": err})
368 //TODO!!!: define some more sophisticated error treatment with some repetition, for now just reset the FSM
369 pBaseFsm := oFsm.pAdaptFsm
370 // Can't call FSM Event directly, decoupling it
371 go func(a_pAFsm *AdapterFsm) {
372 _ = a_pAFsm.pFsm.Event(vlanEvReset)
373 }(pBaseFsm)
374 return
375 }
376}
377
378func (oFsm *OnuUpgradeFsm) enterActivateSw(ctx context.Context, e *fsm.Event) {
379 logger.Infow(ctx, "OnuUpgradeFsm activate SW", log.Fields{
380 "device-id": oFsm.deviceID, "me-id": oFsm.inactiveImageMeID})
381
382 err := oFsm.pOmciCC.sendActivateSoftware(log.WithSpanFromContext(context.TODO(), ctx), ConstDefaultOmciTimeout, false,
383 oFsm.pAdaptFsm.commChan, oFsm.inactiveImageMeID)
384 if err != nil {
385 logger.Errorw(ctx, "ActivateSw abort: can't send activate frame", log.Fields{
386 "device-id": oFsm.deviceID, "error": err})
387 //TODO!!!: define some more sophisticated error treatment with some repetition, for now just reset the FSM
388 pBaseFsm := oFsm.pAdaptFsm
389 // Can't call FSM Event directly, decoupling it
390 go func(a_pAFsm *AdapterFsm) {
391 _ = a_pAFsm.pFsm.Event(vlanEvReset)
392 }(pBaseFsm)
393 return
394 }
395}
396
397func (oFsm *OnuUpgradeFsm) enterCommitSw(ctx context.Context, e *fsm.Event) {
398 logger.Infow(ctx, "OnuUpgradeFsm commit SW - not yet implemented", log.Fields{
399 "device-id": oFsm.deviceID, "me-id": oFsm.inactiveImageMeID})
400 //here should be the sending of the software commit message and staying here while waiting for the response
401}
402
403func (oFsm *OnuUpgradeFsm) enterResetting(ctx context.Context, e *fsm.Event) {
404 logger.Debugw(ctx, "OnuUpgradeFsm resetting", log.Fields{"device-id": oFsm.deviceID})
405
406 pConfigupgradeStateAFsm := oFsm.pAdaptFsm
407 if pConfigupgradeStateAFsm != nil {
408 // abort running message processing
409 fsmAbortMsg := Message{
410 Type: TestMsg,
411 Data: TestMessage{
412 TestMessageVal: AbortMessageProcessing,
413 },
414 }
415 pConfigupgradeStateAFsm.commChan <- fsmAbortMsg
416
417 //try to restart the FSM to 'disabled'
418 // Can't call FSM Event directly, decoupling it
419 go func(a_pAFsm *AdapterFsm) {
420 if a_pAFsm != nil && a_pAFsm.pFsm != nil {
421 _ = a_pAFsm.pFsm.Event(upgradeEvRestart)
422 }
423 }(pConfigupgradeStateAFsm)
424 }
425}
426
427func (oFsm *OnuUpgradeFsm) enterDisabled(ctx context.Context, e *fsm.Event) {
428 logger.Debugw(ctx, "OnuUpgradeFsm enters disabled state", log.Fields{"device-id": oFsm.deviceID})
429 if oFsm.pDeviceHandler != nil {
430 //request removal of 'reference' in the Handler (completely clear the FSM and its data)
431 go oFsm.pDeviceHandler.removeOnuUpgradeFsm(ctx)
432 }
433}
434
435func (oFsm *OnuUpgradeFsm) processOmciUpgradeMessages(ctx context.Context) { //ctx context.Context?
436 logger.Debugw(ctx, "Start OnuUpgradeFsm Msg processing", log.Fields{"for device-id": oFsm.deviceID})
437loop:
438 for {
439 // case <-ctx.Done():
440 // logger.Info(ctx,"MibSync Msg", log.Fields{"Message handling canceled via context for device-id": oFsm.deviceID})
441 // break loop
442 message, ok := <-oFsm.pAdaptFsm.commChan
443 if !ok {
444 logger.Info(ctx, "OnuUpgradeFsm Rx Msg - could not read from channel", log.Fields{"device-id": oFsm.deviceID})
445 // but then we have to ensure a restart of the FSM as well - as exceptional procedure
446 _ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvReset)
447 break loop
448 }
449 logger.Debugw(ctx, "OnuUpgradeFsm Rx Msg", log.Fields{"device-id": oFsm.deviceID})
450
451 switch message.Type {
452 case TestMsg:
453 msg, _ := message.Data.(TestMessage)
454 if msg.TestMessageVal == AbortMessageProcessing {
455 logger.Infow(ctx, "OnuUpgradeFsm abort ProcessMsg", log.Fields{"for device-id": oFsm.deviceID})
456 break loop
457 }
458 logger.Warnw(ctx, "OnuUpgradeFsm unknown TestMessage", log.Fields{"device-id": oFsm.deviceID, "MessageVal": msg.TestMessageVal})
459 case OMCI:
460 msg, _ := message.Data.(OmciMessage)
461 oFsm.handleOmciOnuUpgradeMessage(ctx, msg)
462 default:
463 logger.Warn(ctx, "OnuUpgradeFsm Rx unknown message", log.Fields{"device-id": oFsm.deviceID,
464 "message.Type": message.Type})
465 }
466 }
467 logger.Infow(ctx, "End OnuUpgradeFsm Msg processing", log.Fields{"device-id": oFsm.deviceID})
468}
469
470//nolint: gocyclo
471func (oFsm *OnuUpgradeFsm) handleOmciOnuUpgradeMessage(ctx context.Context, msg OmciMessage) {
472 logger.Debugw(ctx, "Rx OMCI OnuUpgradeFsm Msg", log.Fields{"device-id": oFsm.deviceID,
473 "msgType": msg.OmciMsg.MessageType})
474
475 switch msg.OmciMsg.MessageType {
476 case omci.StartSoftwareDownloadResponseType:
477 {
478 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeStartSoftwareDownloadResponse)
479 if msgLayer == nil {
480 logger.Errorw(ctx, "Omci Msg layer could not be detected for StartSwDlResponse",
481 log.Fields{"device-id": oFsm.deviceID})
482 return
483 }
484 msgObj, msgOk := msgLayer.(*omci.StartSoftwareDownloadResponse)
485 if !msgOk {
486 logger.Errorw(ctx, "Omci Msg layer could not be assigned for StartSwDlResponse",
487 log.Fields{"device-id": oFsm.deviceID})
488 return
489 }
490 logger.Debugw(ctx, "OnuUpgradeFsm StartSwDlResponse data", log.Fields{
491 "device-id": oFsm.deviceID, "data-fields": msgObj})
492 if msgObj.Result != me.Success {
493 logger.Errorw(ctx, "OnuUpgradeFsm StartSwDlResponse result error - later: drive FSM to abort state ?",
494 log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
495 // possibly force FSM into abort or ignore some errors for some messages? store error for mgmt display?
496 return
497 }
498 if msgObj.EntityInstance == oFsm.inactiveImageMeID {
499 logger.Debugw(ctx, "Expected StartSwDlResponse received", log.Fields{"device-id": oFsm.deviceID})
500 if msgObj.WindowSize != oFsm.omciDownloadWindowSizeLimit {
501 // also response WindowSize = 0 is a valid number for used Window size 1
502 logger.Debugw(ctx, "different StartSwDlResponse window size requested by ONU", log.Fields{
503 "acceptedOnuWindowSizeLimit": msgObj.WindowSize, "device-id": oFsm.deviceID})
504 oFsm.omciDownloadWindowSizeLimit = msgObj.WindowSize
505 }
506 oFsm.noOfWindows = oFsm.noOfSections / uint32(oFsm.omciDownloadWindowSizeLimit+1)
507 if oFsm.noOfSections%uint32(oFsm.omciDownloadWindowSizeLimit+1) > 0 {
508 oFsm.noOfWindows++
509 }
510 logger.Debugw(ctx, "OnuUpgradeFsm will use", log.Fields{
511 "windows": oFsm.noOfWindows, "sections": oFsm.noOfSections,
512 "at WindowSizeLimit": oFsm.omciDownloadWindowSizeLimit})
513 oFsm.nextDownloadSectionsAbsolute = 0
514 oFsm.nextDownloadSectionsWindow = 0
515 oFsm.nextDownloadWindow = 0
516
517 _ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvRxStartSwDownload)
518 return
519 }
520 logger.Errorw(ctx, "OnuUpgradeFsm StartSwDlResponse wrong ME instance: try again (later)?",
521 log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
522 // TODO!!!: possibly repeat the start request (once)?
523 return
524 } //StartSoftwareDownloadResponseType
525 case omci.DownloadSectionResponseType:
526 {
527 /* TODO!!!: Have to remove the check here as current used omci-lib does not allow msg layering here
528 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeDownloadSectionResponse)
529 if msgLayer == nil {
530 logger.Errorw(ctx, "Omci Msg layer could not be detected for DlSectionResponse",
531 log.Fields{"device-id": oFsm.deviceID, "omci-message": msg.OmciMsg})
532 return
533 }
534 msgObj, msgOk := msgLayer.(*omci.DownloadSectionResponse)
535 if !msgOk {
536 logger.Errorw(ctx, "Omci Msg layer could not be assigned for DlSectionResponse",
537 log.Fields{"device-id": oFsm.deviceID})
538 return
539 }
540 logger.Debugw(ctx, "OnuUpgradeFsm DlSectionResponse Data", log.Fields{
541 "device-id": oFsm.deviceID, "data-fields": msgObj})
542 if msgObj.Result != me.Success {
543 logger.Errorw(ctx, "OnuUpgradeFsm DlSectionResponse result error - later: repeat window once?", //TODO!!!
544 log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
545 return
546 }
547 if msgObj.EntityInstance == oFsm.inactiveImageMeID {
548 sectionNumber := msgObj.SectionNumber
549 */
550 sectionNumber := oFsm.omciDownloadWindowSizeLimit //as long as access from omci-lib is not given above!!!
551 logger.Debugw(ctx, "DlSectionResponse received", log.Fields{
552 "window section-number": sectionNumber, "device-id": oFsm.deviceID})
553 if sectionNumber != oFsm.omciDownloadWindowSizeLimit {
554 logger.Errorw(ctx, "OnuUpgradeFsm DlSectionResponse section error - later: repeat window once?", //TODO!!!
555 log.Fields{"device-id": oFsm.deviceID, "window-section-limit": oFsm.omciDownloadWindowSizeLimit})
556 return
557 }
558
559 oFsm.nextDownloadWindow++
560 if oFsm.nextDownloadWindow >= oFsm.noOfWindows {
561 oFsm.delayEndSwDl = true //ensure a delay for the EndSwDl message
562 _ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvEndSwDownload)
563 return
564 }
565 oFsm.nextDownloadSectionsWindow = 0
566 _ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvContinueNextWindow)
567 return
568 /* }
569 logger.Errorw(ctx, "OnuUpgradeFsm Omci StartSwDlResponse wrong ME instance: try again (later)?",
570 log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
571 // TODO!!!: possibly repeat the start request (once)?
572 return
573 */
574 } //DownloadSectionResponseType
575 case omci.EndSoftwareDownloadResponseType:
576 {
577 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeEndSoftwareDownloadResponse)
578 if msgLayer == nil {
579 logger.Errorw(ctx, "Omci Msg layer could not be detected for EndSwDlResponse",
580 log.Fields{"device-id": oFsm.deviceID})
581 return
582 }
583 msgObj, msgOk := msgLayer.(*omci.EndSoftwareDownloadResponse)
584 if !msgOk {
585 logger.Errorw(ctx, "Omci Msg layer could not be assigned for EndSwDlResponse",
586 log.Fields{"device-id": oFsm.deviceID})
587 return
588 }
589 logger.Debugw(ctx, "OnuUpgradeFsm EndSwDlResponse data", log.Fields{
590 "device-id": oFsm.deviceID, "data-fields": msgObj})
591 if msgObj.Result != me.Success {
592 //TODO!!: Busy must be handled to give the ONU time for internal image storage, perhaps also processing error (CRC incorrect)
593 logger.Errorw(ctx, "OnuUpgradeFsm EndSwDlResponse result error - later: drive FSM to abort state ?",
594 log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
595 // possibly force FSM into abort or ignore some errors for some messages? store error for mgmt display?
596 return
597 }
598 if msgObj.EntityInstance == oFsm.inactiveImageMeID {
599 logger.Debugw(ctx, "Expected EndSwDlResponse received", log.Fields{"device-id": oFsm.deviceID})
600 _ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvRequestActivate)
601 return
602 }
603 logger.Errorw(ctx, "OnuUpgradeFsm StartSwDlResponse wrong ME instance: try again (later)?",
604 log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
605 // TODO!!!: possibly repeat the end request (once)? or verify ONU upgrade state?
606 return
607 } //EndSoftwareDownloadResponseType
608 case omci.ActivateSoftwareResponseType:
609 {
610 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeActivateSoftwareResponse)
611 if msgLayer == nil {
612 logger.Errorw(ctx, "Omci Msg layer could not be detected for ActivateSw",
613 log.Fields{"device-id": oFsm.deviceID})
614 return
615 }
616 msgObj, msgOk := msgLayer.(*omci.ActivateSoftwareResponse)
617 if !msgOk {
618 logger.Errorw(ctx, "Omci Msg layer could not be assigned for ActivateSw",
619 log.Fields{"device-id": oFsm.deviceID})
620 return
621 }
622 logger.Debugw(ctx, "OnuUpgradeFsm ActivateSwResponse data", log.Fields{
623 "device-id": oFsm.deviceID, "data-fields": msgObj})
624 if msgObj.Result != me.Success {
625 logger.Errorw(ctx, "OnuUpgradeFsm ActivateSwResponse result error - later: drive FSM to abort state ?",
626 log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
627 // TODO!!!: error treatment?, perhaps in the end reset the FSM
628 return
629 }
630 if msgObj.EntityInstance == oFsm.inactiveImageMeID {
631 logger.Debugw(ctx, "Expected ActivateSwResponse received", log.Fields{"device-id": oFsm.deviceID})
632 _ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvWaitForCommit)
633 return
634 }
635 logger.Errorw(ctx, "OnuUpgradeFsm ActivateSwResponse wrong ME instance: abort",
636 log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
637 // TODO!!!: error treatment?, perhaps in the end reset the FSM
638 return
639 } //ActivateSoftwareResponseType
640 default:
641 {
642 logger.Errorw(ctx, "Rx OMCI unhandled MsgType",
643 log.Fields{"omciMsgType": msg.OmciMsg.MessageType, "device-id": oFsm.deviceID})
644 return
645 }
646 }
647}
648
649/*
650func (oFsm *OnuUpgradeFsm) waitforOmciResponse(ctx context.Context) error {
651 select {
652 // maybe be also some outside cancel (but no context modeled for the moment ...)
653 // case <-ctx.Done():
654 // logger.Infow(ctx,"LockState-bridge-init message reception canceled", log.Fields{"for device-id": oFsm.deviceID})
655 case <-time.After(30 * time.Second): //AS FOR THE OTHER OMCI FSM's
656 logger.Warnw(ctx, "OnuUpgradeFsm multi entity timeout", log.Fields{"for device-id": oFsm.deviceID})
657 return fmt.Errorf("OnuUpgradeFsm multi entity timeout %s", oFsm.deviceID)
658 case success := <-oFsm.omciMIdsResponseReceived:
659 if success {
660 logger.Debug(ctx, "OnuUpgradeFsm multi entity response received")
661 return nil
662 }
663 // should not happen so far
664 logger.Warnw(ctx, "OnuUpgradeFsm multi entity response error", log.Fields{"for device-id": oFsm.deviceID})
665 return fmt.Errorf("OnuUpgradeFsm multi entity responseError %s", oFsm.deviceID)
666 }
667}
668*/