[VOL-1614] Device Management update in the Core
This commit went over the device management of devices in the Core
and made the following changes:
1) Update the device state machine to not remove logical
device or ports when a device is disabled.
2) Fix some issues around device deletion
3) Add additional APIs between the Core and Adapters to handle
the scenarios of enable/disable/delete a device
4) Update the simulated Adapters to handle disable/reenable/delete
5) Add a new set of tests for teh device state machine.
Change-Id: Ib2be87ec011762d5315a6d54581a87c1891e92be
diff --git a/rw_core/core/logical_device_agent.go b/rw_core/core/logical_device_agent.go
index 2f85c45..7b2783e 100644
--- a/rw_core/core/logical_device_agent.go
+++ b/rw_core/core/logical_device_agent.go
@@ -329,10 +329,10 @@
switch state {
case voltha.AdminState_ENABLED:
lport.OfpPort.Config = lport.OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
- lport.OfpPort.State = lport.OfpPort.State & ^uint32(ofp.OfpPortState_OFPPS_LINK_DOWN)
+ lport.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LIVE)
case voltha.AdminState_DISABLED:
lport.OfpPort.Config = lport.OfpPort.Config | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
- lport.OfpPort.State = lport.OfpPort.State | uint32(ofp.OfpPortState_OFPPS_LINK_DOWN)
+ lport.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LINK_DOWN)
default:
log.Warnw("unsupported-state-change", log.Fields{"deviceId": device.Id, "state": state})
}
@@ -365,6 +365,37 @@
return err
}
+// deleteAllLogicalPorts deletes all logical ports associated with this device
+func (agent *LogicalDeviceAgent) deleteAllLogicalPorts(device *voltha.Device) error {
+ log.Infow("updatePortsState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
+ agent.lockLogicalDevice.Lock()
+ defer agent.lockLogicalDevice.Unlock()
+ // Get the latest logical device info
+ if ld, err := agent.getLogicalDeviceWithoutLock(); err != nil {
+ log.Warnw("logical-device-unknown", log.Fields{"ldeviceId": agent.logicalDeviceId, "error": err})
+ return err
+ } else {
+ cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
+ updateLogicalPorts := []*voltha.LogicalPort{}
+ for _, lport := range cloned.Ports {
+ if lport.DeviceId != device.Id {
+ updateLogicalPorts = append(updateLogicalPorts, lport)
+ }
+ }
+ if len(updateLogicalPorts) < len(cloned.Ports) {
+ cloned.Ports = updateLogicalPorts
+ // Updating the logical device will trigger the poprt change events to be populated to the controller
+ if err := agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
+ log.Warnw("logical-device-update-failed", log.Fields{"ldeviceId": agent.logicalDeviceId, "error": err})
+ return err
+ }
+ } else {
+ log.Debugw("no-change-required", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
+ }
+ }
+ return nil
+}
+
//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
func (agent *LogicalDeviceAgent) updateLogicalDeviceWithoutLock(logicalDevice *voltha.LogicalDevice) error {
afterUpdate := agent.clusterDataProxy.Update("/logical_devices/"+agent.logicalDeviceId, logicalDevice, false, "")
@@ -770,11 +801,45 @@
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)
+ if err := agent.updateLogicalDeviceWithoutLock(logicaldevice); err != nil {
+ log.Errorw("logical-device-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
+ return err
+ }
+ // Reset the logical device graph
+ go agent.redoDeviceGraph()
}
return nil
}
+// deleteLogicalPorts removes the logical ports associated with that deviceId
+func (agent *LogicalDeviceAgent) deleteLogicalPorts(deviceId string) 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})
+ return nil
+ }
+ updatedLPorts := []*voltha.LogicalPort{}
+ for _, logicalPort := range logicaldevice.Ports {
+ if logicalPort.DeviceId != deviceId {
+ updatedLPorts = append(updatedLPorts, logicalPort)
+ }
+ }
+ logicaldevice.Ports = updatedLPorts
+ log.Debugw("updated-logical-ports", log.Fields{"ports": updatedLPorts})
+ if err := agent.updateLogicalDeviceWithoutLock(logicaldevice); err != nil {
+ log.Errorw("logical-device-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
+ return err
+ }
+ // Reset the logical device graph
+ go agent.redoDeviceGraph()
+
+ return nil
+}
+
// enableLogicalPort enables the logical port
func (agent *LogicalDeviceAgent) enableLogicalPort(lPort *voltha.LogicalPort) error {
agent.lockLogicalDevice.Lock()
@@ -1084,6 +1149,21 @@
agent.deviceGraph.Print()
}
+//redoDeviceGraph regenerates the device graph upon port changes on a device graph
+//TODO: it may yield better performance to have separate deleteLogicalPort functions that would remove
+// all the routes/nodes related to the deleted logical port.
+func (agent *LogicalDeviceAgent) redoDeviceGraph() {
+ log.Debugf("redoDeviceGraph", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
+ agent.lockLogicalDevice.Lock()
+ defer agent.lockLogicalDevice.Unlock()
+ // Get the latest logical device
+ if ld, err := agent.getLogicalDeviceWithoutLock(); err != nil {
+ log.Errorw("logical-device-not-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "error": err})
+ } else {
+ agent.deviceGraph.ComputeRoutes(ld.Ports)
+ }
+}
+
// portAdded is a callback invoked when a port is added to the logical device.
// TODO: To use when POST_ADD is fixed.
func (agent *LogicalDeviceAgent) portAdded(args ...interface{}) interface{} {