blob: ae798d0d39e396b89318a7093a67f2122dd74dec [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
Holger Hildebrandt05011352021-06-15 09:40:24 +000048const cResponse = "response: "
Holger Hildebrandtfb402a62021-05-26 14:40:49 +000049
50//NewOnuImageStatus creates a new instance of OnuImageStatus
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +000051func NewOnuImageStatus(apDeviceHandler cmn.IdeviceHandler, apDevEntry cmn.IonuDeviceEntry) *OnuImageStatus {
Holger Hildebrandtfb402a62021-05-26 14:40:49 +000052 return &OnuImageStatus{
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +000053 deviceID: apDeviceHandler.GetDeviceID(),
54 pDeviceHandler: apDeviceHandler,
55 pDevEntry: apDevEntry,
56 pOmciCC: apDevEntry.GetDevOmciCC(),
Holger Hildebrandtfb402a62021-05-26 14:40:49 +000057 requestedAttributes: make(me.AttributeValueMap),
58 waitingForResp: false,
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +000059 respChannel: make(chan cmn.Message),
Holger Hildebrandtfb402a62021-05-26 14:40:49 +000060 }
61}
Holger Hildebrandt05011352021-06-15 09:40:24 +000062
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +000063// GetOnuImageStatus - TODO: add comment
64func (oo *OnuImageStatus) GetOnuImageStatus(ctx context.Context) (*voltha.OnuImages, error) {
Holger Hildebrandtfb402a62021-05-26 14:40:49 +000065
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +000066 if !oo.pDeviceHandler.IsReadyForOmciConfig() {
Holger Hildebrandt05011352021-06-15 09:40:24 +000067 logger.Errorw(ctx, "command rejected - improper device state", log.Fields{"device-id": oo.deviceID})
68 return nil, fmt.Errorf("command-rejected-improper-device-state")
69 }
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +000070 if oo.pOmciCC == nil {
Holger Hildebrandtfb402a62021-05-26 14:40:49 +000071 logger.Errorw(ctx, "omciCC not ready to receive omci messages", log.Fields{"device-id": oo.deviceID})
72 return nil, fmt.Errorf("omciCC-not-ready-to-receive-omci-messages")
73 }
Holger Hildebrandt05011352021-06-15 09:40:24 +000074 var images voltha.OnuImages
75
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +000076 for i := cmn.FirstSwImageMeID; i <= cmn.SecondSwImageMeID; i++ {
77 logger.Debugw(ctx, "GetOnuImageStatus for image id", log.Fields{"image-id": i, "device-id": oo.deviceID})
Holger Hildebrandtfb402a62021-05-26 14:40:49 +000078
79 var image voltha.OnuImage
80
81 // TODO: Since the summed length of the attributes exceeds the capacity of a single response,
82 // it is distributed on several requests here. It should be discussed whether, in the course of a refactoring,
83 // a global mechanism should be implemented that automates this distribution - which would entail quite some
84 // changes on the respective receiver sides.
85
Holger Hildebrandt3ac49bd2022-02-07 17:46:43 +000086 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 +000087 if err := oo.requestOnuImageAttributes(ctx, uint16(i), &image); err != nil {
88 logger.Errorw(ctx, err.Error(), log.Fields{"requestedAttributes": oo.requestedAttributes, "device-id": oo.deviceID})
89 return nil, err
90 }
Holger Hildebrandt3ac49bd2022-02-07 17:46:43 +000091 oo.requestedAttributes = me.AttributeValueMap{me.SoftwareImage_ProductCode: ""}
Holger Hildebrandtfb402a62021-05-26 14:40:49 +000092 if err := oo.requestOnuImageAttributes(ctx, uint16(i), &image); err != nil {
93 logger.Errorw(ctx, err.Error(), log.Fields{"requestedAttributes": oo.requestedAttributes, "device-id": oo.deviceID})
94 return nil, err
95 }
Holger Hildebrandt3ac49bd2022-02-07 17:46:43 +000096 oo.requestedAttributes = me.AttributeValueMap{me.SoftwareImage_ImageHash: 0}
Holger Hildebrandtfb402a62021-05-26 14:40:49 +000097 if err := oo.requestOnuImageAttributes(ctx, uint16(i), &image); err != nil {
98 logger.Errorw(ctx, err.Error(), log.Fields{"requestedAttributes": oo.requestedAttributes, "device-id": oo.deviceID})
99 return nil, err
100 }
101 images.Items = append(images.Items, &image)
102 }
103 logger.Debugw(ctx, "images of the ONU", log.Fields{"images": images})
Holger Hildebrandt05011352021-06-15 09:40:24 +0000104 oo.updateOnuSwImagePersistentData(ctx)
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000105 return &images, nil
106}
107
108func (oo *OnuImageStatus) requestOnuImageAttributes(ctx context.Context, imageID uint16, image *voltha.OnuImage) error {
109 oo.mutexPLastTxMeInstance.Lock()
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000110 meInstance, err := oo.pOmciCC.SendGetMe(log.WithSpanFromContext(context.TODO(), ctx), me.SoftwareImageClassID,
111 imageID, oo.requestedAttributes, oo.pDeviceHandler.GetOmciTimeout(), true, oo.respChannel)
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000112 if err != nil {
113 oo.mutexPLastTxMeInstance.Unlock()
114 logger.Errorw(ctx, "can't send omci request to get data for image id", log.Fields{"image-id": imageID, "device-id": oo.deviceID})
115 return fmt.Errorf("can't-send-omci-request-to-get-data-for-image-id-%d", imageID)
116 }
117 oo.pLastTxMeInstance = meInstance
118 oo.mutexPLastTxMeInstance.Unlock()
119
120 if err = oo.waitForGetOnuImageStatus(ctx, image); err != nil {
121 logger.Errorw(ctx, err.Error(), log.Fields{"device-id": oo.deviceID})
122 return err
123 }
124 return nil
125}
126
127func (oo *OnuImageStatus) waitForGetOnuImageStatus(ctx context.Context, image *voltha.OnuImage) error {
128 oo.setWaitingForResp(true)
129 select {
130 // maybe be also some outside cancel (but no context modeled for the moment ...)
131 case <-ctx.Done():
132 logger.Errorw(ctx, "waitForGetOnuImageStatus context done", log.Fields{"device-id": oo.deviceID})
133 oo.setWaitingForResp(false)
134 return fmt.Errorf("wait-for-image-status-context-done")
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000135 case <-time.After(oo.pOmciCC.GetMaxOmciTimeoutWithRetries() * time.Second):
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000136 logger.Errorw(ctx, "waitForGetOnuImageStatus timeout", log.Fields{"device-id": oo.deviceID})
137 oo.setWaitingForResp(false)
138 return fmt.Errorf("wait-for-image-status-timeout")
139 case message, ok := <-oo.respChannel:
140 if !ok {
141 logger.Errorw(ctx, "waitForGetOnuImageStatus response error", log.Fields{"device-id": oo.deviceID})
142 oo.setWaitingForResp(false)
143 return fmt.Errorf("wait-for-image-status-response-error")
144 }
145 switch message.Type {
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000146 case cmn.OMCI:
147 msg, _ := message.Data.(cmn.OmciMessage)
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000148 oo.setWaitingForResp(false)
149 return oo.processGetOnuImageStatusResp(ctx, msg, image)
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000150 case cmn.TestMsg:
151 msg, _ := message.Data.(cmn.TestMessage)
152 if msg.TestMessageVal == cmn.AbortMessageProcessing {
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000153 logger.Info(ctx, "waitForGetOnuImageStatus abort msg received", log.Fields{"device-id": oo.deviceID})
154 oo.setWaitingForResp(false)
155 return fmt.Errorf("wait-for-image-status-abort-msg-received")
156 }
157 default:
158 logger.Errorw(ctx, "waitForGetOnuImageStatus wrong msg type received", log.Fields{"msgType": message.Type, "device-id": oo.deviceID})
159 oo.setWaitingForResp(false)
160 return fmt.Errorf("wait-for-image-status-response-error")
161 }
162 }
163 logger.Errorw(ctx, "waitForGetOnuImageStatus processing error", log.Fields{"device-id": oo.deviceID})
164 oo.setWaitingForResp(false)
165 return fmt.Errorf("wait-for-image-status-processing-error")
166
167}
168
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000169func (oo *OnuImageStatus) processGetOnuImageStatusResp(ctx context.Context, msg cmn.OmciMessage, image *voltha.OnuImage) error {
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000170 if msg.OmciMsg.MessageType != omci.GetResponseType {
171 logger.Errorw(ctx, "processGetOnuImageStatusResp wrong response type received", log.Fields{"respType": msg.OmciMsg.MessageType, "device-id": oo.deviceID})
172 return fmt.Errorf("process-image-status-response-error")
173 }
174 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeGetResponse)
175 if msgLayer == nil {
176 logger.Errorw(ctx, "processGetOnuImageStatusResp omci Msg layer not found", log.Fields{"device-id": oo.deviceID})
177 return fmt.Errorf("process-image-status-response-error")
178 }
179 msgObj, msgOk := msgLayer.(*omci.GetResponse)
180 if !msgOk {
181 logger.Errorw(ctx, "processGetOnuImageStatusResp omci msgObj layer could not be found", log.Fields{"device-id": oo.deviceID})
182 return fmt.Errorf("process-image-status-response-error")
183 }
184 oo.mutexPLastTxMeInstance.RLock()
185 if oo.pLastTxMeInstance != nil {
186 if msgObj.EntityClass == oo.pLastTxMeInstance.GetClassID() &&
187 msgObj.EntityInstance == oo.pLastTxMeInstance.GetEntityID() {
188 oo.mutexPLastTxMeInstance.RUnlock()
Holger Hildebrandt05011352021-06-15 09:40:24 +0000189 if err := oo.processAttributesReceived(ctx, msgObj, image); err != nil {
190 logger.Errorw(ctx, err.Error(), log.Fields{"device-id": oo.deviceID})
191 return err
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000192 }
193 return nil
194 }
195 oo.mutexPLastTxMeInstance.RUnlock()
196 logger.Errorw(ctx, "processGetOnuImageStatusResp wrong MeInstance received", log.Fields{"device-id": oo.deviceID})
197 return fmt.Errorf("process-image-status-response-error")
198 }
199 oo.mutexPLastTxMeInstance.RUnlock()
200 logger.Errorw(ctx, "processGetOnuImageStatusResp pLastTxMeInstance is nil", log.Fields{"device-id": oo.deviceID})
201 return fmt.Errorf("process-image-status-response-error")
202}
Holger Hildebrandt05011352021-06-15 09:40:24 +0000203
204func (oo *OnuImageStatus) processAttributesReceived(ctx context.Context, msgObj *omci.GetResponse, image *voltha.OnuImage) error {
205 meAttributes := msgObj.Attributes
206 logger.Debugw(ctx, "processAttributesReceived", log.Fields{"attributes": meAttributes, "device-id": oo.deviceID})
207
Holger Hildebrandt3ac49bd2022-02-07 17:46:43 +0000208 if _, ok := oo.requestedAttributes[me.SoftwareImage_Version]; ok {
Holger Hildebrandt94688c72021-12-17 12:13:02 +0000209 if msgObj.Result != me.Success {
Holger Hildebrandtfdb4bba2022-03-10 12:12:59 +0000210 logger.Errorw(ctx, "processAttributesReceived - retrieval of mandatory attributes not successful",
Holger Hildebrandt05011352021-06-15 09:40:24 +0000211 log.Fields{"device-id": oo.deviceID})
Holger Hildebrandtfdb4bba2022-03-10 12:12:59 +0000212 return fmt.Errorf("retrieve-mandatory-attributes-not-successful")
Holger Hildebrandt05011352021-06-15 09:40:24 +0000213 }
Holger Hildebrandtfdb4bba2022-03-10 12:12:59 +0000214 if !oo.pDevEntry.HandleSwImageIndications(ctx, msgObj.EntityInstance, meAttributes) {
215 logger.Errorw(ctx, "processAttributesReceived - not all mandatory attributes present in SoftwareImage instance", log.Fields{"device-id": oo.deviceID})
216 return fmt.Errorf("not-all-mandatory-attributes-present")
217 }
Holger Hildebrandt94688c72021-12-17 12:13:02 +0000218 }
219 for k := range oo.requestedAttributes {
Holger Hildebrandt05011352021-06-15 09:40:24 +0000220 switch k {
Holger Hildebrandt05011352021-06-15 09:40:24 +0000221 // mandatory attributes
Holger Hildebrandt3ac49bd2022-02-07 17:46:43 +0000222 case me.SoftwareImage_IsCommitted:
223 if meAttributes[me.SoftwareImage_IsCommitted].(uint8) == cmn.SwIsCommitted {
Holger Hildebrandt05011352021-06-15 09:40:24 +0000224 image.IsCommited = true
225 } else {
226 image.IsCommited = false
227 }
Holger Hildebrandt3ac49bd2022-02-07 17:46:43 +0000228 case me.SoftwareImage_IsActive:
229 if meAttributes[me.SoftwareImage_IsActive].(uint8) == cmn.SwIsActive {
Holger Hildebrandt05011352021-06-15 09:40:24 +0000230 image.IsActive = true
231 } else {
232 image.IsActive = false
233 }
Holger Hildebrandt3ac49bd2022-02-07 17:46:43 +0000234 case me.SoftwareImage_IsValid:
235 if meAttributes[me.SoftwareImage_IsValid].(uint8) == cmn.SwIsValid {
Holger Hildebrandt05011352021-06-15 09:40:24 +0000236 image.IsValid = true
237 } else {
238 image.IsValid = false
239 }
Holger Hildebrandt3ac49bd2022-02-07 17:46:43 +0000240 case me.SoftwareImage_Version:
241 image.Version = cmn.TrimStringFromMeOctet(meAttributes[me.SoftwareImage_Version])
Holger Hildebrandt05011352021-06-15 09:40:24 +0000242
243 // optional attributes
Holger Hildebrandt3ac49bd2022-02-07 17:46:43 +0000244 case me.SoftwareImage_ProductCode:
Holger Hildebrandt05011352021-06-15 09:40:24 +0000245 if msgObj.Result == me.Success {
Holger Hildebrandt3ac49bd2022-02-07 17:46:43 +0000246 image.ProductCode = cmn.TrimStringFromMeOctet(meAttributes[me.SoftwareImage_ProductCode])
Holger Hildebrandt05011352021-06-15 09:40:24 +0000247 } else {
248 sResult := msgObj.Result.String()
249 logger.Infow(ctx, "processAttributesReceived - ProductCode",
250 log.Fields{"result": sResult, "unsupported attribute mask": msgObj.UnsupportedAttributeMask, "device-id": oo.deviceID})
251 image.ProductCode = cResponse + sResult
252 }
Holger Hildebrandt3ac49bd2022-02-07 17:46:43 +0000253 case me.SoftwareImage_ImageHash:
Holger Hildebrandt05011352021-06-15 09:40:24 +0000254 if msgObj.Result == me.Success {
Holger Hildebrandt3ac49bd2022-02-07 17:46:43 +0000255 bytes, _ := me.InterfaceToOctets(meAttributes[me.SoftwareImage_ImageHash])
Holger Hildebrandt05011352021-06-15 09:40:24 +0000256 image.Hash = hex.EncodeToString(bytes)
257 } else {
258 sResult := msgObj.Result.String()
259 logger.Infow(ctx, "processAttributesReceived - ImageHash",
260 log.Fields{"result": sResult, "unsupported attribute mask": msgObj.UnsupportedAttributeMask, "device-id": oo.deviceID})
261 image.Hash = cResponse + sResult
262 }
263 }
264 }
265 return nil
266}
267
Holger Hildebrandt05011352021-06-15 09:40:24 +0000268func (oo *OnuImageStatus) updateOnuSwImagePersistentData(ctx context.Context) {
269
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000270 activeImageVersion := oo.pDevEntry.GetActiveImageVersion(ctx)
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000271 persActiveSwVersion := oo.pDevEntry.GetPersActiveSwVersion()
272 if persActiveSwVersion != activeImageVersion {
Holger Hildebrandt05011352021-06-15 09:40:24 +0000273 logger.Infow(ctx, "Active SW version has been changed at ONU - update persistent data",
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000274 log.Fields{"old version": persActiveSwVersion,
Holger Hildebrandt05011352021-06-15 09:40:24 +0000275 "new version": activeImageVersion, "device-id": oo.deviceID})
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000276 oo.pDevEntry.SetPersActiveSwVersion(activeImageVersion)
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000277 if err := oo.pDeviceHandler.StorePersistentData(ctx); err != nil {
Holger Hildebrandt05011352021-06-15 09:40:24 +0000278 logger.Warnw(ctx, "store persistent data error - continue for now as there will be additional write attempts",
279 log.Fields{"device-id": oo.deviceID, "err": err})
280 }
281 return
282 }
Holger Hildebrandt05011352021-06-15 09:40:24 +0000283}
284
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000285func (oo *OnuImageStatus) setWaitingForResp(value bool) {
286 oo.mutexWaitingForResp.Lock()
287 oo.waitingForResp = value
288 oo.mutexWaitingForResp.Unlock()
289}
Holger Hildebrandt05011352021-06-15 09:40:24 +0000290
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000291func (oo *OnuImageStatus) isWaitingForResp() bool {
292 oo.mutexWaitingForResp.RLock()
293 value := oo.waitingForResp
294 oo.mutexWaitingForResp.RUnlock()
295 return value
296}
297
298//CancelProcessing ensures that interrupted processing is canceled while waiting for a response
299func (oo *OnuImageStatus) CancelProcessing(ctx context.Context) {
300 if oo.isWaitingForResp() {
Holger Hildebrandt4b5e73f2021-08-19 06:51:21 +0000301 abortMsg := cmn.Message{
302 Type: cmn.TestMsg,
303 Data: cmn.TestMessage{
304 TestMessageVal: cmn.AbortMessageProcessing,
Holger Hildebrandtfb402a62021-05-26 14:40:49 +0000305 },
306 }
307 oo.respChannel <- abortMsg
308 }
309}