blob: eb4021f351bc5f8f8a006d93e02aa75a15b11d1a [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
mpagenko836a1fd2021-11-01 16:12:42 +000027 "github.com/opencord/omci-lib-go/v2"
28 me "github.com/opencord/omci-lib-go/v2/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.updateOnuSwImagePersistentData(ctx)
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000113 return &images, nil
114}
115
116func (oo *OnuImageStatus) requestOnuImageAttributes(ctx context.Context, imageID uint16, image *voltha.OnuImage) error {
117 oo.mutexPLastTxMeInstance.Lock()
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000118 meInstance, err := oo.pOmciCC.SendGetMe(log.WithSpanFromContext(context.TODO(), ctx), me.SoftwareImageClassID,
119 imageID, oo.requestedAttributes, oo.pDeviceHandler.GetOmciTimeout(), true, oo.respChannel)
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000120 if err != nil {
121 oo.mutexPLastTxMeInstance.Unlock()
122 logger.Errorw(ctx, "can't send omci request to get data for image id", log.Fields{"image-id": imageID, "device-id": oo.deviceID})
123 return fmt.Errorf("can't-send-omci-request-to-get-data-for-image-id-%d", imageID)
124 }
125 oo.pLastTxMeInstance = meInstance
126 oo.mutexPLastTxMeInstance.Unlock()
127
128 if err = oo.waitForGetOnuImageStatus(ctx, image); err != nil {
129 logger.Errorw(ctx, err.Error(), log.Fields{"device-id": oo.deviceID})
130 return err
131 }
132 return nil
133}
134
135func (oo *OnuImageStatus) waitForGetOnuImageStatus(ctx context.Context, image *voltha.OnuImage) error {
136 oo.setWaitingForResp(true)
137 select {
138 // maybe be also some outside cancel (but no context modeled for the moment ...)
139 case <-ctx.Done():
140 logger.Errorw(ctx, "waitForGetOnuImageStatus context done", log.Fields{"device-id": oo.deviceID})
141 oo.setWaitingForResp(false)
142 return fmt.Errorf("wait-for-image-status-context-done")
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000143 case <-time.After(oo.pOmciCC.GetMaxOmciTimeoutWithRetries() * time.Second):
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000144 logger.Errorw(ctx, "waitForGetOnuImageStatus timeout", log.Fields{"device-id": oo.deviceID})
145 oo.setWaitingForResp(false)
146 return fmt.Errorf("wait-for-image-status-timeout")
147 case message, ok := <-oo.respChannel:
148 if !ok {
149 logger.Errorw(ctx, "waitForGetOnuImageStatus response error", log.Fields{"device-id": oo.deviceID})
150 oo.setWaitingForResp(false)
151 return fmt.Errorf("wait-for-image-status-response-error")
152 }
153 switch message.Type {
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000154 case cmn.OMCI:
155 msg, _ := message.Data.(cmn.OmciMessage)
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000156 oo.setWaitingForResp(false)
157 return oo.processGetOnuImageStatusResp(ctx, msg, image)
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000158 case cmn.TestMsg:
159 msg, _ := message.Data.(cmn.TestMessage)
160 if msg.TestMessageVal == cmn.AbortMessageProcessing {
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000161 logger.Info(ctx, "waitForGetOnuImageStatus abort msg received", log.Fields{"device-id": oo.deviceID})
162 oo.setWaitingForResp(false)
163 return fmt.Errorf("wait-for-image-status-abort-msg-received")
164 }
165 default:
166 logger.Errorw(ctx, "waitForGetOnuImageStatus wrong msg type received", log.Fields{"msgType": message.Type, "device-id": oo.deviceID})
167 oo.setWaitingForResp(false)
168 return fmt.Errorf("wait-for-image-status-response-error")
169 }
170 }
171 logger.Errorw(ctx, "waitForGetOnuImageStatus processing error", log.Fields{"device-id": oo.deviceID})
172 oo.setWaitingForResp(false)
173 return fmt.Errorf("wait-for-image-status-processing-error")
174
175}
176
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000177func (oo *OnuImageStatus) processGetOnuImageStatusResp(ctx context.Context, msg cmn.OmciMessage, image *voltha.OnuImage) error {
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000178 if msg.OmciMsg.MessageType != omci.GetResponseType {
179 logger.Errorw(ctx, "processGetOnuImageStatusResp wrong response type received", log.Fields{"respType": msg.OmciMsg.MessageType, "device-id": oo.deviceID})
180 return fmt.Errorf("process-image-status-response-error")
181 }
182 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeGetResponse)
183 if msgLayer == nil {
184 logger.Errorw(ctx, "processGetOnuImageStatusResp omci Msg layer not found", log.Fields{"device-id": oo.deviceID})
185 return fmt.Errorf("process-image-status-response-error")
186 }
187 msgObj, msgOk := msgLayer.(*omci.GetResponse)
188 if !msgOk {
189 logger.Errorw(ctx, "processGetOnuImageStatusResp omci msgObj layer could not be found", log.Fields{"device-id": oo.deviceID})
190 return fmt.Errorf("process-image-status-response-error")
191 }
192 oo.mutexPLastTxMeInstance.RLock()
193 if oo.pLastTxMeInstance != nil {
194 if msgObj.EntityClass == oo.pLastTxMeInstance.GetClassID() &&
195 msgObj.EntityInstance == oo.pLastTxMeInstance.GetEntityID() {
196 oo.mutexPLastTxMeInstance.RUnlock()
Holger Hildebrandt05011352021-06-15 09:40:24 +0000197 if err := oo.processAttributesReceived(ctx, msgObj, image); err != nil {
198 logger.Errorw(ctx, err.Error(), log.Fields{"device-id": oo.deviceID})
199 return err
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000200 }
201 return nil
202 }
203 oo.mutexPLastTxMeInstance.RUnlock()
204 logger.Errorw(ctx, "processGetOnuImageStatusResp wrong MeInstance received", log.Fields{"device-id": oo.deviceID})
205 return fmt.Errorf("process-image-status-response-error")
206 }
207 oo.mutexPLastTxMeInstance.RUnlock()
208 logger.Errorw(ctx, "processGetOnuImageStatusResp pLastTxMeInstance is nil", log.Fields{"device-id": oo.deviceID})
209 return fmt.Errorf("process-image-status-response-error")
210}
Holger Hildebrandt05011352021-06-15 09:40:24 +0000211
212func (oo *OnuImageStatus) processAttributesReceived(ctx context.Context, msgObj *omci.GetResponse, image *voltha.OnuImage) error {
213 meAttributes := msgObj.Attributes
214 logger.Debugw(ctx, "processAttributesReceived", log.Fields{"attributes": meAttributes, "device-id": oo.deviceID})
215
Holger Hildebrandt94688c72021-12-17 12:13:02 +0000216 if _, ok := oo.requestedAttributes[cImgVersion]; ok {
217 if msgObj.Result != me.Success {
Holger Hildebrandt05011352021-06-15 09:40:24 +0000218 logger.Errorw(ctx, "processAttributesReceived retrieval of mandatory attributes failed",
219 log.Fields{"device-id": oo.deviceID})
220 return fmt.Errorf("process-image-status-response-error")
221 }
Holger Hildebrandt94688c72021-12-17 12:13:02 +0000222 oo.pDevEntry.HandleSwImageIndications(ctx, msgObj.EntityInstance, meAttributes)
223 }
224 for k := range oo.requestedAttributes {
Holger Hildebrandt05011352021-06-15 09:40:24 +0000225 switch k {
Holger Hildebrandt05011352021-06-15 09:40:24 +0000226 // 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
Holger Hildebrandt05011352021-06-15 09:40:24 +0000273func (oo *OnuImageStatus) updateOnuSwImagePersistentData(ctx context.Context) {
274
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000275 activeImageVersion := oo.pDevEntry.GetActiveImageVersion(ctx)
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000276 persActiveSwVersion := oo.pDevEntry.GetPersActiveSwVersion()
277 if persActiveSwVersion != activeImageVersion {
Holger Hildebrandt05011352021-06-15 09:40:24 +0000278 logger.Infow(ctx, "Active SW version has been changed at ONU - update persistent data",
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000279 log.Fields{"old version": persActiveSwVersion,
Holger Hildebrandt05011352021-06-15 09:40:24 +0000280 "new version": activeImageVersion, "device-id": oo.deviceID})
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000281 oo.pDevEntry.SetPersActiveSwVersion(activeImageVersion)
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000282 if err := oo.pDeviceHandler.StorePersistentData(ctx); err != nil {
Holger Hildebrandt05011352021-06-15 09:40:24 +0000283 logger.Warnw(ctx, "store persistent data error - continue for now as there will be additional write attempts",
284 log.Fields{"device-id": oo.deviceID, "err": err})
285 }
286 return
287 }
Holger Hildebrandt05011352021-06-15 09:40:24 +0000288}
289
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000290func (oo *OnuImageStatus) setWaitingForResp(value bool) {
291 oo.mutexWaitingForResp.Lock()
292 oo.waitingForResp = value
293 oo.mutexWaitingForResp.Unlock()
294}
Holger Hildebrandt05011352021-06-15 09:40:24 +0000295
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000296func (oo *OnuImageStatus) isWaitingForResp() bool {
297 oo.mutexWaitingForResp.RLock()
298 value := oo.waitingForResp
299 oo.mutexWaitingForResp.RUnlock()
300 return value
301}
302
303//CancelProcessing ensures that interrupted processing is canceled while waiting for a response
304func (oo *OnuImageStatus) CancelProcessing(ctx context.Context) {
305 if oo.isWaitingForResp() {
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000306 abortMsg := cmn.Message{
307 Type: cmn.TestMsg,
308 Data: cmn.TestMessage{
309 TestMessageVal: cmn.AbortMessageProcessing,
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000310 },
311 }
312 oo.respChannel <- abortMsg
313 }
314}