[VOL-1348] EPON tech profile support

Change-Id: I5dfbc17fe6787f255d22d0b5d640bc636bfb172d
diff --git a/VERSION b/VERSION
index 1a45714..31c3bb8 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.4.9-dev
+2.4.11-dev
diff --git a/go.mod b/go.mod
index d7a5201..dd9b888 100755
--- a/go.mod
+++ b/go.mod
@@ -7,7 +7,7 @@
 	github.com/cenkalti/backoff/v3 v3.1.1
 	github.com/gogo/protobuf v1.3.1
 	github.com/golang/protobuf v1.3.2
-	github.com/opencord/voltha-lib-go/v3 v3.1.19
+	github.com/opencord/voltha-lib-go/v3 v3.1.20
 	github.com/opencord/voltha-protos/v3 v3.3.9
 	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 827bbb6..a1dbbd9 100644
--- a/go.sum
+++ b/go.sum
@@ -204,8 +204,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/v3 v3.1.19 h1:WrjN/qi1pQCszoSTlf4jr7hBfKuma7Xeaq/a6V+nsa4=
-github.com/opencord/voltha-lib-go/v3 v3.1.19/go.mod h1:sa508HZ5vlOauh0i+WC0XFX1JZnfHtJqNIms5XBT/Z0=
+github.com/opencord/voltha-lib-go/v3 v3.1.20 h1:TXSz3mivOShau8YkKvXOQrWMWyjqZTnzG/+1U6+2r5Y=
+github.com/opencord/voltha-lib-go/v3 v3.1.20/go.mod h1:sa508HZ5vlOauh0i+WC0XFX1JZnfHtJqNIms5XBT/Z0=
 github.com/opencord/voltha-protos/v3 v3.3.9 h1:BnfDN9oaRBgyAiH9ZN7LpBpEJYxjX/ZS7R4OT2hDrtY=
 github.com/opencord/voltha-protos/v3 v3.3.9/go.mod h1:nl1ETp5Iw3avxOaKD8BJlYY5wYI4KeV95aT1pL63nto=
 github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU=
diff --git a/internal/pkg/core/openolt_flowmgr.go b/internal/pkg/core/openolt_flowmgr.go
index 4a8df12..d14194e 100644
--- a/internal/pkg/core/openolt_flowmgr.go
+++ b/internal/pkg/core/openolt_flowmgr.go
@@ -199,7 +199,7 @@
 	uniID        uint32
 	tpID         uint32
 	uniPort      uint32
-	tpInst       *tp.TechProfile
+	tpInst       interface{}
 	meterID      uint32
 	flowMetadata *voltha.FlowMetadata
 }
