[VOL-1349] EPON OLT adapter (package B)
Change-Id: I634ef62c53813dcf4456f54948f13e06358e263c
diff --git a/vendor/github.com/opencord/voltha-lib-go/v3/pkg/ponresourcemanager/common.go b/vendor/github.com/opencord/voltha-lib-go/v3/pkg/ponresourcemanager/common.go
new file mode 100644
index 0000000..d266617
--- /dev/null
+++ b/vendor/github.com/opencord/voltha-lib-go/v3/pkg/ponresourcemanager/common.go
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package ponresourcemanager
+
+import (
+ "github.com/opencord/voltha-lib-go/v3/pkg/log"
+)
+
+var logger log.CLogger
+
+func init() {
+ // Setup this package so that it's log level can be modified at run time
+ var err error
+ logger, err = log.RegisterPackage(log.JSON, log.ErrorLevel, log.Fields{})
+ if err != nil {
+ panic(err)
+ }
+}
diff --git a/vendor/github.com/opencord/voltha-lib-go/v3/pkg/ponresourcemanager/ponresourcemanager.go b/vendor/github.com/opencord/voltha-lib-go/v3/pkg/ponresourcemanager/ponresourcemanager.go
new file mode 100644
index 0000000..baff575
--- /dev/null
+++ b/vendor/github.com/opencord/voltha-lib-go/v3/pkg/ponresourcemanager/ponresourcemanager.go
@@ -0,0 +1,1334 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ponresourcemanager
+
+import (
+ "context"
+ "encoding/base64"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "time"
+
+ bitmap "github.com/boljen/go-bitmap"
+ "github.com/opencord/voltha-lib-go/v3/pkg/db"
+ "github.com/opencord/voltha-lib-go/v3/pkg/db/kvstore"
+ "github.com/opencord/voltha-lib-go/v3/pkg/log"
+ tp "github.com/opencord/voltha-lib-go/v3/pkg/techprofile"
+)
+
+const (
+ //Constants to identify resource pool
+ UNI_ID = "UNI_ID"
+ ONU_ID = "ONU_ID"
+ ALLOC_ID = "ALLOC_ID"
+ GEMPORT_ID = "GEMPORT_ID"
+ FLOW_ID = "FLOW_ID"
+
+ //Constants for passing command line arugments
+ OLT_MODEL_ARG = "--olt_model"
+ PATH_PREFIX = "service/voltha/resource_manager/{%s}"
+
+ /*The path under which configuration data is stored is defined as technology/device agnostic.
+ That means the path does not include any specific technology/device variable. Using technology/device
+ agnostic path also makes northbound applications, that need to write to this path,
+ technology/device agnostic.
+
+ Default kv client of PonResourceManager reads from/writes to PATH_PREFIX defined above.
+ That is why, an additional kv client (named KVStoreForConfig) is defined to read from the config path.
+ */
+ PATH_PREFIX_FOR_CONFIG = "service/voltha/resource_manager/config"
+ /*The resource ranges for a given device model should be placed
+ at 'resource_manager/<technology>/resource_ranges/<olt_model_type>'
+ path on the KV store.
+ If Resource Range parameters are to be read from the external KV store,
+ they are expected to be stored in the following format.
+ Note: All parameters are MANDATORY for now.
+ constants used as keys to reference the resource range parameters from
+ and external KV store.
+ */
+ UNI_ID_START_IDX = "uni_id_start"
+ UNI_ID_END_IDX = "uni_id_end"
+ ONU_ID_START_IDX = "onu_id_start"
+ ONU_ID_END_IDX = "onu_id_end"
+ ONU_ID_SHARED_IDX = "onu_id_shared"
+ ALLOC_ID_START_IDX = "alloc_id_start"
+ ALLOC_ID_END_IDX = "alloc_id_end"
+ ALLOC_ID_SHARED_IDX = "alloc_id_shared"
+ GEMPORT_ID_START_IDX = "gemport_id_start"
+ GEMPORT_ID_END_IDX = "gemport_id_end"
+ GEMPORT_ID_SHARED_IDX = "gemport_id_shared"
+ FLOW_ID_START_IDX = "flow_id_start"
+ FLOW_ID_END_IDX = "flow_id_end"
+ FLOW_ID_SHARED_IDX = "flow_id_shared"
+ NUM_OF_PON_PORT = "pon_ports"
+
+ /*
+ The KV store backend is initialized with a path prefix and we need to
+ provide only the suffix.
+ */
+ PON_RESOURCE_RANGE_CONFIG_PATH = "resource_ranges/%s"
+
+ //resource path suffix
+ //Path on the KV store for storing alloc id ranges and resource pool for a given interface
+ //Format: <device_id>/alloc_id_pool/<pon_intf_id>
+ ALLOC_ID_POOL_PATH = "{%s}/alloc_id_pool/{%d}"
+ //Path on the KV store for storing gemport id ranges and resource pool for a given interface
+ //Format: <device_id>/gemport_id_pool/<pon_intf_id>
+ GEMPORT_ID_POOL_PATH = "{%s}/gemport_id_pool/{%d}"
+ //Path on the KV store for storing onu id ranges and resource pool for a given interface
+ //Format: <device_id>/onu_id_pool/<pon_intf_id>
+ ONU_ID_POOL_PATH = "{%s}/onu_id_pool/{%d}"
+ //Path on the KV store for storing flow id ranges and resource pool for a given interface
+ //Format: <device_id>/flow_id_pool/<pon_intf_id>
+ FLOW_ID_POOL_PATH = "{%s}/flow_id_pool/{%d}"
+
+ //Path on the KV store for storing list of alloc IDs for a given ONU
+ //Format: <device_id>/<(pon_intf_id, onu_id)>/alloc_ids
+ ALLOC_ID_RESOURCE_MAP_PATH = "{%s}/{%s}/alloc_ids"
+
+ //Path on the KV store for storing list of gemport IDs for a given ONU
+ //Format: <device_id>/<(pon_intf_id, onu_id)>/gemport_ids
+ GEMPORT_ID_RESOURCE_MAP_PATH = "{%s}/{%s}/gemport_ids"
+
+ //Path on the KV store for storing list of Flow IDs for a given ONU
+ //Format: <device_id>/<(pon_intf_id, onu_id)>/flow_ids
+ FLOW_ID_RESOURCE_MAP_PATH = "{%s}/{%s}/flow_ids"
+
+ //Flow Id info: Use to store more metadata associated with the flow_id
+ //Format: <device_id>/<(pon_intf_id, onu_id)>/flow_id_info/<flow_id>
+ FLOW_ID_INFO_PATH = "{%s}/{%s}/flow_id_info/{%d}"
+
+ //path on the kvstore to store onugem info map
+ //format: <device-id>/onu_gem_info/<intfid>
+ ONU_GEM_INFO_PATH = "{%s}/onu_gem_info/{%d}" // onu_gem/<(intfid)>
+
+ //Constants for internal usage.
+ PON_INTF_ID = "pon_intf_id"
+ START_IDX = "start_idx"
+ END_IDX = "end_idx"
+ POOL = "pool"
+ NUM_OF_PON_INTF = 16
+
+ KVSTORE_RETRY_TIMEOUT = 5 * time.Second
+ //Path on the KV store for storing reserved gem ports
+ //Format: reserved_gemport_ids
+ RESERVED_GEMPORT_IDS_PATH = "reserved_gemport_ids"
+)
+
+//type ResourceTypeIndex string
+//type ResourceType string
+
+type PONResourceManager struct {
+ //Implements APIs to initialize/allocate/release alloc/gemport/onu IDs.
+ Technology string
+ DeviceType string
+ DeviceID string
+ Backend string // ETCD, or consul
+ Address string // address of the KV store
+ OLTModel string
+ KVStore *db.Backend
+ KVStoreForConfig *db.Backend
+ TechProfileMgr tp.TechProfileIf // create object of *tp.TechProfileMgr
+
+ // Below attribute, pon_resource_ranges, should be initialized
+ // by reading from KV store.
+ PonResourceRanges map[string]interface{}
+ SharedResourceMgrs map[string]*PONResourceManager
+ SharedIdxByType map[string]string
+ IntfIDs []uint32 // list of pon interface IDs
+ Globalorlocal string
+}
+
+func newKVClient(ctx context.Context, storeType string, address string, timeout time.Duration) (kvstore.Client, error) {
+ logger.Infow(ctx, "kv-store-type", log.Fields{"store": storeType})
+ switch storeType {
+ case "consul":
+ return kvstore.NewConsulClient(ctx, address, timeout)
+ case "etcd":
+ return kvstore.NewEtcdClient(ctx, address, timeout, log.WarnLevel)
+ }
+ return nil, errors.New("unsupported-kv-store")
+}
+
+func SetKVClient(ctx context.Context, Technology string, Backend string, Addr string, configClient bool) *db.Backend {
+ // TODO : Make sure direct call to NewBackend is working fine with backend , currently there is some
+ // issue between kv store and backend , core is not calling NewBackend directly
+ kvClient, err := newKVClient(ctx, Backend, Addr, KVSTORE_RETRY_TIMEOUT)
+ if err != nil {
+ logger.Fatalw(ctx, "Failed to init KV client\n", log.Fields{"err": err})
+ return nil
+ }
+
+ var pathPrefix string
+ if configClient {
+ pathPrefix = PATH_PREFIX_FOR_CONFIG
+ } else {
+ pathPrefix = fmt.Sprintf(PATH_PREFIX, Technology)
+ }
+
+ kvbackend := &db.Backend{
+ Client: kvClient,
+ StoreType: Backend,
+ Address: Addr,
+ Timeout: KVSTORE_RETRY_TIMEOUT,
+ PathPrefix: pathPrefix}
+
+ return kvbackend
+}
+
+// NewPONResourceManager creates a new PON resource manager.
+func NewPONResourceManager(ctx context.Context, Technology string, DeviceType string, DeviceID string, Backend string, Address string) (*PONResourceManager, error) {
+ var PONMgr PONResourceManager
+ PONMgr.Technology = Technology
+ PONMgr.DeviceType = DeviceType
+ PONMgr.DeviceID = DeviceID
+ PONMgr.Backend = Backend
+ PONMgr.Address = Address
+ PONMgr.KVStore = SetKVClient(ctx, Technology, Backend, Address, false)
+ if PONMgr.KVStore == nil {
+ logger.Error(ctx, "KV Client initilization failed")
+ return nil, errors.New("Failed to init KV client")
+ }
+ // init kv client to read from the config path
+ PONMgr.KVStoreForConfig = SetKVClient(ctx, Technology, Backend, Address, true)
+ if PONMgr.KVStoreForConfig == nil {
+ logger.Error(ctx, "KV Config Client initilization failed")
+ return nil, errors.New("Failed to init KV Config client")
+ }
+ // Initialize techprofile for this technology
+ if PONMgr.TechProfileMgr, _ = tp.NewTechProfile(ctx, &PONMgr, Backend, Address); PONMgr.TechProfileMgr == nil {
+ logger.Error(ctx, "Techprofile initialization failed")
+ return nil, errors.New("Failed to init tech profile")
+ }
+ PONMgr.PonResourceRanges = make(map[string]interface{})
+ PONMgr.SharedResourceMgrs = make(map[string]*PONResourceManager)
+ PONMgr.SharedIdxByType = make(map[string]string)
+ PONMgr.SharedIdxByType[ONU_ID] = ONU_ID_SHARED_IDX
+ PONMgr.SharedIdxByType[ALLOC_ID] = ALLOC_ID_SHARED_IDX
+ PONMgr.SharedIdxByType[GEMPORT_ID] = GEMPORT_ID_SHARED_IDX
+ PONMgr.SharedIdxByType[FLOW_ID] = FLOW_ID_SHARED_IDX
+ PONMgr.IntfIDs = make([]uint32, NUM_OF_PON_INTF)
+ PONMgr.OLTModel = DeviceType
+ return &PONMgr, nil
+}
+
+/*
+ Initialize PON resource ranges with config fetched from kv store.
+ return boolean: True if PON resource ranges initialized else false
+ Try to initialize the PON Resource Ranges from KV store based on the
+ OLT model key, if available
+*/
+
+func (PONRMgr *PONResourceManager) InitResourceRangesFromKVStore(ctx context.Context) bool {
+ //Initialize PON resource ranges with config fetched from kv store.
+ //:return boolean: True if PON resource ranges initialized else false
+ // Try to initialize the PON Resource Ranges from KV store based on the
+ // OLT model key, if available
+ if PONRMgr.OLTModel == "" {
+ logger.Error(ctx, "Failed to get OLT model")
+ return false
+ }
+ Path := fmt.Sprintf(PON_RESOURCE_RANGE_CONFIG_PATH, PONRMgr.OLTModel)
+ //get resource from kv store
+ Result, err := PONRMgr.KVStore.Get(ctx, Path)
+ if err != nil {
+ logger.Debugf(ctx, "Error in fetching resource %s from KV strore", Path)
+ return false
+ }
+ if Result == nil {
+ logger.Debug(ctx, "There may be no resources in the KV store in case of fresh bootup, return true")
+ return false
+ }
+ //update internal ranges from kv ranges. If there are missing
+ // values in the KV profile, continue to use the defaults
+ Value, err := ToByte(Result.Value)
+ if err != nil {
+ logger.Error(ctx, "Failed to convert kvpair to byte string")
+ return false
+ }
+ if err := json.Unmarshal(Value, &PONRMgr.PonResourceRanges); err != nil {
+ logger.Error(ctx, "Failed to Unmarshal json byte")
+ return false
+ }
+ logger.Debug(ctx, "Init resource ranges from kvstore success")
+ return true
+}
+
+func (PONRMgr *PONResourceManager) UpdateRanges(ctx context.Context, StartIDx string, StartID uint32, EndIDx string, EndID uint32,
+ SharedIDx string, SharedPoolID uint32, RMgr *PONResourceManager) {
+ /*
+ Update the ranges for all reosurce type in the intermnal maps
+ param: resource type start index
+ param: start ID
+ param: resource type end index
+ param: end ID
+ param: resource type shared index
+ param: shared pool id
+ param: global resource manager
+ */
+ logger.Debugf(ctx, "update ranges for %s, %d", StartIDx, StartID)
+
+ if StartID != 0 {
+ if (PONRMgr.PonResourceRanges[StartIDx] == nil) || (PONRMgr.PonResourceRanges[StartIDx].(uint32) < StartID) {
+ PONRMgr.PonResourceRanges[StartIDx] = StartID
+ }
+ }
+ if EndID != 0 {
+ if (PONRMgr.PonResourceRanges[EndIDx] == nil) || (PONRMgr.PonResourceRanges[EndIDx].(uint32) > EndID) {
+ PONRMgr.PonResourceRanges[EndIDx] = EndID
+ }
+ }
+ //if SharedPoolID != 0 {
+ PONRMgr.PonResourceRanges[SharedIDx] = SharedPoolID
+ //}
+ if RMgr != nil {
+ PONRMgr.SharedResourceMgrs[SharedIDx] = RMgr
+ }
+}
+
+func (PONRMgr *PONResourceManager) InitDefaultPONResourceRanges(ctx context.Context,
+ ONUIDStart uint32,
+ ONUIDEnd uint32,
+ ONUIDSharedPoolID uint32,
+ AllocIDStart uint32,
+ AllocIDEnd uint32,
+ AllocIDSharedPoolID uint32,
+ GEMPortIDStart uint32,
+ GEMPortIDEnd uint32,
+ GEMPortIDSharedPoolID uint32,
+ FlowIDStart uint32,
+ FlowIDEnd uint32,
+ FlowIDSharedPoolID uint32,
+ UNIIDStart uint32,
+ UNIIDEnd uint32,
+ NoOfPONPorts uint32,
+ IntfIDs []uint32) bool {
+
+ /*Initialize default PON resource ranges
+
+ :param onu_id_start_idx: onu id start index
+ :param onu_id_end_idx: onu id end index
+ :param onu_id_shared_pool_id: pool idx for id shared by all intfs or None for no sharing
+ :param alloc_id_start_idx: alloc id start index
+ :param alloc_id_end_idx: alloc id end index
+ :param alloc_id_shared_pool_id: pool idx for alloc id shared by all intfs or None for no sharing
+ :param gemport_id_start_idx: gemport id start index
+ :param gemport_id_end_idx: gemport id end index
+ :param gemport_id_shared_pool_id: pool idx for gemport id shared by all intfs or None for no sharing
+ :param flow_id_start_idx: flow id start index
+ :param flow_id_end_idx: flow id end index
+ :param flow_id_shared_pool_id: pool idx for flow id shared by all intfs or None for no sharing
+ :param num_of_pon_ports: number of PON ports
+ :param intf_ids: interfaces serviced by this manager
+ */
+ PONRMgr.UpdateRanges(ctx, ONU_ID_START_IDX, ONUIDStart, ONU_ID_END_IDX, ONUIDEnd, ONU_ID_SHARED_IDX, ONUIDSharedPoolID, nil)
+ PONRMgr.UpdateRanges(ctx, ALLOC_ID_START_IDX, AllocIDStart, ALLOC_ID_END_IDX, AllocIDEnd, ALLOC_ID_SHARED_IDX, AllocIDSharedPoolID, nil)
+ PONRMgr.UpdateRanges(ctx, GEMPORT_ID_START_IDX, GEMPortIDStart, GEMPORT_ID_END_IDX, GEMPortIDEnd, GEMPORT_ID_SHARED_IDX, GEMPortIDSharedPoolID, nil)
+ PONRMgr.UpdateRanges(ctx, FLOW_ID_START_IDX, FlowIDStart, FLOW_ID_END_IDX, FlowIDEnd, FLOW_ID_SHARED_IDX, FlowIDSharedPoolID, nil)
+ PONRMgr.UpdateRanges(ctx, UNI_ID_START_IDX, UNIIDStart, UNI_ID_END_IDX, UNIIDEnd, "", 0, nil)
+ logger.Debug(ctx, "Initialize default range values")
+ var i uint32
+ if IntfIDs == nil {
+ for i = 0; i < NoOfPONPorts; i++ {
+ PONRMgr.IntfIDs = append(PONRMgr.IntfIDs, i)
+ }
+ } else {
+ PONRMgr.IntfIDs = IntfIDs
+ }
+ return true
+}
+
+func (PONRMgr *PONResourceManager) InitDeviceResourcePool(ctx context.Context) error {
+
+ //Initialize resource pool for all PON ports.
+
+ logger.Debug(ctx, "Init resource ranges")
+
+ var err error
+ for _, Intf := range PONRMgr.IntfIDs {
+ SharedPoolID := PONRMgr.PonResourceRanges[ONU_ID_SHARED_IDX].(uint32)
+ if SharedPoolID != 0 {
+ Intf = SharedPoolID
+ }
+ if err = PONRMgr.InitResourceIDPool(ctx, Intf, ONU_ID,
+ PONRMgr.PonResourceRanges[ONU_ID_START_IDX].(uint32),
+ PONRMgr.PonResourceRanges[ONU_ID_END_IDX].(uint32)); err != nil {
+ logger.Error(ctx, "Failed to init ONU ID resource pool")
+ return err
+ }
+ if SharedPoolID != 0 {
+ break
+ }
+ }
+
+ for _, Intf := range PONRMgr.IntfIDs {
+ SharedPoolID := PONRMgr.PonResourceRanges[ALLOC_ID_SHARED_IDX].(uint32)
+ if SharedPoolID != 0 {
+ Intf = SharedPoolID
+ }
+ if err = PONRMgr.InitResourceIDPool(ctx, Intf, ALLOC_ID,
+ PONRMgr.PonResourceRanges[ALLOC_ID_START_IDX].(uint32),
+ PONRMgr.PonResourceRanges[ALLOC_ID_END_IDX].(uint32)); err != nil {
+ logger.Error(ctx, "Failed to init ALLOC ID resource pool ")
+ return err
+ }
+ if SharedPoolID != 0 {
+ break
+ }
+ }
+ for _, Intf := range PONRMgr.IntfIDs {
+ SharedPoolID := PONRMgr.PonResourceRanges[GEMPORT_ID_SHARED_IDX].(uint32)
+ if SharedPoolID != 0 {
+ Intf = SharedPoolID
+ }
+ if err = PONRMgr.InitResourceIDPool(ctx, Intf, GEMPORT_ID,
+ PONRMgr.PonResourceRanges[GEMPORT_ID_START_IDX].(uint32),
+ PONRMgr.PonResourceRanges[GEMPORT_ID_END_IDX].(uint32)); err != nil {
+ logger.Error(ctx, "Failed to init GEMPORT ID resource pool")
+ return err
+ }
+ if SharedPoolID != 0 {
+ break
+ }
+ }
+
+ for _, Intf := range PONRMgr.IntfIDs {
+ SharedPoolID := PONRMgr.PonResourceRanges[FLOW_ID_SHARED_IDX].(uint32)
+ if SharedPoolID != 0 {
+ Intf = SharedPoolID
+ }
+ if err = PONRMgr.InitResourceIDPool(ctx, Intf, FLOW_ID,
+ PONRMgr.PonResourceRanges[FLOW_ID_START_IDX].(uint32),
+ PONRMgr.PonResourceRanges[FLOW_ID_END_IDX].(uint32)); err != nil {
+ logger.Error(ctx, "Failed to init FLOW ID resource pool")
+ return err
+ }
+ if SharedPoolID != 0 {
+ break
+ }
+ }
+ return err
+}
+
+func (PONRMgr *PONResourceManager) ClearDeviceResourcePool(ctx context.Context) error {
+
+ //Clear resource pool for all PON ports.
+
+ logger.Debug(ctx, "Clear resource ranges")
+
+ for _, Intf := range PONRMgr.IntfIDs {
+ SharedPoolID := PONRMgr.PonResourceRanges[ONU_ID_SHARED_IDX].(uint32)
+ if SharedPoolID != 0 {
+ Intf = SharedPoolID
+ }
+ if status := PONRMgr.ClearResourceIDPool(ctx, Intf, ONU_ID); !status {
+ logger.Error(ctx, "Failed to clear ONU ID resource pool")
+ return errors.New("Failed to clear ONU ID resource pool")
+ }
+ if SharedPoolID != 0 {
+ break
+ }
+ }
+
+ for _, Intf := range PONRMgr.IntfIDs {
+ SharedPoolID := PONRMgr.PonResourceRanges[ALLOC_ID_SHARED_IDX].(uint32)
+ if SharedPoolID != 0 {
+ Intf = SharedPoolID
+ }
+ if status := PONRMgr.ClearResourceIDPool(ctx, Intf, ALLOC_ID); !status {
+ logger.Error(ctx, "Failed to clear ALLOC ID resource pool ")
+ return errors.New("Failed to clear ALLOC ID resource pool")
+ }
+ if SharedPoolID != 0 {
+ break
+ }
+ }
+ for _, Intf := range PONRMgr.IntfIDs {
+ SharedPoolID := PONRMgr.PonResourceRanges[GEMPORT_ID_SHARED_IDX].(uint32)
+ if SharedPoolID != 0 {
+ Intf = SharedPoolID
+ }
+ if status := PONRMgr.ClearResourceIDPool(ctx, Intf, GEMPORT_ID); !status {
+ logger.Error(ctx, "Failed to clear GEMPORT ID resource pool")
+ return errors.New("Failed to clear GEMPORT ID resource pool")
+ }
+ if SharedPoolID != 0 {
+ break
+ }
+ }
+
+ for _, Intf := range PONRMgr.IntfIDs {
+ SharedPoolID := PONRMgr.PonResourceRanges[FLOW_ID_SHARED_IDX].(uint32)
+ if SharedPoolID != 0 {
+ Intf = SharedPoolID
+ }
+ if status := PONRMgr.ClearResourceIDPool(ctx, Intf, FLOW_ID); !status {
+ logger.Error(ctx, "Failed to clear FLOW ID resource pool")
+ return errors.New("Failed to clear FLOW ID resource pool")
+ }
+ if SharedPoolID != 0 {
+ break
+ }
+ }
+ return nil
+}
+
+func (PONRMgr *PONResourceManager) InitResourceIDPool(ctx context.Context, Intf uint32, ResourceType string, StartID uint32, EndID uint32) error {
+
+ /*Initialize Resource ID pool for a given Resource Type on a given PON Port
+
+ :param pon_intf_id: OLT PON interface id
+ :param resource_type: String to identify type of resource
+ :param start_idx: start index for onu id pool
+ :param end_idx: end index for onu id pool
+ :return boolean: True if resource id pool initialized else false
+ */
+
+ // delegate to the master instance if sharing enabled across instances
+ SharedResourceMgr := PONRMgr.SharedResourceMgrs[PONRMgr.SharedIdxByType[ResourceType]]
+ if SharedResourceMgr != nil && PONRMgr != SharedResourceMgr {
+ return SharedResourceMgr.InitResourceIDPool(ctx, Intf, ResourceType, StartID, EndID)
+ }
+
+ Path := PONRMgr.GetPath(ctx, Intf, ResourceType)
+ if Path == "" {
+ logger.Errorf(ctx, "Failed to get path for resource type %s", ResourceType)
+ return fmt.Errorf("Failed to get path for resource type %s", ResourceType)
+ }
+
+ //In case of adapter reboot and reconciliation resource in kv store
+ //checked for its presence if not kv store update happens
+ Res, err := PONRMgr.GetResource(ctx, Path)
+ if (err == nil) && (Res != nil) {
+ logger.Debugf(ctx, "Resource %s already present in store ", Path)
+ return nil
+ } else {
+ var excluded []uint32
+ if ResourceType == GEMPORT_ID {
+ //get gem port ids defined in the KV store, if any, and exclude them from the gem port id pool
+ if reservedGemPortIds, defined := PONRMgr.getReservedGemPortIdsFromKVStore(ctx); defined {
+ excluded = reservedGemPortIds
+ logger.Debugw(ctx, "Excluding some ports from GEM port id pool", log.Fields{"excluded gem ports": excluded})
+ }
+ }
+ FormatResult, err := PONRMgr.FormatResource(ctx, Intf, StartID, EndID, excluded)
+ if err != nil {
+ logger.Errorf(ctx, "Failed to format resource")
+ return err
+ }
+ // Add resource as json in kv store.
+ err = PONRMgr.KVStore.Put(ctx, Path, FormatResult)
+ if err == nil {
+ logger.Debug(ctx, "Successfuly posted to kv store")
+ return err
+ }
+ }
+
+ logger.Debug(ctx, "Error initializing pool")
+
+ return err
+}
+
+func (PONRMgr *PONResourceManager) getReservedGemPortIdsFromKVStore(ctx context.Context) ([]uint32, bool) {
+ var reservedGemPortIds []uint32
+ // read reserved gem ports from the config path
+ KvPair, err := PONRMgr.KVStoreForConfig.Get(ctx, RESERVED_GEMPORT_IDS_PATH)
+ if err != nil {
+ logger.Errorw(ctx, "Unable to get reserved GEM port ids from the kv store", log.Fields{"err": err})
+ return reservedGemPortIds, false
+ }
+ if KvPair == nil || KvPair.Value == nil {
+ //no reserved gem port defined in the store
+ return reservedGemPortIds, false
+ }
+ Val, err := kvstore.ToByte(KvPair.Value)
+ if err != nil {
+ logger.Errorw(ctx, "Failed to convert reserved gem port ids into byte array", log.Fields{"err": err})
+ return reservedGemPortIds, false
+ }
+ if err = json.Unmarshal(Val, &reservedGemPortIds); err != nil {
+ logger.Errorw(ctx, "Failed to unmarshal reservedGemPortIds", log.Fields{"err": err})
+ return reservedGemPortIds, false
+ }
+ return reservedGemPortIds, true
+}
+
+func (PONRMgr *PONResourceManager) FormatResource(ctx context.Context, IntfID uint32, StartIDx uint32, EndIDx uint32,
+ Excluded []uint32) ([]byte, error) {
+ /*
+ Format resource as json.
+ :param pon_intf_id: OLT PON interface id
+ :param start_idx: start index for id pool
+ :param end_idx: end index for id pool
+ :Id values to be Excluded from the pool
+ :return dictionary: resource formatted as map
+ */
+ // Format resource as json to be stored in backend store
+ Resource := make(map[string]interface{})
+ Resource[PON_INTF_ID] = IntfID
+ Resource[START_IDX] = StartIDx
+ Resource[END_IDX] = EndIDx
+ /*
+ Resource pool stored in backend store as binary string.
+ Tracking the resource allocation will be done by setting the bits \
+ in the byte array. The index set will be the resource number allocated.
+ */
+ var TSData *bitmap.Threadsafe
+ if TSData = bitmap.NewTS(int(EndIDx)); TSData == nil {
+ logger.Error(ctx, "Failed to create a bitmap")
+ return nil, errors.New("Failed to create bitmap")
+ }
+ for _, excludedID := range Excluded {
+ if excludedID < StartIDx || excludedID > EndIDx {
+ logger.Warnf(ctx, "Cannot reserve %d. It must be in the range of [%d, %d]", excludedID,
+ StartIDx, EndIDx)
+ continue
+ }
+ PONRMgr.reserveID(ctx, TSData, StartIDx, excludedID)
+ }
+ Resource[POOL] = TSData.Data(false) //we pass false so as the TSData lib api does not do a copy of the data and return
+
+ Value, err := json.Marshal(Resource)
+ if err != nil {
+ logger.Errorf(ctx, "Failed to marshall resource")
+ return nil, err
+ }
+ return Value, err
+}
+func (PONRMgr *PONResourceManager) GetResource(ctx context.Context, Path string) (map[string]interface{}, error) {
+ /*
+ Get resource from kv store.
+
+ :param path: path to get resource
+ :return: resource if resource present in kv store else None
+ */
+ //get resource from kv store
+
+ var Value []byte
+ Result := make(map[string]interface{})
+ var Str string
+
+ Resource, err := PONRMgr.KVStore.Get(ctx, Path)
+ if (err != nil) || (Resource == nil) {
+ logger.Debugf(ctx, "Resource unavailable at %s", Path)
+ return nil, err
+ }
+
+ Value, err = ToByte(Resource.Value)
+ if err != nil {
+ return nil, err
+ }
+
+ // decode resource fetched from backend store to dictionary
+ err = json.Unmarshal(Value, &Result)
+ if err != nil {
+ logger.Error(ctx, "Failed to decode resource")
+ return Result, err
+ }
+ /*
+ resource pool in backend store stored as binary string whereas to
+ access the pool to generate/release IDs it need to be converted
+ as BitArray
+ */
+ Str, err = ToString(Result[POOL])
+ if err != nil {
+ logger.Error(ctx, "Failed to conver to kv pair to string")
+ return Result, err
+ }
+ Decode64, _ := base64.StdEncoding.DecodeString(Str)
+ Result[POOL], err = ToByte(Decode64)
+ if err != nil {
+ logger.Error(ctx, "Failed to convert resource pool to byte")
+ return Result, err
+ }
+
+ return Result, err
+}
+
+func (PONRMgr *PONResourceManager) GetPath(ctx context.Context, IntfID uint32, ResourceType string) string {
+ /*
+ Get path for given resource type.
+ :param pon_intf_id: OLT PON interface id
+ :param resource_type: String to identify type of resource
+ :return: path for given resource type
+ */
+
+ /*
+ Get the shared pool for the given resource type.
+ all the resource ranges and the shared resource maps are initialized during the init.
+ */
+ SharedPoolID := PONRMgr.PonResourceRanges[PONRMgr.SharedIdxByType[ResourceType]].(uint32)
+ if SharedPoolID != 0 {
+ IntfID = SharedPoolID
+ }
+ var Path string
+ if ResourceType == ONU_ID {
+ Path = fmt.Sprintf(ONU_ID_POOL_PATH, PONRMgr.DeviceID, IntfID)
+ } else if ResourceType == ALLOC_ID {
+ Path = fmt.Sprintf(ALLOC_ID_POOL_PATH, PONRMgr.DeviceID, IntfID)
+ } else if ResourceType == GEMPORT_ID {
+ Path = fmt.Sprintf(GEMPORT_ID_POOL_PATH, PONRMgr.DeviceID, IntfID)
+ } else if ResourceType == FLOW_ID {
+ Path = fmt.Sprintf(FLOW_ID_POOL_PATH, PONRMgr.DeviceID, IntfID)
+ } else {
+ logger.Error(ctx, "Invalid resource pool identifier")
+ }
+ return Path
+}
+
+func (PONRMgr *PONResourceManager) GetResourceID(ctx context.Context, IntfID uint32, ResourceType string, NumIDs uint32) ([]uint32, error) {
+ /*
+ Create alloc/gemport/onu/flow id for given OLT PON interface.
+ :param pon_intf_id: OLT PON interface id
+ :param resource_type: String to identify type of resource
+ :param num_of_id: required number of ids
+ :return list/uint32/None: list, uint32 or None if resource type is
+ alloc_id/gemport_id, onu_id or invalid type respectively
+ */
+ if NumIDs < 1 {
+ logger.Error(ctx, "Invalid number of resources requested")
+ return nil, fmt.Errorf("Invalid number of resources requested %d", NumIDs)
+ }
+ // delegate to the master instance if sharing enabled across instances
+
+ SharedResourceMgr := PONRMgr.SharedResourceMgrs[PONRMgr.SharedIdxByType[ResourceType]]
+ if SharedResourceMgr != nil && PONRMgr != SharedResourceMgr {
+ return SharedResourceMgr.GetResourceID(ctx, IntfID, ResourceType, NumIDs)
+ }
+ logger.Debugf(ctx, "Fetching resource from %s rsrc mgr for resource %s", PONRMgr.Globalorlocal, ResourceType)
+
+ Path := PONRMgr.GetPath(ctx, IntfID, ResourceType)
+ if Path == "" {
+ logger.Errorf(ctx, "Failed to get path for resource type %s", ResourceType)
+ return nil, fmt.Errorf("Failed to get path for resource type %s", ResourceType)
+ }
+ logger.Debugf(ctx, "Get resource for type %s on path %s", ResourceType, Path)
+ var Result []uint32
+ var NextID uint32
+ Resource, err := PONRMgr.GetResource(ctx, Path)
+ if (err == nil) && (ResourceType == ONU_ID) || (ResourceType == FLOW_ID) {
+ if NextID, err = PONRMgr.GenerateNextID(ctx, Resource); err != nil {
+ logger.Error(ctx, "Failed to Generate ID")
+ return Result, err
+ }
+ Result = append(Result, NextID)
+ } else if (err == nil) && ((ResourceType == GEMPORT_ID) || (ResourceType == ALLOC_ID)) {
+ if NumIDs == 1 {
+ if NextID, err = PONRMgr.GenerateNextID(ctx, Resource); err != nil {
+ logger.Error(ctx, "Failed to Generate ID")
+ return Result, err
+ }
+ Result = append(Result, NextID)
+ } else {
+ for NumIDs > 0 {
+ if NextID, err = PONRMgr.GenerateNextID(ctx, Resource); err != nil {
+ logger.Error(ctx, "Failed to Generate ID")
+ return Result, err
+ }
+ Result = append(Result, NextID)
+ NumIDs--
+ }
+ }
+ } else {
+ logger.Error(ctx, "get resource failed")
+ return Result, err
+ }
+
+ //Update resource in kv store
+ if PONRMgr.UpdateResource(ctx, Path, Resource) != nil {
+ logger.Errorf(ctx, "Failed to update resource %s", Path)
+ return nil, fmt.Errorf("Failed to update resource %s", Path)
+ }
+ return Result, nil
+}
+
+func checkValidResourceType(ResourceType string) bool {
+ KnownResourceTypes := []string{ONU_ID, ALLOC_ID, GEMPORT_ID, FLOW_ID}
+
+ for _, v := range KnownResourceTypes {
+ if v == ResourceType {
+ return true
+ }
+ }
+ return false
+}
+
+func (PONRMgr *PONResourceManager) FreeResourceID(ctx context.Context, IntfID uint32, ResourceType string, ReleaseContent []uint32) bool {
+ /*
+ Release alloc/gemport/onu/flow id for given OLT PON interface.
+ :param pon_intf_id: OLT PON interface id
+ :param resource_type: String to identify type of resource
+ :param release_content: required number of ids
+ :return boolean: True if all IDs in given release_content release else False
+ */
+ if !checkValidResourceType(ResourceType) {
+ logger.Error(ctx, "Invalid resource type")
+ return false
+ }
+ if ReleaseContent == nil {
+ logger.Debug(ctx, "Nothing to release")
+ return true
+ }
+ // delegate to the master instance if sharing enabled across instances
+ SharedResourceMgr := PONRMgr.SharedResourceMgrs[PONRMgr.SharedIdxByType[ResourceType]]
+ if SharedResourceMgr != nil && PONRMgr != SharedResourceMgr {
+ return SharedResourceMgr.FreeResourceID(ctx, IntfID, ResourceType, ReleaseContent)
+ }
+ Path := PONRMgr.GetPath(ctx, IntfID, ResourceType)
+ if Path == "" {
+ logger.Error(ctx, "Failed to get path")
+ return false
+ }
+ Resource, err := PONRMgr.GetResource(ctx, Path)
+ if err != nil {
+ logger.Error(ctx, "Failed to get resource")
+ return false
+ }
+ for _, Val := range ReleaseContent {
+ PONRMgr.ReleaseID(ctx, Resource, Val)
+ }
+ if PONRMgr.UpdateResource(ctx, Path, Resource) != nil {
+ logger.Errorf(ctx, "Free resource for %s failed", Path)
+ return false
+ }
+ return true
+}
+
+func (PONRMgr *PONResourceManager) UpdateResource(ctx context.Context, Path string, Resource map[string]interface{}) error {
+ /*
+ Update resource in resource kv store.
+ :param path: path to update resource
+ :param resource: resource need to be updated
+ :return boolean: True if resource updated in kv store else False
+ */
+ // TODO resource[POOL] = resource[POOL].bin
+ Value, err := json.Marshal(Resource)
+ if err != nil {
+ logger.Error(ctx, "failed to Marshal")
+ return err
+ }
+ err = PONRMgr.KVStore.Put(ctx, Path, Value)
+ if err != nil {
+ logger.Error(ctx, "failed to put data to kv store %s", Path)
+ return err
+ }
+ return nil
+}
+
+func (PONRMgr *PONResourceManager) ClearResourceIDPool(ctx context.Context, contIntfID uint32, ResourceType string) bool {
+ /*
+ Clear Resource Pool for a given Resource Type on a given PON Port.
+ :return boolean: True if removed else False
+ */
+
+ // delegate to the master instance if sharing enabled across instances
+ SharedResourceMgr := PONRMgr.SharedResourceMgrs[PONRMgr.SharedIdxByType[ResourceType]]
+ if SharedResourceMgr != nil && PONRMgr != SharedResourceMgr {
+ return SharedResourceMgr.ClearResourceIDPool(ctx, contIntfID, ResourceType)
+ }
+ Path := PONRMgr.GetPath(ctx, contIntfID, ResourceType)
+ if Path == "" {
+ logger.Error(ctx, "Failed to get path")
+ return false
+ }
+
+ if err := PONRMgr.KVStore.Delete(ctx, Path); err != nil {
+ logger.Errorf(ctx, "Failed to delete resource %s", Path)
+ return false
+ }
+ logger.Debugf(ctx, "Cleared resource %s", Path)
+ return true
+}
+
+func (PONRMgr PONResourceManager) InitResourceMap(ctx context.Context, PONIntfONUID string) {
+ /*
+ Initialize resource map
+ :param pon_intf_onu_id: reference of PON interface id and onu id
+ */
+ // initialize pon_intf_onu_id tuple to alloc_ids map
+ AllocIDPath := fmt.Sprintf(ALLOC_ID_RESOURCE_MAP_PATH, PONRMgr.DeviceID, PONIntfONUID)
+ var AllocIDs []byte
+ Result := PONRMgr.KVStore.Put(ctx, AllocIDPath, AllocIDs)
+ if Result != nil {
+ logger.Error(ctx, "Failed to update the KV store")
+ return
+ }
+ // initialize pon_intf_onu_id tuple to gemport_ids map
+ GEMPortIDPath := fmt.Sprintf(GEMPORT_ID_RESOURCE_MAP_PATH, PONRMgr.DeviceID, PONIntfONUID)
+ var GEMPortIDs []byte
+ Result = PONRMgr.KVStore.Put(ctx, GEMPortIDPath, GEMPortIDs)
+ if Result != nil {
+ logger.Error(ctx, "Failed to update the KV store")
+ return
+ }
+}
+
+func (PONRMgr PONResourceManager) RemoveResourceMap(ctx context.Context, PONIntfONUID string) bool {
+ /*
+ Remove resource map
+ :param pon_intf_onu_id: reference of PON interface id and onu id
+ */
+ // remove pon_intf_onu_id tuple to alloc_ids map
+ var err error
+ AllocIDPath := fmt.Sprintf(ALLOC_ID_RESOURCE_MAP_PATH, PONRMgr.DeviceID, PONIntfONUID)
+ if err = PONRMgr.KVStore.Delete(ctx, AllocIDPath); err != nil {
+ logger.Errorf(ctx, "Failed to remove resource %s", AllocIDPath)
+ return false
+ }
+ // remove pon_intf_onu_id tuple to gemport_ids map
+ GEMPortIDPath := fmt.Sprintf(GEMPORT_ID_RESOURCE_MAP_PATH, PONRMgr.DeviceID, PONIntfONUID)
+ err = PONRMgr.KVStore.Delete(ctx, GEMPortIDPath)
+ if err != nil {
+ logger.Errorf(ctx, "Failed to remove resource %s", GEMPortIDPath)
+ return false
+ }
+
+ FlowIDPath := fmt.Sprintf(FLOW_ID_RESOURCE_MAP_PATH, PONRMgr.DeviceID, PONIntfONUID)
+ if FlowIDs, err := PONRMgr.KVStore.List(ctx, FlowIDPath); err != nil {
+ for _, Flow := range FlowIDs {
+ FlowIDInfoPath := fmt.Sprintf(FLOW_ID_INFO_PATH, PONRMgr.DeviceID, PONIntfONUID, Flow.Value)
+ if err = PONRMgr.KVStore.Delete(ctx, FlowIDInfoPath); err != nil {
+ logger.Errorf(ctx, "Failed to remove resource %s", FlowIDInfoPath)
+ return false
+ }
+ }
+ }
+
+ if err = PONRMgr.KVStore.Delete(ctx, FlowIDPath); err != nil {
+ logger.Errorf(ctx, "Failed to remove resource %s", FlowIDPath)
+ return false
+ }
+
+ return true
+}
+
+func (PONRMgr *PONResourceManager) GetCurrentAllocIDForOnu(ctx context.Context, IntfONUID string) []uint32 {
+ /*
+ Get currently configured alloc ids for given pon_intf_onu_id
+ :param pon_intf_onu_id: reference of PON interface id and onu id
+ :return list: List of alloc_ids if available, else None
+ */
+ Path := fmt.Sprintf(ALLOC_ID_RESOURCE_MAP_PATH, PONRMgr.DeviceID, IntfONUID)
+
+ var Data []uint32
+ Value, err := PONRMgr.KVStore.Get(ctx, Path)
+ if err == nil {
+ if Value != nil {
+ Val, err := ToByte(Value.Value)
+ if err != nil {
+ logger.Errorw(ctx, "Failed to convert into byte array", log.Fields{"error": err})
+ return Data
+ }
+ if err = json.Unmarshal(Val, &Data); err != nil {
+ logger.Error(ctx, "Failed to unmarshal", log.Fields{"error": err})
+ return Data
+ }
+ }
+ }
+ return Data
+}
+
+func (PONRMgr *PONResourceManager) GetCurrentGEMPortIDsForOnu(ctx context.Context, IntfONUID string) []uint32 {
+ /*
+ Get currently configured gemport ids for given pon_intf_onu_id
+ :param pon_intf_onu_id: reference of PON interface id and onu id
+ :return list: List of gemport IDs if available, else None
+ */
+
+ Path := fmt.Sprintf(GEMPORT_ID_RESOURCE_MAP_PATH, PONRMgr.DeviceID, IntfONUID)
+ logger.Debugf(ctx, "Getting current gemports for %s", Path)
+ var Data []uint32
+ Value, err := PONRMgr.KVStore.Get(ctx, Path)
+ if err == nil {
+ if Value != nil {
+ Val, _ := ToByte(Value.Value)
+ if err = json.Unmarshal(Val, &Data); err != nil {
+ logger.Errorw(ctx, "Failed to unmarshal", log.Fields{"error": err})
+ return Data
+ }
+ }
+ } else {
+ logger.Errorf(ctx, "Failed to get data from kvstore for %s", Path)
+ }
+ return Data
+}
+
+func (PONRMgr *PONResourceManager) GetCurrentFlowIDsForOnu(ctx context.Context, IntfONUID string) []uint32 {
+ /*
+ Get currently configured flow ids for given pon_intf_onu_id
+ :param pon_intf_onu_id: reference of PON interface id and onu id
+ :return list: List of Flow IDs if available, else None
+ */
+
+ Path := fmt.Sprintf(FLOW_ID_RESOURCE_MAP_PATH, PONRMgr.DeviceID, IntfONUID)
+
+ var Data []uint32
+ Value, err := PONRMgr.KVStore.Get(ctx, Path)
+ if err == nil {
+ if Value != nil {
+ Val, _ := ToByte(Value.Value)
+ if err = json.Unmarshal(Val, &Data); err != nil {
+ logger.Error(ctx, "Failed to unmarshal")
+ return Data
+ }
+ }
+ }
+ return Data
+}
+
+func (PONRMgr *PONResourceManager) GetFlowIDInfo(ctx context.Context, IntfONUID string, FlowID uint32, Data interface{}) error {
+ /*
+ Get flow details configured for the ONU.
+ :param pon_intf_onu_id: reference of PON interface id and onu id
+ :param flow_id: Flow Id reference
+ :param Data: Result
+ :return error: nil if no error in getting from KV store
+ */
+
+ Path := fmt.Sprintf(FLOW_ID_INFO_PATH, PONRMgr.DeviceID, IntfONUID, FlowID)
+
+ Value, err := PONRMgr.KVStore.Get(ctx, Path)
+ if err == nil {
+ if Value != nil {
+ Val, err := ToByte(Value.Value)
+ if err != nil {
+ logger.Errorw(ctx, "Failed to convert flowinfo into byte array", log.Fields{"error": err})
+ return err
+ }
+ if err = json.Unmarshal(Val, Data); err != nil {
+ logger.Errorw(ctx, "Failed to unmarshal", log.Fields{"error": err})
+ return err
+ }
+ }
+ }
+ return err
+}
+
+func (PONRMgr *PONResourceManager) RemoveFlowIDInfo(ctx context.Context, IntfONUID string, FlowID uint32) bool {
+ /*
+ Get flow_id details configured for the ONU.
+ :param pon_intf_onu_id: reference of PON interface id and onu id
+ :param flow_id: Flow Id reference
+ */
+ Path := fmt.Sprintf(FLOW_ID_INFO_PATH, PONRMgr.DeviceID, IntfONUID, FlowID)
+
+ if err := PONRMgr.KVStore.Delete(ctx, Path); err != nil {
+ logger.Errorf(ctx, "Falied to remove resource %s", Path)
+ return false
+ }
+ return true
+}
+
+func (PONRMgr *PONResourceManager) UpdateAllocIdsForOnu(ctx context.Context, IntfONUID string, AllocIDs []uint32) error {
+ /*
+ Update currently configured alloc ids for given pon_intf_onu_id
+ :param pon_intf_onu_id: reference of PON interface id and onu id
+ :param alloc_ids: list of alloc ids
+ */
+ var Value []byte
+ var err error
+ Path := fmt.Sprintf(ALLOC_ID_RESOURCE_MAP_PATH, PONRMgr.DeviceID, IntfONUID)
+ Value, err = json.Marshal(AllocIDs)
+ if err != nil {
+ logger.Error(ctx, "failed to Marshal")
+ return err
+ }
+
+ if err = PONRMgr.KVStore.Put(ctx, Path, Value); err != nil {
+ logger.Errorf(ctx, "Failed to update resource %s", Path)
+ return err
+ }
+ return err
+}
+
+func (PONRMgr *PONResourceManager) UpdateGEMPortIDsForOnu(ctx context.Context, IntfONUID string, GEMPortIDs []uint32) error {
+ /*
+ Update currently configured gemport ids for given pon_intf_onu_id
+ :param pon_intf_onu_id: reference of PON interface id and onu id
+ :param gemport_ids: list of gem port ids
+ */
+
+ var Value []byte
+ var err error
+ Path := fmt.Sprintf(GEMPORT_ID_RESOURCE_MAP_PATH, PONRMgr.DeviceID, IntfONUID)
+ logger.Debugf(ctx, "Updating gemport ids for %s", Path)
+ Value, err = json.Marshal(GEMPortIDs)
+ if err != nil {
+ logger.Error(ctx, "failed to Marshal")
+ return err
+ }
+
+ if err = PONRMgr.KVStore.Put(ctx, Path, Value); err != nil {
+ logger.Errorf(ctx, "Failed to update resource %s", Path)
+ return err
+ }
+ return err
+}
+
+func checkForFlowIDInList(FlowIDList []uint32, FlowID uint32) (bool, uint32) {
+ /*
+ Check for a flow id in a given list of flow IDs.
+ :param FLowIDList: List of Flow IDs
+ :param FlowID: Flowd to check in the list
+ : return true and the index if present false otherwise.
+ */
+
+ for idx := range FlowIDList {
+ if FlowID == FlowIDList[idx] {
+ return true, uint32(idx)
+ }
+ }
+ return false, 0
+}
+
+func (PONRMgr *PONResourceManager) UpdateFlowIDForOnu(ctx context.Context, IntfONUID string, FlowID uint32, Add bool) error {
+ /*
+ Update the flow_id list of the ONU (add or remove flow_id from the list)
+ :param pon_intf_onu_id: reference of PON interface id and onu id
+ :param flow_id: flow ID
+ :param add: Boolean flag to indicate whether the flow_id should be
+ added or removed from the list. Defaults to adding the flow.
+ */
+ var Value []byte
+ var err error
+ var RetVal bool
+ var IDx uint32
+ Path := fmt.Sprintf(FLOW_ID_RESOURCE_MAP_PATH, PONRMgr.DeviceID, IntfONUID)
+ FlowIDs := PONRMgr.GetCurrentFlowIDsForOnu(ctx, IntfONUID)
+
+ if Add {
+ if RetVal, _ = checkForFlowIDInList(FlowIDs, FlowID); RetVal {
+ return nil
+ }
+ FlowIDs = append(FlowIDs, FlowID)
+ } else {
+ if RetVal, IDx = checkForFlowIDInList(FlowIDs, FlowID); !RetVal {
+ return nil
+ }
+ // delete the index and shift
+ FlowIDs = append(FlowIDs[:IDx], FlowIDs[IDx+1:]...)
+ }
+ Value, err = json.Marshal(FlowIDs)
+ if err != nil {
+ logger.Error(ctx, "Failed to Marshal")
+ return err
+ }
+
+ if err = PONRMgr.KVStore.Put(ctx, Path, Value); err != nil {
+ logger.Errorf(ctx, "Failed to update resource %s", Path)
+ return err
+ }
+ return err
+}
+
+func (PONRMgr *PONResourceManager) UpdateFlowIDInfoForOnu(ctx context.Context, IntfONUID string, FlowID uint32, FlowData interface{}) error {
+ /*
+ Update any metadata associated with the flow_id. The flow_data could be json
+ or any of other data structure. The resource manager doesnt care
+ :param pon_intf_onu_id: reference of PON interface id and onu id
+ :param flow_id: Flow ID
+ :param flow_data: Flow data blob
+ */
+ var Value []byte
+ var err error
+ Path := fmt.Sprintf(FLOW_ID_INFO_PATH, PONRMgr.DeviceID, IntfONUID, FlowID)
+ Value, err = json.Marshal(FlowData)
+ if err != nil {
+ logger.Error(ctx, "failed to Marshal")
+ return err
+ }
+
+ if err = PONRMgr.KVStore.Put(ctx, Path, Value); err != nil {
+ logger.Errorf(ctx, "Failed to update resource %s", Path)
+ return err
+ }
+ return err
+}
+
+func (PONRMgr *PONResourceManager) GenerateNextID(ctx context.Context, Resource map[string]interface{}) (uint32, error) {
+ /*
+ Generate unique id having OFFSET as start
+ :param resource: resource used to generate ID
+ :return uint32: generated id
+ */
+ ByteArray, err := ToByte(Resource[POOL])
+ if err != nil {
+ logger.Error(ctx, "Failed to convert resource to byte array")
+ return 0, err
+ }
+ Data := bitmap.TSFromData(ByteArray, false)
+ if Data == nil {
+ logger.Error(ctx, "Failed to get data from byte array")
+ return 0, errors.New("Failed to get data from byte array")
+ }
+
+ Len := Data.Len()
+ var Idx int
+ for Idx = 0; Idx < Len; Idx++ {
+ if !Data.Get(Idx) {
+ break
+ }
+ }
+ Data.Set(Idx, true)
+ res := uint32(Resource[START_IDX].(float64))
+ Resource[POOL] = Data.Data(false)
+ logger.Debugf(ctx, "Generated ID for %d", (uint32(Idx) + res))
+ return (uint32(Idx) + res), err
+}
+
+func (PONRMgr *PONResourceManager) ReleaseID(ctx context.Context, Resource map[string]interface{}, Id uint32) bool {
+ /*
+ Release unique id having OFFSET as start index.
+ :param resource: resource used to release ID
+ :param unique_id: id need to be released
+ */
+ ByteArray, err := ToByte(Resource[POOL])
+ if err != nil {
+ logger.Error(ctx, "Failed to convert resource to byte array")
+ return false
+ }
+ Data := bitmap.TSFromData(ByteArray, false)
+ if Data == nil {
+ logger.Error(ctx, "Failed to get resource pool")
+ return false
+ }
+ Idx := Id - uint32(Resource[START_IDX].(float64))
+ Data.Set(int(Idx), false)
+ Resource[POOL] = Data.Data(false)
+
+ return true
+}
+
+/* Reserves a unique id in the specified resource pool.
+:param Resource: resource used to reserve ID
+:param Id: ID to be reserved
+*/
+func (PONRMgr *PONResourceManager) reserveID(ctx context.Context, TSData *bitmap.Threadsafe, StartIndex uint32, Id uint32) bool {
+ Data := bitmap.TSFromData(TSData.Data(false), false)
+ if Data == nil {
+ logger.Error(ctx, "Failed to get resource pool")
+ return false
+ }
+ Idx := Id - StartIndex
+ Data.Set(int(Idx), true)
+ return true
+}
+
+func (PONRMgr *PONResourceManager) GetTechnology() string {
+ return PONRMgr.Technology
+}
+
+func (PONRMgr *PONResourceManager) GetResourceTypeAllocID() string {
+ return ALLOC_ID
+}
+
+func (PONRMgr *PONResourceManager) GetResourceTypeGemPortID() string {
+ return GEMPORT_ID
+}
+
+// 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) {
+ switch t := value.(type) {
+ case []byte:
+ return value.([]byte), nil
+ case string:
+ return []byte(value.(string)), nil
+ default:
+ return nil, fmt.Errorf("unexpected-type-%T", t)
+ }
+}
+
+// ToString converts an interface value to a string. The interface should either be of
+// a string type or []byte. Otherwise, an error is returned.
+func ToString(value interface{}) (string, error) {
+ switch t := value.(type) {
+ case []byte:
+ return string(value.([]byte)), nil
+ case string:
+ return value.(string), nil
+ default:
+ return "", fmt.Errorf("unexpected-type-%T", t)
+ }
+}
+
+func (PONRMgr *PONResourceManager) AddOnuGemInfo(ctx context.Context, intfID uint32, onuGemData interface{}) error {
+ /*
+ Update onugem info map,
+ :param pon_intf_id: reference of PON interface id
+ :param onuegmdata: onugem info map
+ */
+ var Value []byte
+ var err error
+ Path := fmt.Sprintf(ONU_GEM_INFO_PATH, PONRMgr.DeviceID, intfID)
+ Value, err = json.Marshal(onuGemData)
+ if err != nil {
+ logger.Error(ctx, "failed to Marshal")
+ return err
+ }
+
+ if err = PONRMgr.KVStore.Put(ctx, Path, Value); err != nil {
+ logger.Errorf(ctx, "Failed to update resource %s", Path)
+ return err
+ }
+ return err
+}
+
+func (PONRMgr *PONResourceManager) GetOnuGemInfo(ctx context.Context, IntfId uint32, onuGemInfo interface{}) error {
+ /*
+ Get onugeminfo map from kvstore
+ :param intfid: refremce pon intfid
+ :param onuGemInfo: onugem info to return from kv strore.
+ */
+ var Val []byte
+
+ path := fmt.Sprintf(ONU_GEM_INFO_PATH, PONRMgr.DeviceID, IntfId)
+ value, err := PONRMgr.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 onuinfo for path", log.Fields{"path": path})
+ return nil // returning nil as this could happen if there are no onus for the interface yet
+ }
+ if Val, err = kvstore.ToByte(value.Value); err != nil {
+ logger.Error(ctx, "Failed to convert to byte array")
+ return err
+ }
+
+ if err = json.Unmarshal(Val, &onuGemInfo); err != nil {
+ logger.Error(ctx, "Failed to unmarshall")
+ return err
+ }
+ logger.Debugw(ctx, "found onuinfo from path", log.Fields{"path": path, "onuinfo": onuGemInfo})
+ return err
+}
+
+func (PONRMgr *PONResourceManager) DelOnuGemInfoForIntf(ctx context.Context, intfId uint32) error {
+ /*
+ delete onugem info for an interface from kvstore
+ :param intfid: refremce pon intfid
+ */
+
+ path := fmt.Sprintf(ONU_GEM_INFO_PATH, PONRMgr.DeviceID, intfId)
+ if err := PONRMgr.KVStore.Delete(ctx, path); err != nil {
+ logger.Errorf(ctx, "Falied to remove resource %s", path)
+ return err
+ }
+ return nil
+}