blob: 54e8a50d2429ea3b136f75e53ac1f2a5e2f79e37 [file] [log] [blame]
mpagenko3dbcdd22020-07-22 07:38:45 +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 "errors"
23 "strconv"
24 "time"
25
26 "github.com/looplab/fsm"
27
28 "github.com/opencord/omci-lib-go"
29 me "github.com/opencord/omci-lib-go/generated"
30 "github.com/opencord/voltha-lib-go/v3/pkg/log"
31 //ic "github.com/opencord/voltha-protos/v3/go/inter_container"
32 //"github.com/opencord/voltha-protos/v3/go/openflow_13"
33 //"github.com/opencord/voltha-protos/v3/go/voltha"
34)
35
mpagenko1cc3cb42020-07-27 15:24:38 +000036const (
37 // events of config PON ANI port FSM
38 aniEvStart = "uniEvStart"
39 aniEvStartConfig = "aniEvStartConfig"
40 aniEvRxDot1pmapCresp = "aniEvRxDot1pmapCresp"
41 aniEvRxMbpcdResp = "aniEvRxMbpcdResp"
42 aniEvRxTcontsResp = "aniEvRxTcontsResp"
43 aniEvRxGemntcpsResp = "aniEvRxGemntcpsResp"
44 aniEvRxGemiwsResp = "aniEvRxGemiwsResp"
45 aniEvRxPrioqsResp = "aniEvRxPrioqsResp"
46 aniEvRxDot1pmapSresp = "aniEvRxDot1pmapSresp"
47 aniEvTimeoutSimple = "aniEvTimeoutSimple"
48 aniEvTimeoutMids = "aniEvTimeoutMids"
49 aniEvReset = "aniEvReset"
50 aniEvRestart = "aniEvRestart"
51)
52const (
53 // states of config PON ANI port FSM
54 aniStDisabled = "aniStDisabled"
55 aniStStarting = "aniStStarting"
56 aniStCreatingDot1PMapper = "aniStCreatingDot1PMapper"
57 aniStCreatingMBPCD = "aniStCreatingMBPCD"
58 aniStSettingTconts = "aniStSettingTconts"
59 aniStCreatingGemNCTPs = "aniStCreatingGemNCTPs"
60 aniStCreatingGemIWs = "aniStCreatingGemIWs"
61 aniStSettingPQs = "aniStSettingPQs"
62 aniStSettingDot1PMapper = "aniStSettingDot1PMapper"
63 aniStConfigDone = "aniStConfigDone"
64 aniStResetting = "aniStResetting"
65)
66
67//UniPonAniConfigFsm defines the structure for the state machine to config the PON ANI ports of ONU UNI ports via OMCI
mpagenko3dbcdd22020-07-22 07:38:45 +000068type UniPonAniConfigFsm struct {
69 pOmciCC *OmciCC
70 pOnuUniPort *OnuUniPort
71 pUniTechProf *OnuUniTechProf
72 pOnuDB *OnuDeviceDB
73 techProfileID uint16
74 requestEvent OnuDeviceEvent
75 omciMIdsResponseReceived chan bool //seperate channel needed for checking multiInstance OMCI message responses
76 pAdaptFsm *AdapterFsm
mpagenko1cc3cb42020-07-27 15:24:38 +000077 aniConfigCompleted bool
mpagenko3dbcdd22020-07-22 07:38:45 +000078 chSuccess chan<- uint8
79 procStep uint8
80 chanSet bool
81 mapperSP0ID uint16
82 macBPCD0ID uint16
83 tcont0ID uint16
84 alloc0ID uint16
85 gemPortXID []uint16
86 upQueueXID []uint16
87 downQueueXID []uint16
88}
89
mpagenko1cc3cb42020-07-27 15:24:38 +000090//NewUniPonAniConfigFsm is the 'constructor' for the state machine to config the PON ANI ports of ONU UNI ports via OMCI
mpagenko3dbcdd22020-07-22 07:38:45 +000091func NewUniPonAniConfigFsm(apDevOmciCC *OmciCC, apUniPort *OnuUniPort, apUniTechProf *OnuUniTechProf,
92 apOnuDB *OnuDeviceDB, aTechProfileID uint16, aRequestEvent OnuDeviceEvent, aName string,
93 aDeviceID string, aCommChannel chan Message) *UniPonAniConfigFsm {
94 instFsm := &UniPonAniConfigFsm{
mpagenko1cc3cb42020-07-27 15:24:38 +000095 pOmciCC: apDevOmciCC,
96 pOnuUniPort: apUniPort,
97 pUniTechProf: apUniTechProf,
98 pOnuDB: apOnuDB,
99 techProfileID: aTechProfileID,
100 requestEvent: aRequestEvent,
101 aniConfigCompleted: false,
102 chanSet: false,
mpagenko3dbcdd22020-07-22 07:38:45 +0000103 }
104 instFsm.pAdaptFsm = NewAdapterFsm(aName, aDeviceID, aCommChannel)
105 if instFsm.pAdaptFsm == nil {
106 logger.Errorw("UniPonAniConfigFsm's AdapterFsm could not be instantiated!!", log.Fields{
107 "device-id": aDeviceID})
108 return nil
109 }
110
111 instFsm.pAdaptFsm.pFsm = fsm.NewFSM(
mpagenko1cc3cb42020-07-27 15:24:38 +0000112 aniStDisabled,
mpagenko3dbcdd22020-07-22 07:38:45 +0000113 fsm.Events{
114
mpagenko1cc3cb42020-07-27 15:24:38 +0000115 {Name: aniEvStart, Src: []string{aniStDisabled}, Dst: aniStStarting},
mpagenko3dbcdd22020-07-22 07:38:45 +0000116
117 //Note: .1p-Mapper and MBPCD might also have multi instances (per T-Cont) - by now only one 1 T-Cont considered!
mpagenko1cc3cb42020-07-27 15:24:38 +0000118 {Name: aniEvStartConfig, Src: []string{aniStStarting}, Dst: aniStCreatingDot1PMapper},
119 {Name: aniEvRxDot1pmapCresp, Src: []string{aniStCreatingDot1PMapper}, Dst: aniStCreatingMBPCD},
120 {Name: aniEvRxMbpcdResp, Src: []string{aniStCreatingMBPCD}, Dst: aniStSettingTconts},
121 {Name: aniEvRxTcontsResp, Src: []string{aniStSettingTconts}, Dst: aniStCreatingGemNCTPs},
mpagenko3dbcdd22020-07-22 07:38:45 +0000122 // the creatingGemNCTPs state is used for multi ME config if required for all configured/available GemPorts
mpagenko1cc3cb42020-07-27 15:24:38 +0000123 {Name: aniEvRxGemntcpsResp, Src: []string{aniStCreatingGemNCTPs}, Dst: aniStCreatingGemIWs},
mpagenko3dbcdd22020-07-22 07:38:45 +0000124 // the creatingGemIWs state is used for multi ME config if required for all configured/available GemPorts
mpagenko1cc3cb42020-07-27 15:24:38 +0000125 {Name: aniEvRxGemiwsResp, Src: []string{aniStCreatingGemIWs}, Dst: aniStSettingPQs},
mpagenko3dbcdd22020-07-22 07:38:45 +0000126 // the settingPQs state is used for multi ME config if required for all configured/available upstream PriorityQueues
mpagenko1cc3cb42020-07-27 15:24:38 +0000127 {Name: aniEvRxPrioqsResp, Src: []string{aniStSettingPQs}, Dst: aniStSettingDot1PMapper},
128 {Name: aniEvRxDot1pmapSresp, Src: []string{aniStSettingDot1PMapper}, Dst: aniStConfigDone},
mpagenko3dbcdd22020-07-22 07:38:45 +0000129
mpagenko1cc3cb42020-07-27 15:24:38 +0000130 {Name: aniEvTimeoutSimple, Src: []string{
131 aniStCreatingDot1PMapper, aniStCreatingMBPCD, aniStSettingTconts, aniStSettingDot1PMapper}, Dst: aniStStarting},
132 {Name: aniEvTimeoutMids, Src: []string{
133 aniStCreatingGemNCTPs, aniStCreatingGemIWs, aniStSettingPQs}, Dst: aniStStarting},
mpagenko3dbcdd22020-07-22 07:38:45 +0000134
mpagenko1cc3cb42020-07-27 15:24:38 +0000135 // exceptional treatment for all states except aniStResetting
136 {Name: aniEvReset, Src: []string{aniStStarting, aniStCreatingDot1PMapper, aniStCreatingMBPCD,
137 aniStSettingTconts, aniStCreatingGemNCTPs, aniStCreatingGemIWs, aniStSettingPQs, aniStSettingDot1PMapper,
138 aniStConfigDone}, Dst: aniStResetting},
mpagenko3dbcdd22020-07-22 07:38:45 +0000139 // the only way to get to resource-cleared disabled state again is via "resseting"
mpagenko1cc3cb42020-07-27 15:24:38 +0000140 {Name: aniEvRestart, Src: []string{aniStResetting}, Dst: aniStDisabled},
mpagenko3dbcdd22020-07-22 07:38:45 +0000141 },
142
143 fsm.Callbacks{
mpagenko1cc3cb42020-07-27 15:24:38 +0000144 "enter_state": func(e *fsm.Event) { instFsm.pAdaptFsm.logFsmStateChange(e) },
145 ("enter_" + aniStStarting): func(e *fsm.Event) { instFsm.enterConfigStartingState(e) },
146 ("enter_" + aniStCreatingDot1PMapper): func(e *fsm.Event) { instFsm.enterCreatingDot1PMapper(e) },
147 ("enter_" + aniStCreatingMBPCD): func(e *fsm.Event) { instFsm.enterCreatingMBPCD(e) },
148 ("enter_" + aniStSettingTconts): func(e *fsm.Event) { instFsm.enterSettingTconts(e) },
149 ("enter_" + aniStCreatingGemNCTPs): func(e *fsm.Event) { instFsm.enterCreatingGemNCTPs(e) },
150 ("enter_" + aniStCreatingGemIWs): func(e *fsm.Event) { instFsm.enterCreatingGemIWs(e) },
151 ("enter_" + aniStSettingPQs): func(e *fsm.Event) { instFsm.enterSettingPQs(e) },
152 ("enter_" + aniStSettingDot1PMapper): func(e *fsm.Event) { instFsm.enterSettingDot1PMapper(e) },
153 ("enter_" + aniStConfigDone): func(e *fsm.Event) { instFsm.enterAniConfigDone(e) },
154 ("enter_" + aniStResetting): func(e *fsm.Event) { instFsm.enterResettingState(e) },
155 ("enter_" + aniStDisabled): func(e *fsm.Event) { instFsm.enterDisabledState(e) },
mpagenko3dbcdd22020-07-22 07:38:45 +0000156 },
157 )
158 if instFsm.pAdaptFsm.pFsm == nil {
159 logger.Errorw("UniPonAniConfigFsm's Base FSM could not be instantiated!!", log.Fields{
160 "device-id": aDeviceID})
161 return nil
162 }
163
164 logger.Infow("UniPonAniConfigFsm created", log.Fields{"device-id": aDeviceID})
165 return instFsm
166}
167
168//SetFsmCompleteChannel sets the requested channel and channel result for transfer on success
169func (oFsm *UniPonAniConfigFsm) SetFsmCompleteChannel(aChSuccess chan<- uint8, aProcStep uint8) {
170 oFsm.chSuccess = aChSuccess
171 oFsm.procStep = aProcStep
172 oFsm.chanSet = true
173}
174
175func (oFsm *UniPonAniConfigFsm) enterConfigStartingState(e *fsm.Event) {
176 logger.Debugw("UniPonAniConfigFsm start", log.Fields{"in state": e.FSM.Current(),
177 "device-id": oFsm.pAdaptFsm.deviceID})
178 // in case the used channel is not yet defined (can be re-used after restarts)
179 if oFsm.omciMIdsResponseReceived == nil {
180 oFsm.omciMIdsResponseReceived = make(chan bool)
181 logger.Debug("UniPonAniConfigFsm - OMCI multiInstance RxChannel defined")
182 } else {
183 // as we may 're-use' this instance of FSM and the connected channel
184 // make sure there is no 'lingering' request in the already existing channel:
185 // (simple loop sufficient as we are the only receiver)
186 for len(oFsm.omciMIdsResponseReceived) > 0 {
187 <-oFsm.omciMIdsResponseReceived
188 }
189 }
190 // start go routine for processing of LockState messages
191 go oFsm.ProcessOmciAniMessages()
192
193 //let the state machine run forward from here directly
194 pConfigAniStateAFsm := oFsm.pAdaptFsm
195 if pConfigAniStateAFsm != nil {
196 // obviously calling some FSM event here directly does not work - so trying to decouple it ...
197 go func(a_pAFsm *AdapterFsm) {
198 if a_pAFsm != nil && a_pAFsm.pFsm != nil {
199 //stick to pythonAdapter numbering scheme
200 //index 0 in naming refers to possible usage of multiple instances (later)
201 oFsm.mapperSP0ID = ieeeMapperServiceProfileEID + uint16(oFsm.pOnuUniPort.macBpNo) + oFsm.techProfileID
202 oFsm.macBPCD0ID = macBridgePortAniEID + uint16(oFsm.pOnuUniPort.entityId) + oFsm.techProfileID
203 oFsm.tcont0ID = 0x8001 //TODO!: for now fixed, but target is to use value from MibUpload (mibDB)
204 oFsm.alloc0ID = (*(oFsm.pUniTechProf.mapPonAniConfig[uint32(oFsm.pOnuUniPort.uniId)]))[0].tcontParams.allocID
205 //TODO!! this is just for the first GemPort right now - needs update
206 oFsm.gemPortXID = append(oFsm.gemPortXID,
207 (*(oFsm.pUniTechProf.mapPonAniConfig[uint32(oFsm.pOnuUniPort.uniId)]))[0].mapGemPortParams[0].gemPortID)
208 oFsm.upQueueXID = append(oFsm.upQueueXID, 0x8001) //TODO!: for now fixed, but target is to use value from MibUpload (mibDB)
209 //TODO!: for now fixed, but target is to use value from MibUpload (mibDB), also TechProf setting dependency may exist!
210 oFsm.downQueueXID = append(oFsm.downQueueXID, 1)
211
mpagenko1cc3cb42020-07-27 15:24:38 +0000212 a_pAFsm.pFsm.Event(aniEvStartConfig)
mpagenko3dbcdd22020-07-22 07:38:45 +0000213 }
214 }(pConfigAniStateAFsm)
215 }
216}
217
218func (oFsm *UniPonAniConfigFsm) enterCreatingDot1PMapper(e *fsm.Event) {
219 logger.Debugw("UniPonAniConfigFsm Tx Create::Dot1PMapper", log.Fields{
220 "EntitytId": strconv.FormatInt(int64(oFsm.mapperSP0ID), 16),
221 "in state": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
222 meInstance := oFsm.pOmciCC.sendCreateDot1PMapper(context.TODO(), ConstDefaultOmciTimeout, true,
223 oFsm.mapperSP0ID, oFsm.pAdaptFsm.commChan)
224 //accept also nil as (error) return value for writing to LastTx
225 // - this avoids misinterpretation of new received OMCI messages
226 oFsm.pOmciCC.pLastTxMeInstance = meInstance
227}
228
229func (oFsm *UniPonAniConfigFsm) enterCreatingMBPCD(e *fsm.Event) {
230 logger.Debugw("UniPonAniConfigFsm Tx Create::MBPCD", log.Fields{
231 "EntitytId": strconv.FormatInt(int64(oFsm.macBPCD0ID), 16),
232 "TPPtr": strconv.FormatInt(int64(oFsm.mapperSP0ID), 16),
233 "in state": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
234 bridgePtr := macBridgeServiceProfileEID + uint16(oFsm.pOnuUniPort.macBpNo) //cmp also omci_cc.go::sendCreateMBServiceProfile
235 meParams := me.ParamData{
236 EntityID: oFsm.macBPCD0ID,
237 Attributes: me.AttributeValueMap{
238 "BridgeIdPointer": bridgePtr,
239 "PortNum": 0xFF, //fixed unique ANI side indication
240 "TpType": 3, //for .1PMapper
241 "TpPointer": oFsm.mapperSP0ID,
242 },
243 }
244 meInstance := oFsm.pOmciCC.sendCreateMBPConfigDataVar(context.TODO(), ConstDefaultOmciTimeout, true,
245 oFsm.pAdaptFsm.commChan, meParams)
246 //accept also nil as (error) return value for writing to LastTx
247 // - this avoids misinterpretation of new received OMCI messages
248 oFsm.pOmciCC.pLastTxMeInstance = meInstance
249
250}
251
252func (oFsm *UniPonAniConfigFsm) enterSettingTconts(e *fsm.Event) {
253 logger.Debugw("UniPonAniConfigFsm Tx Set::Tcont", log.Fields{
254 "EntitytId": strconv.FormatInt(int64(oFsm.tcont0ID), 16),
255 "AllocId": strconv.FormatInt(int64(oFsm.alloc0ID), 16),
256 "in state": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
257 meParams := me.ParamData{
258 EntityID: oFsm.tcont0ID,
259 Attributes: me.AttributeValueMap{
260 "AllocId": oFsm.alloc0ID,
261 },
262 }
263 meInstance := oFsm.pOmciCC.sendSetTcontVar(context.TODO(), ConstDefaultOmciTimeout, true,
264 oFsm.pAdaptFsm.commChan, meParams)
265 //accept also nil as (error) return value for writing to LastTx
266 // - this avoids misinterpretation of new received OMCI messages
267 oFsm.pOmciCC.pLastTxMeInstance = meInstance
268}
269
270func (oFsm *UniPonAniConfigFsm) enterCreatingGemNCTPs(e *fsm.Event) {
271 //TODO!! this is just for the first GemPort right now - needs update
272 logger.Debugw("UniPonAniConfigFsm - start creating GemNWCtp loop", log.Fields{
273 "in state": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
274 go oFsm.performCreatingGemNCTPs()
275}
276
277func (oFsm *UniPonAniConfigFsm) enterCreatingGemIWs(e *fsm.Event) {
278 logger.Debugw("UniPonAniConfigFsm - start creating GemIwTP loop", log.Fields{
279 "in state": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
280 go oFsm.performCreatingGemIWs()
281}
282
283func (oFsm *UniPonAniConfigFsm) enterSettingPQs(e *fsm.Event) {
284 logger.Debugw("UniPonAniConfigFsm - start setting PrioQueue loop", log.Fields{
285 "in state": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
286 go oFsm.performSettingPQs()
287}
288
289func (oFsm *UniPonAniConfigFsm) enterSettingDot1PMapper(e *fsm.Event) {
290 logger.Debugw("UniPonAniConfigFsm Tx Set::.1pMapper with all PBits set", log.Fields{"EntitytId": 0x8042, /*cmp above*/
291 "toGemIw": 1024 /* cmp above */, "in state": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
292
293 //TODO!! in MultiGemPort constellation the IwTpPtr setting will get variable -f(Prio) based on pUniTechProf
294 logger.Debugw("UniPonAniConfigFsm Tx Set::1pMapper SingleGem", log.Fields{
295 "EntitytId": strconv.FormatInt(int64(oFsm.mapperSP0ID), 16),
296 "GemIwTpPtr": strconv.FormatInt(int64(oFsm.gemPortXID[0]), 16),
297 "in state": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
298 meParams := me.ParamData{
299 EntityID: oFsm.mapperSP0ID,
300 Attributes: me.AttributeValueMap{
301 "InterworkTpPointerForPBitPriority0": oFsm.gemPortXID[0],
302 "InterworkTpPointerForPBitPriority1": oFsm.gemPortXID[0],
303 "InterworkTpPointerForPBitPriority2": oFsm.gemPortXID[0],
304 "InterworkTpPointerForPBitPriority3": oFsm.gemPortXID[0],
305 "InterworkTpPointerForPBitPriority4": oFsm.gemPortXID[0],
306 "InterworkTpPointerForPBitPriority5": oFsm.gemPortXID[0],
307 "InterworkTpPointerForPBitPriority6": oFsm.gemPortXID[0],
308 "InterworkTpPointerForPBitPriority7": oFsm.gemPortXID[0],
309 },
310 }
311 meInstance := oFsm.pOmciCC.sendSetDot1PMapperVar(context.TODO(), ConstDefaultOmciTimeout, true,
312 oFsm.pAdaptFsm.commChan, meParams)
313 //accept also nil as (error) return value for writing to LastTx
314 // - this avoids misinterpretation of new received OMCI messages
315 oFsm.pOmciCC.pLastTxMeInstance = meInstance
316}
317
318func (oFsm *UniPonAniConfigFsm) enterAniConfigDone(e *fsm.Event) {
319
mpagenko1cc3cb42020-07-27 15:24:38 +0000320 oFsm.aniConfigCompleted = true
mpagenko3dbcdd22020-07-22 07:38:45 +0000321
322 //let's reset the state machine in order to release all resources now
323 pConfigAniStateAFsm := oFsm.pAdaptFsm
324 if pConfigAniStateAFsm != nil {
325 // obviously calling some FSM event here directly does not work - so trying to decouple it ...
326 go func(a_pAFsm *AdapterFsm) {
327 if a_pAFsm != nil && a_pAFsm.pFsm != nil {
mpagenko1cc3cb42020-07-27 15:24:38 +0000328 a_pAFsm.pFsm.Event(aniEvReset)
mpagenko3dbcdd22020-07-22 07:38:45 +0000329 }
330 }(pConfigAniStateAFsm)
331 }
mpagenko3dbcdd22020-07-22 07:38:45 +0000332}
333
334func (oFsm *UniPonAniConfigFsm) enterResettingState(e *fsm.Event) {
335 logger.Debugw("UniPonAniConfigFsm resetting", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
mpagenko3dbcdd22020-07-22 07:38:45 +0000336 pConfigAniStateAFsm := oFsm.pAdaptFsm
337 if pConfigAniStateAFsm != nil {
338 // abort running message processing
339 fsmAbortMsg := Message{
340 Type: TestMsg,
341 Data: TestMessage{
342 TestMessageVal: AbortMessageProcessing,
343 },
344 }
345 pConfigAniStateAFsm.commChan <- fsmAbortMsg
346
347 //try to restart the FSM to 'disabled', decouple event transfer
348 go func(a_pAFsm *AdapterFsm) {
349 if a_pAFsm != nil && a_pAFsm.pFsm != nil {
mpagenko1cc3cb42020-07-27 15:24:38 +0000350 a_pAFsm.pFsm.Event(aniEvRestart)
mpagenko3dbcdd22020-07-22 07:38:45 +0000351 }
352 }(pConfigAniStateAFsm)
353 }
354}
355
mpagenko1cc3cb42020-07-27 15:24:38 +0000356func (oFsm *UniPonAniConfigFsm) enterDisabledState(e *fsm.Event) {
357 logger.Debugw("UniPonAniConfigFsm enters disabled state", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
358
359 if oFsm.aniConfigCompleted {
360 logger.Debugw("UniPonAniConfigFsm send dh event notification", log.Fields{
361 "from_State": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
362 //use DeviceHandler event notification directly
363 oFsm.pOmciCC.pBaseDeviceHandler.DeviceProcStatusUpdate(oFsm.requestEvent)
364 oFsm.aniConfigCompleted = false
365 }
366
367 if oFsm.chanSet {
368 // indicate processing done to the caller
369 logger.Debugw("UniPonAniConfigFsm processingDone on channel", log.Fields{
370 "ProcessingStep": oFsm.procStep, "from_State": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
371 oFsm.chSuccess <- oFsm.procStep
372 oFsm.chanSet = false //reset the internal channel state
373 }
374
375}
376
mpagenko3dbcdd22020-07-22 07:38:45 +0000377func (oFsm *UniPonAniConfigFsm) ProcessOmciAniMessages( /*ctx context.Context*/ ) {
378 logger.Debugw("Start UniPonAniConfigFsm Msg processing", log.Fields{"for device-id": oFsm.pAdaptFsm.deviceID})
379loop:
380 for {
381 select {
382 // case <-ctx.Done():
383 // logger.Info("MibSync Msg", log.Fields{"Message handling canceled via context for device-id": oFsm.pAdaptFsm.deviceID})
384 // break loop
385 case message, ok := <-oFsm.pAdaptFsm.commChan:
386 if !ok {
387 logger.Info("UniPonAniConfigFsm Rx Msg - could not read from channel", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
388 // but then we have to ensure a restart of the FSM as well - as exceptional procedure
mpagenko1cc3cb42020-07-27 15:24:38 +0000389 oFsm.pAdaptFsm.pFsm.Event(aniEvReset)
mpagenko3dbcdd22020-07-22 07:38:45 +0000390 break loop
391 }
392 logger.Debugw("UniPonAniConfigFsm Rx Msg", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
393
394 switch message.Type {
395 case TestMsg:
396 msg, _ := message.Data.(TestMessage)
397 if msg.TestMessageVal == AbortMessageProcessing {
398 logger.Infow("UniPonAniConfigFsm abort ProcessMsg", log.Fields{"for device-id": oFsm.pAdaptFsm.deviceID})
399 break loop
400 }
401 logger.Warnw("UniPonAniConfigFsm unknown TestMessage", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID, "MessageVal": msg.TestMessageVal})
402 case OMCI:
403 msg, _ := message.Data.(OmciMessage)
404 oFsm.handleOmciAniConfigMessage(msg)
405 default:
406 logger.Warn("UniPonAniConfigFsm Rx unknown message", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID,
407 "message.Type": message.Type})
408 }
409 }
410 }
411 logger.Infow("End UniPonAniConfigFsm Msg processing", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
412}
413
414func (oFsm *UniPonAniConfigFsm) handleOmciAniConfigMessage(msg OmciMessage) {
415 logger.Debugw("Rx OMCI UniPonAniConfigFsm Msg", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID,
416 "msgType": msg.OmciMsg.MessageType})
417
418 switch msg.OmciMsg.MessageType {
419 case omci.CreateResponseType:
420 {
421 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeCreateResponse)
422 if msgLayer == nil {
423 logger.Error("Omci Msg layer could not be detected for CreateResponse")
424 return
425 }
426 msgObj, msgOk := msgLayer.(*omci.CreateResponse)
427 if !msgOk {
428 logger.Error("Omci Msg layer could not be assigned for CreateResponse")
429 return
430 }
431 logger.Debugw("CreateResponse Data", log.Fields{"deviceId": oFsm.pAdaptFsm.deviceID, "data-fields": msgObj})
432 if msgObj.Result != me.Success {
433 logger.Errorw("Omci CreateResponse Error - later: drive FSM to abort state ?", log.Fields{"Error": msgObj.Result})
434 // possibly force FSM into abort or ignore some errors for some messages? store error for mgmt display?
435 return
436 }
437 if msgObj.EntityClass == oFsm.pOmciCC.pLastTxMeInstance.GetClassID() &&
438 msgObj.EntityInstance == oFsm.pOmciCC.pLastTxMeInstance.GetEntityID() {
439 //store the created ME into DB //TODO??? obviously the Python code does not store the config ...
440 // if, then something like:
441 //oFsm.pOnuDB.StoreMe(msgObj)
442
443 // maybe we can use just the same eventName for different state transitions like "forward"
444 // - might be checked, but so far I go for sure and have to inspect the concrete state events ...
445 switch oFsm.pOmciCC.pLastTxMeInstance.GetName() {
446 case "Ieee8021PMapperServiceProfile":
447 { // let the FSM proceed ...
mpagenko1cc3cb42020-07-27 15:24:38 +0000448 oFsm.pAdaptFsm.pFsm.Event(aniEvRxDot1pmapCresp)
mpagenko3dbcdd22020-07-22 07:38:45 +0000449 }
450 case "MacBridgePortConfigurationData":
451 { // let the FSM proceed ...
mpagenko1cc3cb42020-07-27 15:24:38 +0000452 oFsm.pAdaptFsm.pFsm.Event(aniEvRxMbpcdResp)
mpagenko3dbcdd22020-07-22 07:38:45 +0000453 }
454 case "GemPortNetworkCtp", "GemInterworkingTerminationPoint":
455 { // let aniConfig Multi-Id processing proceed by stopping the wait function
456 oFsm.omciMIdsResponseReceived <- true
457 }
458 }
459 }
460 } //CreateResponseType
461 case omci.SetResponseType:
462 {
463 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeSetResponse)
464 if msgLayer == nil {
465 logger.Error("UniPonAniConfigFsm - Omci Msg layer could not be detected for SetResponse")
466 return
467 }
468 msgObj, msgOk := msgLayer.(*omci.SetResponse)
469 if !msgOk {
470 logger.Error("UniPonAniConfigFsm - Omci Msg layer could not be assigned for SetResponse")
471 return
472 }
473 logger.Debugw("UniPonAniConfigFsm SetResponse Data", log.Fields{"deviceId": oFsm.pAdaptFsm.deviceID, "data-fields": msgObj})
474 if msgObj.Result != me.Success {
475 logger.Errorw("UniPonAniConfigFsm - Omci SetResponse Error - later: drive FSM to abort state ?", log.Fields{"Error": msgObj.Result})
476 // possibly force FSM into abort or ignore some errors for some messages? store error for mgmt display?
477 return
478 }
479 if msgObj.EntityClass == oFsm.pOmciCC.pLastTxMeInstance.GetClassID() &&
480 msgObj.EntityInstance == oFsm.pOmciCC.pLastTxMeInstance.GetEntityID() {
481 //store the created ME into DB //TODO??? obviously the Python code does not store the config ...
482 // if, then something like:
483 //oFsm.pOnuDB.StoreMe(msgObj)
484
485 switch oFsm.pOmciCC.pLastTxMeInstance.GetName() {
486 case "TCont":
487 { // let the FSM proceed ...
mpagenko1cc3cb42020-07-27 15:24:38 +0000488 oFsm.pAdaptFsm.pFsm.Event(aniEvRxTcontsResp)
mpagenko3dbcdd22020-07-22 07:38:45 +0000489 }
490 case "PriorityQueue":
491 { // let the PrioQueue init proceed by stopping the wait function
492 oFsm.omciMIdsResponseReceived <- true
493 }
494 case "Ieee8021PMapperServiceProfile":
495 { // let the FSM proceed ...
mpagenko1cc3cb42020-07-27 15:24:38 +0000496 oFsm.pAdaptFsm.pFsm.Event(aniEvRxDot1pmapSresp)
mpagenko3dbcdd22020-07-22 07:38:45 +0000497 }
498 }
499 }
500 } //SetResponseType
501 default:
502 {
503 logger.Errorw("UniPonAniConfigFsm - Rx OMCI unhandled MsgType", log.Fields{"omciMsgType": msg.OmciMsg.MessageType})
504 return
505 }
506 }
507}
508
509func (oFsm *UniPonAniConfigFsm) performCreatingGemNCTPs() {
510 //TODO!! this is just for the first GemPort right now - needs update
511 // .. for gemPort in range gemPortXID
512 logger.Infow("UniPonAniConfigFsm Tx Create::GemNWCtp", log.Fields{
513 "EntitytId": strconv.FormatInt(int64(oFsm.gemPortXID[0]), 16),
514 "TcontId": strconv.FormatInt(int64(oFsm.tcont0ID), 16),
515 "device-id": oFsm.pAdaptFsm.deviceID})
516 meParams := me.ParamData{
517 EntityID: oFsm.gemPortXID[0],
518 Attributes: me.AttributeValueMap{
519 "PortId": oFsm.gemPortXID[0], //same as EntityID
520 "TContPointer": oFsm.tcont0ID,
521 "Direction": (*(oFsm.pUniTechProf.mapPonAniConfig[uint32(oFsm.pOnuUniPort.uniId)]))[0].mapGemPortParams[0].direction,
522 //ONU-G.TrafficManagementOption dependency ->PrioQueue or TCont
523 // TODO!! verify dependency and QueueId in case of Multi-GemPort setup!
524 "TrafficManagementPointerForUpstream": oFsm.upQueueXID[0], //might be different in wrr-only Setup - tcont0ID
525 "PriorityQueuePointerForDownStream": oFsm.downQueueXID[0],
526 },
527 }
528 meInstance := oFsm.pOmciCC.sendCreateGemNCTPVar(context.TODO(), ConstDefaultOmciTimeout, true,
529 oFsm.pAdaptFsm.commChan, meParams)
530 //accept also nil as (error) return value for writing to LastTx
531 // - this avoids misinterpretation of new received OMCI messages
532 oFsm.pOmciCC.pLastTxMeInstance = meInstance
533
534 //verify response
535 err := oFsm.waitforOmciResponse()
536 if err != nil {
537 logger.Errorw("GemNWCtp create failed, aborting AniConfig FSM!",
538 log.Fields{"deviceId": oFsm.pAdaptFsm.deviceID, "GemIndex": 0}) //running index in loop later!
mpagenko1cc3cb42020-07-27 15:24:38 +0000539 oFsm.pAdaptFsm.pFsm.Event(aniEvReset)
mpagenko3dbcdd22020-07-22 07:38:45 +0000540 return
541 }
542 //for all GemPortID's ports - later
543
544 // if Config has been done for all GemPort instances let the FSM proceed
545 logger.Debugw("GemNWCtp create loop finished", log.Fields{"deviceId": oFsm.pAdaptFsm.deviceID})
mpagenko1cc3cb42020-07-27 15:24:38 +0000546 oFsm.pAdaptFsm.pFsm.Event(aniEvRxGemntcpsResp)
mpagenko3dbcdd22020-07-22 07:38:45 +0000547 return
548}
549
550func (oFsm *UniPonAniConfigFsm) performCreatingGemIWs() {
551 //TODO!! this is just for the first GemPort right now - needs update
552 // .. for gemPort in range gemPortXID
553 logger.Infow("UniPonAniConfigFsm Tx Create::GemIwTp", log.Fields{
554 "EntitytId": strconv.FormatInt(int64(oFsm.gemPortXID[0]), 16),
555 "SPPtr": strconv.FormatInt(int64(oFsm.mapperSP0ID), 16),
556 "device-id": oFsm.pAdaptFsm.deviceID})
557 meParams := me.ParamData{
558 EntityID: oFsm.gemPortXID[0],
559 Attributes: me.AttributeValueMap{
560 "GemPortNetworkCtpConnectivityPointer": oFsm.gemPortXID[0], //same as EntityID, see above
561 "InterworkingOption": 5, //fixed model:: G.998 .1pMapper
562 "ServiceProfilePointer": oFsm.mapperSP0ID,
563 "InterworkingTerminationPointPointer": 0, //not used with .1PMapper Mac bridge
564 "GalProfilePointer": galEthernetEID,
565 },
566 }
567 meInstance := oFsm.pOmciCC.sendCreateGemIWTPVar(context.TODO(), ConstDefaultOmciTimeout, true,
568 oFsm.pAdaptFsm.commChan, meParams)
569 //accept also nil as (error) return value for writing to LastTx
570 // - this avoids misinterpretation of new received OMCI messages
571 oFsm.pOmciCC.pLastTxMeInstance = meInstance
572
573 //verify response
574 err := oFsm.waitforOmciResponse()
575 if err != nil {
576 logger.Errorw("GemIwTp create failed, aborting AniConfig FSM!",
577 log.Fields{"deviceId": oFsm.pAdaptFsm.deviceID, "GemIndex": 0}) //running index in loop later!
mpagenko1cc3cb42020-07-27 15:24:38 +0000578 oFsm.pAdaptFsm.pFsm.Event(aniEvReset)
mpagenko3dbcdd22020-07-22 07:38:45 +0000579 return
580 }
581 //for all GemPortID's ports - later
582
583 // if Config has been done for all GemPort instances let the FSM proceed
584 logger.Debugw("GemIwTp create loop finished", log.Fields{"deviceId": oFsm.pAdaptFsm.deviceID})
mpagenko1cc3cb42020-07-27 15:24:38 +0000585 oFsm.pAdaptFsm.pFsm.Event(aniEvRxGemiwsResp)
mpagenko3dbcdd22020-07-22 07:38:45 +0000586 return
587}
588
589func (oFsm *UniPonAniConfigFsm) performSettingPQs() {
590 //TODO!! this is just for the first upstream PrioQueue right now - needs update
591 //TODO!! implementation is restricted to WRR setting on the TrafficScheduler/Tcont
592 // SP setting would allow relatedPort(Prio) setting in case ONU supports config (ONU-2G QOS)
593
594 // .. for prioQueu in range upQueueXID
595 weight := (*(oFsm.pUniTechProf.mapPonAniConfig[uint32(oFsm.pOnuUniPort.uniId)]))[0].mapGemPortParams[0].queueWeight
596 logger.Infow("UniPonAniConfigFsm Tx Set::PrioQueue", log.Fields{
597 "EntitytId": strconv.FormatInt(int64(oFsm.upQueueXID[0]), 16),
598 "Weight": weight,
599 "device-id": oFsm.pAdaptFsm.deviceID})
600 meParams := me.ParamData{
601 EntityID: oFsm.upQueueXID[0],
602 Attributes: me.AttributeValueMap{
603 "Weight": weight,
604 },
605 }
606 meInstance := oFsm.pOmciCC.sendSetPrioQueueVar(context.TODO(), ConstDefaultOmciTimeout, true,
607 oFsm.pAdaptFsm.commChan, meParams)
608 //accept also nil as (error) return value for writing to LastTx
609 // - this avoids misinterpretation of new received OMCI messages
610 oFsm.pOmciCC.pLastTxMeInstance = meInstance
611
612 //verify response
613 err := oFsm.waitforOmciResponse()
614 if err != nil {
615 logger.Errorw("PrioQueue set failed, aborting AniConfig FSM!",
616 log.Fields{"deviceId": oFsm.pAdaptFsm.deviceID, "QueueIndex": 0}) //running index in loop later!
mpagenko1cc3cb42020-07-27 15:24:38 +0000617 oFsm.pAdaptFsm.pFsm.Event(aniEvReset)
mpagenko3dbcdd22020-07-22 07:38:45 +0000618 return
619 }
620 //for all upstream prioQueus - later
621
622 // if Config has been done for all PrioQueue instances let the FSM proceed
623 logger.Debugw("PrioQueue set loop finished", log.Fields{"deviceId": oFsm.pAdaptFsm.deviceID})
mpagenko1cc3cb42020-07-27 15:24:38 +0000624 oFsm.pAdaptFsm.pFsm.Event(aniEvRxPrioqsResp)
mpagenko3dbcdd22020-07-22 07:38:45 +0000625 return
626}
627
628func (oFsm *UniPonAniConfigFsm) waitforOmciResponse() error {
629 select {
630 // maybe be also some outside cancel (but no context modelled for the moment ...)
631 // case <-ctx.Done():
632 // logger.Infow("LockState-bridge-init message reception canceled", log.Fields{"for device-id": oFsm.pAdaptFsm.deviceID})
633 case <-time.After(30 * time.Second): //3s was detected to be to less in 8*8 bbsim test with debug Info/Debug
634 logger.Warnw("UniPonAniConfigFsm multi entity timeout", log.Fields{"for device-id": oFsm.pAdaptFsm.deviceID})
635 return errors.New("UniPonAniConfigFsm multi entity timeout")
636 case success := <-oFsm.omciMIdsResponseReceived:
637 if success == true {
638 logger.Debug("UniPonAniConfigFsm multi entity response received")
639 return nil
640 }
641 // should not happen so far
642 logger.Warnw("UniPonAniConfigFsm multi entity response error", log.Fields{"for device-id": oFsm.pAdaptFsm.deviceID})
643 return errors.New("UniPonAniConfigFsm multi entity responseError")
644 }
645}