blob: 09ae7bf9bfa195489ba25fa6a084535fd509ff54 [file] [log] [blame]
Takahiro Suzuki241c10e2020-12-17 20:17:57 +09001/*
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"
23 "errors"
24 "fmt"
25 "strconv"
26 "strings"
27 "sync"
28
29 "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"
36const cBasePathOnuKVStore = "service/voltha/openonu"
37
38//definitions for TechProfileProcessing - copied from OltAdapter:openolt_flowmgr.go
39// could perhaps be defined more globally
40const (
41 binaryStringPrefix = "0b"
42)
43
44type resourceEntry int
45
46const (
47 cResourceGemPort resourceEntry = 1
48 cResourceTcont resourceEntry = 2
49)
50
51type uniPersData struct {
52 PersUniID uint32 `json:"uni_id"`
53 PersTpPath string `json:"tp_path"`
54}
55
56type onuPersistentData struct {
57 PersOnuID uint32 `json:"onu_id"`
58 PersIntfID uint32 `json:"intf_id"`
59 PersSnr string `json:"serial_number"`
60 PersAdminState string `json:"admin_state"`
61 PersOperState string `json:"oper_state"`
62 PersUniTpPath []uniPersData `json:"uni_config"`
63}
64
65type tTechProfileIndication struct {
66 techProfileType string
67 techProfileID uint16
68 techProfileConfigDone bool
69}
70
71type tcontParamStruct struct {
72 allocID uint16
73 schedPolicy uint8
74}
75type gemPortParamStruct struct {
76 gemPortID uint16
77 direction uint8
78 gemPortEncState uint8
79 prioQueueIndex uint8
80 pbitString string
81 discardPolicy string
82 queueSchedPolicy string
83 queueWeight uint8
84}
85
86//refers to one tcont and its properties and all assigned GemPorts and their properties
87type tcontGemList struct {
88 tcontParams tcontParamStruct
89 mapGemPortParams map[uint16]*gemPortParamStruct
90}
91
92//refers to all tcont and their Tcont/GemPort Parameters
93type tMapPonAniConfig map[uint16]*tcontGemList
94
95//onuUniTechProf structure holds information about the TechProfiles attached to Uni Ports of the ONU
96type onuUniTechProf struct {
97 deviceID string
98 baseDeviceHandler *deviceHandler
99 tpProcMutex sync.RWMutex
100 mapUniTpPath map[uint32]string
101 sOnuPersistentData onuPersistentData
102 techProfileKVStore *db.Backend
103 onuKVStore *db.Backend
104 onuKVStorePath string
105 chTpConfigProcessingStep chan uint8
106 chTpKvProcessingStep chan uint8
107 mapUniTpIndication map[uint8]*tTechProfileIndication //use pointer values to ease assignments to the map
108 mapPonAniConfig map[uint8]*tMapPonAniConfig //per UNI: use pointer values to ease assignments to the map
109 pAniConfigFsm *uniPonAniConfigFsm
110 procResult error //error indication of processing
111 mutexTPState sync.Mutex
112}
113
114//newOnuUniTechProf returns the instance of a OnuUniTechProf
115//(one instance per ONU/deviceHandler for all possible UNI's)
116func newOnuUniTechProf(ctx context.Context, aDeviceID string, aDeviceHandler *deviceHandler) *onuUniTechProf {
117 logger.Infow("init-OnuUniTechProf", log.Fields{"device-id": aDeviceID})
118 var onuTP onuUniTechProf
119 onuTP.deviceID = aDeviceID
120 onuTP.baseDeviceHandler = aDeviceHandler
121 onuTP.tpProcMutex = sync.RWMutex{}
122 onuTP.mapUniTpPath = make(map[uint32]string)
123 onuTP.sOnuPersistentData.PersUniTpPath = make([]uniPersData, 1)
124 onuTP.chTpConfigProcessingStep = make(chan uint8)
125 onuTP.chTpKvProcessingStep = make(chan uint8)
126 onuTP.mapUniTpIndication = make(map[uint8]*tTechProfileIndication)
127 onuTP.mapPonAniConfig = make(map[uint8]*tMapPonAniConfig)
128 onuTP.procResult = nil //default assumption processing done with success
129
130 onuTP.techProfileKVStore = aDeviceHandler.setBackend(cBasePathTechProfileKVStore)
131 if onuTP.techProfileKVStore == nil {
132 logger.Errorw("Can't access techProfileKVStore - no backend connection to service",
133 log.Fields{"device-id": aDeviceID, "service": cBasePathTechProfileKVStore})
134 }
135
136 onuTP.onuKVStorePath = onuTP.deviceID
137 onuTP.onuKVStore = aDeviceHandler.setBackend(cBasePathOnuKVStore)
138 if onuTP.onuKVStore == nil {
139 logger.Errorw("Can't access onuKVStore - no backend connection to service",
140 log.Fields{"device-id": aDeviceID, "service": cBasePathOnuKVStore})
141 }
142 return &onuTP
143}
144
145// lockTpProcMutex locks OnuUniTechProf processing mutex
146func (onuTP *onuUniTechProf) lockTpProcMutex() {
147 onuTP.tpProcMutex.Lock()
148}
149
150// unlockTpProcMutex unlocks OnuUniTechProf processing mutex
151func (onuTP *onuUniTechProf) unlockTpProcMutex() {
152 onuTP.tpProcMutex.Unlock()
153}
154
155// resetProcessingErrorIndication resets the internal error indication
156// need to be called before evaluation of any subsequent processing (given by waitForTpCompletion())
157func (onuTP *onuUniTechProf) resetProcessingErrorIndication() {
158 onuTP.procResult = nil
159}
160
161// updateOnuUniTpPath verifies and updates changes in the kvStore onuUniTpPath
162func (onuTP *onuUniTechProf) updateOnuUniTpPath(aUniID uint32, aPathString string) bool {
163 /* within some specific InterAdapter processing request write/read access to data is ensured to be sequentially,
164 as also the complete sequence is ensured to 'run to completion' before some new request is accepted
165 no specific concurrency protection to sOnuPersistentData is required here
166 */
167 if existingPath, present := onuTP.mapUniTpPath[aUniID]; present {
168 // uni entry already exists
169 //logger.Debugw(" already exists", log.Fields{"for InstanceId": a_uniInstNo})
170 if existingPath != aPathString {
171 if aPathString == "" {
172 //existing entry to be deleted
173 logger.Debugw("UniTp path delete", log.Fields{
174 "device-id": onuTP.deviceID, "uniID": aUniID, "path": aPathString})
175 delete(onuTP.mapUniTpPath, aUniID)
176 } else {
177 //existing entry to be modified
178 logger.Debugw("UniTp path modify", log.Fields{
179 "device-id": onuTP.deviceID, "uniID": aUniID, "path": aPathString})
180 onuTP.mapUniTpPath[aUniID] = aPathString
181 }
182 return true
183 }
184 //entry already exists
185 logger.Debugw("UniTp path already exists", log.Fields{
186 "device-id": onuTP.deviceID, "uniID": aUniID, "path": aPathString})
187 return false
188 }
189 if aPathString == "" {
190 //delete request in non-existing state , accept as no change
191 logger.Debugw("UniTp path already removed", log.Fields{
192 "device-id": onuTP.deviceID, "uniID": aUniID})
193 return false
194 }
195 logger.Debugw("New UniTp path set", log.Fields{
196 "device-id": onuTP.deviceID, "uniID": aUniID, "path": aPathString})
197 onuTP.mapUniTpPath[aUniID] = aPathString
198 return true
199}
200
201func (onuTP *onuUniTechProf) waitForTpCompletion(cancel context.CancelFunc, wg *sync.WaitGroup) error {
202 defer cancel() //ensure termination of context (may be pro forma)
203 wg.Wait()
204 logger.Debug("some TechProfile Processing completed")
205 onuTP.tpProcMutex.Unlock() //allow further TP related processing
206 return onuTP.procResult
207}
208
209// configureUniTp checks existing tp resources to delete and starts the corresponding OMCI configuation of the UNI port
210// all possibly blocking processing must be run in background to allow for deadline supervision!
211// but take care on sequential background processing when needed (logical dependencies)
212// use waitForTimeoutOrCompletion(ctx, chTpConfigProcessingStep, processingStep) for internal synchronization
213func (onuTP *onuUniTechProf) configureUniTp(ctx context.Context,
214 aUniID uint8, aPathString string, wg *sync.WaitGroup) {
215 defer wg.Done() //always decrement the waitGroup on return
216 logger.Debugw("configure the Uni according to TpPath", log.Fields{
217 "device-id": onuTP.deviceID, "uniID": aUniID, "path": aPathString})
218
219 if onuTP.techProfileKVStore == nil {
220 logger.Debug("techProfileKVStore not set - abort")
221 onuTP.procResult = errors.New("techProfile config aborted: techProfileKVStore not set")
222 return
223 }
224
225 var pCurrentUniPort *onuUniPort
226 for _, uniPort := range onuTP.baseDeviceHandler.uniEntityMap {
227 // only if this port is validated for operState transfer
228 if uniPort.uniID == uint8(aUniID) {
229 pCurrentUniPort = uniPort
230 break //found - end search loop
231 }
232 }
233 if pCurrentUniPort == nil {
234 logger.Errorw("TechProfile configuration aborted: requested uniID not found in PortDB",
235 log.Fields{"device-id": onuTP.deviceID, "uniID": aUniID})
236 onuTP.procResult = errors.New("techProfile config aborted: requested uniID not found")
237 return
238 }
239
240 var processingStep uint8 = 1 // used to synchronize the different processing steps with chTpConfigProcessingStep
241
242 /* if tcontMap not empty {
243 go onuTP.deleteAniSideConfig(ctx, aUniID, processingStep)
244 if !onuTP.waitForTimeoutOrCompletion(ctx, chTpConfigProcessingStep, processingStep) {
245 //timeout or error detected
246 return
247 }
248 clear tcontMap
249 }
250
251 processingStep++
252 */
253 go onuTP.readAniSideConfigFromTechProfile(ctx, aUniID, aPathString, processingStep)
254 if !onuTP.waitForTimeoutOrCompletion(ctx, onuTP.chTpConfigProcessingStep, processingStep) {
255 //timeout or error detected
256 logger.Debugw("tech-profile related configuration aborted on read",
257 log.Fields{"device-id": onuTP.deviceID, "UniId": aUniID})
258 onuTP.procResult = errors.New("techProfile config aborted: tech-profile read issue")
259 return
260 }
261
262 processingStep++
263 if valuePA, existPA := onuTP.mapPonAniConfig[aUniID]; existPA {
264 if _, existTG := (*valuePA)[0]; existTG {
265 //Config data for this uni and and at least TCont Index 0 exist
266 go onuTP.setAniSideConfigFromTechProfile(ctx, aUniID, pCurrentUniPort, processingStep)
267 if !onuTP.waitForTimeoutOrCompletion(ctx, onuTP.chTpConfigProcessingStep, processingStep) {
268 //timeout or error detected
269 logger.Debugw("tech-profile related configuration aborted on set",
270 log.Fields{"device-id": onuTP.deviceID, "UniId": aUniID})
271 onuTP.procResult = errors.New("techProfile config aborted: Omci AniSideConfig failed")
272 //this issue here means that the AniConfigFsm has not finished successfully
273 //which requires to reset it to allow for new usage, e.g. also on a different UNI
274 //(without that it would be reset on device down indication latest)
275 _ = onuTP.pAniConfigFsm.pAdaptFsm.pFsm.Event(aniEvReset)
276 return
277 }
278 } else {
279 // strange: UNI entry exists, but no ANI data, maybe such situation should be cleared up (if observed)
280 logger.Debugw("no Tcont/Gem data for this UNI found - abort", log.Fields{
281 "device-id": onuTP.deviceID, "uniID": aUniID})
282 onuTP.procResult = errors.New("techProfile config aborted: no Tcont/Gem data found for this UNI")
283 return
284 }
285 } else {
286 logger.Debugw("no PonAni data for this UNI found - abort", log.Fields{
287 "device-id": onuTP.deviceID, "uniID": aUniID})
288 onuTP.procResult = errors.New("techProfile config aborted: no AniSide data found for this UNI")
289 return
290 }
291}
292
293func (onuTP *onuUniTechProf) updateOnuTpPathKvStore(ctx context.Context, wg *sync.WaitGroup) {
294 defer wg.Done()
295
296 if onuTP.onuKVStore == nil {
297 logger.Debugw("onuKVStore not set - abort", log.Fields{"device-id": onuTP.deviceID})
298 onuTP.procResult = errors.New("onu/tp-data update aborted: onuKVStore not set")
299 return
300 }
301 var processingStep uint8 = 1 // used to synchronize the different processing steps with chTpKvProcessingStep
302 go onuTP.storePersistentData(ctx, processingStep)
303 if !onuTP.waitForTimeoutOrCompletion(ctx, onuTP.chTpKvProcessingStep, processingStep) {
304 //timeout or error detected
305 logger.Debugw("ONU/TP-data not written - abort", log.Fields{"device-id": onuTP.deviceID})
306 onuTP.procResult = errors.New("onu/tp-data update aborted: during writing process")
307 return
308 }
309}
310
311func (onuTP *onuUniTechProf) restoreFromOnuTpPathKvStore(ctx context.Context) error {
312 if onuTP.onuKVStore == nil {
313 logger.Debugw("onuKVStore not set - abort", log.Fields{"device-id": onuTP.deviceID})
314 return fmt.Errorf(fmt.Sprintf("onuKVStore-not-set-abort-%s", onuTP.deviceID))
315 }
316 if err := onuTP.restorePersistentData(ctx); err != nil {
317 logger.Debugw("ONU/TP-data not read - abort", log.Fields{"device-id": onuTP.deviceID})
318 return err
319 }
320 return nil
321}
322
323func (onuTP *onuUniTechProf) deleteOnuTpPathKvStore(ctx context.Context) error {
324 if onuTP.onuKVStore == nil {
325 logger.Debugw("onuKVStore not set - abort", log.Fields{"device-id": onuTP.deviceID})
326 return fmt.Errorf(fmt.Sprintf("onuKVStore-not-set-abort-%s", onuTP.deviceID))
327 }
328 if err := onuTP.deletePersistentData(ctx); err != nil {
329 logger.Debugw("ONU/TP-data not read - abort", log.Fields{"device-id": onuTP.deviceID})
330 return err
331 }
332 return nil
333}
334
335// deleteTpResource removes Resources from the ONU's specified Uni
336func (onuTP *onuUniTechProf) deleteTpResource(ctx context.Context,
337 aUniID uint32, aPathString string, aResource resourceEntry, aEntryID uint32,
338 wg *sync.WaitGroup) {
339 defer wg.Done()
340 logger.Debugw("this would remove TP resources from ONU's UNI", log.Fields{
341 "device-id": onuTP.deviceID, "uniID": aUniID, "path": aPathString, "Resource": aResource})
342 /*
343 var processingStep uint8 = 1 // used to synchronize the different processing steps with chTpConfigProcessingStep
344 go onuTp.deleteAniResource(ctx, processingStep)
345 if !onuTP.waitForTimeoutOrCompletion(ctx, chTpConfigProcessingStep, processingStep) {
346 //timeout or error detected
347 return
348 }
349 */
350}
351
352/* internal methods *********************/
353
354func (onuTP *onuUniTechProf) storePersistentData(ctx context.Context, aProcessingStep uint8) {
355
356 onuTP.sOnuPersistentData.PersOnuID = onuTP.baseDeviceHandler.pOnuIndication.OnuId
357 onuTP.sOnuPersistentData.PersIntfID = onuTP.baseDeviceHandler.pOnuIndication.IntfId
358 onuTP.sOnuPersistentData.PersSnr = onuTP.baseDeviceHandler.pOnuOmciDevice.serialNumber
359 onuTP.sOnuPersistentData.PersAdminState = "up"
360 onuTP.sOnuPersistentData.PersOperState = "active"
361
362 onuTP.sOnuPersistentData.PersUniTpPath = onuTP.sOnuPersistentData.PersUniTpPath[:0]
363
364 for k, v := range onuTP.mapUniTpPath {
365 onuTP.sOnuPersistentData.PersUniTpPath =
366 append(onuTP.sOnuPersistentData.PersUniTpPath, uniPersData{PersUniID: k, PersTpPath: v})
367 }
368 logger.Debugw("Update ONU/TP-data in KVStore", log.Fields{"device-id": onuTP.deviceID, "onuTP.sOnuPersistentData": onuTP.sOnuPersistentData})
369
370 Value, err := json.Marshal(onuTP.sOnuPersistentData)
371 if err != nil {
372 logger.Errorw("unable to marshal ONU/TP-data", log.Fields{"onuTP.sOnuPersistentData": onuTP.sOnuPersistentData,
373 "device-id": onuTP.deviceID, "err": err})
374 onuTP.chTpKvProcessingStep <- 0 //error indication
375 return
376 }
377 err = onuTP.onuKVStore.Put(ctx, onuTP.onuKVStorePath, Value)
378 if err != nil {
379 logger.Errorw("unable to write ONU/TP-data into KVstore", log.Fields{"device-id": onuTP.deviceID, "err": err})
380 onuTP.chTpKvProcessingStep <- 0 //error indication
381 return
382 }
383 onuTP.chTpKvProcessingStep <- aProcessingStep //done
384}
385
386func (onuTP *onuUniTechProf) restorePersistentData(ctx context.Context) error {
387
388 onuTP.mapUniTpPath = make(map[uint32]string)
389 onuTP.sOnuPersistentData = onuPersistentData{0, 0, "", "", "", make([]uniPersData, 0)}
390
391 Value, err := onuTP.onuKVStore.Get(ctx, onuTP.onuKVStorePath)
392 if err == nil {
393 if Value != nil {
394 logger.Debugw("ONU/TP-data read",
395 log.Fields{"Key": Value.Key, "device-id": onuTP.deviceID})
396 tpTmpBytes, _ := kvstore.ToByte(Value.Value)
397
398 if err = json.Unmarshal(tpTmpBytes, &onuTP.sOnuPersistentData); err != nil {
399 logger.Errorw("unable to unmarshal ONU/TP-data", log.Fields{"error": err, "device-id": onuTP.deviceID})
400 return fmt.Errorf(fmt.Sprintf("unable-to-unmarshal-ONU/TP-data-%s", onuTP.deviceID))
401 }
402 logger.Debugw("ONU/TP-data", log.Fields{"onuTP.sOnuPersistentData": onuTP.sOnuPersistentData,
403 "device-id": onuTP.deviceID})
404
405 for _, uniData := range onuTP.sOnuPersistentData.PersUniTpPath {
406 onuTP.mapUniTpPath[uniData.PersUniID] = uniData.PersTpPath
407 }
408 logger.Debugw("TpPath map", log.Fields{"onuTP.mapUniTpPath": onuTP.mapUniTpPath,
409 "device-id": onuTP.deviceID})
410 } else {
411 logger.Errorw("no ONU/TP-data found", log.Fields{"path": onuTP.onuKVStorePath, "device-id": onuTP.deviceID})
412 return fmt.Errorf(fmt.Sprintf("no-ONU/TP-data-found-%s", onuTP.deviceID))
413 }
414 } else {
415 logger.Errorw("unable to read from KVstore", log.Fields{"device-id": onuTP.deviceID})
416 return fmt.Errorf(fmt.Sprintf("unable-to-read-from-KVstore-%s", onuTP.deviceID))
417 }
418 return nil
419}
420
421func (onuTP *onuUniTechProf) deletePersistentData(ctx context.Context) error {
422
423 logger.Debugw("delete ONU/TP-data in KVStore", log.Fields{"device-id": onuTP.deviceID})
424 err := onuTP.onuKVStore.Delete(ctx, onuTP.onuKVStorePath)
425 if err != nil {
426 logger.Errorw("unable to delete in KVstore", log.Fields{"device-id": onuTP.deviceID, "err": err})
427 return fmt.Errorf(fmt.Sprintf("unable-delete-in-KVstore-%s", onuTP.deviceID))
428 }
429 return nil
430}
431
432func (onuTP *onuUniTechProf) readAniSideConfigFromTechProfile(
433 ctx context.Context, aUniID uint8, aPathString string, aProcessingStep uint8) {
434 var tpInst tp.TechProfile
435
436 subStringSlice := strings.Split(aPathString, "/")
437 if len(subStringSlice) <= 2 {
438 logger.Errorw("invalid path name format",
439 log.Fields{"path": aPathString, "device-id": onuTP.deviceID})
440 onuTP.chTpConfigProcessingStep <- 0 //error indication
441 return
442 }
443
444 if _, existTP := onuTP.mapUniTpIndication[aUniID]; existTP {
445 logger.Warnw("Some active profile entry at reading new TechProfile",
446 log.Fields{"path": aPathString, "device-id": onuTP.deviceID,
447 "UniId": aUniID, "wrongProfile": onuTP.mapUniTpIndication[aUniID].techProfileID})
448 //delete on the mapUniTpIndication map not needed, just overwritten later
449 //delete on the PonAniConfig map should be safe, even if not existing
450 delete(onuTP.mapPonAniConfig, aUniID)
451 } else {
452 // this is normal processing
453 onuTP.mapUniTpIndication[aUniID] = &tTechProfileIndication{} //need to assign some (empty) struct memory first!
454 }
455
456 onuTP.mapUniTpIndication[aUniID].techProfileType = subStringSlice[0]
457 profID, err := strconv.ParseUint(subStringSlice[1], 10, 32)
458 if err != nil {
459 logger.Errorw("invalid ProfileId from path",
460 log.Fields{"ParseErr": err})
461 onuTP.chTpConfigProcessingStep <- 0 //error indication
462 return
463 }
464
465 onuTP.mapUniTpIndication[aUniID].techProfileID = uint16(profID)
466 logger.Debugw("tech-profile path indications",
467 log.Fields{"device-id": onuTP.deviceID, "UniId": aUniID,
468 "profType": onuTP.mapUniTpIndication[aUniID].techProfileType,
469 "profID": onuTP.mapUniTpIndication[aUniID].techProfileID})
470
471 Value, err := onuTP.techProfileKVStore.Get(ctx, aPathString)
472 if err == nil {
473 if Value != nil {
474 logger.Debugw("tech-profile read",
475 log.Fields{"Key": Value.Key, "device-id": onuTP.deviceID})
476 tpTmpBytes, _ := kvstore.ToByte(Value.Value)
477
478 if err = json.Unmarshal(tpTmpBytes, &tpInst); err != nil {
479 logger.Errorw("TechProf - Failed to unmarshal tech-profile into tpInst",
480 log.Fields{"error": err, "device-id": onuTP.deviceID})
481 onuTP.chTpConfigProcessingStep <- 0 //error indication
482 return
483 }
484 logger.Debugw("TechProf - tpInst", log.Fields{"tpInst": tpInst})
485 // access examples
486 logger.Debugw("TechProf content", log.Fields{"Name": tpInst.Name,
487 "MaxGemPayloadSize": tpInst.InstanceCtrl.MaxGemPayloadSize,
488 "DownstreamGemDiscardmaxThreshold": tpInst.DownstreamGemPortAttributeList[0].DiscardConfig.MaxThreshold})
489 } else {
490 logger.Errorw("No tech-profile found",
491 log.Fields{"path": aPathString, "device-id": onuTP.deviceID})
492 onuTP.chTpConfigProcessingStep <- 0 //error indication
493 return
494 }
495 } else {
496 logger.Errorw("kvstore-get failed for path",
497 log.Fields{"path": aPathString, "device-id": onuTP.deviceID})
498 onuTP.chTpConfigProcessingStep <- 0 //error indication
499 return
500 }
501
502 localMapGemPortParams := make(map[uint16]*gemPortParamStruct)
503 localMapGemPortParams[0] = &gemPortParamStruct{}
504 localMapPonAniConfig := make(map[uint16]*tcontGemList)
505 localMapPonAniConfig[0] = &tcontGemList{tcontParamStruct{}, localMapGemPortParams}
506 onuTP.mapPonAniConfig[aUniID] = (*tMapPonAniConfig)(&localMapPonAniConfig)
507
508 (*(onuTP.mapPonAniConfig[aUniID]))[0].tcontParams.allocID = uint16(tpInst.UsScheduler.AllocID)
509 if tpInst.UsScheduler.QSchedPolicy == "StrictPrio" {
510 (*(onuTP.mapPonAniConfig[aUniID]))[0].tcontParams.schedPolicy = 1 //for the moment fixed value acc. G.988 //TODO: defines!
511 } else {
512 //default profile defines "Hybrid" - which probably comes down to WRR with some weigthts for SP
513 (*(onuTP.mapPonAniConfig[aUniID]))[0].tcontParams.schedPolicy = 2 //for G.988 WRR
514 }
515 loNumGemPorts := tpInst.NumGemPorts
516 loGemPortRead := false
517 for pos, content := range tpInst.UpstreamGemPortAttributeList {
518 if uint32(pos) == loNumGemPorts {
519 logger.Debugw("PonAniConfig abort GemPortList - GemList exceeds set NumberOfGemPorts",
520 log.Fields{"device-id": onuTP.deviceID, "index": pos, "NumGem": loNumGemPorts})
521 break
522 }
523 if pos == 0 {
524 //at least one upstream GemPort should always exist (else traffic profile makes no sense)
525 loGemPortRead = true
526 } else {
527 //for all further GemPorts we need to extend the mapGemPortParams
528 (*(onuTP.mapPonAniConfig[aUniID]))[0].mapGemPortParams[uint16(pos)] = &gemPortParamStruct{}
529 }
530 (*(onuTP.mapPonAniConfig[aUniID]))[0].mapGemPortParams[uint16(pos)].gemPortID =
531 uint16(content.GemportID)
532 //direction can be correlated later with Downstream list,
533 // for now just assume bidirectional (upstream never exists alone)
534 (*(onuTP.mapPonAniConfig[aUniID]))[0].mapGemPortParams[uint16(pos)].direction = 3 //as defined in G.988
535 // expected Prio-Queue values 0..7 with 7 for highest PrioQueue, QueueIndex=Prio = 0..7
536 if 7 < content.PriorityQueue {
537 logger.Errorw("PonAniConfig reject on GemPortList - PrioQueue value invalid",
538 log.Fields{"device-id": onuTP.deviceID, "index": pos, "PrioQueue": content.PriorityQueue})
539 //remove PonAniConfig as done so far, delete map should be safe, even if not existing
540 delete(onuTP.mapPonAniConfig, aUniID)
541 onuTP.chTpConfigProcessingStep <- 0 //error indication
542 return
543 }
544 (*(onuTP.mapPonAniConfig[aUniID]))[0].mapGemPortParams[uint16(pos)].prioQueueIndex =
545 uint8(content.PriorityQueue)
546 (*(onuTP.mapPonAniConfig[aUniID]))[0].mapGemPortParams[uint16(pos)].pbitString =
547 strings.TrimPrefix(content.PbitMap, binaryStringPrefix)
548 if content.AesEncryption == "True" {
549 (*(onuTP.mapPonAniConfig[aUniID]))[0].mapGemPortParams[uint16(pos)].gemPortEncState = 1
550 } else {
551 (*(onuTP.mapPonAniConfig[aUniID]))[0].mapGemPortParams[uint16(pos)].gemPortEncState = 0
552 }
553 (*(onuTP.mapPonAniConfig[aUniID]))[0].mapGemPortParams[uint16(pos)].discardPolicy =
554 content.DiscardPolicy
555 (*(onuTP.mapPonAniConfig[aUniID]))[0].mapGemPortParams[uint16(pos)].queueSchedPolicy =
556 content.SchedulingPolicy
557 //'GemWeight' looks strange in default profile, for now we just copy the weight to first queue
558 (*(onuTP.mapPonAniConfig[aUniID]))[0].mapGemPortParams[uint16(pos)].queueWeight =
559 uint8(content.Weight)
560 }
561 if !loGemPortRead {
562 logger.Errorw("PonAniConfig reject - no GemPort could be read from TechProfile",
563 log.Fields{"path": aPathString, "device-id": onuTP.deviceID})
564 //remove PonAniConfig as done so far, delete map should be safe, even if not existing
565 delete(onuTP.mapPonAniConfig, aUniID)
566 onuTP.chTpConfigProcessingStep <- 0 //error indication
567 return
568 }
569
570 logger.Debugw("PonAniConfig read from TechProfile", log.Fields{
571 "device-id": onuTP.deviceID,
572 "AllocId": (*(onuTP.mapPonAniConfig[aUniID]))[0].tcontParams.allocID})
573 for gemIndex, gemEntry := range (*(onuTP.mapPonAniConfig[0]))[0].mapGemPortParams {
574 logger.Debugw("PonAniConfig read from TechProfile", log.Fields{
575 "GemIndex": gemIndex,
576 "GemPort": gemEntry.gemPortID,
577 "QueueScheduling": gemEntry.queueSchedPolicy})
578 }
579
580 onuTP.chTpConfigProcessingStep <- aProcessingStep //done
581}
582
583func (onuTP *onuUniTechProf) setAniSideConfigFromTechProfile(
584 ctx context.Context, aUniID uint8, apCurrentUniPort *onuUniPort, aProcessingStep uint8) {
585
586 if onuTP.pAniConfigFsm == nil {
587 onuTP.createAniConfigFsm(aUniID, apCurrentUniPort, OmciAniConfigDone, aProcessingStep)
588 } else { //AniConfigFsm already init
589 onuTP.runAniConfigFsm(aProcessingStep)
590 }
591}
592
593func (onuTP *onuUniTechProf) waitForTimeoutOrCompletion(
594 ctx context.Context, aChTpProcessingStep <-chan uint8, aProcessingStep uint8) bool {
595 select {
596 case <-ctx.Done():
597 logger.Warnw("processing not completed in-time: force release of TpProcMutex!",
598 log.Fields{"device-id": onuTP.deviceID, "error": ctx.Err()})
599 return false
600 case rxStep := <-aChTpProcessingStep:
601 if rxStep == aProcessingStep {
602 return true
603 }
604 //all other values are not accepted - including 0 for error indication
605 logger.Warnw("Invalid processing step received: abort and force release of TpProcMutex!",
606 log.Fields{"device-id": onuTP.deviceID,
607 "wantedStep": aProcessingStep, "haveStep": rxStep})
608 return false
609 }
610}
611
612// createUniLockFsm initializes and runs the AniConfig FSM to transfer the OMCI related commands for ANI side configuration
613func (onuTP *onuUniTechProf) createAniConfigFsm(aUniID uint8,
614 apCurrentUniPort *onuUniPort, devEvent OnuDeviceEvent, aProcessingStep uint8) {
615 logger.Debugw("createAniConfigFsm", log.Fields{"device-id": onuTP.deviceID})
616 chAniConfigFsm := make(chan Message, 2048)
617 pDevEntry := onuTP.baseDeviceHandler.getOnuDeviceEntry(true)
618 if pDevEntry == nil {
619 logger.Errorw("No valid OnuDevice - aborting", log.Fields{"device-id": onuTP.deviceID})
620 return
621 }
622 pAniCfgFsm := newUniPonAniConfigFsm(pDevEntry.PDevOmciCC, apCurrentUniPort, onuTP,
623 pDevEntry.pOnuDB, onuTP.mapUniTpIndication[aUniID].techProfileID, devEvent,
624 "AniConfigFsm", onuTP.deviceID, chAniConfigFsm)
625 if pAniCfgFsm != nil {
626 onuTP.pAniConfigFsm = pAniCfgFsm
627 onuTP.runAniConfigFsm(aProcessingStep)
628 } else {
629 logger.Errorw("AniConfigFSM could not be created - abort!!", log.Fields{"device-id": onuTP.deviceID})
630 }
631}
632
633// runAniConfigFsm starts the AniConfig FSM to transfer the OMCI related commands for ANI side configuration
634func (onuTP *onuUniTechProf) runAniConfigFsm(aProcessingStep uint8) {
635 /* Uni related ANI config procedure -
636 ***** should run via 'aniConfigDone' state and generate the argument requested event *****
637 */
638 pACStatemachine := onuTP.pAniConfigFsm.pAdaptFsm.pFsm
639 if pACStatemachine != nil {
640 if pACStatemachine.Is(aniStDisabled) {
641 //FSM init requirement to get informed abou FSM completion! (otherwise timeout of the TechProf config)
642 onuTP.pAniConfigFsm.setFsmCompleteChannel(onuTP.chTpConfigProcessingStep, aProcessingStep)
643 if err := pACStatemachine.Event(aniEvStart); err != nil {
644 logger.Warnw("AniConfigFSM: can't start", log.Fields{"err": err})
645 // maybe try a FSM reset and then again ... - TODO!!!
646 } else {
647 /***** AniConfigFSM started */
648 logger.Debugw("AniConfigFSM started", log.Fields{
649 "state": pACStatemachine.Current(), "device-id": onuTP.deviceID})
650 }
651 } else {
652 logger.Warnw("wrong state of AniConfigFSM - want: disabled", log.Fields{
653 "have": pACStatemachine.Current(), "device-id": onuTP.deviceID})
654 // maybe try a FSM reset and then again ... - TODO!!!
655 }
656 } else {
657 logger.Errorw("AniConfigFSM StateMachine invalid - cannot be executed!!", log.Fields{"device-id": onuTP.deviceID})
658 // maybe try a FSM reset and then again ... - TODO!!!
659 }
660}
661
662// setConfigDone sets the requested techProfile config state (if possible)
663func (onuTP *onuUniTechProf) setConfigDone(aUniID uint8, aState bool) {
664 if _, existTP := onuTP.mapUniTpIndication[aUniID]; existTP {
665 onuTP.mutexTPState.Lock()
666 onuTP.mapUniTpIndication[aUniID].techProfileConfigDone = aState
667 onuTP.mutexTPState.Unlock()
668 } //else: the state is just ignored (does not exist)
669}
670
671// getTechProfileDone checks if the Techprofile processing with the requested TechProfile ID was done
672func (onuTP *onuUniTechProf) getTechProfileDone(aUniID uint8, aTpID uint16) bool {
673 if _, existTP := onuTP.mapUniTpIndication[aUniID]; existTP {
674 if onuTP.mapUniTpIndication[aUniID].techProfileID == aTpID {
675 onuTP.mutexTPState.Lock()
676 defer onuTP.mutexTPState.Unlock()
677 return onuTP.mapUniTpIndication[aUniID].techProfileConfigDone
678 }
679 }
680 return false
681}