[VOL-3930] Using a shared lock for Resource acquisition and release

Change-Id: Ibf6346135380ab14d0c89f0e2945ebefdee1b4f9
diff --git a/VERSION b/VERSION
index 3ad0595..9cec716 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-3.1.5
+3.1.6
diff --git a/go.mod b/go.mod
index e4e3460..87d3e12 100644
--- a/go.mod
+++ b/go.mod
@@ -7,7 +7,7 @@
 	github.com/gogo/protobuf v1.3.1
 	github.com/golang/protobuf v1.3.2
 	github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4
-	github.com/opencord/voltha-lib-go/v4 v4.1.0
+	github.com/opencord/voltha-lib-go/v4 v4.1.1
 	github.com/opencord/voltha-protos/v4 v4.0.15
 	go.etcd.io/etcd v0.0.0-20190930204107-236ac2a90522
 	google.golang.org/grpc v1.25.1
diff --git a/go.sum b/go.sum
index 13bf2f6..b1059c6 100644
--- a/go.sum
+++ b/go.sum
@@ -142,8 +142,8 @@
 github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 github.com/onsi/gomega v1.4.2 h1:3mYCb7aPxS/RU7TI1y4rkEn1oKmPRjNJLNEXgw7MH2I=
 github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
-github.com/opencord/voltha-lib-go/v4 v4.1.0 h1:Ba6w5bv36oYrzqfK96f42+hSEMkukwIjpdBWPztLY1g=
-github.com/opencord/voltha-lib-go/v4 v4.1.0/go.mod h1:K7lDkSkJ97EyfvX8fQtBmBvpj7n6MmwnAtD8Jz79HcQ=
+github.com/opencord/voltha-lib-go/v4 v4.1.1 h1:vGpFMoydXOCncyX7Ytmffd0m4kO1SH15AB0NdyFiF/Q=
+github.com/opencord/voltha-lib-go/v4 v4.1.1/go.mod h1:K7lDkSkJ97EyfvX8fQtBmBvpj7n6MmwnAtD8Jz79HcQ=
 github.com/opencord/voltha-protos/v4 v4.0.12 h1:x8drb8inaUByjVLFbXSiQwRTU//dfde0MKIHyKb1JMw=
 github.com/opencord/voltha-protos/v4 v4.0.12/go.mod h1:W/OIFIyvFh/C0vchRUuarIsMylEhzCRM9pNxLvkPtKc=
 github.com/opencord/voltha-protos/v4 v4.0.15 h1:TOKYlt/75w5pxT44HeYfo2kqKvqmHzVpUkiCHOMJTN8=
