Network Graph Refactoring: WIP: Implement the mechanism for storing
locally discovered events in in-memory cache. That cache is used
to cleanup events that are related:
- Removal of a switch will trigger the removal of the corresponding ports.
- Removal of a port will trigger the removal of the corresponding
incoming link and attached devices.
Change-Id: Ibf36cf9299f042bf74a11d863ea9e0666e4e4144
diff --git a/src/main/java/net/onrc/onos/ofcontroller/networkgraph/PortEvent.java b/src/main/java/net/onrc/onos/ofcontroller/networkgraph/PortEvent.java
index 8172f29..f89cdf8 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/networkgraph/PortEvent.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/networkgraph/PortEvent.java
@@ -72,7 +72,7 @@
}
}
- private final SwitchPort id;
+ protected final SwitchPort id;
// TODO Add Hardware Address
// TODO Add Description
diff --git a/src/main/java/net/onrc/onos/ofcontroller/networkgraph/TopologyManager.java b/src/main/java/net/onrc/onos/ofcontroller/networkgraph/TopologyManager.java
index 47022f1..e484d88 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/networkgraph/TopologyManager.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/networkgraph/TopologyManager.java
@@ -68,6 +68,23 @@
new HashMap<ByteBuffer, DeviceEvent>();
//
+ // Local state for keeping track of locally discovered events so we can
+ // cleanup properly when a Switch or Port is removed.
+ //
+ // We keep all Port, Link and Device events per Switch DPID:
+ // - If a switch goes down, we remove all corresponding Port, Link and
+ // Device events.
+ // - If a port on a switch goes down, we remove all corresponding Link
+ // and Device events.
+ //
+ private Map<Long, Map<ByteBuffer, PortEvent>> discoveredAddedPortEvents =
+ new HashMap<>();
+ private Map<Long, Map<ByteBuffer, LinkEvent>> discoveredAddedLinkEvents =
+ new HashMap<>();
+ private Map<Long, Map<ByteBuffer, DeviceEvent>> discoveredAddedDeviceEvents =
+ new HashMap<>();
+
+ //
// Local state for keeping track of the application event notifications
//
List<SwitchEvent> apiAddedSwitchEvents = new LinkedList<SwitchEvent>();
@@ -171,22 +188,14 @@
*/
private void processEvents(Collection<EventEntry<TopologyEvent>> events) {
// Local state for computing the final set of events
- Map<ByteBuffer, SwitchEvent> addedSwitchEvents =
- new HashMap<ByteBuffer, SwitchEvent>();
- Map<ByteBuffer, SwitchEvent> removedSwitchEvents =
- new HashMap<ByteBuffer, SwitchEvent>();
- Map<ByteBuffer, PortEvent> addedPortEvents =
- new HashMap<ByteBuffer, PortEvent>();
- Map<ByteBuffer, PortEvent> removedPortEvents =
- new HashMap<ByteBuffer, PortEvent>();
- Map<ByteBuffer, LinkEvent> addedLinkEvents =
- new HashMap<ByteBuffer, LinkEvent>();
- Map<ByteBuffer, LinkEvent> removedLinkEvents =
- new HashMap<ByteBuffer, LinkEvent>();
- Map<ByteBuffer, DeviceEvent> addedDeviceEvents =
- new HashMap<ByteBuffer, DeviceEvent>();
- Map<ByteBuffer, DeviceEvent> removedDeviceEvents =
- new HashMap<ByteBuffer, DeviceEvent>();
+ Map<ByteBuffer, SwitchEvent> addedSwitchEvents = new HashMap<>();
+ Map<ByteBuffer, SwitchEvent> removedSwitchEvents = new HashMap<>();
+ Map<ByteBuffer, PortEvent> addedPortEvents = new HashMap<>();
+ Map<ByteBuffer, PortEvent> removedPortEvents = new HashMap<>();
+ Map<ByteBuffer, LinkEvent> addedLinkEvents = new HashMap<>();
+ Map<ByteBuffer, LinkEvent> removedLinkEvents = new HashMap<>();
+ Map<ByteBuffer, DeviceEvent> addedDeviceEvents = new HashMap<>();
+ Map<ByteBuffer, DeviceEvent> removedDeviceEvents = new HashMap<>();
//
// Classify and suppress matching events
@@ -445,24 +454,80 @@
TopologyEvent topologyEvent = new TopologyEvent(switchEvent);
eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
+ // Send out notification for each port
for (PortEvent portEvent : portEvents) {
topologyEvent = new TopologyEvent(portEvent);
eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
}
+
+ //
+ // Keep track of the added ports
+ //
+ // Get the old Port Events
+ Map<ByteBuffer, PortEvent> oldPortEvents =
+ discoveredAddedPortEvents.get(switchEvent.getDpid());
+ if (oldPortEvents == null)
+ oldPortEvents = new HashMap<>();
+
+ // Store the new Port Events in the local cache
+ Map<ByteBuffer, PortEvent> newPortEvents = new HashMap<>();
+ for (PortEvent portEvent : portEvents) {
+ ByteBuffer id = ByteBuffer.wrap(portEvent.getID());
+ newPortEvents.put(id, portEvent);
+ }
+ discoveredAddedPortEvents.put(switchEvent.getDpid(),
+ newPortEvents);
+
+ //
+ // Extract the removed ports
+ //
+ List<PortEvent> removedPortEvents = new LinkedList<>();
+ for (Map.Entry<ByteBuffer, PortEvent> entry : oldPortEvents.entrySet()) {
+ ByteBuffer key = entry.getKey();
+ PortEvent portEvent = entry.getValue();
+ if (! newPortEvents.containsKey(key))
+ removedPortEvents.add(portEvent);
+ }
+
+ // Cleanup old removed ports
+ for (PortEvent portEvent : removedPortEvents)
+ removePortDiscoveryEvent(portEvent);
}
}
@Override
public void removeSwitchDiscoveryEvent(SwitchEvent switchEvent) {
- // TODO: Use a copy of the port events previously added for that switch
- Collection<PortEvent> portEvents = new LinkedList<PortEvent>();
+ // Get the old Port Events
+ Map<ByteBuffer, PortEvent> oldPortEvents =
+ discoveredAddedPortEvents.get(switchEvent.getDpid());
+ if (oldPortEvents == null)
+ oldPortEvents = new HashMap<>();
- if (datastore.deactivateSwitch(switchEvent, portEvents)) {
+ if (datastore.deactivateSwitch(switchEvent, oldPortEvents.values())) {
// Send out notification
eventChannel.removeEntry(switchEvent.getID());
- for (PortEvent portEvent : portEvents) {
+ // Send out notification for each port
+ for (PortEvent portEvent : oldPortEvents.values())
eventChannel.removeEntry(portEvent.getID());
+ discoveredAddedPortEvents.remove(switchEvent.getDpid());
+
+ // Cleanup for each link
+ Map<ByteBuffer, LinkEvent> oldLinkEvents =
+ discoveredAddedLinkEvents.get(switchEvent.getDpid());
+ if (oldLinkEvents != null) {
+ for (LinkEvent linkEvent : oldLinkEvents.values())
+ removeLinkDiscoveryEvent(linkEvent);
+ discoveredAddedLinkEvents.remove(switchEvent.getDpid());
+ }
+
+ // Cleanup for each device
+ Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
+ discoveredAddedDeviceEvents.get(switchEvent.getDpid());
+ if (oldDeviceEvents != null) {
+ for (DeviceEvent deviceEvent : oldDeviceEvents.values())
+ removeDeviceDiscoveryEvent(deviceEvent);
+ discoveredAddedDeviceEvents.remove(switchEvent.getDpid());
}
}
}
@@ -473,6 +538,17 @@
// Send out notification
TopologyEvent topologyEvent = new TopologyEvent(portEvent);
eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
+
+ // Store the new Port Event in the local cache
+ Map<ByteBuffer, PortEvent> oldPortEvents =
+ discoveredAddedPortEvents.get(portEvent.getDpid());
+ if (oldPortEvents == null) {
+ oldPortEvents = new HashMap<>();
+ discoveredAddedPortEvents.put(portEvent.getDpid(),
+ oldPortEvents);
+ }
+ ByteBuffer id = ByteBuffer.wrap(portEvent.getID());
+ oldPortEvents.put(id, portEvent);
}
}
@@ -481,6 +557,49 @@
if (datastore.deactivatePort(portEvent)) {
// Send out notification
eventChannel.removeEntry(portEvent.getID());
+
+ // Cleanup the Port Event from the local cache
+ Map<ByteBuffer, PortEvent> oldPortEvents =
+ discoveredAddedPortEvents.get(portEvent.getDpid());
+ if (oldPortEvents != null) {
+ ByteBuffer id = ByteBuffer.wrap(portEvent.getID());
+ oldPortEvents.remove(id);
+ }
+
+ // Cleanup for the incoming link
+ Map<ByteBuffer, LinkEvent> oldLinkEvents =
+ discoveredAddedLinkEvents.get(portEvent.getDpid());
+ if (oldLinkEvents != null) {
+ for (LinkEvent linkEvent : oldLinkEvents.values()) {
+ if (linkEvent.getDst().equals(portEvent.id)) {
+ removeLinkDiscoveryEvent(linkEvent);
+ //
+ // NOTE: oldLinkEvents was modified by
+ // removeLinkDiscoveryEvent() and cannot be iterated
+ // anymore.
+ //
+ break;
+ }
+ }
+ }
+
+ // Cleanup for the connected devices
+ // TODO: The implementation below is probably wrong
+ List<DeviceEvent> removedDeviceEvents = new LinkedList<>();
+ Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
+ discoveredAddedDeviceEvents.get(portEvent.getDpid());
+ if (oldDeviceEvents != null) {
+ for (DeviceEvent deviceEvent : oldDeviceEvents.values()) {
+ for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
+ if (swp.equals(portEvent.id)) {
+ removedDeviceEvents.add(deviceEvent);
+ break;
+ }
+ }
+ }
+ for (DeviceEvent deviceEvent : removedDeviceEvents)
+ removeDeviceDiscoveryEvent(deviceEvent);
+ }
}
}
@@ -490,6 +609,17 @@
// Send out notification
TopologyEvent topologyEvent = new TopologyEvent(linkEvent);
eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
+
+ // Store the new Link Event in the local cache
+ Map<ByteBuffer, LinkEvent> oldLinkEvents =
+ discoveredAddedLinkEvents.get(linkEvent.getDst().getDpid());
+ if (oldLinkEvents == null) {
+ oldLinkEvents = new HashMap<>();
+ discoveredAddedLinkEvents.put(linkEvent.getDst().getDpid(),
+ oldLinkEvents);
+ }
+ ByteBuffer id = ByteBuffer.wrap(linkEvent.getID());
+ oldLinkEvents.put(id, linkEvent);
}
}
@@ -498,6 +628,14 @@
if (datastore.removeLink(linkEvent)) {
// Send out notification
eventChannel.removeEntry(linkEvent.getID());
+
+ // Cleanup the Link Event from the local cache
+ Map<ByteBuffer, LinkEvent> oldLinkEvents =
+ discoveredAddedLinkEvents.get(linkEvent.getDst().getDpid());
+ if (oldLinkEvents != null) {
+ ByteBuffer id = ByteBuffer.wrap(linkEvent.getID());
+ oldLinkEvents.remove(id);
+ }
}
}
@@ -507,6 +645,20 @@
// Send out notification
TopologyEvent topologyEvent = new TopologyEvent(deviceEvent);
eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
+
+ // Store the new Device Event in the local cache
+ // TODO: The implementation below is probably wrong
+ for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
+ Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
+ discoveredAddedDeviceEvents.get(swp.getDpid());
+ if (oldDeviceEvents == null) {
+ oldDeviceEvents = new HashMap<>();
+ discoveredAddedDeviceEvents.put(swp.getDpid(),
+ oldDeviceEvents);
+ }
+ ByteBuffer id = ByteBuffer.wrap(deviceEvent.getID());
+ oldDeviceEvents.put(id, deviceEvent);
+ }
}
}
@@ -515,6 +667,17 @@
if (datastore.removeDevice(deviceEvent)) {
// Send out notification
eventChannel.removeEntry(deviceEvent.getID());
+
+ // Cleanup the Device Event from the local cache
+ // TODO: The implementation below is probably wrong
+ ByteBuffer id = ByteBuffer.wrap(deviceEvent.getID());
+ for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
+ Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
+ discoveredAddedDeviceEvents.get(swp.getDpid());
+ if (oldDeviceEvents != null) {
+ oldDeviceEvents.remove(id);
+ }
+ }
}
}