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