VOL-3121 - Separated ports from devices.

Similar to flows/groups/meters/logical ports.
Also added ListDevicePorts and GetDevicePort to the adapter API.
Also removed unused `// +build integration` tests.

Change-Id: I586adb9f46a249c9430d4205ef5db2d105dbbe06
diff --git a/rw_core/route/device_route.go b/rw_core/route/device_route.go
index a1f2ae9..48339ec 100644
--- a/rw_core/route/device_route.go
+++ b/rw_core/route/device_route.go
@@ -48,13 +48,14 @@
 	Egress  uint32
 }
 
-// GetDeviceFunc returns device function
-type GetDeviceFunc func(ctx context.Context, id string) (*voltha.Device, error)
+// listDevicePortsFunc returns device ports
+type listDevicePortsFunc func(ctx context.Context, id string) (map[uint32]*voltha.Port, error)
 
 // DeviceRoutes represent the set of routes between logical ports of a logical device
 type DeviceRoutes struct {
 	logicalDeviceID     string
-	getDeviceFromModel  GetDeviceFunc
+	rootDeviceID        string
+	listDevicePorts     listDevicePortsFunc
 	logicalPorts        map[uint32]*voltha.LogicalPort
 	RootPorts           map[uint32]uint32
 	rootPortsLock       sync.RWMutex
@@ -65,17 +66,17 @@
 }
 
 // NewDeviceRoutes creates device graph instance
