[VOL-3038] Configuration of tech profiles 1t1gem
version: 0.1.11-dev124
Signed-off-by: mpagenko <michael.pagenkopf@adtran.com>
Change-Id: Iae456e0eb057c885e5d094a3dbb13c8ab7284537
diff --git a/VERSION b/VERSION
index 4948bd9..0ddab70 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.1.11-dev123
+0.1.11-dev124
diff --git a/internal/pkg/onuadaptercore/device_handler.go b/internal/pkg/onuadaptercore/device_handler.go
index bbd7660..f27e3da 100644
--- a/internal/pkg/onuadaptercore/device_handler.go
+++ b/internal/pkg/onuadaptercore/device_handler.go
@@ -291,15 +291,18 @@
//TODO!!! Generally: In this scheme it would be good to have some means to indicate
// possible problems to the caller later autonomously
- // some code to coordinate TP 'run to completion'
- // attention: completion and wg.Add is assumed to be done in both routines,
- // no timeout control so far (needed)
+ // deadline context to ensure completion of background routines waited for
+ //20200721: 10s proved to be less in 8*8 ONU test on local vbox machine with debug, might be further adapted
+ deadline := time.Now().Add(30 * time.Second) //allowed run time to finish before execution
+ dctx, cancel := context.WithDeadline(context.Background(), deadline)
+
var wg sync.WaitGroup
wg.Add(2) // for the 2 go routines to finish
- go dh.pOnuTP.configureUniTp(techProfMsg.UniId, techProfMsg.Path, &wg)
- go dh.pOnuTP.updateOnuTpPathKvStore(&wg)
+ // attention: deadline completion check and wg.Done is to be done in both routines
+ go dh.pOnuTP.configureUniTp(dctx, techProfMsg.UniId, techProfMsg.Path, &wg)
+ go dh.pOnuTP.updateOnuTpPathKvStore(dctx, &wg)
//the wait.. function is responsible for tpProcMutex.Unlock()
- go dh.pOnuTP.waitForTpCompletion(&wg) //let that also run off-line to let the IA messaging return!
+ go dh.pOnuTP.waitForTpCompletion(cancel, &wg) //let that also run off-line to let the IA messaging return!
} else {
dh.pOnuTP.unlockTpProcMutex()
}
@@ -323,12 +326,17 @@
//compare TECH_PROFILE_DOWNLOAD_REQUEST
dh.pOnuTP.lockTpProcMutex()
+
+ // deadline context to ensure completion of background routines waited for
+ deadline := time.Now().Add(10 * time.Second) //allowed run time to finish before execution
+ dctx, cancel := context.WithDeadline(context.Background(), deadline)
+
var wg sync.WaitGroup
wg.Add(1) // for the 1 go routine to finish
- go dh.pOnuTP.deleteTpRessource(delGemPortMsg.UniId, delGemPortMsg.TpPath,
+ go dh.pOnuTP.deleteTpResource(dctx, delGemPortMsg.UniId, delGemPortMsg.TpPath,
cResourceGemPort, delGemPortMsg.GemPortId, &wg)
//the wait.. function is responsible for tpProcMutex.Unlock()
- go dh.pOnuTP.waitForTpCompletion(&wg) //let that also run off-line to let the IA messaging return!
+ go dh.pOnuTP.waitForTpCompletion(cancel, &wg) //let that also run off-line to let the IA messaging return!
}
case ic.InterAdapterMessageType_DELETE_TCONT_REQUEST:
{
@@ -350,14 +358,18 @@
//compare TECH_PROFILE_DOWNLOAD_REQUEST
dh.pOnuTP.lockTpProcMutex()
if bTpModify := dh.pOnuTP.updateOnuUniTpPath(delTcontMsg.UniId, ""); bTpModify == true {
+ // deadline context to ensure completion of background routines waited for
+ deadline := time.Now().Add(10 * time.Second) //allowed run time to finish before execution
+ dctx, cancel := context.WithDeadline(context.Background(), deadline)
+
var wg sync.WaitGroup
- wg.Add(2) // for the 1 go routine to finish
- go dh.pOnuTP.deleteTpRessource(delTcontMsg.UniId, delTcontMsg.TpPath,
+ wg.Add(2) // for the 2 go routines to finish
+ go dh.pOnuTP.deleteTpResource(dctx, delTcontMsg.UniId, delTcontMsg.TpPath,
cResourceTcont, delTcontMsg.AllocId, &wg)
// Removal of the tcont/alloc id mapping represents the removal of the tech profile
- go dh.pOnuTP.updateOnuTpPathKvStore(&wg)
+ go dh.pOnuTP.updateOnuTpPathKvStore(dctx, &wg)
//the wait.. function is responsible for tpProcMutex.Unlock()
- go dh.pOnuTP.waitForTpCompletion(&wg) //let that also run off-line to let the IA messaging return!
+ go dh.pOnuTP.waitForTpCompletion(cancel, &wg) //let that also run off-line to let the IA messaging return!
} else {
dh.pOnuTP.unlockTpProcMutex()
}
@@ -918,13 +930,19 @@
}
}
default:
- { //port lock/unlock FSM's may be active
+ {
+ //port lock/unlock FSM's may be active
if dh.pUnlockStateFsm != nil {
dh.pUnlockStateFsm.pAdaptFsm.pFsm.Event("reset")
}
if dh.pLockStateFsm != nil {
dh.pLockStateFsm.pAdaptFsm.pFsm.Event("reset")
}
+ //techProfile related PonAniConfigFsm FSM may be active
+ // maybe encapsulated as OnuTP method - perhaps later in context of module splitting
+ if dh.pOnuTP.pAniConfigFsm != nil {
+ dh.pOnuTP.pAniConfigFsm.pAdaptFsm.pFsm.Event("reset")
+ }
}
//TODO!!! care about PM/Alarm processing once started
}
@@ -974,12 +992,15 @@
switch dev_Event {
case MibDatabaseSync:
{
- logger.Infow("MibInSync event: update dev state to 'MibSync complete'", log.Fields{"deviceID": dh.deviceID})
+ logger.Debugw("MibInSync event received", log.Fields{"deviceID": dh.deviceID})
//initiate DevStateUpdate
if err := dh.coreProxy.DeviceReasonUpdate(context.TODO(), dh.deviceID, "discovery-mibsync-complete"); err != nil {
logger.Errorw("error-DeviceReasonUpdate to 'mibsync-complete'", log.Fields{
"deviceID": dh.deviceID, "error": err})
+ } else {
+ logger.Infow("dev reason updated to 'MibSync complete'", log.Fields{"deviceID": dh.deviceID})
}
+ //set internal state anyway - as it was done
dh.deviceReason = "discovery-mibsync-complete"
pDevEntry := dh.GetOnuDeviceEntry(false)
@@ -1059,20 +1080,23 @@
}
case MibDownloadDone:
{
- logger.Infow("MibDownloadDone event: update dev state to 'Oper.Active'", log.Fields{"deviceID": dh.deviceID})
+ logger.Debugw("MibDownloadDone event received", log.Fields{"deviceID": dh.deviceID})
//initiate DevStateUpdate
if err := dh.coreProxy.DeviceStateUpdate(context.TODO(), dh.deviceID,
voltha.ConnectStatus_REACHABLE, voltha.OperStatus_ACTIVE); err != nil {
logger.Errorw("error-updating-device-state", log.Fields{"deviceID": dh.deviceID, "error": err})
+ } else {
+ logger.Debugw("dev state updated to 'Oper.Active'", log.Fields{"deviceID": dh.deviceID})
}
- logger.Debug("MibDownloadDone Event: update dev reason to 'initial-mib-downloaded'")
if err := dh.coreProxy.DeviceReasonUpdate(context.TODO(), dh.deviceID, "initial-mib-downloaded"); err != nil {
logger.Errorw("error-DeviceReasonUpdate to 'initial-mib-downloaded'",
log.Fields{"deviceID": dh.deviceID, "error": err})
+ } else {
+ logger.Infow("dev reason updated to 'initial-mib-downloaded'", log.Fields{"deviceID": dh.deviceID})
}
+ //set internal state anyway - as it was done
dh.deviceReason = "initial-mib-downloaded"
-
// *** should generate UniUnlockStateDone event *****
if dh.pUnlockStateFsm == nil {
dh.createUniLockFsm(false, UniUnlockStateDone)
@@ -1089,6 +1113,26 @@
raisedTs := time.Now().UnixNano()
go dh.sendOnuOperStateEvent(voltha.OperStatus_ACTIVE, dh.deviceID, raisedTs) //cmp python onu_active_event
}
+ case OmciAniConfigDone:
+ {
+ logger.Debugw("OmciAniConfigDone event received", log.Fields{"deviceID": dh.deviceID})
+ //TODO!: it might be needed to check some 'cached' pending flow configuration (vlan setting)
+ // - to consider with outstanding flow implementation
+ // attention: the device reason update is done based on ONU-UNI-Port related activity
+ // - which may cause some inconsistency
+ if dh.deviceReason != "tech-profile-config-download-success" {
+ // which may be the case from some previous actvity on another UNI Port of the ONU
+ if err := dh.coreProxy.DeviceReasonUpdate(context.TODO(), dh.deviceID, "tech-profile-config-download-success"); err != nil {
+ logger.Errorw("error-DeviceReasonUpdate to 'tech-profile-config-download-success'",
+ log.Fields{"deviceID": dh.deviceID, "error": err})
+ } else {
+ logger.Infow("update dev reason to 'tech-profile-config-download-success'",
+ log.Fields{"deviceID": dh.deviceID})
+ }
+ //set internal state anyway - as it was done
+ dh.deviceReason = "tech-profile-config-download-success"
+ }
+ }
default:
{
logger.Warnw("unhandled-device-event", log.Fields{"deviceID": dh.deviceID, "event": dev_Event})
diff --git a/internal/pkg/onuadaptercore/omci_ani_config.go b/internal/pkg/onuadaptercore/omci_ani_config.go
new file mode 100644
index 0000000..d968edb
--- /dev/null
+++ b/internal/pkg/onuadaptercore/omci_ani_config.go
@@ -0,0 +1,604 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//Package adaptercoreonu provides the utility for onu devices, flows and statistics
+package adaptercoreonu
+
+import (
+ "context"
+ "errors"
+ "strconv"
+ "time"
+
+ "github.com/looplab/fsm"
+
+ "github.com/opencord/omci-lib-go"
+ me "github.com/opencord/omci-lib-go/generated"
+ "github.com/opencord/voltha-lib-go/v3/pkg/log"
+ //ic "github.com/opencord/voltha-protos/v3/go/inter_container"
+ //"github.com/opencord/voltha-protos/v3/go/openflow_13"
+ //"github.com/opencord/voltha-protos/v3/go/voltha"
+)
+
+//UniPonAniConfigFsm defines the structure for the state machine to lock/unlock the ONU UNI ports via OMCI
+type UniPonAniConfigFsm struct {
+ pOmciCC *OmciCC
+ pOnuUniPort *OnuUniPort
+ pUniTechProf *OnuUniTechProf
+ pOnuDB *OnuDeviceDB
+ techProfileID uint16
+ requestEvent OnuDeviceEvent
+ omciMIdsResponseReceived chan bool //seperate channel needed for checking multiInstance OMCI message responses
+ pAdaptFsm *AdapterFsm
+ chSuccess chan<- uint8
+ procStep uint8
+ chanSet bool
+ mapperSP0ID uint16
+ macBPCD0ID uint16
+ tcont0ID uint16
+ alloc0ID uint16
+ gemPortXID []uint16
+ upQueueXID []uint16
+ downQueueXID []uint16
+}
+
+//NewUniPonAniConfigFsm is the 'constructor' for the state machine to lock/unlock the ONU UNI ports via OMCI
+func NewUniPonAniConfigFsm(apDevOmciCC *OmciCC, apUniPort *OnuUniPort, apUniTechProf *OnuUniTechProf,
+ apOnuDB *OnuDeviceDB, aTechProfileID uint16, aRequestEvent OnuDeviceEvent, aName string,
+ aDeviceID string, aCommChannel chan Message) *UniPonAniConfigFsm {
+ instFsm := &UniPonAniConfigFsm{
+ pOmciCC: apDevOmciCC,
+ pOnuUniPort: apUniPort,
+ pUniTechProf: apUniTechProf,
+ pOnuDB: apOnuDB,
+ techProfileID: aTechProfileID,
+ requestEvent: aRequestEvent,
+ chanSet: false,
+ }
+ instFsm.pAdaptFsm = NewAdapterFsm(aName, aDeviceID, aCommChannel)
+ if instFsm.pAdaptFsm == nil {
+ logger.Errorw("UniPonAniConfigFsm's AdapterFsm could not be instantiated!!", log.Fields{
+ "device-id": aDeviceID})
+ return nil
+ }
+
+ instFsm.pAdaptFsm.pFsm = fsm.NewFSM(
+ "disabled",
+ fsm.Events{
+
+ {Name: "start", Src: []string{"disabled"}, Dst: "starting"},
+
+ //Note: .1p-Mapper and MBPCD might also have multi instances (per T-Cont) - by now only one 1 T-Cont considered!
+ {Name: "start_config", Src: []string{"starting"}, Dst: "creatingDot1PMapper"},
+ {Name: "rx_dot1pmap_cresp", Src: []string{"creatingDot1PMapper"}, Dst: "creatingMBPCD"},
+ {Name: "rx_mbpcd_resp", Src: []string{"creatingMBPCD"}, Dst: "settingTconts"},
+ {Name: "rx_tconts_resp", Src: []string{"settingTconts"}, Dst: "creatingGemNCTPs"},
+ // the creatingGemNCTPs state is used for multi ME config if required for all configured/available GemPorts
+ {Name: "rx_gemntcps_resp", Src: []string{"creatingGemNCTPs"}, Dst: "creatingGemIWs"},
+ // the creatingGemIWs state is used for multi ME config if required for all configured/available GemPorts
+ {Name: "rx_gemiws_resp", Src: []string{"creatingGemIWs"}, Dst: "settingPQs"},
+ // the settingPQs state is used for multi ME config if required for all configured/available upstream PriorityQueues
+ {Name: "rx_prioqs_resp", Src: []string{"settingPQs"}, Dst: "settingDot1PMapper"},
+ {Name: "rx_dot1pmap_sresp", Src: []string{"settingDot1PMapper"}, Dst: "aniConfigDone"},
+
+ {Name: "timeout_simple", Src: []string{
+ "creatingDot1PMapper", "creatingMBPCD", "settingTconts", "settingDot1PMapper"}, Dst: "starting"},
+ {Name: "timeout_mids", Src: []string{
+ "creatingGemNCTPs", "creatingGemIWs", "settingPQs"}, Dst: "starting"},
+
+ // exceptional treatment for all states except "resetting"
+ {Name: "reset", Src: []string{"starting", "creatingDot1PMapper", "creatingMBPCD",
+ "settingTconts", "creatingGemNCTPs", "creatingGemIWs", "settingPQs", "settingDot1PMapper",
+ "aniConfigDone"}, Dst: "resetting"},
+ // the only way to get to resource-cleared disabled state again is via "resseting"
+ {Name: "restart", Src: []string{"resetting"}, Dst: "disabled"},
+ },
+
+ fsm.Callbacks{
+ "enter_state": func(e *fsm.Event) { instFsm.pAdaptFsm.logFsmStateChange(e) },
+ "enter_starting": func(e *fsm.Event) { instFsm.enterConfigStartingState(e) },
+ "enter_creatingDot1PMapper": func(e *fsm.Event) { instFsm.enterCreatingDot1PMapper(e) },
+ "enter_creatingMBPCD": func(e *fsm.Event) { instFsm.enterCreatingMBPCD(e) },
+ "enter_settingTconts": func(e *fsm.Event) { instFsm.enterSettingTconts(e) },
+ "enter_creatingGemNCTPs": func(e *fsm.Event) { instFsm.enterCreatingGemNCTPs(e) },
+ "enter_creatingGemIWs": func(e *fsm.Event) { instFsm.enterCreatingGemIWs(e) },
+ "enter_settingPQs": func(e *fsm.Event) { instFsm.enterSettingPQs(e) },
+ "enter_settingDot1PMapper": func(e *fsm.Event) { instFsm.enterSettingDot1PMapper(e) },
+ "enter_aniConfigDone": func(e *fsm.Event) { instFsm.enterAniConfigDone(e) },
+ "enter_resetting": func(e *fsm.Event) { instFsm.enterResettingState(e) },
+ },
+ )
+ if instFsm.pAdaptFsm.pFsm == nil {
+ logger.Errorw("UniPonAniConfigFsm's Base FSM could not be instantiated!!", log.Fields{
+ "device-id": aDeviceID})
+ return nil
+ }
+
+ logger.Infow("UniPonAniConfigFsm created", log.Fields{"device-id": aDeviceID})
+ return instFsm
+}
+
+//SetFsmCompleteChannel sets the requested channel and channel result for transfer on success
+func (oFsm *UniPonAniConfigFsm) SetFsmCompleteChannel(aChSuccess chan<- uint8, aProcStep uint8) {
+ oFsm.chSuccess = aChSuccess
+ oFsm.procStep = aProcStep
+ oFsm.chanSet = true
+}
+
+func (oFsm *UniPonAniConfigFsm) enterConfigStartingState(e *fsm.Event) {
+ logger.Debugw("UniPonAniConfigFsm start", log.Fields{"in state": e.FSM.Current(),
+ "device-id": oFsm.pAdaptFsm.deviceID})
+ // in case the used channel is not yet defined (can be re-used after restarts)
+ if oFsm.omciMIdsResponseReceived == nil {
+ oFsm.omciMIdsResponseReceived = make(chan bool)
+ logger.Debug("UniPonAniConfigFsm - OMCI multiInstance RxChannel defined")
+ } else {
+ // as we may 're-use' this instance of FSM and the connected channel
+ // make sure there is no 'lingering' request in the already existing channel:
+ // (simple loop sufficient as we are the only receiver)
+ for len(oFsm.omciMIdsResponseReceived) > 0 {
+ <-oFsm.omciMIdsResponseReceived
+ }
+ }
+ // start go routine for processing of LockState messages
+ go oFsm.ProcessOmciAniMessages()
+
+ //let the state machine run forward from here directly
+ pConfigAniStateAFsm := oFsm.pAdaptFsm
+ if pConfigAniStateAFsm != nil {
+ // obviously calling some FSM event here directly does not work - so trying to decouple it ...
+ go func(a_pAFsm *AdapterFsm) {
+ if a_pAFsm != nil && a_pAFsm.pFsm != nil {
+ //stick to pythonAdapter numbering scheme
+ //index 0 in naming refers to possible usage of multiple instances (later)
+ oFsm.mapperSP0ID = ieeeMapperServiceProfileEID + uint16(oFsm.pOnuUniPort.macBpNo) + oFsm.techProfileID
+ oFsm.macBPCD0ID = macBridgePortAniEID + uint16(oFsm.pOnuUniPort.entityId) + oFsm.techProfileID
+ oFsm.tcont0ID = 0x8001 //TODO!: for now fixed, but target is to use value from MibUpload (mibDB)
+ oFsm.alloc0ID = (*(oFsm.pUniTechProf.mapPonAniConfig[uint32(oFsm.pOnuUniPort.uniId)]))[0].tcontParams.allocID
+ //TODO!! this is just for the first GemPort right now - needs update
+ oFsm.gemPortXID = append(oFsm.gemPortXID,
+ (*(oFsm.pUniTechProf.mapPonAniConfig[uint32(oFsm.pOnuUniPort.uniId)]))[0].mapGemPortParams[0].gemPortID)
+ oFsm.upQueueXID = append(oFsm.upQueueXID, 0x8001) //TODO!: for now fixed, but target is to use value from MibUpload (mibDB)
+ //TODO!: for now fixed, but target is to use value from MibUpload (mibDB), also TechProf setting dependency may exist!
+ oFsm.downQueueXID = append(oFsm.downQueueXID, 1)
+
+ a_pAFsm.pFsm.Event("start_config")
+ }
+ }(pConfigAniStateAFsm)
+ }
+}
+
+func (oFsm *UniPonAniConfigFsm) enterCreatingDot1PMapper(e *fsm.Event) {
+ logger.Debugw("UniPonAniConfigFsm Tx Create::Dot1PMapper", log.Fields{
+ "EntitytId": strconv.FormatInt(int64(oFsm.mapperSP0ID), 16),
+ "in state": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
+ meInstance := oFsm.pOmciCC.sendCreateDot1PMapper(context.TODO(), ConstDefaultOmciTimeout, true,
+ oFsm.mapperSP0ID, oFsm.pAdaptFsm.commChan)
+ //accept also nil as (error) return value for writing to LastTx
+ // - this avoids misinterpretation of new received OMCI messages
+ oFsm.pOmciCC.pLastTxMeInstance = meInstance
+}
+
+func (oFsm *UniPonAniConfigFsm) enterCreatingMBPCD(e *fsm.Event) {
+ logger.Debugw("UniPonAniConfigFsm Tx Create::MBPCD", log.Fields{
+ "EntitytId": strconv.FormatInt(int64(oFsm.macBPCD0ID), 16),
+ "TPPtr": strconv.FormatInt(int64(oFsm.mapperSP0ID), 16),
+ "in state": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
+ bridgePtr := macBridgeServiceProfileEID + uint16(oFsm.pOnuUniPort.macBpNo) //cmp also omci_cc.go::sendCreateMBServiceProfile
+ meParams := me.ParamData{
+ EntityID: oFsm.macBPCD0ID,
+ Attributes: me.AttributeValueMap{
+ "BridgeIdPointer": bridgePtr,
+ "PortNum": 0xFF, //fixed unique ANI side indication
+ "TpType": 3, //for .1PMapper
+ "TpPointer": oFsm.mapperSP0ID,
+ },
+ }
+ meInstance := oFsm.pOmciCC.sendCreateMBPConfigDataVar(context.TODO(), ConstDefaultOmciTimeout, true,
+ oFsm.pAdaptFsm.commChan, meParams)
+ //accept also nil as (error) return value for writing to LastTx
+ // - this avoids misinterpretation of new received OMCI messages
+ oFsm.pOmciCC.pLastTxMeInstance = meInstance
+
+}
+
+func (oFsm *UniPonAniConfigFsm) enterSettingTconts(e *fsm.Event) {
+ logger.Debugw("UniPonAniConfigFsm Tx Set::Tcont", log.Fields{
+ "EntitytId": strconv.FormatInt(int64(oFsm.tcont0ID), 16),
+ "AllocId": strconv.FormatInt(int64(oFsm.alloc0ID), 16),
+ "in state": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
+ meParams := me.ParamData{
+ EntityID: oFsm.tcont0ID,
+ Attributes: me.AttributeValueMap{
+ "AllocId": oFsm.alloc0ID,
+ },
+ }
+ meInstance := oFsm.pOmciCC.sendSetTcontVar(context.TODO(), ConstDefaultOmciTimeout, true,
+ oFsm.pAdaptFsm.commChan, meParams)
+ //accept also nil as (error) return value for writing to LastTx
+ // - this avoids misinterpretation of new received OMCI messages
+ oFsm.pOmciCC.pLastTxMeInstance = meInstance
+}
+
+func (oFsm *UniPonAniConfigFsm) enterCreatingGemNCTPs(e *fsm.Event) {
+ //TODO!! this is just for the first GemPort right now - needs update
+ logger.Debugw("UniPonAniConfigFsm - start creating GemNWCtp loop", log.Fields{
+ "in state": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
+ go oFsm.performCreatingGemNCTPs()
+}
+
+func (oFsm *UniPonAniConfigFsm) enterCreatingGemIWs(e *fsm.Event) {
+ logger.Debugw("UniPonAniConfigFsm - start creating GemIwTP loop", log.Fields{
+ "in state": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
+ go oFsm.performCreatingGemIWs()
+}
+
+func (oFsm *UniPonAniConfigFsm) enterSettingPQs(e *fsm.Event) {
+ logger.Debugw("UniPonAniConfigFsm - start setting PrioQueue loop", log.Fields{
+ "in state": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
+ go oFsm.performSettingPQs()
+}
+
+func (oFsm *UniPonAniConfigFsm) enterSettingDot1PMapper(e *fsm.Event) {
+ logger.Debugw("UniPonAniConfigFsm Tx Set::.1pMapper with all PBits set", log.Fields{"EntitytId": 0x8042, /*cmp above*/
+ "toGemIw": 1024 /* cmp above */, "in state": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
+
+ //TODO!! in MultiGemPort constellation the IwTpPtr setting will get variable -f(Prio) based on pUniTechProf
+ logger.Debugw("UniPonAniConfigFsm Tx Set::1pMapper SingleGem", log.Fields{
+ "EntitytId": strconv.FormatInt(int64(oFsm.mapperSP0ID), 16),
+ "GemIwTpPtr": strconv.FormatInt(int64(oFsm.gemPortXID[0]), 16),
+ "in state": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
+ meParams := me.ParamData{
+ EntityID: oFsm.mapperSP0ID,
+ Attributes: me.AttributeValueMap{
+ "InterworkTpPointerForPBitPriority0": oFsm.gemPortXID[0],
+ "InterworkTpPointerForPBitPriority1": oFsm.gemPortXID[0],
+ "InterworkTpPointerForPBitPriority2": oFsm.gemPortXID[0],
+ "InterworkTpPointerForPBitPriority3": oFsm.gemPortXID[0],
+ "InterworkTpPointerForPBitPriority4": oFsm.gemPortXID[0],
+ "InterworkTpPointerForPBitPriority5": oFsm.gemPortXID[0],
+ "InterworkTpPointerForPBitPriority6": oFsm.gemPortXID[0],
+ "InterworkTpPointerForPBitPriority7": oFsm.gemPortXID[0],
+ },
+ }
+ meInstance := oFsm.pOmciCC.sendSetDot1PMapperVar(context.TODO(), ConstDefaultOmciTimeout, true,
+ oFsm.pAdaptFsm.commChan, meParams)
+ //accept also nil as (error) return value for writing to LastTx
+ // - this avoids misinterpretation of new received OMCI messages
+ oFsm.pOmciCC.pLastTxMeInstance = meInstance
+}
+
+func (oFsm *UniPonAniConfigFsm) enterAniConfigDone(e *fsm.Event) {
+
+ //mirror the chanSet state as it will be reset by FSM reset
+ loChanSet := oFsm.chanSet
+
+ //let's reset the state machine in order to release all resources now
+ pConfigAniStateAFsm := oFsm.pAdaptFsm
+ if pConfigAniStateAFsm != nil {
+ // obviously calling some FSM event here directly does not work - so trying to decouple it ...
+ go func(a_pAFsm *AdapterFsm) {
+ if a_pAFsm != nil && a_pAFsm.pFsm != nil {
+ a_pAFsm.pFsm.Event("reset")
+ }
+ }(pConfigAniStateAFsm)
+ }
+
+ logger.Debugw("UniPonAniConfigFsm send dh event notification", log.Fields{
+ "from_State": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
+ //use DeviceHandler event notification directly
+ oFsm.pOmciCC.pBaseDeviceHandler.DeviceProcStatusUpdate(oFsm.requestEvent)
+
+ if loChanSet {
+ // indicate processing done to the caller
+ logger.Debugw("UniPonAniConfigFsm processingDone on channel", log.Fields{
+ "ProcessingStep": oFsm.procStep, "from_State": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
+ oFsm.chSuccess <- oFsm.procStep
+ }
+}
+
+func (oFsm *UniPonAniConfigFsm) enterResettingState(e *fsm.Event) {
+ logger.Debugw("UniPonAniConfigFsm resetting", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+ oFsm.chanSet = false //reset the internal channel state
+ pConfigAniStateAFsm := oFsm.pAdaptFsm
+ if pConfigAniStateAFsm != nil {
+ // abort running message processing
+ fsmAbortMsg := Message{
+ Type: TestMsg,
+ Data: TestMessage{
+ TestMessageVal: AbortMessageProcessing,
+ },
+ }
+ pConfigAniStateAFsm.commChan <- fsmAbortMsg
+
+ //try to restart the FSM to 'disabled', decouple event transfer
+ go func(a_pAFsm *AdapterFsm) {
+ if a_pAFsm != nil && a_pAFsm.pFsm != nil {
+ a_pAFsm.pFsm.Event("restart")
+ }
+ }(pConfigAniStateAFsm)
+ }
+}
+
+func (oFsm *UniPonAniConfigFsm) ProcessOmciAniMessages( /*ctx context.Context*/ ) {
+ logger.Debugw("Start UniPonAniConfigFsm Msg processing", log.Fields{"for device-id": oFsm.pAdaptFsm.deviceID})
+loop:
+ for {
+ select {
+ // case <-ctx.Done():
+ // logger.Info("MibSync Msg", log.Fields{"Message handling canceled via context for device-id": oFsm.pAdaptFsm.deviceID})
+ // break loop
+ case message, ok := <-oFsm.pAdaptFsm.commChan:
+ if !ok {
+ logger.Info("UniPonAniConfigFsm Rx Msg - could not read from channel", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+ // but then we have to ensure a restart of the FSM as well - as exceptional procedure
+ oFsm.pAdaptFsm.pFsm.Event("reset")
+ break loop
+ }
+ logger.Debugw("UniPonAniConfigFsm Rx Msg", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+
+ switch message.Type {
+ case TestMsg:
+ msg, _ := message.Data.(TestMessage)
+ if msg.TestMessageVal == AbortMessageProcessing {
+ logger.Infow("UniPonAniConfigFsm abort ProcessMsg", log.Fields{"for device-id": oFsm.pAdaptFsm.deviceID})
+ break loop
+ }
+ logger.Warnw("UniPonAniConfigFsm unknown TestMessage", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID, "MessageVal": msg.TestMessageVal})
+ case OMCI:
+ msg, _ := message.Data.(OmciMessage)
+ oFsm.handleOmciAniConfigMessage(msg)
+ default:
+ logger.Warn("UniPonAniConfigFsm Rx unknown message", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID,
+ "message.Type": message.Type})
+ }
+ }
+ }
+ logger.Infow("End UniPonAniConfigFsm Msg processing", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+}
+
+func (oFsm *UniPonAniConfigFsm) handleOmciAniConfigMessage(msg OmciMessage) {
+ logger.Debugw("Rx OMCI UniPonAniConfigFsm Msg", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID,
+ "msgType": msg.OmciMsg.MessageType})
+
+ switch msg.OmciMsg.MessageType {
+ case omci.CreateResponseType:
+ {
+ msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeCreateResponse)
+ if msgLayer == nil {
+ logger.Error("Omci Msg layer could not be detected for CreateResponse")
+ return
+ }
+ msgObj, msgOk := msgLayer.(*omci.CreateResponse)
+ if !msgOk {
+ logger.Error("Omci Msg layer could not be assigned for CreateResponse")
+ return
+ }
+ logger.Debugw("CreateResponse Data", log.Fields{"deviceId": oFsm.pAdaptFsm.deviceID, "data-fields": msgObj})
+ if msgObj.Result != me.Success {
+ logger.Errorw("Omci CreateResponse Error - later: drive FSM to abort state ?", log.Fields{"Error": msgObj.Result})
+ // possibly force FSM into abort or ignore some errors for some messages? store error for mgmt display?
+ return
+ }
+ if msgObj.EntityClass == oFsm.pOmciCC.pLastTxMeInstance.GetClassID() &&
+ msgObj.EntityInstance == oFsm.pOmciCC.pLastTxMeInstance.GetEntityID() {
+ //store the created ME into DB //TODO??? obviously the Python code does not store the config ...
+ // if, then something like:
+ //oFsm.pOnuDB.StoreMe(msgObj)
+
+ // maybe we can use just the same eventName for different state transitions like "forward"
+ // - might be checked, but so far I go for sure and have to inspect the concrete state events ...
+ switch oFsm.pOmciCC.pLastTxMeInstance.GetName() {
+ case "Ieee8021PMapperServiceProfile":
+ { // let the FSM proceed ...
+ oFsm.pAdaptFsm.pFsm.Event("rx_dot1pmap_cresp")
+ }
+ case "MacBridgePortConfigurationData":
+ { // let the FSM proceed ...
+ oFsm.pAdaptFsm.pFsm.Event("rx_mbpcd_resp")
+ }
+ case "GemPortNetworkCtp", "GemInterworkingTerminationPoint":
+ { // let aniConfig Multi-Id processing proceed by stopping the wait function
+ oFsm.omciMIdsResponseReceived <- true
+ }
+ }
+ }
+ } //CreateResponseType
+ case omci.SetResponseType:
+ {
+ msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeSetResponse)
+ if msgLayer == nil {
+ logger.Error("UniPonAniConfigFsm - Omci Msg layer could not be detected for SetResponse")
+ return
+ }
+ msgObj, msgOk := msgLayer.(*omci.SetResponse)
+ if !msgOk {
+ logger.Error("UniPonAniConfigFsm - Omci Msg layer could not be assigned for SetResponse")
+ return
+ }
+ logger.Debugw("UniPonAniConfigFsm SetResponse Data", log.Fields{"deviceId": oFsm.pAdaptFsm.deviceID, "data-fields": msgObj})
+ if msgObj.Result != me.Success {
+ logger.Errorw("UniPonAniConfigFsm - Omci SetResponse Error - later: drive FSM to abort state ?", log.Fields{"Error": msgObj.Result})
+ // possibly force FSM into abort or ignore some errors for some messages? store error for mgmt display?
+ return
+ }
+ if msgObj.EntityClass == oFsm.pOmciCC.pLastTxMeInstance.GetClassID() &&
+ msgObj.EntityInstance == oFsm.pOmciCC.pLastTxMeInstance.GetEntityID() {
+ //store the created ME into DB //TODO??? obviously the Python code does not store the config ...
+ // if, then something like:
+ //oFsm.pOnuDB.StoreMe(msgObj)
+
+ switch oFsm.pOmciCC.pLastTxMeInstance.GetName() {
+ case "TCont":
+ { // let the FSM proceed ...
+ oFsm.pAdaptFsm.pFsm.Event("rx_tconts_resp")
+ }
+ case "PriorityQueue":
+ { // let the PrioQueue init proceed by stopping the wait function
+ oFsm.omciMIdsResponseReceived <- true
+ }
+ case "Ieee8021PMapperServiceProfile":
+ { // let the FSM proceed ...
+ oFsm.pAdaptFsm.pFsm.Event("rx_dot1pmap_sresp")
+ }
+ }
+ }
+ } //SetResponseType
+ default:
+ {
+ logger.Errorw("UniPonAniConfigFsm - Rx OMCI unhandled MsgType", log.Fields{"omciMsgType": msg.OmciMsg.MessageType})
+ return
+ }
+ }
+}
+
+func (oFsm *UniPonAniConfigFsm) performCreatingGemNCTPs() {
+ //TODO!! this is just for the first GemPort right now - needs update
+ // .. for gemPort in range gemPortXID
+ logger.Infow("UniPonAniConfigFsm Tx Create::GemNWCtp", log.Fields{
+ "EntitytId": strconv.FormatInt(int64(oFsm.gemPortXID[0]), 16),
+ "TcontId": strconv.FormatInt(int64(oFsm.tcont0ID), 16),
+ "device-id": oFsm.pAdaptFsm.deviceID})
+ meParams := me.ParamData{
+ EntityID: oFsm.gemPortXID[0],
+ Attributes: me.AttributeValueMap{
+ "PortId": oFsm.gemPortXID[0], //same as EntityID
+ "TContPointer": oFsm.tcont0ID,
+ "Direction": (*(oFsm.pUniTechProf.mapPonAniConfig[uint32(oFsm.pOnuUniPort.uniId)]))[0].mapGemPortParams[0].direction,
+ //ONU-G.TrafficManagementOption dependency ->PrioQueue or TCont
+ // TODO!! verify dependency and QueueId in case of Multi-GemPort setup!
+ "TrafficManagementPointerForUpstream": oFsm.upQueueXID[0], //might be different in wrr-only Setup - tcont0ID
+ "PriorityQueuePointerForDownStream": oFsm.downQueueXID[0],
+ },
+ }
+ meInstance := oFsm.pOmciCC.sendCreateGemNCTPVar(context.TODO(), ConstDefaultOmciTimeout, true,
+ oFsm.pAdaptFsm.commChan, meParams)
+ //accept also nil as (error) return value for writing to LastTx
+ // - this avoids misinterpretation of new received OMCI messages
+ oFsm.pOmciCC.pLastTxMeInstance = meInstance
+
+ //verify response
+ err := oFsm.waitforOmciResponse()
+ if err != nil {
+ logger.Errorw("GemNWCtp create failed, aborting AniConfig FSM!",
+ log.Fields{"deviceId": oFsm.pAdaptFsm.deviceID, "GemIndex": 0}) //running index in loop later!
+ oFsm.pAdaptFsm.pFsm.Event("reset")
+ return
+ }
+ //for all GemPortID's ports - later
+
+ // if Config has been done for all GemPort instances let the FSM proceed
+ logger.Debugw("GemNWCtp create loop finished", log.Fields{"deviceId": oFsm.pAdaptFsm.deviceID})
+ oFsm.pAdaptFsm.pFsm.Event("rx_gemntcps_resp")
+ return
+}
+
+func (oFsm *UniPonAniConfigFsm) performCreatingGemIWs() {
+ //TODO!! this is just for the first GemPort right now - needs update
+ // .. for gemPort in range gemPortXID
+ logger.Infow("UniPonAniConfigFsm Tx Create::GemIwTp", log.Fields{
+ "EntitytId": strconv.FormatInt(int64(oFsm.gemPortXID[0]), 16),
+ "SPPtr": strconv.FormatInt(int64(oFsm.mapperSP0ID), 16),
+ "device-id": oFsm.pAdaptFsm.deviceID})
+ meParams := me.ParamData{
+ EntityID: oFsm.gemPortXID[0],
+ Attributes: me.AttributeValueMap{
+ "GemPortNetworkCtpConnectivityPointer": oFsm.gemPortXID[0], //same as EntityID, see above
+ "InterworkingOption": 5, //fixed model:: G.998 .1pMapper
+ "ServiceProfilePointer": oFsm.mapperSP0ID,
+ "InterworkingTerminationPointPointer": 0, //not used with .1PMapper Mac bridge
+ "GalProfilePointer": galEthernetEID,
+ },
+ }
+ meInstance := oFsm.pOmciCC.sendCreateGemIWTPVar(context.TODO(), ConstDefaultOmciTimeout, true,
+ oFsm.pAdaptFsm.commChan, meParams)
+ //accept also nil as (error) return value for writing to LastTx
+ // - this avoids misinterpretation of new received OMCI messages
+ oFsm.pOmciCC.pLastTxMeInstance = meInstance
+
+ //verify response
+ err := oFsm.waitforOmciResponse()
+ if err != nil {
+ logger.Errorw("GemIwTp create failed, aborting AniConfig FSM!",
+ log.Fields{"deviceId": oFsm.pAdaptFsm.deviceID, "GemIndex": 0}) //running index in loop later!
+ oFsm.pAdaptFsm.pFsm.Event("reset")
+ return
+ }
+ //for all GemPortID's ports - later
+
+ // if Config has been done for all GemPort instances let the FSM proceed
+ logger.Debugw("GemIwTp create loop finished", log.Fields{"deviceId": oFsm.pAdaptFsm.deviceID})
+ oFsm.pAdaptFsm.pFsm.Event("rx_gemiws_resp")
+ return
+}
+
+func (oFsm *UniPonAniConfigFsm) performSettingPQs() {
+ //TODO!! this is just for the first upstream PrioQueue right now - needs update
+ //TODO!! implementation is restricted to WRR setting on the TrafficScheduler/Tcont
+ // SP setting would allow relatedPort(Prio) setting in case ONU supports config (ONU-2G QOS)
+
+ // .. for prioQueu in range upQueueXID
+ weight := (*(oFsm.pUniTechProf.mapPonAniConfig[uint32(oFsm.pOnuUniPort.uniId)]))[0].mapGemPortParams[0].queueWeight
+ logger.Infow("UniPonAniConfigFsm Tx Set::PrioQueue", log.Fields{
+ "EntitytId": strconv.FormatInt(int64(oFsm.upQueueXID[0]), 16),
+ "Weight": weight,
+ "device-id": oFsm.pAdaptFsm.deviceID})
+ meParams := me.ParamData{
+ EntityID: oFsm.upQueueXID[0],
+ Attributes: me.AttributeValueMap{
+ "Weight": weight,
+ },
+ }
+ meInstance := oFsm.pOmciCC.sendSetPrioQueueVar(context.TODO(), ConstDefaultOmciTimeout, true,
+ oFsm.pAdaptFsm.commChan, meParams)
+ //accept also nil as (error) return value for writing to LastTx
+ // - this avoids misinterpretation of new received OMCI messages
+ oFsm.pOmciCC.pLastTxMeInstance = meInstance
+
+ //verify response
+ err := oFsm.waitforOmciResponse()
+ if err != nil {
+ logger.Errorw("PrioQueue set failed, aborting AniConfig FSM!",
+ log.Fields{"deviceId": oFsm.pAdaptFsm.deviceID, "QueueIndex": 0}) //running index in loop later!
+ oFsm.pAdaptFsm.pFsm.Event("reset")
+ return
+ }
+ //for all upstream prioQueus - later
+
+ // if Config has been done for all PrioQueue instances let the FSM proceed
+ logger.Debugw("PrioQueue set loop finished", log.Fields{"deviceId": oFsm.pAdaptFsm.deviceID})
+ oFsm.pAdaptFsm.pFsm.Event("rx_prioqs_resp")
+ return
+}
+
+func (oFsm *UniPonAniConfigFsm) waitforOmciResponse() error {
+ select {
+ // maybe be also some outside cancel (but no context modelled for the moment ...)
+ // case <-ctx.Done():
+ // logger.Infow("LockState-bridge-init message reception canceled", log.Fields{"for device-id": oFsm.pAdaptFsm.deviceID})
+ case <-time.After(30 * time.Second): //3s was detected to be to less in 8*8 bbsim test with debug Info/Debug
+ logger.Warnw("UniPonAniConfigFsm multi entity timeout", log.Fields{"for device-id": oFsm.pAdaptFsm.deviceID})
+ return errors.New("UniPonAniConfigFsm multi entity timeout")
+ case success := <-oFsm.omciMIdsResponseReceived:
+ if success == true {
+ logger.Debug("UniPonAniConfigFsm multi entity response received")
+ return nil
+ }
+ // should not happen so far
+ logger.Warnw("UniPonAniConfigFsm multi entity response error", log.Fields{"for device-id": oFsm.pAdaptFsm.deviceID})
+ return errors.New("UniPonAniConfigFsm multi entity responseError")
+ }
+}
diff --git a/internal/pkg/onuadaptercore/omci_cc.go b/internal/pkg/onuadaptercore/omci_cc.go
index 7edd20e..1987562 100644
--- a/internal/pkg/onuadaptercore/omci_cc.go
+++ b/internal/pkg/onuadaptercore/omci_cc.go
@@ -221,7 +221,7 @@
return errors.New("could not assign omci layer")
}
logger.Debugw("omci-message-decoded:", log.Fields{"omciMsgType": omciMsg.MessageType,
- "transCorrId": omciMsg.TransactionID, "DeviceIdent": omciMsg.DeviceIdentifier})
+ "transCorrId": strconv.FormatInt(int64(omciMsg.TransactionID), 16), "DeviceIdent": omciMsg.DeviceIdentifier})
if byte(omciMsg.MessageType) & ^me.AK == 0 {
// Not a response
logger.Debug("RxMsg is no Omci Response Message")
@@ -535,8 +535,8 @@
//supply a response handler for omci response messages to be transferred to the requested FSM
func (oo *OmciCC) receiveOmciResponse(omciMsg *omci.OMCI, packet *gp.Packet, respChan chan Message) error {
- logger.Debugw("omci-message-response received:", log.Fields{"omciMsgType": omciMsg.MessageType,
- "transCorrId": omciMsg.TransactionID, "deviceId": oo.deviceID})
+ logger.Debugw("omci-message-response - transfer on omciRespChannel", log.Fields{"omciMsgType": omciMsg.MessageType,
+ "transCorrId": strconv.FormatInt(int64(omciMsg.TransactionID), 16), "deviceId": oo.deviceID})
if oo.pOnuDeviceEntry == nil {
logger.Errorw("Abort receiving OMCI response, DeviceEntryPointer is nil", log.Fields{
@@ -631,7 +631,8 @@
func (oo *OmciCC) sendCreateGalEthernetProfile(ctx context.Context, timeout int, highPrio bool) *me.ManagedEntity {
tid := oo.GetNextTid(highPrio)
- logger.Debugw("send GalEnetProfile-Create-msg:", log.Fields{"deviceId": oo.deviceID, "SequNo": strconv.FormatInt(int64(tid), 16)})
+ logger.Debugw("send GalEnetProfile-Create-msg:", log.Fields{"deviceId": oo.deviceID,
+ "SequNo": strconv.FormatInt(int64(tid), 16)})
meParams := me.ParamData{
EntityID: galEthernetEID,
@@ -663,21 +664,20 @@
logger.Errorw("Cannot send GalEnetProfile create", log.Fields{
"Err": err, "deviceId": oo.deviceID})
return nil
- } else {
- logger.Debug("send GalEnetProfile-Create-msg done")
- return meInstance
}
- } else {
- logger.Errorw("Cannot generate GalEnetProfileInstance", log.Fields{
- "Err": omciErr.GetError(), "deviceId": oo.deviceID})
- return nil
+ logger.Debug("send GalEnetProfile-Create-msg done")
+ return meInstance
}
+ logger.Errorw("Cannot generate GalEnetProfileInstance", log.Fields{
+ "Err": omciErr.GetError(), "deviceId": oo.deviceID})
+ return nil
}
// might be needed to extend for parameter arguments, here just for setting the ConnectivityMode!!
func (oo *OmciCC) sendSetOnu2g(ctx context.Context, timeout int, highPrio bool) *me.ManagedEntity {
tid := oo.GetNextTid(highPrio)
- logger.Debugw("send ONU2-G-Set-msg:", log.Fields{"deviceId": oo.deviceID, "SequNo": strconv.FormatInt(int64(tid), 16)})
+ logger.Debugw("send ONU2-G-Set-msg:", log.Fields{"deviceId": oo.deviceID,
+ "SequNo": strconv.FormatInt(int64(tid), 16)})
// ONU-G ME-ID is defined to be 0, but we could verify, if the ONU really supports the desired
// connectivity mode 5 (in ConnCap)
@@ -712,23 +712,21 @@
logger.Errorw("Cannot send ONU2-G set", log.Fields{
"Err": err, "deviceId": oo.deviceID})
return nil
- } else {
- logger.Debug("send ONU2-G-Set-msg done")
- return meInstance
}
- } else {
- logger.Errorw("Cannot generate ONU2-G", log.Fields{
- "Err": omciErr.GetError(), "deviceId": oo.deviceID})
- return nil
+ logger.Debug("send ONU2-G-Set-msg done")
+ return meInstance
}
+ logger.Errorw("Cannot generate ONU2-G", log.Fields{
+ "Err": omciErr.GetError(), "deviceId": oo.deviceID})
+ return nil
}
func (oo *OmciCC) sendCreateMBServiceProfile(ctx context.Context,
a_pUniPort *OnuUniPort, timeout int, highPrio bool) *me.ManagedEntity {
tid := oo.GetNextTid(highPrio)
instID := macBridgeServiceProfileEID + uint16(a_pUniPort.macBpNo)
- logger.Debugw("send MBSP-Create-msg:", log.Fields{
- "deviceId": oo.deviceID, "SequNo": strconv.FormatInt(int64(tid), 16), "InstId": instID})
+ logger.Debugw("send MBSP-Create-msg:", log.Fields{"deviceId": oo.deviceID,
+ "SequNo": strconv.FormatInt(int64(tid), 16), "InstId": strconv.FormatInt(int64(instID), 16)})
meParams := me.ParamData{
EntityID: instID,
@@ -770,23 +768,21 @@
logger.Errorw("Cannot send MBSP create", log.Fields{
"Err": err, "deviceId": oo.deviceID})
return nil
- } else {
- logger.Debug("send MBSP-Create-msg done")
- return meInstance
}
- } else {
- logger.Errorw("Cannot generate MBSP Instance", log.Fields{
- "Err": omciErr.GetError(), "deviceId": oo.deviceID})
- return nil
+ logger.Debug("send MBSP-Create-msg done")
+ return meInstance
}
+ logger.Errorw("Cannot generate MBSP Instance", log.Fields{
+ "Err": omciErr.GetError(), "deviceId": oo.deviceID})
+ return nil
}
func (oo *OmciCC) sendCreateMBPConfigData(ctx context.Context,
a_pUniPort *OnuUniPort, timeout int, highPrio bool) *me.ManagedEntity {
tid := oo.GetNextTid(highPrio)
instID := macBridgePortAniEID + a_pUniPort.entityId
- logger.Debugw("send MBPCD-Create-msg:", log.Fields{
- "deviceId": oo.deviceID, "SequNo": strconv.FormatInt(int64(tid), 16), "InstId": instID})
+ logger.Debugw("send MBPCD-Create-msg:", log.Fields{"deviceId": oo.deviceID,
+ "SequNo": strconv.FormatInt(int64(tid), 16), "InstId": strconv.FormatInt(int64(instID), 16)})
meParams := me.ParamData{
EntityID: instID,
@@ -824,15 +820,13 @@
logger.Errorw("Cannot send MBPCD create", log.Fields{
"Err": err, "deviceId": oo.deviceID})
return nil
- } else {
- logger.Debug("send MBPCD-Create-msg done")
- return meInstance
}
- } else {
- logger.Errorw("Cannot generate MBPCD Instance", log.Fields{
- "Err": omciErr.GetError(), "deviceId": oo.deviceID})
- return nil
+ logger.Debug("send MBPCD-Create-msg done")
+ return meInstance
}
+ logger.Errorw("Cannot generate MBPCD Instance", log.Fields{
+ "Err": omciErr.GetError(), "deviceId": oo.deviceID})
+ return nil
}
func (oo *OmciCC) sendCreateEVTOConfigData(ctx context.Context,
@@ -840,8 +834,8 @@
tid := oo.GetNextTid(highPrio)
//same entityId is used as for MBSP (see there), but just arbitrary ...
instID := macBridgeServiceProfileEID + uint16(a_pUniPort.macBpNo)
- logger.Debugw("send EVTOCD-Create-msg:", log.Fields{
- "deviceId": oo.deviceID, "SequNo": strconv.FormatInt(int64(tid), 16), "InstId": instID})
+ logger.Debugw("send EVTOCD-Create-msg:", log.Fields{"deviceId": oo.deviceID,
+ "SequNo": strconv.FormatInt(int64(tid), 16), "InstId": strconv.FormatInt(int64(instID), 16)})
// compare python adapter code WA VOL-1311: this is not done here!
// (setting TPID values for the create would probably anyway be ignored by the omci lib)
@@ -883,21 +877,20 @@
logger.Errorw("Cannot send EVTOCD create", log.Fields{
"Err": err, "deviceId": oo.deviceID})
return nil
- } else {
- logger.Debug("send EVTOCD-Create-msg done")
- return meInstance
}
- } else {
- logger.Errorw("Cannot generate EVTOCD Instance", log.Fields{
- "Err": omciErr.GetError(), "deviceId": oo.deviceID})
- return nil
+ logger.Debug("send EVTOCD-Create-msg done")
+ return meInstance
}
+ logger.Errorw("Cannot generate EVTOCD Instance", log.Fields{
+ "Err": omciErr.GetError(), "deviceId": oo.deviceID})
+ return nil
}
func (oo *OmciCC) sendSetOnuGLS(ctx context.Context, timeout int,
highPrio bool, requestedAttributes me.AttributeValueMap, rxChan chan Message) *me.ManagedEntity {
tid := oo.GetNextTid(highPrio)
- logger.Debugw("send ONU-G-Set-msg:", log.Fields{"deviceId": oo.deviceID, "SequNo": strconv.FormatInt(int64(tid), 16)})
+ logger.Debugw("send ONU-G-Set-msg:", log.Fields{"deviceId": oo.deviceID,
+ "SequNo": strconv.FormatInt(int64(tid), 16)})
// ONU-G ME-ID is defined to be 0, no need to perform a DB lookup
meParams := me.ParamData{
@@ -929,21 +922,20 @@
logger.Errorw("Cannot send ONU-G set", log.Fields{
"Err": err, "deviceId": oo.deviceID})
return nil
- } else {
- logger.Debug("send ONU-G-Set-msg done")
- return meInstance
}
- } else {
- logger.Errorw("Cannot generate ONU-G", log.Fields{
- "Err": omciErr.GetError(), "deviceId": oo.deviceID})
- return nil
+ logger.Debug("send ONU-G-Set-msg done")
+ return meInstance
}
+ logger.Errorw("Cannot generate ONU-G", log.Fields{
+ "Err": omciErr.GetError(), "deviceId": oo.deviceID})
+ return nil
}
func (oo *OmciCC) sendSetUniGLS(ctx context.Context, aInstNo uint16, timeout int,
highPrio bool, requestedAttributes me.AttributeValueMap, rxChan chan Message) *me.ManagedEntity {
tid := oo.GetNextTid(highPrio)
- logger.Debugw("send UNI-G-Set-msg:", log.Fields{"deviceId": oo.deviceID, "SequNo": strconv.FormatInt(int64(tid), 16)})
+ logger.Debugw("send UNI-G-Set-msg:", log.Fields{"deviceId": oo.deviceID,
+ "SequNo": strconv.FormatInt(int64(tid), 16)})
// UNI-G ME-ID is taken from Mib Upload stored OnuUniPort instance (argument)
meParams := me.ParamData{
@@ -975,21 +967,20 @@
logger.Errorw("Cannot send UNIG-G-Set", log.Fields{
"Err": err, "deviceId": oo.deviceID})
return nil
- } else {
- logger.Debug("send UNI-G-Set-msg done")
- return meInstance
}
- } else {
- logger.Errorw("Cannot generate UNI-G", log.Fields{
- "Err": omciErr.GetError(), "deviceId": oo.deviceID})
- return nil
+ logger.Debug("send UNI-G-Set-msg done")
+ return meInstance
}
+ logger.Errorw("Cannot generate UNI-G", log.Fields{
+ "Err": omciErr.GetError(), "deviceId": oo.deviceID})
+ return nil
}
func (oo *OmciCC) sendSetVeipLS(ctx context.Context, aInstNo uint16, timeout int,
highPrio bool, requestedAttributes me.AttributeValueMap, rxChan chan Message) *me.ManagedEntity {
tid := oo.GetNextTid(highPrio)
- logger.Debugw("send VEIP-Set-msg:", log.Fields{"deviceId": oo.deviceID, "SequNo": strconv.FormatInt(int64(tid), 16)})
+ logger.Debugw("send VEIP-Set-msg:", log.Fields{"deviceId": oo.deviceID,
+ "SequNo": strconv.FormatInt(int64(tid), 16)})
// ONU-G ME-ID is defined to be 0, no need to perform a DB lookup
meParams := me.ParamData{
@@ -1021,22 +1012,21 @@
logger.Errorw("Cannot send VEIP-Set", log.Fields{
"Err": err, "deviceId": oo.deviceID})
return nil
- } else {
- logger.Debug("send VEIP-Set-msg done")
- return meInstance
}
- } else {
- logger.Errorw("Cannot generate VEIP", log.Fields{
- "Err": omciErr.GetError(), "deviceId": oo.deviceID})
- return nil
+ logger.Debug("send VEIP-Set-msg done")
+ return meInstance
}
+ logger.Errorw("Cannot generate VEIP", log.Fields{
+ "Err": omciErr.GetError(), "deviceId": oo.deviceID})
+ return nil
}
func (oo *OmciCC) sendGetMe(ctx context.Context, classID me.ClassID, entityID uint16, requestedAttributes me.AttributeValueMap,
timeout int, highPrio bool) *me.ManagedEntity {
tid := oo.GetNextTid(highPrio)
- logger.Debugw("send get-request-msg", log.Fields{"classID": classID, "deviceId": oo.deviceID, "SequNo": strconv.FormatInt(int64(tid), 16)})
+ logger.Debugw("send get-request-msg", log.Fields{"classID": classID, "deviceId": oo.deviceID,
+ "SequNo": strconv.FormatInt(int64(tid), 16)})
meParams := me.ParamData{
EntityID: entityID,
@@ -1063,12 +1053,308 @@
if err != nil {
logger.Errorw("Cannot send get-request-msg", log.Fields{"meClassIdName": meClassIdName, "Err": err, "deviceId": oo.deviceID})
return nil
- } else {
- logger.Debugw("send get-request-msg done", log.Fields{"meClassIdName": meClassIdName, "deviceId": oo.deviceID})
- return meInstance
}
- } else {
- logger.Errorw("Cannot generate meDefinition", log.Fields{"classID": classID, "Err": omciErr.GetError(), "deviceId": oo.deviceID})
- return nil
+ logger.Debugw("send get-request-msg done", log.Fields{"meClassIdName": meClassIdName, "deviceId": oo.deviceID})
+ return meInstance
}
+ logger.Errorw("Cannot generate meDefinition", log.Fields{"classID": classID, "Err": omciErr.GetError(), "deviceId": oo.deviceID})
+ return nil
+}
+
+func (oo *OmciCC) sendCreateDot1PMapper(ctx context.Context, timeout int, highPrio bool,
+ aInstID uint16, rxChan chan Message) *me.ManagedEntity {
+ tid := oo.GetNextTid(highPrio)
+ logger.Debugw("send .1pMapper-Create-msg:", log.Fields{"deviceId": oo.deviceID,
+ "SequNo": strconv.FormatInt(int64(tid), 16), "InstId": strconv.FormatInt(int64(aInstID), 16)})
+
+ meParams := me.ParamData{
+ EntityID: aInstID,
+ Attributes: me.AttributeValueMap{},
+ }
+ meInstance, omciErr := me.NewIeee8021PMapperServiceProfile(meParams)
+ if omciErr.GetError() == nil {
+ //we have to set all 'untouched' parameters to default by some additional option parameter!!
+ omciLayer, msgLayer, err := omci.EncodeFrame(meInstance, omci.CreateRequestType,
+ omci.TransactionID(tid), omci.AddDefaults(true))
+ if err != nil {
+ logger.Errorw("Cannot encode .1pMapper for create", log.Fields{
+ "Err": err, "deviceId": oo.deviceID})
+ return nil
+ }
+
+ pkt, err := serializeOmciLayer(omciLayer, msgLayer)
+ if err != nil {
+ logger.Errorw("Cannot serialize .1pMapper create", log.Fields{
+ "Err": err, "deviceId": oo.deviceID})
+ return nil
+ }
+
+ omciRxCallbackPair := CallbackPair{
+ cbKey: tid,
+ cbEntry: CallbackPairEntry{rxChan, oo.receiveOmciResponse},
+ }
+ err = oo.Send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
+ if err != nil {
+ logger.Errorw("Cannot send .1pMapper create", log.Fields{
+ "Err": err, "deviceId": oo.deviceID})
+ return nil
+ }
+ logger.Debug("send .1pMapper-create-msg done")
+ return meInstance
+ }
+ logger.Errorw("Cannot generate .1pMapper", log.Fields{
+ "Err": omciErr.GetError(), "deviceId": oo.deviceID})
+ return nil
+}
+
+func (oo *OmciCC) sendCreateMBPConfigDataVar(ctx context.Context, timeout int, highPrio bool,
+ rxChan chan Message, params ...me.ParamData) *me.ManagedEntity {
+ tid := oo.GetNextTid(highPrio)
+ logger.Debugw("send MBPCD-Create-msg:", log.Fields{"deviceId": oo.deviceID,
+ "SequNo": strconv.FormatInt(int64(tid), 16),
+ "InstId": strconv.FormatInt(int64(params[0].EntityID), 16)})
+
+ meInstance, omciErr := me.NewMacBridgePortConfigurationData(params[0])
+ if omciErr.GetError() == nil {
+ //obviously we have to set all 'untouched' parameters to default by some additional option parameter!!
+ omciLayer, msgLayer, err := omci.EncodeFrame(meInstance, omci.CreateRequestType,
+ omci.TransactionID(tid), omci.AddDefaults(true))
+ if err != nil {
+ logger.Errorw("Cannot encode MBPCD for create", log.Fields{
+ "Err": err, "deviceId": oo.deviceID})
+ return nil
+ }
+
+ pkt, err := serializeOmciLayer(omciLayer, msgLayer)
+ if err != nil {
+ logger.Errorw("Cannot serialize MBPCD create", log.Fields{
+ "Err": err, "deviceId": oo.deviceID})
+ return nil
+ }
+
+ omciRxCallbackPair := CallbackPair{
+ cbKey: tid,
+ cbEntry: CallbackPairEntry{rxChan, oo.receiveOmciResponse},
+ }
+ err = oo.Send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
+ if err != nil {
+ logger.Errorw("Cannot send MBPCD create", log.Fields{
+ "Err": err, "deviceId": oo.deviceID})
+ return nil
+ }
+ logger.Debug("send MBPCD-Create-msg done")
+ return meInstance
+ }
+ logger.Errorw("Cannot generate MBPCD Instance", log.Fields{
+ "Err": omciErr.GetError(), "deviceId": oo.deviceID})
+ return nil
+}
+
+func (oo *OmciCC) sendCreateGemNCTPVar(ctx context.Context, timeout int, highPrio bool,
+ rxChan chan Message, params ...me.ParamData) *me.ManagedEntity {
+ tid := oo.GetNextTid(highPrio)
+ logger.Debugw("send GemNCTP-Create-msg:", log.Fields{"deviceId": oo.deviceID,
+ "SequNo": strconv.FormatInt(int64(tid), 16),
+ "InstId": strconv.FormatInt(int64(params[0].EntityID), 16)})
+
+ meInstance, omciErr := me.NewGemPortNetworkCtp(params[0])
+ if omciErr.GetError() == nil {
+ //obviously we have to set all 'untouched' parameters to default by some additional option parameter!!
+ omciLayer, msgLayer, err := omci.EncodeFrame(meInstance, omci.CreateRequestType,
+ omci.TransactionID(tid), omci.AddDefaults(true))
+ if err != nil {
+ logger.Errorw("Cannot encode GemNCTP for create", log.Fields{
+ "Err": err, "deviceId": oo.deviceID})
+ return nil
+ }
+
+ pkt, err := serializeOmciLayer(omciLayer, msgLayer)
+ if err != nil {
+ logger.Errorw("Cannot serialize GemNCTP create", log.Fields{
+ "Err": err, "deviceId": oo.deviceID})
+ return nil
+ }
+
+ omciRxCallbackPair := CallbackPair{
+ cbKey: tid,
+ cbEntry: CallbackPairEntry{rxChan, oo.receiveOmciResponse},
+ }
+ err = oo.Send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
+ if err != nil {
+ logger.Errorw("Cannot send GemNCTP create", log.Fields{
+ "Err": err, "deviceId": oo.deviceID})
+ return nil
+ }
+ logger.Debug("send GemNCTP-Create-msg done")
+ return meInstance
+ }
+ logger.Errorw("Cannot generate GemNCTP Instance", log.Fields{
+ "Err": omciErr.GetError(), "deviceId": oo.deviceID})
+ return nil
+}
+
+func (oo *OmciCC) sendCreateGemIWTPVar(ctx context.Context, timeout int, highPrio bool,
+ rxChan chan Message, params ...me.ParamData) *me.ManagedEntity {
+ tid := oo.GetNextTid(highPrio)
+ logger.Debugw("send GemIwTp-Create-msg:", log.Fields{"deviceId": oo.deviceID,
+ "SequNo": strconv.FormatInt(int64(tid), 16),
+ "InstId": strconv.FormatInt(int64(params[0].EntityID), 16)})
+
+ meInstance, omciErr := me.NewGemInterworkingTerminationPoint(params[0])
+ if omciErr.GetError() == nil {
+ //all SetByCreate Parameters (assumed to be) set here, for optimisation no 'AddDefaults'
+ omciLayer, msgLayer, err := omci.EncodeFrame(meInstance, omci.CreateRequestType,
+ omci.TransactionID(tid))
+ if err != nil {
+ logger.Errorw("Cannot encode GemIwTp for create", log.Fields{
+ "Err": err, "deviceId": oo.deviceID})
+ return nil
+ }
+
+ pkt, err := serializeOmciLayer(omciLayer, msgLayer)
+ if err != nil {
+ logger.Errorw("Cannot serialize GemIwTp create", log.Fields{
+ "Err": err, "deviceId": oo.deviceID})
+ return nil
+ }
+
+ omciRxCallbackPair := CallbackPair{
+ cbKey: tid,
+ cbEntry: CallbackPairEntry{rxChan, oo.receiveOmciResponse},
+ }
+ err = oo.Send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
+ if err != nil {
+ logger.Errorw("Cannot send GemIwTp create", log.Fields{
+ "Err": err, "deviceId": oo.deviceID})
+ return nil
+ }
+ logger.Debug("send GemIwTp-Create-msg done")
+ return meInstance
+ }
+ logger.Errorw("Cannot generate GemIwTp Instance", log.Fields{
+ "Err": omciErr.GetError(), "deviceId": oo.deviceID})
+ return nil
+}
+
+func (oo *OmciCC) sendSetTcontVar(ctx context.Context, timeout int, highPrio bool,
+ rxChan chan Message, params ...me.ParamData) *me.ManagedEntity {
+ tid := oo.GetNextTid(highPrio)
+ logger.Debugw("send TCont-Set-msg:", log.Fields{"deviceId": oo.deviceID,
+ "SequNo": strconv.FormatInt(int64(tid), 16),
+ "InstId": strconv.FormatInt(int64(params[0].EntityID), 16)})
+
+ meInstance, omciErr := me.NewTCont(params[0])
+ if omciErr.GetError() == nil {
+ omciLayer, msgLayer, err := omci.EncodeFrame(meInstance, omci.SetRequestType, omci.TransactionID(tid))
+ if err != nil {
+ logger.Errorw("Cannot encode TCont for set", log.Fields{
+ "Err": err, "deviceId": oo.deviceID})
+ return nil
+ }
+
+ pkt, err := serializeOmciLayer(omciLayer, msgLayer)
+ if err != nil {
+ logger.Errorw("Cannot serialize TCont set", log.Fields{
+ "Err": err, "deviceId": oo.deviceID})
+ return nil
+ }
+
+ omciRxCallbackPair := CallbackPair{
+ cbKey: tid,
+ cbEntry: CallbackPairEntry{rxChan, oo.receiveOmciResponse},
+ }
+ err = oo.Send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
+ if err != nil {
+ logger.Errorw("Cannot send TCont set", log.Fields{
+ "Err": err, "deviceId": oo.deviceID})
+ return nil
+ }
+ logger.Debug("send TCont-set msg done")
+ return meInstance
+ }
+ logger.Errorw("Cannot generate TCont Instance", log.Fields{
+ "Err": omciErr.GetError(), "deviceId": oo.deviceID})
+ return nil
+}
+
+func (oo *OmciCC) sendSetPrioQueueVar(ctx context.Context, timeout int, highPrio bool,
+ rxChan chan Message, params ...me.ParamData) *me.ManagedEntity {
+ tid := oo.GetNextTid(highPrio)
+ logger.Debugw("send PrioQueue-Set-msg:", log.Fields{"deviceId": oo.deviceID,
+ "SequNo": strconv.FormatInt(int64(tid), 16),
+ "InstId": strconv.FormatInt(int64(params[0].EntityID), 16)})
+
+ meInstance, omciErr := me.NewPriorityQueue(params[0])
+ if omciErr.GetError() == nil {
+ omciLayer, msgLayer, err := omci.EncodeFrame(meInstance, omci.SetRequestType, omci.TransactionID(tid))
+ if err != nil {
+ logger.Errorw("Cannot encode PrioQueue for set", log.Fields{
+ "Err": err, "deviceId": oo.deviceID})
+ return nil
+ }
+
+ pkt, err := serializeOmciLayer(omciLayer, msgLayer)
+ if err != nil {
+ logger.Errorw("Cannot serialize PrioQueue set", log.Fields{
+ "Err": err, "deviceId": oo.deviceID})
+ return nil
+ }
+
+ omciRxCallbackPair := CallbackPair{
+ cbKey: tid,
+ cbEntry: CallbackPairEntry{rxChan, oo.receiveOmciResponse},
+ }
+ err = oo.Send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
+ if err != nil {
+ logger.Errorw("Cannot send PrioQueue set", log.Fields{
+ "Err": err, "deviceId": oo.deviceID})
+ return nil
+ }
+ logger.Debug("send PrioQueue-set msg done")
+ return meInstance
+ }
+ logger.Errorw("Cannot generate PrioQueue Instance", log.Fields{
+ "Err": omciErr.GetError(), "deviceId": oo.deviceID})
+ return nil
+}
+
+func (oo *OmciCC) sendSetDot1PMapperVar(ctx context.Context, timeout int, highPrio bool,
+ rxChan chan Message, params ...me.ParamData) *me.ManagedEntity {
+ tid := oo.GetNextTid(highPrio)
+ logger.Debugw("send 1PMapper-Set-msg:", log.Fields{"deviceId": oo.deviceID,
+ "SequNo": strconv.FormatInt(int64(tid), 16),
+ "InstId": strconv.FormatInt(int64(params[0].EntityID), 16)})
+
+ meInstance, omciErr := me.NewIeee8021PMapperServiceProfile(params[0])
+ if omciErr.GetError() == nil {
+ omciLayer, msgLayer, err := omci.EncodeFrame(meInstance, omci.SetRequestType, omci.TransactionID(tid))
+ if err != nil {
+ logger.Errorw("Cannot encode 1PMapper for set", log.Fields{
+ "Err": err, "deviceId": oo.deviceID})
+ return nil
+ }
+
+ pkt, err := serializeOmciLayer(omciLayer, msgLayer)
+ if err != nil {
+ logger.Errorw("Cannot serialize 1PMapper set", log.Fields{
+ "Err": err, "deviceId": oo.deviceID})
+ return nil
+ }
+
+ omciRxCallbackPair := CallbackPair{
+ cbKey: tid,
+ cbEntry: CallbackPairEntry{rxChan, oo.receiveOmciResponse},
+ }
+ err = oo.Send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
+ if err != nil {
+ logger.Errorw("Cannot send 1PMapper set", log.Fields{
+ "Err": err, "deviceId": oo.deviceID})
+ return nil
+ }
+ logger.Debug("send 1PMapper-set msg done")
+ return meInstance
+ }
+ logger.Errorw("Cannot generate 1PMapper Instance", log.Fields{
+ "Err": omciErr.GetError(), "deviceId": oo.deviceID})
+ return nil
}
diff --git a/internal/pkg/onuadaptercore/onu_device_entry.go b/internal/pkg/onuadaptercore/onu_device_entry.go
index 9b453ce..a08e03f 100644
--- a/internal/pkg/onuadaptercore/onu_device_entry.go
+++ b/internal/pkg/onuadaptercore/onu_device_entry.go
@@ -53,6 +53,7 @@
UniAdminStateDone OnuDeviceEvent = 6 // Uni ports admin set done - general
PortLinkUp OnuDeviceEvent = 7 // Port link state change
PortLinkDw OnuDeviceEvent = 8 // Port link state change
+ OmciAniConfigDone OnuDeviceEvent = 9 // AniSide config according to TechProfile done
// Add other events here as needed (alarms separate???)
)
diff --git a/internal/pkg/onuadaptercore/onu_uni_tp.go b/internal/pkg/onuadaptercore/onu_uni_tp.go
index 1539b9a..0ab7984 100644
--- a/internal/pkg/onuadaptercore/onu_uni_tp.go
+++ b/internal/pkg/onuadaptercore/onu_uni_tp.go
@@ -20,8 +20,11 @@
import (
"context"
"encoding/json"
+ "strconv"
+ "strings"
"sync"
+ "github.com/looplab/fsm"
"github.com/opencord/voltha-lib-go/v3/pkg/db"
"github.com/opencord/voltha-lib-go/v3/pkg/db/kvstore"
"github.com/opencord/voltha-lib-go/v3/pkg/log"
@@ -49,9 +52,39 @@
persAdminState string
persOperState string
persUniTpPath map[uint32]string
- persUniTpData map[uint32]tp.TechProfile
}
+type tTechProfileIndication struct {
+ techProfileType string
+ techProfileID uint16
+}
+
+type tcontParamStruct struct {
+ allocID uint16
+ schedPolicy uint8
+}
+type gemPortParamStruct struct {
+ gemPortID uint16
+ direction uint8
+ gemPortEncState uint8
+ usedPbitMap uint8
+ ponOmciCC bool
+ discardPolicy string
+ //could also be a queue specific paramter, not used that way here
+ maxQueueSize uint16
+ queueSchedPolicy string
+ queueWeight uint8
+}
+
+//refers to one tcont and its properties and all assigned GemPorts and their properties
+type tcontGemList struct {
+ tcontParams tcontParamStruct
+ mapGemPortParams map[uint16]*gemPortParamStruct
+}
+
+//refers to all tcont and their Tcont/GemPort Parameters
+type tMapPonAniConfig map[uint16]*tcontGemList
+
//OnuUniTechProf structure holds information about the TechProfiles attached to Uni Ports of the ONU
type OnuUniTechProf struct {
deviceID string
@@ -59,6 +92,10 @@
tpProcMutex sync.RWMutex
sOnuPersistentData onuPersistentData
techProfileKVStore *db.Backend
+ chTpProcessingStep chan uint8
+ mapUniTpIndication map[uint32]*tTechProfileIndication //use pointer values to ease assignments to the map
+ mapPonAniConfig map[uint32]*tMapPonAniConfig //per UNI: use pointer values to ease assignments to the map
+ pAniConfigFsm *UniPonAniConfigFsm
}
//NewOnuUniTechProf returns the instance of a OnuUniTechProf
@@ -70,7 +107,9 @@
onuTP.baseDeviceHandler = aDeviceHandler
onuTP.tpProcMutex = sync.RWMutex{}
onuTP.sOnuPersistentData.persUniTpPath = make(map[uint32]string)
- onuTP.sOnuPersistentData.persUniTpData = make(map[uint32]tp.TechProfile)
+ onuTP.chTpProcessingStep = make(chan uint8)
+ onuTP.mapUniTpIndication = make(map[uint32]*tTechProfileIndication)
+ onuTP.mapPonAniConfig = make(map[uint32]*tMapPonAniConfig)
onuTP.techProfileKVStore = aDeviceHandler.SetBackend(cBasePathTechProfileKVStore)
if onuTP.techProfileKVStore == nil {
@@ -132,72 +171,342 @@
return true
}
-func (onuTP *OnuUniTechProf) configureUniTp(aUniID uint32, aPathString string, wg *sync.WaitGroup) {
- defer wg.Done()
+func (onuTP *OnuUniTechProf) waitForTpCompletion(cancel context.CancelFunc, wg *sync.WaitGroup) {
+ defer cancel() //ensure termination of context (may be pro forma)
+ wg.Wait()
+ logger.Debug("some TechProfile Processing completed")
+ onuTP.tpProcMutex.Unlock() //allow further TP related processing
+}
+
+// configureUniTp checks existing tp resources to delete and starts the corresponding OMCI configuation of the UNI port
+// all possibly blocking processing must be run in background to allow for deadline supervision!
+// but take care on sequential background processing when needed (logical dependencies)
+// use waitForTimeoutOrCompletion(ctx, processingStep) for internal synchronisation
+func (onuTP *OnuUniTechProf) configureUniTp(ctx context.Context,
+ aUniID uint32, aPathString string, wg *sync.WaitGroup) {
+ defer wg.Done() //always decrement the waitGroup on return
logger.Debugw("configure the Uni according to TpPath", log.Fields{
"deviceID": onuTP.deviceID, "uniID": aUniID, "path": aPathString})
- //TODO!!!
- // reaction on existing tp, deletion of tp, start the corresponding OMCI configuation of the UNI port
-
if onuTP.techProfileKVStore == nil {
logger.Debug("techProfileKVStore not set - abort")
return
}
- Value, err := onuTP.techProfileKVStore.Get(context.TODO(), aPathString)
- if err == nil {
- if Value != nil {
- logger.Debugw("tech-profile read",
- log.Fields{"Key": Value.Key, "Value": Value.Value})
- tpTmpBytes, _ := kvstore.ToByte(Value.Value)
+ //ensure that the given uniID is available (configured) in the UniPort class (used for OMCI entities)
+ var pCurrentUniPort *OnuUniPort
+ for _, uniPort := range onuTP.baseDeviceHandler.uniEntityMap {
+ // only if this port is validated for operState transfer
+ if uniPort.uniId == uint8(aUniID) {
+ pCurrentUniPort = uniPort
+ break //found - end search loop
+ }
+ }
+ if pCurrentUniPort == nil {
+ logger.Errorw("TechProfile configuration aborted: requested uniID not found in PortDB",
+ log.Fields{"device-id": onuTP.deviceID, "uniID": aUniID})
+ return
+ }
- var tpInst tp.TechProfile
- if err = json.Unmarshal(tpTmpBytes, &tpInst); err != nil {
- logger.Errorw("TechProf - Failed to unmarshal tech-profile into tpInst",
- log.Fields{"error": err, "device-id": onuTP.deviceID})
- } else {
- logger.Debugw("TechProf - tpInst", log.Fields{"tpInst": tpInst})
- onuTP.sOnuPersistentData.persUniTpData[aUniID] = tpInst
+ var processingStep uint8 = 1 // used to synchronize the different processing steps with chTpProcessingStep
- // access examples
- logger.Debugw("TechProf - name",
- log.Fields{"onuTP.sOnuPersistentData.persUniTpData[aUniID].Name": onuTP.sOnuPersistentData.persUniTpData[aUniID].Name})
- //
- logger.Debugw("TechProf - instance_control.max_gem_payload_size",
- log.Fields{"onuTP.sOnuPersistentData.persUniTpData[aUniID].InstanceCtrl.MaxGemPayloadSize": onuTP.sOnuPersistentData.persUniTpData[aUniID].InstanceCtrl.MaxGemPayloadSize})
- //
- logger.Debugw("TechProf - downstream_gem_port_attribute_list.discard_config.max_threshold",
- log.Fields{"onuTP.sOnuPersistentData.persUniTpData[aUniID].DownstreamGemPortAttributeList[0].DiscardConfig.MaxThreshold": onuTP.sOnuPersistentData.persUniTpData[aUniID].DownstreamGemPortAttributeList[0].DiscardConfig.MaxThreshold})
+ //according to updateOnuUniTpPath() logic the assumption here is, that this configuration is only called
+ // in case the KVPath has changed for the given UNI,
+ // as T-Cont and Gem-Id's are dependent on TechProfile-Id this means, that possibly previously existing
+ // (ANI) configuration of this port has to be removed first
+ // (moreover in this case a possibly existing flow configuration is also not valid anymore and needs clean-up as well)
+ // existence of configuration can be detected based on tp stored TCONT's
+ //TODO!!!:
+ /* if tcontMap not empty {
+ go onuTP.deleteAniSideConfig(ctx, aUniID, processingStep)
+ if !onuTP.waitForTimeoutOrCompletion(ctx, processingStep) {
+ //timeout or error detected
+ return
+ }
+ clear tcontMap
+ }
+
+ processingStep++
+ */
+ go onuTP.readAniSideConfigFromTechProfile(ctx, aUniID, aPathString, processingStep)
+ if !onuTP.waitForTimeoutOrCompletion(ctx, processingStep) {
+ //timeout or error detected
+ logger.Debugw("tech-profile related configuration aborted on read",
+ log.Fields{"device-id": onuTP.deviceID, "UniId": aUniID})
+ return
+ }
+
+ processingStep++
+ if valuePA, existPA := onuTP.mapPonAniConfig[aUniID]; existPA {
+ if _, existTG := (*valuePA)[0]; existTG {
+ //Config data for this uni and and at least TCont Index 0 exist
+ go onuTP.setAniSideConfigFromTechProfile(ctx, aUniID, pCurrentUniPort, processingStep)
+ if !onuTP.waitForTimeoutOrCompletion(ctx, processingStep) {
+ //timeout or error detected
+ logger.Debugw("tech-profile related configuration aborted on set",
+ log.Fields{"device-id": onuTP.deviceID, "UniId": aUniID})
+ //this issue here means that the AniConfigFsm has not finished succesfully
+ //which requires to reset it to allow for new usage, e.g. also on a different UNI
+ //(without that it would be reset on device down indication latest)
+ onuTP.pAniConfigFsm.pAdaptFsm.pFsm.Event("reset")
+ return
}
} else {
- logger.Debugw("No tech-profile found", log.Fields{"path": aPathString, "device-id": onuTP.deviceID})
+ // strange: UNI entry exists, but no ANI data, maybe such situation should be cleared up (if observed)
+ logger.Debugw("no Tcont/Gem data for this UNI found - abort", log.Fields{
+ "deviceID": onuTP.deviceID, "uniID": aUniID})
}
} else {
- logger.Errorw("kvstore-get failed for path",
- log.Fields{"path": aPathString, "device-id": onuTP.deviceID})
+ logger.Debugw("no PonAni data for this UNI found - abort", log.Fields{
+ "deviceID": onuTP.deviceID, "uniID": aUniID})
}
}
-func (onuTP *OnuUniTechProf) updateOnuTpPathKvStore(wg *sync.WaitGroup) {
+func (onuTP *OnuUniTechProf) updateOnuTpPathKvStore(ctx context.Context, wg *sync.WaitGroup) {
defer wg.Done()
logger.Debugw("this would update the ONU's TpPath in KVStore", log.Fields{
"deviceID": onuTP.deviceID})
//TODO!!!
- //make use of onuTP.sOnuPersistentData to store the TpPath to KVStore
+ //make use of onuTP.sOnuPersistentData to store the TpPath to KVStore - as background routine
+ /*
+ var processingStep uint8 = 1 // used to synchronize the different processing steps with chTpProcessingStep
+ go onuTp.storePersistentData(ctx, processingStep)
+ if !onuTP.waitForTimeoutOrCompletion(ctx, processingStep) {
+ //timeout or error detected
+ return
+ }
+ */
}
-// deleteTpRessource removes ressources from the ONU's specified Uni
-func (onuTP *OnuUniTechProf) deleteTpRessource(aUniID uint32, aPathString string,
- aRessource resourceEntry, aEntryID uint32, wg *sync.WaitGroup) {
+// deleteTpResource removes Resources from the ONU's specified Uni
+func (onuTP *OnuUniTechProf) deleteTpResource(ctx context.Context,
+ aUniID uint32, aPathString string, aResource resourceEntry, aEntryID uint32,
+ wg *sync.WaitGroup) {
defer wg.Done()
logger.Debugw("this would remove TP resources from ONU's UNI", log.Fields{
- "deviceID": onuTP.deviceID, "uniID": aUniID, "path": aPathString, "ressource": aRessource})
+ "deviceID": onuTP.deviceID, "uniID": aUniID, "path": aPathString, "Resource": aResource})
//TODO!!!
+ //delete the given resource from ONU OMCI config and data base - as background routine
+ /*
+ var processingStep uint8 = 1 // used to synchronize the different processing steps with chTpProcessingStep
+ go onuTp.deleteAniResource(ctx, processingStep)
+ if !onuTP.waitForTimeoutOrCompletion(ctx, processingStep) {
+ //timeout or error detected
+ return
+ }
+ */
}
-func (onuTP *OnuUniTechProf) waitForTpCompletion(wg *sync.WaitGroup) {
- wg.Wait()
- logger.Debug("some TechProfile Processing completed")
- onuTP.tpProcMutex.Unlock() //allow further TP related processing
+/* internal methods *********************/
+func (onuTP *OnuUniTechProf) readAniSideConfigFromTechProfile(
+ ctx context.Context, aUniID uint32, aPathString string, aProcessingStep uint8) {
+ var tpInst tp.TechProfile
+
+ //store profile type and identifier for later usage within the OMCI identifier and possibly ME setup
+ //pathstring is defined to be in the form of <ProfType>/<profID>/<Interface/../Identifier>
+ subStringSlice := strings.Split(aPathString, "/")
+ if len(subStringSlice) <= 2 {
+ logger.Errorw("invalid path name format",
+ log.Fields{"path": aPathString, "device-id": onuTP.deviceID})
+ onuTP.chTpProcessingStep <- 0 //error indication
+ return
+ }
+
+ //just some logical check to avoid unexpected behavior
+ //at this point it is assumed that a new TechProfile is assigned to the UNI
+ //expectation is that no TPIndication entry exists here, if yes,
+ // then we throw a warning and remove it (and the possible ANIConfig) simply
+ // note that the ONU config state may be ambivalent in such a case
+ // also note, that the PonAniConfig map is not checked additionally
+ // consistency to TPIndication is assumed
+ if _, existTP := onuTP.mapUniTpIndication[aUniID]; existTP {
+ logger.Warnw("Some active profile entry at reading new TechProfile",
+ log.Fields{"path": aPathString, "device-id": onuTP.deviceID,
+ "UniId": aUniID, "wrongProfile": onuTP.mapUniTpIndication[aUniID].techProfileID})
+ //delete on the mapUniTpIndication map not needed, just overwritten later
+ //delete on the PonAniConfig map should be safe, even if not existing
+ delete(onuTP.mapPonAniConfig, aUniID)
+ } else {
+ // this is normal processing
+ onuTP.mapUniTpIndication[aUniID] = &tTechProfileIndication{} //need to assign some (empty) struct memory first!
+ }
+
+ onuTP.mapUniTpIndication[aUniID].techProfileType = subStringSlice[0]
+ profID, err := strconv.ParseUint(subStringSlice[1], 10, 32)
+ if err != nil {
+ logger.Errorw("invalid ProfileId from path",
+ log.Fields{"ParseErr": err})
+ onuTP.chTpProcessingStep <- 0 //error indication
+ return
+ }
+
+ //note the limitation on ID range (probably even more limited) - based on usage within OMCI EntityID
+ onuTP.mapUniTpIndication[aUniID].techProfileID = uint16(profID)
+ logger.Debugw("tech-profile path indications",
+ log.Fields{"device-id": onuTP.deviceID, "UniId": aUniID,
+ "profType": onuTP.mapUniTpIndication[aUniID].techProfileType,
+ "profID": onuTP.mapUniTpIndication[aUniID].techProfileID})
+
+ Value, err := onuTP.techProfileKVStore.Get(context.TODO(), aPathString)
+ if err == nil {
+ if Value != nil {
+ logger.Debugw("tech-profile read",
+ log.Fields{"Key": Value.Key, "device-id": onuTP.deviceID})
+ tpTmpBytes, _ := kvstore.ToByte(Value.Value)
+
+ if err = json.Unmarshal(tpTmpBytes, &tpInst); err != nil {
+ logger.Errorw("TechProf - Failed to unmarshal tech-profile into tpInst",
+ log.Fields{"error": err, "device-id": onuTP.deviceID})
+ onuTP.chTpProcessingStep <- 0 //error indication
+ return
+ }
+ logger.Debugw("TechProf - tpInst", log.Fields{"tpInst": tpInst})
+ // access examples
+ logger.Debugw("TechProf content", log.Fields{"Name": tpInst.Name,
+ "MaxGemPayloadSize": tpInst.InstanceCtrl.MaxGemPayloadSize,
+ "DownstreamGemDiscardmaxThreshold": tpInst.DownstreamGemPortAttributeList[0].DiscardConfig.MaxThreshold})
+ } else {
+ logger.Errorw("No tech-profile found",
+ log.Fields{"path": aPathString, "device-id": onuTP.deviceID})
+ onuTP.chTpProcessingStep <- 0 //error indication
+ return
+ }
+ } else {
+ logger.Errorw("kvstore-get failed for path",
+ log.Fields{"path": aPathString, "device-id": onuTP.deviceID})
+ onuTP.chTpProcessingStep <- 0 //error indication
+ return
+ }
+
+ //for first start assume a 1Tcont1Gem profile, later extend for multi GemPerTcont and MultiTcontMultiGem
+ localMapGemPortParams := make(map[uint16]*gemPortParamStruct)
+ localMapGemPortParams[0] = &gemPortParamStruct{}
+ localMapPonAniConfig := make(map[uint16]*tcontGemList)
+ localMapPonAniConfig[0] = &tcontGemList{tcontParamStruct{}, localMapGemPortParams}
+ onuTP.mapPonAniConfig[aUniID] = (*tMapPonAniConfig)(&localMapPonAniConfig)
+
+ //get the relevant values from the profile and store to mapPonAniConfig
+ (*(onuTP.mapPonAniConfig[aUniID]))[0].tcontParams.allocID = uint16(tpInst.UsScheduler.AllocID)
+ //maybe tCont scheduling not (yet) needed - just to basicaly have it for future
+ // (would only be relevant in case of ONU-2G QOS configuration flexibility)
+ if tpInst.UsScheduler.QSchedPolicy == "StrictPrio" {
+ (*(onuTP.mapPonAniConfig[aUniID]))[0].tcontParams.schedPolicy = 1 //for the moment fixed value acc. G.988 //TODO: defines!
+ } else {
+ // default profile defines "Hybrid" - which probably comes down to WRR with some weigthts for SP
+ (*(onuTP.mapPonAniConfig[aUniID]))[0].tcontParams.schedPolicy = 2 //for G.988 WRR
+ }
+ for pos, content := range tpInst.UpstreamGemPortAttributeList {
+ if pos == 1 {
+ logger.Debugw("PonAniConfig abort GemPortList - still only one Gemport supported",
+ log.Fields{"device-id": onuTP.deviceID})
+ break
+ }
+ // a downstream GemPort should always exist (only downstream for MC)
+ (*(onuTP.mapPonAniConfig[aUniID]))[0].mapGemPortParams[uint16(pos)].gemPortID = uint16(content.GemportID)
+ // direction can be correlated later with Downstream list, for now just assume bidirectional (upstream never exists alone)
+ (*(onuTP.mapPonAniConfig[aUniID]))[0].mapGemPortParams[uint16(pos)].direction = 3 //as defined in G.988
+ if content.AesEncryption == "True" {
+ (*(onuTP.mapPonAniConfig[aUniID]))[0].mapGemPortParams[uint16(pos)].gemPortEncState = 1
+ } else {
+ (*(onuTP.mapPonAniConfig[aUniID]))[0].mapGemPortParams[uint16(pos)].gemPortEncState = 0
+ }
+
+ (*(onuTP.mapPonAniConfig[aUniID]))[0].mapGemPortParams[uint16(pos)].discardPolicy = content.DiscardPolicy
+ (*(onuTP.mapPonAniConfig[aUniID]))[0].mapGemPortParams[uint16(pos)].queueSchedPolicy = content.SchedulingPolicy
+ //'GemWeight' looks strange in default profile, for now we just copy the weight to first queue
+ (*(onuTP.mapPonAniConfig[aUniID]))[0].mapGemPortParams[uint16(pos)].queueWeight = uint8(content.Weight)
+ }
+ //TODO!! MC (downstream) GemPorts can be set using DownstreamGemPortAttributeList seperately
+
+ //logger does not simply output the given structures, just give some example debug values
+ logger.Debugw("PonAniConfig read from TechProfile", log.Fields{
+ "device-id": onuTP.deviceID,
+ "AllocId": (*(onuTP.mapPonAniConfig[aUniID]))[0].tcontParams.allocID,
+ "GemPort": (*(onuTP.mapPonAniConfig[aUniID]))[0].mapGemPortParams[0].gemPortID,
+ "QueueScheduling": (*(onuTP.mapPonAniConfig[aUniID]))[0].mapGemPortParams[0].queueSchedPolicy})
+
+ onuTP.chTpProcessingStep <- aProcessingStep //done
+}
+
+func (onuTP *OnuUniTechProf) setAniSideConfigFromTechProfile(
+ ctx context.Context, aUniID uint32, apCurrentUniPort *OnuUniPort, aProcessingStep uint8) {
+
+ //OMCI transfer of ANI data acc. to mapPonAniConfig
+ // also the FSM's are running in background,
+ // hence we have to make sure they indicate 'success' success on chTpProcessingStep with aProcessingStep
+ if onuTP.pAniConfigFsm == nil {
+ onuTP.createAniConfigFsm(aUniID, apCurrentUniPort, OmciAniConfigDone, aProcessingStep)
+ } else { //AniConfigFsm already init
+ onuTP.runAniConfigFsm(aProcessingStep)
+ }
+}
+
+func (onuTP *OnuUniTechProf) waitForTimeoutOrCompletion(
+ ctx context.Context, aProcessingStep uint8) bool {
+ select {
+ case <-ctx.Done():
+ logger.Warnw("processing not completed in-time: force release of TpProcMutex!",
+ log.Fields{"deviceID": onuTP.deviceID, "error": ctx.Err()})
+ return false
+ case rxStep := <-onuTP.chTpProcessingStep:
+ if rxStep == aProcessingStep {
+ return true
+ }
+ //all other values are not accepted - including 0 for error indication
+ logger.Warnw("Invalid processing step received: abort and force release of TpProcMutex!",
+ log.Fields{"deviceID": onuTP.deviceID,
+ "wantedStep": aProcessingStep, "haveStep": rxStep})
+ return false
+ }
+}
+
+// createUniLockFsm initialises and runs the AniConfig FSM to transfer the OMCI related commands for ANI side configuration
+func (onuTP *OnuUniTechProf) createAniConfigFsm(aUniID uint32,
+ apCurrentUniPort *OnuUniPort, devEvent OnuDeviceEvent, aProcessingStep uint8) {
+ logger.Debugw("createAniConfigFsm", log.Fields{"deviceID": onuTP.deviceID})
+ chAniConfigFsm := make(chan Message, 2048)
+ pDevEntry := onuTP.baseDeviceHandler.GetOnuDeviceEntry(true)
+ if pDevEntry == nil {
+ logger.Errorw("No valid OnuDevice - aborting", log.Fields{"deviceID": onuTP.deviceID})
+ return
+ }
+ pAniCfgFsm := NewUniPonAniConfigFsm(pDevEntry.PDevOmciCC, apCurrentUniPort, onuTP,
+ pDevEntry.pOnuDB, onuTP.mapUniTpIndication[aUniID].techProfileID, devEvent,
+ "AniConfigFsm", onuTP.deviceID, chAniConfigFsm)
+ if pAniCfgFsm != nil {
+ onuTP.pAniConfigFsm = pAniCfgFsm
+ onuTP.runAniConfigFsm(aProcessingStep)
+ } else {
+ logger.Errorw("AniConfigFSM could not be created - abort!!", log.Fields{"deviceID": onuTP.deviceID})
+ }
+}
+
+// runAniConfigFsm starts the AniConfig FSM to transfer the OMCI related commands for ANI side configuration
+func (onuTP *OnuUniTechProf) runAniConfigFsm(aProcessingStep uint8) {
+ /* Uni related ANI config procedure -
+ ***** should run via 'aniConfigDone' state and generate the argument requested event *****
+ */
+ var pACStatemachine *fsm.FSM
+ pACStatemachine = onuTP.pAniConfigFsm.pAdaptFsm.pFsm
+ if pACStatemachine != nil {
+ if pACStatemachine.Is("disabled") {
+ //FSM init requirement to get informed abou FSM completion! (otherwise timeout of the TechProf config)
+ onuTP.pAniConfigFsm.SetFsmCompleteChannel(onuTP.chTpProcessingStep, aProcessingStep)
+ if err := pACStatemachine.Event("start"); err != nil {
+ logger.Warnw("AniConfigFSM: can't start", log.Fields{"err": err})
+ // maybe try a FSM reset and then again ... - TODO!!!
+ } else {
+ /***** AniConfigFSM started */
+ logger.Debugw("AniConfigFSM started", log.Fields{
+ "state": pACStatemachine.Current(), "deviceID": onuTP.deviceID})
+ }
+ } else {
+ logger.Warnw("wrong state of AniConfigFSM - want: disabled", log.Fields{
+ "have": pACStatemachine.Current(), "deviceID": onuTP.deviceID})
+ // maybe try a FSM reset and then again ... - TODO!!!
+ }
+ } else {
+ logger.Errorw("AniConfigFSM StateMachine invalid - cannot be executed!!", log.Fields{"deviceID": onuTP.deviceID})
+ // maybe try a FSM reset and then again ... - TODO!!!
+ }
}
diff --git a/internal/pkg/onuadaptercore/openonu.go b/internal/pkg/onuadaptercore/openonu.go
index 1c72b4c..3de061e 100644
--- a/internal/pkg/onuadaptercore/openonu.go
+++ b/internal/pkg/onuadaptercore/openonu.go
@@ -268,7 +268,9 @@
//Update_flows_incrementally updates (add/remove) the flows on a given device
func (oo *OpenONUAC) Update_flows_incrementally(device *voltha.Device, flows *openflow_13.FlowChanges, groups *openflow_13.FlowGroupChanges, flowMetadata *voltha.FlowMetadata) error {
- return errors.New("unImplemented")
+ // return errors.New("unImplemented")
+ // testwise: just acknowledge to see, if that avoids ongoing TechProfile config sequences ...
+ return nil
}
//Update_pm_config returns PmConfigs nil or error