Added support in the TopologyManager for processing explicitly configured
Topology Elements.
This is needed for the Optical topology use case.
Also, modified TopologyElement.getConfigState() : if there is no
CONFIG_STATE attribute, then return NOT_CONFIGURED as a default value.
Change-Id: I6e1c6899b750094948c106c1a6f981ec73774303
diff --git a/src/main/java/net/onrc/onos/core/topology/TopologyElement.java b/src/main/java/net/onrc/onos/core/topology/TopologyElement.java
index f169456..81ecb1f 100644
--- a/src/main/java/net/onrc/onos/core/topology/TopologyElement.java
+++ b/src/main/java/net/onrc/onos/core/topology/TopologyElement.java
@@ -195,7 +195,8 @@
*/
@Override
public ConfigState getConfigState() {
- return ConfigState.valueOf(getStringAttribute(ELEMENT_CONFIG_STATE));
+ return ConfigState.valueOf(getStringAttribute(ELEMENT_CONFIG_STATE,
+ ConfigState.NOT_CONFIGURED.toString()));
}
/**
@@ -207,5 +208,4 @@
public AdminStatus getStatus() {
return AdminStatus.valueOf(getStringAttribute(ELEMENT_ADMIN_STATUS));
}
-
}
diff --git a/src/main/java/net/onrc/onos/core/topology/TopologyEvent.java b/src/main/java/net/onrc/onos/core/topology/TopologyEvent.java
index 82fa6e5..28a9821 100644
--- a/src/main/java/net/onrc/onos/core/topology/TopologyEvent.java
+++ b/src/main/java/net/onrc/onos/core/topology/TopologyEvent.java
@@ -218,6 +218,30 @@
}
/**
+ * Returns the config state of the topology element.
+ *
+ * @return the config state of the topology element.
+ */
+ public ConfigState getConfigState() {
+ if (mastershipEvent != null) {
+ return mastershipEvent.getConfigState();
+ }
+ if (switchEvent != null) {
+ return switchEvent.getConfigState();
+ }
+ if (portEvent != null) {
+ return portEvent.getConfigState();
+ }
+ if (linkEvent != null) {
+ return linkEvent.getConfigState();
+ }
+ if (hostEvent != null) {
+ return hostEvent.getConfigState();
+ }
+ return ConfigState.NOT_CONFIGURED; // Default: not configured
+ }
+
+ /**
* Checks if all events contained are equal.
*
* @param obj TopologyEvent to compare against
diff --git a/src/main/java/net/onrc/onos/core/topology/TopologyEventPreprocessor.java b/src/main/java/net/onrc/onos/core/topology/TopologyEventPreprocessor.java
index 475dca1..90f7315 100644
--- a/src/main/java/net/onrc/onos/core/topology/TopologyEventPreprocessor.java
+++ b/src/main/java/net/onrc/onos/core/topology/TopologyEventPreprocessor.java
@@ -1,6 +1,7 @@
package net.onrc.onos.core.topology;
import java.nio.ByteBuffer;
+import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
@@ -51,7 +52,7 @@
//
// Switch mastership state (updated by the topology events)
//
- Map<Dpid, OnosInstanceId> switchMastership = new HashMap<>();
+ private Map<Dpid, OnosInstanceId> switchMastership = new HashMap<>();
/**
* Constructor for a given Registry Service.
@@ -69,14 +70,14 @@
private final OnosInstanceId onosInstanceId;
// The last ADD events received from this ONOS instance
- Map<ByteBuffer, TopologyEvent> topologyEvents = new HashMap<>();
+ private Map<ByteBuffer, TopologyEvent> topologyEvents = new HashMap<>();
/**
* Constructor for a given ONOS Instance ID.
*
* @param onosInstanceId the ONOS Instance ID.
*/
- OnosInstanceLastAddEvents(OnosInstanceId onosInstanceId) {
+ private OnosInstanceLastAddEvents(OnosInstanceId onosInstanceId) {
this.onosInstanceId = checkNotNull(onosInstanceId);
}
@@ -87,10 +88,11 @@
* @return true if the event should be applied to the final Topology
* as well, otherwise false.
*/
- boolean processEvent(EventEntry<TopologyEvent> event) {
+ private boolean processEvent(EventEntry<TopologyEvent> event) {
TopologyEvent topologyEvent = event.eventData();
ByteBuffer id = topologyEvent.getIDasByteBuffer();
OnosInstanceId masterId = null;
+ boolean isConfigured = false;
// Get the Master of the Origin DPID
Dpid dpid = topologyEvent.getOriginDpid();
@@ -98,6 +100,10 @@
masterId = switchMastership.get(dpid);
}
+ if (topologyEvent.getConfigState() == ConfigState.CONFIGURED) {
+ isConfigured = true;
+ }
+
//
// Apply the event based on its type
//
@@ -106,7 +112,7 @@
topologyEvents.put(id, topologyEvent);
reorderedEvents.remove(id);
// Allow the ADD only if the event was originated by the Master
- return onosInstanceId.equals(masterId);
+ return isConfigured || onosInstanceId.equals(masterId);
case ENTRY_REMOVE:
reorderedEvents.remove(id);
@@ -121,7 +127,7 @@
if (masterId == null) {
return true;
}
- return onosInstanceId.equals(masterId);
+ return isConfigured || onosInstanceId.equals(masterId);
default:
log.error("Unknown topology event {}", event.eventType());
@@ -139,7 +145,7 @@
* @param dpid the DPID to use.
* @return a list of postponed events for the given DPID.
*/
- List<EventEntry<TopologyEvent>> getPostponedEvents(Dpid dpid) {
+ private List<EventEntry<TopologyEvent>> getPostponedEvents(Dpid dpid) {
List<EventEntry<TopologyEvent>> result = new LinkedList<>();
//
@@ -169,7 +175,7 @@
*
* @return a list of previously reordered events.
*/
- List<EventEntry<TopologyEvent>> extractReorderedEvents() {
+ private List<EventEntry<TopologyEvent>> extractReorderedEvents() {
List<EventEntry<TopologyEvent>> result = new LinkedList<>();
//
@@ -202,6 +208,77 @@
}
/**
+ * Processes a Mastership Event.
+ *
+ * @param instance the ONOS instance state to use.
+ * @param event the event to process.
+ * @return a list of postponed events if the processed event is a
+ * Mastership Event for a new Master, otherwise an empty list.
+ */
+ private List<EventEntry<TopologyEvent>> processMastershipEvent(
+ OnosInstanceLastAddEvents instance,
+ EventEntry<TopologyEvent> event) {
+ TopologyEvent topologyEvent = event.eventData();
+ MastershipEvent mastershipEvent = topologyEvent.getMastershipEvent();
+
+ if (mastershipEvent == null) {
+ return Collections.emptyList(); // Not a Mastership Event
+ }
+
+ OnosInstanceId onosInstanceId = topologyEvent.getOnosInstanceId();
+ Dpid dpid = mastershipEvent.getDpid();
+ boolean newMaster = false;
+
+ //
+ // Update the Switch Mastership state:
+ // - If ADD a MASTER and the Mastership is confirmed by the
+ // Registry Service, or if the ADD is explicitly CONFIGURED,
+ // then add to the Mastership map and fetch the postponed
+ // events from the originating ONOS Instance.
+ // - Otherwise, remove from the Mastership map, but only if it is
+ // the current MASTER.
+ //
+ if ((event.eventType() == EventEntry.Type.ENTRY_ADD) &&
+ (mastershipEvent.getRole() == Role.MASTER)) {
+
+ //
+ // Accept if explicitly configured, otherwise check
+ // with the Registry Service.
+ //
+ if (topologyEvent.getConfigState() == ConfigState.CONFIGURED) {
+ newMaster = true;
+ } else {
+ //
+ // Check with the Registry Service as well
+ //
+ try {
+ String rc =
+ registryService.getControllerForSwitch(dpid.value());
+ if ((rc != null) &&
+ onosInstanceId.equals(new OnosInstanceId(rc))) {
+ newMaster = true;
+ }
+ } catch (RegistryException e) {
+ log.error("Caught RegistryException while pre-processing Mastership Event", e);
+ }
+ }
+ }
+
+ if (newMaster) {
+ // Add to the map
+ switchMastership.put(dpid, onosInstanceId);
+ return instance.getPostponedEvents(dpid);
+ }
+
+ // Not a Master: eventually remove from the map
+ OnosInstanceId oldId = switchMastership.get(dpid);
+ if (onosInstanceId.equals(oldId)) {
+ switchMastership.remove(dpid);
+ }
+ return Collections.emptyList();
+ }
+
+ /**
* Pre-processes a list of events.
*
* @param events the events to pre-process.
@@ -215,7 +292,7 @@
// Process the events
//
for (EventEntry<TopologyEvent> event : events) {
- List<EventEntry<TopologyEvent>> postponedEvents = null;
+ List<EventEntry<TopologyEvent>> postponedEvents;
// Ignore NO-OP events
if (event.isNoop()) {
@@ -236,49 +313,7 @@
instanceState.put(onosInstanceId, instance);
}
- //
- // Update the Switch Mastership state:
- // - If ADD a MASTER and the Mastership is confirmed by the
- // Registry Service, then add to the Mastership map and fetch
- // the postponed events from the originating ONOS Instance.
- // - Otherwise, remove from the Mastership map, but only if it is
- // the current MASTER.
- //
- MastershipEvent mastershipEvent =
- topologyEvent.getMastershipEvent();
- if (mastershipEvent != null) {
- Dpid dpid = mastershipEvent.getDpid();
- boolean newMaster = false;
-
- if ((event.eventType() == EventEntry.Type.ENTRY_ADD) &&
- (mastershipEvent.getRole() == Role.MASTER)) {
- //
- // Check with the Registry Service as well
- //
- try {
- String rc =
- registryService.getControllerForSwitch(dpid.value());
- if ((rc != null) &&
- onosInstanceId.equals(new OnosInstanceId(rc))) {
- newMaster = true;
- }
- } catch (RegistryException e) {
- log.error("Caught RegistryException while pre-processing Mastership Event", e);
- }
- }
-
- if (newMaster) {
- // Add to the map
- switchMastership.put(dpid, onosInstanceId);
- postponedEvents = instance.getPostponedEvents(dpid);
- } else {
- // Eventually remove from the map
- OnosInstanceId oldId = switchMastership.get(dpid);
- if (onosInstanceId.equals(oldId)) {
- switchMastership.remove(dpid);
- }
- }
- }
+ postponedEvents = processMastershipEvent(instance, event);
//
// Process the event and eventually store it in the
@@ -289,9 +324,7 @@
}
// Add the postponed events (if any)
- if (postponedEvents != null) {
- result.addAll(postponedEvents);
- }
+ result.addAll(postponedEvents);
}
// Extract and add the previously reordered events
diff --git a/src/test/java/net/onrc/onos/core/topology/TopologyManagerTest.java b/src/test/java/net/onrc/onos/core/topology/TopologyManagerTest.java
index ae783cc..14a3685 100644
--- a/src/test/java/net/onrc/onos/core/topology/TopologyManagerTest.java
+++ b/src/test/java/net/onrc/onos/core/topology/TopologyManagerTest.java
@@ -1551,4 +1551,142 @@
theTopologyListener.clear();
events.clear();
}
+
+ /**
+ * Tests processing of Configured Switch Events with Mastership switchover
+ * between two ONOS instance, and the delivery of the topology events.
+ * <p/>
+ * NOTE: This test is similar to testProcessSwitchMastershipSwitchover()
+ * except that the topology and all events are considered as statically
+ * configured.
+ * <p/>
+ * We test the following scenario:
+ * - Initially, a Mastership Event and a Switch Event from one ONOS
+ * instance are processed - both events should be delivered.
+ * - Later, a Mastership Event and a Switch event from another ONOS
+ * instances are processed - both events should be delivered.
+ */
+ @Test
+ public void testProcessConfiguredSwitchMastershipSwitchover() {
+ TopologyEvents topologyEvents;
+ List<EventEntry<TopologyEvent>> events = new LinkedList<>();
+ EventEntry<TopologyEvent> eventEntry;
+ TopologyEvent topologyMastershipEvent;
+ TopologyEvent topologySwitchEvent;
+
+ setupTopologyManagerWithEventHandler();
+
+ // Reset the Registry Service so it is not used
+ reset(registryService);
+
+ // Prepare the Mastership Event from the first ONOS instance
+ Role role = Role.MASTER;
+ MastershipEvent mastershipEvent =
+ new MastershipEvent(DPID_1, ONOS_INSTANCE_ID_1, role);
+ mastershipEvent.createStringAttribute(
+ TopologyElement.ELEMENT_CONFIG_STATE,
+ ConfigState.CONFIGURED.toString());
+ topologyMastershipEvent = new TopologyEvent(mastershipEvent,
+ ONOS_INSTANCE_ID_1);
+
+ // Prepare the Switch Event from the first ONOS instance
+ SwitchEvent switchEvent = new SwitchEvent(DPID_1);
+ switchEvent.createStringAttribute(
+ TopologyElement.ELEMENT_CONFIG_STATE,
+ ConfigState.CONFIGURED.toString());
+ topologySwitchEvent = new TopologyEvent(switchEvent,
+ ONOS_INSTANCE_ID_1);
+
+ // Add the Mastership Event
+ eventEntry = new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
+ topologyMastershipEvent);
+ events.add(eventEntry);
+
+ // Add the Switch Event
+ eventEntry = new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
+ topologySwitchEvent);
+ events.add(eventEntry);
+
+ // Process the events
+ TestUtils.callMethod(theEventHandler, "processEvents",
+ List.class, events);
+
+ // Check the fired events: both events should be fired
+ topologyEvents = theTopologyListener.topologyEvents;
+ assertNotNull(topologyEvents);
+ assertThat(topologyEvents.getAddedMastershipEvents(),
+ hasItem(mastershipEvent));
+ assertThat(topologyEvents.getAddedSwitchEvents(),
+ hasItem(switchEvent));
+ theTopologyListener.clear();
+ events.clear();
+
+ // Prepare the Mastership Event from the second ONOS instance
+ role = Role.MASTER;
+ mastershipEvent = new MastershipEvent(DPID_1,
+ ONOS_INSTANCE_ID_2, role);
+ mastershipEvent.createStringAttribute(
+ TopologyElement.ELEMENT_CONFIG_STATE,
+ ConfigState.CONFIGURED.toString());
+ topologyMastershipEvent = new TopologyEvent(mastershipEvent,
+ ONOS_INSTANCE_ID_2);
+
+ // Prepare the Switch Event from second ONOS instance
+ switchEvent = new SwitchEvent(DPID_1);
+ switchEvent.createStringAttribute(
+ TopologyElement.ELEMENT_CONFIG_STATE,
+ ConfigState.CONFIGURED.toString());
+ topologySwitchEvent = new TopologyEvent(switchEvent,
+ ONOS_INSTANCE_ID_2);
+
+ // Add the Mastership Event
+ eventEntry = new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
+ topologyMastershipEvent);
+ events.add(eventEntry);
+
+ // Add the Switch Event
+ eventEntry = new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
+ topologySwitchEvent);
+ events.add(eventEntry);
+
+ // Process the events
+ TestUtils.callMethod(theEventHandler, "processEvents",
+ List.class, events);
+
+ // Check the fired events: both events should be fired
+ topologyEvents = theTopologyListener.topologyEvents;
+ assertNotNull(topologyEvents);
+ assertThat(topologyEvents.getAddedMastershipEvents(),
+ hasItem(mastershipEvent));
+ assertThat(topologyEvents.getAddedSwitchEvents(),
+ hasItem(switchEvent));
+ theTopologyListener.clear();
+ events.clear();
+
+ // Prepare the REMOVE Switch Event from first ONOS instance
+ //
+ // NOTE: This event only is explicitly marked as NOT_CONFIGURED,
+ // otherwise it will override the previous configuration events.
+ //
+ switchEvent = new SwitchEvent(DPID_1);
+ switchEvent.createStringAttribute(
+ TopologyElement.ELEMENT_CONFIG_STATE,
+ ConfigState.NOT_CONFIGURED.toString());
+ topologySwitchEvent = new TopologyEvent(switchEvent,
+ ONOS_INSTANCE_ID_1);
+ // Add the Switch Event
+ eventEntry = new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_REMOVE,
+ topologySwitchEvent);
+ events.add(eventEntry);
+
+ // Process the events
+ TestUtils.callMethod(theEventHandler, "processEvents",
+ List.class, events);
+
+ // Check the fired events: no events should be fired
+ topologyEvents = theTopologyListener.topologyEvents;
+ assertNull(topologyEvents);
+ theTopologyListener.clear();
+ events.clear();
+ }
}