[VOL-1036] Initial implementation of device lifecycle management
Change-Id: I5aa58fdcbcd852f6f5eef35d48f25f76e20c0418
diff --git a/rw_core/core/logical_device_agent.go b/rw_core/core/logical_device_agent.go
index 117c869..218478f 100644
--- a/rw_core/core/logical_device_agent.go
+++ b/rw_core/core/logical_device_agent.go
@@ -25,17 +25,18 @@
"github.com/opencord/voltha-go/protos/voltha"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
- "reflect"
+ "sync"
)
type LogicalDeviceAgent struct {
- logicalDeviceId string
- lastData *voltha.LogicalDevice
- rootDeviceId string
- deviceMgr *DeviceManager
- ldeviceMgr *LogicalDeviceManager
- clusterDataProxy *model.Proxy
- exitChannel chan int
+ logicalDeviceId string
+ lastData *voltha.LogicalDevice
+ rootDeviceId string
+ deviceMgr *DeviceManager
+ ldeviceMgr *LogicalDeviceManager
+ clusterDataProxy *model.Proxy
+ exitChannel chan int
+ lockLogicalDevice sync.RWMutex
}
func NewLogicalDeviceAgent(id string, device *voltha.Device, ldeviceMgr *LogicalDeviceManager, deviceMgr *DeviceManager,
@@ -47,11 +48,12 @@
agent.deviceMgr = deviceMgr
agent.clusterDataProxy = cdProxy
agent.ldeviceMgr = ldeviceMgr
+ agent.lockLogicalDevice = sync.RWMutex{}
return &agent
}
func (agent *LogicalDeviceAgent) Start(ctx context.Context) error {
- log.Info("starting-logical_device-agent")
+ log.Infow("starting-logical_device-agent", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
//Build the logical device based on information retrieved from the device adapter
var switchCap *ca.SwitchCapability
var err error
@@ -68,7 +70,7 @@
//hence. may need to extract the port by the NNI port id defined by the adapter during device
//creation
var nniPorts *voltha.Ports
- if nniPorts, err = agent.deviceMgr.getNNIPorts(ctx, agent.rootDeviceId); err != nil {
+ if nniPorts, err = agent.deviceMgr.getPorts(ctx, agent.rootDeviceId, voltha.Port_ETHERNET_NNI); err != nil {
log.Errorw("error-creating-logical-port", log.Fields{"error": err})
}
var portCap *ca.PortCapability
@@ -80,8 +82,11 @@
}
lp := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
+ lp.DeviceId = agent.rootDeviceId
ld.Ports = append(ld.Ports, lp)
}
+ agent.lockLogicalDevice.Lock()
+ defer agent.lockLogicalDevice.Unlock()
// Save the logical device
if added := agent.clusterDataProxy.Add("/logical_devices", ld, ""); added == nil {
log.Errorw("failed-to-add-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
@@ -92,8 +97,30 @@
return nil
}
+func (agent *LogicalDeviceAgent) getLogicalDevice() (*voltha.LogicalDevice, error) {
+ log.Debug("getLogicalDevice")
+ agent.lockLogicalDevice.Lock()
+ defer agent.lockLogicalDevice.Unlock()
+ logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 1, false, "")
+ if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
+ cloned := proto.Clone(lDevice).(*voltha.LogicalDevice)
+ return cloned, nil
+ }
+ return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
+}
+
+func (agent *LogicalDeviceAgent) getLogicalDeviceWithoutLock() (*voltha.LogicalDevice, error) {
+ log.Debug("getLogicalDeviceWithoutLock")
+ logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 1, false, "")
+ if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
+ cloned := proto.Clone(lDevice).(*voltha.LogicalDevice)
+ return cloned, nil
+ }
+ return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
+}
+
func (agent *LogicalDeviceAgent) addUNILogicalPort(ctx context.Context, childDevice *voltha.Device, portNo uint32) error {
- log.Info("addUNILogicalPort-start")
+ log.Infow("addUNILogicalPort-start", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
// Build the logical device based on information retrieved from the device adapter
var portCap *ca.PortCapability
var err error
@@ -101,29 +128,67 @@
log.Errorw("error-creating-logical-port", log.Fields{"error": err})
return err
}
+ agent.lockLogicalDevice.Lock()
+ defer agent.lockLogicalDevice.Unlock()
// Get stored logical device
- if ldevice, err := agent.ldeviceMgr.getLogicalDevice(agent.logicalDeviceId); err != nil {
+ if ldevice, err := agent.getLogicalDeviceWithoutLock(); err != nil {
return status.Error(codes.NotFound, agent.logicalDeviceId)
} else {
- cloned := reflect.ValueOf(ldevice).Elem().Interface().(voltha.LogicalDevice)
- lp := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
+ cloned := proto.Clone(ldevice).(*voltha.LogicalDevice)
+ lp := proto.Clone(portCap.Port).(*voltha.LogicalPort)
+ lp.DeviceId = childDevice.Id
cloned.Ports = append(cloned.Ports, lp)
- afterUpdate := agent.clusterDataProxy.Update("/logical_devices/"+agent.logicalDeviceId, &cloned, false, "")
- if afterUpdate == nil {
- return status.Errorf(codes.Internal, "failed-add-UNI-port:%s", agent.logicalDeviceId)
- }
+ return agent.updateLogicalDeviceWithoutLock(cloned)
+ }
+}
+
+//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
+func (agent *LogicalDeviceAgent) updateLogicalDeviceWithoutLock(logicalDevice *voltha.LogicalDevice) error {
+ cloned := proto.Clone(logicalDevice).(*voltha.LogicalDevice)
+ afterUpdate := agent.clusterDataProxy.Update("/logical_devices/"+agent.logicalDeviceId, cloned, false, "")
+ if afterUpdate == nil {
+ return status.Errorf(codes.Internal, "failed-updating-logical-device:%s", agent.logicalDeviceId)
+ }
+ return nil
+}
+
+// deleteLogicalPort removes the logical port associated with a child device
+func (agent *LogicalDeviceAgent) deleteLogicalPort(device *voltha.Device) error {
+ agent.lockLogicalDevice.Lock()
+ defer agent.lockLogicalDevice.Unlock()
+ // Get the most up to date logical device
+ var logicaldevice *voltha.LogicalDevice
+ if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
+ log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "deviceId": device.Id})
return nil
}
+ index := -1
+ for i, logicalPort := range logicaldevice.Ports {
+ if logicalPort.DeviceId == device.Id {
+ index = i
+ break
+ }
+ }
+ if index >= 0 {
+ copy(logicaldevice.Ports[index:], logicaldevice.Ports[index+1:])
+ logicaldevice.Ports[len(logicaldevice.Ports)-1] = nil
+ logicaldevice.Ports = logicaldevice.Ports[:len(logicaldevice.Ports)-1]
+ log.Debugw("logical-port-deleted", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
+ return agent.updateLogicalDeviceWithoutLock(logicaldevice)
+ }
+ return nil
}
func (agent *LogicalDeviceAgent) Stop(ctx context.Context) {
log.Info("stopping-logical_device-agent")
+ agent.lockLogicalDevice.Lock()
+ defer agent.lockLogicalDevice.Unlock()
+ //Remove the logical device from the model
+ if removed := agent.clusterDataProxy.Remove("/logical_devices/"+agent.logicalDeviceId, ""); removed == nil {
+ log.Errorw("failed-to-remove-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
+ } else {
+ log.Debugw("logicaldevice-removed", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
+ }
agent.exitChannel <- 1
log.Info("logical_device-agent-stopped")
}
-
-func (agent *LogicalDeviceAgent) getLogicalDevice(ctx context.Context) *voltha.LogicalDevice {
- log.Debug("getLogicalDevice")
- cp := proto.Clone(agent.lastData)
- return cp.(*voltha.LogicalDevice)
-}