Merge "adding some logging and checking Intent type more carefully" into dev/ramcloud-new-datamodel
diff --git a/src/main/java/net/onrc/onos/datagrid/web/DatagridWebRoutable.java b/src/main/java/net/onrc/onos/datagrid/web/DatagridWebRoutable.java
index 28399c8..a8c3f5b 100755
--- a/src/main/java/net/onrc/onos/datagrid/web/DatagridWebRoutable.java
+++ b/src/main/java/net/onrc/onos/datagrid/web/DatagridWebRoutable.java
@@ -20,6 +20,7 @@
router.attach("/add/intents/json", IntentResource.class);
router.attach("/get/intents/json", IntentResource.class);
router.attach("/get/intent/{intent_id}/json", IntentResource.class);
+ router.attach("/get/ng-events/json", GetNGEventsResource.class);
return router;
}
diff --git a/src/main/java/net/onrc/onos/datagrid/web/GetNGEventsResource.java b/src/main/java/net/onrc/onos/datagrid/web/GetNGEventsResource.java
new file mode 100644
index 0000000..20efa68
--- /dev/null
+++ b/src/main/java/net/onrc/onos/datagrid/web/GetNGEventsResource.java
@@ -0,0 +1,41 @@
+package net.onrc.onos.datagrid.web;
+
+import java.util.Collection;
+
+import net.onrc.onos.datagrid.IDatagridService;
+import net.onrc.onos.datagrid.IEventChannel;
+import net.onrc.onos.ofcontroller.networkgraph.TopologyEvent;
+import net.onrc.onos.ofcontroller.networkgraph.TopologyManager;
+
+import org.restlet.resource.Get;
+import org.restlet.resource.ServerResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class GetNGEventsResource extends ServerResource {
+
+ public static final Logger log = LoggerFactory.getLogger(GetNGEventsResource.class);
+
+ @Get("json")
+ public String retrieve() {
+ IDatagridService datagridService =
+ (IDatagridService) getContext().getAttributes().
+ get(IDatagridService.class.getCanonicalName());
+
+
+ log.debug("Get network graph events");
+
+ IEventChannel<byte[], TopologyEvent> channel = datagridService.createChannel(TopologyManager.EVENT_CHANNEL_NAME,
+ byte[].class, TopologyEvent.class);
+
+ Collection<TopologyEvent> entries = channel.getAllEntries();
+
+ String result = "";
+ for (TopologyEvent event : entries) {
+ result += event.toString() + "\n";
+ }
+
+ return result;
+ }
+
+}
diff --git a/src/main/java/net/onrc/onos/intent/Intent.java b/src/main/java/net/onrc/onos/intent/Intent.java
index 9a40325..b6a51cb 100644
--- a/src/main/java/net/onrc/onos/intent/Intent.java
+++ b/src/main/java/net/onrc/onos/intent/Intent.java
@@ -1,5 +1,9 @@
package net.onrc.onos.intent;
+import java.util.LinkedList;
+
+import com.esotericsoftware.kryo.serializers.FieldSerializer.Optional;
+
/**
* @author Toshio Koide (t-koide@onlab.us)
*/
@@ -18,19 +22,25 @@
private String id;
private IntentState state = IntentState.CREATED;
+ @Optional(value="logs")
+ private LinkedList<String> logs = new LinkedList<>();
+
/**
* Default constructor for Kryo deserialization
*/
protected Intent() {
+ logs.add(String.format("created, time:%d", System.nanoTime())); // for measurement
}
public Intent(String id) {
+ logs.add(String.format("created, time:%d", System.nanoTime())); // for measurement
this.id = id;
}
public Intent(String id, IntentState state) {
+ logs.add(String.format("created, time:%d", System.nanoTime())); // for measurement
+ setState(state);
this.id = id;
- this.state = state;
}
public String getId() {
@@ -42,11 +52,17 @@
}
public IntentState setState(IntentState newState) {
+ logs.add(String.format("setState, oldState:%s, newState:%s, time:%d",
+ state, newState, System.nanoTime())); // for measurement
IntentState oldState = state;
state = newState;
return oldState;
}
+ public LinkedList<String> getLogs() {
+ return logs;
+ }
+
@Override
public int hashCode() {
return (id == null) ? 0 : id.hashCode();
diff --git a/src/main/java/net/onrc/onos/intent/PathIntent.java b/src/main/java/net/onrc/onos/intent/PathIntent.java
index 28e2dd3..9a49035 100644
--- a/src/main/java/net/onrc/onos/intent/PathIntent.java
+++ b/src/main/java/net/onrc/onos/intent/PathIntent.java
@@ -11,7 +11,7 @@
protected Intent parentIntent;
public static String createFirstId(String parentId) {
- return String.format("pi%s___0", parentId);
+ return String.format("%s___0", parentId);
}
public static String createNextId(String currentId) {
diff --git a/src/main/java/net/onrc/onos/intent/PathIntentMap.java b/src/main/java/net/onrc/onos/intent/PathIntentMap.java
index d70def2..85ea16c 100644
--- a/src/main/java/net/onrc/onos/intent/PathIntentMap.java
+++ b/src/main/java/net/onrc/onos/intent/PathIntentMap.java
@@ -7,22 +7,47 @@
import net.onrc.onos.ofcontroller.networkgraph.Link;
import net.onrc.onos.ofcontroller.networkgraph.LinkEvent;
+import net.onrc.onos.ofcontroller.networkgraph.PortEvent.SwitchPort;
/**
* @author Toshio Koide (t-koide@onlab.us)
*/
public class PathIntentMap extends IntentMap {
- protected HashMap<LinkEvent, HashSet<PathIntent>> linkToIntents = new HashMap<>();
+ private HashMap<Long, HashMap<Long, HashSet<PathIntent>>> intents;
+
+ public PathIntentMap() {
+ intents = new HashMap<>();
+ }
+
+ private HashSet<PathIntent> get(SwitchPort swPort) {
+ Long dpid = swPort.getDpid();
+ Long port = swPort.getNumber();
+ HashMap<Long, HashSet<PathIntent>> portToIntents = intents.get(dpid);
+ if (portToIntents == null) {
+ portToIntents = new HashMap<>();
+ intents.put(dpid, portToIntents);
+ }
+ HashSet<PathIntent> targetIntents = portToIntents.get(port);
+ if (targetIntents == null) {
+ targetIntents = new HashSet<>();
+ portToIntents.put(port, targetIntents);
+ }
+ return targetIntents;
+ }
+
+ private void put(SwitchPort swPort, PathIntent intent) {
+ get(swPort).add(intent);
+ }
@Override
protected void putIntent(Intent intent) {
+ if (!(intent instanceof PathIntent)) return; // TODO throw exception
super.putIntent(intent);
- for (LinkEvent linkEvent: ((PathIntent) intent).getPath()) {
- HashSet<PathIntent> value = linkToIntents.get(linkEvent);
- if (value == null)
- value = new HashSet<PathIntent>();
- value.add((PathIntent) intent);
- linkToIntents.put(linkEvent, value);
+
+ PathIntent pathIntent = (PathIntent) intent;
+ for (LinkEvent linkEvent: pathIntent.getPath()) {
+ put(linkEvent.getSrc(), (PathIntent) intent);
+ put(linkEvent.getDst(), (PathIntent) intent);
}
}
@@ -30,20 +55,38 @@
protected void removeIntent(String intentId) {
PathIntent intent = (PathIntent) getIntent(intentId);
for (LinkEvent linkEvent: intent.getPath()) {
- HashSet<PathIntent> value = linkToIntents.get(linkEvent);
- value.remove(intent);
+ get(linkEvent.getSrc()).remove(intent);
+ get(linkEvent.getDst()).remove(intent);
}
super.removeIntent(intentId);
}
public Collection<PathIntent> getIntentsByLink(LinkEvent linkEvent) {
- Collection<PathIntent> intents = linkToIntents.get(linkEvent);
- if (intents == null) {
- return null;
+ return getIntentsByPort(
+ linkEvent.getSrc().getDpid(),
+ linkEvent.getSrc().getNumber());
+ }
+
+ public Collection<PathIntent> getIntentsByPort(Long dpid, Long port) {
+ HashMap<Long, HashSet<PathIntent>> portToIntents = intents.get(dpid);
+ if (portToIntents != null) {
+ HashSet<PathIntent> targetIntents = portToIntents.get(port);
+ if (targetIntents != null) {
+ return Collections.unmodifiableCollection(targetIntents);
+ }
}
- else {
- return Collections.unmodifiableCollection(intents);
+ return new HashSet<>();
+ }
+
+ public Collection<PathIntent> getIntentsByDpid(Long dpid) {
+ HashSet<PathIntent> result = new HashSet<>();
+ HashMap<Long, HashSet<PathIntent>> portToIntents = intents.get(dpid);
+ if (portToIntents != null) {
+ for (HashSet<PathIntent> targetIntents: portToIntents.values()) {
+ result.addAll(targetIntents);
+ }
}
+ return result;
}
/**
@@ -55,7 +98,7 @@
if (link == null) return null;
Double bandwidth = link.getCapacity();
LinkEvent linkEvent = new LinkEvent(link);
- if (!bandwidth.isInfinite() && linkToIntents.containsKey(linkEvent)) {
+ if (!bandwidth.isInfinite()) {
for (PathIntent intent: getIntentsByLink(linkEvent)) {
Double intentBandwidth = intent.getBandwidth();
if (intentBandwidth == null || intentBandwidth.isInfinite() || intentBandwidth.isNaN())
diff --git a/src/main/java/net/onrc/onos/intent/runtime/PathCalcRuntime.java b/src/main/java/net/onrc/onos/intent/runtime/PathCalcRuntime.java
index 043a006..64d3def 100644
--- a/src/main/java/net/onrc/onos/intent/runtime/PathCalcRuntime.java
+++ b/src/main/java/net/onrc/onos/intent/runtime/PathCalcRuntime.java
@@ -42,6 +42,9 @@
IntentOperationList pathIntentOpList = new IntentOperationList();
HashMap<Switch, ConstrainedBFSTree> spfTrees = new HashMap<>();
+ // TODO optimize locking of NetworkGraph
+ graph.acquireReadLock();
+
for (IntentOperation intentOp: intentOpList) {
switch (intentOp.operator) {
case ADD:
@@ -119,6 +122,9 @@
break;
}
}
+ // TODO optimize locking of NetworkGraph
+ graph.releaseReadLock();
+
return pathIntentOpList;
}
}
\ No newline at end of file
diff --git a/src/main/java/net/onrc/onos/intent/runtime/PathCalcRuntimeModule.java b/src/main/java/net/onrc/onos/intent/runtime/PathCalcRuntimeModule.java
index 67902dd..2eecf2c 100755
--- a/src/main/java/net/onrc/onos/intent/runtime/PathCalcRuntimeModule.java
+++ b/src/main/java/net/onrc/onos/intent/runtime/PathCalcRuntimeModule.java
@@ -8,6 +8,9 @@
import java.util.Map;
import java.util.Map.Entry;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import net.floodlightcontroller.core.module.FloodlightModuleContext;
import net.floodlightcontroller.core.module.FloodlightModuleException;
import net.floodlightcontroller.core.module.IFloodlightModule;
@@ -48,28 +51,24 @@
private IEventChannel<Long, IntentOperationList> opEventChannel;
private static final String INTENT_OP_EVENT_CHANNEL_NAME = "onos.pathintent";
private static final String INTENT_STATE_EVENT_CHANNEL_NAME = "onos.pathintent_state";
+ private static final Logger log = LoggerFactory.getLogger(PathCalcRuntimeModule.class);
// ================================================================================
// private methods
// ================================================================================
- private void reroutePaths(Collection<LinkEvent> removedLinkEvents) {
- HashSet<PathIntent> oldPaths = new HashSet<>();
- for (LinkEvent linkEvent : removedLinkEvents) {
- Collection<PathIntent> intents = pathIntents.getIntentsByLink(linkEvent);
- if (intents == null)
- continue;
- oldPaths.addAll(intents);
- }
-
- if (oldPaths.isEmpty())
+ private void reroutePaths(Collection<Intent> oldPaths) {
+ if (oldPaths == null || oldPaths.isEmpty())
return;
IntentOperationList reroutingOperation = new IntentOperationList();
- for (PathIntent pathIntent : oldPaths) {
- reroutingOperation.add(Operator.ADD, pathIntent.getParentIntent());
+ for (Intent pathIntent : oldPaths) {
+ reroutingOperation.add(Operator.ADD, ((PathIntent) pathIntent).getParentIntent());
}
- executeIntentOperations(reroutingOperation);
+ }
+
+ private void log(String step) {
+ log.error("Step:{}, Time:{}", step, System.nanoTime());
}
// ================================================================================
@@ -85,14 +84,14 @@
@Override
public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
- Map<Class<? extends IFloodlightService>, IFloodlightService> m = new HashMap<>(1);
+ Map<Class<? extends IFloodlightService>, IFloodlightService> m = new HashMap<>();
m.put(IPathCalcRuntimeService.class, this);
return m;
}
@Override
public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
- Collection<Class<? extends IFloodlightService>> l = new ArrayList<>();
+ Collection<Class<? extends IFloodlightService>> l = new ArrayList<>(2);
l.add(IDatagridService.class);
l.add(INetworkGraphService.class);
return l;
@@ -123,9 +122,12 @@
@Override
public IntentOperationList executeIntentOperations(IntentOperationList list) {
// update the map of high-level intents
+ log("begin_updateInMemoryIntents");
highLevelIntents.executeOperations(list);
+ log("end_updateInMemoryIntents");
// change states of high-level intents
+ log("begin_updateInMemoryIntents");
IntentStateList states = new IntentStateList();
for (IntentOperation op : list) {
String id = op.intent.getId();
@@ -135,15 +137,21 @@
states.put(id, IntentState.INST_REQ);
}
highLevelIntents.changeStates(states);
+ log("end_updateInMemoryIntents");
// calculate path-intents (low-level operations)
+ log("begin_calcPathIntents");
IntentOperationList pathIntentOperations = runtime.calcPathIntents(list, pathIntents);
+ log("end_calcPathIntents");
// persist calculated low-level operations into data store
+ log("begin_persistPathIntents");
long key = persistIntent.getKey();
persistIntent.persistIfLeader(key, pathIntentOperations);
+ log("end_persistPathIntents");
// remove error-intents and reflect them to high-level intents
+ log("begin_removeErrorIntents");
states.clear();
Iterator<IntentOperation> i = pathIntentOperations.iterator();
while (i.hasNext()) {
@@ -154,19 +162,26 @@
}
}
highLevelIntents.changeStates(states);
+ log("end_removeErrorIntents");
- // update the map of low-level intents and publish the low-level
- // operations
+ // update the map of path intents and publish the path operations
+ log("begin_updateInMemoryPathIntents");
pathIntents.executeOperations(pathIntentOperations);
+ log("end_updateInMemoryPathIntents");
- // send remove operation includes intent which has a complete path
- // TODO need optimization
+ // Demo special: add a complete path to remove operation
+ log("begin_addPathToRemoveOperation");
for (IntentOperation op: pathIntentOperations) {
if(op.operator.equals(Operator.REMOVE)) {
op.intent = pathIntents.getIntent(op.intent.getId());
}
}
+ log("end_addPathToRemoveOperation");
+
+ // send notification
+ log("begin_sendNotification");
opEventChannel.addEntry(key, pathIntentOperations);
+ log("end_sendNotification");
return pathIntentOperations;
}
@@ -199,8 +214,35 @@
Collection<LinkEvent> removedLinkEvents,
Collection<DeviceEvent> addedDeviceEvents,
Collection<DeviceEvent> removedDeviceEvents) {
- // TODO add getIntentsByPort() and getIntentsBySwitch() to PathIntentMap.
- reroutePaths(removedLinkEvents);
+
+ log("called_networkGraphEvents");
+ HashSet<Intent> affectedPaths = new HashSet<>();
+
+ if (addedLinkEvents.size() > 0 ||
+ addedPortEvents.size() > 0 ||
+ addedSwitchEvents.size() > 0) {
+ log("begin_getAllIntents");
+ affectedPaths.addAll(getPathIntents().getAllIntents());
+ log("end_getAllIntents");
+ }
+ else {
+ log("begin_getIntentsByLink");
+ for (LinkEvent linkEvent: removedLinkEvents)
+ affectedPaths.addAll(pathIntents.getIntentsByLink(linkEvent));
+ log("end_getIntentsByLink");
+
+ log("begin_getIntentsByPort");
+ for (PortEvent portEvent: removedPortEvents)
+ affectedPaths.addAll(pathIntents.getIntentsByPort(portEvent.getDpid(), portEvent.getNumber()));
+ log("end_getIntentsByPort");
+
+ log("begin_getIntentsByDpid");
+ for (SwitchEvent switchEvent: removedSwitchEvents)
+ affectedPaths.addAll(pathIntents.getIntentsByDpid(switchEvent.getDpid()));
+ log("end_getIntentsByDpid");
+ }
+ reroutePaths(affectedPaths);
+ log("finished_networkGraphEvents");
}
// ================================================================================
@@ -209,6 +251,7 @@
@Override
public void entryAdded(IntentStateList value) {
+ log("called_EntryAdded");
entryUpdated(value);
}
@@ -219,7 +262,9 @@
@Override
public void entryUpdated(IntentStateList value) {
+ log("called_EntryUpdated");
// reflect state changes of path-level intent into application-level intents
+ log("begin_changeStateByNotification");
IntentStateList parentStates = new IntentStateList();
for (Entry<String, IntentState> entry: value.entrySet()) {
PathIntent pathIntent = (PathIntent) pathIntents.getIntent(entry.getKey());
@@ -245,5 +290,6 @@
}
highLevelIntents.changeStates(parentStates);
pathIntents.changeStates(value);
+ log("end_changeStateByNotification");
}
-}
\ No newline at end of file
+}
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 7fe7955..ec3c0e4 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/networkgraph/TopologyManager.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/networkgraph/TopologyManager.java
@@ -48,7 +48,7 @@
.getLogger(TopologyManager.class);
private IEventChannel<byte[], TopologyEvent> eventChannel;
- private static final String EVENT_CHANNEL_NAME = "onos.topology";
+ public static final String EVENT_CHANNEL_NAME = "onos.topology";
private EventHandler eventHandler = new EventHandler();
private final NetworkGraphDatastore datastore;
@@ -387,6 +387,27 @@
return; // No events to dispatch
}
+ //
+ // Debug statements
+ // TODO: Those statements should be removed in the future
+ //
+ for (SwitchEvent switchEvent : apiAddedSwitchEvents)
+ log.debug("Dispatch Network Graph Event: ADDED {}", switchEvent);
+ for (SwitchEvent switchEvent : apiRemovedSwitchEvents)
+ log.debug("Dispatch Network Graph Event: REMOVED {}", switchEvent);
+ for (PortEvent portEvent : apiAddedPortEvents)
+ log.debug("Dispatch Network Graph Event: ADDED {}", portEvent);
+ for (PortEvent portEvent : apiRemovedPortEvents)
+ log.debug("Dispatch Network Graph Event: REMOVED {}", portEvent);
+ for (LinkEvent linkEvent : apiAddedLinkEvents)
+ log.debug("Dispatch Network Graph Event: ADDED {}", linkEvent);
+ for (LinkEvent linkEvent : apiRemovedLinkEvents)
+ log.debug("Dispatch Network Graph Event: REMOVED {}", linkEvent);
+ for (DeviceEvent deviceEvent : apiAddedDeviceEvents)
+ log.debug("Dispatch Network Graph Event: ADDED {}", deviceEvent);
+ for (DeviceEvent deviceEvent : apiRemovedDeviceEvents)
+ log.debug("Dispatch Network Graph Event: REMOVED {}", deviceEvent);
+
// Deliver the events
for (INetworkGraphListener listener : this.networkGraphListeners) {
// TODO: Should copy before handing them over to listener?
@@ -433,16 +454,13 @@
// - Apply reordered Link and Device Events if Switches or Ports
// were added
//
- Map<ByteBuffer, PortEvent> portEvents = reorderedAddedPortEvents;
- Map<ByteBuffer, LinkEvent> linkEvents = reorderedAddedLinkEvents;
- Map<ByteBuffer, DeviceEvent> deviceEvents = reorderedAddedDeviceEvents;
- reorderedAddedPortEvents = new HashMap<>();
- reorderedAddedLinkEvents = new HashMap<>();
- reorderedAddedDeviceEvents = new HashMap<>();
+
//
// Apply reordered Port Events if Switches were added
//
if (hasAddedSwitchEvents) {
+ Map<ByteBuffer, PortEvent> portEvents = reorderedAddedPortEvents;
+ reorderedAddedPortEvents = new HashMap<>();
for (PortEvent portEvent : portEvents.values())
addPort(portEvent);
}
@@ -450,8 +468,13 @@
// Apply reordered Link and Device Events if Switches or Ports
// were added.
//
+ Map<ByteBuffer, LinkEvent> linkEvents = reorderedAddedLinkEvents;
+ reorderedAddedLinkEvents = new HashMap<>();
for (LinkEvent linkEvent : linkEvents.values())
addLink(linkEvent);
+ //
+ Map<ByteBuffer, DeviceEvent> deviceEvents = reorderedAddedDeviceEvents;
+ reorderedAddedDeviceEvents = new HashMap<>();
for (DeviceEvent deviceEvent : deviceEvents.values())
addDevice(deviceEvent);
}
@@ -1225,15 +1248,6 @@
// }
for (RCLink l : RCLink.getAllLinks()) {
- // check if src/dst switch/port exist before triggering event
- Port srcPort = networkGraph.getPort(l.getSrc().dpid,
- l.getSrc().number);
- Port dstPort = networkGraph.getPort(l.getDst().dpid,
- l.getDst().number);
- if (srcPort == null || dstPort == null) {
- continue;
- }
-
LinkEvent linkEvent = new LinkEvent(l.getSrc().dpid,
l.getSrc().number,
l.getDst().dpid,
diff --git a/src/test/java/net/onrc/onos/intent/IntentTest.java b/src/test/java/net/onrc/onos/intent/IntentTest.java
new file mode 100644
index 0000000..abc5373
--- /dev/null
+++ b/src/test/java/net/onrc/onos/intent/IntentTest.java
@@ -0,0 +1,77 @@
+package net.onrc.onos.intent;
+
+import static org.junit.Assert.*;
+
+import java.util.HashSet;
+
+import org.junit.Test;
+
+/**
+ * @author Toshio Koide (t-koide@onlab.us)
+ */
+public class IntentTest {
+ @Test
+ public void testCreateIntent() {
+ Intent intent = new Intent("id");
+ assertEquals("id", intent.getId());
+ assertEquals(Intent.IntentState.CREATED, intent.getState());
+ }
+
+ @Test
+ public void testCreateIntentWithState() {
+ Intent intent = new Intent("id", Intent.IntentState.INST_REQ);
+ assertEquals("id", intent.getId());
+ assertEquals(Intent.IntentState.INST_REQ, intent.getState());
+ }
+
+ @Test
+ public void testSetState() {
+ Intent intent = new Intent("id");
+
+ intent.setState(Intent.IntentState.INST_REQ);
+ assertEquals(Intent.IntentState.INST_REQ, intent.getState());
+
+ intent.setState(Intent.IntentState.DEL_REQ);
+ assertEquals(Intent.IntentState.DEL_REQ, intent.getState());
+ }
+
+ @Test
+ public void testEquals() {
+ Intent intent1 = new Intent("id1");
+ Intent intent2 = new Intent("id1");
+ Intent intent3 = new Intent("id2");
+ Intent intent4 = new Intent("id2");
+
+ assertEquals(intent1, intent2);
+ assertEquals(intent3, intent4);
+
+ assertFalse(intent1.equals(intent3));
+ assertFalse(intent3.equals(intent1));
+
+ intent1.setState(Intent.IntentState.INST_ACK);
+ intent2.setState(Intent.IntentState.INST_NACK);
+ assertEquals(intent1, intent2);
+ }
+
+ @Test
+ public void testHashCode() {
+ Intent intent1 = new Intent("id1");
+ intent1.setState(Intent.IntentState.INST_ACK);
+ Intent intent2 = new Intent("id1");
+ intent2.setState(Intent.IntentState.INST_NACK);
+ Intent intent3 = new Intent("id2");
+ Intent intent4 = new Intent("id2");
+
+ HashSet<Intent> intents = new HashSet<>();
+ intents.add(intent1);
+ intents.add(intent2);
+ intents.add(intent3);
+ intents.add(intent4);
+
+ assertEquals(2, intents.size());
+ assertTrue(intents.contains(intent1));
+ assertTrue(intents.contains(intent2));
+ assertTrue(intents.contains(intent3));
+ assertTrue(intents.contains(intent4));
+ }
+}
diff --git a/src/test/java/net/onrc/onos/intent/PathIntentMapTest.java b/src/test/java/net/onrc/onos/intent/PathIntentMapTest.java
new file mode 100644
index 0000000..1fb96ad
--- /dev/null
+++ b/src/test/java/net/onrc/onos/intent/PathIntentMapTest.java
@@ -0,0 +1,197 @@
+package net.onrc.onos.intent;
+
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.*;
+
+import java.util.Collection;
+
+import net.onrc.onos.intent.IntentOperation.Operator;
+import net.onrc.onos.ofcontroller.networkgraph.Link;
+import net.onrc.onos.ofcontroller.networkgraph.LinkEvent;
+import net.onrc.onos.ofcontroller.networkgraph.Path;
+import net.onrc.onos.ofcontroller.networkgraph.Port;
+import net.onrc.onos.ofcontroller.networkgraph.Switch;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class PathIntentMapTest {
+ Link link12, link23, link24;
+ Switch sw1, sw2, sw3, sw4;
+ Port port11, port22, port21, port23, port31, port41;
+ Path path1, path2;
+ PathIntent intent1, intent2;
+
+ @Before
+ public void setUp() throws Exception {
+ sw1 = createMock(Switch.class);
+ sw2 = createMock(Switch.class);
+ sw3 = createMock(Switch.class);
+ sw4 = createMock(Switch.class);
+ expect(sw1.getDpid()).andReturn(1L).anyTimes();
+ expect(sw2.getDpid()).andReturn(2L).anyTimes();
+ expect(sw3.getDpid()).andReturn(3L).anyTimes();
+ expect(sw4.getDpid()).andReturn(4L).anyTimes();
+ replay(sw1);
+ replay(sw2);
+ replay(sw3);
+ replay(sw4);
+
+ port11 = createMock(Port.class);
+ port22 = createMock(Port.class);
+ port21 = createMock(Port.class);
+ port23 = createMock(Port.class);
+ port31 = createMock(Port.class);
+ port41 = createMock(Port.class);
+ expect(port11.getNumber()).andReturn(1L).anyTimes();
+ expect(port22.getNumber()).andReturn(2L).anyTimes();
+ expect(port21.getNumber()).andReturn(1L).anyTimes();
+ expect(port23.getNumber()).andReturn(3L).anyTimes();
+ expect(port31.getNumber()).andReturn(1L).anyTimes();
+ expect(port41.getNumber()).andReturn(1L).anyTimes();
+ replay(port11);
+ replay(port22);
+ replay(port21);
+ replay(port23);
+ replay(port31);
+ replay(port41);
+
+ link12 = createMock(Link.class);
+ link23 = createMock(Link.class);
+ link24 = createMock(Link.class);
+ expect(link12.getCapacity()).andReturn(1000.0).anyTimes();
+ expect(link23.getCapacity()).andReturn(1000.0).anyTimes();
+ expect(link24.getCapacity()).andReturn(1000.0).anyTimes();
+ expect(link12.getSrcSwitch()).andReturn(sw1).anyTimes();
+ expect(link23.getSrcSwitch()).andReturn(sw2).anyTimes();
+ expect(link24.getSrcSwitch()).andReturn(sw2).anyTimes();
+ expect(link12.getSrcPort()).andReturn(port11).anyTimes();
+ expect(link23.getSrcPort()).andReturn(port21).anyTimes();
+ expect(link24.getSrcPort()).andReturn(port23).anyTimes();
+ expect(link12.getDstSwitch()).andReturn(sw2).anyTimes();
+ expect(link23.getDstSwitch()).andReturn(sw3).anyTimes();
+ expect(link24.getDstSwitch()).andReturn(sw4).anyTimes();
+ expect(link12.getDstPort()).andReturn(port22).anyTimes();
+ expect(link23.getDstPort()).andReturn(port31).anyTimes();
+ expect(link24.getDstPort()).andReturn(port41).anyTimes();
+ replay(link12);
+ replay(link23);
+ replay(link24);
+
+ path1 = new Path();
+ path1.add(new LinkEvent(link12));
+ path1.add(new LinkEvent(link23));
+
+ path2 = new Path();
+ path2.add(new LinkEvent(link12));
+ path2.add(new LinkEvent(link24));
+
+ intent1 = new PathIntent("1", path1, 400.0, new Intent("_1"));
+ intent2 = new PathIntent("2", path2, 400.0, new Intent("_2"));
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ @Test
+ public void testCreate() {
+ PathIntentMap intents = new PathIntentMap();
+ assertEquals(0, intents.getAllIntents().size());
+ }
+
+ @Test
+ public void testGetIntentsByDpid() {
+ IntentOperationList operations = new IntentOperationList();
+ operations.add(Operator.ADD, intent1);
+ operations.add(Operator.ADD, intent2);
+ assertEquals(2, operations.size());
+
+ PathIntentMap intents = new PathIntentMap();
+ intents.executeOperations(operations);
+ assertEquals(2, intents.getAllIntents().size());
+
+ Collection<PathIntent> pathIntents = intents.getIntentsByDpid(1L);
+ assertEquals(2, pathIntents.size());
+ assertTrue(pathIntents.contains(intent1));
+ assertTrue(pathIntents.contains(intent2));
+
+ pathIntents = intents.getIntentsByDpid(2L);
+ assertEquals(2, pathIntents.size());
+ assertTrue(pathIntents.contains(intent1));
+ assertTrue(pathIntents.contains(intent2));
+
+ pathIntents = intents.getIntentsByDpid(3L);
+ assertEquals(1, pathIntents.size());
+ assertTrue(pathIntents.contains(intent1));
+
+ pathIntents = intents.getIntentsByDpid(4L);
+ assertEquals(1, pathIntents.size());
+ assertTrue(pathIntents.contains(intent2));
+ }
+
+ @Test
+ public void testGetPathIntentsByPort() {
+ IntentOperationList operations = new IntentOperationList();
+ operations.add(Operator.ADD, intent1);
+ operations.add(Operator.ADD, intent2);
+ assertEquals(2, operations.size());
+
+ PathIntentMap intents = new PathIntentMap();
+ intents.executeOperations(operations);
+ assertEquals(2, intents.getAllIntents().size());
+
+ Collection<PathIntent> pathIntents = intents.getIntentsByPort(1L, 1L);
+ assertEquals(2, pathIntents.size());
+ assertTrue(pathIntents.contains(intent1));
+ assertTrue(pathIntents.contains(intent2));
+
+ pathIntents = intents.getIntentsByPort(2L, 1L);
+ assertEquals(1, pathIntents.size());
+ assertTrue(pathIntents.contains(intent1));
+
+ pathIntents = intents.getIntentsByPort(2L, 3L);
+ assertEquals(1, pathIntents.size());
+ assertTrue(pathIntents.contains(intent2));
+ }
+
+ @Test
+ public void testGetPathIntentsByLink() {
+ IntentOperationList operations = new IntentOperationList();
+ operations.add(Operator.ADD, intent1);
+ operations.add(Operator.ADD, intent2);
+ assertEquals(2, operations.size());
+
+ PathIntentMap intents = new PathIntentMap();
+ intents.executeOperations(operations);
+ assertEquals(2, intents.getAllIntents().size());
+
+ Collection<PathIntent> pathIntents = intents.getIntentsByLink(new LinkEvent(link12));
+ assertEquals(2, pathIntents.size());
+ assertTrue(pathIntents.contains(intent1));
+ assertTrue(pathIntents.contains(intent2));
+
+ pathIntents = intents.getIntentsByLink(new LinkEvent(link23));
+ assertEquals(1, pathIntents.size());
+ assertTrue(pathIntents.contains(intent1));
+
+ pathIntents = intents.getIntentsByLink(new LinkEvent(link24));
+ assertEquals(1, pathIntents.size());
+ assertTrue(pathIntents.contains(intent2));
+ }
+
+ @Test
+ public void testGetAvailableBandwidth() {
+ IntentOperationList operations = new IntentOperationList();
+ operations.add(Operator.ADD, intent1);
+ operations.add(Operator.ADD, intent2);
+ assertEquals(2, operations.size());
+
+ PathIntentMap intents = new PathIntentMap();
+ intents.executeOperations(operations);
+ assertEquals(2, intents.getAllIntents().size());
+
+ assertEquals(200.0, intents.getAvailableBandwidth(link12), 0.0);
+ }
+}
diff --git a/src/test/java/net/onrc/onos/intent/PathIntentTest.java b/src/test/java/net/onrc/onos/intent/PathIntentTest.java
index 211a68a..dd34e90 100644
--- a/src/test/java/net/onrc/onos/intent/PathIntentTest.java
+++ b/src/test/java/net/onrc/onos/intent/PathIntentTest.java
@@ -34,13 +34,13 @@
@Test
public void testCreateFirstId() {
String id = PathIntent.createFirstId("100");
- assertEquals("pi100___0", id);
+ assertEquals("100___0", id);
}
@Test
public void testCreateNextId() {
- String id = PathIntent.createNextId("pi100___999");
- assertEquals("pi100___1000", id);
+ String id = PathIntent.createNextId("100___999");
+ assertEquals("100___1000", id);
}
@Test
diff --git a/web/get_datagrid_ngevents.py b/web/get_datagrid_ngevents.py
new file mode 100755
index 0000000..34c3338
--- /dev/null
+++ b/web/get_datagrid_ngevents.py
@@ -0,0 +1,63 @@
+#! /usr/bin/env python
+# -*- Mode: python; py-indent-offset: 4; tab-width: 8; indent-tabs-mode: t; -*-
+
+import pprint
+import os
+import sys
+import subprocess
+import json
+import argparse
+import io
+import time
+
+from flask import Flask, json, Response, render_template, make_response, request
+
+## Global Var ##
+ControllerIP="127.0.0.1"
+ControllerPort=8080
+
+DEBUG=0
+pp = pprint.PrettyPrinter(indent=4)
+
+app = Flask(__name__)
+
+## Worker Functions ##
+def log_error(txt):
+ print '%s' % (txt)
+
+def debug(txt):
+ if DEBUG:
+ print '%s' % (txt)
+
+# @app.route("/wm/onos/datagrid/get/map/<map-name>/json ")
+# Sample output:
+
+def print_datagrid_map(parsedResult):
+ print '%s' % (parsedResult)
+
+def get_datagrid_map():
+ try:
+ command = "curl -s \"http://%s:%s/wm/onos/datagrid/get/ng-events/json\"" % (ControllerIP, ControllerPort)
+ debug("get_datagrid_map %s" % command)
+
+ result = os.popen(command).read()
+ debug("result %s" % result)
+ if len(result) == 0:
+ print "No Map found"
+ return;
+
+ # TODO: For now, the string is not JSON-formatted
+ # parsedResult = json.loads(result)
+ parsedResult = result
+ debug("parsed %s" % parsedResult)
+ except:
+ log_error("Controller IF has issue")
+ exit(1)
+
+ print_datagrid_map(parsedResult)
+
+
+if __name__ == "__main__":
+
+ # Do the work
+ get_datagrid_map()
diff --git a/web/topology_rest_napi.py b/web/topology_rest_napi.py
new file mode 100755
index 0000000..45fc814
--- /dev/null
+++ b/web/topology_rest_napi.py
@@ -0,0 +1,208 @@
+#!/usr/bin/env python
+
+import json
+from urllib2 import Request, urlopen, URLError, HTTPError
+from flask import Flask, json, Response, render_template, make_response, request
+
+## Global Var for ON.Lab local REST ##
+RestIP="localhost"
+RestPort=8080
+ONOS_DEFAULT_HOST="localhost" ;# Has to set if LB=False
+DEBUG=1
+controllers=["ubuntu1","ubuntu2","ubuntu3","ubuntu4"]
+
+app = Flask(__name__)
+
+## Worker Functions ##
+def log_error(txt):
+ print '%s' % (txt)
+
+def debug(txt):
+ if DEBUG:
+ print '%s' % (txt)
+
+def node_id(switch_array, dpid):
+ id = -1
+ for i, val in enumerate(switch_array):
+ if val['name'] == dpid:
+ id = i
+ break
+
+ return id
+
+###### ONOS REST API ##############################
+## Worker Func ###
+def get_json(url):
+ code = 200;
+ try:
+ response = urlopen(url)
+ except URLError, e:
+ print "get_json: REST IF %s has issue. Reason: %s" % (url, e.reason)
+ result = ""
+ return (500, result)
+ except HTTPError, e:
+ print "get_json: REST IF %s has issue. Code %s" % (url, e.code)
+ result = ""
+ return (e.code, result)
+
+ result = response.read()
+# parsedResult = json.loads(result)
+ return (code, result)
+
+### File Fetch ###
+@app.route('/ui/img/<filename>', methods=['GET'])
+@app.route('/img/<filename>', methods=['GET'])
+@app.route('/css/<filename>', methods=['GET'])
+@app.route('/js/models/<filename>', methods=['GET'])
+@app.route('/js/views/<filename>', methods=['GET'])
+@app.route('/js/<filename>', methods=['GET'])
+@app.route('/lib/<filename>', methods=['GET'])
+@app.route('/log/<filename>', methods=['GET'])
+@app.route('/', methods=['GET'])
+@app.route('/<filename>', methods=['GET'])
+@app.route('/tpl/<filename>', methods=['GET'])
+@app.route('/ons-demo/<filename>', methods=['GET'])
+@app.route('/ons-demo/js/<filename>', methods=['GET'])
+@app.route('/ons-demo/d3/<filename>', methods=['GET'])
+@app.route('/ons-demo/css/<filename>', methods=['GET'])
+@app.route('/ons-demo/assets/<filename>', methods=['GET'])
+@app.route('/ons-demo/data/<filename>', methods=['GET'])
+def return_file(filename="index.html"):
+ if request.path == "/":
+ fullpath = "./index.html"
+ else:
+ fullpath = str(request.path)[1:]
+
+ try:
+ open(fullpath)
+ except:
+ response = make_response("Cannot find a file: %s" % (fullpath), 500)
+ response.headers["Content-type"] = "text/html"
+ return response
+
+ response = make_response(open(fullpath).read())
+ suffix = fullpath.split(".")[-1]
+
+ if suffix == "html" or suffix == "htm":
+ response.headers["Content-type"] = "text/html"
+ elif suffix == "js":
+ response.headers["Content-type"] = "application/javascript"
+ elif suffix == "css":
+ response.headers["Content-type"] = "text/css"
+ elif suffix == "png":
+ response.headers["Content-type"] = "image/png"
+ elif suffix == "svg":
+ response.headers["Content-type"] = "image/svg+xml"
+
+ return response
+
+## API for ON.Lab local GUI ##
+@app.route('/topology', methods=['GET'])
+def topology_for_gui():
+ try:
+ #url="http://%s:%s/wm/onos/topology/switches/all/json" % (RestIP, RestPort)
+ url="http://%s:%s/wm/onos/ng/switches/json" % (RestIP, RestPort)
+ (code, result) = get_json(url)
+ parsedResult = json.loads(result)
+ except:
+ log_error("REST IF has issue: %s" % url)
+ log_error("%s" % result)
+ return
+
+ topo = {}
+ switches = []
+ links = []
+ devices = []
+
+ for v in parsedResult:
+ if v.has_key('dpid'):
+# if v.has_key('dpid') and str(v['state']) == "ACTIVE":#;if you want only ACTIVE nodes
+ dpid = str(v['dpid'])
+ state = str(v['state'])
+ sw = {}
+ sw['name']=dpid
+ sw['group']= -1
+
+ if state == "INACTIVE":
+ sw['group']=0
+ switches.append(sw)
+
+ try:
+ url="http://%s:%s/wm/onos/registry/switches/json" % (RestIP, RestPort)
+ (code, result) = get_json(url)
+ parsedResult = json.loads(result)
+ except:
+ log_error("REST IF has issue: %s" % url)
+ log_error("%s" % result)
+
+ for key in parsedResult:
+ dpid = key
+ ctrl = parsedResult[dpid][0]['controllerId']
+ sw_id = node_id(switches, dpid)
+ if sw_id != -1:
+ if switches[sw_id]['group'] != 0:
+ switches[sw_id]['group'] = controllers.index(ctrl) + 1
+
+ try:
+ #url = "http://%s:%s/wm/onos/topology/links/json" % (RestIP, RestPort)
+ url = "http://%s:%s/wm/onos/ng/links/json" % (RestIP, RestPort)
+ (code, result) = get_json(url)
+ parsedResult = json.loads(result)
+ except:
+ log_error("REST IF has issue: %s" % url)
+ log_error("%s" % result)
+ return
+# sys.exit(0)
+
+ for v in parsedResult:
+ link = {}
+ if v.has_key('dst-switch'):
+ dst_dpid = str(v['dst-switch'])
+ dst_id = node_id(switches, dst_dpid)
+ if v.has_key('src-switch'):
+ src_dpid = str(v['src-switch'])
+ src_id = node_id(switches, src_dpid)
+ link['source'] = src_id
+ link['target'] = dst_id
+
+ #onpath = 0
+ #for (s,d) in path:
+ # if s == v['src-switch'] and d == v['dst-switch']:
+ # onpath = 1
+ # break
+ #link['type'] = onpath
+
+ links.append(link)
+
+ topo['nodes'] = switches
+ topo['links'] = links
+
+ js = json.dumps(topo)
+ resp = Response(js, status=200, mimetype='application/json')
+ return resp
+
+@app.route("/controller_status")
+def controller_status():
+ url= "http://%s:%d/wm/onos/registry/controllers/json" % (RestIP, RestPort)
+ (code, result) = get_json(url)
+ parsedResult = json.loads(result)
+
+ cont_status=[]
+ for i in controllers:
+ status={}
+ if i in parsedResult:
+ onos=1
+ else:
+ onos=0
+ status["name"]=i
+ status["onos"]=onos
+ status["cassandra"]=0
+ cont_status.append(status)
+
+ js = json.dumps(cont_status)
+ resp = Response(js, status=200, mimetype='application/json')
+ return resp
+
+if __name__ == "__main__":
+ app.debug = True
+ app.run(threaded=True, host="0.0.0.0", port=9000)