blob: e052684c81729c513fcd89800b0f8f793c7f4a0f [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"
Andrea Campanella6515c582020-10-05 11:25:00 +020024 "fmt"
mpagenko3dbcdd22020-07-22 07:38:45 +000025 "strconv"
26 "strings"
mpagenkoaf801632020-07-03 10:00:42 +000027 "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"
Holger Hildebrandt9ca8b132020-08-07 14:45:03 +000036
37//definitions for TechProfileProcessing - copied from OltAdapter:openolt_flowmgr.go
38// could perhaps be defined more globally
39const (
Himani Chawla6d2ae152020-09-02 13:11:20 +053040 // binaryStringPrefix is binary string prefix
41 binaryStringPrefix = "0b"
42 // binaryBit1 is binary bit 1 expressed as a character
43 //binaryBit1 = '1'
Holger Hildebrandt9ca8b132020-08-07 14:45:03 +000044)
mpagenkoaf801632020-07-03 10:00:42 +000045
46type resourceEntry int
47
48const (
49 cResourceGemPort resourceEntry = 1
50 cResourceTcont resourceEntry = 2
51)
52
mpagenko3dbcdd22020-07-22 07:38:45 +000053type tTechProfileIndication struct {
mpagenkodff5dda2020-08-28 11:52:01 +000054 techProfileType string
55 techProfileID uint16
56 techProfileConfigDone bool
mpagenko3dbcdd22020-07-22 07:38:45 +000057}
58
59type tcontParamStruct struct {
60 allocID uint16
61 schedPolicy uint8
62}
63type gemPortParamStruct struct {
Himani Chawla4d908332020-08-31 12:30:20 +053064 //ponOmciCC bool
mpagenko3dbcdd22020-07-22 07:38:45 +000065 gemPortID uint16
66 direction uint8
67 gemPortEncState uint8
Holger Hildebrandt9ca8b132020-08-07 14:45:03 +000068 prioQueueIndex uint8
69 pbitString string
mpagenko3dbcdd22020-07-22 07:38:45 +000070 discardPolicy string
Himani Chawla4d908332020-08-31 12:30:20 +053071 //could also be a queue specific parameter, not used that way here
72 //maxQueueSize uint16
mpagenko3dbcdd22020-07-22 07:38:45 +000073 queueSchedPolicy string
74 queueWeight uint8
75}
76
77//refers to one tcont and its properties and all assigned GemPorts and their properties
78type tcontGemList struct {
79 tcontParams tcontParamStruct
80 mapGemPortParams map[uint16]*gemPortParamStruct
81}
82
83//refers to all tcont and their Tcont/GemPort Parameters
84type tMapPonAniConfig map[uint16]*tcontGemList
85
Himani Chawla6d2ae152020-09-02 13:11:20 +053086//onuUniTechProf structure holds information about the TechProfiles attached to Uni Ports of the ONU
87type onuUniTechProf struct {
Himani Chawla6d2ae152020-09-02 13:11:20 +053088 baseDeviceHandler *deviceHandler
mpagenko01e726e2020-10-23 09:45:29 +000089 deviceID string
mpagenkodff5dda2020-08-28 11:52:01 +000090 tpProcMutex sync.RWMutex
mpagenkodff5dda2020-08-28 11:52:01 +000091 techProfileKVStore *db.Backend
mpagenkodff5dda2020-08-28 11:52:01 +000092 chTpConfigProcessingStep chan uint8
mpagenkodff5dda2020-08-28 11:52:01 +000093 mapUniTpIndication map[uint8]*tTechProfileIndication //use pointer values to ease assignments to the map
94 mapPonAniConfig map[uint8]*tMapPonAniConfig //per UNI: use pointer values to ease assignments to the map
Himani Chawla6d2ae152020-09-02 13:11:20 +053095 pAniConfigFsm *uniPonAniConfigFsm
mpagenkodff5dda2020-08-28 11:52:01 +000096 procResult error //error indication of processing
97 mutexTPState sync.Mutex
mpagenko01e726e2020-10-23 09:45:29 +000098 tpProfileExists bool
mpagenkoaf801632020-07-03 10:00:42 +000099}
100
Himani Chawla6d2ae152020-09-02 13:11:20 +0530101//newOnuUniTechProf returns the instance of a OnuUniTechProf
mpagenkoaf801632020-07-03 10:00:42 +0000102//(one instance per ONU/deviceHandler for all possible UNI's)
mpagenko01e726e2020-10-23 09:45:29 +0000103func newOnuUniTechProf(ctx context.Context, aDeviceHandler *deviceHandler) *onuUniTechProf {
104 logger.Infow("init-OnuUniTechProf", log.Fields{"device-id": aDeviceHandler.deviceID})
Himani Chawla6d2ae152020-09-02 13:11:20 +0530105 var onuTP onuUniTechProf
mpagenkoaf801632020-07-03 10:00:42 +0000106 onuTP.baseDeviceHandler = aDeviceHandler
mpagenko01e726e2020-10-23 09:45:29 +0000107 onuTP.deviceID = aDeviceHandler.deviceID
mpagenkoaf801632020-07-03 10:00:42 +0000108 onuTP.tpProcMutex = sync.RWMutex{}
mpagenkodff5dda2020-08-28 11:52:01 +0000109 onuTP.chTpConfigProcessingStep = make(chan uint8)
mpagenkodff5dda2020-08-28 11:52:01 +0000110 onuTP.mapUniTpIndication = make(map[uint8]*tTechProfileIndication)
111 onuTP.mapPonAniConfig = make(map[uint8]*tMapPonAniConfig)
mpagenko1cc3cb42020-07-27 15:24:38 +0000112 onuTP.procResult = nil //default assumption processing done with success
mpagenkoaf801632020-07-03 10:00:42 +0000113
Himani Chawla6d2ae152020-09-02 13:11:20 +0530114 onuTP.techProfileKVStore = aDeviceHandler.setBackend(cBasePathTechProfileKVStore)
mpagenkoaf801632020-07-03 10:00:42 +0000115 if onuTP.techProfileKVStore == nil {
116 logger.Errorw("Can't access techProfileKVStore - no backend connection to service",
mpagenko01e726e2020-10-23 09:45:29 +0000117 log.Fields{"device-id": aDeviceHandler.deviceID, "service": cBasePathTechProfileKVStore})
mpagenkoaf801632020-07-03 10:00:42 +0000118 }
Holger Hildebrandt9ca8b132020-08-07 14:45:03 +0000119
mpagenkoaf801632020-07-03 10:00:42 +0000120 return &onuTP
121}
122
123// lockTpProcMutex locks OnuUniTechProf processing mutex
Himani Chawla6d2ae152020-09-02 13:11:20 +0530124func (onuTP *onuUniTechProf) lockTpProcMutex() {
mpagenkoaf801632020-07-03 10:00:42 +0000125 onuTP.tpProcMutex.Lock()
126}
127
128// unlockTpProcMutex unlocks OnuUniTechProf processing mutex
Himani Chawla6d2ae152020-09-02 13:11:20 +0530129func (onuTP *onuUniTechProf) unlockTpProcMutex() {
mpagenkoaf801632020-07-03 10:00:42 +0000130 onuTP.tpProcMutex.Unlock()
131}
132
Holger Hildebrandt47555e72020-09-21 11:07:24 +0000133// resetTpProcessingErrorIndication resets the internal error indication
mpagenko1cc3cb42020-07-27 15:24:38 +0000134// need to be called before evaluation of any subsequent processing (given by waitForTpCompletion())
Holger Hildebrandt47555e72020-09-21 11:07:24 +0000135func (onuTP *onuUniTechProf) resetTpProcessingErrorIndication() {
mpagenko1cc3cb42020-07-27 15:24:38 +0000136 onuTP.procResult = nil
137}
138
Holger Hildebrandt47555e72020-09-21 11:07:24 +0000139func (onuTP *onuUniTechProf) getTpProcessingErrorIndication() error {
mpagenko1cc3cb42020-07-27 15:24:38 +0000140 return onuTP.procResult
mpagenko3dbcdd22020-07-22 07:38:45 +0000141}
142
143// configureUniTp checks existing tp resources to delete and starts the corresponding OMCI configuation of the UNI port
144// all possibly blocking processing must be run in background to allow for deadline supervision!
145// but take care on sequential background processing when needed (logical dependencies)
Himani Chawla4d908332020-08-31 12:30:20 +0530146// use waitForTimeoutOrCompletion(ctx, chTpConfigProcessingStep, processingStep) for internal synchronization
Himani Chawla6d2ae152020-09-02 13:11:20 +0530147func (onuTP *onuUniTechProf) configureUniTp(ctx context.Context,
mpagenkodff5dda2020-08-28 11:52:01 +0000148 aUniID uint8, aPathString string, wg *sync.WaitGroup) {
mpagenko3dbcdd22020-07-22 07:38:45 +0000149 defer wg.Done() //always decrement the waitGroup on return
mpagenkoaf801632020-07-03 10:00:42 +0000150 logger.Debugw("configure the Uni according to TpPath", log.Fields{
mpagenko01e726e2020-10-23 09:45:29 +0000151 "device-id": onuTP.deviceID, "uni-id": aUniID, "path": aPathString})
mpagenkoaf801632020-07-03 10:00:42 +0000152
mpagenkoaf801632020-07-03 10:00:42 +0000153 if onuTP.techProfileKVStore == nil {
154 logger.Debug("techProfileKVStore not set - abort")
Himani Chawla26e555c2020-08-31 12:30:20 +0530155 onuTP.procResult = errors.New("techProfile config aborted: techProfileKVStore not set")
mpagenkoaf801632020-07-03 10:00:42 +0000156 return
157 }
158
mpagenko3dbcdd22020-07-22 07:38:45 +0000159 //ensure that the given uniID is available (configured) in the UniPort class (used for OMCI entities)
Himani Chawla6d2ae152020-09-02 13:11:20 +0530160 var pCurrentUniPort *onuUniPort
mpagenko3dbcdd22020-07-22 07:38:45 +0000161 for _, uniPort := range onuTP.baseDeviceHandler.uniEntityMap {
162 // only if this port is validated for operState transfer
Himani Chawla26e555c2020-08-31 12:30:20 +0530163 if uniPort.uniID == uint8(aUniID) {
mpagenko3dbcdd22020-07-22 07:38:45 +0000164 pCurrentUniPort = uniPort
165 break //found - end search loop
166 }
167 }
168 if pCurrentUniPort == nil {
169 logger.Errorw("TechProfile configuration aborted: requested uniID not found in PortDB",
mpagenko01e726e2020-10-23 09:45:29 +0000170 log.Fields{"device-id": onuTP.deviceID, "uni-id": aUniID})
Andrea Campanella6515c582020-10-05 11:25:00 +0200171 onuTP.procResult = fmt.Errorf("techProfile config aborted: requested uniID not found %d on %s",
172 aUniID, onuTP.deviceID)
mpagenko3dbcdd22020-07-22 07:38:45 +0000173 return
174 }
mpagenkoaf801632020-07-03 10:00:42 +0000175
mpagenkodff5dda2020-08-28 11:52:01 +0000176 var processingStep uint8 = 1 // used to synchronize the different processing steps with chTpConfigProcessingStep
mpagenkoaf801632020-07-03 10:00:42 +0000177
mpagenko3dbcdd22020-07-22 07:38:45 +0000178 //according to updateOnuUniTpPath() logic the assumption here is, that this configuration is only called
179 // in case the KVPath has changed for the given UNI,
180 // as T-Cont and Gem-Id's are dependent on TechProfile-Id this means, that possibly previously existing
181 // (ANI) configuration of this port has to be removed first
182 // (moreover in this case a possibly existing flow configuration is also not valid anymore and needs clean-up as well)
183 // existence of configuration can be detected based on tp stored TCONT's
Andrea Campanella6515c582020-10-05 11:25:00 +0200184 //TODO:
mpagenko3dbcdd22020-07-22 07:38:45 +0000185 /* if tcontMap not empty {
186 go onuTP.deleteAniSideConfig(ctx, aUniID, processingStep)
mpagenkodff5dda2020-08-28 11:52:01 +0000187 if !onuTP.waitForTimeoutOrCompletion(ctx, chTpConfigProcessingStep, processingStep) {
mpagenko3dbcdd22020-07-22 07:38:45 +0000188 //timeout or error detected
189 return
190 }
191 clear tcontMap
192 }
193
194 processingStep++
195 */
196 go onuTP.readAniSideConfigFromTechProfile(ctx, aUniID, aPathString, processingStep)
mpagenkodff5dda2020-08-28 11:52:01 +0000197 if !onuTP.waitForTimeoutOrCompletion(ctx, onuTP.chTpConfigProcessingStep, processingStep) {
mpagenko3dbcdd22020-07-22 07:38:45 +0000198 //timeout or error detected
mpagenko01e726e2020-10-23 09:45:29 +0000199 if onuTP.tpProfileExists {
200 //ignore the internal error in case the new profile is already configured
201 // and abort the processing here
202 return
203 }
mpagenko3dbcdd22020-07-22 07:38:45 +0000204 logger.Debugw("tech-profile related configuration aborted on read",
mpagenko01e726e2020-10-23 09:45:29 +0000205 log.Fields{"device-id": onuTP.deviceID, "uni-id": aUniID})
Andrea Campanella6515c582020-10-05 11:25:00 +0200206 onuTP.procResult = fmt.Errorf("techProfile config aborted: tech-profile read issue for %d on %s",
207 aUniID, onuTP.deviceID)
mpagenko3dbcdd22020-07-22 07:38:45 +0000208 return
209 }
210
211 processingStep++
212 if valuePA, existPA := onuTP.mapPonAniConfig[aUniID]; existPA {
213 if _, existTG := (*valuePA)[0]; existTG {
214 //Config data for this uni and and at least TCont Index 0 exist
215 go onuTP.setAniSideConfigFromTechProfile(ctx, aUniID, pCurrentUniPort, processingStep)
mpagenkodff5dda2020-08-28 11:52:01 +0000216 if !onuTP.waitForTimeoutOrCompletion(ctx, onuTP.chTpConfigProcessingStep, processingStep) {
mpagenko3dbcdd22020-07-22 07:38:45 +0000217 //timeout or error detected
218 logger.Debugw("tech-profile related configuration aborted on set",
mpagenko01e726e2020-10-23 09:45:29 +0000219 log.Fields{"device-id": onuTP.deviceID, "uni-id": aUniID})
Andrea Campanella6515c582020-10-05 11:25:00 +0200220 onuTP.procResult = fmt.Errorf("techProfile config aborted: Omci AniSideConfig failed %d on %s",
221 aUniID, onuTP.deviceID)
Himani Chawla4d908332020-08-31 12:30:20 +0530222 //this issue here means that the AniConfigFsm has not finished successfully
mpagenko3dbcdd22020-07-22 07:38:45 +0000223 //which requires to reset it to allow for new usage, e.g. also on a different UNI
224 //(without that it would be reset on device down indication latest)
Himani Chawla4d908332020-08-31 12:30:20 +0530225 _ = onuTP.pAniConfigFsm.pAdaptFsm.pFsm.Event(aniEvReset)
mpagenko3dbcdd22020-07-22 07:38:45 +0000226 return
mpagenkoaf801632020-07-03 10:00:42 +0000227 }
228 } else {
mpagenko3dbcdd22020-07-22 07:38:45 +0000229 // strange: UNI entry exists, but no ANI data, maybe such situation should be cleared up (if observed)
230 logger.Debugw("no Tcont/Gem data for this UNI found - abort", log.Fields{
mpagenko01e726e2020-10-23 09:45:29 +0000231 "device-id": onuTP.deviceID, "uni-id": aUniID})
Andrea Campanella6515c582020-10-05 11:25:00 +0200232 onuTP.procResult = fmt.Errorf("techProfile config aborted: no Tcont/Gem data found for this UNI %d on %s",
233 aUniID, onuTP.deviceID)
mpagenko1cc3cb42020-07-27 15:24:38 +0000234 return
mpagenkoaf801632020-07-03 10:00:42 +0000235 }
236 } else {
mpagenko3dbcdd22020-07-22 07:38:45 +0000237 logger.Debugw("no PonAni data for this UNI found - abort", log.Fields{
mpagenko01e726e2020-10-23 09:45:29 +0000238 "device-id": onuTP.deviceID, "uni-id": aUniID})
Andrea Campanella6515c582020-10-05 11:25:00 +0200239 onuTP.procResult = fmt.Errorf("techProfile config aborted: no AniSide data found for this UNI %d on %s",
240 aUniID, onuTP.deviceID)
mpagenko1cc3cb42020-07-27 15:24:38 +0000241 return
mpagenkoaf801632020-07-03 10:00:42 +0000242 }
243}
244
mpagenko3dbcdd22020-07-22 07:38:45 +0000245/* internal methods *********************/
Holger Hildebrandt9ca8b132020-08-07 14:45:03 +0000246
Himani Chawla6d2ae152020-09-02 13:11:20 +0530247func (onuTP *onuUniTechProf) readAniSideConfigFromTechProfile(
mpagenkodff5dda2020-08-28 11:52:01 +0000248 ctx context.Context, aUniID uint8, aPathString string, aProcessingStep uint8) {
mpagenko3dbcdd22020-07-22 07:38:45 +0000249 var tpInst tp.TechProfile
250
mpagenko01e726e2020-10-23 09:45:29 +0000251 onuTP.tpProfileExists = false
mpagenko3dbcdd22020-07-22 07:38:45 +0000252 //store profile type and identifier for later usage within the OMCI identifier and possibly ME setup
253 //pathstring is defined to be in the form of <ProfType>/<profID>/<Interface/../Identifier>
254 subStringSlice := strings.Split(aPathString, "/")
255 if len(subStringSlice) <= 2 {
256 logger.Errorw("invalid path name format",
257 log.Fields{"path": aPathString, "device-id": onuTP.deviceID})
mpagenkodff5dda2020-08-28 11:52:01 +0000258 onuTP.chTpConfigProcessingStep <- 0 //error indication
mpagenko3dbcdd22020-07-22 07:38:45 +0000259 return
260 }
mpagenko01e726e2020-10-23 09:45:29 +0000261 profID, err := strconv.ParseUint(subStringSlice[1], 10, 32)
262 if err != nil {
263 logger.Errorw("invalid ProfileId from path",
264 log.Fields{"ParseErr": err})
265 onuTP.chTpConfigProcessingStep <- 0 //error indication
266 return
267 }
mpagenko3dbcdd22020-07-22 07:38:45 +0000268
mpagenko3dbcdd22020-07-22 07:38:45 +0000269 //at this point it is assumed that a new TechProfile is assigned to the UNI
mpagenko01e726e2020-10-23 09:45:29 +0000270 //expectation is that no TPIndication entry exists here, if exists and with the same TPId
271 // then we throw a warning, set an internal error and abort with error,
272 // which is later re-defined to success response to OLT adapter
273 // if TPId has changed, current data is removed (note that the ONU config state may be
274 // ambivalent in such a case)
mpagenko3dbcdd22020-07-22 07:38:45 +0000275 if _, existTP := onuTP.mapUniTpIndication[aUniID]; existTP {
276 logger.Warnw("Some active profile entry at reading new TechProfile",
277 log.Fields{"path": aPathString, "device-id": onuTP.deviceID,
mpagenko01e726e2020-10-23 09:45:29 +0000278 "uni-id": aUniID, "wrongProfile": onuTP.mapUniTpIndication[aUniID].techProfileID})
279 if uint16(profID) == onuTP.mapUniTpIndication[aUniID].techProfileID {
280 // ProfId not changed - assume profile to be still the same
281 // anyway this should not appear after full support of profile (Gem/TCont) removal
282 logger.Warnw("New TechProfile already exists - aborting configuration",
283 log.Fields{"device-id": onuTP.deviceID})
284 onuTP.tpProfileExists = true
285 onuTP.chTpConfigProcessingStep <- 0 //error indication
286 return
287 }
mpagenko3dbcdd22020-07-22 07:38:45 +0000288 //delete on the mapUniTpIndication map not needed, just overwritten later
289 //delete on the PonAniConfig map should be safe, even if not existing
290 delete(onuTP.mapPonAniConfig, aUniID)
291 } else {
292 // this is normal processing
293 onuTP.mapUniTpIndication[aUniID] = &tTechProfileIndication{} //need to assign some (empty) struct memory first!
294 }
295
296 onuTP.mapUniTpIndication[aUniID].techProfileType = subStringSlice[0]
mpagenko3dbcdd22020-07-22 07:38:45 +0000297 //note the limitation on ID range (probably even more limited) - based on usage within OMCI EntityID
298 onuTP.mapUniTpIndication[aUniID].techProfileID = uint16(profID)
mpagenko01e726e2020-10-23 09:45:29 +0000299 onuTP.mapUniTpIndication[aUniID].techProfileConfigDone = false
mpagenko3dbcdd22020-07-22 07:38:45 +0000300 logger.Debugw("tech-profile path indications",
mpagenko01e726e2020-10-23 09:45:29 +0000301 log.Fields{"device-id": onuTP.deviceID, "uni-id": aUniID,
mpagenko3dbcdd22020-07-22 07:38:45 +0000302 "profType": onuTP.mapUniTpIndication[aUniID].techProfileType,
303 "profID": onuTP.mapUniTpIndication[aUniID].techProfileID})
304
Holger Hildebrandt9ca8b132020-08-07 14:45:03 +0000305 Value, err := onuTP.techProfileKVStore.Get(ctx, aPathString)
mpagenko3dbcdd22020-07-22 07:38:45 +0000306 if err == nil {
307 if Value != nil {
308 logger.Debugw("tech-profile read",
309 log.Fields{"Key": Value.Key, "device-id": onuTP.deviceID})
310 tpTmpBytes, _ := kvstore.ToByte(Value.Value)
311
312 if err = json.Unmarshal(tpTmpBytes, &tpInst); err != nil {
313 logger.Errorw("TechProf - Failed to unmarshal tech-profile into tpInst",
314 log.Fields{"error": err, "device-id": onuTP.deviceID})
mpagenkodff5dda2020-08-28 11:52:01 +0000315 onuTP.chTpConfigProcessingStep <- 0 //error indication
mpagenko3dbcdd22020-07-22 07:38:45 +0000316 return
317 }
318 logger.Debugw("TechProf - tpInst", log.Fields{"tpInst": tpInst})
319 // access examples
320 logger.Debugw("TechProf content", log.Fields{"Name": tpInst.Name,
321 "MaxGemPayloadSize": tpInst.InstanceCtrl.MaxGemPayloadSize,
322 "DownstreamGemDiscardmaxThreshold": tpInst.DownstreamGemPortAttributeList[0].DiscardConfig.MaxThreshold})
323 } else {
324 logger.Errorw("No tech-profile found",
325 log.Fields{"path": aPathString, "device-id": onuTP.deviceID})
mpagenkodff5dda2020-08-28 11:52:01 +0000326 onuTP.chTpConfigProcessingStep <- 0 //error indication
mpagenko3dbcdd22020-07-22 07:38:45 +0000327 return
328 }
329 } else {
330 logger.Errorw("kvstore-get failed for path",
331 log.Fields{"path": aPathString, "device-id": onuTP.deviceID})
mpagenkodff5dda2020-08-28 11:52:01 +0000332 onuTP.chTpConfigProcessingStep <- 0 //error indication
mpagenko3dbcdd22020-07-22 07:38:45 +0000333 return
334 }
335
mpagenko01e726e2020-10-23 09:45:29 +0000336 //default start with 1Tcont profile, later perhaps extend to MultiTcontMultiGem
mpagenko3dbcdd22020-07-22 07:38:45 +0000337 localMapGemPortParams := make(map[uint16]*gemPortParamStruct)
338 localMapGemPortParams[0] = &gemPortParamStruct{}
339 localMapPonAniConfig := make(map[uint16]*tcontGemList)
340 localMapPonAniConfig[0] = &tcontGemList{tcontParamStruct{}, localMapGemPortParams}
341 onuTP.mapPonAniConfig[aUniID] = (*tMapPonAniConfig)(&localMapPonAniConfig)
342
Holger Hildebrandt9ca8b132020-08-07 14:45:03 +0000343 //note: the code is currently restricted to one TCcont per Onu (index [0])
mpagenko3dbcdd22020-07-22 07:38:45 +0000344 //get the relevant values from the profile and store to mapPonAniConfig
345 (*(onuTP.mapPonAniConfig[aUniID]))[0].tcontParams.allocID = uint16(tpInst.UsScheduler.AllocID)
Himani Chawla4d908332020-08-31 12:30:20 +0530346 //maybe tCont scheduling not (yet) needed - just to basically have it for future
mpagenko3dbcdd22020-07-22 07:38:45 +0000347 // (would only be relevant in case of ONU-2G QOS configuration flexibility)
348 if tpInst.UsScheduler.QSchedPolicy == "StrictPrio" {
349 (*(onuTP.mapPonAniConfig[aUniID]))[0].tcontParams.schedPolicy = 1 //for the moment fixed value acc. G.988 //TODO: defines!
350 } else {
Holger Hildebrandt9ca8b132020-08-07 14:45:03 +0000351 //default profile defines "Hybrid" - which probably comes down to WRR with some weigthts for SP
mpagenko3dbcdd22020-07-22 07:38:45 +0000352 (*(onuTP.mapPonAniConfig[aUniID]))[0].tcontParams.schedPolicy = 2 //for G.988 WRR
353 }
mpagenko1cc3cb42020-07-27 15:24:38 +0000354 loNumGemPorts := tpInst.NumGemPorts
355 loGemPortRead := false
mpagenko3dbcdd22020-07-22 07:38:45 +0000356 for pos, content := range tpInst.UpstreamGemPortAttributeList {
mpagenko1cc3cb42020-07-27 15:24:38 +0000357 if uint32(pos) == loNumGemPorts {
358 logger.Debugw("PonAniConfig abort GemPortList - GemList exceeds set NumberOfGemPorts",
359 log.Fields{"device-id": onuTP.deviceID, "index": pos, "NumGem": loNumGemPorts})
mpagenko3dbcdd22020-07-22 07:38:45 +0000360 break
361 }
Holger Hildebrandt9ca8b132020-08-07 14:45:03 +0000362 if pos == 0 {
363 //at least one upstream GemPort should always exist (else traffic profile makes no sense)
364 loGemPortRead = true
365 } else {
366 //for all further GemPorts we need to extend the mapGemPortParams
367 (*(onuTP.mapPonAniConfig[aUniID]))[0].mapGemPortParams[uint16(pos)] = &gemPortParamStruct{}
368 }
369 (*(onuTP.mapPonAniConfig[aUniID]))[0].mapGemPortParams[uint16(pos)].gemPortID =
370 uint16(content.GemportID)
371 //direction can be correlated later with Downstream list,
372 // for now just assume bidirectional (upstream never exists alone)
mpagenko3dbcdd22020-07-22 07:38:45 +0000373 (*(onuTP.mapPonAniConfig[aUniID]))[0].mapGemPortParams[uint16(pos)].direction = 3 //as defined in G.988
Holger Hildebrandt9ca8b132020-08-07 14:45:03 +0000374 // expected Prio-Queue values 0..7 with 7 for highest PrioQueue, QueueIndex=Prio = 0..7
375 if 7 < content.PriorityQueue {
376 logger.Errorw("PonAniConfig reject on GemPortList - PrioQueue value invalid",
377 log.Fields{"device-id": onuTP.deviceID, "index": pos, "PrioQueue": content.PriorityQueue})
378 //remove PonAniConfig as done so far, delete map should be safe, even if not existing
379 delete(onuTP.mapPonAniConfig, aUniID)
mpagenkodff5dda2020-08-28 11:52:01 +0000380 onuTP.chTpConfigProcessingStep <- 0 //error indication
Holger Hildebrandt9ca8b132020-08-07 14:45:03 +0000381 return
382 }
383 (*(onuTP.mapPonAniConfig[aUniID]))[0].mapGemPortParams[uint16(pos)].prioQueueIndex =
384 uint8(content.PriorityQueue)
385 (*(onuTP.mapPonAniConfig[aUniID]))[0].mapGemPortParams[uint16(pos)].pbitString =
Himani Chawla6d2ae152020-09-02 13:11:20 +0530386 strings.TrimPrefix(content.PbitMap, binaryStringPrefix)
mpagenko3dbcdd22020-07-22 07:38:45 +0000387 if content.AesEncryption == "True" {
388 (*(onuTP.mapPonAniConfig[aUniID]))[0].mapGemPortParams[uint16(pos)].gemPortEncState = 1
389 } else {
390 (*(onuTP.mapPonAniConfig[aUniID]))[0].mapGemPortParams[uint16(pos)].gemPortEncState = 0
391 }
Holger Hildebrandt9ca8b132020-08-07 14:45:03 +0000392 (*(onuTP.mapPonAniConfig[aUniID]))[0].mapGemPortParams[uint16(pos)].discardPolicy =
393 content.DiscardPolicy
394 (*(onuTP.mapPonAniConfig[aUniID]))[0].mapGemPortParams[uint16(pos)].queueSchedPolicy =
395 content.SchedulingPolicy
mpagenko3dbcdd22020-07-22 07:38:45 +0000396 //'GemWeight' looks strange in default profile, for now we just copy the weight to first queue
Holger Hildebrandt9ca8b132020-08-07 14:45:03 +0000397 (*(onuTP.mapPonAniConfig[aUniID]))[0].mapGemPortParams[uint16(pos)].queueWeight =
398 uint8(content.Weight)
mpagenko3dbcdd22020-07-22 07:38:45 +0000399 }
Himani Chawla4d908332020-08-31 12:30:20 +0530400 if !loGemPortRead {
Holger Hildebrandt9ca8b132020-08-07 14:45:03 +0000401 logger.Errorw("PonAniConfig reject - no GemPort could be read from TechProfile",
mpagenko1cc3cb42020-07-27 15:24:38 +0000402 log.Fields{"path": aPathString, "device-id": onuTP.deviceID})
Holger Hildebrandt9ca8b132020-08-07 14:45:03 +0000403 //remove PonAniConfig as done so far, delete map should be safe, even if not existing
404 delete(onuTP.mapPonAniConfig, aUniID)
mpagenkodff5dda2020-08-28 11:52:01 +0000405 onuTP.chTpConfigProcessingStep <- 0 //error indication
mpagenko1cc3cb42020-07-27 15:24:38 +0000406 return
407 }
Himani Chawla4d908332020-08-31 12:30:20 +0530408 //TODO!! MC (downstream) GemPorts can be set using DownstreamGemPortAttributeList separately
mpagenko3dbcdd22020-07-22 07:38:45 +0000409
410 //logger does not simply output the given structures, just give some example debug values
411 logger.Debugw("PonAniConfig read from TechProfile", log.Fields{
Holger Hildebrandt9ca8b132020-08-07 14:45:03 +0000412 "device-id": onuTP.deviceID,
413 "AllocId": (*(onuTP.mapPonAniConfig[aUniID]))[0].tcontParams.allocID})
414 for gemIndex, gemEntry := range (*(onuTP.mapPonAniConfig[0]))[0].mapGemPortParams {
415 logger.Debugw("PonAniConfig read from TechProfile", log.Fields{
416 "GemIndex": gemIndex,
417 "GemPort": gemEntry.gemPortID,
418 "QueueScheduling": gemEntry.queueSchedPolicy})
419 }
mpagenko3dbcdd22020-07-22 07:38:45 +0000420
mpagenkodff5dda2020-08-28 11:52:01 +0000421 onuTP.chTpConfigProcessingStep <- aProcessingStep //done
mpagenko3dbcdd22020-07-22 07:38:45 +0000422}
423
Himani Chawla6d2ae152020-09-02 13:11:20 +0530424func (onuTP *onuUniTechProf) setAniSideConfigFromTechProfile(
425 ctx context.Context, aUniID uint8, apCurrentUniPort *onuUniPort, aProcessingStep uint8) {
mpagenko3dbcdd22020-07-22 07:38:45 +0000426
427 //OMCI transfer of ANI data acc. to mapPonAniConfig
428 // also the FSM's are running in background,
mpagenkodff5dda2020-08-28 11:52:01 +0000429 // hence we have to make sure they indicate 'success' success on chTpConfigProcessingStep with aProcessingStep
mpagenko3dbcdd22020-07-22 07:38:45 +0000430 if onuTP.pAniConfigFsm == nil {
431 onuTP.createAniConfigFsm(aUniID, apCurrentUniPort, OmciAniConfigDone, aProcessingStep)
432 } else { //AniConfigFsm already init
433 onuTP.runAniConfigFsm(aProcessingStep)
434 }
435}
436
Himani Chawla6d2ae152020-09-02 13:11:20 +0530437func (onuTP *onuUniTechProf) waitForTimeoutOrCompletion(
mpagenkodff5dda2020-08-28 11:52:01 +0000438 ctx context.Context, aChTpProcessingStep <-chan uint8, aProcessingStep uint8) bool {
mpagenko3dbcdd22020-07-22 07:38:45 +0000439 select {
440 case <-ctx.Done():
441 logger.Warnw("processing not completed in-time: force release of TpProcMutex!",
divyadesai4d299552020-08-18 07:13:49 +0000442 log.Fields{"device-id": onuTP.deviceID, "error": ctx.Err()})
mpagenko3dbcdd22020-07-22 07:38:45 +0000443 return false
mpagenkodff5dda2020-08-28 11:52:01 +0000444 case rxStep := <-aChTpProcessingStep:
mpagenko3dbcdd22020-07-22 07:38:45 +0000445 if rxStep == aProcessingStep {
446 return true
447 }
448 //all other values are not accepted - including 0 for error indication
449 logger.Warnw("Invalid processing step received: abort and force release of TpProcMutex!",
divyadesai4d299552020-08-18 07:13:49 +0000450 log.Fields{"device-id": onuTP.deviceID,
mpagenko3dbcdd22020-07-22 07:38:45 +0000451 "wantedStep": aProcessingStep, "haveStep": rxStep})
452 return false
453 }
454}
455
Himani Chawla4d908332020-08-31 12:30:20 +0530456// createUniLockFsm initializes and runs the AniConfig FSM to transfer the OMCI related commands for ANI side configuration
Himani Chawla6d2ae152020-09-02 13:11:20 +0530457func (onuTP *onuUniTechProf) createAniConfigFsm(aUniID uint8,
458 apCurrentUniPort *onuUniPort, devEvent OnuDeviceEvent, aProcessingStep uint8) {
divyadesai4d299552020-08-18 07:13:49 +0000459 logger.Debugw("createAniConfigFsm", log.Fields{"device-id": onuTP.deviceID})
mpagenko3dbcdd22020-07-22 07:38:45 +0000460 chAniConfigFsm := make(chan Message, 2048)
Himani Chawla6d2ae152020-09-02 13:11:20 +0530461 pDevEntry := onuTP.baseDeviceHandler.getOnuDeviceEntry(true)
mpagenko3dbcdd22020-07-22 07:38:45 +0000462 if pDevEntry == nil {
divyadesai4d299552020-08-18 07:13:49 +0000463 logger.Errorw("No valid OnuDevice - aborting", log.Fields{"device-id": onuTP.deviceID})
mpagenko3dbcdd22020-07-22 07:38:45 +0000464 return
465 }
Himani Chawla6d2ae152020-09-02 13:11:20 +0530466 pAniCfgFsm := newUniPonAniConfigFsm(pDevEntry.PDevOmciCC, apCurrentUniPort, onuTP,
mpagenko3dbcdd22020-07-22 07:38:45 +0000467 pDevEntry.pOnuDB, onuTP.mapUniTpIndication[aUniID].techProfileID, devEvent,
mpagenko01e726e2020-10-23 09:45:29 +0000468 "AniConfigFsm", onuTP.baseDeviceHandler, chAniConfigFsm)
mpagenko3dbcdd22020-07-22 07:38:45 +0000469 if pAniCfgFsm != nil {
470 onuTP.pAniConfigFsm = pAniCfgFsm
471 onuTP.runAniConfigFsm(aProcessingStep)
472 } else {
divyadesai4d299552020-08-18 07:13:49 +0000473 logger.Errorw("AniConfigFSM could not be created - abort!!", log.Fields{"device-id": onuTP.deviceID})
mpagenko3dbcdd22020-07-22 07:38:45 +0000474 }
475}
476
477// runAniConfigFsm starts the AniConfig FSM to transfer the OMCI related commands for ANI side configuration
Himani Chawla6d2ae152020-09-02 13:11:20 +0530478func (onuTP *onuUniTechProf) runAniConfigFsm(aProcessingStep uint8) {
mpagenko3dbcdd22020-07-22 07:38:45 +0000479 /* Uni related ANI config procedure -
480 ***** should run via 'aniConfigDone' state and generate the argument requested event *****
481 */
Himani Chawla4d908332020-08-31 12:30:20 +0530482 pACStatemachine := onuTP.pAniConfigFsm.pAdaptFsm.pFsm
mpagenko3dbcdd22020-07-22 07:38:45 +0000483 if pACStatemachine != nil {
mpagenko1cc3cb42020-07-27 15:24:38 +0000484 if pACStatemachine.Is(aniStDisabled) {
mpagenko3dbcdd22020-07-22 07:38:45 +0000485 //FSM init requirement to get informed abou FSM completion! (otherwise timeout of the TechProf config)
Himani Chawla6d2ae152020-09-02 13:11:20 +0530486 onuTP.pAniConfigFsm.setFsmCompleteChannel(onuTP.chTpConfigProcessingStep, aProcessingStep)
mpagenko1cc3cb42020-07-27 15:24:38 +0000487 if err := pACStatemachine.Event(aniEvStart); err != nil {
mpagenko3dbcdd22020-07-22 07:38:45 +0000488 logger.Warnw("AniConfigFSM: can't start", log.Fields{"err": err})
489 // maybe try a FSM reset and then again ... - TODO!!!
490 } else {
491 /***** AniConfigFSM started */
492 logger.Debugw("AniConfigFSM started", log.Fields{
divyadesai4d299552020-08-18 07:13:49 +0000493 "state": pACStatemachine.Current(), "device-id": onuTP.deviceID})
mpagenko3dbcdd22020-07-22 07:38:45 +0000494 }
495 } else {
496 logger.Warnw("wrong state of AniConfigFSM - want: disabled", log.Fields{
divyadesai4d299552020-08-18 07:13:49 +0000497 "have": pACStatemachine.Current(), "device-id": onuTP.deviceID})
mpagenko3dbcdd22020-07-22 07:38:45 +0000498 // maybe try a FSM reset and then again ... - TODO!!!
499 }
500 } else {
divyadesai4d299552020-08-18 07:13:49 +0000501 logger.Errorw("AniConfigFSM StateMachine invalid - cannot be executed!!", log.Fields{"device-id": onuTP.deviceID})
mpagenko3dbcdd22020-07-22 07:38:45 +0000502 // maybe try a FSM reset and then again ... - TODO!!!
503 }
mpagenkoaf801632020-07-03 10:00:42 +0000504}
mpagenkodff5dda2020-08-28 11:52:01 +0000505
mpagenko01e726e2020-10-23 09:45:29 +0000506// clearAniSideConfig deletes all internal TechProfile related data connected to the requested UniPort
507func (onuTP *onuUniTechProf) clearAniSideConfig(aUniID uint8) {
508 logger.Debugw("removing TpIndication and PonAniConfig data", log.Fields{
509 "device-id": onuTP.deviceID, "uni-id": aUniID})
510 //a mutex protection on the concerned data should not be needed here, as the config/write action should not
511 // interfere with any read action or the initial write/config activity at start
512 //remove the TechProfile indications of this UNI, should be safe even if not existing
513 delete(onuTP.mapUniTpIndication, aUniID)
514 //delete on the PonAniConfig map of this UNI should be safe, even if not existing
515 delete(onuTP.mapPonAniConfig, aUniID)
516}
517
mpagenkodff5dda2020-08-28 11:52:01 +0000518// setConfigDone sets the requested techProfile config state (if possible)
Himani Chawla6d2ae152020-09-02 13:11:20 +0530519func (onuTP *onuUniTechProf) setConfigDone(aUniID uint8, aState bool) {
mpagenkodff5dda2020-08-28 11:52:01 +0000520 if _, existTP := onuTP.mapUniTpIndication[aUniID]; existTP {
521 onuTP.mutexTPState.Lock()
522 onuTP.mapUniTpIndication[aUniID].techProfileConfigDone = aState
523 onuTP.mutexTPState.Unlock()
524 } //else: the state is just ignored (does not exist)
525}
526
527// getTechProfileDone checks if the Techprofile processing with the requested TechProfile ID was done
Himani Chawla6d2ae152020-09-02 13:11:20 +0530528func (onuTP *onuUniTechProf) getTechProfileDone(aUniID uint8, aTpID uint16) bool {
mpagenkodff5dda2020-08-28 11:52:01 +0000529 if _, existTP := onuTP.mapUniTpIndication[aUniID]; existTP {
530 if onuTP.mapUniTpIndication[aUniID].techProfileID == aTpID {
531 onuTP.mutexTPState.Lock()
532 defer onuTP.mutexTPState.Unlock()
533 return onuTP.mapUniTpIndication[aUniID].techProfileConfigDone
534 }
535 }
536 //for all other constellations indicate false = Config not done
537 return false
538}