-func NewDeviceRoutes(ctx context.Context, logicalDeviceID string, getDevice GetDeviceFunc) *DeviceRoutes {
-	var dr DeviceRoutes
-	dr.logicalDeviceID = logicalDeviceID
-	dr.getDeviceFromModel = getDevice
-	dr.RootPorts = make(map[uint32]uint32)
-	dr.Routes = make(map[PathID][]Hop)
-	dr.devicesPonPorts = make(map[string][]*voltha.Port)
-	dr.childConnectionPort = make(map[string]uint32)
-	dr.logicalPorts = make(map[uint32]*voltha.LogicalPort)
-	logger.Debug(ctx, "new device routes created ...")
-	return &dr
+func NewDeviceRoutes(logicalDeviceID, rootDeviceID string, deviceMgr listDevicePortsFunc) *DeviceRoutes {
+	return &DeviceRoutes{
+		logicalDeviceID:     logicalDeviceID,
+		rootDeviceID:        rootDeviceID,
+		listDevicePorts:     deviceMgr,
+		RootPorts:           make(map[uint32]uint32),
+		Routes:              make(map[PathID][]Hop),
+		devicesPonPorts:     make(map[string][]*voltha.Port),
+		childConnectionPort: make(map[string]uint32),
+		logicalPorts:        make(map[uint32]*voltha.LogicalPort),
+	}
 }
 
 //IsRootPort returns true if the port is a root port on a logical device
@@ -103,7 +104,7 @@
 	if err != nil {
 		return nil, err
 	}
-	rootDevicePonPort, err := dr.getParentPonPort(ctx, nniPort.DeviceId, uniPort.DeviceId)
+	rootDevicePonPort, err := dr.getParentPonPort(ctx, uniPort.DeviceId)
 	if err != nil {
 		return nil, err
 	}
@@ -154,8 +155,6 @@
 	if len(nniPorts) == 0 {
 		return fmt.Errorf("no nni port :%w", ErrNoRoute)
 	}
-	var rootDevice *voltha.Device
-	var childDevice *voltha.Device
 	var copyFromNNIPort *voltha.LogicalPort
 	for idx, nniPort := range nniPorts {
 		if idx == 0 {
@@ -165,36 +164,38 @@
 			return nil
 		}
 		// Get root device
-		rootDevice, err = dr.getDeviceWithCacheUpdate(ctx, nniPort.DeviceId)
+		rootDeviceID := nniPort.DeviceId
+		rootDevicePorts, err := dr.getDeviceWithCacheUpdate(ctx, nniPort.DeviceId)
 		if err != nil {
 			return err
 		}
-		if len(rootDevice.Ports) == 0 {
-			err = status.Errorf(codes.FailedPrecondition, "no-port-%s", rootDevice.Id)
+		if len(rootDevicePorts) == 0 {
+			err = status.Errorf(codes.FailedPrecondition, "no-port-%s", rootDeviceID)
 			return err
 		}
-		for _, rootDevicePort := range rootDevice.Ports {
+		for _, rootDevicePort := range rootDevicePorts {
 			if rootDevicePort.Type == voltha.Port_PON_OLT {
-				logger.Debugw(ctx, "peers", log.Fields{"root-device-id": rootDevice.Id, "port-no": rootDevicePort.PortNo, "len-peers": len(rootDevicePort.Peers)})
+				logger.Debugw(ctx, "peers", log.Fields{"root-device-id": rootDeviceID, "port-no": rootDevicePort.PortNo, "len-peers": len(rootDevicePort.Peers)})
 				for _, rootDevicePeer := range rootDevicePort.Peers {
-					childDevice, err = dr.getDeviceWithCacheUpdate(ctx, rootDevicePeer.DeviceId)
+					childDeviceID := rootDevicePeer.DeviceId
+					childDevicePorts, err := dr.getDeviceWithCacheUpdate(ctx, rootDevicePeer.DeviceId)
 					if err != nil {
 						return err
 					}
-					childPonPort, err := dr.getChildPonPort(ctx, childDevice.Id)
+					childPonPort, err := dr.getChildPonPort(ctx, childDeviceID)
 					if err != nil {
 						return err
 					}
-					for _, childDevicePort := range childDevice.Ports {
+					for _, childDevicePort := range childDevicePorts {
 						if childDevicePort.Type == voltha.Port_ETHERNET_UNI {
-							childLogicalPort, exist := physPortToLogicalPortMap[concatDeviceIDPortID(childDevice.Id, childDevicePort.PortNo)]
+							childLogicalPort, exist := physPortToLogicalPortMap[concatDeviceIDPortID(childDeviceID, childDevicePort.PortNo)]
 							if !exist {
 								// This can happen if this logical port has not been created yet for that device
 								continue
 							}
 							dr.Routes[PathID{Ingress: nniPort.OfpPort.PortNo, Egress: childLogicalPort}] = []Hop{
-								{DeviceID: rootDevice.Id, Ingress: nniPort.DevicePortNo, Egress: rootDevicePort.PortNo},
-								{DeviceID: childDevice.Id, Ingress: childPonPort, Egress: childDevicePort.PortNo},
+								{DeviceID: rootDeviceID, Ingress: nniPort.DevicePortNo, Egress: rootDevicePort.PortNo},
+								{DeviceID: childDeviceID, Ingress: childPonPort, Egress: childDevicePort.PortNo},
 							}
 							dr.Routes[PathID{Ingress: childLogicalPort, Egress: nniPort.OfpPort.PortNo}] = getReverseRoute(
 								dr.Routes[PathID{Ingress: nniPort.OfpPort.PortNo, Egress: childLogicalPort}])
@@ -209,20 +210,20 @@
 
 // AddPort augments the current set of routes with new routes corresponding to the logical port "lp".  If the routes have
 // not been built yet then use logical port "lps" to compute all current routes (lps includes lp)
-func (dr *DeviceRoutes) AddPort(ctx context.Context, lp *voltha.LogicalPort, device *voltha.Device, lps map[uint32]*voltha.LogicalPort) error {
+func (dr *DeviceRoutes) AddPort(ctx context.Context, lp *voltha.LogicalPort, deviceID string, devicePorts map[uint32]*voltha.Port, lps map[uint32]*voltha.LogicalPort) error {
 	logger.Debugw(ctx, "add-port-to-routes", log.Fields{"port": lp, "count-logical-ports": len(lps)})
 
 	// Adding NNI port
 	if lp.RootPort {
-		return dr.AddNNIPort(ctx, lp, device, lps)
+		return dr.AddNNIPort(ctx, lp, deviceID, devicePorts, lps)
 	}
 
 	// Adding UNI port
-	return dr.AddUNIPort(ctx, lp, device, lps)
+	return dr.AddUNIPort(ctx, lp, deviceID, devicePorts, lps)
 }
 
 // AddUNIPort setup routes between the logical UNI port lp and all registered NNI ports
-func (dr *DeviceRoutes) AddUNIPort(ctx context.Context, lp *voltha.LogicalPort, device *voltha.Device, lps map[uint32]*voltha.LogicalPort) error {
+func (dr *DeviceRoutes) AddUNIPort(ctx context.Context, lp *voltha.LogicalPort, deviceID string, devicePorts map[uint32]*voltha.Port, lps map[uint32]*voltha.LogicalPort) error {
 	logger.Debugw(ctx, "add-uni-port-to-routes", log.Fields{"port": lp, "count-logical-ports": len(lps)})
 
 	dr.routeBuildLock.Lock()
@@ -232,14 +233,14 @@
 	dr.logicalPorts[lp.OfpPort.PortNo] = lp
 
 	// Update internal structures with device data
-	dr.updateCache(device)
+	dr.updateCache(deviceID, devicePorts)
 
 	// Adding a UNI port
 	childPonPort, err := dr.getChildPonPort(ctx, lp.DeviceId)
 	if err != nil {
 		return err
 	}
-	rootDevicePonPort, err := dr.getParentPonPort(ctx, device.ParentId, device.Id)
+	rootDevicePonPort, err := dr.getParentPonPort(ctx, deviceID)
 	if err != nil {
 		return err
 	}
@@ -259,14 +260,14 @@
 }
 
 // AddNNIPort setup routes between the logical NNI port lp and all registered UNI ports
-func (dr *DeviceRoutes) AddNNIPort(ctx context.Context, lp *voltha.LogicalPort, device *voltha.Device, lps map[uint32]*voltha.LogicalPort) error {
-	logger.Debugw(ctx, "add-port-to-routes", log.Fields{"port": lp, "logical-ports-count": len(lps), "device-id": device.Id})
+func (dr *DeviceRoutes) AddNNIPort(ctx context.Context, lp *voltha.LogicalPort, deviceID string, devicePorts map[uint32]*voltha.Port, lps map[uint32]*voltha.LogicalPort) error {
+	logger.Debugw(ctx, "add-port-to-routes", log.Fields{"port": lp, "logical-ports-count": len(lps), "device-id": deviceID})
 
 	dr.routeBuildLock.Lock()
 	defer dr.routeBuildLock.Unlock()
 
 	// Update internal structures with device data
-	dr.updateCache(device)
+	dr.updateCache(deviceID, devicePorts)
 
 	// Setup the physical ports to logical ports map, the nni ports as well as the root ports map
 	physPortToLogicalPortMap := make(map[string]uint32)
@@ -280,22 +281,23 @@
 		dr.logicalPorts[lp.OfpPort.PortNo] = lp
 	}
 
-	for _, rootDevicePort := range device.Ports {
+	for _, rootDevicePort := range devicePorts {
 		if rootDevicePort.Type == voltha.Port_PON_OLT {
-			logger.Debugw(ctx, "peers", log.Fields{"root-device-id": device.Id, "port-no": rootDevicePort.PortNo, "len-peers": len(rootDevicePort.Peers)})
+			logger.Debugw(ctx, "peers", log.Fields{"root-device-id": deviceID, "port-no": rootDevicePort.PortNo, "len-peers": len(rootDevicePort.Peers)})
 			for _, rootDevicePeer := range rootDevicePort.Peers {
-				childDevice, err := dr.getDeviceWithCacheUpdate(ctx, rootDevicePeer.DeviceId)
+				childDeviceID := rootDevicePeer.DeviceId
+				childDevicePorts, err := dr.getDeviceWithCacheUpdate(ctx, rootDevicePeer.DeviceId)
 				if err != nil {
 					continue
 				}
 
-				childPonPort, err := dr.getChildPonPort(ctx, childDevice.Id)
+				childPonPort, err := dr.getChildPonPort(ctx, childDeviceID)
 				if err != nil {
 					continue
 				}
 
-				for _, childDevicePort := range childDevice.Ports {
-					childLogicalPort, exist := physPortToLogicalPortMap[concatDeviceIDPortID(childDevice.Id, childDevicePort.PortNo)]
+				for _, childDevicePort := range childDevicePorts {
+					childLogicalPort, exist := physPortToLogicalPortMap[concatDeviceIDPortID(childDeviceID, childDevicePort.PortNo)]
 					if !exist {
 						// This can happen if this logical port has not been created yet for that device
 						continue
@@ -303,8 +305,8 @@
 
 					if childDevicePort.Type == voltha.Port_ETHERNET_UNI {
 						dr.Routes[PathID{Ingress: lp.OfpPort.PortNo, Egress: childLogicalPort}] = []Hop{
-							{DeviceID: device.Id, Ingress: lp.DevicePortNo, Egress: rootDevicePort.PortNo},
-							{DeviceID: childDevice.Id, Ingress: childPonPort, Egress: childDevicePort.PortNo},
+							{DeviceID: deviceID, Ingress: lp.DevicePortNo, Egress: rootDevicePort.PortNo},
+							{DeviceID: childDeviceID, Ingress: childPonPort, Egress: childDevicePort.PortNo},
 						}
 						dr.Routes[PathID{Ingress: childLogicalPort, Egress: lp.OfpPort.PortNo}] = getReverseRoute(
 							dr.Routes[PathID{Ingress: lp.OfpPort.PortNo, Egress: childLogicalPort}])
@@ -317,11 +319,11 @@
 }
 
 // AddAllPorts setups up new routes using all ports on the device. lps includes the device's logical port
-func (dr *DeviceRoutes) AddAllPorts(ctx context.Context, device *voltha.Device, lps map[uint32]*voltha.LogicalPort) error {
-	logger.Debugw(ctx, "add-all-port-to-routes", log.Fields{"logical-ports-count": len(lps), "device-id": device.Id})
+func (dr *DeviceRoutes) AddAllPorts(ctx context.Context, deviceID string, devicePorts map[uint32]*voltha.Port, lps map[uint32]*voltha.LogicalPort) error {
+	logger.Debugw(ctx, "add-all-port-to-routes", log.Fields{"logical-ports-count": len(lps), "device-id": deviceID})
 	for _, lp := range lps {
-		if lp.DeviceId == device.Id {
-			if err := dr.AddPort(ctx, lp, device, lps); err != nil {
+		if lp.DeviceId == deviceID {
+			if err := dr.AddPort(ctx, lp, deviceID, devicePorts, lps); err != nil {
 				return err
 			}
 		}
@@ -411,14 +413,14 @@
 }
 
 //getDeviceWithCacheUpdate returns the from the model and updates the PON ports map of that device.
-func (dr *DeviceRoutes) getDeviceWithCacheUpdate(ctx context.Context, deviceID string) (*voltha.Device, error) {
-	device, err := dr.getDeviceFromModel(ctx, deviceID)
+func (dr *DeviceRoutes) getDeviceWithCacheUpdate(ctx context.Context, deviceID string) (map[uint32]*voltha.Port, error) {
+	devicePorts, err := dr.listDevicePorts(ctx, deviceID)
 	if err != nil {
 		logger.Errorw(ctx, "device-not-found", log.Fields{"deviceId": deviceID, "error": err})
 		return nil, err
 	}
-	dr.updateCache(device)
-	return device, nil
+	dr.updateCache(deviceID, devicePorts)
+	return devicePorts, nil
 }
 
 //copyFromExistingNNIRoutes copies routes from an existing set of NNI routes
@@ -491,14 +493,14 @@
 }
 
 // getParentPonPort returns the parent PON port of the child device
-func (dr *DeviceRoutes) getParentPonPort(ctx context.Context, deviceID string, childDeviceID string) (uint32, error) {
+func (dr *DeviceRoutes) getParentPonPort(ctx context.Context, childDeviceID string) (uint32, error) {
 	if pNo, exist := dr.childConnectionPort[childDeviceID]; exist {
 		return pNo, nil
 	}
 
 	// Get parent device from the model
-	if _, err := dr.getDeviceWithCacheUpdate(ctx, deviceID); err != nil {
-		logger.Errorw(ctx, "device-not-found", log.Fields{"deviceId": deviceID, "error": err})
+	if _, err := dr.getDeviceWithCacheUpdate(ctx, dr.rootDeviceID); err != nil {
+		logger.Errorw(ctx, "device-not-found", log.Fields{"deviceId": dr.rootDeviceID, "error": err})
 		return 0, err
 	}
 	// Try again
@@ -508,10 +510,10 @@
 	return 0, fmt.Errorf("pon port associated with child device %s not found", childDeviceID)
 }
 
-func (dr *DeviceRoutes) updateCache(device *voltha.Device) {
-	for _, port := range device.Ports {
+func (dr *DeviceRoutes) updateCache(deviceID string, devicePorts map[uint32]*voltha.Port) {
+	for _, port := range devicePorts {
 		if port.Type == voltha.Port_PON_ONU || port.Type == voltha.Port_PON_OLT {
-			dr.devicesPonPorts[device.Id] = append(dr.devicesPonPorts[device.Id], port)
+			dr.devicesPonPorts[deviceID] = append(dr.devicesPonPorts[deviceID], port)
 			for _, peer := range port.Peers {
 				if port.Type == voltha.Port_PON_ONU {
 					dr.childConnectionPort[port.DeviceId] = peer.PortNo
diff --git a/rw_core/route/device_route_test.go b/rw_core/route/device_route_test.go
index 0fd0836..3857837 100644
--- a/rw_core/route/device_route_test.go
+++ b/rw_core/route/device_route_test.go
@@ -48,13 +48,15 @@
 
 //onuRegistration is a message sent from an ONU device to an OLT device to register an ONU
 type onuRegistration struct {
-	onu      *voltha.Device
+	onuID    string
+	onuPorts map[uint32]*voltha.Port
 	oltPonNo uint32
 	onuPonNo uint32
 }
 
 type logicalDeviceManager struct {
 	logicalDeviceID string
+	rootDeviceID    string
 	ports           map[uint32]*voltha.LogicalPort
 	deviceRoutes    *DeviceRoutes
 	ldChnl          chan portRegistration
@@ -62,23 +64,19 @@
 	done            chan struct{}
 }
 
-func newLogicalDeviceManager(ld *voltha.LogicalDevice, ch chan portRegistration, totalLogicalPorts int, done chan struct{}) *logicalDeviceManager {
-	ports := make(map[uint32]*voltha.LogicalPort)
-	for _, p := range ld.Ports {
-		ports[p.DevicePortNo] = p
-	}
-
+func newLogicalDeviceManager(ld *voltha.LogicalDevice, rootDeviceID string, ch chan portRegistration, totalLogicalPorts int, done chan struct{}) *logicalDeviceManager {
 	return &logicalDeviceManager{
 		logicalDeviceID: ld.Id,
-		ports:           ports,
+		rootDeviceID:    rootDeviceID,
+		ports:           make(map[uint32]*voltha.LogicalPort),
 		ldChnl:          ch,
 		numLogicalPorts: totalLogicalPorts,
 		done:            done,
 	}
 }
 
-func (ldM *logicalDeviceManager) start(ctx context.Context, getDevice GetDeviceFunc, buildRoutes bool) {
-	ldM.deviceRoutes = NewDeviceRoutes(ctx, ldM.logicalDeviceID, getDevice)
+func (ldM *logicalDeviceManager) start(ctx context.Context, listDevicePorts listDevicePortsFunc, buildRoutes bool) {
+	ldM.deviceRoutes = NewDeviceRoutes(ldM.logicalDeviceID, ldM.rootDeviceID, listDevicePorts)
 	ofpPortNo := uint32(1)
 	for portReg := range ldM.ldChnl {
 		if portReg.port == nil {
@@ -94,11 +92,11 @@
 		}
 		ldM.ports[lp.DevicePortNo] = lp
 		if buildRoutes {
-			device, err := getDevice(context.WithValue(context.Background(), testSetupPhase, true), lp.DeviceId)
+			devicePorts, err := listDevicePorts(context.WithValue(context.Background(), testSetupPhase, true), lp.DeviceId)
 			if err != nil {
 				fmt.Println("Error when getting device:", lp.DeviceId, err)
 			}
-			if err := ldM.deviceRoutes.AddPort(context.Background(), lp, device, ldM.ports); err != nil && !strings.Contains(err.Error(), "code = FailedPrecondition") {
+			if err := ldM.deviceRoutes.AddPort(context.Background(), lp, lp.DeviceId, devicePorts, ldM.ports); err != nil && !strings.Contains(err.Error(), "code = FailedPrecondition") {
 				fmt.Println("(Error when adding port:", lp, len(ldM.ports), err)
 			}
 		}
@@ -109,7 +107,8 @@
 }
 
 type oltManager struct {
-	olt              *voltha.Device
+	oltID            string
+	oltPorts         map[uint32]*voltha.Port
 	logicalDeviceMgr *logicalDeviceManager
 	numNNIPort       int
 	numPonPortOnOlt  int
@@ -118,7 +117,8 @@
 
 func newOltManager(oltDeviceID string, ldMgr *logicalDeviceManager, numNNIPort int, numPonPortOnOlt int, ch chan onuRegistration) *oltManager {
 	return &oltManager{
-		olt:              &voltha.Device{Id: oltDeviceID, ParentId: ldMgr.logicalDeviceID, Root: true},
+		oltID:            oltDeviceID, // ParentId: ldMgr.logicalDeviceID, Root: true},
+		oltPorts:         make(map[uint32]*voltha.Port),
 		logicalDeviceMgr: ldMgr,
 		numNNIPort:       numNNIPort,
 		numPonPortOnOlt:  numPonPortOnOlt,
@@ -127,41 +127,40 @@
 }
 
 func (oltM *oltManager) start() {
-	oltM.olt.Ports = make([]*voltha.Port, 0)
 	// Setup the OLT nni ports and trigger the nni ports creation
 	for nniPort := 1; nniPort < oltM.numNNIPort+1; nniPort++ {
-		p := &voltha.Port{Label: fmt.Sprintf("nni-%d", nniPort), PortNo: uint32(nniPort), DeviceId: oltM.olt.Id, Type: voltha.Port_ETHERNET_NNI}
-		oltM.olt.Ports = append(oltM.olt.Ports, p)
+		p := &voltha.Port{Label: fmt.Sprintf("nni-%d", nniPort), PortNo: uint32(nniPort), DeviceId: oltM.oltID, Type: voltha.Port_ETHERNET_NNI}
+		oltM.oltPorts[p.PortNo] = p
 		oltM.logicalDeviceMgr.ldChnl <- portRegistration{port: p, rootPort: true}
 	}
 
 	// Create OLT pon ports
 	for ponPort := oltM.numNNIPort + 1; ponPort < oltM.numPonPortOnOlt+oltM.numNNIPort+1; ponPort++ {
-		p := voltha.Port{PortNo: uint32(ponPort), DeviceId: oltM.olt.Id, Type: voltha.Port_PON_OLT}
-		oltM.olt.Ports = append(oltM.olt.Ports, &p)
+		p := &voltha.Port{PortNo: uint32(ponPort), DeviceId: oltM.oltID, Type: voltha.Port_PON_OLT}
+		oltM.oltPorts[p.PortNo] = p
 	}
 
 	// Wait for onu registration
 	for onuReg := range oltM.oltChnl {
-		if onuReg.onu == nil {
+		if onuReg.onuPorts == nil {
 			// All onu has registered - exit the loop
 			break
 		}
-		oltM.registerOnu(onuReg.onu, onuReg.oltPonNo, onuReg.onuPonNo)
+		oltM.registerOnu(onuReg.onuID, onuReg.onuPorts, onuReg.oltPonNo, onuReg.onuPonNo)
 	}
 	// Inform the logical device manager we are done
 	oltM.logicalDeviceMgr.ldChnl <- portRegistration{port: nil}
 }
 
-func (oltM *oltManager) registerOnu(onu *voltha.Device, oltPonNo uint32, onuPonNo uint32) {
+func (oltM *oltManager) registerOnu(onuID string, onuPorts map[uint32]*voltha.Port, oltPonNo uint32, onuPonNo uint32) {
 	// Update the olt pon peers
-	for _, port := range oltM.olt.Ports {
+	for _, port := range oltM.oltPorts {
 		if port.Type == voltha.Port_PON_OLT && port.PortNo == oltPonNo {
-			port.Peers = append(port.Peers, &voltha.Port_PeerPort{DeviceId: onu.Id, PortNo: onuPonNo})
+			port.Peers = append(port.Peers, &voltha.Port_PeerPort{DeviceId: onuID, PortNo: onuPonNo})
 		}
 	}
 	// For each uni port on the ONU trigger the creation of a logical port
-	for _, port := range onu.Ports {
+	for _, port := range onuPorts {
 		if port.Type == voltha.Port_ETHERNET_UNI {
 			oltM.logicalDeviceMgr.ldChnl <- portRegistration{port: port, rootPort: false}
 		}
@@ -177,6 +176,7 @@
 	numGetDeviceInvokedLock sync.RWMutex
 	deviceLock              sync.RWMutex
 	onus                    []*voltha.Device
+	onuPorts                map[string]map[uint32]*voltha.Port
 }
 
 func newOnuManager(oltMgr *oltManager, numOnus int, numUnisPerOnu int, startingUniPortNo int) *onuManager {
@@ -186,6 +186,7 @@
 		numUnisPerOnu:     numUnisPerOnu,
 		startingUniPortNo: startingUniPortNo,
 		onus:              make([]*voltha.Device, 0),
+		onuPorts:          make(map[string]map[uint32]*voltha.Port),
 	}
 }
 
@@ -198,22 +199,24 @@
 				var onu *voltha.Device
 				defer wg.Done()
 				id := fmt.Sprintf("%d-onu-%d", oltPonNum, onuID)
-				onu = &voltha.Device{Id: id, ParentId: onuM.oltMgr.olt.Id, ParentPortNo: uint32(oltPonNum)}
+				onu = &voltha.Device{Id: id, ParentId: onuM.oltMgr.oltID, ParentPortNo: uint32(oltPonNum)}
 				ponPort := &voltha.Port{Label: fmt.Sprintf("%s:pon-%d", onu.Id, onuID), PortNo: 1, DeviceId: onu.Id, Type: voltha.Port_PON_ONU}
 				ponPort.Peers = make([]*voltha.Port_PeerPort, 0)
-				peerPort := voltha.Port_PeerPort{DeviceId: onuM.oltMgr.olt.Id, PortNo: uint32(oltPonNum)}
+				peerPort := voltha.Port_PeerPort{DeviceId: onuM.oltMgr.oltID, PortNo: uint32(oltPonNum)}
 				ponPort.Peers = append(ponPort.Peers, &peerPort)
-				onu.Ports = make([]*voltha.Port, 0)
-				onu.Ports = append(onu.Ports, ponPort)
+				onuPorts := make(map[uint32]*voltha.Port)
+				onuPorts[ponPort.PortNo] = ponPort
 				for j := onuM.startingUniPortNo; j < onuM.numUnisPerOnu+onuM.startingUniPortNo; j++ {
 					uniPort := &voltha.Port{Label: fmt.Sprintf("%s:uni-%d", onu.Id, j), PortNo: uint32(oltPonNum)<<12 + uint32(onuID+1)<<4 + uint32(j), DeviceId: onu.Id, Type: voltha.Port_ETHERNET_UNI}
-					onu.Ports = append(onu.Ports, uniPort)
+					onuPorts[uniPort.PortNo] = uniPort
 				}
 				onuM.deviceLock.Lock()
 				onuM.onus = append(onuM.onus, onu)
+				onuM.onuPorts[id] = onuPorts
 				onuM.deviceLock.Unlock()
 				onuM.oltMgr.oltChnl <- onuRegistration{
-					onu:      onu,
+					onuID:    onu.Id,
+					onuPorts: onuPorts,
 					oltPonNo: uint32(oltPonNum),
 					onuPonNo: 1,
 				}
@@ -223,34 +226,30 @@
 	wg.Wait()
 	//send an empty device to indicate the end of onu registration
 	onuM.oltMgr.oltChnl <- onuRegistration{
-		onu:      nil,
+		onuPorts: nil,
 		oltPonNo: 0,
 		onuPonNo: 1,
 	}
 }
 
-func (onuM *onuManager) getOnu(deviceID string) *voltha.Device {
+func (onuM *onuManager) getOnuPorts(deviceID string) (map[uint32]*voltha.Port, bool) {
 	onuM.deviceLock.Lock()
 	defer onuM.deviceLock.Unlock()
-	for _, onu := range onuM.onus {
-		if onu.Id == deviceID {
-			return onu
-		}
-	}
-	return nil
+	ports, have := onuM.onuPorts[deviceID]
+	return ports, have
 }
 
-func (onuM *onuManager) GetDeviceHelper(ctx context.Context, id string) (*voltha.Device, error) {
+func (onuM *onuManager) ListDevicePortsHelper(ctx context.Context, id string) (map[uint32]*voltha.Port, error) {
 	if ctx.Value(testSetupPhase) != true {
 		onuM.numGetDeviceInvokedLock.Lock()
 		onuM.numGetDeviceInvoked++
 		onuM.numGetDeviceInvokedLock.Unlock()
 	}
 	if id == oltDeviceID {
-		return onuM.oltMgr.olt, nil
+		return onuM.oltMgr.oltPorts, nil
 	}
-	if onu := onuM.getOnu(id); onu != nil {
-		return onu, nil
+	if onuPorts, have := onuM.getOnuPorts(id); have {
+		return onuPorts, nil
 	}
 	return nil, errors.New("not-found")
 }
@@ -268,14 +267,13 @@
 	// Create all the devices and logical device before computing the routes in one go
 	ld := &voltha.LogicalDevice{Id: logicalDeviceID}
 	ldMgrChnl := make(chan portRegistration, numNNIPort*numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu)
-	ldMgr := newLogicalDeviceManager(ld, ldMgrChnl, numNNIPort+numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu, done)
+	ldMgr := newLogicalDeviceManager(ld, oltDeviceID, ldMgrChnl, numNNIPort+numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu, done)
 	oltMgrChnl := make(chan onuRegistration, numPonPortOnOlt*numOnuPerOltPonPort)
 	oltMgr := newOltManager(oltDeviceID, ldMgr, numNNIPort, numPonPortOnOlt, oltMgrChnl)
 	onuMgr := newOnuManager(oltMgr, numOnuPerOltPonPort, numUniPerOnu, 2)
-	getDevice := onuMgr.GetDeviceHelper
 	// Start the managers.  Only the devices are created.  No routes will be built.
 	ctx := context.Background()
-	go ldMgr.start(ctx, getDevice, false)
+	go ldMgr.start(ctx, onuMgr.ListDevicePortsHelper, false)
 	go oltMgr.start()
 	go onuMgr.start(numNNIPort+1, numPonPortOnOlt)
 
@@ -316,14 +314,13 @@
 	// Create all the devices and logical device before computing the routes in one go
 	ld := &voltha.LogicalDevice{Id: logicalDeviceID}
 	ldMgrChnl := make(chan portRegistration, numNNIPort*numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu)
-	ldMgr := newLogicalDeviceManager(ld, ldMgrChnl, numNNIPort+numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu, done)
+	ldMgr := newLogicalDeviceManager(ld, oltDeviceID, ldMgrChnl, numNNIPort+numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu, done)
 	oltMgrChnl := make(chan onuRegistration, numPonPortOnOlt*numOnuPerOltPonPort)
 	oltMgr := newOltManager(oltDeviceID, ldMgr, numNNIPort, numPonPortOnOlt, oltMgrChnl)
 	onuMgr := newOnuManager(oltMgr, numOnuPerOltPonPort, numUniPerOnu, 2)
-	getDevice := onuMgr.GetDeviceHelper
-
-	ctx := context.Background()
+	getDevice := onuMgr.ListDevicePortsHelper
 	// Start the managers and trigger the routes to be built as the logical ports become available
+	ctx := context.Background()
 	go ldMgr.start(ctx, getDevice, true)
 	go oltMgr.start()
 	go onuMgr.start(numNNIPort+1, numPonPortOnOlt)
@@ -362,11 +359,11 @@
 	// Create all the devices and logical device before computing the routes in one go
 	ld1 := &voltha.LogicalDevice{Id: logicalDeviceID}
 	ldMgrChnl1 := make(chan portRegistration, numNNIPort*numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu)
-	ldMgr1 := newLogicalDeviceManager(ld1, ldMgrChnl1, numNNIPort+numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu, done)
+	ldMgr1 := newLogicalDeviceManager(ld1, oltDeviceID, ldMgrChnl1, numNNIPort+numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu, done)
 	oltMgrChnl1 := make(chan onuRegistration, numPonPortOnOlt*numOnuPerOltPonPort)
 	oltMgr1 := newOltManager(oltDeviceID, ldMgr1, numNNIPort, numPonPortOnOlt, oltMgrChnl1)
 	onuMgr1 := newOnuManager(oltMgr1, numOnuPerOltPonPort, numUniPerOnu, 2)
-	getDevice := onuMgr1.GetDeviceHelper
+	getDevice := onuMgr1.ListDevicePortsHelper
 	ctx := context.Background()
 	// Start the managers.  Only the devices are created.  No routes will be built.
 	go ldMgr1.start(ctx, getDevice, false)
@@ -387,7 +384,7 @@
 	// Create all the devices and logical device before computing the routes in one go
 	ld2 := &voltha.LogicalDevice{Id: logicalDeviceID}
 	ldMgrChnl2 := make(chan portRegistration, numNNIPort*numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu)
-	ldMgr2 := newLogicalDeviceManager(ld2, ldMgrChnl2, numNNIPort+numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu, done)
+	ldMgr2 := newLogicalDeviceManager(ld2, oltDeviceID, ldMgrChnl2, numNNIPort+numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu, done)
 	oltMgrChnl2 := make(chan onuRegistration, numPonPortOnOlt*numOnuPerOltPonPort)
 	oltMgr2 := newOltManager(oltDeviceID, ldMgr2, numNNIPort, numPonPortOnOlt, oltMgrChnl2)
 	onuMgr2 := newOnuManager(oltMgr2, numOnuPerOltPonPort, numUniPerOnu, 2)