@@ -299,7 +299,7 @@
 	UsMeterID uint32, DsMeterID uint32, flowMetadata *voltha.FlowMetadata) {
 	var allocID uint32
 	var gemPorts []uint32
-	var TpInst *tp.TechProfile
+	var TpInst interface{}
 
 	logger.Infow("dividing-flow", log.Fields{
 		"device-id":  f.deviceHandler.device.Id,
@@ -427,9 +427,9 @@
 			"device-id": f.deviceHandler.device.Id})
 
 	if sq.direction == tp_pb.Direction_UPSTREAM {
-		SchedCfg, err = f.techprofile[sq.intfID].GetUsScheduler(sq.tpInst)
+		SchedCfg, err = f.techprofile[sq.intfID].GetUsScheduler(sq.tpInst.(*tp.TechProfile))
 	} else if sq.direction == tp_pb.Direction_DOWNSTREAM {
-		SchedCfg, err = f.techprofile[sq.intfID].GetDsScheduler(sq.tpInst)
+		SchedCfg, err = f.techprofile[sq.intfID].GetDsScheduler(sq.tpInst.(*tp.TechProfile))
 	}
 
 	if err != nil {
@@ -481,7 +481,7 @@
 	pbs := cbs + ebs
 	TrafficShaping := &tp_pb.TrafficShapingInfo{Cir: cir, Cbs: cbs, Pir: pir, Pbs: pbs}
 
-	TrafficSched := []*tp_pb.TrafficScheduler{f.techprofile[sq.intfID].GetTrafficScheduler(sq.tpInst, SchedCfg, TrafficShaping)}
+	TrafficSched := []*tp_pb.TrafficScheduler{f.techprofile[sq.intfID].GetTrafficScheduler(sq.tpInst.(*tp.TechProfile), SchedCfg, TrafficShaping)}
 	TrafficSched[0].TechProfileId = sq.tpID
 
 	if err := f.pushSchedulerQueuesToDevice(ctx, sq, TrafficShaping, TrafficSched); err != nil {
@@ -509,7 +509,7 @@
 
 func (f *OpenOltFlowMgr) pushSchedulerQueuesToDevice(ctx context.Context, sq schedQueue, TrafficShaping *tp_pb.TrafficShapingInfo, TrafficSched []*tp_pb.TrafficScheduler) error {
 
-	trafficQueues, err := f.techprofile[sq.intfID].GetTrafficQueues(sq.tpInst, sq.direction)
+	trafficQueues, err := f.techprofile[sq.intfID].GetTrafficQueues(sq.tpInst.(*tp.TechProfile), sq.direction)
 
 	if err != nil {
 		return olterrors.NewErrAdapter("unable-to-construct-traffic-queue-configuration",
@@ -553,7 +553,7 @@
 		"device-id":      f.deviceHandler.device.Id})
 
 	if sq.direction == tp_pb.Direction_DOWNSTREAM {
-		multicastTrafficQueues := f.techprofile[sq.intfID].GetMulticastTrafficQueues(sq.tpInst)
+		multicastTrafficQueues := f.techprofile[sq.intfID].GetMulticastTrafficQueues(sq.tpInst.(*tp.TechProfile))
 		if len(multicastTrafficQueues) > 0 {
 			if _, present := f.interfaceToMcastQueueMap[sq.intfID]; !present {
 				//assumed that there is only one queue per PON for the multicast service
@@ -592,10 +592,10 @@
 			"uni-port":  sq.uniPort,
 			"device-id": f.deviceHandler.device.Id})
 	if sq.direction == tp_pb.Direction_UPSTREAM {
-		SchedCfg, err = f.techprofile[sq.intfID].GetUsScheduler(sq.tpInst)
+		SchedCfg, err = f.techprofile[sq.intfID].GetUsScheduler(sq.tpInst.(*tp.TechProfile))
 		Direction = "upstream"
 	} else if sq.direction == tp_pb.Direction_DOWNSTREAM {
-		SchedCfg, err = f.techprofile[sq.intfID].GetDsScheduler(sq.tpInst)
+		SchedCfg, err = f.techprofile[sq.intfID].GetDsScheduler(sq.tpInst.(*tp.TechProfile))
 		Direction = "downstream"
 	}
 
@@ -633,10 +633,10 @@
 
 	TrafficShaping := &tp_pb.TrafficShapingInfo{Cir: cir, Cbs: cbs, Pir: pir, Pbs: pbs}
 
-	TrafficSched := []*tp_pb.TrafficScheduler{f.techprofile[sq.intfID].GetTrafficScheduler(sq.tpInst, SchedCfg, TrafficShaping)}
+	TrafficSched := []*tp_pb.TrafficScheduler{f.techprofile[sq.intfID].GetTrafficScheduler(sq.tpInst.(*tp.TechProfile), SchedCfg, TrafficShaping)}
 	TrafficSched[0].TechProfileId = sq.tpID
 
-	TrafficQueues, err := f.techprofile[sq.intfID].GetTrafficQueues(sq.tpInst, sq.direction)
+	TrafficQueues, err := f.techprofile[sq.intfID].GetTrafficQueues(sq.tpInst.(*tp.TechProfile), sq.direction)
 	if err != nil {
 		return olterrors.NewErrAdapter("unable-to-construct-traffic-queue-configuration",
 			log.Fields{
@@ -689,7 +689,7 @@
 }
 
 // This function allocates tconts and GEM ports for an ONU
-func (f *OpenOltFlowMgr) createTcontGemports(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, uni string, uniPort uint32, TpID uint32, UsMeterID uint32, DsMeterID uint32, flowMetadata *voltha.FlowMetadata) (uint32, []uint32, *tp.TechProfile) {
+func (f *OpenOltFlowMgr) createTcontGemports(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, uni string, uniPort uint32, TpID uint32, UsMeterID uint32, DsMeterID uint32, flowMetadata *voltha.FlowMetadata) (uint32, []uint32, interface{}) {
 	var allocIDs []uint32
 	var allgemPortIDs []uint32
 	var gemPortIDs []uint32
@@ -733,53 +733,85 @@
 				"device-id": f.deviceHandler.device.Id})
 		tpInstanceExists = true
 	}
-	if UsMeterID != 0 {
-		sq := schedQueue{direction: tp_pb.Direction_UPSTREAM, intfID: intfID, onuID: onuID, uniID: uniID, tpID: TpID,
-			uniPort: uniPort, tpInst: techProfileInstance, meterID: UsMeterID, flowMetadata: flowMetadata}
-		if err := f.CreateSchedulerQueues(ctx, sq); err != nil {
-			logger.Errorw("CreateSchedulerQueues-failed-upstream",
-				log.Fields{
-					"error":     err,
-					"meter-id":  UsMeterID,
-					"device-id": f.deviceHandler.device.Id})
-			return 0, nil, nil
-		}
-	}
-	if DsMeterID != 0 {
-		sq := schedQueue{direction: tp_pb.Direction_DOWNSTREAM, intfID: intfID, onuID: onuID, uniID: uniID, tpID: TpID,
-			uniPort: uniPort, tpInst: techProfileInstance, meterID: DsMeterID, flowMetadata: flowMetadata}
-		if err := f.CreateSchedulerQueues(ctx, sq); err != nil {
-			logger.Errorw("CreateSchedulerQueues-failed-downstream",
-				log.Fields{
-					"error":     err,
-					"meter-id":  DsMeterID,
-					"device-id": f.deviceHandler.device.Id})
-			return 0, nil, nil
-		}
-	}
 
-	allocID := techProfileInstance.UsScheduler.AllocID
-	for _, gem := range techProfileInstance.UpstreamGemPortAttributeList {
-		gemPortIDs = append(gemPortIDs, gem.GemportID)
-	}
+	switch tpInst := techProfileInstance.(type) {
+	case *tp.TechProfile:
+		if UsMeterID != 0 {
+			sq := schedQueue{direction: tp_pb.Direction_UPSTREAM, intfID: intfID, onuID: onuID, uniID: uniID, tpID: TpID,
+				uniPort: uniPort, tpInst: techProfileInstance, meterID: UsMeterID, flowMetadata: flowMetadata}
+			if err := f.CreateSchedulerQueues(ctx, sq); err != nil {
+				logger.Errorw("CreateSchedulerQueues-failed-upstream",
+					log.Fields{
+						"error":     err,
+						"meter-id":  UsMeterID,
+						"device-id": f.deviceHandler.device.Id})
+				return 0, nil, nil
+			}
+		}
+		if DsMeterID != 0 {
+			sq := schedQueue{direction: tp_pb.Direction_DOWNSTREAM, intfID: intfID, onuID: onuID, uniID: uniID, tpID: TpID,
+				uniPort: uniPort, tpInst: techProfileInstance, meterID: DsMeterID, flowMetadata: flowMetadata}
+			if err := f.CreateSchedulerQueues(ctx, sq); err != nil {
+				logger.Errorw("CreateSchedulerQueues-failed-downstream",
+					log.Fields{
+						"error":     err,
+						"meter-id":  DsMeterID,
+						"device-id": f.deviceHandler.device.Id})
+				return 0, nil, nil
+			}
+		}
+		allocID := tpInst.UsScheduler.AllocID
+		for _, gem := range tpInst.UpstreamGemPortAttributeList {
+			gemPortIDs = append(gemPortIDs, gem.GemportID)
+		}
+		allocIDs = appendUnique(allocIDs, allocID)
 
-	if tpInstanceExists {
+		if tpInstanceExists {
+			return allocID, gemPortIDs, techProfileInstance
+		}
+
+		for _, gemPortID := range gemPortIDs {
+			allgemPortIDs = appendUnique(allgemPortIDs, gemPortID)
+		}
+		logger.Infow("allocated-tcont-and-gem-ports",
+			log.Fields{
+				"alloc-ids": allocIDs,
+				"gemports":  allgemPortIDs,
+				"device-id": f.deviceHandler.device.Id})
+		// Send Tconts and GEM ports to KV store
+		f.storeTcontsGEMPortsIntoKVStore(ctx, intfID, onuID, uniID, allocIDs, allgemPortIDs)
 		return allocID, gemPortIDs, techProfileInstance
+	case *tp.EponProfile:
+		// CreateSchedulerQueues for EPON needs to be implemented here
+		// when voltha-protos for EPON is completed.
+		allocID := tpInst.AllocID
+		for _, gem := range tpInst.UpstreamQueueAttributeList {
+			gemPortIDs = append(gemPortIDs, gem.GemportID)
+		}
+		allocIDs = appendUnique(allocIDs, allocID)
+
+		if tpInstanceExists {
+			return allocID, gemPortIDs, techProfileInstance
+		}
+
+		for _, gemPortID := range gemPortIDs {
+			allgemPortIDs = appendUnique(allgemPortIDs, gemPortID)
+		}
+		logger.Infow("allocated-tcont-and-gem-ports",
+			log.Fields{
+				"alloc-ids": allocIDs,
+				"gemports":  allgemPortIDs,
+				"device-id": f.deviceHandler.device.Id})
+		// Send Tconts and GEM ports to KV store
+		f.storeTcontsGEMPortsIntoKVStore(ctx, intfID, onuID, uniID, allocIDs, allgemPortIDs)
+		return allocID, gemPortIDs, techProfileInstance
+	default:
+		logger.Errorw("unknown-tech",
+			log.Fields{
+				"tpInst": tpInst})
+		return 0, nil, nil
 	}
 
-	allocIDs = appendUnique(allocIDs, allocID)
-	for _, gemPortID := range gemPortIDs {
-		allgemPortIDs = appendUnique(allgemPortIDs, gemPortID)
-	}
-
-	logger.Infow("allocated-tcont-and-gem-ports",
-		log.Fields{
-			"alloc-ids": allocIDs,
-			"gemports":  allgemPortIDs,
-			"device-id": f.deviceHandler.device.Id})
-	// Send Tconts and GEM ports to KV store
-	f.storeTcontsGEMPortsIntoKVStore(ctx, intfID, onuID, uniID, allocIDs, allgemPortIDs)
-	return allocID, gemPortIDs, techProfileInstance
 }
 
 func (f *OpenOltFlowMgr) storeTcontsGEMPortsIntoKVStore(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, allocID []uint32, gemPortIDs []uint32) {
@@ -2006,6 +2038,7 @@
 }
 
 //clearResources clears pon resources in kv store and the device
+// nolint: gocyclo
 func (f *OpenOltFlowMgr) clearResources(ctx context.Context, flow *ofp.OfpFlowStats, Intf uint32, onuID int32, uniID int32,
 	gemPortID int32, flowID uint32, flowDirection string,
 	portNum uint32, updatedFlows []rsrcMgr.FlowInfo) error {
@@ -2128,24 +2161,44 @@
 						"device-id":  f.deviceHandler.device.Id,
 						"gemport-id": gemPortID})
 			}
-
-			ok, _ := f.isTechProfileUsedByAnotherGem(ctx, Intf, uint32(onuID), uint32(uniID), tpID, techprofileInst, uint32(gemPortID))
-			if !ok {
+			switch techprofileInst := techprofileInst.(type) {
+			case *tp.TechProfile:
+				ok, _ := f.isTechProfileUsedByAnotherGem(ctx, Intf, uint32(onuID), uint32(uniID), tpID, techprofileInst, uint32(gemPortID))
+				if !ok {
+					f.resourceMgr.RemoveTechProfileIDForOnu(ctx, Intf, uint32(onuID), uint32(uniID), tpID)
+					f.DeleteTechProfileInstance(ctx, Intf, uint32(onuID), uint32(uniID), "", tpID)
+					f.RemoveSchedulerQueues(ctx, schedQueue{direction: tp_pb.Direction_UPSTREAM, intfID: Intf, onuID: uint32(onuID), uniID: uint32(uniID), tpID: tpID, uniPort: portNum, tpInst: techprofileInst})
+					f.RemoveSchedulerQueues(ctx, schedQueue{direction: tp_pb.Direction_DOWNSTREAM, intfID: Intf, onuID: uint32(onuID), uniID: uint32(uniID), tpID: tpID, uniPort: portNum, tpInst: techprofileInst})
+					f.resourceMgr.FreeAllocID(ctx, Intf, uint32(onuID), uint32(uniID), techprofileInst.UsScheduler.AllocID)
+					// Delete the TCONT on the ONU.
+					if err := f.sendDeleteTcontToChild(Intf, uint32(onuID), uint32(uniID), uint32(techprofileInst.UsScheduler.AllocID), tpPath); err != nil {
+						logger.Errorw("error-processing-delete-tcont-towards-onu",
+							log.Fields{
+								"intf":      Intf,
+								"onu-id":    onuID,
+								"uni-id":    uniID,
+								"device-id": f.deviceHandler.device.Id,
+								"alloc-id":  techprofileInst.UsScheduler.AllocID})
+					}
+				}
+			case *tp.EponProfile:
 				f.resourceMgr.RemoveTechProfileIDForOnu(ctx, Intf, uint32(onuID), uint32(uniID), tpID)
-				f.RemoveSchedulerQueues(ctx, schedQueue{direction: tp_pb.Direction_UPSTREAM, intfID: Intf, onuID: uint32(onuID), uniID: uint32(uniID), tpID: tpID, uniPort: portNum, tpInst: techprofileInst})
-				f.RemoveSchedulerQueues(ctx, schedQueue{direction: tp_pb.Direction_DOWNSTREAM, intfID: Intf, onuID: uint32(onuID), uniID: uint32(uniID), tpID: tpID, uniPort: portNum, tpInst: techprofileInst})
 				f.DeleteTechProfileInstance(ctx, Intf, uint32(onuID), uint32(uniID), "", tpID)
-				f.resourceMgr.FreeAllocID(ctx, Intf, uint32(onuID), uint32(uniID), techprofileInst.UsScheduler.AllocID)
+				f.resourceMgr.FreeAllocID(ctx, Intf, uint32(onuID), uint32(uniID), techprofileInst.AllocID)
 				// Delete the TCONT on the ONU.
-				if err := f.sendDeleteTcontToChild(Intf, uint32(onuID), uint32(uniID), uint32(techprofileInst.UsScheduler.AllocID), tpPath); err != nil {
+				if err := f.sendDeleteTcontToChild(Intf, uint32(onuID), uint32(uniID), uint32(techprofileInst.AllocID), tpPath); err != nil {
 					logger.Errorw("error-processing-delete-tcont-towards-onu",
 						log.Fields{
 							"intf":      Intf,
 							"onu-id":    onuID,
 							"uni-id":    uniID,
 							"device-id": f.deviceHandler.device.Id,
-							"alloc-id":  techprofileInst.UsScheduler.AllocID})
+							"alloc-id":  techprofileInst.AllocID})
 				}
+			default:
+				logger.Errorw("error-unknown-tech",
+					log.Fields{
+						"techprofileInst": techprofileInst})
 			}
 		}
 	}
@@ -3053,6 +3106,7 @@
 			"gem":      gemPortID}, err)
 }
 
