[VOL-4532] Remove duplicate maps in FlowManager and ResourceManager
Change-Id: I0a0fee7dbd3b3a25f2f0eee062bf565ba3212df3
diff --git a/internal/pkg/core/device_handler.go b/internal/pkg/core/device_handler.go
index a8c33f0..c17d92e 100644
--- a/internal/pkg/core/device_handler.go
+++ b/internal/pkg/core/device_handler.go
@@ -1052,7 +1052,7 @@
}
logger.Debugw(ctx, "publish-pon-metrics", log.Fields{"pon-port": port.Label})
- onuGemInfoLst := dh.flowMgr[intfID].getOnuGemInfoList(ctx)
+ onuGemInfoLst := dh.resourceMgr[intfID].GetOnuGemInfoList(ctx)
if len(onuGemInfoLst) > 0 {
go dh.portStats.collectOnuAndGemStats(ctx, onuGemInfoLst)
}
@@ -1333,7 +1333,7 @@
func (dh *DeviceHandler) activateONU(ctx context.Context, intfID uint32, onuID int64, serialNum *oop.SerialNumber, serialNumber string) error {
logger.Debugw(ctx, "activate-onu", log.Fields{"intf-id": intfID, "onu-id": onuID, "serialNum": serialNum, "serialNumber": serialNumber, "device-id": dh.device.Id, "OmccEncryption": dh.openOLT.config.OmccEncryption})
- if err := dh.flowMgr[intfID].AddOnuInfoToFlowMgrCacheAndKvStore(ctx, intfID, uint32(onuID), serialNumber); err != nil {
+ if err := dh.resourceMgr[intfID].AddNewOnuGemInfoToCacheAndKvStore(ctx, intfID, uint32(onuID), serialNumber); err != nil {
return olterrors.NewErrAdapter("onu-activate-failed", log.Fields{"onu": onuID, "intf-id": intfID}, err)
}
var pir uint32 = 1000000
@@ -2037,7 +2037,7 @@
var ponPort uint32
for ponPort = 0; ponPort < dh.totalPonPorts; ponPort++ {
var err error
- onuGemData := dh.flowMgr[ponPort].getOnuGemInfoList(ctx)
+ onuGemData := dh.resourceMgr[ponPort].GetOnuGemInfoList(ctx)
for i, onu := range onuGemData {
logger.Debugw(ctx, "onu-data", log.Fields{"onu": onu})
if err = dh.clearUNIData(ctx, &onuGemData[i]); err != nil {
@@ -2487,7 +2487,7 @@
for _, gem := range onuGem.GemPorts {
_ = dh.resourceMgr[intfID].DeleteFlowIDsForGem(ctx, intfID, gem)
}
- if err := dh.flowMgr[intfID].RemoveOnuInfoFromFlowMgrCacheAndKvStore(ctx, intfID, onuID); err != nil {
+ if err := dh.resourceMgr[intfID].DelOnuGemInfo(ctx, intfID, onuID); err != nil {
logger.Warnw(ctx, "persistence-update-onu-gem-info-failed", log.Fields{
"intf-id": intfID,
"onu-device": onu,
diff --git a/internal/pkg/core/device_handler_test.go b/internal/pkg/core/device_handler_test.go
index 9c5961c..867f821 100644
--- a/internal/pkg/core/device_handler_test.go
+++ b/internal/pkg/core/device_handler_test.go
@@ -233,9 +233,7 @@
dh.flowMgr[i].grpMgr = dh.groupMgr
dh.flowMgr[i].resourceMgr = dh.resourceMgr[i]
dh.flowMgr[i].techprofile = mocks.MockTechProfile{}
- dh.flowMgr[i].gemToFlowIDs = make(map[uint32][]uint64)
dh.flowMgr[i].packetInGemPort = make(map[resourcemanager.PacketInInfoKey]uint32)
- dh.flowMgr[i].flowIDToGems = make(map[uint64][]uint32)
dh.resourceMgr[i].TechprofileRef = dh.flowMgr[i].techprofile
@@ -253,7 +251,6 @@
dh.flowMgr[i].flowHandlerRoutineActive[j] = true
go dh.flowMgr[i].perOnuFlowHandlerRoutine(j, dh.flowMgr[i].incomingFlows[j], dh.flowMgr[i].stopFlowHandlerRoutine[j])
}
- dh.flowMgr[i].onuGemInfoMap = make(map[uint32]*resourcemanager.OnuGemInfo)
}
dh.Client = &mocks.MockOpenoltClient{}
dh.eventMgr = &OpenOltEventMgr{eventProxy: &mocks.MockEventProxy{}, handler: dh}
diff --git a/internal/pkg/core/openolt_flowmgr.go b/internal/pkg/core/openolt_flowmgr.go
index 818b167..81f7fcb 100644
--- a/internal/pkg/core/openolt_flowmgr.go
+++ b/internal/pkg/core/openolt_flowmgr.go
@@ -204,20 +204,9 @@
grpMgr *OpenOltGroupMgr
resourceMgr *rsrcMgr.OpenOltResourceMgr
- gemToFlowIDs map[uint32][]uint64 // gem port id to flow ids
- gemToFlowIDsKey sync.RWMutex // lock to be used to access the gemToFlowIDs map
-
packetInGemPort map[rsrcMgr.PacketInInfoKey]uint32 //packet in gem port local cache
packetInGemPortLock sync.RWMutex
- // TODO create a type rsrcMgr.OnuGemInfos to be used instead of []rsrcMgr.OnuGemInfo
- onuGemInfoMap map[uint32]*rsrcMgr.OnuGemInfo //onu, gem and uni info local cache -> map of onuID to OnuGemInfo
- // We need to have a global lock on the onuGemInfo map
- onuGemInfoLock sync.RWMutex
-
- flowIDToGems map[uint64][]uint32
- flowIDToGemsLock sync.RWMutex
-
// Slice of channels. Each channel in slice, index by ONU ID, queues flows per ONU.
// A go routine per ONU, waits on the unique channel (indexed by ONU ID) for incoming flows (add/remove)
incomingFlows []chan flowControlBlock
@@ -239,9 +228,7 @@
logger.Errorw(ctx, "error-while-populating-tech-profile-mgr", log.Fields{"err": err})
return nil
}
- flowMgr.gemToFlowIDs = make(map[uint32][]uint64)
flowMgr.packetInGemPort = make(map[rsrcMgr.PacketInInfoKey]uint32)
- flowMgr.flowIDToGems = make(map[uint64][]uint32)
// Create a slice of buffered channels for handling concurrent flows per ONU.
// The additional entry (+1) is to handle the NNI trap flows on a separate channel from individual ONUs channel
@@ -257,20 +244,6 @@
flowMgr.flowHandlerRoutineActive[i] = true
go flowMgr.perOnuFlowHandlerRoutine(i, flowMgr.incomingFlows[i], flowMgr.stopFlowHandlerRoutine[i])
}
- flowMgr.onuGemInfoMap = make(map[uint32]*rsrcMgr.OnuGemInfo)
- //Load the onugem info cache from kv store on flowmanager start
- onuIDStart := flowMgr.deviceHandler.deviceInfo.OnuIdStart
- onuIDEnd := flowMgr.deviceHandler.deviceInfo.OnuIdEnd
- for onuID := onuIDStart; onuID <= onuIDEnd; onuID++ {
- // check for a valid serial number in onuGem as GetOnuGemInfo can return nil error in case of nothing found in the path.
- onugem, err := rMgr.GetOnuGemInfo(ctx, ponPortIdx, onuID)
- if err == nil && onugem != nil && onugem.SerialNumber != "" {
- flowMgr.onuGemInfoMap[onuID] = onugem
- }
- }
-
- //Load flowID list per gem map And gemIDs per flow per interface from the kvstore.
- flowMgr.loadFlowIDsForGemAndGemIDsForFlow(ctx)
//load interface to multicast queue map from kv store
flowMgr.grpMgr.LoadInterfaceToMulticastQueueMap(ctx)
@@ -281,11 +254,11 @@
func (f *OpenOltFlowMgr) registerFlow(ctx context.Context, flowFromCore *ofp.OfpFlowStats, deviceFlow *openoltpb2.Flow) error {
if !deviceFlow.ReplicateFlow && deviceFlow.GemportId > 0 {
// Flow is not replicated in this case, we need to register the flow for a single gem-port
- return f.registerFlowIDForGemAndGemIDForFlow(ctx, uint32(deviceFlow.AccessIntfId), uint32(deviceFlow.GemportId), flowFromCore)
+ return f.resourceMgr.RegisterFlowIDForGem(ctx, uint32(deviceFlow.AccessIntfId), uint32(deviceFlow.GemportId), flowFromCore)
} else if deviceFlow.ReplicateFlow && len(deviceFlow.PbitToGemport) > 0 {
// Flow is replicated in this case. We need to register the flow for all the gem-ports it is replicated to.
for _, gemPort := range deviceFlow.PbitToGemport {
- if err := f.registerFlowIDForGemAndGemIDForFlow(ctx, uint32(deviceFlow.AccessIntfId), gemPort, flowFromCore); err != nil {
+ if err := f.resourceMgr.RegisterFlowIDForGem(ctx, uint32(deviceFlow.AccessIntfId), gemPort, flowFromCore); err != nil {
return err
}
}
@@ -293,31 +266,6 @@
return nil
}
-func (f *OpenOltFlowMgr) registerFlowIDForGemAndGemIDForFlow(ctx context.Context, accessIntfID uint32, gemPortID uint32, flowFromCore *ofp.OfpFlowStats) error {
- // update gem->flows map
- f.gemToFlowIDsKey.Lock()
- flowIDList, ok := f.gemToFlowIDs[gemPortID]
- if !ok {
- flowIDList = []uint64{flowFromCore.Id}
- } else {
- flowIDList = appendUnique64bit(flowIDList, flowFromCore.Id)
- }
- f.gemToFlowIDs[gemPortID] = flowIDList
- f.gemToFlowIDsKey.Unlock()
-
- // update flow->gems map
- f.flowIDToGemsLock.Lock()
- if _, ok := f.flowIDToGems[flowFromCore.Id]; !ok {
- f.flowIDToGems[flowFromCore.Id] = []uint32{gemPortID}
- } else {
- f.flowIDToGems[flowFromCore.Id] = appendUnique32bit(f.flowIDToGems[flowFromCore.Id], gemPortID)
- }
- f.flowIDToGemsLock.Unlock()
-
- // update the flowids for a gem to the KVstore
- return f.resourceMgr.UpdateFlowIDsForGem(ctx, accessIntfID, gemPortID, flowIDList)
-}
-
func (f *OpenOltFlowMgr) processAddFlow(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, portNo uint32,
classifierInfo map[string]interface{}, actionInfo map[string]interface{}, flow *ofp.OfpFlowStats, TpID uint32,
UsMeterID uint32, DsMeterID uint32, flowMetadata *ofp.FlowMetadata) error {
@@ -985,15 +933,17 @@
"device-id": f.deviceHandler.device.Id})
/* Update the allocated alloc_id and gem_port_id for the ONU/UNI to KV store */
if err := f.resourceMgr.UpdateAllocIdsForOnu(ctx, intfID, onuID, uniID, allocID); err != nil {
- logger.Errorw(ctx, "error-while-uploading-allocid-to-kv-store", log.Fields{"device-id": f.deviceHandler.device.Id})
+ logger.Errorw(ctx, "error-while-uploading-allocid-to-kv-store", log.Fields{"device-id": f.deviceHandler.device.Id, "onuID": onuID, "allocID": allocID})
}
if err := f.resourceMgr.UpdateGEMPortIDsForOnu(ctx, intfID, onuID, uniID, gemPortIDs); err != nil {
- logger.Errorw(ctx, "error-while-uploading-gemports-to-kv-store", log.Fields{"device-id": f.deviceHandler.device.Id})
+ logger.Errorw(ctx, "error-while-uploading-gemports-to-kv-store", log.Fields{"device-id": f.deviceHandler.device.Id, "onuID": onuID, "gemPort": gemPortIDs})
}
logger.Infow(ctx, "stored-tconts-and-gem-into-kv-store-successfully", log.Fields{"device-id": f.deviceHandler.device.Id})
for _, gemPort := range gemPortIDs {
- f.addGemPortToOnuInfoMap(ctx, intfID, onuID, gemPort)
+ if err := f.resourceMgr.AddGemToOnuGemInfo(ctx, intfID, onuID, gemPort); err != nil {
+ logger.Errorw(ctx, "error-while-uploading-onugeminfos-to-kv-store", log.Fields{"device-id": f.deviceHandler.device.Id, "onuID": onuID, "gemPort": gemPort})
+ }
}
}
@@ -1911,48 +1861,6 @@
return nil
}
-// Once the gemport is released for a given onu, it also has to be cleared from local cache
-// which was used for deriving the gemport->logicalPortNo during packet-in.
-// Otherwise stale info continues to exist after gemport is freed and wrong logicalPortNo
-// is conveyed to ONOS during packet-in OF message.
-func (f *OpenOltFlowMgr) deleteGemPortFromLocalCache(ctx context.Context, intfID uint32, onuID uint32, gemPortID uint32) {
- logger.Infow(ctx, "deleting-gem-from-local-cache",
- log.Fields{
- "gem-port-id": gemPortID,
- "intf-id": intfID,
- "onu-id": onuID,
- "device-id": f.deviceHandler.device.Id})
- f.onuGemInfoLock.RLock()
- onugem, ok := f.onuGemInfoMap[onuID]
- f.onuGemInfoLock.RUnlock()
- if !ok {
- logger.Warnw(ctx, "onu gem info already cleared from cache", log.Fields{
- "gem-port-id": gemPortID,
- "intf-id": intfID,
- "onu-id": onuID,
- "device-id": f.deviceHandler.device.Id})
- return
- }
-deleteLoop:
- for j, gem := range onugem.GemPorts {
- // If the gemport is found, delete it from local cache.
- if gem == gemPortID {
- onugem.GemPorts = append(onugem.GemPorts[:j], onugem.GemPorts[j+1:]...)
- f.onuGemInfoLock.Lock()
- f.onuGemInfoMap[onuID] = onugem
- f.onuGemInfoLock.Unlock()
- logger.Infow(ctx, "removed-gemport-from-local-cache",
- log.Fields{
- "intf-id": intfID,
- "onu-id": onuID,
- "deletedgemport-id": gemPortID,
- "gemports": onugem.GemPorts,
- "device-id": f.deviceHandler.device.Id})
- break deleteLoop
- }
- }
-}
-
//clearResources clears pon resources in kv store and the device
// nolint: gocyclo
func (f *OpenOltFlowMgr) clearResources(ctx context.Context, intfID uint32, onuID int32, uniID int32,
@@ -1988,20 +1896,15 @@
case *tp_pb.TechProfileInstance:
for _, gemPort := range techprofileInst.UpstreamGemPortAttributeList {
gemPortID := gemPort.GemportId
- used := f.isGemPortUsedByAnotherFlow(gemPortID, flowID)
+ used := f.resourceMgr.IsGemPortUsedByAnotherFlow(gemPortID, flowID)
if used {
- f.gemToFlowIDsKey.RLock()
- flowIDs := f.gemToFlowIDs[gemPortID]
- f.gemToFlowIDsKey.RUnlock()
-
+ flowIDs, err := f.resourceMgr.GetFlowIDsForGem(ctx, intfID, gemPortID)
+ if err != nil {
+ return err
+ }
for i, flowIDinMap := range flowIDs {
if flowIDinMap == flowID {
flowIDs = append(flowIDs[:i], flowIDs[i+1:]...)
- f.gemToFlowIDsKey.Lock()
- f.gemToFlowIDs[gemPortID] = flowIDs
- f.gemToFlowIDsKey.Unlock()
- // everytime gemToFlowIDs cache is updated the same should be updated
- // in kv store by calling UpdateFlowIDsForGem
if err := f.resourceMgr.UpdateFlowIDsForGem(ctx, intfID, gemPortID, flowIDs); err != nil {
return err
}
@@ -2036,16 +1939,9 @@
for _, gemPort := range techprofileInst.UpstreamGemPortAttributeList {
gemPortID := gemPort.GemportId
- f.deleteGemPortFromLocalCache(ctx, intfID, uint32(onuID), gemPortID)
_ = f.resourceMgr.RemoveGemFromOnuGemInfo(ctx, intfID, uint32(onuID), gemPortID) // ignore error and proceed.
- if err := f.resourceMgr.DeleteFlowIDsForGem(ctx, intfID, gemPortID); err == nil {
- //everytime an entry is deleted from gemToFlowIDs cache, the same should be updated in kv as well
- // by calling DeleteFlowIDsForGem
- f.gemToFlowIDsKey.Lock()
- delete(f.gemToFlowIDs, gemPortID)
- f.gemToFlowIDsKey.Unlock()
- } else {
+ if err := f.resourceMgr.DeleteFlowIDsForGem(ctx, intfID, gemPortID); err != nil {
logger.Errorw(ctx, "error-removing-flow-ids-of-gem-port",
log.Fields{
"err": err,
@@ -2214,11 +2110,6 @@
return err
}
- // Delete the flow-id to gemport list entry from the map now the flow is deleted.
- f.flowIDToGemsLock.Lock()
- delete(f.flowIDToGems, flow.Id)
- f.flowIDToGemsLock.Unlock()
-
if err = f.clearResources(ctx, Intf, onuID, uniID, flow.Id, portNum, tpID, true); err != nil {
logger.Errorw(ctx, "failed-to-clear-resources-for-flow", log.Fields{
"flow-id": flow.Id,
@@ -2440,24 +2331,6 @@
}
f.resourceMgr.AddUniPortToOnuInfo(ctx, intfID, onuID, portNo)
- // also update flowmgr cache
- f.onuGemInfoLock.Lock()
- onugem, ok := f.onuGemInfoMap[onuID]
- if ok {
- found := false
- for _, uni := range onugem.UniPorts {
- if uni == portNo {
- found = true
- break
- }
- }
- if !found {
- onugem.UniPorts = append(onugem.UniPorts, portNo)
- f.onuGemInfoMap[onuID] = onugem
- logger.Infow(ctx, "added uni port to onugem cache", log.Fields{"uni": portNo})
- }
- }
- f.onuGemInfoLock.Unlock()
tpID, err := getTpIDFromFlow(ctx, flow)
if err != nil {
@@ -2596,118 +2469,6 @@
return nil
}
-//AddOnuInfoToFlowMgrCacheAndKvStore function adds onu info to cache and kvstore
-func (f *OpenOltFlowMgr) AddOnuInfoToFlowMgrCacheAndKvStore(ctx context.Context, intfID uint32, onuID uint32, serialNum string) error {
-
- f.onuGemInfoLock.RLock()
- _, ok := f.onuGemInfoMap[onuID]
- f.onuGemInfoLock.RUnlock()
- // If the ONU already exists in onuGemInfo list, nothing to do
- if ok {
- logger.Debugw(ctx, "onu-id-already-exists-in-cache",
- log.Fields{"onuID": onuID,
- "serialNum": serialNum})
- return nil
- }
-
- onuGemInfo := rsrcMgr.OnuGemInfo{OnuID: onuID, SerialNumber: serialNum, IntfID: intfID}
- f.onuGemInfoLock.Lock()
- f.onuGemInfoMap[onuID] = &onuGemInfo
- f.onuGemInfoLock.Unlock()
- if err := f.resourceMgr.AddOnuGemInfo(ctx, intfID, onuID, onuGemInfo); err != nil {
- return err
- }
- logger.Infow(ctx, "added-onuinfo",
- log.Fields{
- "intf-id": intfID,
- "onu-id": onuID,
- "serial-num": serialNum,
- "onu": onuGemInfo,
- "device-id": f.deviceHandler.device.Id})
- return nil
-}
-
-//RemoveOnuInfoFromFlowMgrCacheAndKvStore function adds onu info to cache and kvstore
-func (f *OpenOltFlowMgr) RemoveOnuInfoFromFlowMgrCacheAndKvStore(ctx context.Context, intfID uint32, onuID uint32) error {
-
- f.onuGemInfoLock.Lock()
- delete(f.onuGemInfoMap, onuID)
- f.onuGemInfoLock.Unlock()
-
- if err := f.resourceMgr.DelOnuGemInfo(ctx, intfID, onuID); err != nil {
- return err
- }
- logger.Infow(ctx, "deleted-onuinfo",
- log.Fields{
- "intf-id": intfID,
- "onu-id": onuID,
- "device-id": f.deviceHandler.device.Id})
- return nil
-}
-
-//addGemPortToOnuInfoMap function adds GEMport to ONU map
-func (f *OpenOltFlowMgr) addGemPortToOnuInfoMap(ctx context.Context, intfID uint32, onuID uint32, gemPort uint32) {
-
- logger.Infow(ctx, "adding-gem-to-onu-info-map",
- log.Fields{
- "gem-port-id": gemPort,
- "intf-id": intfID,
- "onu-id": onuID,
- "device-id": f.deviceHandler.device.Id})
- f.onuGemInfoLock.RLock()
- onugem, ok := f.onuGemInfoMap[onuID]
- f.onuGemInfoLock.RUnlock()
- if !ok {
- logger.Warnw(ctx, "onu gem info is missing", log.Fields{
- "gem-port-id": gemPort,
- "intf-id": intfID,
- "onu-id": onuID,
- "device-id": f.deviceHandler.device.Id})
- return
- }
-
- if onugem.OnuID == onuID {
- // check if gem already exists , else update the cache and kvstore
- for _, gem := range onugem.GemPorts {
- if gem == gemPort {
- logger.Debugw(ctx, "gem-already-in-cache-no-need-to-update-cache-and-kv-store",
- log.Fields{
- "gem": gemPort,
- "device-id": f.deviceHandler.device.Id})
- return
- }
- }
- onugem.GemPorts = append(onugem.GemPorts, gemPort)
- f.onuGemInfoLock.Lock()
- f.onuGemInfoMap[onuID] = onugem
- f.onuGemInfoLock.Unlock()
- logger.Debugw(ctx, "updated onu gem info from cache", log.Fields{"onugem": onugem})
- } else {
- logger.Warnw(ctx, "mismatched onu id", log.Fields{
- "gem-port-id": gemPort,
- "intf-id": intfID,
- "onu-id": onuID,
- "device-id": f.deviceHandler.device.Id})
- return
- }
- err := f.resourceMgr.AddGemToOnuGemInfo(ctx, intfID, onuID, gemPort)
- if err != nil {
- logger.Errorw(ctx, "failed-to-add-gem-to-onu",
- log.Fields{
- "intf-id": intfID,
- "onu-id": onuID,
- "gemPort": gemPort,
- "device-id": f.deviceHandler.device.Id})
- return
- }
- logger.Infow(ctx, "gem-added-to-onu-info-map",
- log.Fields{
- "gem-port-id": gemPort,
- "intf-id": intfID,
- "onu-id": onuID,
- "device-id": f.deviceHandler.device.Id})
-}
-
//GetLogicalPortFromPacketIn function computes logical port UNI/NNI port from packet-in indication and returns the same
func (f *OpenOltFlowMgr) GetLogicalPortFromPacketIn(ctx context.Context, packetIn *openoltpb2.PacketIndication) (uint32, error) {
var logicalPortNum uint32
@@ -3128,20 +2889,6 @@
return nil
}
-func (f *OpenOltFlowMgr) isGemPortUsedByAnotherFlow(gemPortID uint32, flowID uint64) bool {
- f.gemToFlowIDsKey.RLock()
- flowIDList := f.gemToFlowIDs[gemPortID]
- f.gemToFlowIDsKey.RUnlock()
- if len(flowIDList) > 0 {
- for _, id := range flowIDList {
- if flowID != id {
- return true
- }
- }
- }
- return false
-}
-
func (f *OpenOltFlowMgr) isAllocUsedByAnotherUNI(ctx context.Context, sq schedQueue) bool {
tpInst := sq.tpInst.(*tp_pb.TechProfileInstance)
if tpInst.InstanceControl.Onu == "single-instance" && sq.direction == tp_pb.Direction_UPSTREAM {
@@ -3357,15 +3104,6 @@
return uint32(TpID), nil
}
-func appendUnique64bit(slice []uint64, item uint64) []uint64 {
- for _, sliceElement := range slice {
- if sliceElement == item {
- return slice
- }
- }
- return append(slice, item)
-}
-
func appendUnique32bit(slice []uint32, item uint32) []uint32 {
for _, sliceElement := range slice {
if sliceElement == item {
@@ -3466,32 +3204,6 @@
return 0, 0, nil
}
-func (f *OpenOltFlowMgr) loadFlowIDsForGemAndGemIDsForFlow(ctx context.Context) {
- logger.Debug(ctx, "loadFlowIDsForGemAndGemIDsForFlow - start")
- f.onuGemInfoLock.RLock()
- f.gemToFlowIDsKey.Lock()
- f.flowIDToGemsLock.Lock()
- for _, og := range f.onuGemInfoMap {
- for _, gem := range og.GemPorts {
- flowIDs, err := f.resourceMgr.GetFlowIDsForGem(ctx, f.ponPortIdx, gem)
- if err == nil {
- f.gemToFlowIDs[gem] = flowIDs
- for _, flowID := range flowIDs {
- if _, ok := f.flowIDToGems[flowID]; !ok {
- f.flowIDToGems[flowID] = []uint32{gem}
- } else {
- f.flowIDToGems[flowID] = appendUnique32bit(f.flowIDToGems[flowID], gem)
- }
- }
- }
- }
- }
- f.flowIDToGemsLock.Unlock()
- f.gemToFlowIDsKey.Unlock()
- f.onuGemInfoLock.RUnlock()
- logger.Debug(ctx, "loadFlowIDsForGemAndGemIDsForFlow - end")
-}
-
//clearMulticastFlowFromResourceManager removes a multicast flow from the KV store and
// clears resources reserved for this multicast flow
func (f *OpenOltFlowMgr) clearMulticastFlowFromResourceManager(ctx context.Context, flow *ofp.OfpFlowStats) error {
@@ -3548,16 +3260,6 @@
}, nil
}
-func (f *OpenOltFlowMgr) getOnuGemInfoList(ctx context.Context) []rsrcMgr.OnuGemInfo {
- var onuGemInfoLst []rsrcMgr.OnuGemInfo
- f.onuGemInfoLock.RLock()
- defer f.onuGemInfoLock.RUnlock()
- for _, v := range f.onuGemInfoMap {
- onuGemInfoLst = append(onuGemInfoLst, *v)
- }
- return onuGemInfoLst
-}
-
// revertTechProfileInstance is called when CreateScheduler or CreateQueues request fails
func (f *OpenOltFlowMgr) revertTechProfileInstance(ctx context.Context, sq schedQueue) {
diff --git a/internal/pkg/core/openolt_flowmgr_test.go b/internal/pkg/core/openolt_flowmgr_test.go
index 5f64a71..a880297 100644
--- a/internal/pkg/core/openolt_flowmgr_test.go
+++ b/internal/pkg/core/openolt_flowmgr_test.go
@@ -21,8 +21,6 @@
"context"
"encoding/hex"
"fmt"
- "reflect"
- "strconv"
"sync"
"testing"
"time"
@@ -676,154 +674,6 @@
}
}
-func TestOpenOltFlowMgr_UpdateOnuInfo(t *testing.T) {
- ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
- defer cancel()
-
- wg := sync.WaitGroup{}
-
- intfCount := NumPonPorts
- onuCount := OnuIDEnd - OnuIDStart + 1
-
- for i := 0; i < intfCount; i++ {
- for j := 1; j <= onuCount; j++ {
- wg.Add(1)
- go func(i uint32, j uint32) {
- // TODO: actually verify success
- _ = flowMgr[i].AddOnuInfoToFlowMgrCacheAndKvStore(ctx, i, i, fmt.Sprintf("onu-%d", i))
- wg.Done()
- }(uint32(i), uint32(j))
- }
-
- }
-
- wg.Wait()
-}
-
-func TestOpenOltFlowMgr_addGemPortToOnuInfoMap(t *testing.T) {
- intfNum := NumPonPorts
- onuNum := OnuIDEnd - OnuIDStart + 1
-
- // clean the flowMgr
- for i := 0; i < intfNum; i++ {
- flowMgr[i].onuGemInfoMap = make(map[uint32]*rsrcMgr.OnuGemInfo)
- }
-
- ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
- defer cancel()
-
- // Create OnuInfo
- for i := 0; i < intfNum; i++ {
- for o := 1; o <= onuNum; o++ {
- // TODO: actually verify success
- _ = flowMgr[i].AddOnuInfoToFlowMgrCacheAndKvStore(ctx, uint32(i), uint32(o), fmt.Sprintf("i%do%d", i, o-1))
- }
- }
-
- // Add gemPorts to OnuInfo in parallel threads
- wg := sync.WaitGroup{}
- for o := 1; o <= onuNum; o++ {
- for i := 0; i < intfNum; i++ {
- wg.Add(1)
- go func(intfId uint32, onuId uint32) {
- gemID, _ := strconv.Atoi(fmt.Sprintf("90%d%d", intfId, onuId-1))
-
- flowMgr[intfId].addGemPortToOnuInfoMap(ctx, intfId, onuId, uint32(gemID))
- wg.Done()
- }(uint32(i), uint32(o))
- }
- }
-
- wg.Wait()
-
- // check that each entry of onuGemInfoMap has the correct number of ONUs
- for i := 0; i < intfNum; i++ {
- lenofOnu := len(flowMgr[i].onuGemInfoMap)
- if onuNum != lenofOnu {
- t.Errorf("onuGemInfoMap length is not as expected len = %d, want %d", lenofOnu, onuNum)
- }
-
- for o := 1; o <= onuNum; o++ {
- lenOfGemPorts := len(flowMgr[i].onuGemInfoMap[uint32(o)].GemPorts)
- // check that each onuEntry has 1 gemPort
- if lenOfGemPorts != 1 {
- t.Errorf("Expected 1 GemPort per ONU, found %d", lenOfGemPorts)
- }
-
- // check that the value of the gemport is correct
- gemID, _ := strconv.Atoi(fmt.Sprintf("90%d%d", i, o-1))
- currentValue := flowMgr[i].onuGemInfoMap[uint32(o)].GemPorts[0]
- if uint32(gemID) != currentValue {
- t.Errorf("Expected GemPort value to be %d, found %d", gemID, currentValue)
- }
- }
- }
-}
-
-func TestOpenOltFlowMgr_deleteGemPortFromLocalCache(t *testing.T) {
- // Create fresh flowMgr instance
- flowMgr = newMockFlowmgr()
- type args struct {
- intfID uint32
- onuID uint32
- gemPortIDs []uint32
- gemPortIDsToBeDeleted []uint32
- gemPortIDsRemaining []uint32
- serialNum string
- finalLength int
- }
- tests := []struct {
- name string
- args args
- }{
- // Add/Delete single gem port
- {"DeleteGemPortFromLocalCache1", args{0, 1, []uint32{1}, []uint32{1}, []uint32{}, "onu1", 0}},
- // Delete all gemports
- {"DeleteGemPortFromLocalCache2", args{0, 1, []uint32{1, 2, 3, 4}, []uint32{1, 2, 3, 4}, []uint32{}, "onu1", 0}},
- // Try to delete when there is no gem port
- {"DeleteGemPortFromLocalCache3", args{0, 1, []uint32{}, []uint32{1, 2}, nil, "onu1", 0}},
- // Try to delete non-existent gem port
- {"DeleteGemPortFromLocalCache4", args{0, 1, []uint32{1}, []uint32{2}, []uint32{1}, "onu1", 1}},
- // Try to delete two of the gem ports
- {"DeleteGemPortFromLocalCache5", args{0, 1, []uint32{1, 2, 3, 4}, []uint32{2, 4}, []uint32{1, 3}, "onu1", 2}},
- }
- ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
- defer cancel()
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- if err := flowMgr[tt.args.intfID].RemoveOnuInfoFromFlowMgrCacheAndKvStore(ctx, tt.args.intfID, tt.args.onuID); err != nil {
- t.Errorf("failed to remove onu")
- }
- if err := flowMgr[tt.args.intfID].AddOnuInfoToFlowMgrCacheAndKvStore(ctx, tt.args.intfID, tt.args.onuID, tt.args.serialNum); err != nil {
- t.Errorf("failed to add onu")
- }
- for _, gemPort := range tt.args.gemPortIDs {
- flowMgr[tt.args.intfID].addGemPortToOnuInfoMap(ctx, tt.args.intfID, tt.args.onuID, gemPort)
- }
- for _, gemPortDeleted := range tt.args.gemPortIDsToBeDeleted {
- flowMgr[tt.args.intfID].deleteGemPortFromLocalCache(ctx, tt.args.intfID, tt.args.onuID, gemPortDeleted)
- }
- lenofGemPorts := 0
- gP, ok := flowMgr[tt.args.intfID].onuGemInfoMap[tt.args.onuID]
- if ok {
- lenofGemPorts = len(gP.GemPorts)
- }
- if lenofGemPorts != tt.args.finalLength {
- t.Errorf("GemPorts length is not as expected len = %d, want %d", lenofGemPorts, tt.args.finalLength)
- }
- gP, ok = flowMgr[tt.args.intfID].onuGemInfoMap[tt.args.onuID]
- var gemPorts []uint32
- if ok {
- gemPorts = gP.GemPorts
- }
- if !reflect.DeepEqual(tt.args.gemPortIDsRemaining, gemPorts) {
- t.Errorf("GemPorts are not as expected = %v, want %v", gemPorts, tt.args.gemPortIDsRemaining)
- }
-
- })
- }
-}
-
func TestOpenOltFlowMgr_GetLogicalPortFromPacketIn(t *testing.T) {
type args struct {
packetIn *openoltpb2.PacketIndication
diff --git a/internal/pkg/resourcemanager/resourcemanager.go b/internal/pkg/resourcemanager/resourcemanager.go
index 476bbf5..cfc755e 100755
--- a/internal/pkg/resourcemanager/resourcemanager.go
+++ b/internal/pkg/resourcemanager/resourcemanager.go
@@ -244,7 +244,9 @@
}
ResourceMgr.InitLocalCache()
-
+ if err := ResourceMgr.LoadLocalCacheFromKVStore(ctx, PonIntfID); err != nil {
+ logger.Error(ctx, "failed-to-load-local-cache-from-kvstore")
+ }
logger.Info(ctx, "Initialization of resource manager success!")
return &ResourceMgr
}
@@ -263,6 +265,52 @@
rsrcMgr.groupInfo = make(map[string]*GroupInfo)
}
+//LoadLocalCacheFromKVStore loads local maps
+func (rsrcMgr *OpenOltResourceMgr) LoadLocalCacheFromKVStore(ctx context.Context, PonIntfID uint32) error {
+
+ //List all the keys for OnuGemInfo
+ prefixPath := fmt.Sprintf(OnuGemInfoPathPathPrefix, PonIntfID)
+ keys, err := rsrcMgr.KVStore.List(ctx, prefixPath)
+ logger.Debug(ctx, "load-local-cache-from-KV-store-started")
+ if err != nil {
+ logger.Errorf(ctx, "failed-to-list-keys-from-path-%s", prefixPath)
+ return err
+ }
+ for path := range keys {
+ var Val []byte
+ var onugem OnuGemInfo
+ // Get rid of the path prefix
+ stringToBeReplaced := rsrcMgr.KVStore.PathPrefix + "/"
+ replacedWith := ""
+ path = strings.Replace(path, stringToBeReplaced, replacedWith, 1)
+
+ value, err := rsrcMgr.KVStore.Get(ctx, path)
+ if err != nil {
+ logger.Errorw(ctx, "failed-to-get-from-kv-store", log.Fields{"path": path})
+ return err
+ } else if value == nil {
+ logger.Debug(ctx, "no-onugeminfo-for-path", log.Fields{"path": path})
+ continue
+ }
+ if Val, err = kvstore.ToByte(value.Value); err != nil {
+ logger.Error(ctx, "failed-to-covert-to-byte-array")
+ return err
+ }
+ if err = json.Unmarshal(Val, &onugem); err != nil {
+ logger.Error(ctx, "failed-to-unmarshall")
+ return err
+ }
+ logger.Debugw(ctx, "found-onugeminfo-from-path", log.Fields{"path": path, "onuGemInfo": onugem})
+
+ rsrcMgr.onuGemInfoLock.Lock()
+ rsrcMgr.onuGemInfo[path] = &onugem
+ rsrcMgr.onuGemInfoLock.Unlock()
+
+ }
+ logger.Debug(ctx, "load-local-cache-from-KV-store-finished")
+ return nil
+}
+
// InitializeDeviceResourceRangeAndPool initializes the resource range pool according to the sharing type, then apply
// device specific information. If KV doesn't exist
// or is broader than the device, the device's information will
@@ -948,6 +996,36 @@
return &onugem, nil
}
+//AddNewOnuGemInfoToCacheAndKvStore function adds a new onu gem info to cache and kvstore
+func (rsrcMgr *OpenOltResourceMgr) AddNewOnuGemInfoToCacheAndKvStore(ctx context.Context, intfID uint32, onuID uint32, serialNum string) error {
+
+ Path := fmt.Sprintf(OnuGemInfoPath, intfID, onuID)
+
+ rsrcMgr.onuGemInfoLock.Lock()
+ _, ok := rsrcMgr.onuGemInfo[Path]
+ rsrcMgr.onuGemInfoLock.Unlock()
+
+ // If the ONU already exists in onuGemInfo list, nothing to do
+ if ok {
+ logger.Debugw(ctx, "onu-id-already-exists-in-cache", log.Fields{"onuID": onuID, "serialNum": serialNum})
+ return nil
+ }
+
+ onuGemInfo := OnuGemInfo{OnuID: onuID, SerialNumber: serialNum, IntfID: intfID}
+
+ if err := rsrcMgr.AddOnuGemInfo(ctx, intfID, onuID, onuGemInfo); err != nil {
+ return err
+ }
+ logger.Infow(ctx, "added-onuinfo",
+ log.Fields{
+ "intf-id": intfID,
+ "onu-id": onuID,
+ "serial-num": serialNum,
+ "onu": onuGemInfo,
+ "device-id": rsrcMgr.DeviceID})
+ return nil
+}
+
// AddOnuGemInfo adds onu info on to the kvstore per interface
func (rsrcMgr *OpenOltResourceMgr) AddOnuGemInfo(ctx context.Context, intfID uint32, onuID uint32, onuGem OnuGemInfo) error {
@@ -965,7 +1043,7 @@
logger.Errorf(ctx, "Failed to update resource %s", Path)
return err
}
- logger.Debugw(ctx, "added onu gem info to store", log.Fields{"onuGemInfo": onuGem})
+ logger.Debugw(ctx, "added onu gem info to store", log.Fields{"onuGemInfo": onuGem, "Path": Path})
//update cache
rsrcMgr.onuGemInfoLock.Lock()
@@ -1173,6 +1251,34 @@
return flowIDs, nil
}
+// IsGemPortUsedByAnotherFlow returns true if given gem is used by another flow
+func (rsrcMgr *OpenOltResourceMgr) IsGemPortUsedByAnotherFlow(gemPortID uint32, flowID uint64) bool {
+ rsrcMgr.flowIDsForGemLock.RLock()
+ flowIDList := rsrcMgr.flowIDsForGem[gemPortID]
+ rsrcMgr.flowIDsForGemLock.RUnlock()
+ for _, id := range flowIDList {
+ if flowID != id {
+ return true
+ }
+ }
+ return false
+}
+
+// RegisterFlowIDForGem updates both cache and KV store for flowIDsForGem map
+func (rsrcMgr *OpenOltResourceMgr) RegisterFlowIDForGem(ctx context.Context, accessIntfID uint32, gemPortID uint32, flowFromCore *ofp.OfpFlowStats) error {
+ // get from cache
+ rsrcMgr.flowIDsForGemLock.RLock()
+ flowIDs, ok := rsrcMgr.flowIDsForGem[gemPortID]
+ rsrcMgr.flowIDsForGemLock.RUnlock()
+ if !ok {
+ flowIDs = []uint64{flowFromCore.Id}
+ } else {
+ flowIDs = appendUnique64bit(flowIDs, flowFromCore.Id)
+ }
+ // update the flowids for a gem to the KVstore
+ return rsrcMgr.UpdateFlowIDsForGem(ctx, accessIntfID, gemPortID, flowIDs)
+}
+
//UpdateFlowIDsForGem updates flow id per gemport
func (rsrcMgr *OpenOltResourceMgr) UpdateFlowIDsForGem(ctx context.Context, intf uint32, gem uint32, flowIDs []uint64) error {
var val []byte
@@ -1424,6 +1530,17 @@
return false, groupInfo, nil
}
+// GetOnuGemInfoList returns all gems in the onuGemInfo map
+func (rsrcMgr *OpenOltResourceMgr) GetOnuGemInfoList(ctx context.Context) []OnuGemInfo {
+ var onuGemInfoLst []OnuGemInfo
+ rsrcMgr.onuGemInfoLock.RLock()
+ defer rsrcMgr.onuGemInfoLock.RUnlock()
+ for _, v := range rsrcMgr.onuGemInfo {
+ onuGemInfoLst = append(onuGemInfoLst, *v)
+ }
+ return onuGemInfoLst
+}
+
// toByte converts an interface value to a []byte. The interface should either be of
// a string type or []byte. Otherwise, an error is returned.
func toByte(value interface{}) ([]byte, error) {
@@ -1436,3 +1553,12 @@
return nil, fmt.Errorf("unexpected-type-%T", t)
}
}
+
+func appendUnique64bit(slice []uint64, item uint64) []uint64 {
+ for _, sliceElement := range slice {
+ if sliceElement == item {
+ return slice
+ }
+ }
+ return append(slice, item)
+}
diff --git a/internal/pkg/resourcemanager/resourcemanager_test.go b/internal/pkg/resourcemanager/resourcemanager_test.go
index 5392eb7..85a5811 100644
--- a/internal/pkg/resourcemanager/resourcemanager_test.go
+++ b/internal/pkg/resourcemanager/resourcemanager_test.go
@@ -27,6 +27,7 @@
"context"
"encoding/json"
"errors"
+ "fmt"
"reflect"
"strconv"
"strings"
@@ -493,6 +494,162 @@
}
}
+func TestOpenOltResourceMgr_deleteGemPort(t *testing.T) {
+
+ type args struct {
+ intfID uint32
+ onuID uint32
+ gemPortIDs []uint32
+ gemPortIDsToBeDeleted []uint32
+ gemPortIDsRemaining []uint32
+ serialNum string
+ finalLength int
+ }
+ tests := []struct {
+ name string
+ fields *fields
+ args args
+ }{
+ // Add/Delete single gem port
+ {"DeleteGemPortFromLocalCache1", getResMgr(), args{0, 1, []uint32{1}, []uint32{1}, []uint32{}, "onu1", 0}},
+ // Delete all gemports
+ {"DeleteGemPortFromLocalCache2", getResMgr(), args{0, 1, []uint32{1, 2, 3, 4}, []uint32{1, 2, 3, 4}, []uint32{}, "onu1", 0}},
+ // Try to delete when there is no gem port
+ {"DeleteGemPortFromLocalCache3", getResMgr(), args{0, 1, []uint32{}, []uint32{1, 2}, nil, "onu1", 0}},
+ // Try to delete non-existent gem port
+ {"DeleteGemPortFromLocalCache4", getResMgr(), args{0, 1, []uint32{1}, []uint32{2}, []uint32{1}, "onu1", 1}},
+ // Try to delete two of the gem ports
+ {"DeleteGemPortFromLocalCache5", getResMgr(), args{0, 1, []uint32{1, 2, 3, 4}, []uint32{2, 4}, []uint32{1, 3}, "onu1", 2}},
+ }
+ ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
+ defer cancel()
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ RsrcMgr := testResMgrObject(tt.fields)
+ if err := RsrcMgr.DelOnuGemInfo(ctx, tt.args.intfID, tt.args.onuID); err != nil {
+ t.Errorf("failed to remove onu")
+ }
+ if err := RsrcMgr.AddNewOnuGemInfoToCacheAndKvStore(ctx, tt.args.intfID, tt.args.onuID, tt.args.serialNum); err != nil {
+ t.Errorf("failed to add onu")
+ }
+ for _, gemPort := range tt.args.gemPortIDs {
+ if err := RsrcMgr.AddGemToOnuGemInfo(ctx, tt.args.intfID, tt.args.onuID, gemPort); err != nil {
+ t.Errorf("failed to add gem to onu")
+ }
+ }
+ for _, gemPortDeleted := range tt.args.gemPortIDsToBeDeleted {
+ if err := RsrcMgr.RemoveGemFromOnuGemInfo(ctx, tt.args.intfID, tt.args.onuID, gemPortDeleted); err != nil {
+ t.Errorf("failed to remove gem from onu")
+ }
+ }
+ lenofGemPorts := 0
+ gP, err := RsrcMgr.GetOnuGemInfo(ctx, tt.args.intfID, tt.args.onuID)
+ if err != nil || gP == nil {
+ t.Errorf("failed to get onuGemInfo")
+ }
+ var gemPorts []uint32
+
+ lenofGemPorts = len(gP.GemPorts)
+ gemPorts = gP.GemPorts
+
+ if lenofGemPorts != tt.args.finalLength {
+ t.Errorf("GemPorts length is not as expected len = %d, want %d", lenofGemPorts, tt.args.finalLength)
+ }
+
+ if !reflect.DeepEqual(tt.args.gemPortIDsRemaining, gemPorts) {
+ t.Errorf("GemPorts are not as expected = %v, want %v", gemPorts, tt.args.gemPortIDsRemaining)
+ }
+ })
+ }
+}
+
+func TestOpenOltResourceMgr_AddNewOnuGemInfo(t *testing.T) {
+
+ type args struct {
+ PONIntfID uint32
+ OnuCount uint32
+ }
+ tests := []struct {
+ name string
+ fields *fields
+ args args
+ want error
+ }{
+ {"AddNewOnuGemInfoForIntf-0", getResMgr(), args{0, 32}, nil},
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ RsrcMgr := testResMgrObject(tt.fields)
+ ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
+ defer cancel()
+ for j := 1; j <= int(tt.args.OnuCount); j++ {
+ go func(i uint32, j uint32) {
+ // TODO: actually verify success
+ _ = RsrcMgr.AddNewOnuGemInfoToCacheAndKvStore(ctx, i, i, fmt.Sprintf("onu-%d", i))
+ }(tt.args.PONIntfID, uint32(j))
+ }
+ })
+ }
+}
+
+func TestOpenOltFlowMgr_addGemPortToOnuInfoMap(t *testing.T) {
+
+ type args struct {
+ intfID uint32
+ onuID uint32
+ gemPortIDs []uint32
+ gemPortIDsRemaining []uint32
+ serialNum string
+ finalLength int
+ }
+ tests := []struct {
+ name string
+ fields *fields
+ args args
+ }{
+ // Add single gem port
+ {"addGemPortToOnuInfoMap1", getResMgr(), args{0, 1, []uint32{1}, []uint32{1}, "onu1", 1}},
+ // Delete all gemports
+ {"addGemPortToOnuInfoMap2", getResMgr(), args{0, 1, []uint32{1, 2, 3, 4}, []uint32{1, 2, 3, 4}, "onu1", 4}},
+ // Do not add any gemport
+ {"addGemPortToOnuInfoMap3", getResMgr(), args{0, 1, []uint32{}, nil, "onu1", 0}},
+ }
+ ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
+ defer cancel()
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ RsrcMgr := testResMgrObject(tt.fields)
+ if err := RsrcMgr.DelOnuGemInfo(ctx, tt.args.intfID, tt.args.onuID); err != nil {
+ t.Errorf("failed to remove onu")
+ }
+ if err := RsrcMgr.AddNewOnuGemInfoToCacheAndKvStore(ctx, tt.args.intfID, tt.args.onuID, tt.args.serialNum); err != nil {
+ t.Errorf("failed to add onu")
+ }
+ for _, gemPort := range tt.args.gemPortIDs {
+ if err := RsrcMgr.AddGemToOnuGemInfo(ctx, tt.args.intfID, tt.args.onuID, gemPort); err != nil {
+ t.Errorf("failed to add gem to onu")
+ }
+ }
+
+ lenofGemPorts := 0
+ gP, err := RsrcMgr.GetOnuGemInfo(ctx, tt.args.intfID, tt.args.onuID)
+
+ var gemPorts []uint32
+ if err == nil && gP != nil {
+ lenofGemPorts = len(gP.GemPorts)
+ gemPorts = gP.GemPorts
+ }
+ if lenofGemPorts != tt.args.finalLength {
+ t.Errorf("GemPorts length is not as expected len = %d, want %d", lenofGemPorts, tt.args.finalLength)
+ }
+
+ if !reflect.DeepEqual(tt.args.gemPortIDsRemaining, gemPorts) {
+ t.Errorf("GemPorts are not as expected = %v, want %v", gemPorts, tt.args.gemPortIDsRemaining)
+ }
+ })
+ }
+}
+
func TestOpenOltResourceMgr_GetCurrentGEMPortIDsForOnu(t *testing.T) {
type args struct {
intfID uint32