blob: 0ab7984e6d6d7b74c2357f99249fe2ad58f0b225 [file] [log] [blame]
mpagenkoaf801632020-07-03 10:00:42 +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/json"
mpagenko3dbcdd22020-07-22 07:38:45 +000023 "strconv"
24 "strings"
mpagenkoaf801632020-07-03 10:00:42 +000025 "sync"
26
mpagenko3dbcdd22020-07-22 07:38:45 +000027 "github.com/looplab/fsm"
mpagenkoaf801632020-07-03 10:00:42 +000028 "github.com/opencord/voltha-lib-go/v3/pkg/db"
29 "github.com/opencord/voltha-lib-go/v3/pkg/db/kvstore"
30 "github.com/opencord/voltha-lib-go/v3/pkg/log"
31 tp "github.com/opencord/voltha-lib-go/v3/pkg/techprofile"
32)
33
34const cBasePathTechProfileKVStore = "service/voltha/technology_profiles"
35
36type resourceEntry int
37
38const (
39 cResourceGemPort resourceEntry = 1
40 cResourceTcont resourceEntry = 2
41)
42
43type onuSerialNumber struct {
44 sliceVendorID []byte
45 sliceVendorSpecific []byte
46}
47
48type onuPersistentData struct {
49 persOnuID uint32
50 persIntfID uint32
51 persSnr onuSerialNumber
52 persAdminState string
53 persOperState string
54 persUniTpPath map[uint32]string
mpagenkoaf801632020-07-03 10:00:42 +000055}
56
mpagenko3dbcdd22020-07-22 07:38:45 +000057type tTechProfileIndication struct {
58 techProfileType string
59 techProfileID uint16
60}
61
62type tcontParamStruct struct {
63 allocID uint16
64 schedPolicy uint8
65}
66type gemPortParamStruct struct {
67 gemPortID uint16
68 direction uint8
69 gemPortEncState uint8
70 usedPbitMap uint8
71 ponOmciCC bool
72 discardPolicy string
73 //could also be a queue specific paramter, not used that way here
74 maxQueueSize uint16
75 queueSchedPolicy string
76 queueWeight uint8
77}
78
79//refers to one tcont and its properties and all assigned GemPorts and their properties
80type tcontGemList struct {
81 tcontParams tcontParamStruct
82 mapGemPortParams map[uint16]*gemPortParamStruct
83}
84
85//refers to all tcont and their Tcont/GemPort Parameters
86type tMapPonAniConfig map[uint16]*tcontGemList
87
mpagenkoaf801632020-07-03 10:00:42 +000088//OnuUniTechProf structure holds information about the TechProfiles attached to Uni Ports of the ONU
89type OnuUniTechProf struct {
90 deviceID string
91 baseDeviceHandler *DeviceHandler
92 tpProcMutex sync.RWMutex
93 sOnuPersistentData onuPersistentData
94 techProfileKVStore *db.Backend
mpagenko3dbcdd22020-07-22 07:38:45 +000095 chTpProcessingStep chan uint8
96 mapUniTpIndication map[uint32]*tTechProfileIndication //use pointer values to ease assignments to the map
97 mapPonAniConfig map[uint32]*tMapPonAniConfig //per UNI: use pointer values to ease assignments to the map
98 pAniConfigFsm *UniPonAniConfigFsm
mpagenkoaf801632020-07-03 10:00:42 +000099}
100
101//NewOnuUniTechProf returns the instance of a OnuUniTechProf
102//(one instance per ONU/deviceHandler for all possible UNI's)
103func NewOnuUniTechProf(ctx context.Context, aDeviceID string, aDeviceHandler *DeviceHandler) *OnuUniTechProf {
104 logger.Infow("init-OnuUniTechProf", log.Fields{"deviceId": aDeviceID})
105 var onuTP OnuUniTechProf
106 onuTP.deviceID = aDeviceID
107 onuTP.baseDeviceHandler = aDeviceHandler
108 onuTP.tpProcMutex = sync.RWMutex{}
109 onuTP.sOnuPersistentData.persUniTpPath = make(map[uint32]string)
mpagenko3dbcdd22020-07-22 07:38:45 +0000110 onuTP.chTpProcessingStep = make(chan uint8)
111 onuTP.mapUniTpIndication = make(map[uint32]*tTechProfileIndication)
112 onuTP.mapPonAniConfig = make(map[uint32]*tMapPonAniConfig)
mpagenkoaf801632020-07-03 10:00:42 +0000113
114 onuTP.techProfileKVStore = aDeviceHandler.SetBackend(cBasePathTechProfileKVStore)
115 if onuTP.techProfileKVStore == nil {
116 logger.Errorw("Can't access techProfileKVStore - no backend connection to service",
117 log.Fields{"deviceID": aDeviceID, "service": cBasePathTechProfileKVStore})
118 }
119 return &onuTP
120}
121
122// lockTpProcMutex locks OnuUniTechProf processing mutex
123func (onuTP *OnuUniTechProf) lockTpProcMutex() {
124 onuTP.tpProcMutex.Lock()
125}
126
127// unlockTpProcMutex unlocks OnuUniTechProf processing mutex
128func (onuTP *OnuUniTechProf) unlockTpProcMutex() {
129 onuTP.tpProcMutex.Unlock()
130}
131
132// updateOnuUniTpPath verifies and updates changes in the kvStore onuUniTpPath
133func (onuTP *OnuUniTechProf) updateOnuUniTpPath(aUniID uint32, aPathString string) bool {
134 /* within some specific InterAdapter processing request write/read access to data is ensured to be sequentially,
135 as also the complete sequence is ensured to 'run to completion' before some new request is accepted
136 no specific concurrency protection to sOnuPersistentData is required here
137 */
138 if existingPath, present := onuTP.sOnuPersistentData.persUniTpPath[aUniID]; present {
139 // uni entry already exists
140 //logger.Debugw(" already exists", log.Fields{"for InstanceId": a_uniInstNo})
141 if existingPath != aPathString {
142 if aPathString == "" {
143 //existing entry to be deleted
144 logger.Debugw("UniTp path delete", log.Fields{
145 "deviceID": onuTP.deviceID, "uniID": aUniID, "path": aPathString})
146 delete(onuTP.sOnuPersistentData.persUniTpPath, aUniID)
147 } else {
148 //existing entry to be modified
149 logger.Debugw("UniTp path modify", log.Fields{
150 "deviceID": onuTP.deviceID, "uniID": aUniID, "path": aPathString})
151 onuTP.sOnuPersistentData.persUniTpPath[aUniID] = aPathString
152 }
153 return true
154 }
155 //entry already exists
156 logger.Debugw("UniTp path already exists", log.Fields{
157 "deviceID": onuTP.deviceID, "uniID": aUniID, "path": aPathString})
158 return false
159 }
160 //uni entry does not exist
161 if aPathString == "" {
162 //delete request in non-existing state , accept as no change
163 logger.Debugw("UniTp path already removed", log.Fields{
164 "deviceID": onuTP.deviceID, "uniID": aUniID})
165 return false
166 }
167 //new entry to be set
168 logger.Debugw("New UniTp path set", log.Fields{
169 "deviceID": onuTP.deviceID, "uniID": aUniID, "path": aPathString})
170 onuTP.sOnuPersistentData.persUniTpPath[aUniID] = aPathString
171 return true
172}
173
mpagenko3dbcdd22020-07-22 07:38:45 +0000174func (onuTP *OnuUniTechProf) waitForTpCompletion(cancel context.CancelFunc, wg *sync.WaitGroup) {
175 defer cancel() //ensure termination of context (may be pro forma)
176 wg.Wait()
177 logger.Debug("some TechProfile Processing completed")
178 onuTP.tpProcMutex.Unlock() //allow further TP related processing
179}
180
181// configureUniTp checks existing tp resources to delete and starts the corresponding OMCI configuation of the UNI port
182// all possibly blocking processing must be run in background to allow for deadline supervision!
183// but take care on sequential background processing when needed (logical dependencies)
184// use waitForTimeoutOrCompletion(ctx, processingStep) for internal synchronisation
185func (onuTP *OnuUniTechProf) configureUniTp(ctx context.Context,
186 aUniID uint32, aPathString string, wg *sync.WaitGroup) {
187 defer wg.Done() //always decrement the waitGroup on return
mpagenkoaf801632020-07-03 10:00:42 +0000188 logger.Debugw("configure the Uni according to TpPath", log.Fields{
189 "deviceID": onuTP.deviceID, "uniID": aUniID, "path": aPathString})
190
mpagenkoaf801632020-07-03 10:00:42 +0000191 if onuTP.techProfileKVStore == nil {
192 logger.Debug("techProfileKVStore not set - abort")
193 return
194 }
195
mpagenko3dbcdd22020-07-22 07:38:45 +0000196 //ensure that the given uniID is available (configured) in the UniPort class (used for OMCI entities)
197 var pCurrentUniPort *OnuUniPort
198 for _, uniPort := range onuTP.baseDeviceHandler.uniEntityMap {
199 // only if this port is validated for operState transfer
200 if uniPort.uniId == uint8(aUniID) {
201 pCurrentUniPort = uniPort
202 break //found - end search loop
203 }
204 }
205 if pCurrentUniPort == nil {
206 logger.Errorw("TechProfile configuration aborted: requested uniID not found in PortDB",
207 log.Fields{"device-id": onuTP.deviceID, "uniID": aUniID})
208 return
209 }
mpagenkoaf801632020-07-03 10:00:42 +0000210
mpagenko3dbcdd22020-07-22 07:38:45 +0000211 var processingStep uint8 = 1 // used to synchronize the different processing steps with chTpProcessingStep
mpagenkoaf801632020-07-03 10:00:42 +0000212
mpagenko3dbcdd22020-07-22 07:38:45 +0000213 //according to updateOnuUniTpPath() logic the assumption here is, that this configuration is only called
214 // in case the KVPath has changed for the given UNI,
215 // as T-Cont and Gem-Id's are dependent on TechProfile-Id this means, that possibly previously existing
216 // (ANI) configuration of this port has to be removed first
217 // (moreover in this case a possibly existing flow configuration is also not valid anymore and needs clean-up as well)
218 // existence of configuration can be detected based on tp stored TCONT's
219 //TODO!!!:
220 /* if tcontMap not empty {
221 go onuTP.deleteAniSideConfig(ctx, aUniID, processingStep)
222 if !onuTP.waitForTimeoutOrCompletion(ctx, processingStep) {
223 //timeout or error detected
224 return
225 }
226 clear tcontMap
227 }
228
229 processingStep++
230 */
231 go onuTP.readAniSideConfigFromTechProfile(ctx, aUniID, aPathString, processingStep)
232 if !onuTP.waitForTimeoutOrCompletion(ctx, processingStep) {
233 //timeout or error detected
234 logger.Debugw("tech-profile related configuration aborted on read",
235 log.Fields{"device-id": onuTP.deviceID, "UniId": aUniID})
236 return
237 }
238
239 processingStep++
240 if valuePA, existPA := onuTP.mapPonAniConfig[aUniID]; existPA {
241 if _, existTG := (*valuePA)[0]; existTG {
242 //Config data for this uni and and at least TCont Index 0 exist
243 go onuTP.setAniSideConfigFromTechProfile(ctx, aUniID, pCurrentUniPort, processingStep)
244 if !onuTP.waitForTimeoutOrCompletion(ctx, processingStep) {
245 //timeout or error detected
246 logger.Debugw("tech-profile related configuration aborted on set",
247 log.Fields{"device-id": onuTP.deviceID, "UniId": aUniID})
248 //this issue here means that the AniConfigFsm has not finished succesfully
249 //which requires to reset it to allow for new usage, e.g. also on a different UNI
250 //(without that it would be reset on device down indication latest)
251 onuTP.pAniConfigFsm.pAdaptFsm.pFsm.Event("reset")
252 return
mpagenkoaf801632020-07-03 10:00:42 +0000253 }
254 } else {
mpagenko3dbcdd22020-07-22 07:38:45 +0000255 // strange: UNI entry exists, but no ANI data, maybe such situation should be cleared up (if observed)
256 logger.Debugw("no Tcont/Gem data for this UNI found - abort", log.Fields{
257 "deviceID": onuTP.deviceID, "uniID": aUniID})
mpagenkoaf801632020-07-03 10:00:42 +0000258 }
259 } else {
mpagenko3dbcdd22020-07-22 07:38:45 +0000260 logger.Debugw("no PonAni data for this UNI found - abort", log.Fields{
261 "deviceID": onuTP.deviceID, "uniID": aUniID})
mpagenkoaf801632020-07-03 10:00:42 +0000262 }
263}
264
mpagenko3dbcdd22020-07-22 07:38:45 +0000265func (onuTP *OnuUniTechProf) updateOnuTpPathKvStore(ctx context.Context, wg *sync.WaitGroup) {
mpagenkoaf801632020-07-03 10:00:42 +0000266 defer wg.Done()
267 logger.Debugw("this would update the ONU's TpPath in KVStore", log.Fields{
268 "deviceID": onuTP.deviceID})
269 //TODO!!!
mpagenko3dbcdd22020-07-22 07:38:45 +0000270 //make use of onuTP.sOnuPersistentData to store the TpPath to KVStore - as background routine
271 /*
272 var processingStep uint8 = 1 // used to synchronize the different processing steps with chTpProcessingStep
273 go onuTp.storePersistentData(ctx, processingStep)
274 if !onuTP.waitForTimeoutOrCompletion(ctx, processingStep) {
275 //timeout or error detected
276 return
277 }
278 */
mpagenkoaf801632020-07-03 10:00:42 +0000279}
280
mpagenko3dbcdd22020-07-22 07:38:45 +0000281// deleteTpResource removes Resources from the ONU's specified Uni
282func (onuTP *OnuUniTechProf) deleteTpResource(ctx context.Context,
283 aUniID uint32, aPathString string, aResource resourceEntry, aEntryID uint32,
284 wg *sync.WaitGroup) {
mpagenkoaf801632020-07-03 10:00:42 +0000285 defer wg.Done()
286 logger.Debugw("this would remove TP resources from ONU's UNI", log.Fields{
mpagenko3dbcdd22020-07-22 07:38:45 +0000287 "deviceID": onuTP.deviceID, "uniID": aUniID, "path": aPathString, "Resource": aResource})
mpagenkoaf801632020-07-03 10:00:42 +0000288 //TODO!!!
mpagenko3dbcdd22020-07-22 07:38:45 +0000289 //delete the given resource from ONU OMCI config and data base - as background routine
290 /*
291 var processingStep uint8 = 1 // used to synchronize the different processing steps with chTpProcessingStep
292 go onuTp.deleteAniResource(ctx, processingStep)
293 if !onuTP.waitForTimeoutOrCompletion(ctx, processingStep) {
294 //timeout or error detected
295 return
296 }
297 */
mpagenkoaf801632020-07-03 10:00:42 +0000298}
299
mpagenko3dbcdd22020-07-22 07:38:45 +0000300/* internal methods *********************/
301func (onuTP *OnuUniTechProf) readAniSideConfigFromTechProfile(
302 ctx context.Context, aUniID uint32, aPathString string, aProcessingStep uint8) {
303 var tpInst tp.TechProfile
304
305 //store profile type and identifier for later usage within the OMCI identifier and possibly ME setup
306 //pathstring is defined to be in the form of <ProfType>/<profID>/<Interface/../Identifier>
307 subStringSlice := strings.Split(aPathString, "/")
308 if len(subStringSlice) <= 2 {
309 logger.Errorw("invalid path name format",
310 log.Fields{"path": aPathString, "device-id": onuTP.deviceID})
311 onuTP.chTpProcessingStep <- 0 //error indication
312 return
313 }
314
315 //just some logical check to avoid unexpected behavior
316 //at this point it is assumed that a new TechProfile is assigned to the UNI
317 //expectation is that no TPIndication entry exists here, if yes,
318 // then we throw a warning and remove it (and the possible ANIConfig) simply
319 // note that the ONU config state may be ambivalent in such a case
320 // also note, that the PonAniConfig map is not checked additionally
321 // consistency to TPIndication is assumed
322 if _, existTP := onuTP.mapUniTpIndication[aUniID]; existTP {
323 logger.Warnw("Some active profile entry at reading new TechProfile",
324 log.Fields{"path": aPathString, "device-id": onuTP.deviceID,
325 "UniId": aUniID, "wrongProfile": onuTP.mapUniTpIndication[aUniID].techProfileID})
326 //delete on the mapUniTpIndication map not needed, just overwritten later
327 //delete on the PonAniConfig map should be safe, even if not existing
328 delete(onuTP.mapPonAniConfig, aUniID)
329 } else {
330 // this is normal processing
331 onuTP.mapUniTpIndication[aUniID] = &tTechProfileIndication{} //need to assign some (empty) struct memory first!
332 }
333
334 onuTP.mapUniTpIndication[aUniID].techProfileType = subStringSlice[0]
335 profID, err := strconv.ParseUint(subStringSlice[1], 10, 32)
336 if err != nil {
337 logger.Errorw("invalid ProfileId from path",
338 log.Fields{"ParseErr": err})
339 onuTP.chTpProcessingStep <- 0 //error indication
340 return
341 }
342
343 //note the limitation on ID range (probably even more limited) - based on usage within OMCI EntityID
344 onuTP.mapUniTpIndication[aUniID].techProfileID = uint16(profID)
345 logger.Debugw("tech-profile path indications",
346 log.Fields{"device-id": onuTP.deviceID, "UniId": aUniID,
347 "profType": onuTP.mapUniTpIndication[aUniID].techProfileType,
348 "profID": onuTP.mapUniTpIndication[aUniID].techProfileID})
349
350 Value, err := onuTP.techProfileKVStore.Get(context.TODO(), aPathString)
351 if err == nil {
352 if Value != nil {
353 logger.Debugw("tech-profile read",
354 log.Fields{"Key": Value.Key, "device-id": onuTP.deviceID})
355 tpTmpBytes, _ := kvstore.ToByte(Value.Value)
356
357 if err = json.Unmarshal(tpTmpBytes, &tpInst); err != nil {
358 logger.Errorw("TechProf - Failed to unmarshal tech-profile into tpInst",
359 log.Fields{"error": err, "device-id": onuTP.deviceID})
360 onuTP.chTpProcessingStep <- 0 //error indication
361 return
362 }
363 logger.Debugw("TechProf - tpInst", log.Fields{"tpInst": tpInst})
364 // access examples
365 logger.Debugw("TechProf content", log.Fields{"Name": tpInst.Name,
366 "MaxGemPayloadSize": tpInst.InstanceCtrl.MaxGemPayloadSize,
367 "DownstreamGemDiscardmaxThreshold": tpInst.DownstreamGemPortAttributeList[0].DiscardConfig.MaxThreshold})
368 } else {
369 logger.Errorw("No tech-profile found",
370 log.Fields{"path": aPathString, "device-id": onuTP.deviceID})
371 onuTP.chTpProcessingStep <- 0 //error indication
372 return
373 }
374 } else {
375 logger.Errorw("kvstore-get failed for path",
376 log.Fields{"path": aPathString, "device-id": onuTP.deviceID})
377 onuTP.chTpProcessingStep <- 0 //error indication
378 return
379 }
380
381 //for first start assume a 1Tcont1Gem profile, later extend for multi GemPerTcont and MultiTcontMultiGem
382 localMapGemPortParams := make(map[uint16]*gemPortParamStruct)
383 localMapGemPortParams[0] = &gemPortParamStruct{}
384 localMapPonAniConfig := make(map[uint16]*tcontGemList)
385 localMapPonAniConfig[0] = &tcontGemList{tcontParamStruct{}, localMapGemPortParams}
386 onuTP.mapPonAniConfig[aUniID] = (*tMapPonAniConfig)(&localMapPonAniConfig)
387
388 //get the relevant values from the profile and store to mapPonAniConfig
389 (*(onuTP.mapPonAniConfig[aUniID]))[0].tcontParams.allocID = uint16(tpInst.UsScheduler.AllocID)
390 //maybe tCont scheduling not (yet) needed - just to basicaly have it for future
391 // (would only be relevant in case of ONU-2G QOS configuration flexibility)
392 if tpInst.UsScheduler.QSchedPolicy == "StrictPrio" {
393 (*(onuTP.mapPonAniConfig[aUniID]))[0].tcontParams.schedPolicy = 1 //for the moment fixed value acc. G.988 //TODO: defines!
394 } else {
395 // default profile defines "Hybrid" - which probably comes down to WRR with some weigthts for SP
396 (*(onuTP.mapPonAniConfig[aUniID]))[0].tcontParams.schedPolicy = 2 //for G.988 WRR
397 }
398 for pos, content := range tpInst.UpstreamGemPortAttributeList {
399 if pos == 1 {
400 logger.Debugw("PonAniConfig abort GemPortList - still only one Gemport supported",
401 log.Fields{"device-id": onuTP.deviceID})
402 break
403 }
404 // a downstream GemPort should always exist (only downstream for MC)
405 (*(onuTP.mapPonAniConfig[aUniID]))[0].mapGemPortParams[uint16(pos)].gemPortID = uint16(content.GemportID)
406 // direction can be correlated later with Downstream list, for now just assume bidirectional (upstream never exists alone)
407 (*(onuTP.mapPonAniConfig[aUniID]))[0].mapGemPortParams[uint16(pos)].direction = 3 //as defined in G.988
408 if content.AesEncryption == "True" {
409 (*(onuTP.mapPonAniConfig[aUniID]))[0].mapGemPortParams[uint16(pos)].gemPortEncState = 1
410 } else {
411 (*(onuTP.mapPonAniConfig[aUniID]))[0].mapGemPortParams[uint16(pos)].gemPortEncState = 0
412 }
413
414 (*(onuTP.mapPonAniConfig[aUniID]))[0].mapGemPortParams[uint16(pos)].discardPolicy = content.DiscardPolicy
415 (*(onuTP.mapPonAniConfig[aUniID]))[0].mapGemPortParams[uint16(pos)].queueSchedPolicy = content.SchedulingPolicy
416 //'GemWeight' looks strange in default profile, for now we just copy the weight to first queue
417 (*(onuTP.mapPonAniConfig[aUniID]))[0].mapGemPortParams[uint16(pos)].queueWeight = uint8(content.Weight)
418 }
419 //TODO!! MC (downstream) GemPorts can be set using DownstreamGemPortAttributeList seperately
420
421 //logger does not simply output the given structures, just give some example debug values
422 logger.Debugw("PonAniConfig read from TechProfile", log.Fields{
423 "device-id": onuTP.deviceID,
424 "AllocId": (*(onuTP.mapPonAniConfig[aUniID]))[0].tcontParams.allocID,
425 "GemPort": (*(onuTP.mapPonAniConfig[aUniID]))[0].mapGemPortParams[0].gemPortID,
426 "QueueScheduling": (*(onuTP.mapPonAniConfig[aUniID]))[0].mapGemPortParams[0].queueSchedPolicy})
427
428 onuTP.chTpProcessingStep <- aProcessingStep //done
429}
430
431func (onuTP *OnuUniTechProf) setAniSideConfigFromTechProfile(
432 ctx context.Context, aUniID uint32, apCurrentUniPort *OnuUniPort, aProcessingStep uint8) {
433
434 //OMCI transfer of ANI data acc. to mapPonAniConfig
435 // also the FSM's are running in background,
436 // hence we have to make sure they indicate 'success' success on chTpProcessingStep with aProcessingStep
437 if onuTP.pAniConfigFsm == nil {
438 onuTP.createAniConfigFsm(aUniID, apCurrentUniPort, OmciAniConfigDone, aProcessingStep)
439 } else { //AniConfigFsm already init
440 onuTP.runAniConfigFsm(aProcessingStep)
441 }
442}
443
444func (onuTP *OnuUniTechProf) waitForTimeoutOrCompletion(
445 ctx context.Context, aProcessingStep uint8) bool {
446 select {
447 case <-ctx.Done():
448 logger.Warnw("processing not completed in-time: force release of TpProcMutex!",
449 log.Fields{"deviceID": onuTP.deviceID, "error": ctx.Err()})
450 return false
451 case rxStep := <-onuTP.chTpProcessingStep:
452 if rxStep == aProcessingStep {
453 return true
454 }
455 //all other values are not accepted - including 0 for error indication
456 logger.Warnw("Invalid processing step received: abort and force release of TpProcMutex!",
457 log.Fields{"deviceID": onuTP.deviceID,
458 "wantedStep": aProcessingStep, "haveStep": rxStep})
459 return false
460 }
461}
462
463// createUniLockFsm initialises and runs the AniConfig FSM to transfer the OMCI related commands for ANI side configuration
464func (onuTP *OnuUniTechProf) createAniConfigFsm(aUniID uint32,
465 apCurrentUniPort *OnuUniPort, devEvent OnuDeviceEvent, aProcessingStep uint8) {
466 logger.Debugw("createAniConfigFsm", log.Fields{"deviceID": onuTP.deviceID})
467 chAniConfigFsm := make(chan Message, 2048)
468 pDevEntry := onuTP.baseDeviceHandler.GetOnuDeviceEntry(true)
469 if pDevEntry == nil {
470 logger.Errorw("No valid OnuDevice - aborting", log.Fields{"deviceID": onuTP.deviceID})
471 return
472 }
473 pAniCfgFsm := NewUniPonAniConfigFsm(pDevEntry.PDevOmciCC, apCurrentUniPort, onuTP,
474 pDevEntry.pOnuDB, onuTP.mapUniTpIndication[aUniID].techProfileID, devEvent,
475 "AniConfigFsm", onuTP.deviceID, chAniConfigFsm)
476 if pAniCfgFsm != nil {
477 onuTP.pAniConfigFsm = pAniCfgFsm
478 onuTP.runAniConfigFsm(aProcessingStep)
479 } else {
480 logger.Errorw("AniConfigFSM could not be created - abort!!", log.Fields{"deviceID": onuTP.deviceID})
481 }
482}
483
484// runAniConfigFsm starts the AniConfig FSM to transfer the OMCI related commands for ANI side configuration
485func (onuTP *OnuUniTechProf) runAniConfigFsm(aProcessingStep uint8) {
486 /* Uni related ANI config procedure -
487 ***** should run via 'aniConfigDone' state and generate the argument requested event *****
488 */
489 var pACStatemachine *fsm.FSM
490 pACStatemachine = onuTP.pAniConfigFsm.pAdaptFsm.pFsm
491 if pACStatemachine != nil {
492 if pACStatemachine.Is("disabled") {
493 //FSM init requirement to get informed abou FSM completion! (otherwise timeout of the TechProf config)
494 onuTP.pAniConfigFsm.SetFsmCompleteChannel(onuTP.chTpProcessingStep, aProcessingStep)
495 if err := pACStatemachine.Event("start"); err != nil {
496 logger.Warnw("AniConfigFSM: can't start", log.Fields{"err": err})
497 // maybe try a FSM reset and then again ... - TODO!!!
498 } else {
499 /***** AniConfigFSM started */
500 logger.Debugw("AniConfigFSM started", log.Fields{
501 "state": pACStatemachine.Current(), "deviceID": onuTP.deviceID})
502 }
503 } else {
504 logger.Warnw("wrong state of AniConfigFSM - want: disabled", log.Fields{
505 "have": pACStatemachine.Current(), "deviceID": onuTP.deviceID})
506 // maybe try a FSM reset and then again ... - TODO!!!
507 }
508 } else {
509 logger.Errorw("AniConfigFSM StateMachine invalid - cannot be executed!!", log.Fields{"deviceID": onuTP.deviceID})
510 // maybe try a FSM reset and then again ... - TODO!!!
511 }
mpagenkoaf801632020-07-03 10:00:42 +0000512}