+// nolint: gocyclo
 func installFlowOnAllGemports(ctx context.Context,
 	f1 func(ctx context.Context, intfId uint32, onuId uint32, uniId uint32,
 		portNo uint32, classifier map[string]interface{}, action map[string]interface{},
@@ -3065,7 +3119,7 @@
 	classifier map[string]interface{}, action map[string]interface{},
 	logicalFlow *ofp.OfpFlowStats,
 	gemPorts []uint32,
-	TpInst *tp.TechProfile,
+	TpInst interface{},
 	FlowType string,
 	direction string,
 	tpID uint32,
@@ -3085,35 +3139,90 @@
 	// the LSB position which marks the PCP bit consumed by the given gem port.
 	// This PCP bit now becomes a classifier in the flow.
 
-	attributes := TpInst.DownstreamGemPortAttributeList
-	if direction == Upstream {
-		attributes = TpInst.UpstreamGemPortAttributeList
-	}
-
-	for _, gemPortAttribute := range attributes {
-		if direction == Downstream && strings.ToUpper(gemPortAttribute.IsMulticast) == "TRUE" {
-			continue
+	switch TpInst := TpInst.(type) {
+	case *tp.TechProfile:
+		attributes := TpInst.DownstreamGemPortAttributeList
+		if direction == Upstream {
+			attributes = TpInst.UpstreamGemPortAttributeList
 		}
-		gemPortID := gemPortAttribute.GemportID
-		if allPbitsMarked(gemPortAttribute.PbitMap) {
-			classifier[VlanPcp] = uint32(VlanPCPMask)
-			if FlowType == DhcpFlow || FlowType == IgmpFlow || FlowType == HsiaFlow {
-				f1(ctx, args["intfId"], args["onuId"], args["uniId"], args["portNo"], classifier, action, logicalFlow, args["allocId"], gemPortID, tpID)
-			} else if FlowType == EapolFlow {
-				f2(ctx, args["intfId"], args["onuId"], args["uniId"], args["portNo"], classifier, action, logicalFlow, args["allocId"], gemPortID, vlanID[0], tpID)
+
+		for _, gemPortAttribute := range attributes {
+			if direction == Downstream && strings.ToUpper(gemPortAttribute.IsMulticast) == "TRUE" {
+				continue
 			}
-		} else {
-			for pos, pbitSet := range strings.TrimPrefix(gemPortAttribute.PbitMap, BinaryStringPrefix) {
-				if pbitSet == BinaryBit1 {
-					classifier[VlanPcp] = uint32(len(strings.TrimPrefix(gemPortAttribute.PbitMap, BinaryStringPrefix))) - 1 - uint32(pos)
+			gemPortID := gemPortAttribute.GemportID
+			if allPbitsMarked(gemPortAttribute.PbitMap) {
+				classifier[VlanPcp] = uint32(VlanPCPMask)
+				if FlowType == DhcpFlow || FlowType == IgmpFlow || FlowType == HsiaFlow {
+					f1(ctx, args["intfId"], args["onuId"], args["uniId"], args["portNo"], classifier, action, logicalFlow, args["allocId"], gemPortID, tpID)
+				} else if FlowType == EapolFlow {
+					f2(ctx, args["intfId"], args["onuId"], args["uniId"], args["portNo"], classifier, action, logicalFlow, args["allocId"], gemPortID, vlanID[0], tpID)
+				}
+			} else {
+				for pos, pbitSet := range strings.TrimPrefix(gemPortAttribute.PbitMap, BinaryStringPrefix) {
+					if pbitSet == BinaryBit1 {
+						classifier[VlanPcp] = uint32(len(strings.TrimPrefix(gemPortAttribute.PbitMap, BinaryStringPrefix))) - 1 - uint32(pos)
+						if FlowType == DhcpFlow || FlowType == IgmpFlow || FlowType == HsiaFlow {
+							f1(ctx, args["intfId"], args["onuId"], args["uniId"], args["portNo"], classifier, action, logicalFlow, args["allocId"], gemPortID, tpID)
+						} else if FlowType == EapolFlow {
+							f2(ctx, args["intfId"], args["onuId"], args["uniId"], args["portNo"], classifier, action, logicalFlow, args["allocId"], gemPortID, vlanID[0], tpID)
+						}
+					}
+				}
+			}
+		}
+	case *tp.EponProfile:
+		if direction == Upstream {
+			attributes := TpInst.UpstreamQueueAttributeList
+			for _, queueAttribute := range attributes {
+				gemPortID := queueAttribute.GemportID
+				if allPbitsMarked(queueAttribute.PbitMap) {
+					classifier[VlanPcp] = uint32(VlanPCPMask)
 					if FlowType == DhcpFlow || FlowType == IgmpFlow || FlowType == HsiaFlow {
 						f1(ctx, args["intfId"], args["onuId"], args["uniId"], args["portNo"], classifier, action, logicalFlow, args["allocId"], gemPortID, tpID)
 					} else if FlowType == EapolFlow {
 						f2(ctx, args["intfId"], args["onuId"], args["uniId"], args["portNo"], classifier, action, logicalFlow, args["allocId"], gemPortID, vlanID[0], tpID)
 					}
+				} else {
+					for pos, pbitSet := range strings.TrimPrefix(queueAttribute.PbitMap, BinaryStringPrefix) {
+						if pbitSet == BinaryBit1 {
+							classifier[VlanPcp] = uint32(len(strings.TrimPrefix(queueAttribute.PbitMap, BinaryStringPrefix))) - 1 - uint32(pos)
+							if FlowType == DhcpFlow || FlowType == IgmpFlow || FlowType == HsiaFlow {
+								f1(ctx, args["intfId"], args["onuId"], args["uniId"], args["portNo"], classifier, action, logicalFlow, args["allocId"], gemPortID, tpID)
+							} else if FlowType == EapolFlow {
+								f2(ctx, args["intfId"], args["onuId"], args["uniId"], args["portNo"], classifier, action, logicalFlow, args["allocId"], gemPortID, vlanID[0], tpID)
+							}
+						}
+					}
+				}
+			}
+		} else {
+			attributes := TpInst.DownstreamQueueAttributeList
+			for _, queueAttribute := range attributes {
+				gemPortID := queueAttribute.GemportID
+				if allPbitsMarked(queueAttribute.PbitMap) {
+					classifier[VlanPcp] = uint32(VlanPCPMask)
+					if FlowType == DhcpFlow || FlowType == IgmpFlow || FlowType == HsiaFlow {
+						f1(ctx, args["intfId"], args["onuId"], args["uniId"], args["portNo"], classifier, action, logicalFlow, args["allocId"], gemPortID, tpID)
+					} else if FlowType == EapolFlow {
+						f2(ctx, args["intfId"], args["onuId"], args["uniId"], args["portNo"], classifier, action, logicalFlow, args["allocId"], gemPortID, vlanID[0], tpID)
+					}
+				} else {
+					for pos, pbitSet := range strings.TrimPrefix(queueAttribute.PbitMap, BinaryStringPrefix) {
+						if pbitSet == BinaryBit1 {
+							classifier[VlanPcp] = uint32(len(strings.TrimPrefix(queueAttribute.PbitMap, BinaryStringPrefix))) - 1 - uint32(pos)
+							if FlowType == DhcpFlow || FlowType == IgmpFlow || FlowType == HsiaFlow {
+								f1(ctx, args["intfId"], args["onuId"], args["uniId"], args["portNo"], classifier, action, logicalFlow, args["allocId"], gemPortID, tpID)
+							} else if FlowType == EapolFlow {
+								f2(ctx, args["intfId"], args["onuId"], args["uniId"], args["portNo"], classifier, action, logicalFlow, args["allocId"], gemPortID, vlanID[0], tpID)
+							}
+						}
+					}
 				}
 			}
 		}
+	default:
+		logger.Errorw("unknown-tech", log.Fields{"tpInst": TpInst})
 	}
 }
 
@@ -3328,14 +3437,14 @@
 }
 
 func (f *OpenOltFlowMgr) checkAndAddFlow(ctx context.Context, args map[string]uint32, classifierInfo map[string]interface{},
-	actionInfo map[string]interface{}, flow *ofp.OfpFlowStats, TpInst *tp.TechProfile, gemPorts []uint32,
+	actionInfo map[string]interface{}, flow *ofp.OfpFlowStats, TpInst interface{}, gemPorts []uint32,
 	tpID uint32, uni string) {
 	var gemPort uint32
 	intfID := args[IntfID]
 	onuID := args[OnuID]
 	uniID := args[UniID]
 	portNo := args[PortNo]
-	allocID := TpInst.UsScheduler.AllocID
+	allocID := args[AllocID]
 	if ipProto, ok := classifierInfo[IPProto]; ok {
 		if ipProto.(uint32) == IPProtoDhcp {
 			logger.Infow("adding-dhcp-flow", log.Fields{
@@ -3474,7 +3583,7 @@
 		// still be used on other uni ports.
 		// So, we need to check and make sure that no other gem port is referring to the given TP ID
 		// on any other uni port.
-		tpInstances := f.techprofile[ponIntf].FindAllTpInstances(ctx, tpID, ponIntf, onuID)
+		tpInstances := f.techprofile[ponIntf].FindAllTpInstances(ctx, tpID, ponIntf, onuID).([]tp.TechProfile)
 		logger.Debugw("got-single-instance-tp-instances", log.Fields{"tp-instances": tpInstances})
 		for i := 0; i < len(tpInstances); i++ {
 			tpI := tpInstances[i]
diff --git a/internal/pkg/core/openolt_flowmgr_test.go b/internal/pkg/core/openolt_flowmgr_test.go
index 1e3dca3..4a74e9a 100644
--- a/internal/pkg/core/openolt_flowmgr_test.go
+++ b/internal/pkg/core/openolt_flowmgr_test.go
@@ -216,6 +216,54 @@
 
 }
 
+func TestOpenOltFlowMgr_createTcontGemports(t *testing.T) {
+	// flowMgr := newMockFlowmgr()
+	bands := make([]*ofp.OfpMeterBandHeader, 2)
+	bands[0] = &ofp.OfpMeterBandHeader{Type: ofp.OfpMeterBandType_OFPMBT_DROP, Rate: 1000, BurstSize: 5000, Data: &ofp.OfpMeterBandHeader_Drop{}}
+	bands[1] = &ofp.OfpMeterBandHeader{Type: ofp.OfpMeterBandType_OFPMBT_DROP, Rate: 2000, BurstSize: 5000, Data: &ofp.OfpMeterBandHeader_Drop{}}
+	ofpMeterConfig := &ofp.OfpMeterConfig{Flags: 1, MeterId: 1, Bands: bands}
+	flowmetadata := &voltha.FlowMetadata{
+		Meters: []*ofp.OfpMeterConfig{ofpMeterConfig},
+	}
+	type args struct {
+		intfID       uint32
+		onuID        uint32
+		uniID        uint32
+		uni          string
+		uniPort      uint32
+		TpID         uint32
+		UsMeterID    uint32
+		DsMeterID    uint32
+		flowMetadata *voltha.FlowMetadata
+	}
+	tests := []struct {
+		name string
+		args args
+	}{
+		{"createTcontGemports-1", args{intfID: 0, onuID: 1, uniID: 1, uni: "16", uniPort: 1, TpID: 64, UsMeterID: 1, DsMeterID: 1, flowMetadata: flowmetadata}},
+		{"createTcontGemports-1", args{intfID: 0, onuID: 1, uniID: 1, uni: "16", uniPort: 1, TpID: 65, UsMeterID: 1, DsMeterID: 1, flowMetadata: flowmetadata}},
+	}
+	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
+	defer cancel()
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			_, _, tpInst := flowMgr.createTcontGemports(ctx, tt.args.intfID, tt.args.onuID, tt.args.uniID, tt.args.uni, tt.args.uniPort, tt.args.TpID, tt.args.UsMeterID, tt.args.DsMeterID, tt.args.flowMetadata)
+			switch tpInst := tpInst.(type) {
+			case *tp.TechProfile:
+				if tt.args.TpID != 64 {
+					t.Errorf("OpenOltFlowMgr.createTcontGemports() error = different tech, tech %v", tpInst)
+				}
+			case *tp.EponProfile:
+				if tt.args.TpID != 65 {
+					t.Errorf("OpenOltFlowMgr.createTcontGemports() error = different tech, tech %v", tpInst)
+				}
+			default:
+				t.Errorf("OpenOltFlowMgr.createTcontGemports() error = different tech, tech %v", tpInst)
+			}
+		})
+	}
+}
+
 func TestOpenOltFlowMgr_RemoveFlow(t *testing.T) {
 	// flowMgr := newMockFlowmgr()
 	logger.Debug("Info Warning Error: Starting RemoveFlow() test")
diff --git a/pkg/mocks/mockTechprofile.go b/pkg/mocks/mockTechprofile.go
index 8937459..d47864c 100644
--- a/pkg/mocks/mockTechprofile.go
+++ b/pkg/mocks/mockTechprofile.go
@@ -19,6 +19,7 @@
 
 import (
 	"context"
+
 	"github.com/opencord/voltha-lib-go/v3/pkg/db"
 	tp "github.com/opencord/voltha-lib-go/v3/pkg/techprofile"
 	tp_pb "github.com/opencord/voltha-protos/v3/go/tech_profile"
@@ -41,24 +42,38 @@
 }
 
 // GetTPInstanceFromKVStore to mock techprofile GetTPInstanceFromKVStore method
-func (m MockTechProfile) GetTPInstanceFromKVStore(ctx context.Context, techProfiletblID uint32, path string) (*tp.TechProfile, error) {
+func (m MockTechProfile) GetTPInstanceFromKVStore(ctx context.Context, techProfiletblID uint32, path string) (interface{}, error) {
 	logger.Debug("Warning Warning Warning: GetTPInstanceFromKVStore")
 	return nil, nil
 
 }
 
 // CreateTechProfInstance to mock techprofile CreateTechProfInstance method
-func (m MockTechProfile) CreateTechProfInstance(ctx context.Context, techProfiletblID uint32, uniPortName string, intfID uint32) (*tp.TechProfile, error) {
+func (m MockTechProfile) CreateTechProfInstance(ctx context.Context, techProfiletblID uint32, uniPortName string, intfID uint32) (interface{}, error) {
 
-	return &tp.TechProfile{
-		Name:                           "mock-tech-profile",
-		SubscriberIdentifier:           "257",
-		ProfileType:                    "mock",
-		Version:                        0,
-		NumGemPorts:                    2,
-		UpstreamGemPortAttributeList:   nil,
-		DownstreamGemPortAttributeList: nil,
-	}, nil
+	if techProfiletblID == 64 {
+		return &tp.TechProfile{
+			Name:                           "mock-tech-profile",
+			SubscriberIdentifier:           "257",
+			ProfileType:                    "mock",
+			Version:                        0,
+			NumGemPorts:                    2,
+			UpstreamGemPortAttributeList:   nil,
+			DownstreamGemPortAttributeList: nil,
+		}, nil
+	} else if techProfiletblID == 65 {
+		return &tp.EponProfile{
+			Name:                         "mock-epon-profile",
+			SubscriberIdentifier:         "257",
+			ProfileType:                  "mock",
+			Version:                      0,
+			NumGemPorts:                  2,
+			UpstreamQueueAttributeList:   nil,
+			DownstreamQueueAttributeList: nil,
+		}, nil
+	} else {
+		return nil, nil
+	}
 
 }
 
@@ -102,11 +117,11 @@
 }
 
 // GetGemportIDForPbit to mock techprofile GetGemportIDForPbit method
-func (m MockTechProfile) GetGemportIDForPbit(tp *tp.TechProfile, Dir tp_pb.Direction, pbit uint32) uint32 {
+func (m MockTechProfile) GetGemportIDForPbit(tp interface{}, Dir tp_pb.Direction, pbit uint32) uint32 {
 	return 0
 }
 
 // FindAllTpInstances to mock techprofile FindAllTpInstances method
-func (m MockTechProfile) FindAllTpInstances(ctx context.Context, techProfiletblID uint32, ponIntf uint32, onuID uint32) []tp.TechProfile {
+func (m MockTechProfile) FindAllTpInstances(ctx context.Context, techProfiletblID uint32, ponIntf uint32, onuID uint32) interface{} {
 	return []tp.TechProfile{}
 }
diff --git a/vendor/github.com/opencord/voltha-lib-go/v3/pkg/techprofile/config.go b/vendor/github.com/opencord/voltha-lib-go/v3/pkg/techprofile/config.go
index fe3e4a2..fa2a6de 100644
--- a/vendor/github.com/opencord/voltha-lib-go/v3/pkg/techprofile/config.go
+++ b/vendor/github.com/opencord/voltha-lib-go/v3/pkg/techprofile/config.go
@@ -72,6 +72,23 @@
 	SCHEDULING_POLICY                  = "scheduling_policy"
 	MAX_Q_SIZE                         = "max_q_size"
 	AES_ENCRYPTION                     = "aes_encryption"
+	// String Keys for EPON
+	EPON_ATTRIBUTE              = "epon_attribute"
+	PACKAGE_TYPE                = "package_type"
+	TRAFFIC_TYPE                = "traffic type"
+	UNSOLICITED_GRANT_SIZE      = "unsolicited_grant_size"
+	NOMINAL_INTERVAL            = "nominal_interval"
+	TOLERATED_POLL_JITTER       = "tolerated_poll_jitter"
+	REQUEST_TRANSMISSION_POLICY = "request_transmission_policy"
+	NUM_Q_SETS                  = "num_q_sets"
+	Q_THRESHOLDS                = "q_thresholds"
+	Q_THRESHOLD1                = "q_threshold1"
+	Q_THRESHOLD2                = "q_threshold2"
+	Q_THRESHOLD3                = "q_threshold3"
+	Q_THRESHOLD4                = "q_threshold4"
+	Q_THRESHOLD5                = "q_threshold5"
+	Q_THRESHOLD6                = "q_threshold6"
+	Q_THRESHOLD7                = "q_threshold7"
 )
 
 // TechprofileFlags represents the set of configurations used
diff --git a/vendor/github.com/opencord/voltha-lib-go/v3/pkg/techprofile/tech_profile.go b/vendor/github.com/opencord/voltha-lib-go/v3/pkg/techprofile/tech_profile.go
index 60e4dae..492c9e8 100644
--- a/vendor/github.com/opencord/voltha-lib-go/v3/pkg/techprofile/tech_profile.go
+++ b/vendor/github.com/opencord/voltha-lib-go/v3/pkg/techprofile/tech_profile.go
@@ -105,19 +105,19 @@
 var uniPortNameFormat = regexp.MustCompile(`^olt-{[a-z0-9\-]+}/pon-{[0-9]+}/onu-{[0-9]+}/uni-{[0-9]+}$`)
 
 /*
-type InferredAdditionBWIndication int32
+  type InferredAdditionBWIndication int32
 
-const (
-	InferredAdditionBWIndication_InferredAdditionBWIndication_None       InferredAdditionBWIndication = 0
-	InferredAdditionBWIndication_InferredAdditionBWIndication_Assured    InferredAdditionBWIndication = 1
-	InferredAdditionBWIndication_InferredAdditionBWIndication_BestEffort InferredAdditionBWIndication = 2
-)
+  const (
+	  InferredAdditionBWIndication_InferredAdditionBWIndication_None       InferredAdditionBWIndication = 0
+	  InferredAdditionBWIndication_InferredAdditionBWIndication_Assured    InferredAdditionBWIndication = 1
+	  InferredAdditionBWIndication_InferredAdditionBWIndication_BestEffort InferredAdditionBWIndication = 2
+  )
 
-var InferredAdditionBWIndication_name = map[int32]string{
-	0: "InferredAdditionBWIndication_None",
-	1: "InferredAdditionBWIndication_Assured",
-	2: "InferredAdditionBWIndication_BestEffort",
-}
+  var InferredAdditionBWIndication_name = map[int32]string{
+	  0: "InferredAdditionBWIndication_None",
+	  1: "InferredAdditionBWIndication_Assured",
+	  2: "InferredAdditionBWIndication_BestEffort",
+  }
 */
 // instance control defaults
 const (
@@ -245,6 +245,141 @@
 	DownstreamGemPortAttributeList []iGemPortAttribute `json:"downstream_gem_port_attribute_list"`
 }
 
+// QThresholds struct for EPON
+type QThresholds struct {
+	QThreshold1 uint32 `json:"q_threshold1"`
+	QThreshold2 uint32 `json:"q_threshold2"`
+	QThreshold3 uint32 `json:"q_threshold3"`
+	QThreshold4 uint32 `json:"q_threshold4"`
+	QThreshold5 uint32 `json:"q_threshold5"`
+	QThreshold6 uint32 `json:"q_threshold6"`
+	QThreshold7 uint32 `json:"q_threshold7"`
+}
+
+// UpstreamQueueAttribute struct for EPON
+type UpstreamQueueAttribute struct {
+	MaxQueueSize              string        `json:"max_q_size"`
+	PbitMap                   string        `json:"pbit_map"`
+	AesEncryption             string        `json:"aes_encryption"`
+	TrafficType               string        `json:"traffic_type"`
+	UnsolicitedGrantSize      uint32        `json:"unsolicited_grant_size"`
+	NominalInterval           uint32        `json:"nominal_interval"`
+	ToleratedPollJitter       uint32        `json:"tolerated_poll_jitter"`
+	RequestTransmissionPolicy uint32        `json:"request_transmission_policy"`
+	NumQueueSet               uint32        `json:"num_q_sets"`
+	QThresholds               QThresholds   `json:"q_thresholds"`
+	SchedulingPolicy          string        `json:"scheduling_policy"`
+	PriorityQueue             uint32        `json:"priority_q"`
+	Weight                    uint32        `json:"weight"`
+	DiscardPolicy             string        `json:"discard_policy"`
+	DiscardConfig             DiscardConfig `json:"discard_config"`
+}
+
+// Default EPON constants
+const (
+	defaultPakageType = "B"
+)
+const (
+	defaultTrafficType               = "BE"
+	defaultUnsolicitedGrantSize      = 0
+	defaultNominalInterval           = 0
+	defaultToleratedPollJitter       = 0
+	defaultRequestTransmissionPolicy = 0
+	defaultNumQueueSet               = 2
+)
+const (
+	defaultQThreshold1 = 5500
+	defaultQThreshold2 = 0
+	defaultQThreshold3 = 0
+	defaultQThreshold4 = 0
+	defaultQThreshold5 = 0
+	defaultQThreshold6 = 0
+	defaultQThreshold7 = 0
+)
+
+// DownstreamQueueAttribute struct for EPON
+type DownstreamQueueAttribute struct {
+	MaxQueueSize     string        `json:"max_q_size"`
+	PbitMap          string        `json:"pbit_map"`
+	AesEncryption    string        `json:"aes_encryption"`
+	SchedulingPolicy string        `json:"scheduling_policy"`
+	PriorityQueue    uint32        `json:"priority_q"`
+	Weight           uint32        `json:"weight"`
+	DiscardPolicy    string        `json:"discard_policy"`
+	DiscardConfig    DiscardConfig `json:"discard_config"`
+}
+
+// iUpstreamQueueAttribute struct for EPON
+type iUpstreamQueueAttribute struct {
+	GemportID                 uint32        `json:"q_id"`
+	MaxQueueSize              string        `json:"max_q_size"`
+	PbitMap                   string        `json:"pbit_map"`
+	AesEncryption             string        `json:"aes_encryption"`
+	TrafficType               string        `json:"traffic_type"`
+	UnsolicitedGrantSize      uint32        `json:"unsolicited_grant_size"`
+	NominalInterval           uint32        `json:"nominal_interval"`
+	ToleratedPollJitter       uint32        `json:"tolerated_poll_jitter"`
+	RequestTransmissionPolicy uint32        `json:"request_transmission_policy"`
+	NumQueueSet               uint32        `json:"num_q_sets"`
+	QThresholds               QThresholds   `json:"q_thresholds"`
+	SchedulingPolicy          string        `json:"scheduling_policy"`
+	PriorityQueue             uint32        `json:"priority_q"`
+	Weight                    uint32        `json:"weight"`
+	DiscardPolicy             string        `json:"discard_policy"`
+	DiscardConfig             DiscardConfig `json:"discard_config"`
+}
+
+// iDownstreamQueueAttribute struct for EPON
+type iDownstreamQueueAttribute struct {
+	GemportID        uint32        `json:"q_id"`
+	MaxQueueSize     string        `json:"max_q_size"`
+	PbitMap          string        `json:"pbit_map"`
+	AesEncryption    string        `json:"aes_encryption"`
+	SchedulingPolicy string        `json:"scheduling_policy"`
+	PriorityQueue    uint32        `json:"priority_q"`
+	Weight           uint32        `json:"weight"`
+	DiscardPolicy    string        `json:"discard_policy"`
+	DiscardConfig    DiscardConfig `json:"discard_config"`
+}
+
+// EponAttribute struct for EPON
+type EponAttribute struct {
+	PackageType string `json:"pakage_type"`
+}
+
+// DefaultTechProfile struct for EPON
+type DefaultEponProfile struct {
+	Name                         string                     `json:"name"`
+	ProfileType                  string                     `json:"profile_type"`
+	Version                      int                        `json:"version"`
+	NumGemPorts                  uint32                     `json:"num_gem_ports"`
+	InstanceCtrl                 InstanceControl            `json:"instance_control"`
+	EponAttribute                EponAttribute              `json:"epon_attribute"`
+	UpstreamQueueAttributeList   []UpstreamQueueAttribute   `json:"upstream_queue_attribute_list"`
+	DownstreamQueueAttributeList []DownstreamQueueAttribute `json:"downstream_queue_attribute_list"`
+}
+
+// TechProfile struct for EPON
+type EponProfile struct {
+	Name                         string                      `json:"name"`
+	SubscriberIdentifier         string                      `json:"subscriber_identifier"`
+	ProfileType                  string                      `json:"profile_type"`
+	Version                      int                         `json:"version"`
+	NumGemPorts                  uint32                      `json:"num_gem_ports"`
+	InstanceCtrl                 InstanceControl             `json:"instance_control"`
+	EponAttribute                EponAttribute               `json:"epon_attribute"`
+	AllocID                      uint32                      `json:"llid"`
+	UpstreamQueueAttributeList   []iUpstreamQueueAttribute   `json:"upstream_queue_attribute_list"`
+	DownstreamQueueAttributeList []iDownstreamQueueAttribute `json:"downstream_queue_attribute_list"`
+}
+
+const (
+	xgspon      = "xgspon"
+	xgsponBbsim = "XGS-PON"
+	gpon        = "gpon"
+	epon        = "EPON"
+)
+
 func (t *TechProfileMgr) SetKVClient() *db.Backend {
 	kvClient, err := newKVClient(t.config.KVStoreType, t.config.KVStoreAddress, t.config.KVStoreTimeout)
 	if err != nil {
@@ -264,9 +399,9 @@
 		PathPrefix: t.config.TPKVPathPrefix}
 
 	/* 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
-		   kv := model.NewBackend(t.config.KVStoreType, t.config.KVStoreHost, t.config.KVStorePort,
-										t.config.KVStoreTimeout,  kvStoreTechProfilePathPrefix)
+		  issue between kv store and backend , core is not calling NewBackend directly
+	 kv := model.NewBackend(t.config.KVStoreType, t.config.KVStoreHost, t.config.KVStorePort,
+								  t.config.KVStoreTimeout,  kvStoreTechProfilePathPrefix)
 	*/
 }
 
@@ -304,22 +439,34 @@
 	return fmt.Sprintf(t.config.TPInstanceKVPath, t.resourceMgr.GetTechnology(), techProfiletblID, uniPortName)
 }
 
-func (t *TechProfileMgr) GetTPInstanceFromKVStore(ctx context.Context, techProfiletblID uint32, path string) (*TechProfile, error) {
-	var KvTpIns TechProfile
-	var resPtr *TechProfile = &KvTpIns
+func (t *TechProfileMgr) GetTPInstanceFromKVStore(ctx context.Context, techProfiletblID uint32, path string) (interface{}, error) {
 	var err error
 	var kvResult *kvstore.KVPair
-
-	logger.Infow("get-tp-instance-form-kv-store", log.Fields{"path": path, "tpid": techProfiletblID})
+	var KvTpIns TechProfile
+	var KvEponIns EponProfile
+	var resPtr interface{}
+	// For example:
+	// tpInstPath like "XGS-PON/64/uni_port_name"
+	// is broken into ["XGS-PON" "64" ...]
+	pathSlice := regexp.MustCompile(`/`).Split(path, -1)
+	switch pathSlice[0] {
+	case xgspon, xgsponBbsim, gpon:
+		resPtr = &KvTpIns
+	case epon:
+		resPtr = &KvEponIns
+	default:
+		log.Errorw("unknown-tech", log.Fields{"tech": pathSlice[0]})
+		return nil, fmt.Errorf("unknown-tech-%s", pathSlice[0])
+	}
 
 	kvResult, _ = t.config.KVBackend.Get(ctx, path)
 	if kvResult == nil {
-		logger.Infow("tp-instance-not-found-on-kv", log.Fields{"key": path})
+		log.Infow("tp-instance-not-found-on-kv", log.Fields{"key": path})
 		return nil, nil
 	} else {
 		if value, err := kvstore.ToByte(kvResult.Value); err == nil {
 			if err = json.Unmarshal(value, resPtr); err != nil {
-				logger.Errorw("error-unmarshal-kv-result", log.Fields{"key": path, "value": value})
+				log.Errorw("error-unmarshal-kv-result", log.Fields{"key": path, "value": value})
 				return nil, errors.New("error-unmarshal-kv-result")
 			} else {
 				return resPtr, nil
@@ -342,6 +489,21 @@
 	}
 	return err
 }
+
+func (t *TechProfileMgr) addEponProfInstanceToKVStore(ctx context.Context, techProfiletblID uint32, uniPortName string, tpInstance *EponProfile) error {
+	path := t.GetTechProfileInstanceKVPath(techProfiletblID, uniPortName)
+	logger.Debugw("Adding techprof instance to kvstore", log.Fields{"key": path, "tpinstance": tpInstance})
+	tpInstanceJson, err := json.Marshal(*tpInstance)
+	if err == nil {
+		// Backend will convert JSON byte array into string format
+		logger.Debugw("Storing tech profile instance to KV Store", log.Fields{"key": path, "val": tpInstanceJson})
+		err = t.config.KVBackend.Put(ctx, path, tpInstanceJson)
+	} else {
+		logger.Errorw("Error in marshaling into Json format", log.Fields{"key": path, "tpinstance": tpInstance})
+	}
+	return err
+}
+
 func (t *TechProfileMgr) getTPFromKVStore(ctx context.Context, techProfiletblID uint32) *DefaultTechProfile {
 	var kvtechprofile DefaultTechProfile
 	key := fmt.Sprintf(t.config.TPFileKVPath, t.resourceMgr.GetTechnology(), techProfiletblID)
@@ -366,8 +528,34 @@
 	return nil
 }
 
-func (t *TechProfileMgr) CreateTechProfInstance(ctx context.Context, techProfiletblID uint32, uniPortName string, intfId uint32) (*TechProfile, error) {
+func (t *TechProfileMgr) getEponTPFromKVStore(ctx context.Context, techProfiletblID uint32) *DefaultEponProfile {
+	var kvtechprofile DefaultEponProfile
+	key := fmt.Sprintf(t.config.TPFileKVPath, t.resourceMgr.GetTechnology(), techProfiletblID)
+	logger.Debugw("Getting techprofile from KV store", log.Fields{"techProfiletblID": techProfiletblID, "Key": key})
+	kvresult, err := t.config.KVBackend.Get(ctx, key)
+	if err != nil {
+		logger.Errorw("Error while fetching value from KV store", log.Fields{"key": key})
+		return nil
+	}
+	if kvresult != nil {
+		/* Backend will return Value in string format,needs to be converted to []byte before unmarshal*/
+		if value, err := kvstore.ToByte(kvresult.Value); err == nil {
+			if err = json.Unmarshal(value, &kvtechprofile); err != nil {
+				logger.Errorw("Error unmarshaling techprofile fetched from KV store", log.Fields{"techProfiletblID": techProfiletblID, "error": err, "techprofile_json": value})
+				return nil
+			}
+
+			logger.Debugw("Success fetched techprofile from KV store", log.Fields{"techProfiletblID": techProfiletblID, "value": kvtechprofile})
+			return &kvtechprofile
+		}
+	}
+	return nil
+}
+
+func (t *TechProfileMgr) CreateTechProfInstance(ctx context.Context, techProfiletblID uint32, uniPortName string, intfId uint32) (interface{}, error) {
 	var tpInstance *TechProfile
+	var tpEponInstance *EponProfile
+
 	logger.Infow("creating-tp-instance", log.Fields{"tableid": techProfiletblID, "uni": uniPortName, "intId": intfId})
 
 	// Make sure the uniPortName is as per format pon-{[0-9]+}/onu-{[0-9]+}/uni-{[0-9]+}
@@ -375,31 +563,62 @@
 		logger.Errorw("uni-port-name-not-confirming-to-format", log.Fields{"uniPortName": uniPortName})
 		return nil, errors.New("uni-port-name-not-confirming-to-format")
 	}
-
-	tp := t.getTPFromKVStore(ctx, techProfiletblID)
-	if tp != nil {
-		if err := t.validateInstanceControlAttr(tp.InstanceCtrl); err != nil {
-			logger.Error("invalid-instance-ctrl-attr--using-default-tp")
-			tp = t.getDefaultTechProfile()
-		} else {
-			logger.Infow("using-specified-tp-from-kv-store", log.Fields{"tpid": techProfiletblID})
-		}
-	} else {
-		logger.Info("tp-not-found-on-kv--creating-default-tp")
-		tp = t.getDefaultTechProfile()
-	}
 	tpInstancePath := t.GetTechProfileInstanceKVPath(techProfiletblID, uniPortName)
-	if tpInstance = t.allocateTPInstance(ctx, uniPortName, tp, intfId, tpInstancePath); tpInstance == nil {
-		logger.Error("tp-intance-allocation-failed")
-		return nil, errors.New("tp-intance-allocation-failed")
+	// For example:
+	// tpInstPath like "XGS-PON/64/uni_port_name"
+	// is broken into ["XGS-PON" "64" ...]
+	pathSlice := regexp.MustCompile(`/`).Split(tpInstancePath, -1)
+	if pathSlice[0] == epon {
+		tp := t.getEponTPFromKVStore(ctx, techProfiletblID)
+		if tp != nil {
+			if err := t.validateInstanceControlAttr(tp.InstanceCtrl); err != nil {
+				logger.Error("invalid-instance-ctrl-attr--using-default-tp")
+				tp = t.getDefaultEponProfile()
+			} else {
+				logger.Infow("using-specified-tp-from-kv-store", log.Fields{"tpid": techProfiletblID})
+			}
+		} else {
+			logger.Info("tp-not-found-on-kv--creating-default-tp")
+			tp = t.getDefaultEponProfile()
+		}
+
+		if tpEponInstance = t.allocateEponTPInstance(ctx, uniPortName, tp, intfId, tpInstancePath); tpEponInstance == nil {
+			logger.Error("tp-intance-allocation-failed")
+			return nil, errors.New("tp-intance-allocation-failed")
+		}
+		if err := t.addEponProfInstanceToKVStore(ctx, techProfiletblID, uniPortName, tpEponInstance); err != nil {
+			logger.Errorw("error-adding-tp-to-kv-store", log.Fields{"tableid": techProfiletblID, "uni": uniPortName})
+			return nil, errors.New("error-adding-tp-to-kv-store")
+		}
+		logger.Infow("tp-added-to-kv-store-successfully",
+			log.Fields{"tpid": techProfiletblID, "uni": uniPortName, "intfId": intfId})
+		return tpEponInstance, nil
+	} else {
+		tp := t.getTPFromKVStore(ctx, techProfiletblID)
+		if tp != nil {
+			if err := t.validateInstanceControlAttr(tp.InstanceCtrl); err != nil {
+				logger.Error("invalid-instance-ctrl-attr--using-default-tp")
+				tp = t.getDefaultTechProfile()
+			} else {
+				logger.Infow("using-specified-tp-from-kv-store", log.Fields{"tpid": techProfiletblID})
+			}
+		} else {
+			logger.Info("tp-not-found-on-kv--creating-default-tp")
+			tp = t.getDefaultTechProfile()
+		}
+
+		if tpInstance = t.allocateTPInstance(ctx, uniPortName, tp, intfId, tpInstancePath); tpInstance == nil {
+			logger.Error("tp-intance-allocation-failed")
+			return nil, errors.New("tp-intance-allocation-failed")
+		}
+		if err := t.addTechProfInstanceToKVStore(ctx, techProfiletblID, uniPortName, tpInstance); err != nil {
+			logger.Errorw("error-adding-tp-to-kv-store", log.Fields{"tableid": techProfiletblID, "uni": uniPortName})
+			return nil, errors.New("error-adding-tp-to-kv-store")
+		}
+		logger.Infow("tp-added-to-kv-store-successfully",
+			log.Fields{"tpid": techProfiletblID, "uni": uniPortName, "intfId": intfId})
+		return tpInstance, nil
 	}
-	if err := t.addTechProfInstanceToKVStore(ctx, techProfiletblID, uniPortName, tpInstance); err != nil {
-		logger.Errorw("error-adding-tp-to-kv-store", log.Fields{"tableid": techProfiletblID, "uni": uniPortName})
-		return nil, errors.New("error-adding-tp-to-kv-store")
-	}
-	logger.Infow("tp-added-to-kv-store-successfully",
-		log.Fields{"tpid": techProfiletblID, "uni": uniPortName, "intfId": intfId})
-	return tpInstance, nil
 }
 
 func (t *TechProfileMgr) DeleteTechProfileInstance(ctx context.Context, techProfiletblID uint32, uniPortName string) error {
@@ -561,6 +780,91 @@
 		DownstreamGemPortAttributeList: dsGemPortAttributeList}
 }
 
+// allocateTPInstance function for EPON
+func (t *TechProfileMgr) allocateEponTPInstance(ctx context.Context, uniPortName string, tp *DefaultEponProfile, intfId uint32, tpInstPath string) *EponProfile {
+
+	var usQueueAttributeList []iUpstreamQueueAttribute
+	var dsQueueAttributeList []iDownstreamQueueAttribute
+	var tcontIDs []uint32
+	var gemPorts []uint32
+	var err error
+
+	log.Infow("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 {
+			log.Errorw("Error getting alloc id from rsrcrMgr", log.Fields{"intfId": intfId})
+			return nil
+		}
+	} else { // "single-instance"
+		if tpInst, err := t.getSingleInstanceEponTp(ctx, tpInstPath); err != nil {
+			log.Errorw("Error getting alloc id from rsrcrMgr", log.Fields{"intfId": intfId})
+			return nil
+		} 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 {
+				log.Errorw("Error getting alloc id from rsrcrMgr", log.Fields{"intfId": intfId})
+				return nil
+			}
+		} else {
+			// Use the alloc-id from the existing TpInstance
+			tcontIDs = append(tcontIDs, tpInst.AllocID)
+		}
+	}
+	log.Debugw("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 {
+		log.Errorw("Error getting gemport ids from rsrcrMgr", log.Fields{"intfId": intfId, "numGemports": tp.NumGemPorts})
+		return nil
+	}
+	log.Infow("Allocated tconts and GEM ports successfully", log.Fields{"tconts": tcontIDs, "gemports": gemPorts})
+	for index := 0; index < int(tp.NumGemPorts); index++ {
+		usQueueAttributeList = append(usQueueAttributeList,
+			iUpstreamQueueAttribute{GemportID: gemPorts[index],
+				MaxQueueSize:              tp.UpstreamQueueAttributeList[index].MaxQueueSize,
+				PbitMap:                   tp.UpstreamQueueAttributeList[index].PbitMap,
+				AesEncryption:             tp.UpstreamQueueAttributeList[index].AesEncryption,
+				TrafficType:               tp.UpstreamQueueAttributeList[index].TrafficType,
+				UnsolicitedGrantSize:      tp.UpstreamQueueAttributeList[index].UnsolicitedGrantSize,
+				NominalInterval:           tp.UpstreamQueueAttributeList[index].NominalInterval,
+				ToleratedPollJitter:       tp.UpstreamQueueAttributeList[index].ToleratedPollJitter,
+				RequestTransmissionPolicy: tp.UpstreamQueueAttributeList[index].RequestTransmissionPolicy,
+				NumQueueSet:               tp.UpstreamQueueAttributeList[index].NumQueueSet,
+				QThresholds:               tp.UpstreamQueueAttributeList[index].QThresholds,
+				SchedulingPolicy:          tp.UpstreamQueueAttributeList[index].SchedulingPolicy,
+				PriorityQueue:             tp.UpstreamQueueAttributeList[index].PriorityQueue,
+				Weight:                    tp.UpstreamQueueAttributeList[index].Weight,
+				DiscardPolicy:             tp.UpstreamQueueAttributeList[index].DiscardPolicy,
+				DiscardConfig:             tp.UpstreamQueueAttributeList[index].DiscardConfig})
+	}
+
+	log.Info("length of DownstreamGemPortAttributeList", len(tp.DownstreamQueueAttributeList))
+	for index := 0; index < int(tp.NumGemPorts); index++ {
+		dsQueueAttributeList = append(dsQueueAttributeList,
+			iDownstreamQueueAttribute{GemportID: gemPorts[index],
+				MaxQueueSize:     tp.DownstreamQueueAttributeList[index].MaxQueueSize,
+				PbitMap:          tp.DownstreamQueueAttributeList[index].PbitMap,
+				AesEncryption:    tp.DownstreamQueueAttributeList[index].AesEncryption,
+				SchedulingPolicy: tp.DownstreamQueueAttributeList[index].SchedulingPolicy,
+				PriorityQueue:    tp.DownstreamQueueAttributeList[index].PriorityQueue,
+				Weight:           tp.DownstreamQueueAttributeList[index].Weight,
+				DiscardPolicy:    tp.DownstreamQueueAttributeList[index].DiscardPolicy,
+				DiscardConfig:    tp.DownstreamQueueAttributeList[index].DiscardConfig})
+	}
+
+	return &EponProfile{
+		SubscriberIdentifier:         uniPortName,
+		Name:                         tp.Name,
+		ProfileType:                  tp.ProfileType,
+		Version:                      tp.Version,
+		NumGemPorts:                  tp.NumGemPorts,
+		InstanceCtrl:                 tp.InstanceCtrl,
+		EponAttribute:                tp.EponAttribute,
+		AllocID:                      tcontIDs[0],
+		UpstreamQueueAttributeList:   usQueueAttributeList,
+		DownstreamQueueAttributeList: dsQueueAttributeList}
+}
+
 // getSingleInstanceTp returns another TpInstance for an ONU on a different
 // uni port for the same TP ID, if it finds one, else nil.
 func (t *TechProfileMgr) getSingleInstanceTp(ctx context.Context, tpPath string) (*TechProfile, error) {
@@ -587,6 +891,30 @@
 	return nil, nil
 }
 
+func (t *TechProfileMgr) getSingleInstanceEponTp(ctx context.Context, tpPath string) (*EponProfile, error) {
+	var tpInst EponProfile
+
+	// For example:
+	// tpPath like "service/voltha/technology_profiles/xgspon/64/pon-{0}/onu-{1}/uni-{1}"
+	// is broken into ["service/voltha/technology_profiles/xgspon/64/pon-{0}/onu-{1}" ""]
+	uniPathSlice := regexp.MustCompile(`/uni-{[0-9]+}$`).Split(tpPath, 2)
+	kvPairs, _ := t.config.KVBackend.List(ctx, uniPathSlice[0])
+
+	// Find a valid TP Instance among all the UNIs of that ONU for the given TP ID
+	for keyPath, kvPair := range kvPairs {
+		if value, err := kvstore.ToByte(kvPair.Value); err == nil {
+			if err = json.Unmarshal(value, &tpInst); err != nil {
+				logger.Errorw("error-unmarshal-kv-pair", log.Fields{"keyPath": keyPath, "value": value})
+				return nil, errors.New("error-unmarshal-kv-pair")
+			} else {
+				logger.Debugw("found-valid-tp-instance-on-another-uni", log.Fields{"keyPath": keyPath})
+				return &tpInst, nil
+			}
+		}
+	}
+	return nil, nil
+}
+
 func (t *TechProfileMgr) getDefaultTechProfile() *DefaultTechProfile {
 
 	var usGemPortAttributeList []GemPortAttribute
@@ -650,6 +978,70 @@
 		DownstreamGemPortAttributeList: dsGemPortAttributeList}
 }
 
+// getDefaultTechProfile function for EPON
+func (t *TechProfileMgr) getDefaultEponProfile() *DefaultEponProfile {
+
+	var usQueueAttributeList []UpstreamQueueAttribute
+	var dsQueueAttributeList []DownstreamQueueAttribute
+
+	for _, pbit := range t.config.DefaultPbits {
+		log.Debugw("Creating Queue", log.Fields{"pbit": pbit})
+		usQueueAttributeList = append(usQueueAttributeList,
+			UpstreamQueueAttribute{
+				MaxQueueSize:              defaultMaxQueueSize,
+				PbitMap:                   pbit,
+				AesEncryption:             defaultAESEncryption,
+				TrafficType:               defaultTrafficType,
+				UnsolicitedGrantSize:      defaultUnsolicitedGrantSize,
+				NominalInterval:           defaultNominalInterval,
+				ToleratedPollJitter:       defaultToleratedPollJitter,
+				RequestTransmissionPolicy: defaultRequestTransmissionPolicy,
+				NumQueueSet:               defaultNumQueueSet,
+				QThresholds: QThresholds{
+					QThreshold1: defaultQThreshold1,
+					QThreshold2: defaultQThreshold2,
+					QThreshold3: defaultQThreshold3,
+					QThreshold4: defaultQThreshold4,
+					QThreshold5: defaultQThreshold5,
+					QThreshold6: defaultQThreshold6,
+					QThreshold7: defaultQThreshold7},
+				SchedulingPolicy: SchedulingPolicy_name[defaultSchedulePolicy],
+				PriorityQueue:    defaultPriorityQueue,
+				Weight:           defaultQueueWeight,
+				DiscardPolicy:    DiscardPolicy_name[defaultdropPolicy],
+				DiscardConfig: DiscardConfig{
+					MinThreshold:   defaultMinThreshold,
+					MaxThreshold:   defaultMaxThreshold,
+					MaxProbability: defaultMaxProbability}})
+		dsQueueAttributeList = append(dsQueueAttributeList,
+			DownstreamQueueAttribute{
+				MaxQueueSize:     defaultMaxQueueSize,
+				PbitMap:          pbit,
+				AesEncryption:    defaultAESEncryption,
+				SchedulingPolicy: SchedulingPolicy_name[defaultSchedulePolicy],
+				PriorityQueue:    defaultPriorityQueue,
+				Weight:           defaultQueueWeight,
+				DiscardPolicy:    DiscardPolicy_name[defaultdropPolicy],
+				DiscardConfig: DiscardConfig{
+					MinThreshold:   defaultMinThreshold,
+					MaxThreshold:   defaultMaxThreshold,
+					MaxProbability: defaultMaxProbability}})
+	}
+	return &DefaultEponProfile{
+		Name:        t.config.DefaultTPName,
+		ProfileType: t.resourceMgr.GetTechnology(),
+		Version:     t.config.TPVersion,
+		NumGemPorts: uint32(len(usQueueAttributeList)),
+		InstanceCtrl: InstanceControl{
+			Onu:               defaultOnuInstance,
+			Uni:               defaultUniInstance,
+			MaxGemPayloadSize: defaultGemPayloadSize},
+		EponAttribute: EponAttribute{
+			PackageType: defaultPakageType},
+		UpstreamQueueAttributeList:   usQueueAttributeList,
+		DownstreamQueueAttributeList: dsQueueAttributeList}
+}
+
 func (t *TechProfileMgr) GetprotoBufParamValue(paramType string, paramKey string) int32 {
 	var result int32 = -1
 
@@ -880,65 +1272,128 @@
 		Scheduler: UsScheduler}
 }
 
-func (t *TechProfileMgr) GetGemportIDForPbit(tp *TechProfile, dir tp_pb.Direction, pbit uint32) uint32 {
+func (t *TechProfileMgr) GetGemportIDForPbit(tp interface{}, dir tp_pb.Direction, pbit uint32) uint32 {
 	/*
-	   Function to get the Gemport ID mapped to a pbit.
+	  Function to get the Gemport ID mapped to a pbit.
 	*/
-	if dir == tp_pb.Direction_UPSTREAM {
-		// upstream GEM ports
-		numGemPorts := len(tp.UpstreamGemPortAttributeList)
-		for gemCnt := 0; gemCnt < numGemPorts; gemCnt++ {
-			lenOfPbitMap := len(tp.UpstreamGemPortAttributeList[gemCnt].PbitMap)
-			for pbitMapIdx := 2; pbitMapIdx < lenOfPbitMap; pbitMapIdx++ {
-				// Given a sample pbit map string "0b00000001", lenOfPbitMap is 10
-				// "lenOfPbitMap - pbitMapIdx + 1" will give pbit-i th value from LSB position in the pbit map string
-				if p, err := strconv.Atoi(string(tp.UpstreamGemPortAttributeList[gemCnt].PbitMap[lenOfPbitMap-pbitMapIdx+1])); err == nil {
-					if uint32(pbitMapIdx-2) == pbit && p == 1 { // Check this p-bit is set
-						logger.Debugw("Found-US-GEMport-for-Pcp", log.Fields{"pbit": pbit, "GEMport": tp.UpstreamGemPortAttributeList[gemCnt].GemportID})
-						return tp.UpstreamGemPortAttributeList[gemCnt].GemportID
+	switch tp := tp.(type) {
+	case *TechProfile:
+		if dir == tp_pb.Direction_UPSTREAM {
+			// upstream GEM ports
+			numGemPorts := len(tp.UpstreamGemPortAttributeList)
+			for gemCnt := 0; gemCnt < numGemPorts; gemCnt++ {
+				lenOfPbitMap := len(tp.UpstreamGemPortAttributeList[gemCnt].PbitMap)
+				for pbitMapIdx := 2; pbitMapIdx < lenOfPbitMap; pbitMapIdx++ {
+					// Given a sample pbit map string "0b00000001", lenOfPbitMap is 10
+					// "lenOfPbitMap - pbitMapIdx + 1" will give pbit-i th value from LSB position in the pbit map string
+					if p, err := strconv.Atoi(string(tp.UpstreamGemPortAttributeList[gemCnt].PbitMap[lenOfPbitMap-pbitMapIdx+1])); err == nil {
+						if uint32(pbitMapIdx-2) == pbit && p == 1 { // Check this p-bit is set
+							logger.Debugw("Found-US-GEMport-for-Pcp", log.Fields{"pbit": pbit, "GEMport": tp.UpstreamGemPortAttributeList[gemCnt].GemportID})
+							return tp.UpstreamGemPortAttributeList[gemCnt].GemportID
+						}
+					}
+				}
+			}
+		} else if dir == tp_pb.Direction_DOWNSTREAM {
+			//downstream GEM ports
+			numGemPorts := len(tp.DownstreamGemPortAttributeList)
+			for gemCnt := 0; gemCnt < numGemPorts; gemCnt++ {
+				lenOfPbitMap := len(tp.DownstreamGemPortAttributeList[gemCnt].PbitMap)
+				for pbitMapIdx := 2; pbitMapIdx < lenOfPbitMap; pbitMapIdx++ {
+					// Given a sample pbit map string "0b00000001", lenOfPbitMap is 10
+					// "lenOfPbitMap - pbitMapIdx + 1" will give pbit-i th value from LSB position in the pbit map string
+					if p, err := strconv.Atoi(string(tp.DownstreamGemPortAttributeList[gemCnt].PbitMap[lenOfPbitMap-pbitMapIdx+1])); err == nil {
+						if uint32(pbitMapIdx-2) == pbit && p == 1 { // Check this p-bit is set
+							logger.Debugw("Found-DS-GEMport-for-Pcp", log.Fields{"pbit": pbit, "GEMport": tp.DownstreamGemPortAttributeList[gemCnt].GemportID})
+							return tp.DownstreamGemPortAttributeList[gemCnt].GemportID
+						}
 					}
 				}
 			}
 		}
-	} else if dir == tp_pb.Direction_DOWNSTREAM {
-		//downstream GEM ports
-		numGemPorts := len(tp.DownstreamGemPortAttributeList)
-		for gemCnt := 0; gemCnt < numGemPorts; gemCnt++ {
-			lenOfPbitMap := len(tp.DownstreamGemPortAttributeList[gemCnt].PbitMap)
-			for pbitMapIdx := 2; pbitMapIdx < lenOfPbitMap; pbitMapIdx++ {
-				// Given a sample pbit map string "0b00000001", lenOfPbitMap is 10
-				// "lenOfPbitMap - pbitMapIdx + 1" will give pbit-i th value from LSB position in the pbit map string
-				if p, err := strconv.Atoi(string(tp.DownstreamGemPortAttributeList[gemCnt].PbitMap[lenOfPbitMap-pbitMapIdx+1])); err == nil {
-					if uint32(pbitMapIdx-2) == pbit && p == 1 { // Check this p-bit is set
-						logger.Debugw("Found-DS-GEMport-for-Pcp", log.Fields{"pbit": pbit, "GEMport": tp.DownstreamGemPortAttributeList[gemCnt].GemportID})
-						return tp.DownstreamGemPortAttributeList[gemCnt].GemportID
+		logger.Errorw("No-GemportId-Found-For-Pcp", log.Fields{"pcpVlan": pbit})
+	case *EponProfile:
+		if dir == tp_pb.Direction_UPSTREAM {
+			// upstream GEM ports
+			numGemPorts := len(tp.UpstreamQueueAttributeList)
+			for gemCnt := 0; gemCnt < numGemPorts; gemCnt++ {
+				lenOfPbitMap := len(tp.UpstreamQueueAttributeList[gemCnt].PbitMap)
+				for pbitMapIdx := 2; pbitMapIdx < lenOfPbitMap; pbitMapIdx++ {
+					// Given a sample pbit map string "0b00000001", lenOfPbitMap is 10
+					// "lenOfPbitMap - pbitMapIdx + 1" will give pbit-i th value from LSB position in the pbit map string
+					if p, err := strconv.Atoi(string(tp.UpstreamQueueAttributeList[gemCnt].PbitMap[lenOfPbitMap-pbitMapIdx+1])); err == nil {
+						if uint32(pbitMapIdx-2) == pbit && p == 1 { // Check this p-bit is set
+							logger.Debugw("Found-US-Queue-for-Pcp", log.Fields{"pbit": pbit, "Queue": tp.UpstreamQueueAttributeList[gemCnt].GemportID})
+							return tp.UpstreamQueueAttributeList[gemCnt].GemportID
+						}
+					}
+				}
+			}
+		} else if dir == tp_pb.Direction_DOWNSTREAM {
+			//downstream GEM ports
+			numGemPorts := len(tp.DownstreamQueueAttributeList)
+			for gemCnt := 0; gemCnt < numGemPorts; gemCnt++ {
+				lenOfPbitMap := len(tp.DownstreamQueueAttributeList[gemCnt].PbitMap)
+				for pbitMapIdx := 2; pbitMapIdx < lenOfPbitMap; pbitMapIdx++ {
+					// Given a sample pbit map string "0b00000001", lenOfPbitMap is 10
+					// "lenOfPbitMap - pbitMapIdx + 1" will give pbit-i th value from LSB position in the pbit map string
+					if p, err := strconv.Atoi(string(tp.DownstreamQueueAttributeList[gemCnt].PbitMap[lenOfPbitMap-pbitMapIdx+1])); err == nil {
+						if uint32(pbitMapIdx-2) == pbit && p == 1 { // Check this p-bit is set
+							logger.Debugw("Found-DS-Queue-for-Pcp", log.Fields{"pbit": pbit, "Queue": tp.DownstreamQueueAttributeList[gemCnt].GemportID})
+							return tp.DownstreamQueueAttributeList[gemCnt].GemportID
+						}
 					}
 				}
 			}
 		}
+		logger.Errorw("No-QueueId-Found-For-Pcp", log.Fields{"pcpVlan": pbit})
+	default:
+		logger.Errorw("unknown-tech", log.Fields{"tp": tp})
 	}
-	logger.Errorw("No-GemportId-Found-For-Pcp", log.Fields{"pcpVlan": pbit})
 	return 0
 }
 
 // FindAllTpInstances returns all TechProfile instances for a given TechProfile table-id, pon interface ID and onu ID.
-func (t *TechProfileMgr) FindAllTpInstances(ctx context.Context, techProfiletblID uint32, ponIntf uint32, onuID uint32) []TechProfile {
-	var tp TechProfile
+func (t *TechProfileMgr) FindAllTpInstances(ctx context.Context, techProfiletblID uint32, ponIntf uint32, onuID uint32) interface{} {
+	var tpTech TechProfile
+	var tpEpon EponProfile
+
 	onuTpInstancePath := fmt.Sprintf("%s/%d/pon-{%d}/onu-{%d}", t.resourceMgr.GetTechnology(), techProfiletblID, ponIntf, onuID)
 
 	if kvPairs, _ := t.config.KVBackend.List(ctx, onuTpInstancePath); kvPairs != nil {
-		tpInstances := make([]TechProfile, 0, len(kvPairs))
+		tech := t.resourceMgr.GetTechnology()
+		tpInstancesTech := make([]TechProfile, 0, len(kvPairs))
+		tpInstancesEpon := make([]EponProfile, 0, len(kvPairs))
+
 		for kvPath, kvPair := range kvPairs {
 			if value, err := kvstore.ToByte(kvPair.Value); err == nil {
-				if err = json.Unmarshal(value, &tp); err != nil {
-					logger.Errorw("error-unmarshal-kv-pair", log.Fields{"kvPath": kvPath, "value": value})
-					continue
-				} else {
-					tpInstances = append(tpInstances, tp)
+				if tech == xgspon || tech == xgsponBbsim || tech == gpon {
+					if err = json.Unmarshal(value, &tpTech); err != nil {
+						logger.Errorw("error-unmarshal-kv-pair", log.Fields{"kvPath": kvPath, "value": value})
+						continue
+					} else {
+						tpInstancesTech = append(tpInstancesTech, tpTech)
+					}
+				} else if tech == epon {
+					if err = json.Unmarshal(value, &tpEpon); err != nil {
+						logger.Errorw("error-unmarshal-kv-pair", log.Fields{"kvPath": kvPath, "value": value})
+						continue
+					} else {
+						tpInstancesEpon = append(tpInstancesEpon, tpEpon)
+					}
 				}
 			}
 		}
-		return tpInstances
+
+		switch tech {
+		case xgspon, xgsponBbsim, gpon:
+			return tpInstancesTech
+		case epon:
+			return tpInstancesEpon
+		default:
+			log.Errorw("unknown-technology", log.Fields{"tech": tech})
+			return nil
+		}
 	}
 	return nil
 }
diff --git a/vendor/github.com/opencord/voltha-lib-go/v3/pkg/techprofile/tech_profile_if.go b/vendor/github.com/opencord/voltha-lib-go/v3/pkg/techprofile/tech_profile_if.go
index e605d49..8391a5b 100644
--- a/vendor/github.com/opencord/voltha-lib-go/v3/pkg/techprofile/tech_profile_if.go
+++ b/vendor/github.com/opencord/voltha-lib-go/v3/pkg/techprofile/tech_profile_if.go
@@ -26,8 +26,8 @@
 type TechProfileIf interface {
 	SetKVClient() *db.Backend
 	GetTechProfileInstanceKVPath(techProfiletblID uint32, uniPortName string) string
-	GetTPInstanceFromKVStore(ctx context.Context, techProfiletblID uint32, path string) (*TechProfile, error)
-	CreateTechProfInstance(ctx context.Context, techProfiletblID uint32, uniPortName string, intfId uint32) (*TechProfile, error)
+	GetTPInstanceFromKVStore(ctx context.Context, techProfiletblID uint32, path string) (interface{}, error)
+	CreateTechProfInstance(ctx context.Context, techProfiletblID uint32, uniPortName string, intfId uint32) (interface{}, error)
 	DeleteTechProfileInstance(ctx context.Context, techProfiletblID uint32, uniPortName string) error
 	GetprotoBufParamValue(paramType string, paramKey string) int32
 	GetUsScheduler(tpInstance *TechProfile) (*tp_pb.SchedulerConfig, error)
@@ -36,6 +36,6 @@
 		ShapingCfg *tp_pb.TrafficShapingInfo) *tp_pb.TrafficScheduler
 	GetTrafficQueues(tp *TechProfile, Dir tp_pb.Direction) ([]*tp_pb.TrafficQueue, error)
 	GetMulticastTrafficQueues(tp *TechProfile) []*tp_pb.TrafficQueue
-	GetGemportIDForPbit(tp *TechProfile, Dir tp_pb.Direction, pbit uint32) uint32
-	FindAllTpInstances(ctx context.Context, techProfiletblID uint32, ponIntf uint32, onuID uint32) []TechProfile
+	GetGemportIDForPbit(tp interface{}, Dir tp_pb.Direction, pbit uint32) uint32
+	FindAllTpInstances(ctx context.Context, techProfiletblID uint32, ponIntf uint32, onuID uint32) interface{}
 }
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 2b9c41a..af2b034 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -67,7 +67,7 @@
 github.com/mitchellh/go-homedir
 # github.com/mitchellh/mapstructure v1.1.2
 github.com/mitchellh/mapstructure
-# github.com/opencord/voltha-lib-go/v3 v3.1.19
+# github.com/opencord/voltha-lib-go/v3 v3.1.20
 github.com/opencord/voltha-lib-go/v3/pkg/adapters
 github.com/opencord/voltha-lib-go/v3/pkg/adapters/adapterif
 github.com/opencord/voltha-lib-go/v3/pkg/adapters/common