diff --git a/internal/pkg/core/device_handler_test.go b/internal/pkg/core/device_handler_test.go
index 012ce51..1cae8b6 100644
--- a/internal/pkg/core/device_handler_test.go
+++ b/internal/pkg/core/device_handler_test.go
@@ -20,6 +20,7 @@
 import (
 	"context"
 	conf "github.com/opencord/voltha-lib-go/v4/pkg/config"
+	tp "github.com/opencord/voltha-lib-go/v4/pkg/techprofile"
 	"net"
 	"reflect"
 	"sync"
@@ -193,15 +194,23 @@
 	ranges["gemport_id_shared"] = uint32(0)
 	ranges["flow_id_shared"] = uint32(0)
 
-	ponmgr := &ponrmgr.PONResourceManager{
-		DeviceID: "onu-1",
-		IntfIDs:  []uint32{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
-		KVStore: &db.Backend{
-			Client: &mocks.MockKVClient{},
-		},
-		PonResourceRanges: ranges,
-		SharedIdxByType:   sharedIdxByType,
+	ponmgr := &ponrmgr.PONResourceManager{}
+
+	ctx := context.TODO()
+	tpMgr, err := tp.NewTechProfile(ctx, ponmgr, "etcd", "127.0.0.1", "/")
+	if err != nil {
+		logger.Fatal(ctx, err.Error())
 	}
+
+	ponmgr.DeviceID = "onu-1"
+	ponmgr.IntfIDs = []uint32{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
+	ponmgr.KVStore = &db.Backend{
+		Client: &mocks.MockKVClient{},
+	}
+	ponmgr.PonResourceRanges = ranges
+	ponmgr.SharedIdxByType = sharedIdxByType
+	ponmgr.TechProfileMgr = tpMgr
+
 	for i := 0; i < NumPonPorts; i++ {
 		dh.resourceMgr.ResourceMgrs[uint32(i)] = ponmgr
 	}
diff --git a/internal/pkg/core/openolt_flowmgr.go b/internal/pkg/core/openolt_flowmgr.go
index 680df66..31ca07d 100644
--- a/internal/pkg/core/openolt_flowmgr.go
+++ b/internal/pkg/core/openolt_flowmgr.go
@@ -840,6 +840,9 @@
 		}
 		logger.Infow(ctx, "allocated-tcont-and-gem-ports",
 			log.Fields{
+				"intf-id":   intfID,
+				"onu-id":    onuID,
+				"uni-id":    uniID,
 				"alloc-ids": allocIDs,
 				"gemports":  allgemPortIDs,
 				"device-id": f.deviceHandler.device.Id})
diff --git a/internal/pkg/resourcemanager/resourcemanager.go b/internal/pkg/resourcemanager/resourcemanager.go
index 140bbc8..7a3f8ec 100755
--- a/internal/pkg/resourcemanager/resourcemanager.go
+++ b/internal/pkg/resourcemanager/resourcemanager.go
@@ -446,7 +446,7 @@
 		return 0, err
 	}
 	// Get ONU id for a provided pon interface ID.
-	onuID, err := RsrcMgr.ResourceMgrs[ponIntfID].GetResourceID(ctx, ponIntfID,
+	onuID, err := RsrcMgr.ResourceMgrs[ponIntfID].TechProfileMgr.GetResourceID(ctx, ponIntfID,
 		ponrmgr.ONU_ID, 1)
 	if err != nil {
 		logger.Errorf(ctx, "Failed to get resource for interface %d for type %s",
@@ -841,7 +841,13 @@
 	RsrcMgr.OnuIDMgmtLock[intfID].Lock()
 	defer RsrcMgr.OnuIDMgmtLock[intfID].Unlock()
 
-	RsrcMgr.ResourceMgrs[intfID].FreeResourceID(ctx, intfID, ponrmgr.ONU_ID, onuID)
+	if err := RsrcMgr.ResourceMgrs[intfID].TechProfileMgr.FreeResourceID(ctx, intfID, ponrmgr.ONU_ID, onuID); err != nil {
+		logger.Errorw(ctx, "error-while-freeing-onu-id", log.Fields{
+			"intf-id": intfID,
+			"onu-id":  onuID,
+			"err":     err.Error(),
+		})
+	}
 
 	/* Free onu id for a particular interface.*/
 	var IntfonuID string
@@ -861,7 +867,13 @@
 	RsrcMgr.RemoveAllocIDForOnu(ctx, IntfID, onuID, uniID, allocID)
 	allocIDs := make([]uint32, 0)
 	allocIDs = append(allocIDs, allocID)
-	RsrcMgr.ResourceMgrs[IntfID].FreeResourceID(ctx, IntfID, ponrmgr.ALLOC_ID, allocIDs)
+	if err := RsrcMgr.ResourceMgrs[IntfID].TechProfileMgr.FreeResourceID(ctx, IntfID, ponrmgr.ALLOC_ID, allocIDs); err != nil {
+		logger.Errorw(ctx, "error-while-freeing-alloc-id", log.Fields{
+			"intf-id": IntfID,
+			"onu-id":  onuID,
+			"err":     err.Error(),
+		})
+	}
 }
 
 // FreeGemPortID frees GemPortID on the PON resource pool and also frees the gemPortID association
@@ -874,7 +886,13 @@
 	RsrcMgr.RemoveGemPortIDForOnu(ctx, IntfID, onuID, uniID, gemPortID)
 	gemPortIDs := make([]uint32, 0)
 	gemPortIDs = append(gemPortIDs, gemPortID)
-	RsrcMgr.ResourceMgrs[IntfID].FreeResourceID(ctx, IntfID, ponrmgr.GEMPORT_ID, gemPortIDs)
+	if err := RsrcMgr.ResourceMgrs[IntfID].TechProfileMgr.FreeResourceID(ctx, IntfID, ponrmgr.GEMPORT_ID, gemPortIDs); err != nil {
+		logger.Errorw(ctx, "error-while-freeing-gem-port-id", log.Fields{
+			"intf-id": IntfID,
+			"onu-id":  onuID,
+			"err":     err.Error(),
+		})
+	}
 }
 
 // FreePONResourcesForONU make the pon resources free for a given pon interface and onu id, and the clears the
@@ -886,16 +904,28 @@
 	RsrcMgr.AllocIDMgmtLock[intfID].Lock()
 	AllocIDs := RsrcMgr.ResourceMgrs[intfID].GetCurrentAllocIDForOnu(ctx, IntfOnuIDUniID)
 
-	RsrcMgr.ResourceMgrs[intfID].FreeResourceID(ctx, intfID,
+	if err := RsrcMgr.ResourceMgrs[intfID].TechProfileMgr.FreeResourceID(ctx, intfID,
 		ponrmgr.ALLOC_ID,
-		AllocIDs)
+		AllocIDs); err != nil {
+		logger.Errorw(ctx, "error-while-freeing-all-alloc-ids-for-onu", log.Fields{
+			"intf-id": intfID,
+			"onu-id":  onuID,
+			"err":     err.Error(),
+		})
+	}
 	RsrcMgr.AllocIDMgmtLock[intfID].Unlock()
 
 	RsrcMgr.GemPortIDMgmtLock[intfID].Lock()
 	GEMPortIDs := RsrcMgr.ResourceMgrs[intfID].GetCurrentGEMPortIDsForOnu(ctx, IntfOnuIDUniID)
-	RsrcMgr.ResourceMgrs[intfID].FreeResourceID(ctx, intfID,
+	if err := RsrcMgr.ResourceMgrs[intfID].TechProfileMgr.FreeResourceID(ctx, intfID,
 		ponrmgr.GEMPORT_ID,
-		GEMPortIDs)
+		GEMPortIDs); err != nil {
+		logger.Errorw(ctx, "error-while-freeing-all-gem-port-ids-for-onu", log.Fields{
+			"intf-id": intfID,
+			"onu-id":  onuID,
+			"err":     err.Error(),
+		})
+	}
 	RsrcMgr.GemPortIDMgmtLock[intfID].Unlock()
 
 	// Clear resource map associated with (pon_intf_id, gemport_id) tuple.
diff --git a/internal/pkg/resourcemanager/resourcemanager_test.go b/internal/pkg/resourcemanager/resourcemanager_test.go
index bef6709..e71d07e 100644
--- a/internal/pkg/resourcemanager/resourcemanager_test.go
+++ b/internal/pkg/resourcemanager/resourcemanager_test.go
@@ -27,6 +27,7 @@
 	"context"
 	"encoding/json"
 	"errors"
+	tp "github.com/opencord/voltha-lib-go/v4/pkg/techprofile"
 	"reflect"
 	"strconv"
 	"strings"
@@ -86,6 +87,7 @@
 
 // getResMgr mocks OpenOltResourceMgr struct.
 func getResMgr() *fields {
+	ctx := context.TODO()
 	var resMgr fields
 	resMgr.KVStore = &db.Backend{
 		Client: &MockResKVClient{},
@@ -106,15 +108,21 @@
 	ranges["gemport_id_shared"] = uint32(0)
 	ranges["flow_id_shared"] = uint32(0)
 	resMgr.NumOfPonPorts = 16
-	ponMgr := &ponrmgr.PONResourceManager{
-		DeviceID: "onu-1",
-		IntfIDs:  []uint32{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
-		KVStore: &db.Backend{
-			Client: &MockResKVClient{},
-		},
-		PonResourceRanges: ranges,
-		SharedIdxByType:   sharedIdxByType,
+	ponMgr := &ponrmgr.PONResourceManager{}
+	tpMgr, err := tp.NewTechProfile(ctx, ponMgr, "etcd", "127.0.0.1", "/")
+	if err != nil {
+		logger.Fatal(ctx, err.Error())
 	}
+
+	ponMgr.DeviceID = "onu-1"
+	ponMgr.IntfIDs = []uint32{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
+	ponMgr.KVStore = &db.Backend{
+		Client: &MockResKVClient{},
+	}
+	ponMgr.PonResourceRanges = ranges
+	ponMgr.SharedIdxByType = sharedIdxByType
+	ponMgr.TechProfileMgr = tpMgr
+
 	var ponIntf uint32
 	for ponIntf = 0; ponIntf < resMgr.NumOfPonPorts; ponIntf++ {
 		resMgr.ResourceMgrs[ponIntf] = ponMgr
diff --git a/pkg/mocks/mockTechprofile.go b/pkg/mocks/mockTechprofile.go
index f150190..c57dd54 100644
--- a/pkg/mocks/mockTechprofile.go
+++ b/pkg/mocks/mockTechprofile.go
@@ -198,3 +198,13 @@
 func (m MockTechProfile) FindAllTpInstances(ctx context.Context, techProfiletblID uint32, ponIntf uint32, onuID uint32) interface{} {
 	return []tp.TechProfile{}
 }
+
+// GetResourceID to mock techprofile GetResourceID method
+func (m MockTechProfile) GetResourceID(ctx context.Context, IntfID uint32, ResourceType string, NumIDs uint32) ([]uint32, error) {
+	return []uint32{}, nil
+}
+
+// FreeResourceID to mock techprofile FreeResourceID method
+func (m MockTechProfile) FreeResourceID(ctx context.Context, IntfID uint32, ResourceType string, ReleaseContent []uint32) error {
+	return nil
+}
diff --git a/vendor/github.com/opencord/voltha-lib-go/v4/pkg/ponresourcemanager/ponresourcemanager.go b/vendor/github.com/opencord/voltha-lib-go/v4/pkg/ponresourcemanager/ponresourcemanager.go
index 415ce21..70ed8e6 100644
--- a/vendor/github.com/opencord/voltha-lib-go/v4/pkg/ponresourcemanager/ponresourcemanager.go
+++ b/vendor/github.com/opencord/voltha-lib-go/v4/pkg/ponresourcemanager/ponresourcemanager.go
@@ -703,6 +703,13 @@
 	   :return list/uint32/None: list, uint32 or None if resource type is
 	    alloc_id/gemport_id, onu_id or invalid type respectively
 	*/
+
+	logger.Debugw(ctx, "getting-resource-id", log.Fields{
+		"intf-id":       IntfID,
+		"resource-type": ResourceType,
+		"num":           NumIDs,
+	})
+
 	if NumIDs < 1 {
 		logger.Error(ctx, "Invalid number of resources requested")
 		return nil, fmt.Errorf("Invalid number of resources requested %d", NumIDs)
@@ -771,21 +778,30 @@
 	return false
 }
 
-func (PONRMgr *PONResourceManager) FreeResourceID(ctx context.Context, IntfID uint32, ResourceType string, ReleaseContent []uint32) bool {
+func (PONRMgr *PONResourceManager) FreeResourceID(ctx context.Context, IntfID uint32, ResourceType string, ReleaseContent []uint32) error {
 	/*
-	   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
+	  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
 	*/
+
+	logger.Debugw(ctx, "freeing-resource-id", log.Fields{
+		"intf-id":         IntfID,
+		"resource-type":   ResourceType,
+		"release-content": ReleaseContent,
+	})
+
 	if !checkValidResourceType(ResourceType) {
-		logger.Error(ctx, "Invalid resource type")
-		return false
+		err := fmt.Errorf("Invalid resource type: %s", ResourceType)
+		logger.Error(ctx, err.Error())
+		return err
 	}
 	if ReleaseContent == nil {
-		logger.Debug(ctx, "Nothing to release")
-		return true
+		err := fmt.Errorf("Nothing to release")
+		logger.Debug(ctx, err.Error())
+		return err
 	}
 	// delegate to the master instance if sharing enabled across instances
 	SharedResourceMgr := PONRMgr.SharedResourceMgrs[PONRMgr.SharedIdxByType[ResourceType]]
@@ -794,22 +810,24 @@
 	}
 	Path := PONRMgr.GetPath(ctx, IntfID, ResourceType)
 	if Path == "" {
-		logger.Error(ctx, "Failed to get path")
-		return false
+		err := fmt.Errorf("Failed to get path for IntfId %d and ResourceType %s", IntfID, ResourceType)
+		logger.Error(ctx, err.Error())
+		return err
 	}
 	Resource, err := PONRMgr.GetResource(ctx, Path)
 	if err != nil {
-		logger.Error(ctx, "Failed to get resource")
-		return false
+		logger.Error(ctx, err.Error())
+		return err
 	}
 	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
+		err := fmt.Errorf("Free resource for %s failed", Path)
+		logger.Errorf(ctx, err.Error())
+		return err
 	}
-	return true
+	return nil
 }
 
 func (PONRMgr *PONResourceManager) UpdateResource(ctx context.Context, Path string, Resource map[string]interface{}) error {
@@ -1258,6 +1276,10 @@
 	return GEMPORT_ID
 }
 
+func (PONRMgr *PONResourceManager) GetResourceTypeOnuID() string {
+	return ONU_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) {
diff --git a/vendor/github.com/opencord/voltha-lib-go/v4/pkg/techprofile/tech_profile.go b/vendor/github.com/opencord/voltha-lib-go/v4/pkg/techprofile/tech_profile.go
index 5cb5a2e..0f2741f 100644
--- a/vendor/github.com/opencord/voltha-lib-go/v4/pkg/techprofile/tech_profile.go
+++ b/vendor/github.com/opencord/voltha-lib-go/v4/pkg/techprofile/tech_profile.go
@@ -36,8 +36,10 @@
 // Interface to pon resource manager APIs
 type iPonResourceMgr interface {
 	GetResourceID(ctx context.Context, IntfID uint32, ResourceType string, NumIDs uint32) ([]uint32, error)
+	FreeResourceID(ctx context.Context, IntfID uint32, ResourceType string, ReleaseContent []uint32) error
 	GetResourceTypeAllocID() string
 	GetResourceTypeGemPortID() string
+	GetResourceTypeOnuID() string
 	GetTechnology() string
 }
 
@@ -221,6 +223,7 @@
 type TechProfileMgr struct {
 	config            *TechProfileFlags
 	resourceMgr       iPonResourceMgr
+	OnuIDMgmtLock     sync.RWMutex
 	GemPortIDMgmtLock sync.RWMutex
 	AllocIDMgmtLock   sync.RWMutex
 }
@@ -659,9 +662,7 @@
 	logger.Infow(ctx, "Allocating TechProfileMgr instance from techprofile template", log.Fields{"uniPortName": uniPortName, "intfId": intfId, "numGem": tp.NumGemPorts})
 
 	if tp.InstanceCtrl.Onu == "multi-instance" {
-		t.AllocIDMgmtLock.Lock()
-		tcontIDs, err = t.resourceMgr.GetResourceID(ctx, intfId, t.resourceMgr.GetResourceTypeAllocID(), 1)
-		t.AllocIDMgmtLock.Unlock()
+		tcontIDs, err = t.GetResourceID(ctx, intfId, t.resourceMgr.GetResourceTypeAllocID(), 1)
 		if err != nil {
 			logger.Errorw(ctx, "Error getting alloc id from rsrcrMgr", log.Fields{"intfId": intfId})
 			return nil
@@ -673,9 +674,7 @@
 		} else if tpInst == nil {
 			// No "single-instance" tp found on one any uni port for the given TP ID
 			// Allocate a new TcontID or AllocID
-			t.AllocIDMgmtLock.Lock()
-			tcontIDs, err = t.resourceMgr.GetResourceID(ctx, intfId, t.resourceMgr.GetResourceTypeAllocID(), 1)
-			t.AllocIDMgmtLock.Unlock()
+			tcontIDs, err = t.GetResourceID(ctx, intfId, t.resourceMgr.GetResourceTypeAllocID(), 1)
 			if err != nil {
 				logger.Errorw(ctx, "Error getting alloc id from rsrcrMgr", log.Fields{"intfId": intfId})
 				return nil
@@ -686,9 +685,7 @@
 		}
 	}
 	logger.Debugw(ctx, "Num GEM ports in TP:", log.Fields{"NumGemPorts": tp.NumGemPorts})
-	t.GemPortIDMgmtLock.Lock()
-	gemPorts, err = t.resourceMgr.GetResourceID(ctx, intfId, t.resourceMgr.GetResourceTypeGemPortID(), tp.NumGemPorts)
-	t.GemPortIDMgmtLock.Unlock()
+	gemPorts, err = t.GetResourceID(ctx, intfId, t.resourceMgr.GetResourceTypeGemPortID(), tp.NumGemPorts)
 	if err != nil {
 		logger.Errorw(ctx, "Error getting gemport ids from rsrcrMgr", log.Fields{"intfId": intfId, "numGemports": tp.NumGemPorts})
 		return nil
@@ -793,7 +790,7 @@
 	logger.Infow(ctx, "Allocating TechProfileMgr instance from techprofile template", log.Fields{"uniPortName": uniPortName, "intfId": intfId, "numGem": tp.NumGemPorts})
 
 	if tp.InstanceCtrl.Onu == "multi-instance" {
-		if tcontIDs, err = t.resourceMgr.GetResourceID(ctx, intfId, t.resourceMgr.GetResourceTypeAllocID(), 1); err != nil {
+		if tcontIDs, err = t.GetResourceID(ctx, intfId, t.resourceMgr.GetResourceTypeAllocID(), 1); err != nil {
 			logger.Errorw(ctx, "Error getting alloc id from rsrcrMgr", log.Fields{"intfId": intfId})
 			return nil
 		}
@@ -804,7 +801,7 @@
 		} else if tpInst == nil {
 			// No "single-instance" tp found on one any uni port for the given TP ID
 			// Allocate a new TcontID or AllocID
-			if tcontIDs, err = t.resourceMgr.GetResourceID(ctx, intfId, t.resourceMgr.GetResourceTypeAllocID(), 1); err != nil {
+			if tcontIDs, err = t.GetResourceID(ctx, intfId, t.resourceMgr.GetResourceTypeAllocID(), 1); err != nil {
 				logger.Errorw(ctx, "Error getting alloc id from rsrcrMgr", log.Fields{"intfId": intfId})
 				return nil
 			}
@@ -814,7 +811,7 @@
 		}
 	}
 	logger.Debugw(ctx, "Num GEM ports in TP:", log.Fields{"NumGemPorts": tp.NumGemPorts})
-	if gemPorts, err = t.resourceMgr.GetResourceID(ctx, intfId, t.resourceMgr.GetResourceTypeGemPortID(), tp.NumGemPorts); err != nil {
+	if gemPorts, err = t.GetResourceID(ctx, intfId, t.resourceMgr.GetResourceTypeGemPortID(), tp.NumGemPorts); err != nil {
 		logger.Errorw(ctx, "Error getting gemport ids from rsrcrMgr", log.Fields{"intfId": intfId, "numGemports": tp.NumGemPorts})
 		return nil
 	}
@@ -1397,3 +1394,62 @@
 	}
 	return nil
 }
+
+func (t *TechProfileMgr) GetResourceID(ctx context.Context, IntfID uint32, ResourceType string, NumIDs uint32) ([]uint32, error) {
+	logger.Debugw(ctx, "getting-resource-id", log.Fields{
+		"intf-id":       IntfID,
+		"resource-type": ResourceType,
+		"num":           NumIDs,
+	})
+	var err error
+	var ids []uint32
+	switch ResourceType {
+	case t.resourceMgr.GetResourceTypeAllocID():
+		t.AllocIDMgmtLock.Lock()
+		ids, err = t.resourceMgr.GetResourceID(ctx, IntfID, ResourceType, NumIDs)
+		t.AllocIDMgmtLock.Unlock()
+	case t.resourceMgr.GetResourceTypeGemPortID():
+		t.GemPortIDMgmtLock.Lock()
+		ids, err = t.resourceMgr.GetResourceID(ctx, IntfID, ResourceType, NumIDs)
+		t.GemPortIDMgmtLock.Unlock()
+	case t.resourceMgr.GetResourceTypeOnuID():
+		t.OnuIDMgmtLock.Lock()
+		ids, err = t.resourceMgr.GetResourceID(ctx, IntfID, ResourceType, NumIDs)
+		t.OnuIDMgmtLock.Unlock()
+	default:
+		return nil, fmt.Errorf("ResourceType %s not supported", ResourceType)
+	}
+	if err != nil {
+		return nil, err
+	}
+	return ids, nil
+}
+
+func (t *TechProfileMgr) FreeResourceID(ctx context.Context, IntfID uint32, ResourceType string, ReleaseContent []uint32) error {
+	logger.Debugw(ctx, "freeing-resource-id", log.Fields{
+		"intf-id":         IntfID,
+		"resource-type":   ResourceType,
+		"release-content": ReleaseContent,
+	})
+	var err error
+	switch ResourceType {
+	case t.resourceMgr.GetResourceTypeAllocID():
+		t.AllocIDMgmtLock.Lock()
+		err = t.resourceMgr.FreeResourceID(ctx, IntfID, ResourceType, ReleaseContent)
+		t.AllocIDMgmtLock.Unlock()
+	case t.resourceMgr.GetResourceTypeGemPortID():
+		t.GemPortIDMgmtLock.Lock()
+		err = t.resourceMgr.FreeResourceID(ctx, IntfID, ResourceType, ReleaseContent)
+		t.GemPortIDMgmtLock.Unlock()
+	case t.resourceMgr.GetResourceTypeOnuID():
+		t.OnuIDMgmtLock.Lock()
+		err = t.resourceMgr.FreeResourceID(ctx, IntfID, ResourceType, ReleaseContent)
+		t.OnuIDMgmtLock.Unlock()
+	default:
+		return fmt.Errorf("ResourceType %s not supported", ResourceType)
+	}
+	if err != nil {
+		return err
+	}
+	return nil
+}
diff --git a/vendor/github.com/opencord/voltha-lib-go/v4/pkg/techprofile/tech_profile_if.go b/vendor/github.com/opencord/voltha-lib-go/v4/pkg/techprofile/tech_profile_if.go
index d3a79ce..84d84ee 100644
--- a/vendor/github.com/opencord/voltha-lib-go/v4/pkg/techprofile/tech_profile_if.go
+++ b/vendor/github.com/opencord/voltha-lib-go/v4/pkg/techprofile/tech_profile_if.go
@@ -38,4 +38,6 @@
 	GetMulticastTrafficQueues(ctx context.Context, tp *TechProfile) []*tp_pb.TrafficQueue
 	GetGemportForPbit(ctx context.Context, tp interface{}, Dir tp_pb.Direction, pbit uint32) interface{}
 	FindAllTpInstances(ctx context.Context, techProfiletblID uint32, ponIntf uint32, onuID uint32) interface{}
+	GetResourceID(ctx context.Context, IntfID uint32, ResourceType string, NumIDs uint32) ([]uint32, error)
+	FreeResourceID(ctx context.Context, IntfID uint32, ResourceType string, ReleaseContent []uint32) error
 }
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 50d4a85..e70a77c 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -52,7 +52,7 @@
 # github.com/jcmturner/gofork v1.0.0
 github.com/jcmturner/gofork/encoding/asn1
 github.com/jcmturner/gofork/x/crypto/pbkdf2
-# github.com/opencord/voltha-lib-go/v4 v4.1.0
+# github.com/opencord/voltha-lib-go/v4 v4.1.1
 github.com/opencord/voltha-lib-go/v4/pkg/adapters
 github.com/opencord/voltha-lib-go/v4/pkg/adapters/adapterif
 github.com/opencord/voltha-lib-go/v4/pkg/adapters/common