blob: 4423e2c36cfc2017193c199cdb9a4295d3d78355 [file] [log] [blame]
Holger Hildebrandtfb402a62021-05-26 14:40:49 +00001/*
Joey Armstrong89c812c2024-01-12 19:00:20 -05002 * Copyright 2020-2024 Open Networking Foundation (ONF) and the ONF Contributors
Holger Hildebrandtfb402a62021-05-26 14:40:49 +00003 *
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
Joey Armstrong89c812c2024-01-12 19:00:20 -050017// Package swupg provides the utilities for onu sw upgrade
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +000018package 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
Joey Armstrong89c812c2024-01-12 19:00:20 -050034// OnuImageStatus implements methods to get status info of onu images
Holger Hildebrandtfb402a62021-05-26 14:40:49 +000035type 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
Holger Hildebrandtd930cb22022-06-17 09:24:50 +000046 isExtendedOmci bool
Holger Hildebrandtfb402a62021-05-26 14:40:49 +000047}
48
Holger Hildebrandt05011352021-06-15 09:40:24 +000049const cResponse = "response: "
Holger Hildebrandtfb402a62021-05-26 14:40:49 +000050
Joey Armstrong89c812c2024-01-12 19:00:20 -050051// NewOnuImageStatus creates a new instance of OnuImageStatus
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +000052func NewOnuImageStatus(apDeviceHandler cmn.IdeviceHandler, apDevEntry cmn.IonuDeviceEntry) *OnuImageStatus {
Holger Hildebrandtfb402a62021-05-26 14:40:49 +000053 return &OnuImageStatus{
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +000054 deviceID: apDeviceHandler.GetDeviceID(),
55 pDeviceHandler: apDeviceHandler,
56 pDevEntry: apDevEntry,
57 pOmciCC: apDevEntry.GetDevOmciCC(),
Holger Hildebrandtfb402a62021-05-26 14:40:49 +000058 requestedAttributes: make(me.AttributeValueMap),
59 waitingForResp: false,
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +000060 respChannel: make(chan cmn.Message),
Holger Hildebrandtd930cb22022-06-17 09:24:50 +000061 isExtendedOmci: apDevEntry.GetPersIsExtOmciSupported(),
Holger Hildebrandtfb402a62021-05-26 14:40:49 +000062 }
63}
Holger Hildebrandt05011352021-06-15 09:40:24 +000064
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +000065// GetOnuImageStatus - TODO: add comment
66func (oo *OnuImageStatus) GetOnuImageStatus(ctx context.Context) (*voltha.OnuImages, error) {
Holger Hildebrandtfb402a62021-05-26 14:40:49 +000067
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +000068 if !oo.pDeviceHandler.IsReadyForOmciConfig() {
Holger Hildebrandt05011352021-06-15 09:40:24 +000069 logger.Errorw(ctx, "command rejected - improper device state", log.Fields{"device-id": oo.deviceID})
70 return nil, fmt.Errorf("command-rejected-improper-device-state")
71 }
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +000072 if oo.pOmciCC == nil {
Holger Hildebrandtfb402a62021-05-26 14:40:49 +000073 logger.Errorw(ctx, "omciCC not ready to receive omci messages", log.Fields{"device-id": oo.deviceID})
74 return nil, fmt.Errorf("omciCC-not-ready-to-receive-omci-messages")
75 }
Holger Hildebrandt05011352021-06-15 09:40:24 +000076 var images voltha.OnuImages
77
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +000078 for i := cmn.FirstSwImageMeID; i <= cmn.SecondSwImageMeID; i++ {
79 logger.Debugw(ctx, "GetOnuImageStatus for image id", log.Fields{"image-id": i, "device-id": oo.deviceID})
Holger Hildebrandtfb402a62021-05-26 14:40:49 +000080
81 var image voltha.OnuImage
82
83 // TODO: Since the summed length of the attributes exceeds the capacity of a single response,
84 // it is distributed on several requests here. It should be discussed whether, in the course of a refactoring,
85 // a global mechanism should be implemented that automates this distribution - which would entail quite some
86 // changes on the respective receiver sides.
87
Holger Hildebrandt3ac49bd2022-02-07 17:46:43 +000088 oo.requestedAttributes = me.AttributeValueMap{me.SoftwareImage_Version: "", me.SoftwareImage_IsCommitted: 0, me.SoftwareImage_IsActive: 0, me.SoftwareImage_IsValid: 0}
Holger Hildebrandtfb402a62021-05-26 14:40:49 +000089 if err := oo.requestOnuImageAttributes(ctx, uint16(i), &image); err != nil {
90 logger.Errorw(ctx, err.Error(), log.Fields{"requestedAttributes": oo.requestedAttributes, "device-id": oo.deviceID})
91 return nil, err
92 }
Holger Hildebrandt3ac49bd2022-02-07 17:46:43 +000093 oo.requestedAttributes = me.AttributeValueMap{me.SoftwareImage_ProductCode: ""}
Holger Hildebrandtfb402a62021-05-26 14:40:49 +000094 if err := oo.requestOnuImageAttributes(ctx, uint16(i), &image); err != nil {
95 logger.Errorw(ctx, err.Error(), log.Fields{"requestedAttributes": oo.requestedAttributes, "device-id": oo.deviceID})
96 return nil, err
97 }
Holger Hildebrandt3ac49bd2022-02-07 17:46:43 +000098 oo.requestedAttributes = me.AttributeValueMap{me.SoftwareImage_ImageHash: 0}
Holger Hildebrandtfb402a62021-05-26 14:40:49 +000099 if err := oo.requestOnuImageAttributes(ctx, uint16(i), &image); err != nil {
100 logger.Errorw(ctx, err.Error(), log.Fields{"requestedAttributes": oo.requestedAttributes, "device-id": oo.deviceID})
101 return nil, err
102 }
103 images.Items = append(images.Items, &image)
104 }
105 logger.Debugw(ctx, "images of the ONU", log.Fields{"images": images})
Holger Hildebrandt05011352021-06-15 09:40:24 +0000106 oo.updateOnuSwImagePersistentData(ctx)
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000107 return &images, nil
108}
109
110func (oo *OnuImageStatus) requestOnuImageAttributes(ctx context.Context, imageID uint16, image *voltha.OnuImage) error {
111 oo.mutexPLastTxMeInstance.Lock()
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000112 meInstance, err := oo.pOmciCC.SendGetMe(log.WithSpanFromContext(context.TODO(), ctx), me.SoftwareImageClassID,
Holger Hildebrandtd930cb22022-06-17 09:24:50 +0000113 imageID, oo.requestedAttributes, oo.pDeviceHandler.GetOmciTimeout(), true, oo.respChannel, oo.isExtendedOmci)
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000114 if err != nil {
115 oo.mutexPLastTxMeInstance.Unlock()
116 logger.Errorw(ctx, "can't send omci request to get data for image id", log.Fields{"image-id": imageID, "device-id": oo.deviceID})
117 return fmt.Errorf("can't-send-omci-request-to-get-data-for-image-id-%d", imageID)
118 }
119 oo.pLastTxMeInstance = meInstance
120 oo.mutexPLastTxMeInstance.Unlock()
121
122 if err = oo.waitForGetOnuImageStatus(ctx, image); err != nil {
123 logger.Errorw(ctx, err.Error(), log.Fields{"device-id": oo.deviceID})
124 return err
125 }
126 return nil
127}
128
129func (oo *OnuImageStatus) waitForGetOnuImageStatus(ctx context.Context, image *voltha.OnuImage) error {
130 oo.setWaitingForResp(true)
131 select {
132 // maybe be also some outside cancel (but no context modeled for the moment ...)
133 case <-ctx.Done():
134 logger.Errorw(ctx, "waitForGetOnuImageStatus context done", log.Fields{"device-id": oo.deviceID})
135 oo.setWaitingForResp(false)
136 return fmt.Errorf("wait-for-image-status-context-done")
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000137 case <-time.After(oo.pOmciCC.GetMaxOmciTimeoutWithRetries() * time.Second):
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000138 logger.Errorw(ctx, "waitForGetOnuImageStatus timeout", log.Fields{"device-id": oo.deviceID})
139 oo.setWaitingForResp(false)
140 return fmt.Errorf("wait-for-image-status-timeout")
141 case message, ok := <-oo.respChannel:
142 if !ok {
143 logger.Errorw(ctx, "waitForGetOnuImageStatus response error", log.Fields{"device-id": oo.deviceID})
144 oo.setWaitingForResp(false)
145 return fmt.Errorf("wait-for-image-status-response-error")
146 }
147 switch message.Type {
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000148 case cmn.OMCI:
149 msg, _ := message.Data.(cmn.OmciMessage)
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000150 oo.setWaitingForResp(false)
151 return oo.processGetOnuImageStatusResp(ctx, msg, image)
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000152 case cmn.TestMsg:
153 msg, _ := message.Data.(cmn.TestMessage)
154 if msg.TestMessageVal == cmn.AbortMessageProcessing {
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000155 logger.Info(ctx, "waitForGetOnuImageStatus abort msg received", log.Fields{"device-id": oo.deviceID})
156 oo.setWaitingForResp(false)
157 return fmt.Errorf("wait-for-image-status-abort-msg-received")
158 }
159 default:
160 logger.Errorw(ctx, "waitForGetOnuImageStatus wrong msg type received", log.Fields{"msgType": message.Type, "device-id": oo.deviceID})
161 oo.setWaitingForResp(false)
162 return fmt.Errorf("wait-for-image-status-response-error")
163 }
164 }
165 logger.Errorw(ctx, "waitForGetOnuImageStatus processing error", log.Fields{"device-id": oo.deviceID})
166 oo.setWaitingForResp(false)
167 return fmt.Errorf("wait-for-image-status-processing-error")
168
169}
170
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000171func (oo *OnuImageStatus) processGetOnuImageStatusResp(ctx context.Context, msg cmn.OmciMessage, image *voltha.OnuImage) error {
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000172 if msg.OmciMsg.MessageType != omci.GetResponseType {
173 logger.Errorw(ctx, "processGetOnuImageStatusResp wrong response type received", log.Fields{"respType": msg.OmciMsg.MessageType, "device-id": oo.deviceID})
174 return fmt.Errorf("process-image-status-response-error")
175 }
176 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeGetResponse)
177 if msgLayer == nil {
178 logger.Errorw(ctx, "processGetOnuImageStatusResp omci Msg layer not found", log.Fields{"device-id": oo.deviceID})
179 return fmt.Errorf("process-image-status-response-error")
180 }
181 msgObj, msgOk := msgLayer.(*omci.GetResponse)
182 if !msgOk {
183 logger.Errorw(ctx, "processGetOnuImageStatusResp omci msgObj layer could not be found", log.Fields{"device-id": oo.deviceID})
184 return fmt.Errorf("process-image-status-response-error")
185 }
186 oo.mutexPLastTxMeInstance.RLock()
187 if oo.pLastTxMeInstance != nil {
188 if msgObj.EntityClass == oo.pLastTxMeInstance.GetClassID() &&
189 msgObj.EntityInstance == oo.pLastTxMeInstance.GetEntityID() {
190 oo.mutexPLastTxMeInstance.RUnlock()
Holger Hildebrandt05011352021-06-15 09:40:24 +0000191 if err := oo.processAttributesReceived(ctx, msgObj, image); err != nil {
192 logger.Errorw(ctx, err.Error(), log.Fields{"device-id": oo.deviceID})
193 return err
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000194 }
195 return nil
196 }
197 oo.mutexPLastTxMeInstance.RUnlock()
198 logger.Errorw(ctx, "processGetOnuImageStatusResp wrong MeInstance received", log.Fields{"device-id": oo.deviceID})
199 return fmt.Errorf("process-image-status-response-error")
200 }
201 oo.mutexPLastTxMeInstance.RUnlock()
202 logger.Errorw(ctx, "processGetOnuImageStatusResp pLastTxMeInstance is nil", log.Fields{"device-id": oo.deviceID})
203 return fmt.Errorf("process-image-status-response-error")
204}
Holger Hildebrandt05011352021-06-15 09:40:24 +0000205
206func (oo *OnuImageStatus) processAttributesReceived(ctx context.Context, msgObj *omci.GetResponse, image *voltha.OnuImage) error {
207 meAttributes := msgObj.Attributes
208 logger.Debugw(ctx, "processAttributesReceived", log.Fields{"attributes": meAttributes, "device-id": oo.deviceID})
209
Holger Hildebrandt3ac49bd2022-02-07 17:46:43 +0000210 if _, ok := oo.requestedAttributes[me.SoftwareImage_Version]; ok {
Holger Hildebrandt94688c72021-12-17 12:13:02 +0000211 if msgObj.Result != me.Success {
Holger Hildebrandtfdb4bba2022-03-10 12:12:59 +0000212 logger.Errorw(ctx, "processAttributesReceived - retrieval of mandatory attributes not successful",
Holger Hildebrandt05011352021-06-15 09:40:24 +0000213 log.Fields{"device-id": oo.deviceID})
Holger Hildebrandtfdb4bba2022-03-10 12:12:59 +0000214 return fmt.Errorf("retrieve-mandatory-attributes-not-successful")
Holger Hildebrandt05011352021-06-15 09:40:24 +0000215 }
Holger Hildebrandtfdb4bba2022-03-10 12:12:59 +0000216 if !oo.pDevEntry.HandleSwImageIndications(ctx, msgObj.EntityInstance, meAttributes) {
217 logger.Errorw(ctx, "processAttributesReceived - not all mandatory attributes present in SoftwareImage instance", log.Fields{"device-id": oo.deviceID})
218 return fmt.Errorf("not-all-mandatory-attributes-present")
219 }
Holger Hildebrandt94688c72021-12-17 12:13:02 +0000220 }
221 for k := range oo.requestedAttributes {
Holger Hildebrandt05011352021-06-15 09:40:24 +0000222 switch k {
Holger Hildebrandt05011352021-06-15 09:40:24 +0000223 // mandatory attributes
Holger Hildebrandt3ac49bd2022-02-07 17:46:43 +0000224 case me.SoftwareImage_IsCommitted:
225 if meAttributes[me.SoftwareImage_IsCommitted].(uint8) == cmn.SwIsCommitted {
Holger Hildebrandt05011352021-06-15 09:40:24 +0000226 image.IsCommited = true
227 } else {
228 image.IsCommited = false
229 }
Holger Hildebrandt3ac49bd2022-02-07 17:46:43 +0000230 case me.SoftwareImage_IsActive:
231 if meAttributes[me.SoftwareImage_IsActive].(uint8) == cmn.SwIsActive {
Holger Hildebrandt05011352021-06-15 09:40:24 +0000232 image.IsActive = true
233 } else {
234 image.IsActive = false
235 }
Holger Hildebrandt3ac49bd2022-02-07 17:46:43 +0000236 case me.SoftwareImage_IsValid:
237 if meAttributes[me.SoftwareImage_IsValid].(uint8) == cmn.SwIsValid {
Holger Hildebrandt05011352021-06-15 09:40:24 +0000238 image.IsValid = true
239 } else {
240 image.IsValid = false
241 }
Holger Hildebrandt3ac49bd2022-02-07 17:46:43 +0000242 case me.SoftwareImage_Version:
243 image.Version = cmn.TrimStringFromMeOctet(meAttributes[me.SoftwareImage_Version])
Holger Hildebrandt05011352021-06-15 09:40:24 +0000244
245 // optional attributes
Holger Hildebrandt3ac49bd2022-02-07 17:46:43 +0000246 case me.SoftwareImage_ProductCode:
Akash Soni35407db2024-12-11 13:01:00 +0530247 // Check if me.SoftwareImage_ImageHash exists in meAttributes
248 if prodAttr, found := meAttributes[me.SoftwareImage_ProductCode]; found {
249 // Process the prod attribute if msgObj.Result is successful
250 if msgObj.Result == me.Success {
251 image.ProductCode = cmn.TrimStringFromMeOctet(prodAttr)
252 } 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 }
Holger Hildebrandt05011352021-06-15 09:40:24 +0000258 }
Holger Hildebrandt3ac49bd2022-02-07 17:46:43 +0000259 case me.SoftwareImage_ImageHash:
Holger Hildebrandt05011352021-06-15 09:40:24 +0000260 if msgObj.Result == me.Success {
Holger Hildebrandt3ac49bd2022-02-07 17:46:43 +0000261 bytes, _ := me.InterfaceToOctets(meAttributes[me.SoftwareImage_ImageHash])
Holger Hildebrandt05011352021-06-15 09:40:24 +0000262 image.Hash = hex.EncodeToString(bytes)
263 } else {
264 sResult := msgObj.Result.String()
265 logger.Infow(ctx, "processAttributesReceived - ImageHash",
266 log.Fields{"result": sResult, "unsupported attribute mask": msgObj.UnsupportedAttributeMask, "device-id": oo.deviceID})
267 image.Hash = cResponse + sResult
268 }
269 }
270 }
271 return nil
272}
273
Holger Hildebrandt05011352021-06-15 09:40:24 +0000274func (oo *OnuImageStatus) updateOnuSwImagePersistentData(ctx context.Context) {
275
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000276 activeImageVersion := oo.pDevEntry.GetActiveImageVersion(ctx)
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000277 persActiveSwVersion := oo.pDevEntry.GetPersActiveSwVersion()
278 if persActiveSwVersion != activeImageVersion {
Holger Hildebrandt05011352021-06-15 09:40:24 +0000279 logger.Infow(ctx, "Active SW version has been changed at ONU - update persistent data",
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000280 log.Fields{"old version": persActiveSwVersion,
Holger Hildebrandt05011352021-06-15 09:40:24 +0000281 "new version": activeImageVersion, "device-id": oo.deviceID})
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000282 oo.pDevEntry.SetPersActiveSwVersion(activeImageVersion)
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000283 if err := oo.pDeviceHandler.StorePersistentData(ctx); err != nil {
Holger Hildebrandt05011352021-06-15 09:40:24 +0000284 logger.Warnw(ctx, "store persistent data error - continue for now as there will be additional write attempts",
285 log.Fields{"device-id": oo.deviceID, "err": err})
286 }
287 return
288 }
Holger Hildebrandt05011352021-06-15 09:40:24 +0000289}
290
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000291func (oo *OnuImageStatus) setWaitingForResp(value bool) {
292 oo.mutexWaitingForResp.Lock()
293 oo.waitingForResp = value
294 oo.mutexWaitingForResp.Unlock()
295}
Holger Hildebrandt05011352021-06-15 09:40:24 +0000296
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000297func (oo *OnuImageStatus) isWaitingForResp() bool {
298 oo.mutexWaitingForResp.RLock()
299 value := oo.waitingForResp
300 oo.mutexWaitingForResp.RUnlock()
301 return value
302}
303
Joey Armstrong89c812c2024-01-12 19:00:20 -0500304// CancelProcessing ensures that interrupted processing is canceled while waiting for a response
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000305func (oo *OnuImageStatus) CancelProcessing(ctx context.Context) {
Holger Hildebrandt12609a12022-03-25 13:23:25 +0000306 logger.Debugw(ctx, "CancelProcessing entered", log.Fields{"device-id": oo.deviceID})
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000307 if oo.isWaitingForResp() {
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000308 abortMsg := cmn.Message{
309 Type: cmn.TestMsg,
310 Data: cmn.TestMessage{
311 TestMessageVal: cmn.AbortMessageProcessing,
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000312 },
313 }
314 oo.respChannel <- abortMsg
315 }
316}