blob: fb34a264ce01c38b51d1148d44f079f3a0d9217f [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
17//Package adaptercoreonu provides the utility for onu devices, flows and statistics
18package adaptercoreonu
19
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"
29 "github.com/opencord/voltha-lib-go/v4/pkg/log"
30 "github.com/opencord/voltha-protos/v4/go/voltha"
31)
32
33//OnuImageStatus implements methods to get status info of onu images
34type OnuImageStatus struct {
35 pDevEntry *OnuDeviceEntry
36 deviceID string
37 requestedAttributes me.AttributeValueMap
38 mutexWaitingForResp sync.RWMutex
39 waitingForResp bool
40 respChannel chan Message
41 mutexPLastTxMeInstance sync.RWMutex
42 pLastTxMeInstance *me.ManagedEntity
43}
44
45const (
46 cImgVersion = "Version"
47 cImgIsCommitted = "IsCommitted"
48 cImgIsActive = "IsActive"
49 cImgIsValid = "IsValid"
50 cImgProductCode = "ProductCode"
51 cImgImageHash = "ImageHash"
52)
53
54//NewOnuImageStatus creates a new instance of OnuImageStatus
55func NewOnuImageStatus(pDevEntry *OnuDeviceEntry) *OnuImageStatus {
56 return &OnuImageStatus{
57 pDevEntry: pDevEntry,
58 deviceID: pDevEntry.deviceID,
59 requestedAttributes: make(me.AttributeValueMap),
60 waitingForResp: false,
61 respChannel: make(chan Message),
62 }
63}
64func (oo *OnuImageStatus) getOnuImageStatus(ctx context.Context) (*voltha.OnuImages, error) {
65
66 var images voltha.OnuImages
67
68 if oo.pDevEntry.PDevOmciCC == nil {
69 logger.Errorw(ctx, "omciCC not ready to receive omci messages", log.Fields{"device-id": oo.deviceID})
70 return nil, fmt.Errorf("omciCC-not-ready-to-receive-omci-messages")
71 }
72 for i := firstSwImageMeID; i <= secondSwImageMeID; i++ {
73 logger.Debugw(ctx, "getOnuImageStatus for image id", log.Fields{"image-id": i, "device-id": oo.deviceID})
74
75 var image voltha.OnuImage
76
77 // TODO: Since the summed length of the attributes exceeds the capacity of a single response,
78 // it is distributed on several requests here. It should be discussed whether, in the course of a refactoring,
79 // a global mechanism should be implemented that automates this distribution - which would entail quite some
80 // changes on the respective receiver sides.
81
82 oo.requestedAttributes = me.AttributeValueMap{cImgVersion: "", cImgIsCommitted: 0, cImgIsActive: 0, cImgIsValid: 0}
83 if err := oo.requestOnuImageAttributes(ctx, uint16(i), &image); err != nil {
84 logger.Errorw(ctx, err.Error(), log.Fields{"requestedAttributes": oo.requestedAttributes, "device-id": oo.deviceID})
85 return nil, err
86 }
87 oo.requestedAttributes = me.AttributeValueMap{cImgProductCode: ""}
88 if err := oo.requestOnuImageAttributes(ctx, uint16(i), &image); err != nil {
89 logger.Errorw(ctx, err.Error(), log.Fields{"requestedAttributes": oo.requestedAttributes, "device-id": oo.deviceID})
90 return nil, err
91 }
92 oo.requestedAttributes = me.AttributeValueMap{cImgImageHash: 0}
93 if err := oo.requestOnuImageAttributes(ctx, uint16(i), &image); err != nil {
94 logger.Errorw(ctx, err.Error(), log.Fields{"requestedAttributes": oo.requestedAttributes, "device-id": oo.deviceID})
95 return nil, err
96 }
97 images.Items = append(images.Items, &image)
98 }
99 logger.Debugw(ctx, "images of the ONU", log.Fields{"images": images})
100 return &images, nil
101}
102
103func (oo *OnuImageStatus) requestOnuImageAttributes(ctx context.Context, imageID uint16, image *voltha.OnuImage) error {
104 oo.mutexPLastTxMeInstance.Lock()
105 meInstance, err := oo.pDevEntry.PDevOmciCC.sendGetMe(log.WithSpanFromContext(context.TODO(), ctx), me.SoftwareImageClassID,
106 imageID, oo.requestedAttributes, oo.pDevEntry.pOpenOnuAc.omciTimeout, true, oo.respChannel)
107 if err != nil {
108 oo.mutexPLastTxMeInstance.Unlock()
109 logger.Errorw(ctx, "can't send omci request to get data for image id", log.Fields{"image-id": imageID, "device-id": oo.deviceID})
110 return fmt.Errorf("can't-send-omci-request-to-get-data-for-image-id-%d", imageID)
111 }
112 oo.pLastTxMeInstance = meInstance
113 oo.mutexPLastTxMeInstance.Unlock()
114
115 if err = oo.waitForGetOnuImageStatus(ctx, image); err != nil {
116 logger.Errorw(ctx, err.Error(), log.Fields{"device-id": oo.deviceID})
117 return err
118 }
119 return nil
120}
121
122func (oo *OnuImageStatus) waitForGetOnuImageStatus(ctx context.Context, image *voltha.OnuImage) error {
123 oo.setWaitingForResp(true)
124 select {
125 // maybe be also some outside cancel (but no context modeled for the moment ...)
126 case <-ctx.Done():
127 logger.Errorw(ctx, "waitForGetOnuImageStatus context done", log.Fields{"device-id": oo.deviceID})
128 oo.setWaitingForResp(false)
129 return fmt.Errorf("wait-for-image-status-context-done")
130 case <-time.After(oo.pDevEntry.PDevOmciCC.GetMaxOmciTimeoutWithRetries() * time.Second):
131 logger.Errorw(ctx, "waitForGetOnuImageStatus timeout", log.Fields{"device-id": oo.deviceID})
132 oo.setWaitingForResp(false)
133 return fmt.Errorf("wait-for-image-status-timeout")
134 case message, ok := <-oo.respChannel:
135 if !ok {
136 logger.Errorw(ctx, "waitForGetOnuImageStatus response error", log.Fields{"device-id": oo.deviceID})
137 oo.setWaitingForResp(false)
138 return fmt.Errorf("wait-for-image-status-response-error")
139 }
140 switch message.Type {
141 case OMCI:
142 msg, _ := message.Data.(OmciMessage)
143 oo.setWaitingForResp(false)
144 return oo.processGetOnuImageStatusResp(ctx, msg, image)
145 case TestMsg:
146 msg, _ := message.Data.(TestMessage)
147 if msg.TestMessageVal == AbortMessageProcessing {
148 logger.Info(ctx, "waitForGetOnuImageStatus abort msg received", log.Fields{"device-id": oo.deviceID})
149 oo.setWaitingForResp(false)
150 return fmt.Errorf("wait-for-image-status-abort-msg-received")
151 }
152 default:
153 logger.Errorw(ctx, "waitForGetOnuImageStatus wrong msg type received", log.Fields{"msgType": message.Type, "device-id": oo.deviceID})
154 oo.setWaitingForResp(false)
155 return fmt.Errorf("wait-for-image-status-response-error")
156 }
157 }
158 logger.Errorw(ctx, "waitForGetOnuImageStatus processing error", log.Fields{"device-id": oo.deviceID})
159 oo.setWaitingForResp(false)
160 return fmt.Errorf("wait-for-image-status-processing-error")
161
162}
163
164func (oo *OnuImageStatus) processGetOnuImageStatusResp(ctx context.Context, msg OmciMessage, image *voltha.OnuImage) error {
165 if msg.OmciMsg.MessageType != omci.GetResponseType {
166 logger.Errorw(ctx, "processGetOnuImageStatusResp wrong response type received", log.Fields{"respType": msg.OmciMsg.MessageType, "device-id": oo.deviceID})
167 return fmt.Errorf("process-image-status-response-error")
168 }
169 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeGetResponse)
170 if msgLayer == nil {
171 logger.Errorw(ctx, "processGetOnuImageStatusResp omci Msg layer not found", log.Fields{"device-id": oo.deviceID})
172 return fmt.Errorf("process-image-status-response-error")
173 }
174 msgObj, msgOk := msgLayer.(*omci.GetResponse)
175 if !msgOk {
176 logger.Errorw(ctx, "processGetOnuImageStatusResp omci msgObj layer could not be found", log.Fields{"device-id": oo.deviceID})
177 return fmt.Errorf("process-image-status-response-error")
178 }
179 oo.mutexPLastTxMeInstance.RLock()
180 if oo.pLastTxMeInstance != nil {
181 if msgObj.EntityClass == oo.pLastTxMeInstance.GetClassID() &&
182 msgObj.EntityInstance == oo.pLastTxMeInstance.GetEntityID() {
183 oo.mutexPLastTxMeInstance.RUnlock()
184
185 meAttributes := msgObj.Attributes
186 logger.Debugw(ctx, "processGetOnuImageStatusResp omci attributes received", log.Fields{"attributes": meAttributes, "device-id": oo.deviceID})
187
188 for k := range oo.requestedAttributes {
189 switch k {
190 case cImgIsCommitted:
191 if meAttributes[cImgIsCommitted].(uint8) == swIsCommitted {
192 image.IsCommited = true
193 } else {
194 image.IsCommited = false
195 }
196 case cImgIsActive:
197 if meAttributes[cImgIsActive].(uint8) == swIsActive {
198 image.IsActive = true
199 } else {
200 image.IsActive = false
201 }
202 case cImgIsValid:
203 if meAttributes[cImgIsValid].(uint8) == swIsValid {
204 image.IsValid = true
205 } else {
206 image.IsValid = false
207 }
208 case cImgVersion:
209 image.Version = TrimStringFromMeOctet(meAttributes[cImgVersion])
210 case cImgProductCode:
211 image.ProductCode = TrimStringFromMeOctet(meAttributes[cImgProductCode])
212 case cImgImageHash:
213 bytes, _ := me.InterfaceToOctets(meAttributes[cImgImageHash])
214 image.Hash = hex.EncodeToString(bytes)
215 }
216 }
217 return nil
218 }
219 oo.mutexPLastTxMeInstance.RUnlock()
220 logger.Errorw(ctx, "processGetOnuImageStatusResp wrong MeInstance received", log.Fields{"device-id": oo.deviceID})
221 return fmt.Errorf("process-image-status-response-error")
222 }
223 oo.mutexPLastTxMeInstance.RUnlock()
224 logger.Errorw(ctx, "processGetOnuImageStatusResp pLastTxMeInstance is nil", log.Fields{"device-id": oo.deviceID})
225 return fmt.Errorf("process-image-status-response-error")
226}
227func (oo *OnuImageStatus) setWaitingForResp(value bool) {
228 oo.mutexWaitingForResp.Lock()
229 oo.waitingForResp = value
230 oo.mutexWaitingForResp.Unlock()
231}
232func (oo *OnuImageStatus) isWaitingForResp() bool {
233 oo.mutexWaitingForResp.RLock()
234 value := oo.waitingForResp
235 oo.mutexWaitingForResp.RUnlock()
236 return value
237}
238
239//CancelProcessing ensures that interrupted processing is canceled while waiting for a response
240func (oo *OnuImageStatus) CancelProcessing(ctx context.Context) {
241 if oo.isWaitingForResp() {
242 abortMsg := Message{
243 Type: TestMsg,
244 Data: TestMessage{
245 TestMessageVal: AbortMessageProcessing,
246 },
247 }
248 oo.respChannel <- abortMsg
249 }
250}