blob: 4e1215f345e056e8c6ebc1e13765489f04fe672f [file] [log] [blame]
Holger Hildebrandtfb402a62021-05-26 14:40:49 +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
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +000017//Package swupg provides the utilities for onu sw upgrade
18package swupg
Holger Hildebrandtfb402a62021-05-26 14:40:49 +000019
20import (
21 "context"
22 "encoding/hex"
23 "fmt"
24 "sync"
25 "time"
26
27 "github.com/opencord/omci-lib-go"
28 me "github.com/opencord/omci-lib-go/generated"
khenaidoo7d3c5582021-08-11 18:09:44 -040029 "github.com/opencord/voltha-lib-go/v7/pkg/log"
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +000030 cmn "github.com/opencord/voltha-openonu-adapter-go/internal/pkg/common"
khenaidoo7d3c5582021-08-11 18:09:44 -040031 "github.com/opencord/voltha-protos/v5/go/voltha"
Holger Hildebrandtfb402a62021-05-26 14:40:49 +000032)
33
34//OnuImageStatus implements methods to get status info of onu images
35type OnuImageStatus struct {
Holger Hildebrandtfb402a62021-05-26 14:40:49 +000036 deviceID string
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +000037 pDeviceHandler cmn.IdeviceHandler
38 pDevEntry cmn.IonuDeviceEntry
39 pOmciCC *cmn.OmciCC
Holger Hildebrandtfb402a62021-05-26 14:40:49 +000040 requestedAttributes me.AttributeValueMap
41 mutexWaitingForResp sync.RWMutex
42 waitingForResp bool
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +000043 respChannel chan cmn.Message
Holger Hildebrandtfb402a62021-05-26 14:40:49 +000044 mutexPLastTxMeInstance sync.RWMutex
45 pLastTxMeInstance *me.ManagedEntity
46}
47
48const (
49 cImgVersion = "Version"
50 cImgIsCommitted = "IsCommitted"
51 cImgIsActive = "IsActive"
52 cImgIsValid = "IsValid"
53 cImgProductCode = "ProductCode"
54 cImgImageHash = "ImageHash"
55)
Holger Hildebrandt05011352021-06-15 09:40:24 +000056const cResponse = "response: "
Holger Hildebrandtfb402a62021-05-26 14:40:49 +000057
58//NewOnuImageStatus creates a new instance of OnuImageStatus
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +000059func NewOnuImageStatus(apDeviceHandler cmn.IdeviceHandler, apDevEntry cmn.IonuDeviceEntry) *OnuImageStatus {
Holger Hildebrandtfb402a62021-05-26 14:40:49 +000060 return &OnuImageStatus{
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +000061 deviceID: apDeviceHandler.GetDeviceID(),
62 pDeviceHandler: apDeviceHandler,
63 pDevEntry: apDevEntry,
64 pOmciCC: apDevEntry.GetDevOmciCC(),
Holger Hildebrandtfb402a62021-05-26 14:40:49 +000065 requestedAttributes: make(me.AttributeValueMap),
66 waitingForResp: false,
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +000067 respChannel: make(chan cmn.Message),
Holger Hildebrandtfb402a62021-05-26 14:40:49 +000068 }
69}
Holger Hildebrandt05011352021-06-15 09:40:24 +000070
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +000071// GetOnuImageStatus - TODO: add comment
72func (oo *OnuImageStatus) GetOnuImageStatus(ctx context.Context) (*voltha.OnuImages, error) {
Holger Hildebrandtfb402a62021-05-26 14:40:49 +000073
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +000074 if !oo.pDeviceHandler.IsReadyForOmciConfig() {
Holger Hildebrandt05011352021-06-15 09:40:24 +000075 logger.Errorw(ctx, "command rejected - improper device state", log.Fields{"device-id": oo.deviceID})
76 return nil, fmt.Errorf("command-rejected-improper-device-state")
77 }
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +000078 if oo.pOmciCC == nil {
Holger Hildebrandtfb402a62021-05-26 14:40:49 +000079 logger.Errorw(ctx, "omciCC not ready to receive omci messages", log.Fields{"device-id": oo.deviceID})
80 return nil, fmt.Errorf("omciCC-not-ready-to-receive-omci-messages")
81 }
Holger Hildebrandt05011352021-06-15 09:40:24 +000082 var images voltha.OnuImages
83
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +000084 for i := cmn.FirstSwImageMeID; i <= cmn.SecondSwImageMeID; i++ {
85 logger.Debugw(ctx, "GetOnuImageStatus for image id", log.Fields{"image-id": i, "device-id": oo.deviceID})
Holger Hildebrandtfb402a62021-05-26 14:40:49 +000086
87 var image voltha.OnuImage
88
89 // TODO: Since the summed length of the attributes exceeds the capacity of a single response,
90 // it is distributed on several requests here. It should be discussed whether, in the course of a refactoring,
91 // a global mechanism should be implemented that automates this distribution - which would entail quite some
92 // changes on the respective receiver sides.
93
94 oo.requestedAttributes = me.AttributeValueMap{cImgVersion: "", cImgIsCommitted: 0, cImgIsActive: 0, cImgIsValid: 0}
95 if err := oo.requestOnuImageAttributes(ctx, uint16(i), &image); err != nil {
96 logger.Errorw(ctx, err.Error(), log.Fields{"requestedAttributes": oo.requestedAttributes, "device-id": oo.deviceID})
97 return nil, err
98 }
99 oo.requestedAttributes = me.AttributeValueMap{cImgProductCode: ""}
100 if err := oo.requestOnuImageAttributes(ctx, uint16(i), &image); err != nil {
101 logger.Errorw(ctx, err.Error(), log.Fields{"requestedAttributes": oo.requestedAttributes, "device-id": oo.deviceID})
102 return nil, err
103 }
104 oo.requestedAttributes = me.AttributeValueMap{cImgImageHash: 0}
105 if err := oo.requestOnuImageAttributes(ctx, uint16(i), &image); err != nil {
106 logger.Errorw(ctx, err.Error(), log.Fields{"requestedAttributes": oo.requestedAttributes, "device-id": oo.deviceID})
107 return nil, err
108 }
109 images.Items = append(images.Items, &image)
110 }
111 logger.Debugw(ctx, "images of the ONU", log.Fields{"images": images})
Holger Hildebrandt05011352021-06-15 09:40:24 +0000112 oo.updateOnuSwImageIndications(ctx, &images)
113 oo.updateOnuSwImagePersistentData(ctx)
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000114 return &images, nil
115}
116
117func (oo *OnuImageStatus) requestOnuImageAttributes(ctx context.Context, imageID uint16, image *voltha.OnuImage) error {
118 oo.mutexPLastTxMeInstance.Lock()
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000119 meInstance, err := oo.pOmciCC.SendGetMe(log.WithSpanFromContext(context.TODO(), ctx), me.SoftwareImageClassID,
120 imageID, oo.requestedAttributes, oo.pDeviceHandler.GetOmciTimeout(), true, oo.respChannel)
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000121 if err != nil {
122 oo.mutexPLastTxMeInstance.Unlock()
123 logger.Errorw(ctx, "can't send omci request to get data for image id", log.Fields{"image-id": imageID, "device-id": oo.deviceID})
124 return fmt.Errorf("can't-send-omci-request-to-get-data-for-image-id-%d", imageID)
125 }
126 oo.pLastTxMeInstance = meInstance
127 oo.mutexPLastTxMeInstance.Unlock()
128
129 if err = oo.waitForGetOnuImageStatus(ctx, image); err != nil {
130 logger.Errorw(ctx, err.Error(), log.Fields{"device-id": oo.deviceID})
131 return err
132 }
133 return nil
134}
135
136func (oo *OnuImageStatus) waitForGetOnuImageStatus(ctx context.Context, image *voltha.OnuImage) error {
137 oo.setWaitingForResp(true)
138 select {
139 // maybe be also some outside cancel (but no context modeled for the moment ...)
140 case <-ctx.Done():
141 logger.Errorw(ctx, "waitForGetOnuImageStatus context done", log.Fields{"device-id": oo.deviceID})
142 oo.setWaitingForResp(false)
143 return fmt.Errorf("wait-for-image-status-context-done")
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000144 case <-time.After(oo.pOmciCC.GetMaxOmciTimeoutWithRetries() * time.Second):
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000145 logger.Errorw(ctx, "waitForGetOnuImageStatus timeout", log.Fields{"device-id": oo.deviceID})
146 oo.setWaitingForResp(false)
147 return fmt.Errorf("wait-for-image-status-timeout")
148 case message, ok := <-oo.respChannel:
149 if !ok {
150 logger.Errorw(ctx, "waitForGetOnuImageStatus response error", log.Fields{"device-id": oo.deviceID})
151 oo.setWaitingForResp(false)
152 return fmt.Errorf("wait-for-image-status-response-error")
153 }
154 switch message.Type {
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000155 case cmn.OMCI:
156 msg, _ := message.Data.(cmn.OmciMessage)
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000157 oo.setWaitingForResp(false)
158 return oo.processGetOnuImageStatusResp(ctx, msg, image)
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000159 case cmn.TestMsg:
160 msg, _ := message.Data.(cmn.TestMessage)
161 if msg.TestMessageVal == cmn.AbortMessageProcessing {
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000162 logger.Info(ctx, "waitForGetOnuImageStatus abort msg received", log.Fields{"device-id": oo.deviceID})
163 oo.setWaitingForResp(false)
164 return fmt.Errorf("wait-for-image-status-abort-msg-received")
165 }
166 default:
167 logger.Errorw(ctx, "waitForGetOnuImageStatus wrong msg type received", log.Fields{"msgType": message.Type, "device-id": oo.deviceID})
168 oo.setWaitingForResp(false)
169 return fmt.Errorf("wait-for-image-status-response-error")
170 }
171 }
172 logger.Errorw(ctx, "waitForGetOnuImageStatus processing error", log.Fields{"device-id": oo.deviceID})
173 oo.setWaitingForResp(false)
174 return fmt.Errorf("wait-for-image-status-processing-error")
175
176}
177
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000178func (oo *OnuImageStatus) processGetOnuImageStatusResp(ctx context.Context, msg cmn.OmciMessage, image *voltha.OnuImage) error {
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000179 if msg.OmciMsg.MessageType != omci.GetResponseType {
180 logger.Errorw(ctx, "processGetOnuImageStatusResp wrong response type received", log.Fields{"respType": msg.OmciMsg.MessageType, "device-id": oo.deviceID})
181 return fmt.Errorf("process-image-status-response-error")
182 }
183 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeGetResponse)
184 if msgLayer == nil {
185 logger.Errorw(ctx, "processGetOnuImageStatusResp omci Msg layer not found", log.Fields{"device-id": oo.deviceID})
186 return fmt.Errorf("process-image-status-response-error")
187 }
188 msgObj, msgOk := msgLayer.(*omci.GetResponse)
189 if !msgOk {
190 logger.Errorw(ctx, "processGetOnuImageStatusResp omci msgObj layer could not be found", log.Fields{"device-id": oo.deviceID})
191 return fmt.Errorf("process-image-status-response-error")
192 }
193 oo.mutexPLastTxMeInstance.RLock()
194 if oo.pLastTxMeInstance != nil {
195 if msgObj.EntityClass == oo.pLastTxMeInstance.GetClassID() &&
196 msgObj.EntityInstance == oo.pLastTxMeInstance.GetEntityID() {
197 oo.mutexPLastTxMeInstance.RUnlock()
Holger Hildebrandt05011352021-06-15 09:40:24 +0000198 if err := oo.processAttributesReceived(ctx, msgObj, image); err != nil {
199 logger.Errorw(ctx, err.Error(), log.Fields{"device-id": oo.deviceID})
200 return err
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000201 }
202 return nil
203 }
204 oo.mutexPLastTxMeInstance.RUnlock()
205 logger.Errorw(ctx, "processGetOnuImageStatusResp wrong MeInstance received", log.Fields{"device-id": oo.deviceID})
206 return fmt.Errorf("process-image-status-response-error")
207 }
208 oo.mutexPLastTxMeInstance.RUnlock()
209 logger.Errorw(ctx, "processGetOnuImageStatusResp pLastTxMeInstance is nil", log.Fields{"device-id": oo.deviceID})
210 return fmt.Errorf("process-image-status-response-error")
211}
Holger Hildebrandt05011352021-06-15 09:40:24 +0000212
213func (oo *OnuImageStatus) processAttributesReceived(ctx context.Context, msgObj *omci.GetResponse, image *voltha.OnuImage) error {
214 meAttributes := msgObj.Attributes
215 logger.Debugw(ctx, "processAttributesReceived", log.Fields{"attributes": meAttributes, "device-id": oo.deviceID})
216
217 for k := range oo.requestedAttributes {
218
219 if msgObj.Result != me.Success && k != cImgProductCode && k != cImgImageHash {
220 logger.Errorw(ctx, "processAttributesReceived retrieval of mandatory attributes failed",
221 log.Fields{"device-id": oo.deviceID})
222 return fmt.Errorf("process-image-status-response-error")
223 }
224 switch k {
225
226 // mandatory attributes
227 case cImgIsCommitted:
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000228 if meAttributes[cImgIsCommitted].(uint8) == cmn.SwIsCommitted {
Holger Hildebrandt05011352021-06-15 09:40:24 +0000229 image.IsCommited = true
230 } else {
231 image.IsCommited = false
232 }
233 case cImgIsActive:
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000234 if meAttributes[cImgIsActive].(uint8) == cmn.SwIsActive {
Holger Hildebrandt05011352021-06-15 09:40:24 +0000235 image.IsActive = true
236 } else {
237 image.IsActive = false
238 }
239 case cImgIsValid:
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000240 if meAttributes[cImgIsValid].(uint8) == cmn.SwIsValid {
Holger Hildebrandt05011352021-06-15 09:40:24 +0000241 image.IsValid = true
242 } else {
243 image.IsValid = false
244 }
245 case cImgVersion:
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000246 image.Version = cmn.TrimStringFromMeOctet(meAttributes[cImgVersion])
Holger Hildebrandt05011352021-06-15 09:40:24 +0000247
248 // optional attributes
249 case cImgProductCode:
250 if msgObj.Result == me.Success {
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000251 image.ProductCode = cmn.TrimStringFromMeOctet(meAttributes[cImgProductCode])
Holger Hildebrandt05011352021-06-15 09:40:24 +0000252 } else {
253 sResult := msgObj.Result.String()
254 logger.Infow(ctx, "processAttributesReceived - ProductCode",
255 log.Fields{"result": sResult, "unsupported attribute mask": msgObj.UnsupportedAttributeMask, "device-id": oo.deviceID})
256 image.ProductCode = cResponse + sResult
257 }
258 case cImgImageHash:
259 if msgObj.Result == me.Success {
260 bytes, _ := me.InterfaceToOctets(meAttributes[cImgImageHash])
261 image.Hash = hex.EncodeToString(bytes)
262 } else {
263 sResult := msgObj.Result.String()
264 logger.Infow(ctx, "processAttributesReceived - ImageHash",
265 log.Fields{"result": sResult, "unsupported attribute mask": msgObj.UnsupportedAttributeMask, "device-id": oo.deviceID})
266 image.Hash = cResponse + sResult
267 }
268 }
269 }
270 return nil
271}
272
273func (oo *OnuImageStatus) updateOnuSwImageIndications(ctx context.Context, images *voltha.OnuImages) {
274
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000275 oo.pDevEntry.LockMutexOnuSwImageIndications()
276 onuSwImageIndications := oo.pDevEntry.GetOnuSwImageIndications()
Holger Hildebrandt05011352021-06-15 09:40:24 +0000277 validActiveImageFound := false
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000278 for i := cmn.FirstSwImageMeID; i <= cmn.SecondSwImageMeID; i++ {
Holger Hildebrandt05011352021-06-15 09:40:24 +0000279 if images.Items[i].IsActive && images.Items[i].IsValid {
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000280 onuSwImageIndications.ActiveEntityEntry.EntityID = uint16(i)
281 onuSwImageIndications.ActiveEntityEntry.Valid = images.Items[i].IsValid
282 onuSwImageIndications.ActiveEntityEntry.Version = images.Items[i].Version
Holger Hildebrandt05011352021-06-15 09:40:24 +0000283 if images.Items[i].IsCommited {
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000284 onuSwImageIndications.ActiveEntityEntry.IsCommitted = cmn.SwIsCommitted
Holger Hildebrandt05011352021-06-15 09:40:24 +0000285 } else {
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000286 onuSwImageIndications.ActiveEntityEntry.IsCommitted = cmn.SwIsUncommitted
Holger Hildebrandt05011352021-06-15 09:40:24 +0000287 }
288 validActiveImageFound = true
289 break
290 }
291 }
292 if !validActiveImageFound {
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000293 onuSwImageIndications.ActiveEntityEntry.Valid = false
Holger Hildebrandt05011352021-06-15 09:40:24 +0000294 }
295 validInactiveImageFound := false
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000296 for i := cmn.FirstSwImageMeID; i <= cmn.SecondSwImageMeID; i++ {
Holger Hildebrandt05011352021-06-15 09:40:24 +0000297 if !images.Items[i].IsActive && images.Items[i].IsValid {
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000298 onuSwImageIndications.InActiveEntityEntry.EntityID = uint16(i)
299 onuSwImageIndications.InActiveEntityEntry.Valid = images.Items[i].IsValid
300 onuSwImageIndications.InActiveEntityEntry.Version = images.Items[i].Version
Holger Hildebrandt05011352021-06-15 09:40:24 +0000301 if images.Items[i].IsCommited {
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000302 onuSwImageIndications.InActiveEntityEntry.IsCommitted = cmn.SwIsCommitted
Holger Hildebrandt05011352021-06-15 09:40:24 +0000303 } else {
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000304 onuSwImageIndications.InActiveEntityEntry.IsCommitted = cmn.SwIsUncommitted
Holger Hildebrandt05011352021-06-15 09:40:24 +0000305 }
306 validInactiveImageFound = true
307 break
308 }
309 }
310 if !validInactiveImageFound {
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000311 onuSwImageIndications.InActiveEntityEntry.Valid = false
Holger Hildebrandt05011352021-06-15 09:40:24 +0000312 }
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000313 oo.pDevEntry.SetOnuSwImageIndications(onuSwImageIndications)
314 oo.pDevEntry.UnlockMutexOnuSwImageIndications()
Holger Hildebrandt05011352021-06-15 09:40:24 +0000315}
316
317func (oo *OnuImageStatus) updateOnuSwImagePersistentData(ctx context.Context) {
318
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000319 activeImageVersion := oo.pDevEntry.GetActiveImageVersion(ctx)
320 oo.pDevEntry.LockMutexPersOnuConfig()
321 persActiveSwVersion := oo.pDevEntry.GetPersActiveSwVersion()
322 if persActiveSwVersion != activeImageVersion {
Holger Hildebrandt05011352021-06-15 09:40:24 +0000323 logger.Infow(ctx, "Active SW version has been changed at ONU - update persistent data",
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000324 log.Fields{"old version": persActiveSwVersion,
Holger Hildebrandt05011352021-06-15 09:40:24 +0000325 "new version": activeImageVersion, "device-id": oo.deviceID})
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000326 oo.pDevEntry.SetPersActiveSwVersion(activeImageVersion)
327 oo.pDevEntry.UnlockMutexPersOnuConfig()
328 if err := oo.pDeviceHandler.StorePersistentData(ctx); err != nil {
Holger Hildebrandt05011352021-06-15 09:40:24 +0000329 logger.Warnw(ctx, "store persistent data error - continue for now as there will be additional write attempts",
330 log.Fields{"device-id": oo.deviceID, "err": err})
331 }
332 return
333 }
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000334 oo.pDevEntry.UnlockMutexPersOnuConfig()
Holger Hildebrandt05011352021-06-15 09:40:24 +0000335}
336
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000337func (oo *OnuImageStatus) setWaitingForResp(value bool) {
338 oo.mutexWaitingForResp.Lock()
339 oo.waitingForResp = value
340 oo.mutexWaitingForResp.Unlock()
341}
Holger Hildebrandt05011352021-06-15 09:40:24 +0000342
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000343func (oo *OnuImageStatus) isWaitingForResp() bool {
344 oo.mutexWaitingForResp.RLock()
345 value := oo.waitingForResp
346 oo.mutexWaitingForResp.RUnlock()
347 return value
348}
349
350//CancelProcessing ensures that interrupted processing is canceled while waiting for a response
351func (oo *OnuImageStatus) CancelProcessing(ctx context.Context) {
352 if oo.isWaitingForResp() {
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000353 abortMsg := cmn.Message{
354 Type: cmn.TestMsg,
355 Data: cmn.TestMessage{
356 TestMessageVal: cmn.AbortMessageProcessing,
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000357 },
358 }
359 oo.respChannel <- abortMsg
360 }
361}