blob: 1481c6174625785553ae152d22dc50b99da6dcf7 [file] [log] [blame]
/*
* Copyright 2020-2024 Open Networking Foundation (ONF) and the ONF Contributors
*
* 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 mib provides the utilities for managing the onu mib
package mib
import (
"context"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"strconv"
"strings"
"sync"
"github.com/looplab/fsm"
"time"
"github.com/google/gopacket"
"github.com/opencord/omci-lib-go/v2"
me "github.com/opencord/omci-lib-go/v2/generated"
"github.com/opencord/voltha-lib-go/v7/pkg/db/kvstore"
"github.com/opencord/voltha-lib-go/v7/pkg/log"
cmn "github.com/opencord/voltha-openonu-adapter-go/internal/pkg/common"
devdb "github.com/opencord/voltha-openonu-adapter-go/internal/pkg/devdb"
otst "github.com/opencord/voltha-openonu-adapter-go/internal/pkg/omcitst"
"github.com/opencord/voltha-protos/v5/go/inter_adapter"
)
type sLastTxMeParameter struct {
pLastTxMeInstance *me.ManagedEntity
lastTxMessageType omci.MessageType
repeatCount uint8
}
const (
retryDelay = 30 * time.Second
maxRetries = 3
initialRetryAttempt = 1
)
var supportedClassIds = []me.ClassID{
me.CardholderClassID, // 5
me.CircuitPackClassID, // 6
me.SoftwareImageClassID, // 7
me.PhysicalPathTerminationPointEthernetUniClassID, // 11
me.PhysicalPathTerminationPointPotsUniClassID, // 53
me.OltGClassID, // 131
me.OnuPowerSheddingClassID, // 133
me.IpHostConfigDataClassID, // 134
me.OnuGClassID, // 256
me.Onu2GClassID, // 257
me.TContClassID, // 262
me.AniGClassID, // 263
me.UniGClassID, // 264
me.PriorityQueueClassID, // 277
me.TrafficSchedulerClassID, // 278
me.VirtualEthernetInterfacePointClassID, // 329
me.EnhancedSecurityControlClassID, // 332
me.OnuDynamicPowerManagementControlClassID, // 336
// 347 // definitions for ME "IPv6 host config data" are currently missing in omci-lib-go!
}
var omccVersionSupportsExtendedOmciFormat = map[uint8]bool{
0x80: false,
0x81: false,
0x82: false,
0x83: false,
0x84: false,
0x85: false,
0x86: false,
0xA0: false,
0xA1: false,
0xA2: false,
0xA3: false,
0x96: true,
0xB0: true,
0xB1: true,
0xB2: true,
0xB3: true,
0xB4: true,
}
var fsmMsg cmn.TestMessageType
func (oo *OnuDeviceEntry) enterStartingState(ctx context.Context, e *fsm.Event) {
logger.Debugw(ctx, "MibSync FSM", log.Fields{"Start processing MibSync-msgs in State": e.FSM.Current(), "device-id": oo.deviceID})
oo.pOnuDB = devdb.NewOnuDeviceDB(log.WithSpanFromContext(context.TODO(), ctx), oo.deviceID)
go oo.processMibSyncMessages(ctx)
}
func (oo *OnuDeviceEntry) enterResettingMibState(ctx context.Context, e *fsm.Event) {
logger.Debugw(ctx, "MibSync FSM", log.Fields{"Start MibTemplate processing in State": e.FSM.Current(), "device-id": oo.deviceID})
if (!oo.IsNewOnu() && !oo.baseDeviceHandler.IsReconciling()) || //use case: re-auditing failed
oo.baseDeviceHandler.IsSkipOnuConfigReconciling() { //use case: reconciling without omci-config failed
oo.baseDeviceHandler.PrepareReconcilingWithActiveAdapter(ctx)
oo.devState = cmn.DeviceStatusInit
}
logger.Debugw(ctx, "MibSync FSM", log.Fields{"send mibReset in State": e.FSM.Current(), "device-id": oo.deviceID})
oo.mutexLastTxParamStruct.Lock()
_ = oo.PDevOmciCC.SendMibReset(log.WithSpanFromContext(context.TODO(), ctx), oo.baseDeviceHandler.GetOmciTimeout(), true)
//TODO: needs to handle timeouts
//even though lastTxParameters are currently not used for checking the ResetResponse message we have to ensure
// that the lastTxMessageType is correctly set to avoid misinterpreting other responses
oo.lastTxParamStruct.lastTxMessageType = omci.MibResetRequestType
oo.lastTxParamStruct.repeatCount = 0
oo.mutexLastTxParamStruct.Unlock()
}
func (oo *OnuDeviceEntry) enterGettingVendorAndSerialState(ctx context.Context, e *fsm.Event) {
logger.Debugw(ctx, "MibSync FSM", log.Fields{"Start getting VendorId and SerialNumber in State": e.FSM.Current(), "device-id": oo.deviceID})
requestedAttributes := me.AttributeValueMap{me.OnuG_VendorId: "", me.OnuG_SerialNumber: 0}
oo.mutexLastTxParamStruct.Lock()
meInstance, err := oo.PDevOmciCC.SendGetMe(log.WithSpanFromContext(context.TODO(), ctx), me.OnuGClassID, cmn.OnugMeID, requestedAttributes,
oo.baseDeviceHandler.GetOmciTimeout(), true, oo.PMibUploadFsm.CommChan, false)
//accept also nil as (error) return value for writing to LastTx
// - this avoids misinterpretation of new received OMCI messages
if err != nil {
oo.mutexLastTxParamStruct.Unlock()
logger.Errorw(ctx, "ONU-G get failed, aborting MibSync FSM", log.Fields{"device-id": oo.deviceID})
pMibUlFsm := oo.PMibUploadFsm
if pMibUlFsm != nil {
//nolint:unparam
go func(a_pAFsm *cmn.AdapterFsm) {
_ = oo.PMibUploadFsm.PFsm.Event(UlEvStop)
}(pMibUlFsm)
}
return
}
oo.lastTxParamStruct.lastTxMessageType = omci.GetRequestType
oo.lastTxParamStruct.pLastTxMeInstance = meInstance
oo.mutexLastTxParamStruct.Unlock()
}
func (oo *OnuDeviceEntry) enterGettingVersionState(ctx context.Context, e *fsm.Event) {
logger.Debugw(ctx, "MibSync FSM", log.Fields{"Start getting Version in State": e.FSM.Current(), "device-id": oo.deviceID})
requestedAttributes := me.AttributeValueMap{me.OnuG_Version: ""}
oo.mutexLastTxParamStruct.Lock()
meInstance, err := oo.PDevOmciCC.SendGetMe(log.WithSpanFromContext(context.TODO(), ctx), me.OnuGClassID, cmn.OnugMeID,
requestedAttributes, oo.baseDeviceHandler.GetOmciTimeout(), true, oo.PMibUploadFsm.CommChan, false)
//accept also nil as (error) return value for writing to LastTx
// - this avoids misinterpretation of new received OMCI messages
if err != nil {
oo.mutexLastTxParamStruct.Unlock()
logger.Errorw(ctx, "ONU-G get failed, aborting MibSync FSM", log.Fields{"device-id": oo.deviceID})
pMibUlFsm := oo.PMibUploadFsm
if pMibUlFsm != nil {
//nolint:unparam
go func(a_pAFsm *cmn.AdapterFsm) {
_ = oo.PMibUploadFsm.PFsm.Event(UlEvStop)
}(pMibUlFsm)
}
return
}
oo.lastTxParamStruct.lastTxMessageType = omci.GetRequestType
oo.lastTxParamStruct.pLastTxMeInstance = meInstance
oo.mutexLastTxParamStruct.Unlock()
}
func (oo *OnuDeviceEntry) enterGettingEquipIDAndOmccVersState(ctx context.Context, e *fsm.Event) {
logger.Debugw(ctx, "MibSync FSM", log.Fields{"Start getting EquipmentId and OMCC version in State": e.FSM.Current(), "device-id": oo.deviceID})
requestedAttributes := me.AttributeValueMap{me.Onu2G_EquipmentId: "", me.Onu2G_OpticalNetworkUnitManagementAndControlChannelOmccVersion: 0}
oo.mutexLastTxParamStruct.Lock()
meInstance, err := oo.PDevOmciCC.SendGetMe(log.WithSpanFromContext(context.TODO(), ctx), me.Onu2GClassID, cmn.Onu2gMeID, requestedAttributes,
oo.baseDeviceHandler.GetOmciTimeout(), true, oo.PMibUploadFsm.CommChan, false)
//accept also nil as (error) return value for writing to LastTx
// - this avoids misinterpretation of new received OMCI messages
if err != nil {
oo.mutexLastTxParamStruct.Unlock()
logger.Errorw(ctx, "ONU2-G get failed, aborting MibSync FSM!", log.Fields{"device-id": oo.deviceID})
pMibUlFsm := oo.PMibUploadFsm
if pMibUlFsm != nil {
//nolint:unparam
go func(a_pAFsm *cmn.AdapterFsm) {
_ = oo.PMibUploadFsm.PFsm.Event(UlEvStop)
}(pMibUlFsm)
}
return
}
oo.lastTxParamStruct.lastTxMessageType = omci.GetRequestType
oo.lastTxParamStruct.pLastTxMeInstance = meInstance
oo.mutexLastTxParamStruct.Unlock()
}
func (oo *OnuDeviceEntry) enterTestingExtOmciSupportState(ctx context.Context, e *fsm.Event) {
logger.Debugw(ctx, "MibSync FSM", log.Fields{"Start testing extended OMCI msg in State": e.FSM.Current(), "device-id": oo.deviceID})
omciVerify := otst.NewOmciTestRequest(log.WithSpanFromContext(context.TODO(), ctx),
oo.deviceID, oo.PDevOmciCC, true, true, true)
verifyExec := make(chan bool)
omciVerify.PerformOmciTest(log.WithSpanFromContext(context.TODO(), ctx), verifyExec)
// If verification of test message in extended OMCI format fails, reset ONU capability to OMCI baseline format
select {
case <-time.After(((cmn.CDefaultRetries+1)*otst.CTestRequestOmciTimeout + 1) * time.Second):
logger.Warnw(ctx, "testing extended OMCI msg format timed out - reset to baseline format", log.Fields{"device-id": oo.deviceID})
oo.MutexPersOnuConfig.Lock()
oo.SOnuPersistentData.PersIsExtOmciSupported = false
oo.MutexPersOnuConfig.Unlock()
case success := <-verifyExec:
if success {
logger.Debugw(ctx, "testing extended OMCI msg format succeeded", log.Fields{"device-id": oo.deviceID})
} else {
logger.Warnw(ctx, "testing extended OMCI msg format failed - reset to baseline format", log.Fields{"device-id": oo.deviceID, "result": success})
oo.MutexPersOnuConfig.Lock()
oo.SOnuPersistentData.PersIsExtOmciSupported = false
oo.MutexPersOnuConfig.Unlock()
}
}
pMibUlFsm := oo.PMibUploadFsm
if pMibUlFsm != nil {
//nolint:unparam
go func(a_pAFsm *cmn.AdapterFsm) {
_ = oo.PMibUploadFsm.PFsm.Event(UlEvGetFirstSwVersion)
}(pMibUlFsm)
}
}
func (oo *OnuDeviceEntry) enterGettingFirstSwVersionState(ctx context.Context, e *fsm.Event) {
logger.Debugw(ctx, "MibSync FSM", log.Fields{"Start getting IsActive and Version of first SW-image in State": e.FSM.Current(), "device-id": oo.deviceID})
requestedAttributes := me.AttributeValueMap{me.SoftwareImage_IsCommitted: 0, me.SoftwareImage_IsActive: 0, me.SoftwareImage_Version: ""}
oo.mutexLastTxParamStruct.Lock()
meInstance, err := oo.PDevOmciCC.SendGetMe(log.WithSpanFromContext(context.TODO(), ctx), me.SoftwareImageClassID, cmn.FirstSwImageMeID, requestedAttributes,
oo.baseDeviceHandler.GetOmciTimeout(), true, oo.PMibUploadFsm.CommChan, oo.GetPersIsExtOmciSupported())
//accept also nil as (error) return value for writing to LastTx
// - this avoids misinterpretation of new received OMCI messages
if err != nil {
oo.mutexLastTxParamStruct.Unlock()
logger.Errorw(ctx, "SoftwareImage get failed, aborting MibSync FSM", log.Fields{"device-id": oo.deviceID})
pMibUlFsm := oo.PMibUploadFsm
if pMibUlFsm != nil {
//nolint:unparam
go func(a_pAFsm *cmn.AdapterFsm) {
_ = oo.PMibUploadFsm.PFsm.Event(UlEvStop)
}(pMibUlFsm)
}
return
}
oo.lastTxParamStruct.lastTxMessageType = omci.GetRequestType
oo.lastTxParamStruct.pLastTxMeInstance = meInstance
oo.mutexLastTxParamStruct.Unlock()
}
func (oo *OnuDeviceEntry) enterGettingSecondSwVersionState(ctx context.Context, e *fsm.Event) {
logger.Debugw(ctx, "MibSync FSM", log.Fields{"Start getting IsActive and Version of second SW-image in State": e.FSM.Current(), "device-id": oo.deviceID})
requestedAttributes := me.AttributeValueMap{me.SoftwareImage_IsCommitted: 0, me.SoftwareImage_IsActive: 0, me.SoftwareImage_Version: ""}
oo.mutexLastTxParamStruct.Lock()
meInstance, err := oo.PDevOmciCC.SendGetMe(log.WithSpanFromContext(context.TODO(), ctx), me.SoftwareImageClassID, cmn.SecondSwImageMeID, requestedAttributes,
oo.baseDeviceHandler.GetOmciTimeout(), true, oo.PMibUploadFsm.CommChan, oo.GetPersIsExtOmciSupported())
//accept also nil as (error) return value for writing to LastTx
// - this avoids misinterpretation of new received OMCI messages
if err != nil {
oo.mutexLastTxParamStruct.Unlock()
logger.Errorw(ctx, "SoftwareImage get failed, aborting MibSync FSM", log.Fields{"device-id": oo.deviceID})
pMibUlFsm := oo.PMibUploadFsm
if pMibUlFsm != nil {
//nolint:unparam
go func(a_pAFsm *cmn.AdapterFsm) {
_ = oo.PMibUploadFsm.PFsm.Event(UlEvStop)
}(pMibUlFsm)
}
return
}
oo.lastTxParamStruct.lastTxMessageType = omci.GetRequestType
oo.lastTxParamStruct.pLastTxMeInstance = meInstance
oo.mutexLastTxParamStruct.Unlock()
}
func (oo *OnuDeviceEntry) enterGettingMacAddressState(ctx context.Context, e *fsm.Event) {
logger.Debugw(ctx, "MibSync FSM", log.Fields{"Start getting MacAddress in State": e.FSM.Current(), "device-id": oo.deviceID})
requestedAttributes := me.AttributeValueMap{me.IpHostConfigData_MacAddress: ""}
oo.mutexLastTxParamStruct.Lock()
meInstance, err := oo.PDevOmciCC.SendGetMe(log.WithSpanFromContext(context.TODO(), ctx), me.IpHostConfigDataClassID, cmn.IPHostConfigDataMeID, requestedAttributes,
oo.baseDeviceHandler.GetOmciTimeout(), true, oo.PMibUploadFsm.CommChan, oo.GetPersIsExtOmciSupported())
//accept also nil as (error) return value for writing to LastTx
// - this avoids misinterpretation of new received OMCI messages
if err != nil {
oo.mutexLastTxParamStruct.Unlock()
logger.Errorw(ctx, "IpHostConfigData get failed, aborting MibSync FSM", log.Fields{"device-id": oo.deviceID})
pMibUlFsm := oo.PMibUploadFsm
if pMibUlFsm != nil {
//nolint:unparam
go func(a_pAFsm *cmn.AdapterFsm) {
_ = oo.PMibUploadFsm.PFsm.Event(UlEvStop)
}(pMibUlFsm)
}
return
}
oo.lastTxParamStruct.lastTxMessageType = omci.GetRequestType
oo.lastTxParamStruct.pLastTxMeInstance = meInstance
oo.mutexLastTxParamStruct.Unlock()
}
//nolint:unparam
func (oo *OnuDeviceEntry) enterGettingMibTemplateState(ctx context.Context, e *fsm.Event) {
oo.mutexOnuSwImageIndications.RLock()
if oo.onuSwImageIndications.ActiveEntityEntry.Valid {
oo.MutexPersOnuConfig.Lock()
oo.SOnuPersistentData.PersActiveSwVersion = oo.onuSwImageIndications.ActiveEntityEntry.Version
oo.MutexPersOnuConfig.Unlock()
oo.mutexOnuSwImageIndications.RUnlock()
} else {
oo.mutexOnuSwImageIndications.RUnlock()
logger.Errorw(ctx, "get-mib-template: no active SW version found, working with empty SW version, which might be untrustworthy",
log.Fields{"device-id": oo.deviceID})
}
//create the MIB Template path
oo.mibTemplatePath = oo.buildMibTemplatePath()
if cmnMEDBVal, exist := oo.pOpenOnuAc.FetchEntryFromMibDatabaseMap(ctx, oo.mibTemplatePath); exist {
logger.Infow(ctx, "A Common MIB DB Instance exist for this type of ONT", log.Fields{"device-id": oo.deviceID, "mibTemplatePath": oo.mibTemplatePath})
oo.pOpenOnuAc.LockMutexMibTemplateGenerated()
oo.pOnuDB.CommonMeDb = cmnMEDBVal
//VOL-5406:If the Instance is present but the MIB templates are cleaned up . Check and create one.
Value, err := oo.mibTemplateKVStore.Get(log.WithSpanFromContext(context.TODO(), ctx), oo.mibTemplatePath)
if err == nil {
if Value == nil {
error := oo.createAndPersistMibTemplate(ctx)
if error != nil {
logger.Errorw(ctx, "MibSync - MibTemplate - Failed to create and persist the mib template", log.Fields{"error": err, "device-id": oo.deviceID})
} else {
logger.Infow(ctx, "MIB Template created and stored ", log.Fields{"device-id": oo.deviceID, "mibTemplatePath": oo.mibTemplatePath})
}
}
} else {
logger.Errorw(ctx, "MibSync - MibTemplate - Failed to create and persist the mib template", log.Fields{"error": err, "device-id": oo.deviceID})
}
if cmnMEDBVal.MIBUploadStatus == devdb.Completed {
oo.pOnuDB.CommonMeDb.MeDbLock.Lock()
oo.updateOnuSpecificEntries(ctx)
oo.pOnuDB.CommonMeDb.MeDbLock.Unlock()
fsmMsg = cmn.LoadMibTemplateOk
} else {
logger.Errorw(ctx, "A previous MIB Upload for this type of ONT has failed, request for a MIB UPload", log.Fields{"device-id": oo.deviceID})
oo.pOpenOnuAc.ResetEntryFromMibDatabaseMap(ctx, oo.mibTemplatePath)
fsmMsg = cmn.LoadMibTemplateFailed
}
oo.pOpenOnuAc.UnlockMutexMibTemplateGenerated()
} else {
Value, err := oo.mibTemplateKVStore.Get(log.WithSpanFromContext(context.TODO(), ctx), oo.mibTemplatePath)
if err == nil && Value != nil {
logger.Infow(ctx, "No Common MIB DB instance exist , creating from Template", log.Fields{"device-id": oo.deviceID, "mibTemplatePath": oo.mibTemplatePath})
oo.processMibTemplate(ctx, Value)
fsmMsg = cmn.LoadMibTemplateOk
} else {
logger.Infow(ctx, "Neither Common MIB DB Instance nor MIB template exist for this type of ONT", log.Fields{"device-id": oo.deviceID, "mibTemplatePath": oo.mibTemplatePath})
oo.pOpenOnuAc.LockMutexMibTemplateGenerated()
cmnMEDBValue, _ := oo.pOpenOnuAc.CreateEntryAtMibDatabaseMap(ctx, oo.mibTemplatePath)
oo.pOnuDB.CommonMeDb = cmnMEDBValue
oo.pOnuDB.CommonMeDb.MeDbLock.Lock()
fsmMsg = cmn.LoadMibTemplateFailed
}
}
mibSyncMsg := cmn.Message{
Type: cmn.TestMsg,
Data: cmn.TestMessage{
TestMessageVal: fsmMsg,
},
}
oo.PMibUploadFsm.CommChan <- mibSyncMsg
}
func (oo *OnuDeviceEntry) enterUploadingState(ctx context.Context, e *fsm.Event) {
logger.Debugw(ctx, "MibSync FSM", log.Fields{"send MibUpload in State": e.FSM.Current(), "device-id": oo.deviceID})
_ = oo.PDevOmciCC.SendMibUpload(log.WithSpanFromContext(context.TODO(), ctx),
oo.baseDeviceHandler.GetOmciTimeout(), true, oo.GetPersIsExtOmciSupported())
//even though lastTxParameters are currently not used for checking the ResetResponse message we have to ensure
// that the lastTxMessageType is correctly set to avoid misinterpreting other responses
oo.mutexLastTxParamStruct.Lock()
oo.lastTxParamStruct.lastTxMessageType = omci.MibUploadRequestType
oo.mutexLastTxParamStruct.Unlock()
}
func (oo *OnuDeviceEntry) enterUploadDoneState(ctx context.Context, e *fsm.Event) {
logger.Debugw(ctx, "MibSync FSM", log.Fields{"send notification to core in State": e.FSM.Current(), "device-id": oo.deviceID})
oo.transferSystemEvent(ctx, cmn.MibDatabaseSync)
go func() {
_ = oo.PMibUploadFsm.PFsm.Event(UlEvSuccess)
}()
}
func (oo *OnuDeviceEntry) enterInSyncState(ctx context.Context, e *fsm.Event) {
oo.MutexPersOnuConfig.Lock()
oo.SOnuPersistentData.PersMibLastDbSync = uint32(time.Now().Unix())
oo.MutexPersOnuConfig.Unlock()
if oo.mibAuditInterval > 0 {
logger.Debugw(ctx, "MibSync FSM", log.Fields{"trigger next Audit in State": e.FSM.Current(), "oo.mibAuditInterval": oo.mibAuditInterval, "device-id": oo.deviceID})
go func() {
time.Sleep(oo.mibAuditInterval)
if err := oo.PMibUploadFsm.PFsm.Event(UlEvAuditMib); err != nil {
logger.Debugw(ctx, "MibSyncFsm: Can't go to state auditing", log.Fields{"device-id": oo.deviceID, "err": err})
}
}()
}
}
func (oo *OnuDeviceEntry) enterVerifyingAndStoringTPsState(ctx context.Context, e *fsm.Event) {
logger.Debugw(ctx, "MibSync FSM", log.Fields{"Start verifying and storing TPs in State": e.FSM.Current(), "device-id": oo.deviceID})
if oo.getAllStoredTpInstFromParentAdapter(ctx) {
logger.Debugw(ctx, "MibSync FSM", log.Fields{"reconciling - verifying TPs successful": e.FSM.Current(), "device-id": oo.deviceID})
go func() {
_ = oo.PMibUploadFsm.PFsm.Event(UlEvSuccess)
}()
} else {
logger.Debugw(ctx, "MibSync FSM", log.Fields{"reconciling - verifying TPs not successful": e.FSM.Current(), "device-id": oo.deviceID})
oo.baseDeviceHandler.SetReconcilingReasonUpdate(true)
go func() {
if err := oo.baseDeviceHandler.StorePersistentData(ctx); err != nil {
logger.Warnw(ctx, "reconciling - store persistent data error - continue for now as there will be additional write attempts",
log.Fields{"device-id": oo.deviceID, "err": err})
}
_ = oo.PMibUploadFsm.PFsm.Event(UlEvMismatch)
}()
}
}
func (oo *OnuDeviceEntry) enterExaminingMdsState(ctx context.Context, e *fsm.Event) {
logger.Debugw(ctx, "MibSync FSM", log.Fields{"Start GetMds processing in State": e.FSM.Current(), "device-id": oo.deviceID})
oo.pOpenOnuAc.RLockMutexDeviceHandlersMap()
dh, _ := oo.pOpenOnuAc.GetDeviceHandler(oo.deviceID)
oo.pOpenOnuAc.RUnlockMutexDeviceHandlersMap()
if dh.GetSkipOnuConfigEnabled() {
go func() {
_ = oo.PMibUploadFsm.PFsm.Event(UlEvSuccess)
}()
} else {
oo.requestMdsValue(ctx)
}
}
func (oo *OnuDeviceEntry) enterResynchronizingState(ctx context.Context, e *fsm.Event) {
logger.Debugw(ctx, "MibSync FSM", log.Fields{"Start MibResync processing in State": e.FSM.Current(), "device-id": oo.deviceID})
logger.Debug(ctx, "function not implemented yet")
// TODOs:
// VOL-3805 - Provide exclusive OMCI channel for one FSM
// VOL-3785 - New event notifications and corresponding performance counters for openonu-adapter-go
// VOL-3792 - Support periodical audit via mib resync
// VOL-3793 - ONU-reconcile handling after adapter restart based on mib resync
}
func (oo *OnuDeviceEntry) enterExaminingMdsSuccessState(ctx context.Context, e *fsm.Event) {
logger.Debugw(ctx, "MibSync FSM",
log.Fields{"Start processing on examining MDS success in State": e.FSM.Current(), "device-id": oo.deviceID})
if oo.getMibFromTemplate(ctx) {
oo.baseDeviceHandler.StartReconciling(ctx, true)
oo.baseDeviceHandler.AddAllUniPorts(ctx)
_ = oo.baseDeviceHandler.ReasonUpdate(ctx, cmn.DrInitialMibDownloaded, oo.baseDeviceHandler.IsReconcilingReasonUpdate())
oo.baseDeviceHandler.SetReadyForOmciConfig(true)
if !oo.baseDeviceHandler.GetCollectorIsRunning() {
var waitForOmciProcess sync.WaitGroup
waitForOmciProcess.Add(1)
// Start PM collector routine
go oo.baseDeviceHandler.StartCollector(ctx, &waitForOmciProcess)
waitForOmciProcess.Wait()
}
if !oo.baseDeviceHandler.GetAlarmManagerIsRunning(ctx) {
go oo.baseDeviceHandler.StartAlarmManager(ctx)
}
for _, uniPort := range *oo.baseDeviceHandler.GetUniEntityMap() {
// only if this port was enabled for use by the operator at startup
if (1<<uniPort.UniID)&oo.baseDeviceHandler.GetUniPortMask() == (1 << uniPort.UniID) {
if !oo.baseDeviceHandler.GetFlowMonitoringIsRunning(uniPort.UniID) {
go oo.baseDeviceHandler.PerOnuFlowHandlerRoutine(uniPort.UniID)
}
}
}
oo.MutexPersOnuConfig.RLock()
if oo.SOnuPersistentData.PersUniDisableDone {
oo.MutexPersOnuConfig.RUnlock()
oo.baseDeviceHandler.DisableUniPortStateUpdate(ctx)
_ = oo.baseDeviceHandler.ReasonUpdate(ctx, cmn.DrOmciAdminLock, oo.baseDeviceHandler.IsReconcilingReasonUpdate())
} else {
oo.MutexPersOnuConfig.RUnlock()
oo.baseDeviceHandler.EnableUniPortStateUpdate(ctx)
}
// no need to reconcile additional data for MibDownloadFsm, LockStateFsm, or UnlockStateFsm
if oo.baseDeviceHandler.ReconcileDeviceTechProf(ctx) {
// start go routine with select() on reconciling flow channel before
// starting flow reconciling process to prevent loss of any signal
syncChannel := make(chan struct{})
go func(aSyncChannel chan struct{}) {
// In multi-ONU/multi-flow environment stopping reconcilement has to be delayed until
// we get a signal that the processing of the last step to rebuild the adapter internal
// flow data is finished.
expiry := oo.baseDeviceHandler.GetReconcileExpiryVlanConfigAbort()
oo.setReconcilingFlows(true)
aSyncChannel <- struct{}{}
select {
case success := <-oo.chReconcilingFlowsFinished:
if success {
logger.Debugw(ctx, "reconciling flows has been finished in time",
log.Fields{"device-id": oo.deviceID})
_ = oo.PMibUploadFsm.PFsm.Event(UlEvSuccess)
} else {
logger.Debugw(ctx, "wait for reconciling flows aborted",
log.Fields{"device-id": oo.deviceID})
}
case <-time.After(expiry):
logger.Errorw(ctx, "timeout waiting for reconciling flows to be finished!",
log.Fields{"device-id": oo.deviceID, "expiry": expiry})
_ = oo.PMibUploadFsm.PFsm.Event(UlEvMismatch)
}
oo.setReconcilingFlows(false)
}(syncChannel)
// block further processing until the above Go routine has really started
// and is ready to receive values from chReconcilingFlowsFinished
<-syncChannel
oo.baseDeviceHandler.ReconcileDeviceFlowConfig(ctx)
}
} else {
logger.Debugw(ctx, "MibSync FSM",
log.Fields{"Getting MIB from template not successful": e.FSM.Current(), "device-id": oo.deviceID})
go func() {
//switch to reconciling with OMCI config
_ = oo.PMibUploadFsm.PFsm.Event(UlEvMismatch)
}()
}
}
func (oo *OnuDeviceEntry) enterAuditingState(ctx context.Context, e *fsm.Event) {
logger.Debugw(ctx, "MibSync FSM", log.Fields{"Start MibAudit processing in State": e.FSM.Current(), "device-id": oo.deviceID})
if oo.baseDeviceHandler.CheckAuditStartCondition(ctx, cmn.CUploadFsm) {
oo.requestMdsValue(ctx)
} else {
logger.Debugw(ctx, "MibSync FSM", log.Fields{"Configuration is ongoing or missing - skip auditing!": e.FSM.Current(), "device-id": oo.deviceID})
go func() {
_ = oo.PMibUploadFsm.PFsm.Event(UlEvSuccess)
}()
}
}
func (oo *OnuDeviceEntry) enterReAuditingState(ctx context.Context, e *fsm.Event) {
logger.Debugw(ctx, "MibSync FSM", log.Fields{"Start retest MdsValue processing in State": e.FSM.Current(), "device-id": oo.deviceID})
if oo.baseDeviceHandler.CheckAuditStartCondition(ctx, cmn.CUploadFsm) {
oo.requestMdsValue(ctx)
} else {
logger.Debugw(ctx, "MibSync FSM", log.Fields{"Configuration is ongoing or missing - skip re-auditing!": e.FSM.Current(), "device-id": oo.deviceID})
go func() {
_ = oo.PMibUploadFsm.PFsm.Event(UlEvSuccess)
}()
}
}
func (oo *OnuDeviceEntry) enterOutOfSyncState(ctx context.Context, e *fsm.Event) {
logger.Debugw(ctx, "MibSync FSM", log.Fields{"Start MibReconcile processing in State": e.FSM.Current(), "device-id": oo.deviceID})
logger.Debug(ctx, "function not implemented yet")
}
func (oo *OnuDeviceEntry) processMibSyncMessages(ctx context.Context) {
logger.Debugw(ctx, "MibSync Msg", log.Fields{"Start routine to process OMCI-messages for device-id": oo.deviceID})
oo.mutexMibSyncMsgProcessorRunning.Lock()
oo.mibSyncMsgProcessorRunning = true
oo.mutexMibSyncMsgProcessorRunning.Unlock()
loop:
for {
// case <-ctx.Done():
// logger.Info("MibSync Msg", log.Fields{"Message handling canceled via context for device-id": onuDeviceEntry.deviceID})
// break loop
message, ok := <-oo.PMibUploadFsm.CommChan
if !ok {
logger.Info(ctx, "MibSync Msg", log.Fields{"Message couldn't be read from channel for device-id": oo.deviceID})
oo.mutexMibSyncMsgProcessorRunning.Lock()
oo.mibSyncMsgProcessorRunning = false
oo.mutexMibSyncMsgProcessorRunning.Unlock()
break loop
}
logger.Debugw(ctx, "MibSync Msg", log.Fields{"Received message on ONU MibSyncChan for device-id": oo.deviceID})
switch message.Type {
case cmn.TestMsg:
msg, _ := message.Data.(cmn.TestMessage)
if msg.TestMessageVal == cmn.AbortMessageProcessing {
logger.Debugw(ctx, "MibSync Msg abort ProcessMsg", log.Fields{"for device-id": oo.deviceID})
oo.mutexMibSyncMsgProcessorRunning.Lock()
oo.mibSyncMsgProcessorRunning = false
oo.mutexMibSyncMsgProcessorRunning.Unlock()
break loop
}
oo.handleTestMsg(ctx, msg)
case cmn.OMCI:
msg, _ := message.Data.(cmn.OmciMessage)
oo.handleOmciMessage(ctx, msg)
default:
logger.Warn(ctx, "MibSync Msg", log.Fields{"Unknown message type received for device-id": oo.deviceID, "message.Type": message.Type})
}
}
logger.Info(ctx, "MibSync Msg", log.Fields{"Stopped handling of MibSyncChan for device-id": oo.deviceID})
// TODO: only this action?
_ = oo.PMibUploadFsm.PFsm.Event(UlEvStop)
}
func (oo *OnuDeviceEntry) handleTestMsg(ctx context.Context, msg cmn.TestMessage) {
logger.Debugw(ctx, "MibSync Msg", log.Fields{"TestMessage received for device-id": oo.deviceID, "msg.TestMessageVal": msg.TestMessageVal})
switch msg.TestMessageVal {
case cmn.LoadMibTemplateFailed:
_ = oo.PMibUploadFsm.PFsm.Event(UlEvUploadMib)
logger.Debugw(ctx, "MibSync Msg", log.Fields{"state": string(oo.PMibUploadFsm.PFsm.Current())})
case cmn.LoadMibTemplateOk:
_ = oo.PMibUploadFsm.PFsm.Event(UlEvSuccess)
logger.Debugw(ctx, "MibSync Msg", log.Fields{"state": string(oo.PMibUploadFsm.PFsm.Current())})
default:
logger.Warn(ctx, "MibSync Msg", log.Fields{"Unknown message type received for device-id": oo.deviceID, "msg.TestMessageVal": msg.TestMessageVal})
}
}
func (oo *OnuDeviceEntry) handleOmciMibResetResponseMessage(ctx context.Context, msg cmn.OmciMessage) {
if oo.PMibUploadFsm.PFsm.Is(UlStResettingMib) {
msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeMibResetResponse)
if msgLayer != nil {
msgObj, msgOk := msgLayer.(*omci.MibResetResponse)
if msgOk {
logger.Infow(ctx, "MibResetResponse Data", log.Fields{"data-fields": msgObj})
if msgObj.Result == me.Success {
oo.MutexPersOnuConfig.Lock()
oo.SOnuPersistentData.PersMibDataSyncAdpt = cmn.MdsDefaultMib
oo.MutexPersOnuConfig.Unlock()
oo.PDevOmciCC.ResetConfFailMEs()
// trigger retrieval of VendorId and SerialNumber
_ = oo.PMibUploadFsm.PFsm.Event(UlEvGetVendorAndSerial)
return
}
logger.Errorw(ctx, "Omci MibResetResponse Error", log.Fields{"device-id": oo.deviceID, "Error": msgObj.Result})
} else {
logger.Errorw(ctx, "Omci Msg layer could not be assigned", log.Fields{"device-id": oo.deviceID})
}
} else {
logger.Errorw(ctx, "Omci Msg layer could not be detected", log.Fields{"device-id": oo.deviceID})
}
} else {
//in case the last request was MdsGetRequest this issue may appear if the ONU was online before and has received the MIB reset
// with Sequence number 0x8000 as last request before - so it may still respond to that
// then we may force the ONU to react on the MdsGetRequest with a new message that uses an increased Sequence number
oo.mutexLastTxParamStruct.Lock()
if oo.lastTxParamStruct.lastTxMessageType == omci.GetRequestType && oo.lastTxParamStruct.repeatCount == 0 {
logger.Debugw(ctx, "MibSync FSM - repeat MdsGetRequest (updated SequenceNumber)", log.Fields{"device-id": oo.deviceID})
requestedAttributes := me.AttributeValueMap{me.OnuData_MibDataSync: ""}
_, err := oo.PDevOmciCC.SendGetMe(log.WithSpanFromContext(context.TODO(), ctx),
me.OnuDataClassID, cmn.OnuDataMeID, requestedAttributes, oo.baseDeviceHandler.GetOmciTimeout(), true, oo.PMibUploadFsm.CommChan, false)
if err != nil {
oo.mutexLastTxParamStruct.Unlock()
logger.Errorw(ctx, "ONUData get failed, aborting MibSync", log.Fields{"device-id": oo.deviceID})
_ = oo.PMibUploadFsm.PFsm.Event(UlEvStop)
return
}
//TODO: needs extra handling of timeouts
oo.lastTxParamStruct.repeatCount = 1
oo.mutexLastTxParamStruct.Unlock()
return
}
oo.mutexLastTxParamStruct.Unlock()
logger.Errorw(ctx, "unexpected MibResetResponse - ignoring", log.Fields{"device-id": oo.deviceID})
//perhaps some still lingering message from some prior activity, let's wait for the real response
return
}
logger.Info(ctx, "MibSync Msg", log.Fields{"Stopped handling of MibSyncChan for device-id": oo.deviceID})
_ = oo.PMibUploadFsm.PFsm.Event(UlEvStop)
}
func (oo *OnuDeviceEntry) handleOmciMibUploadResponseMessage(ctx context.Context, msg cmn.OmciMessage) {
msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeMibUploadResponse)
if msgLayer == nil {
logger.Errorw(ctx, "Omci Msg layer could not be detected", log.Fields{"device-id": oo.deviceID})
return
}
msgObj, msgOk := msgLayer.(*omci.MibUploadResponse)
if !msgOk {
logger.Errorw(ctx, "Omci Msg layer could not be assigned", log.Fields{"device-id": oo.deviceID})
return
}
logger.Debugw(ctx, "MibUploadResponse Data for:", log.Fields{"device-id": oo.deviceID, "data-fields": msgObj})
/* to be verified / reworked !!! */
oo.PDevOmciCC.UploadNoOfCmds = msgObj.NumberOfCommands
if oo.PDevOmciCC.UploadSequNo < oo.PDevOmciCC.UploadNoOfCmds {
_ = oo.PDevOmciCC.SendMibUploadNext(log.WithSpanFromContext(context.TODO(), ctx),
oo.baseDeviceHandler.GetOmciTimeout(), true, oo.GetPersIsExtOmciSupported())
//even though lastTxParameters are currently not used for checking the ResetResponse message we have to ensure
// that the lastTxMessageType is correctly set to avoid misinterpreting other responses
oo.mutexLastTxParamStruct.Lock()
oo.lastTxParamStruct.lastTxMessageType = omci.MibUploadNextRequestType
oo.mutexLastTxParamStruct.Unlock()
} else {
logger.Errorw(ctx, "Invalid number of commands received for:", log.Fields{"device-id": oo.deviceID, "UploadNoOfCmds": oo.PDevOmciCC.UploadNoOfCmds})
//TODO right action?
_ = oo.PMibUploadFsm.PFsm.Event(UlEvTimeout)
}
}
func (oo *OnuDeviceEntry) handleOmciMibUploadNextResponseMessage(ctx context.Context, msg cmn.OmciMessage) {
msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeMibUploadNextResponse)
if msgLayer != nil {
msgObj, msgOk := msgLayer.(*omci.MibUploadNextResponse)
if !msgOk {
logger.Errorw(ctx, "Omci Msg layer could not be assigned", log.Fields{"device-id": oo.deviceID})
return
}
meName := msgObj.ReportedME.GetName()
meClassID := msgObj.ReportedME.GetClassID()
meEntityID := msgObj.ReportedME.GetEntityID()
logger.Debugw(ctx, "MibUploadNextResponse Data for:", log.Fields{"device-id": oo.deviceID, "meName": meName, "data-fields": msgObj})
if meName == devdb.CUnknownItuG988ManagedEntity || meName == devdb.CUnknownVendorSpecificManagedEntity {
logger.Debugw(ctx, "MibUploadNextResponse contains unknown ME", log.Fields{"device-id": oo.deviceID,
"Me-Name": devdb.UnknownMeOrAttribName(meName), "Me-ClassId": meClassID, "Me-InstId": meEntityID,
"unknown mask": msgObj.ReportedME.GetAttributeMask(), "unknown attributes": msgObj.BaseLayer.Payload})
oo.pOnuDB.PutUnknownMeOrAttrib(ctx, devdb.UnknownMeOrAttribName(meName), meClassID, meEntityID,
msgObj.ReportedME.GetAttributeMask(), msgObj.BaseLayer.Payload[devdb.CStartUnknownMeAttribsInBaseLayerPayload:])
} else {
//with relaxed decoding set in the OMCI-LIB we have the chance to detect if there are some unknown attributes appended which we cannot decode
if unknownAttrLayer := (*msg.OmciPacket).Layer(omci.LayerTypeUnknownAttributes); unknownAttrLayer != nil {
logger.Warnw(ctx, "MibUploadNextResponse contains unknown attributes", log.Fields{"device-id": oo.deviceID})
if unknownAttributes, ok := unknownAttrLayer.(*omci.UnknownAttributes); ok {
// provide a loop over several ME's here already in preparation of OMCI extended message format
for _, unknown := range unknownAttributes.Attributes {
unknownAttrClassID := unknown.EntityClass // ClassID
unknownAttrInst := unknown.EntityInstance // uint16
unknownAttrMask := unknown.AttributeMask // ui
unknownAttrBlob := unknown.AttributeData // []byte
logger.Warnw(ctx, "unknown attributes detected for", log.Fields{"device-id": oo.deviceID,
"Me-ClassId": unknownAttrClassID, "Me-InstId": unknownAttrInst, "unknown mask": unknownAttrMask,
"unknown attributes": unknownAttrBlob})
oo.pOnuDB.PutUnknownMeOrAttrib(ctx, devdb.CUnknownAttributesManagedEntity, unknown.EntityClass, unknown.EntityInstance,
unknown.AttributeMask, unknown.AttributeData)
} // for all included ME's with unknown attributes
} else {
logger.Errorw(ctx, "unknownAttrLayer could not be decoded", log.Fields{"device-id": oo.deviceID})
}
}
oo.pOnuDB.PutMe(ctx, meClassID, meEntityID, msgObj.ReportedME.GetAttributeValueMap())
}
if msg.OmciMsg.DeviceIdentifier == omci.ExtendedIdent {
for _, additionalME := range msgObj.AdditionalMEs {
meName := additionalME.GetName()
meClassID := additionalME.GetClassID()
meEntityID := additionalME.GetEntityID()
attributes := additionalME.GetAttributeValueMap()
if meName == devdb.CUnknownItuG988ManagedEntity || meName == devdb.CUnknownVendorSpecificManagedEntity {
attribMask := additionalME.GetAttributeMask()
logger.Debugw(ctx, "MibUploadNextResponse AdditionalData contains unknown ME", log.Fields{"device-id": oo.deviceID,
"Me-Name": devdb.UnknownMeOrAttribName(meName), "Me-ClassId": meClassID, "Me-InstId": meEntityID,
"unknown mask": attribMask})
attribValues := make([]byte, 0)
for key, value := range attributes {
if key != cmn.CGenericManagedEntityIDName {
data, err := me.InterfaceToOctets(value)
if err != nil {
logger.Infow(ctx, "MibUploadNextResponse unknown ME AdditionalData attrib - could not decode", log.Fields{"device-id": oo.deviceID, "key": key})
} else {
attribValues = append(attribValues[:], data[:]...)
logger.Debugw(ctx, "MibUploadNextResponse unknown ME AdditionalData attrib", log.Fields{"device-id": oo.deviceID, "attribValues": attribValues, "data": data, "key": key})
}
}
}
oo.pOnuDB.PutUnknownMeOrAttrib(ctx, devdb.UnknownMeOrAttribName(meName), meClassID, meEntityID, attribMask, attribValues)
} else {
logger.Debugw(ctx, "MibUploadNextResponse AdditionalData for:", log.Fields{"device-id": oo.deviceID, "meName": meName, "meEntityID": meEntityID, "attributes": attributes})
oo.pOnuDB.PutMe(ctx, meClassID, meEntityID, attributes)
}
}
}
} else {
logger.Errorw(ctx, "Omci Msg layer could not be detected", log.Fields{"device-id": oo.deviceID})
//as long as omci-lib does not support decoding of table attribute as 'unknown/unspecified' attribute
// we have to verify, if this failure is from table attribute and try to go forward with ignoring the complete message
errLayer := (*msg.OmciPacket).Layer(gopacket.LayerTypeDecodeFailure)
if failure, decodeOk := errLayer.(*gopacket.DecodeFailure); decodeOk {
errMsg := failure.String()
if !strings.Contains(strings.ToLower(errMsg), "table decode") {
//something still unexected happened, needs deeper investigation - stop complete MIB upload process (timeout)
return
}
logger.Warnw(ctx, "Decode issue on received MibUploadNextResponse frame - found table attribute(s) (message ignored)",
log.Fields{"device-id": oo.deviceID, "issue": errMsg})
}
}
if oo.PDevOmciCC.UploadSequNo < oo.PDevOmciCC.UploadNoOfCmds {
_ = oo.PDevOmciCC.SendMibUploadNext(log.WithSpanFromContext(context.TODO(), ctx),
oo.baseDeviceHandler.GetOmciTimeout(), true, oo.GetPersIsExtOmciSupported())
//even though lastTxParameters are currently not used for checking the ResetResponse message we have to ensure
// that the lastTxMessageType is correctly set to avoid misinterpreting other responses
oo.mutexLastTxParamStruct.Lock()
oo.lastTxParamStruct.lastTxMessageType = omci.MibUploadNextRequestType
oo.mutexLastTxParamStruct.Unlock()
} else {
oo.pOnuDB.LogMeDb(ctx)
err := oo.createAndPersistMibTemplate(ctx)
if err != nil {
logger.Errorw(ctx, "MibSync - MibTemplate - Failed to create and persist the mib template", log.Fields{"error": err, "device-id": oo.deviceID})
}
oo.updateOnuSpecificEntries(ctx)
logger.Errorw(ctx, "MibSync - Updtaed the ONU Specific MEs ", log.Fields{"device-id": oo.deviceID})
cmnMEDB, _ := oo.pOpenOnuAc.FetchEntryFromMibDatabaseMap(ctx, oo.mibTemplatePath)
cmnMEDB.MIBUploadStatus = devdb.Completed
oo.pOnuDB.CommonMeDb.MeDbLock.Unlock()
oo.pOpenOnuAc.SetMibTemplatesGenerated(oo.mibTemplatePath, true)
oo.pOpenOnuAc.UnlockMutexMibTemplateGenerated()
_ = oo.PMibUploadFsm.PFsm.Event(UlEvSuccess)
}
}
// nolint: gocyclo
func (oo *OnuDeviceEntry) handleOmciGetResponseMessage(ctx context.Context, msg cmn.OmciMessage) error {
var err error = nil
oo.mutexLastTxParamStruct.RLock()
if oo.lastTxParamStruct.lastTxMessageType != omci.GetRequestType ||
oo.lastTxParamStruct.pLastTxMeInstance == nil {
//in case the last request was MibReset this issue may appear if the ONU was online before and has received the MDS GetRequest
// with Sequence number 0x8000 as last request before - so it may still respond to that
// then we may force the ONU to react on the MIB reset with a new message that uses an increased Sequence number
if oo.lastTxParamStruct.lastTxMessageType == omci.MibResetRequestType && oo.lastTxParamStruct.repeatCount == 0 {
logger.Debugw(ctx, "MibSync FSM - repeat mibReset (updated SequenceNumber)", log.Fields{"device-id": oo.deviceID})
_ = oo.PDevOmciCC.SendMibReset(log.WithSpanFromContext(context.TODO(), ctx), oo.baseDeviceHandler.GetOmciTimeout(), true)
//TODO: needs extra handling of timeouts
oo.lastTxParamStruct.repeatCount = 1
oo.mutexLastTxParamStruct.RUnlock()
return nil
}
oo.mutexLastTxParamStruct.RUnlock()
logger.Warnw(ctx, "unexpected GetResponse - ignoring", log.Fields{"device-id": oo.deviceID})
//perhaps some still lingering message from some prior activity, let's wait for the real response
return nil
}
oo.mutexLastTxParamStruct.RUnlock()
msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeGetResponse)
if msgLayer == nil {
logger.Errorw(ctx, "omci Msg layer could not be detected for GetResponse - handling of MibSyncChan stopped",
log.Fields{"device-id": oo.deviceID})
_ = oo.PMibUploadFsm.PFsm.Event(UlEvStop)
return fmt.Errorf("omci Msg layer could not be detected for GetResponse - handling of MibSyncChan stopped: %s", oo.deviceID)
}
msgObj, msgOk := msgLayer.(*omci.GetResponse)
if !msgOk {
logger.Errorw(ctx, "omci Msg layer could not be assigned for GetResponse - handling of MibSyncChan stopped",
log.Fields{"device-id": oo.deviceID})
_ = oo.PMibUploadFsm.PFsm.Event(UlEvStop)
return fmt.Errorf("omci Msg layer could not be assigned for GetResponse - handling of MibSyncChan stopped: %s", oo.deviceID)
}
logger.Debugw(ctx, "MibSync FSM - GetResponse Data", log.Fields{"device-id": oo.deviceID, "data-fields": msgObj})
if msgObj.Result == me.Success {
oo.mutexLastTxParamStruct.RLock()
entityID := oo.lastTxParamStruct.pLastTxMeInstance.GetEntityID()
if msgObj.EntityClass == oo.lastTxParamStruct.pLastTxMeInstance.GetClassID() && msgObj.EntityInstance == entityID {
meAttributes := msgObj.Attributes
meInstance := oo.lastTxParamStruct.pLastTxMeInstance.GetName()
logger.Debugf(ctx, "MibSync FSM - GetResponse Data for %s",
log.Fields{"device-id": oo.deviceID, "data-fields": msgObj}, meInstance)
switch meInstance {
case "OnuG":
oo.mutexLastTxParamStruct.RUnlock()
return oo.handleOmciGetResponseOnuG(ctx, meAttributes)
case "Onu2G":
oo.mutexLastTxParamStruct.RUnlock()
var equipmentID string
if onu2GEquipmentID, ok := meAttributes[me.Onu2G_EquipmentId]; ok {
equipmentID = cmn.TrimStringFromMeOctet(onu2GEquipmentID)
if equipmentID == "" {
logger.Infow(ctx,
"MibSync FSM - optional attribute EquipmentID is empty in Onu2G instance - fill with appropriate value",
log.Fields{"device-id": oo.deviceID})
equipmentID = cEmptyEquipIDString
}
} else {
logger.Infow(ctx,
"MibSync FSM - optional attribute EquipmentID not present in Onu2G instance - fill with appropriate value",
log.Fields{"device-id": oo.deviceID})
equipmentID = cNotPresentEquipIDString
}
oo.MutexPersOnuConfig.Lock()
oo.SOnuPersistentData.PersEquipmentID = equipmentID
logger.Debugw(ctx, "MibSync FSM - GetResponse Data for Onu2-G - EquipmentId", log.Fields{"device-id": oo.deviceID,
"onuDeviceEntry.equipmentID": oo.SOnuPersistentData.PersEquipmentID})
oo.MutexPersOnuConfig.Unlock()
var omccVersion uint8
if onu2GOmccVersion, ok := meAttributes[me.Onu2G_OpticalNetworkUnitManagementAndControlChannelOmccVersion]; ok {
oo.MutexPersOnuConfig.Lock()
omccVersion = onu2GOmccVersion.(uint8)
if _, ok := omccVersionSupportsExtendedOmciFormat[omccVersion]; ok {
oo.SOnuPersistentData.PersIsExtOmciSupported = omccVersionSupportsExtendedOmciFormat[omccVersion]
if oo.SOnuPersistentData.PersIsExtOmciSupported && !oo.baseDeviceHandler.GetExtendedOmciSupportEnabled() {
logger.Infow(ctx, "MibSync FSM - ONU supports extended OMCI, but support is disabled in the adapter: reset flag",
log.Fields{"device-id": oo.deviceID})
oo.SOnuPersistentData.PersIsExtOmciSupported = false
}
} else {
logger.Infow(ctx, "MibSync FSM - unknown OMCC version in Onu2G instance - disable extended OMCI support",
log.Fields{"device-id": oo.deviceID})
oo.SOnuPersistentData.PersIsExtOmciSupported = false
}
logger.Debugw(ctx, "MibSync FSM - GetResponse Data for Onu2-G - OMCC version", log.Fields{"device-id": oo.deviceID,
"omccVersion": omccVersion, "isExtOmciSupported": oo.SOnuPersistentData.PersIsExtOmciSupported})
oo.MutexPersOnuConfig.Unlock()
} else {
logger.Errorw(ctx,
"MibSync FSM - mandatory attribute OMCC version not present in Onu2G instance - handling of MibSyncChan stopped!",
log.Fields{"device-id": oo.deviceID})
_ = oo.PMibUploadFsm.PFsm.Event(UlEvStop)
return fmt.Errorf(
"mibSync FSM - mandatory attribute OMCC version not present in Onu2G instance - handling of MibSyncChan stopped: %s",
oo.deviceID)
}
oo.MutexPersOnuConfig.RLock()
if oo.SOnuPersistentData.PersIsExtOmciSupported {
oo.MutexPersOnuConfig.RUnlock()
// trigger test of OMCI extended msg format
_ = oo.PMibUploadFsm.PFsm.Event(UlEvTestExtOmciSupport)
return nil
}
oo.MutexPersOnuConfig.RUnlock()
// trigger retrieval of 1st SW-image info
_ = oo.PMibUploadFsm.PFsm.Event(UlEvGetFirstSwVersion)
return nil
case "SoftwareImage":
oo.mutexLastTxParamStruct.RUnlock()
if entityID > cmn.SecondSwImageMeID {
logger.Errorw(ctx, "mibSync FSM - Failed to GetResponse Data for SoftwareImage with expected EntityId",
log.Fields{"device-id": oo.deviceID, "entity-ID": entityID})
return fmt.Errorf("mibSync FSM - SwResponse Data with unexpected EntityId: %s %x",
oo.deviceID, entityID)
}
// need to use function for go lint complexity
if !oo.HandleSwImageIndications(ctx, entityID, meAttributes) {
logger.Errorw(ctx,
"MibSync FSM - Not all mandatory attributes present in in SoftwareImage instance - handling of MibSyncChan stopped!",
log.Fields{"device-id": oo.deviceID})
_ = oo.PMibUploadFsm.PFsm.Event(UlEvStop)
return fmt.Errorf(
"mibSync FSM - Not all mandatory attributes present in in SoftwareImage instance - handling of MibSyncChan stopped: %s",
oo.deviceID)
}
return nil
case "IpHostConfigData":
oo.mutexLastTxParamStruct.RUnlock()
oo.MutexPersOnuConfig.Lock()
if ipHostConfigMacAddress, ok := meAttributes[me.IpHostConfigData_MacAddress]; ok {
macBytes, _ := me.InterfaceToOctets(ipHostConfigMacAddress)
if cmn.OmciMacAddressLen == len(macBytes) {
oo.SOnuPersistentData.PersMacAddress = hex.EncodeToString(macBytes[:])
logger.Debugw(ctx, "MibSync FSM - GetResponse Data for IpHostConfigData - MacAddress", log.Fields{"device-id": oo.deviceID,
"macAddress": oo.SOnuPersistentData.PersMacAddress})
} else {
logger.Infow(ctx, "MibSync FSM - MacAddress wrong length - fill macAddress with zeros",
log.Fields{"device-id": oo.deviceID, "length": len(macBytes)})
oo.SOnuPersistentData.PersMacAddress = cEmptyMacAddrString
}
} else {
// since ONU creates instances of this ME automatically only when IP host services are available,
// processing continues here despite the error
logger.Infow(ctx, "MibSync FSM - MacAddress attribute not present in IpHostConfigData instance - fill macAddress with zeros",
log.Fields{"device-id": oo.deviceID})
oo.SOnuPersistentData.PersMacAddress = cEmptyMacAddrString
}
oo.MutexPersOnuConfig.Unlock()
// trigger retrieval of mib template
_ = oo.PMibUploadFsm.PFsm.Event(UlEvGetMibTemplate)
return nil
case "OnuData":
oo.mutexLastTxParamStruct.RUnlock()
if onuDataMibDataSync, ok := meAttributes[me.OnuData_MibDataSync]; ok {
oo.checkMdsValue(ctx, onuDataMibDataSync.(uint8))
} else {
logger.Errorw(ctx, "MibSync FSM - MibDataSync attribute not present in OnuData instance - handling of MibSyncChan stopped!",
log.Fields{"device-id": oo.deviceID})
_ = oo.PMibUploadFsm.PFsm.Event(UlEvStop)
return fmt.Errorf("mibSync FSM - VendorId attribute not present in OnuG instance - handling of MibSyncChan stopped: %s",
oo.deviceID)
}
return nil
default:
oo.mutexLastTxParamStruct.RUnlock()
logger.Warnw(ctx, "Unsupported ME name received!",
log.Fields{"ME name": meInstance, "device-id": oo.deviceID})
}
} else {
oo.mutexLastTxParamStruct.RUnlock()
logger.Warnf(ctx, "MibSync FSM - Received GetResponse Data for %s with wrong classID or entityID ",
log.Fields{"device-id": oo.deviceID, "data-fields": msgObj}, msgObj.EntityClass)
}
} else {
if err = oo.handleOmciGetResponseErrors(ctx, msgObj); err == nil {
return nil
}
}
logger.Info(ctx, "MibSync Msg", log.Fields{"Stopped handling of MibSyncChan for device-id": oo.deviceID})
_ = oo.PMibUploadFsm.PFsm.Event(UlEvStop)
return err
}
// HandleSwImageIndications updates onuSwImageIndications with the ONU data just received
func (oo *OnuDeviceEntry) HandleSwImageIndications(ctx context.Context, entityID uint16, meAttributes me.AttributeValueMap) bool {
var imageVersion string
var imageIsCommitted, imageIsActive uint8
allMandAttribsPresent := false
if softwareImageIsCommitted, ok := meAttributes[me.SoftwareImage_IsCommitted]; ok {
if softwareImageIsActiveimage, ok := meAttributes[me.SoftwareImage_IsActive]; ok {
if softwareImageVersion, ok := meAttributes[me.SoftwareImage_Version]; ok {
imageVersion = cmn.TrimStringFromMeOctet(softwareImageVersion)
imageIsActive = softwareImageIsActiveimage.(uint8)
imageIsCommitted = softwareImageIsCommitted.(uint8)
allMandAttribsPresent = true
}
}
}
if !allMandAttribsPresent {
logger.Errorw(ctx, "MibSync FSM - Not all mandatory attributes present in SoftwareImage instance - skip processing!", log.Fields{"device-id": oo.deviceID})
return allMandAttribsPresent
}
oo.MutexPersOnuConfig.RLock()
logger.Infow(ctx, "MibSync FSM - GetResponse Data for SoftwareImage",
log.Fields{"device-id": oo.deviceID, "entityID": entityID,
"version": imageVersion, "isActive": imageIsActive, "isCommitted": imageIsCommitted, "SNR": oo.SOnuPersistentData.PersSerialNumber})
oo.MutexPersOnuConfig.RUnlock()
if cmn.FirstSwImageMeID == entityID {
//always accept the state of the first image (2nd image info should not yet be available)
oo.mutexOnuSwImageIndications.Lock()
if imageIsActive == cmn.SwIsActive {
oo.onuSwImageIndications.ActiveEntityEntry.EntityID = entityID
oo.onuSwImageIndications.ActiveEntityEntry.Valid = true
oo.onuSwImageIndications.ActiveEntityEntry.Version = imageVersion
oo.onuSwImageIndications.ActiveEntityEntry.IsCommitted = imageIsCommitted
//as the SW version indication may stem from some ONU Down/up event
//the complementary image state is to be invalidated
// (state of the second image is always expected afterwards or just invalid)
oo.onuSwImageIndications.InActiveEntityEntry.Valid = false
} else {
oo.onuSwImageIndications.InActiveEntityEntry.EntityID = entityID
oo.onuSwImageIndications.InActiveEntityEntry.Valid = true
oo.onuSwImageIndications.InActiveEntityEntry.Version = imageVersion
oo.onuSwImageIndications.InActiveEntityEntry.IsCommitted = imageIsCommitted
//as the SW version indication may stem form some ONU Down/up event
//the complementary image state is to be invalidated
// (state of the second image is always expected afterwards or just invalid)
oo.onuSwImageIndications.ActiveEntityEntry.Valid = false
}
oo.mutexOnuSwImageIndications.Unlock()
_ = oo.PMibUploadFsm.PFsm.Event(UlEvGetSecondSwVersion)
return allMandAttribsPresent
} else if cmn.SecondSwImageMeID == entityID {
//2nd image info might conflict with first image info, in which case we priorize first image info!
oo.mutexOnuSwImageIndications.Lock()
if imageIsActive == cmn.SwIsActive { //2nd image reported to be active
if oo.onuSwImageIndications.ActiveEntityEntry.Valid {
//conflict exists - state of first image is left active
logger.Warnw(ctx, "mibSync FSM - both ONU images are reported as active - assuming 2nd to be inactive",
log.Fields{"device-id": oo.deviceID})
oo.onuSwImageIndications.InActiveEntityEntry.EntityID = entityID
oo.onuSwImageIndications.InActiveEntityEntry.Valid = true ////to indicate that at least something has been reported
oo.onuSwImageIndications.InActiveEntityEntry.Version = imageVersion
oo.onuSwImageIndications.InActiveEntityEntry.IsCommitted = imageIsCommitted
} else { //first image inactive, this one active
oo.onuSwImageIndications.ActiveEntityEntry.EntityID = entityID
oo.onuSwImageIndications.ActiveEntityEntry.Valid = true
oo.onuSwImageIndications.ActiveEntityEntry.Version = imageVersion
oo.onuSwImageIndications.ActiveEntityEntry.IsCommitted = imageIsCommitted
}
} else { //2nd image reported to be inactive
if oo.onuSwImageIndications.InActiveEntityEntry.Valid {
//conflict exists - both images inactive - regard it as ONU failure and assume first image to be active
logger.Warnw(ctx, "mibSync FSM - both ONU images are reported as inactive, defining first to be active",
log.Fields{"device-id": oo.deviceID})
oo.onuSwImageIndications.ActiveEntityEntry.EntityID = cmn.FirstSwImageMeID
oo.onuSwImageIndications.ActiveEntityEntry.Valid = true //to indicate that at least something has been reported
//copy active commit/version from the previously stored inactive position
oo.onuSwImageIndications.ActiveEntityEntry.Version = oo.onuSwImageIndications.InActiveEntityEntry.Version
oo.onuSwImageIndications.ActiveEntityEntry.IsCommitted = oo.onuSwImageIndications.InActiveEntityEntry.IsCommitted
}
//in any case we indicate (and possibly overwrite) the second image indications as inactive
oo.onuSwImageIndications.InActiveEntityEntry.EntityID = entityID
oo.onuSwImageIndications.InActiveEntityEntry.Valid = true
oo.onuSwImageIndications.InActiveEntityEntry.Version = imageVersion
oo.onuSwImageIndications.InActiveEntityEntry.IsCommitted = imageIsCommitted
}
oo.mutexOnuSwImageIndications.Unlock()
_ = oo.PMibUploadFsm.PFsm.Event(UlEvGetMacAddress)
}
return allMandAttribsPresent
}
func (oo *OnuDeviceEntry) handleOmciMessage(ctx context.Context, msg cmn.OmciMessage) {
logger.Debugw(ctx, "MibSync Msg", log.Fields{"OmciMessage received for device-id": oo.deviceID,
"msgType": msg.OmciMsg.MessageType, "msg": msg})
//further analysis could be done here based on msg.OmciMsg.Payload, e.g. verification of error code ...
switch msg.OmciMsg.MessageType {
case omci.MibResetResponseType:
oo.handleOmciMibResetResponseMessage(ctx, msg)
case omci.MibUploadResponseType:
oo.handleOmciMibUploadResponseMessage(ctx, msg)
case omci.MibUploadNextResponseType:
oo.handleOmciMibUploadNextResponseMessage(ctx, msg)
case omci.GetResponseType:
//TODO: error handling
_ = oo.handleOmciGetResponseMessage(ctx, msg)
default:
logger.Warnw(ctx, "Unknown Message Type", log.Fields{"device-id": oo.deviceID, "msgType": msg.OmciMsg.MessageType})
}
}
func (oo *OnuDeviceEntry) handleOmciGetResponseOnuG(ctx context.Context, meAttributes me.AttributeValueMap) error {
currentState := oo.PMibUploadFsm.PFsm.Current()
if currentState == UlStGettingVendorAndSerial {
if onuGVendorID, ok := meAttributes[me.OnuG_VendorId]; ok {
vendorID := cmn.TrimStringFromMeOctet(onuGVendorID)
if vendorID == "" {
logger.Infow(ctx,
"MibSync FSM - mandatory attribute VendorId is empty in OnuG instance - fill with appropriate value",
log.Fields{"device-id": oo.deviceID})
vendorID = cEmptyVendorIDString
}
oo.MutexPersOnuConfig.Lock()
oo.SOnuPersistentData.PersVendorID = vendorID
oo.MutexPersOnuConfig.Unlock()
} else {
logger.Errorw(ctx,
"MibSync FSM - mandatory attribute VendorId not present in OnuG instance - handling of MibSyncChan stopped!",
log.Fields{"device-id": oo.deviceID})
_ = oo.PMibUploadFsm.PFsm.Event(UlEvStop)
return fmt.Errorf(
"mibSync FSM - mandatory attribute VendorId not present in OnuG instance - handling of MibSyncChan stopped: %s",
oo.deviceID)
}
if onuGSerialNumber, ok := meAttributes[me.OnuG_SerialNumber]; ok {
oo.MutexPersOnuConfig.Lock()
snBytes, _ := me.InterfaceToOctets(onuGSerialNumber)
if cmn.OnugSerialNumberLen == len(snBytes) {
snVendorPart := string(snBytes[:4])
snNumberPart := hex.EncodeToString(snBytes[4:])
oo.SOnuPersistentData.PersSerialNumber = snVendorPart + snNumberPart
} else {
logger.Infow(ctx, "MibSync FSM - SerialNumber has wrong length - fill serialNumber with zeros",
log.Fields{"device-id": oo.deviceID, "length": len(snBytes)})
oo.SOnuPersistentData.PersSerialNumber = cEmptySerialNumberString
}
oo.MutexPersOnuConfig.Unlock()
} else {
logger.Errorw(ctx,
"MibSync FSM - mandatory attribute SerialNumber not present in OnuG instance - handling of MibSyncChan stopped!",
log.Fields{"device-id": oo.deviceID})
_ = oo.PMibUploadFsm.PFsm.Event(UlEvStop)
return fmt.Errorf(
"mibSync FSM - mandatory attribute SerialNumber not present in OnuG instance - handling of MibSyncChan stopped: %s",
oo.deviceID)
}
oo.MutexPersOnuConfig.Lock()
logger.Debugw(ctx, "MibSync FSM - GetResponse Data for Onu-G - VendorId/SerialNumber", log.Fields{"device-id": oo.deviceID,
"onuDeviceEntry.vendorID": oo.SOnuPersistentData.PersVendorID,
"onuDeviceEntry.serialNumber": oo.SOnuPersistentData.PersSerialNumber})
oo.MutexPersOnuConfig.Unlock()
// trigger retrieval of Version
_ = oo.PMibUploadFsm.PFsm.Event(UlEvGetVersion)
return nil
} else if currentState == UlStGettingVersion {
if onuGVersion, ok := meAttributes[me.OnuG_Version]; ok {
version := cmn.TrimStringFromMeOctet(onuGVersion)
if version == "" {
logger.Infow(ctx, "MibSync FSM - mandatory attribute Version is empty in OnuG instance - fill with appropriate value",
log.Fields{"device-id": oo.deviceID})
version = cEmptyVersionString
}
oo.MutexPersOnuConfig.Lock()
oo.SOnuPersistentData.PersVersion = version
oo.MutexPersOnuConfig.Unlock()
} else {
logger.Errorw(ctx,
"MibSync FSM - mandatory attribute Version not present in OnuG instance - handling of MibSyncChan stopped!",
log.Fields{"device-id": oo.deviceID})
_ = oo.PMibUploadFsm.PFsm.Event(UlEvStop)
return fmt.Errorf(
"mibSync FSM - mandatory attribute Version not present in OnuG instance - handling of MibSyncChan stopped: %s",
oo.deviceID)
}
oo.MutexPersOnuConfig.Lock()
logger.Debugw(ctx, "MibSync FSM - GetResponse Data for Onu-G - Version", log.Fields{"device-id": oo.deviceID,
"onuDeviceEntry.version": oo.SOnuPersistentData.PersVersion})
oo.MutexPersOnuConfig.Unlock()
// trigger retrieval of EquipmentId and OMCC version
_ = oo.PMibUploadFsm.PFsm.Event(UlEvGetEquipIDAndOmcc)
return nil
} else {
logger.Errorw(ctx, "MibSync FSM - wrong state OnuG response processing - handling of MibSyncChan stopped!",
log.Fields{"currentState": currentState, "device-id": oo.deviceID})
_ = oo.PMibUploadFsm.PFsm.Event(UlEvStop)
return fmt.Errorf("mibSync FSM - wrong state OnuG response processing - handling of MibSyncChan stopped: %s",
oo.deviceID)
}
}
func (oo *OnuDeviceEntry) handleOmciGetResponseErrors(ctx context.Context, msgObj *omci.GetResponse) error {
var err error = nil
logger.Debugf(ctx, "MibSync FSM - erroneous result in GetResponse Data: %s", log.Fields{"device-id": oo.deviceID, "data-fields": msgObj}, msgObj.Result)
// Up to now the following erroneous results have been seen for different ONU-types to indicate an unsupported ME
if msgObj.Result == me.UnknownInstance || msgObj.Result == me.UnknownEntity || msgObj.Result == me.ProcessingError || msgObj.Result == me.NotSupported {
oo.mutexLastTxParamStruct.RLock()
if oo.lastTxParamStruct.pLastTxMeInstance != nil {
entityID := oo.lastTxParamStruct.pLastTxMeInstance.GetEntityID()
if msgObj.EntityClass == oo.lastTxParamStruct.pLastTxMeInstance.GetClassID() && msgObj.EntityInstance == entityID {
meInstance := oo.lastTxParamStruct.pLastTxMeInstance.GetName()
switch meInstance {
case "IpHostConfigData":
oo.mutexLastTxParamStruct.RUnlock()
logger.Debugw(ctx, "MibSync FSM - erroneous result for IpHostConfigData received - ONU doesn't support ME - fill macAddress with zeros",
log.Fields{"device-id": oo.deviceID, "data-fields": msgObj})
oo.MutexPersOnuConfig.Lock()
oo.SOnuPersistentData.PersMacAddress = cEmptyMacAddrString
oo.MutexPersOnuConfig.Unlock()
// trigger retrieval of mib template
_ = oo.PMibUploadFsm.PFsm.Event(UlEvGetMibTemplate)
return nil
default:
oo.mutexLastTxParamStruct.RUnlock()
logger.Warnf(ctx, "MibSync FSM - erroneous result for %s received - no exceptional treatment defined", log.Fields{"device-id": oo.deviceID, "data-fields": msgObj}, meInstance)
err = fmt.Errorf("erroneous result for %s received - no exceptional treatment defined: %s", meInstance, oo.deviceID)
}
} else {
oo.mutexLastTxParamStruct.RUnlock()
}
} else {
oo.mutexLastTxParamStruct.RUnlock()
logger.Warnw(ctx, "Pointer to last Tx MeInstance is nil!", log.Fields{"device-id": oo.deviceID})
}
} else {
logger.Errorf(ctx, "MibSync FSM - erroneous result in GetResponse Data: %s", log.Fields{"device-id": oo.deviceID, "data-fields": msgObj}, msgObj.Result)
err = fmt.Errorf("erroneous result in GetResponse Data: %s - %s", msgObj.Result, oo.deviceID)
}
return err
}
// IsNewOnu - TODO: add comment
func (oo *OnuDeviceEntry) IsNewOnu() bool {
oo.MutexPersOnuConfig.RLock()
defer oo.MutexPersOnuConfig.RUnlock()
return oo.SOnuPersistentData.PersMibLastDbSync == 0
}
func isSupportedClassID(meClassID me.ClassID) bool {
for _, v := range supportedClassIds {
if v == meClassID {
return true
}
}
return false
}
func (oo *OnuDeviceEntry) mibDbVolatileDict(ctx context.Context) error {
logger.Debug(ctx, "MibVolatileDict- running from default Entry code")
return errors.New("not_implemented")
}
// createAndPersistMibTemplate method creates a mib template for the device id when operator enables the ONU device for the first time.
// We are creating a placeholder for "SerialNumber" for ME Class ID 6 and 256 and "MacAddress" for ME Class ID 134 in the template
// and then storing the template into etcd "service/voltha/omci_mibs/go_templates/verdor_id/equipment_id/software_version" path.
func (oo *OnuDeviceEntry) createAndPersistMibTemplate(ctx context.Context) error {
logger.Debugw(ctx, "MibSync - MibTemplate - path name", log.Fields{"path": oo.mibTemplatePath,
"device-id": oo.deviceID})
//Fetch the MEs dependent on serial number and MAC address and add them to onuSpecific ME DB
//Modify the serial number and MAC address with generic content in the common DB.
knownAttributeMEDb := oo.pOnuDB.CommonMeDb.MeDb
for firstLevelKey, firstLevelValue := range knownAttributeMEDb {
classID := strconv.Itoa(int(firstLevelKey))
for secondLevelKey, secondLevelValue := range firstLevelValue {
switch classID {
case "6", "256":
if _, exists := secondLevelValue["SerialNumber"]; exists {
oo.pOnuDB.PutOnuSpeficMe(ctx, firstLevelKey, secondLevelKey, secondLevelValue)
secondLevelValue["SerialNumber"] = "%SERIAL_NUMBER%"
}
case "134":
if _, exists := secondLevelValue["MacAddress"]; exists {
oo.pOnuDB.PutOnuSpeficMe(ctx, firstLevelKey, secondLevelKey, secondLevelValue)
secondLevelValue["MacAddress"] = "%MAC_ADDRESS%"
}
}
}
}
//Create the MIB Template
currentTime := time.Now()
templateMap := make(map[string]interface{})
templateMap["TemplateName"] = oo.mibTemplatePath
templateMap["TemplateCreated"] = currentTime.Format("2006-01-02 15:04:05.000000")
firstLevelMap := oo.pOnuDB.CommonMeDb.MeDb
for firstLevelKey, firstLevelValue := range firstLevelMap {
logger.Debugw(ctx, "MibSync - MibTemplate - firstLevelKey", log.Fields{"firstLevelKey": firstLevelKey})
classID := strconv.Itoa(int(firstLevelKey))
secondLevelMap := make(map[string]interface{})
for secondLevelKey, secondLevelValue := range firstLevelValue {
// ManagedEntityId is already key of secondLevelMap - remove this redundant attribute from secondLevelValue
delete(secondLevelValue, cmn.CGenericManagedEntityIDName)
thirdLevelMap := make(map[string]interface{})
entityID := strconv.Itoa(int(secondLevelKey))
thirdLevelMap["Attributes"] = secondLevelValue
secondLevelMap[entityID] = thirdLevelMap
if classID == "6" || classID == "256" {
forthLevelMap := map[string]interface{}(thirdLevelMap["Attributes"].(me.AttributeValueMap))
delete(forthLevelMap, "SerialNumber")
forthLevelMap["SerialNumber"] = "%SERIAL_NUMBER%"
}
if classID == "134" {
forthLevelMap := map[string]interface{}(thirdLevelMap["Attributes"].(me.AttributeValueMap))
delete(forthLevelMap, "MacAddress")
forthLevelMap["MacAddress"] = "%MAC_ADDRESS%"
}
}
templateMap[classID] = secondLevelMap
}
unknownMeAndAttribMap := oo.pOnuDB.CommonMeDb.UnknownMeAndAttribDb
for unknownMeAndAttribMapKey := range unknownMeAndAttribMap {
templateMap[string(unknownMeAndAttribMapKey)] = unknownMeAndAttribMap[unknownMeAndAttribMapKey]
}
mibTemplate, err := json.Marshal(&templateMap)
if err != nil {
logger.Errorw(ctx, "MibSync - MibTemplate - Failed to marshal mibTemplate", log.Fields{"error": err, "device-id": oo.deviceID})
oo.pOpenOnuAc.SetMibTemplatesGenerated(oo.mibTemplatePath, false)
return err
}
err = oo.mibTemplateKVStore.Put(log.WithSpanFromContext(context.TODO(), ctx), oo.mibTemplatePath, string(mibTemplate))
if err != nil {
logger.Errorw(ctx, "MibSync - MibTemplate - Failed to store template in etcd", log.Fields{"error": err, "device-id": oo.deviceID})
oo.pOpenOnuAc.SetMibTemplatesGenerated(oo.mibTemplatePath, false)
return err
}
logger.Debugw(ctx, "MibSync - MibTemplate - Stored the template to etcd", log.Fields{"device-id": oo.deviceID})
return nil
}
func (oo *OnuDeviceEntry) requestMdsValue(ctx context.Context) {
logger.Debugw(ctx, "Request MDS value", log.Fields{"device-id": oo.deviceID})
requestedAttributes := me.AttributeValueMap{me.OnuData_MibDataSync: ""}
meInstance, err := oo.PDevOmciCC.SendGetMe(log.WithSpanFromContext(context.TODO(), ctx),
me.OnuDataClassID, cmn.OnuDataMeID, requestedAttributes, oo.baseDeviceHandler.GetOmciTimeout(), true,
oo.PMibUploadFsm.CommChan, oo.GetPersIsExtOmciSupported())
//accept also nil as (error) return value for writing to LastTx
// - this avoids misinterpretation of new received OMCI messages
if err != nil {
logger.Errorw(ctx, "ONUData get failed, aborting MibSync FSM!", log.Fields{"device-id": oo.deviceID})
pMibUlFsm := oo.PMibUploadFsm
if pMibUlFsm != nil {
//nolint:unparam
go func(a_pAFsm *cmn.AdapterFsm) {
_ = oo.PMibUploadFsm.PFsm.Event(UlEvStop)
}(pMibUlFsm)
}
return
}
oo.mutexLastTxParamStruct.Lock()
oo.lastTxParamStruct.lastTxMessageType = omci.GetRequestType
oo.lastTxParamStruct.pLastTxMeInstance = meInstance
oo.lastTxParamStruct.repeatCount = 0
oo.mutexLastTxParamStruct.Unlock()
}
func (oo *OnuDeviceEntry) checkMdsValue(ctx context.Context, mibDataSyncOnu uint8) {
oo.MutexPersOnuConfig.RLock()
logger.Debugw(ctx, "MibSync FSM - GetResponse Data for Onu-Data - MibDataSync", log.Fields{"device-id": oo.deviceID,
"mibDataSyncOnu": mibDataSyncOnu, "PersMibDataSyncAdpt": oo.SOnuPersistentData.PersMibDataSyncAdpt})
mdsValuesAreEqual := oo.SOnuPersistentData.PersMibDataSyncAdpt == mibDataSyncOnu
oo.MutexPersOnuConfig.RUnlock()
if oo.PMibUploadFsm.PFsm.Is(UlStAuditing) {
if mdsValuesAreEqual {
logger.Debugw(ctx, "MibSync FSM - mib audit - MDS check ok", log.Fields{"device-id": oo.deviceID})
_ = oo.PMibUploadFsm.PFsm.Event(UlEvSuccess)
} else {
logger.Warnw(ctx, "MibSync FSM - mib audit - MDS check failed for the first time!", log.Fields{"device-id": oo.deviceID})
_ = oo.PMibUploadFsm.PFsm.Event(UlEvMismatch)
}
} else if oo.PMibUploadFsm.PFsm.Is(UlStReAuditing) {
if mdsValuesAreEqual {
logger.Debugw(ctx, "MibSync FSM - mib reaudit - MDS check ok", log.Fields{"device-id": oo.deviceID})
_ = oo.PMibUploadFsm.PFsm.Event(UlEvSuccess)
} else {
logger.Errorw(ctx, "MibSync FSM - mib reaudit - MDS check failed for the second time - send ONU device event and reconcile!",
log.Fields{"device-id": oo.deviceID})
oo.SendOnuDeviceEvent(ctx, cmn.OnuMibAuditFailureMds, cmn.OnuMibAuditFailureMdsDesc)
// To reconcile ONU with active adapter later on, we have to retrieve TP instances from parent adapter.
// In the present use case inconsistencies between TP pathes stored in kv store and TP instances retrieved
// should not occur. Nevertheless, the respective code is inserted to catch the unlikely case.
if !oo.getAllStoredTpInstFromParentAdapter(ctx) {
logger.Debugw(ctx, "MibSync FSM - mib reaudit - inconsistencies between TP pathes stored in kv and parent adapter instances",
log.Fields{"device-id": oo.deviceID})
oo.baseDeviceHandler.SetReconcilingReasonUpdate(true)
go func() {
if err := oo.baseDeviceHandler.StorePersistentData(ctx); err != nil {
logger.Warnw(ctx,
"MibSync FSM - mib reaudit - store persistent data error - continue for now as there will be additional write attempts",
log.Fields{"device-id": oo.deviceID, "err": err})
}
}()
}
_ = oo.PMibUploadFsm.PFsm.Event(UlEvMismatch)
}
} else if oo.PMibUploadFsm.PFsm.Is(UlStExaminingMds) {
if mdsValuesAreEqual && mibDataSyncOnu != 0 {
logger.Debugw(ctx, "MibSync FSM - MDS examination ok", log.Fields{"device-id": oo.deviceID})
_ = oo.PMibUploadFsm.PFsm.Event(UlEvSuccess)
} else {
logger.Debugw(ctx, "MibSync FSM - MDS examination failed - new provisioning", log.Fields{"device-id": oo.deviceID})
_ = oo.PMibUploadFsm.PFsm.Event(UlEvMismatch)
}
} else {
logger.Warnw(ctx, "wrong state for MDS evaluation!", log.Fields{"state": oo.PMibUploadFsm.PFsm.Current(), "device-id": oo.deviceID})
}
}
// GetActiveImageMeID returns the Omci MeId of the active ONU image together with error code for validity
func (oo *OnuDeviceEntry) GetActiveImageMeID(ctx context.Context) (uint16, error) {
oo.mutexOnuSwImageIndications.RLock()
if oo.onuSwImageIndications.ActiveEntityEntry.Valid {
value := oo.onuSwImageIndications.ActiveEntityEntry.EntityID
oo.mutexOnuSwImageIndications.RUnlock()
return value, nil
}
oo.mutexOnuSwImageIndications.RUnlock()
return 0xFFFF, fmt.Errorf("no valid active image found: %s", oo.deviceID)
}
// GetInactiveImageMeID returns the Omci MeId of the inactive ONU image together with error code for validity
func (oo *OnuDeviceEntry) GetInactiveImageMeID(ctx context.Context) (uint16, error) {
oo.mutexOnuSwImageIndications.RLock()
if oo.onuSwImageIndications.InActiveEntityEntry.Valid {
value := oo.onuSwImageIndications.InActiveEntityEntry.EntityID
oo.mutexOnuSwImageIndications.RUnlock()
return value, nil
}
oo.mutexOnuSwImageIndications.RUnlock()
return 0xFFFF, fmt.Errorf("no valid inactive image found: %s", oo.deviceID)
}
// IsImageToBeCommitted returns true if the active image is still uncommitted
func (oo *OnuDeviceEntry) IsImageToBeCommitted(ctx context.Context, aImageID uint16) bool {
oo.mutexOnuSwImageIndications.RLock()
if oo.onuSwImageIndications.ActiveEntityEntry.Valid {
if oo.onuSwImageIndications.ActiveEntityEntry.EntityID == aImageID {
if oo.onuSwImageIndications.ActiveEntityEntry.IsCommitted == cmn.SwIsUncommitted {
oo.mutexOnuSwImageIndications.RUnlock()
return true
}
}
}
oo.mutexOnuSwImageIndications.RUnlock()
return false //all other case are treated as 'nothing to commit
}
func (oo *OnuDeviceEntry) getMibFromTemplate(ctx context.Context) bool {
oo.mibTemplatePath = oo.buildMibTemplatePath()
logger.Debugw(ctx, "MibSync FSM - get Mib from template", log.Fields{"path": fmt.Sprintf("%s/%s", cBasePathMibTemplateKvStore, oo.mibTemplatePath),
"device-id": oo.deviceID})
restoredFromMibTemplate := false
oo.pOpenOnuAc.LockMutexMibTemplateGenerated()
defer oo.pOpenOnuAc.UnlockMutexMibTemplateGenerated()
if meDbValue, ok := oo.pOpenOnuAc.FetchEntryFromMibDatabaseMap(ctx, oo.mibTemplatePath); ok {
logger.Infow(ctx, "Found MIB common DB Instance , copy and use", log.Fields{"path": oo.mibTemplatePath, "device-id": oo.deviceID})
oo.pOnuDB.CommonMeDb = meDbValue
oo.updateOnuSpecificEntries(ctx)
restoredFromMibTemplate = true
} else {
//Create a common ME MIB Instance as it doesn't prior exists.
Value, err := oo.mibTemplateKVStore.Get(log.WithSpanFromContext(context.TODO(), ctx), oo.mibTemplatePath)
//Unmarshal the MIB template and create the entry in the ONU Common Device DB
if err == nil {
if Value != nil {
oo.processMibTemplate(ctx, Value)
restoredFromMibTemplate = true
} else {
logger.Infow(ctx, "No MIB template found", log.Fields{"path": oo.mibTemplatePath, "device-id": oo.deviceID})
}
} else {
logger.Errorw(ctx, "Get from kvstore operation failed for path",
log.Fields{"path": oo.mibTemplatePath, "device-id": oo.deviceID})
}
}
return restoredFromMibTemplate
}
func (oo *OnuDeviceEntry) getAllStoredTpInstFromParentAdapter(ctx context.Context) bool {
allTpInstPresent := true
oo.MutexPersOnuConfig.Lock()
oo.MutexReconciledTpInstances.Lock()
for indexUni, uniData := range oo.SOnuPersistentData.PersUniConfig {
uniID := uniData.PersUniID
oo.ReconciledTpInstances[uniID] = make(map[uint8]inter_adapter.TechProfileDownloadMessage)
for tpID, tpPath := range uniData.PersTpPathMap {
if tpPath != "" {
logger.Infow(ctx, "Starting retrieval for TechProfileInstance", log.Fields{
"uniID": uniID, "tpID": tpID, "tpPath": tpPath, "device-id": oo.deviceID,
})
// Attempt the initial call before entering the retry loop
iaTechTpInst, err := oo.baseDeviceHandler.GetTechProfileInstanceFromParentAdapter(ctx, uniID, tpPath)
if err != nil {
var ticker *time.Ticker
// Log the initial failure and proceed to the retry mechanism
logger.Warnw(ctx, "Initial TechProfileInstance API call failed, entering retry mechanism", log.Fields{
"tp-id": tpID, "tpPath": tpPath, "uni-id": uniID, "device-id": oo.deviceID, "err": err,
})
// Retry logic
/*
We are retrying here because the OLT adapter may not have been up and reachable
at the time of the initial attempt. This prevents the ONU adapter from fetching
the TechProfile.
This issue might occur when both the ONU and OLT adapters are restarted simultaneously,
causing a temporary mismatch in their availability. The retry logic ensures that
the ONU adapter periodically attempts to fetch the TechProfile, allowing time for the
OLT adapter to come up and become operational,and once the OLT adaptor is up with this retry attempts we can fetch the tech profile.This helps prevent the reconciliation
process from failing prematurely due to transient unavailability of the OLT adapter.
*/
for tpRetryAttempt := initialRetryAttempt; tpRetryAttempt <= maxRetries; tpRetryAttempt++ {
ticker = time.NewTicker(retryDelay)
select {
case _, ok := <-oo.baseDeviceHandler.GetDeviceDeleteCommChan(ctx):
if !ok {
logger.Warnw(ctx, "Device deletion channel closed - aborting retry", log.Fields{"device-id": oo.deviceID})
ticker.Stop()
return false
}
case <-ticker.C:
iaTechTpInst, err = oo.baseDeviceHandler.GetTechProfileInstanceFromParentAdapter(ctx, uniID, tpPath)
if err != nil {
logger.Warnw(ctx, "TechProfileInstance API will be retried", log.Fields{
"tp-id": tpID, "tpPath": tpPath, "uni-id": uniID,
"device-id": oo.deviceID, "err": err, "retry": tpRetryAttempt,
"totalRetries": maxRetries,
})
continue
}
logger.Info(ctx, "Successfully retrieved TechProfileInstance after retry", log.Fields{
"retry": tpRetryAttempt, "device-id": oo.deviceID,
})
}
if err == nil {
break // Exit the retry loop upon success
}
}
}
if err == nil && iaTechTpInst != nil {
logger.Debugw(ctx, "reconciling - store Tp instance", log.Fields{"uniID": uniID, "tpID": tpID,
"*iaTechTpInst": iaTechTpInst, "device-id": oo.deviceID})
oo.ReconciledTpInstances[uniID][tpID] = *iaTechTpInst
} else {
// During the absence of the ONU adapter there seem to have been TP specific configurations!
// The no longer available TP and the associated flows must be deleted from the ONU KV store
// and after a MIB reset a new reconciling attempt with OMCI configuration must be started.
allTpInstPresent = false
logger.Infow(ctx, "reconciling - can't get tp instance - delete tp and associated flows",
log.Fields{"tp-id": tpID, "tpPath": tpPath, "uni-id": uniID, "device-id": oo.deviceID, "err": err})
delete(oo.SOnuPersistentData.PersUniConfig[indexUni].PersTpPathMap, tpID)
flowSlice := oo.SOnuPersistentData.PersUniConfig[indexUni].PersFlowParams
for indexFlow, flowData := range flowSlice {
if flowData.VlanRuleParams.TpID == tpID {
if len(flowSlice) == 1 {
flowSlice = []cmn.UniVlanFlowParams{}
} else {
flowSlice = append(flowSlice[:indexFlow], flowSlice[indexFlow+1:]...)
}
oo.SOnuPersistentData.PersUniConfig[indexUni].PersFlowParams = flowSlice
}
}
}
}
}
}
oo.MutexReconciledTpInstances.Unlock()
oo.MutexPersOnuConfig.Unlock()
return allTpInstPresent
}
// CancelProcessing terminates potentially running reconciling processes and stops the FSM
func (oo *OnuDeviceEntry) CancelProcessing(ctx context.Context) {
logger.Debugw(ctx, "CancelProcessing entered", log.Fields{"device-id": oo.deviceID})
if oo.isReconcilingFlows() {
oo.SendChReconcilingFlowsFinished(ctx, false)
}
//the MibSync FSM might be active all the ONU-active time,
// hence it must be stopped unconditionally
oo.mutexMibSyncMsgProcessorRunning.RLock()
defer oo.mutexMibSyncMsgProcessorRunning.RUnlock()
if oo.mibSyncMsgProcessorRunning {
pMibUlFsm := oo.PMibUploadFsm
if pMibUlFsm != nil {
// abort running message processing
fsmAbortMsg := cmn.Message{
Type: cmn.TestMsg,
Data: cmn.TestMessage{
TestMessageVal: cmn.AbortMessageProcessing,
},
}
pMibUlFsm.CommChan <- fsmAbortMsg
_ = pMibUlFsm.PFsm.Event(UlEvStop)
}
}
}
// Updates Serial Number and MAC Address in the database
func (oo *OnuDeviceEntry) updateOnuSpecificEntries(ctx context.Context) {
knownAttributeMEDb := oo.pOnuDB.CommonMeDb.MeDb
for firstLevelKey, firstLevelValue := range knownAttributeMEDb {
classID := strconv.Itoa(int(firstLevelKey))
for secondLevelKey, secondLevelValue := range firstLevelValue {
switch classID {
case "6", "256":
oo.updateAttribute(ctx, "SerialNumber", secondLevelValue, firstLevelKey, secondLevelKey, oo.SOnuPersistentData.PersSerialNumber)
case "134":
oo.updateAttribute(ctx, "MacAddress", secondLevelValue, firstLevelKey, secondLevelKey, oo.SOnuPersistentData.PersMacAddress)
}
}
}
}
// Updates a specific attribute in the MIB database
func (oo *OnuDeviceEntry) updateAttribute(ctx context.Context, attributeName string, attributesMap me.AttributeValueMap, classID me.ClassID, entityID uint16, newValue interface{}) {
if _, exists := attributesMap[attributeName]; exists {
logger.Infow(ctx, "Updating "+attributeName, log.Fields{"classID": strconv.Itoa(int(classID)), "oldValue": attributesMap[attributeName], "newValue": newValue})
attributeCopy := make(me.AttributeValueMap)
for k, v := range attributesMap {
attributeCopy[k] = v
}
attributeCopy[attributeName] = newValue
oo.pOnuDB.PutOnuSpeficMe(ctx, classID, entityID, attributeCopy)
} else {
logger.Warnw(ctx, attributeName+" key not found", log.Fields{"classID": strconv.Itoa(int(classID))})
}
}
// Processes the MIB template by replacing tokens and unmarshaling it
func (oo *OnuDeviceEntry) processMibTemplate(ctx context.Context, value *kvstore.KVPair) {
mibTmpString, _ := kvstore.ToString(value.Value)
mibTmpString2 := strings.ReplaceAll(mibTmpString, "\x00", "")
mibTmpBytes := []byte(mibTmpString2)
logger.Debugf(ctx, "MibSync FSM - Mib template tokens swapped out: %s", mibTmpBytes)
var firstLevelMap map[string]interface{}
if err := json.Unmarshal(mibTmpBytes, &firstLevelMap); err != nil {
logger.Errorw(ctx, "MibSync FSM - Failed to unmarshal template", log.Fields{"error": err, "device-id": oo.deviceID})
return
}
cmnMEDbValue, _ := oo.pOpenOnuAc.CreateEntryAtMibDatabaseMap(ctx, oo.mibTemplatePath)
oo.populateMibDatabase(ctx, cmnMEDbValue, firstLevelMap)
cmnMEDbValue.MIBUploadStatus = devdb.Completed
oo.pOnuDB.CommonMeDb = cmnMEDbValue
}
// Populates the MIB database with parsed data
func (oo *OnuDeviceEntry) populateMibDatabase(ctx context.Context, cmnMEDbValue *devdb.OnuCmnMEDB, firstLevelMap map[string]interface{}) {
cmnMEDbValue.MeDbLock.Lock()
defer cmnMEDbValue.MeDbLock.Unlock()
logger.Infow(ctx, "Populating MIbDatabase with the template information ", log.Fields{"device-id": oo.deviceID})
for firstLevelKey, firstLevelValue := range firstLevelMap {
if uint16ValidNumber, err := strconv.ParseUint(firstLevelKey, 10, 16); err == nil {
meClassID := me.ClassID(uint16ValidNumber)
if isSupportedClassID(meClassID) {
secondLevelMap := firstLevelValue.(map[string]interface{})
for secondLevelKey, secondLevelValue := range secondLevelMap {
if uint16ValidNumber, err := strconv.ParseUint(secondLevelKey, 10, 16); err == nil {
meEntityID := uint16(uint16ValidNumber)
thirdLevelMap := secondLevelValue.(map[string]interface{})
if attributes, exists := thirdLevelMap["Attributes"].(map[string]interface{}); exists {
if _, found := cmnMEDbValue.MeDb[meClassID]; !found {
cmnMEDbValue.MeDb[meClassID] = make(map[uint16]me.AttributeValueMap)
}
if _, found := cmnMEDbValue.MeDb[meClassID][meEntityID]; !found {
cmnMEDbValue.MeDb[meClassID][meEntityID] = make(me.AttributeValueMap)
}
for attrKey, attrValue := range attributes {
cmnMEDbValue.MeDb[meClassID][meEntityID][attrKey] = attrValue
}
}
}
}
}
}
}
}