Merge branch ARP and DeviceStorageImpl fixes branch.
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/ILinkStorage.java b/src/main/java/net/onrc/onos/ofcontroller/core/ILinkStorage.java
index 483fbda..c8312d4 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/core/ILinkStorage.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/ILinkStorage.java
@@ -43,7 +43,17 @@
* If only dpid is set all links associated with Switch are retrieved
*/
public List<Link> getLinks(Long dpid, short port);
+
public List<Link> getLinks(String dpid);
+
+ /**
+ * Get list of all reverse links connected to the switch specified by
+ * given DPID.
+ * @param dpid DPID of desired switch.
+ * @return List of reverse links. Empty list if no port was found.
+ */
+ public List<Link> getReverseLinks(String dpid);
+
public List<Link> getActiveLinks();
public LinkInfo getLinkInfo(Link link);
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjects.java b/src/main/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjects.java
index 160587f..869333b 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjects.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjects.java
@@ -128,6 +128,10 @@
@JsonIgnore
@Adjacency(label="link")
public Iterable<IPortObject> getLinkedPorts();
+
+ @JsonIgnore
+ @Adjacency(label="link",direction = Direction.IN)
+ public Iterable<IPortObject> getReverseLinkedPorts();
@Adjacency(label="link")
public void removeLink(final IPortObject dest_port);
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/internal/LinkStorageImpl.java b/src/main/java/net/onrc/onos/ofcontroller/core/internal/LinkStorageImpl.java
index 68e2c6f..09e87ca 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/core/internal/LinkStorageImpl.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/internal/LinkStorageImpl.java
@@ -306,6 +306,38 @@
}
/**
+ * Get list of all reverse links connected to the switch specified by
+ * given DPID.
+ * @param dpid DPID of desired switch.
+ * @return List of reverse links. Empty list if no port was found.
+ */
+ @Override
+ public List<Link> getReverseLinks(String dpid) {
+ List<Link> links = new ArrayList<Link>();
+
+ ISwitchObject srcSw = op.searchSwitch(dpid);
+
+ if(srcSw != null) {
+ for(IPortObject srcPort : srcSw.getPorts()) {
+ for(IPortObject dstPort : srcPort.getReverseLinkedPorts()) {
+ ISwitchObject dstSw = dstPort.getSwitch();
+ if(dstSw != null) {
+ Link link = new Link(
+ HexString.toLong(dstSw.getDPID()),
+ dstPort.getNumber(),
+
+ HexString.toLong(srcSw.getDPID()),
+ srcPort.getNumber());
+ links.add(link);
+ }
+ }
+ }
+ }
+
+ return links;
+ }
+
+ /**
* Get list of all links whose state is ACTIVE.
* @return List of active links. Empty list if no port was found.
*/
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/internal/SwitchStorageImpl.java b/src/main/java/net/onrc/onos/ofcontroller/core/internal/SwitchStorageImpl.java
index 1735a36..c01a3cb 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/core/internal/SwitchStorageImpl.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/internal/SwitchStorageImpl.java
@@ -306,6 +306,7 @@
op.commit();
}
}
+ success = true;
} catch (Exception e) {
op.rollback();
e.printStackTrace();
diff --git a/src/main/java/net/onrc/onos/ofcontroller/floodlightlistener/NetworkGraphPublisher.java b/src/main/java/net/onrc/onos/ofcontroller/floodlightlistener/NetworkGraphPublisher.java
index c1f66d9..26292d9 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/floodlightlistener/NetworkGraphPublisher.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/floodlightlistener/NetworkGraphPublisher.java
@@ -3,6 +3,7 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@@ -212,11 +213,29 @@
// TODO publish ADD_SWITCH event here
TopologyElement topologyElement =
new TopologyElement(sw.getId());
+ datagridService.notificationSendTopologyElementAdded(topologyElement);
+ // Add the ports
// TODO: Add only ports that are UP?
for (OFPhysicalPort port : sw.getPorts()) {
- topologyElement.addSwitchPort(port.getPortNumber());
+ TopologyElement topologyElementPort =
+ new TopologyElement(sw.getId(),
+ port.getPortNumber());
+ datagridService.notificationSendTopologyElementAdded(topologyElementPort);
}
- datagridService.notificationSendTopologyElementAdded(topologyElement);
+
+ // Add all links that might be connected already
+ List<Link> links = linkStore.getLinks(HexString.toHexString(sw.getId()));
+ // Add all reverse links as well
+ List<Link> reverseLinks = linkStore.getReverseLinks(HexString.toHexString(sw.getId()));
+ links.addAll(reverseLinks);
+ for (Link link : links) {
+ TopologyElement topologyElementLink =
+ new TopologyElement(link.getSrc(),
+ link.getSrcPort(),
+ link.getDst(),
+ link.getDstPort());
+ datagridService.notificationSendTopologyElementAdded(topologyElementLink);
+ }
}
}
}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowDatabaseOperation.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowDatabaseOperation.java
index d06c62c..926788f 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowDatabaseOperation.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowDatabaseOperation.java
@@ -326,6 +326,44 @@
}
/**
+ * Delete a flow entry from the Network MAP.
+ *
+ * @param dbHandler the Graph Database handler to use.
+ * @param flowObj the corresponding Flow Path object for the Flow Entry.
+ * @param flowEntry the Flow Entry to delete.
+ * @return true on success, otherwise false.
+ */
+ static boolean deleteFlowEntry(GraphDBOperation dbHandler,
+ IFlowPath flowObj,
+ FlowEntry flowEntry) {
+ IFlowEntry flowEntryObj = null;
+ try {
+ flowEntryObj = dbHandler.searchFlowEntry(flowEntry.flowEntryId());
+ } catch (Exception e) {
+ log.error(":deleteFlowEntry FlowEntryId:{} failed",
+ flowEntry.flowEntryId().toString());
+ return false;
+ }
+ //
+ // TODO: Don't print an error for now, because multiple controller
+ // instances might be deleting the same flow entry.
+ //
+ /*
+ if (flowEntryObj == null) {
+ log.error(":deleteFlowEntry FlowEntryId:{} failed: FlowEntry object not found",
+ flowEntry.flowEntryId().toString());
+ return false;
+ }
+ */
+ if (flowEntryObj == null)
+ return true;
+
+ flowObj.removeFlowEntry(flowEntryObj);
+ dbHandler.removeFlowEntry(flowEntryObj);
+ return true;
+ }
+
+ /**
* Delete all previously added flows.
*
* @param dbHandler the Graph Database handler to use.
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowEventHandler.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowEventHandler.java
index 0a6cd76..cb1e678 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowEventHandler.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowEventHandler.java
@@ -74,6 +74,13 @@
}
/**
+ * Get the network topology.
+ *
+ * @return the network topology.
+ */
+ protected Topology getTopology() { return this.topology; }
+
+ /**
* Run the thread.
*/
@Override
@@ -107,7 +114,7 @@
flowEntryEvents.add(eventEntry);
}
- // Process the events (if any)
+ // Process the initial events (if any)
processEvents();
//
@@ -170,6 +177,9 @@
for (EventEntry<FlowPath> eventEntry : flowPathEvents) {
FlowPath flowPath = eventEntry.eventData();
+ log.debug("Flow Event: {} {}", eventEntry.eventType(),
+ flowPath.toString());
+
switch (eventEntry.eventType()) {
case ENTRY_ADD: {
//
@@ -240,6 +250,10 @@
boolean isTopologyModified = false;
for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
TopologyElement topologyElement = eventEntry.eventData();
+
+ log.debug("Topology Event: {} {}", eventEntry.eventType(),
+ topologyElement.toString());
+
switch (eventEntry.eventType()) {
case ENTRY_ADD:
isTopologyModified |= topology.addTopologyElement(topologyElement);
@@ -462,7 +476,7 @@
FlowEntry newFlowEntry =
newFlowEntriesMap.get(oldFlowEntry.dpid().value());
if (newFlowEntry == null) {
- // The old Flow Entry should be deleted
+ // The old Flow Entry should be deleted: not on the path
oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
deletedFlowEntries.add(oldFlowEntry);
@@ -490,7 +504,7 @@
if (oldFlowEntry != null) {
//
- // The old Flow Entry should be deleted
+ // The old Flow Entry should be deleted: path diverges
//
oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
@@ -545,8 +559,7 @@
// Note that the Flow Entries that will be deleted are added at
// the end.
//
- for (FlowEntry flowEntry : deletedFlowEntries)
- finalFlowEntries.add(flowEntry);
+ finalFlowEntries.addAll(deletedFlowEntries);
flowPath.dataPath().setFlowEntries(finalFlowEntries);
return hasChanged;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowManager.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowManager.java
index 4465835..c22b916 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowManager.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowManager.java
@@ -551,6 +551,18 @@
}
/**
+ * Delete a flow entry from the Network MAP.
+ *
+ * @param flowObj the corresponding Flow Path object for the Flow Entry.
+ * @param flowEntry the Flow Entry to delete.
+ * @return true on success, otherwise false.
+ */
+ private boolean deleteFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
+ return FlowDatabaseOperation.deleteFlowEntry(dbHandler, flowObj,
+ flowEntry);
+ }
+
+ /**
* Delete all previously added flows.
*
* @return true on success, otherwise false.
@@ -702,6 +714,15 @@
}
/**
+ * Get the network topology.
+ *
+ * @return the network topology.
+ */
+ public Topology getTopology() {
+ return flowEventHandler.getTopology();
+ }
+
+ /**
* Reconcile a flow.
*
* @param flowObj the flow that needs to be reconciliated.
@@ -840,7 +861,6 @@
* Flow Entries.
*/
public void pushModifiedFlowEntries(Collection<FlowPath> modifiedFlowPaths) {
-
// TODO: For now, the pushing of Flow Entries is disabled
if (true)
return;
@@ -848,57 +868,83 @@
Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
for (FlowPath flowPath : modifiedFlowPaths) {
+ //
+ // Find the Flow Path in the Network MAP.
+ // NOTE: The Flow Path might not be found if the Flow was just
+ // removed by some other controller instance.
+ //
IFlowPath flowObj = dbHandler.searchFlowPath(flowPath.flowId());
- if (flowObj == null) {
- String logMsg = "Cannot find Network MAP entry for Flow Path " +
- flowPath.flowId();
- log.error(logMsg);
- continue;
- }
+ boolean isFlowEntryDeleted = false;
for (FlowEntry flowEntry : flowPath.flowEntries()) {
+ log.debug("Updating Flow Entry: {}", flowEntry.toString());
+
if (flowEntry.flowEntrySwitchState() !=
FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED) {
continue; // No need to update the entry
}
+ if (flowEntry.flowEntryUserState() ==
+ FlowEntryUserState.FE_USER_DELETE) {
+ isFlowEntryDeleted = true;
+ }
+ //
+ // Install the Flow Entries into my switches
+ //
IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
- if (mySwitch == null)
- continue; // Ignore the entry: not my switch
+ if (mySwitch != null) {
+ //
+ // Assign the FlowEntry ID if needed
+ //
+ if (! flowEntry.isValidFlowEntryId()) {
+ long id = getNextFlowEntryId();
+ flowEntry.setFlowEntryId(new FlowEntryId(id));
+ }
- //
- // Assign the FlowEntry ID if needed
- //
- if (! flowEntry.isValidFlowEntryId()) {
- long id = getNextFlowEntryId();
- flowEntry.setFlowEntryId(new FlowEntryId(id));
+ //
+ // Install the Flow Entry into the switch
+ //
+ if (! installFlowEntry(mySwitch, flowPath, flowEntry)) {
+ String logMsg = "Cannot install Flow Entry " +
+ flowEntry.flowEntryId() +
+ " from Flow Path " + flowPath.flowId() +
+ " on switch " + flowEntry.dpid();
+ log.error(logMsg);
+ continue;
+ }
+
+ //
+ // NOTE: Here we assume that the switch has been
+ // successfully updated.
+ //
+ flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
}
//
- // Install the Flow Entry into the switch
+ // TODO: For now Flow Entries are removed from the Datagrid
+ // and from the Network Map by all instances, even if this
+ // Flow Entry is not for our switches.
//
- if (! installFlowEntry(mySwitch, flowPath, flowEntry)) {
- String logMsg = "Cannot install Flow Entry " +
- flowEntry.flowEntryId() +
- " from Flow Path " + flowPath.flowId() +
- " on switch " + flowEntry.dpid();
- log.error(logMsg);
- continue;
- }
+ // This is needed to handle the case a switch going down:
+ // it has no Master controller instance, hence no
+ // controller instance will cleanup its flow entries.
+ // This is sub-optimal: we need to elect a controller
+ // instance to handle the cleanup of such orphaned flow
+ // entries.
+ //
//
- // NOTE: Here we assume that the switch has been successfully
- // updated.
- //
- flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
- //
// Write the Flow Entry to the Datagrid
//
switch (flowEntry.flowEntryUserState()) {
case FE_USER_ADD:
+ if (mySwitch == null)
+ break; // Install only flow entries for my switches
datagridService.notificationSendFlowEntryAdded(flowEntry);
break;
case FE_USER_MODIFY:
+ if (mySwitch == null)
+ break; // Install only flow entries for my switches
datagridService.notificationSendFlowEntryUpdated(flowEntry);
break;
case FE_USER_DELETE:
@@ -909,15 +955,41 @@
//
// Write the Flow Entry to the Network Map
//
- try {
- if (addFlowEntry(flowObj, flowEntry) == null) {
- String logMsg = "Cannot write to Network MAP Flow Entry " +
- flowEntry.flowEntryId() +
- " from Flow Path " + flowPath.flowId() +
- " on switch " + flowEntry.dpid();
- log.error(logMsg);
+ if (mySwitch == null) {
+ if (flowEntry.flowEntryUserState() !=
+ FlowEntryUserState.FE_USER_DELETE) {
continue;
}
+ if (! flowEntry.isValidFlowEntryId())
+ continue;
+ }
+ if (flowObj == null) {
+ String logMsg = "Cannot find Network MAP entry for Flow Path " + flowPath.flowId();
+ continue;
+ }
+ try {
+ switch (flowEntry.flowEntryUserState()) {
+ case FE_USER_ADD:
+ // FALLTHROUGH
+ case FE_USER_MODIFY:
+ if (addFlowEntry(flowObj, flowEntry) == null) {
+ String logMsg = "Cannot write to Network MAP Flow Entry " +
+ flowEntry.flowEntryId() +
+ " from Flow Path " + flowPath.flowId() +
+ " on switch " + flowEntry.dpid();
+ log.error(logMsg);
+ }
+ break;
+ case FE_USER_DELETE:
+ if (deleteFlowEntry(flowObj, flowEntry) == false) {
+ String logMsg = "Cannot remove from Network MAP Flow Entry " +
+ flowEntry.flowEntryId() +
+ " from Flow Path " + flowPath.flowId() +
+ " on switch " + flowEntry.dpid();
+ log.error(logMsg);
+ }
+ break;
+ }
} catch (Exception e) {
String logMsg = "Exception writing Flow Entry to Network MAP";
log.debug(logMsg);
@@ -925,6 +997,26 @@
continue;
}
}
+
+ //
+ // Remove Flow Entries that were deleted
+ //
+ // NOTE: We create a new ArrayList, and add only the Flow Entries
+ // that are NOT FE_USER_DELETE.
+ // This is sub-optimal: if it adds notable processing cost,
+ // the Flow Entries container should be changed to LinkedList
+ // or some other container that has O(1) cost of removing an entry.
+ //
+ if (isFlowEntryDeleted) {
+ ArrayList<FlowEntry> newFlowEntries = new ArrayList<FlowEntry>();
+ for (FlowEntry flowEntry : flowPath.flowEntries()) {
+ if (flowEntry.flowEntryUserState() !=
+ FlowEntryUserState.FE_USER_DELETE) {
+ newFlowEntries.add(flowEntry);
+ }
+ }
+ flowPath.dataPath().setFlowEntries(newFlowEntries);
+ }
}
dbHandler.commit();
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/IFlowService.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/IFlowService.java
index 1f8cd5b..8d362d1 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/IFlowService.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/IFlowService.java
@@ -4,6 +4,7 @@
import net.floodlightcontroller.core.module.IFloodlightService;
import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowPath;
+import net.onrc.onos.ofcontroller.topology.Topology;
import net.onrc.onos.ofcontroller.util.CallerId;
import net.onrc.onos.ofcontroller.util.DataPathEndpoints;
import net.onrc.onos.ofcontroller.util.FlowId;
@@ -112,4 +113,11 @@
* @return the added shortest-path flow on success, otherwise null.
*/
FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath);
+
+ /**
+ * Get the network topology.
+ *
+ * @return the network topology.
+ */
+ Topology getTopology();
}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/topology/Topology.java b/src/main/java/net/onrc/onos/ofcontroller/topology/Topology.java
index d5ceb6a..7d7d739 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/topology/Topology.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/topology/Topology.java
@@ -213,14 +213,6 @@
node = addNode(topologyElement.getSwitch());
isModified = true;
}
- // Add the ports for the switch
- for (Integer portId : topologyElement.getSwitchPorts().values()) {
- Integer port = node.getPort(portId);
- if (port == null) {
- node.addPort(portId);
- isModified = true;
- }
- }
break;
}
case ELEMENT_PORT: {
diff --git a/src/main/java/net/onrc/onos/ofcontroller/topology/TopologyElement.java b/src/main/java/net/onrc/onos/ofcontroller/topology/TopologyElement.java
index 574946d..b01c7d3 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/topology/TopologyElement.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/topology/TopologyElement.java
@@ -24,9 +24,6 @@
private long toSwitchDpid = 0; // The Neighbor Switch DPID
private int toSwitchPort = 0; // The Neighbor Switch Port
- // All (known) ports for a Switch
- private Map<Integer, Integer> switchPorts = new TreeMap<Integer, Integer>();
-
/**
* Default constructor.
*/
@@ -95,28 +92,6 @@
}
/**
- * Get the Switch Ports.
- *
- * NOTE: Applies for Type.ELEMENT_SWITCH
- *
- * @return the collection of Switch Ports.
- */
- public Map<Integer, Integer> getSwitchPorts() {
- return switchPorts;
- }
-
- /**
- * Add a Switch Port.
- *
- * NOTE: Applies for Type.ELEMENT_SWITCH
- *
- * @param switchPort the Switch Port to add.
- */
- public void addSwitchPort(int switchPort) {
- switchPorts.put(switchPort, switchPort);
- }
-
- /**
* Get the Switch Port.
*
* NOTE: Applies for Type.ELEMENT_PORT
diff --git a/src/main/java/net/onrc/onos/ofcontroller/topology/web/RouteResource.java b/src/main/java/net/onrc/onos/ofcontroller/topology/web/RouteResource.java
index b340996..0d33b27 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/topology/web/RouteResource.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/topology/web/RouteResource.java
@@ -1,5 +1,6 @@
package net.onrc.onos.ofcontroller.topology.web;
+import net.onrc.onos.ofcontroller.flowmanager.IFlowService;
import net.onrc.onos.ofcontroller.topology.ITopologyNetService;
import net.onrc.onos.ofcontroller.topology.TopologyManager;
import net.onrc.onos.ofcontroller.util.DataPath;
@@ -18,11 +19,22 @@
@Get("json")
public DataPath retrieve() {
- ITopologyNetService topologyNetService = new TopologyManager("");
+ // Get the services that are needed for the computation
+ ITopologyNetService topologyNetService =
+ (ITopologyNetService)getContext().getAttributes().
+ get(ITopologyNetService.class.getCanonicalName());
+ IFlowService flowService =
+ (IFlowService)getContext().getAttributes().
+ get(IFlowService.class.getCanonicalName());
+
if (topologyNetService == null) {
log.debug("Topology Net Service not found");
return null;
}
+ if (flowService == null) {
+ log.debug("Flow Service not found");
+ return null;
+ }
String srcDpidStr = (String) getRequestAttributes().get("src-dpid");
String srcPortStr = (String) getRequestAttributes().get("src-port");
@@ -37,7 +49,8 @@
Port dstPort = new Port(Short.parseShort(dstPortStr));
DataPath result =
- topologyNetService.getDatabaseShortestPath(
+ topologyNetService.getTopologyShortestPath(
+ flowService.getTopology(),
new SwitchPort(srcDpid, srcPort),
new SwitchPort(dstDpid, dstPort));
if (result != null) {
diff --git a/src/test/java/net/onrc/onos/ofcontroller/core/internal/LinkStorageImplTest.java b/src/test/java/net/onrc/onos/ofcontroller/core/internal/LinkStorageImplTest.java
index abb8809..4aea22a 100644
--- a/src/test/java/net/onrc/onos/ofcontroller/core/internal/LinkStorageImplTest.java
+++ b/src/test/java/net/onrc/onos/ofcontroller/core/internal/LinkStorageImplTest.java
@@ -256,6 +256,21 @@
Link linkToVerifyNot = createFeasibleLink();
assertFalse(links.contains(linkToVerifyNot));
}
+
+ /**
+ * Test if {@link LinkStorageImpl#getReverseLinks(String)} can correctly return Links connected to specific MAC address.
+ */
+ @Test
+ public void testGetReverseLinks_ByString() {
+ Link linkToVeryfy = createExistingLink();
+ String dpid = HexString.toHexString(linkToVeryfy.getDst());
+
+ List<Link> links = linkStorage.getReverseLinks(dpid);
+ assertTrue(links.contains(linkToVeryfy));
+
+ Link linkToVerifyNot = createFeasibleLink();
+ assertFalse(links.contains(linkToVerifyNot));
+ }
/**
* Test if {@link LinkStorageImpl#deleteLink(Link)} can correctly delete a Link.
@@ -447,6 +462,35 @@
}
/**
+ * Class defines a function called back when {@link IPortObject#getReverseLinkedPorts()} is called.
+ * @author Naoki Shiota
+ *
+ */
+ private class GetReverseLinkedPortsCallback implements IAnswer< Iterable<IPortObject> > {
+ private long dpid;
+ private short port;
+
+ public GetReverseLinkedPortsCallback(long dpid, short port) {
+ this.dpid = dpid;
+ this.port = port;
+ }
+
+ @Override
+ public Iterable<IPortObject> answer() throws Throwable {
+ List<IPortObject> ports = new ArrayList<IPortObject>();
+
+ for(Link lk : links) {
+ if(lk.getDst() == dpid && lk.getDstPort() == port) {
+ ports.add(createMockPort(lk.getSrc(), lk.getSrcPort()));
+ }
+ }
+
+ return ports;
+ }
+
+ }
+
+ /**
* Class defines a function called back when {@link LinkStorageImplTest} is called.
* @author Naoki Shiota
*
@@ -567,6 +611,9 @@
// Mock getLinkPorts() method
EasyMock.expect(mockPort.getLinkedPorts()).andAnswer(new GetLinkedPortsCallback(dpid, number)).anyTimes();
+
+ // Mock getReverseLinkPorts() method
+ EasyMock.expect(mockPort.getReverseLinkedPorts()).andAnswer(new GetReverseLinkedPortsCallback(dpid, number)).anyTimes();
// Mock getSwitch() method
EasyMock.expect(mockPort.getSwitch()).andAnswer(new GetSwitchCallback(dpid)).anyTimes();
diff --git a/src/test/java/net/onrc/onos/ofcontroller/core/internal/TestableGraphDBOperation.java b/src/test/java/net/onrc/onos/ofcontroller/core/internal/TestableGraphDBOperation.java
index be9bca4..d7724ae 100644
--- a/src/test/java/net/onrc/onos/ofcontroller/core/internal/TestableGraphDBOperation.java
+++ b/src/test/java/net/onrc/onos/ofcontroller/core/internal/TestableGraphDBOperation.java
@@ -163,6 +163,7 @@
private ISwitchObject sw;
private List<IPortObject> linkedPorts;
+ private List<IPortObject> reverseLinkedPorts;
private List<IDeviceObject> devices;
private List<IFlowEntry> inflows,outflows;
@@ -180,6 +181,7 @@
type = "port";
linkedPorts = new ArrayList<IPortObject>();
+ reverseLinkedPorts = new ArrayList<IPortObject>();
linkedPortsToAdd = new ArrayList<IPortObject>();
linkedPortsToRemove = new ArrayList<IPortObject>();
devices = new ArrayList<IDeviceObject>();
@@ -290,6 +292,9 @@
public Iterable<IPortObject> getLinkedPorts() { return linkedPorts; }
@Override
+ public Iterable<IPortObject> getReverseLinkedPorts() { return reverseLinkedPorts; }
+
+ @Override
public void removeLink(IPortObject dest_port) { linkedPortsToRemove.add(dest_port); }
@Override