Merge "Added note about the URL" into dev/ramcloud-new-datamodel
diff --git a/src/main/java/net/onrc/onos/intent/FlowEntry.java b/src/main/java/net/onrc/onos/intent/FlowEntry.java
index 374e5d6..7aa3d76 100644
--- a/src/main/java/net/onrc/onos/intent/FlowEntry.java
+++ b/src/main/java/net/onrc/onos/intent/FlowEntry.java
@@ -51,7 +51,7 @@
public net.onrc.onos.ofcontroller.util.FlowEntry getFlowEntry() {
net.onrc.onos.ofcontroller.util.FlowEntry entry = new net.onrc.onos.ofcontroller.util.FlowEntry();
entry.setDpid(new Dpid(sw));
- entry.setFlowEntryId(new FlowEntryId(0)); // all zero for now
+ entry.setFlowEntryId(new FlowEntryId(hashCode())); // naive, but useful for now
entry.setFlowEntryMatch(match.getFlowEntryMatch());
FlowEntryActions flowEntryActions = new FlowEntryActions();
for(Action action : actions) {
@@ -71,6 +71,19 @@
return entry;
}
- //TODO: implement hash for cookie
- //TODO: implement equals (don't include operator!)
-}
\ No newline at end of file
+
+ public int hashCode() {
+ return match.hashCode();
+ }
+
+ public boolean equals(Object o) {
+ if(!(o instanceof FlowEntry)) {
+ return false;
+ }
+ FlowEntry other = (FlowEntry) o;
+ // Note: we should not consider the operator for this comparison
+ return this.match.equals(other.match)
+ && this.actions.containsAll(other.actions)
+ && other.actions.containsAll(this.actions);
+ }
+}
diff --git a/src/main/java/net/onrc/onos/intent/ForwardAction.java b/src/main/java/net/onrc/onos/intent/ForwardAction.java
index 6ca514d..9344d8c 100644
--- a/src/main/java/net/onrc/onos/intent/ForwardAction.java
+++ b/src/main/java/net/onrc/onos/intent/ForwardAction.java
@@ -25,5 +25,16 @@
action.setActionOutput(new net.onrc.onos.ofcontroller.util.Port((short) dstPort));
return action;
}
+
+ public int hashCode() {
+ return (int) dstPort;
+ }
-}
\ No newline at end of file
+ public boolean equals(Object o) {
+ if(!(o instanceof ForwardAction)) {
+ return false;
+ }
+ ForwardAction action = (ForwardAction) o;
+ return this.dstPort == action.dstPort;
+ }
+}
diff --git a/src/main/java/net/onrc/onos/intent/Intent.java b/src/main/java/net/onrc/onos/intent/Intent.java
index b6a51cb..c6a960f 100644
--- a/src/main/java/net/onrc/onos/intent/Intent.java
+++ b/src/main/java/net/onrc/onos/intent/Intent.java
@@ -54,6 +54,9 @@
public IntentState setState(IntentState newState) {
logs.add(String.format("setState, oldState:%s, newState:%s, time:%d",
state, newState, System.nanoTime())); // for measurement
+ if (logs.size() > 20) { // TODO this size should be configurable
+ logs.removeFirst();
+ }
IntentState oldState = state;
state = newState;
return oldState;
diff --git a/src/main/java/net/onrc/onos/intent/Match.java b/src/main/java/net/onrc/onos/intent/Match.java
index 5adb598..886fb64 100644
--- a/src/main/java/net/onrc/onos/intent/Match.java
+++ b/src/main/java/net/onrc/onos/intent/Match.java
@@ -1,5 +1,7 @@
package net.onrc.onos.intent;
+import java.util.Arrays;
+
import net.floodlightcontroller.util.MACAddress;
//import net.onrc.onos.ofcontroller.networkgraph.Port;
//import net.onrc.onos.ofcontroller.networkgraph.Switch;
@@ -30,9 +32,9 @@
if(obj instanceof Match) {
Match other = (Match) obj;
return this.sw == other.sw &&
- this.srcMac.equals(other.srcMac) &&
- this.dstMac.equals(other.dstMac) &&
- this.srcPort == other.srcPort;
+ this.srcMac.equals(other.srcMac) &&
+ this.dstMac.equals(other.dstMac) &&
+ this.srcPort == other.srcPort;
}
else {
return false;
@@ -51,4 +53,14 @@
public String toString() {
return "Sw:" + sw + " (" + srcPort + "," + srcMac + "," + dstMac + ")";
}
+
+ @Override
+ public int hashCode() {
+ long[] nums = new long[4];
+ nums[0] = sw;
+ nums[1] = srcPort;
+ nums[2] = srcMac.toLong();
+ nums[3] = dstMac.toLong();
+ return Arrays.hashCode(nums);
+ }
}
diff --git a/src/main/java/net/onrc/onos/intent/persist/PersistIntent.java b/src/main/java/net/onrc/onos/intent/persist/PersistIntent.java
index 515b0bf..380a0f2 100755
--- a/src/main/java/net/onrc/onos/intent/persist/PersistIntent.java
+++ b/src/main/java/net/onrc/onos/intent/persist/PersistIntent.java
@@ -9,6 +9,8 @@
import edu.stanford.ramcloud.JRamCloud;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
import java.util.concurrent.atomic.AtomicLong;
import net.onrc.onos.datagrid.web.IntentResource;
import net.onrc.onos.datastore.RCTable;
@@ -29,7 +31,8 @@
private long range = 10000L;
private final IControllerRegistryService controllerRegistry;
NetworkGraph graph = null;
- private final String intentJournal = "G:IntentJournal";
+ private final static String intentJournal = "G:IntentJournal";
+ private final static int valueStoreLimit = 1024 * 1024;
private RCTable table;
private Kryo kryo = new Kryo();
private ByteArrayOutputStream stream;
@@ -61,6 +64,7 @@
}
private long getNextBlock() {
+ // XXX This method is not thread safe, may lose allocated IdBlock
idBlock = controllerRegistry.allocateUniqueIdBlock(range);
nextId = new AtomicLong(idBlock.getStart());
rangeEnd = idBlock.getEnd();
@@ -73,15 +77,40 @@
// TODO call controllerRegistry.isClusterLeader()
if (leader) {
try {
+ // reserve key 10 entries for multi-write if size over 1MB
+ key *= 10;
kryo.writeObject(output, operations);
output.close();
+ ByteBuffer keyBytes = ByteBuffer.allocate(8).putLong(key);
byte[] buffer = stream.toByteArray();
- table.create(String.valueOf(key).getBytes(), buffer);
+ int total = buffer.length;
+ if ((total >= valueStoreLimit )) {
+ int writeCount = total / valueStoreLimit;
+ int remainder = total % valueStoreLimit;
+ int upperIndex = 0;
+ for (int i = 0; i < writeCount; i++, key++) {
+ keyBytes.clear();
+ keyBytes.putLong(key);
+ keyBytes.flip();
+ upperIndex = (i * valueStoreLimit + valueStoreLimit) - 1;
+ log.debug("writing using indexes {}:{}", (i*valueStoreLimit) ,upperIndex);
+ table.create(keyBytes.array(), Arrays.copyOfRange(buffer, i * valueStoreLimit, upperIndex));
+ }
+ if (remainder > 0) {
+ keyBytes.clear();
+ keyBytes.putLong(key);
+ keyBytes.flip();
+ log.debug("writing using indexes {}:{}" ,upperIndex ,total);
+ table.create(keyBytes.array(), Arrays.copyOfRange(buffer, upperIndex + 1, total - 1));
+ }
+ } else {
+ keyBytes.flip();
+ table.create(keyBytes.array(), buffer);
+ }
log.debug("key is {} value length is {}", key, buffer.length);
stream.reset();
stream.close();
log.debug("persist operations to ramcloud size of operations: {}", operations.size());
- if (buffer.length > 921600 ) log.error("oversize key {} value length is {}", key, buffer.length);
ret = true;
} catch (JRamCloud.ObjectExistsException ex) {
log.warn("Failed to store intent journal with key " + key);
diff --git a/src/main/java/net/onrc/onos/intent/runtime/PlanCalcRuntime.java b/src/main/java/net/onrc/onos/intent/runtime/PlanCalcRuntime.java
index b12711a..5691c53 100644
--- a/src/main/java/net/onrc/onos/intent/runtime/PlanCalcRuntime.java
+++ b/src/main/java/net/onrc/onos/intent/runtime/PlanCalcRuntime.java
@@ -5,13 +5,11 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import net.floodlightcontroller.util.MACAddress;
import net.onrc.onos.intent.FlowEntry;
import net.onrc.onos.intent.Intent;
@@ -23,6 +21,9 @@
import net.onrc.onos.ofcontroller.networkgraph.LinkEvent;
//import net.onrc.onos.ofcontroller.networkgraph.NetworkGraph;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
/**
*
* @author Brian O'Connor <bocon@onlab.us>
@@ -40,7 +41,7 @@
public List<Set<FlowEntry>> computePlan(IntentOperationList intentOps) {
long start = System.nanoTime();
- Set<Collection<FlowEntry>> flowEntries = computeFlowEntries(intentOps);
+ List<Collection<FlowEntry>> flowEntries = computeFlowEntries(intentOps);
long step1 = System.nanoTime();
List<Set<FlowEntry>> plan = buildPhases(flowEntries);
long step2 = System.nanoTime();
@@ -49,8 +50,8 @@
return plan;
}
- private Set<Collection<FlowEntry>> computeFlowEntries(IntentOperationList intentOps) {
- Set<Collection<FlowEntry>> flowEntries = new HashSet<>();
+ private List<Collection<FlowEntry>> computeFlowEntries(IntentOperationList intentOps) {
+ List<Collection<FlowEntry>> flowEntries = new LinkedList<>();
for(IntentOperation i : intentOps) {
if(!(i.intent instanceof PathIntent)) {
log.warn("Not a path intent: {}", i);
@@ -106,7 +107,7 @@
return flowEntries;
}
- private List<Set<FlowEntry>> buildPhases(Set<Collection<FlowEntry>> flowEntries) {
+ private List<Set<FlowEntry>> buildPhases(List<Collection<FlowEntry>> flowEntries) {
Map<FlowEntry, Integer> map = new HashMap<>();
List<Set<FlowEntry>> plan = new ArrayList<>();
for(Collection<FlowEntry> c : flowEntries) {
diff --git a/src/main/java/net/onrc/onos/intent/runtime/PlanInstallModule.java b/src/main/java/net/onrc/onos/intent/runtime/PlanInstallModule.java
index 4d4e437..b8bed85 100644
--- a/src/main/java/net/onrc/onos/intent/runtime/PlanInstallModule.java
+++ b/src/main/java/net/onrc/onos/intent/runtime/PlanInstallModule.java
@@ -2,6 +2,7 @@
import java.util.ArrayList;
import java.util.Collection;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -69,6 +70,9 @@
IntentOperationList intents = intentQueue.take();
//TODO: consider draining the remaining intent lists
// and processing in one big batch
+// List<IntentOperationList> remaining = new LinkedList<>();
+// intentQueue.drainTo(remaining);
+
processIntents(intents);
} catch (InterruptedException e) {
log.warn("Error taking from intent queue: {}", e.getMessage());
@@ -77,12 +81,20 @@
}
private void processIntents(IntentOperationList intents) {
+ log("start_processIntents");
log.debug("Processing OperationList {}", intents);
+ log("begin_computePlan");
List<Set<FlowEntry>> plan = planCalc.computePlan(intents);
+ log("end_computePlan");
log.debug("Plan: {}", plan);
+ log("begin_installPlan");
boolean success = planInstall.installPlan(plan);
+ log("end_installPlan");
+ log("begin_sendInstallNotif");
sendNotifications(intents, true, success);
+ log("end_sendInstallNotif");
+ log("finish");
}
private void sendNotifications(IntentOperationList intents, boolean installed, boolean success) {
@@ -116,8 +128,12 @@
@Override
public void entryAdded(IntentOperationList value) {
+ log("start_intentNotifRecv");
+ log("begin_sendReceivedNotif");
sendNotifications(value, false, false);
-
+ log("end_sendReceivedNotif");
+ log("finish");
+
log.debug("Added OperationList {}", value);
try {
intentQueue.put(value);
@@ -136,6 +152,11 @@
// This channel is a queue, so this method is not needed
}
}
+
+ public static void log(String step) {
+ log.error("Time:{}, Step:{}", System.nanoTime(), step);
+ }
+
@Override
public void startUp(FloodlightModuleContext context) {
// start subscriber
diff --git a/src/main/java/net/onrc/onos/intent/runtime/PlanInstallRuntime.java b/src/main/java/net/onrc/onos/intent/runtime/PlanInstallRuntime.java
index a524875..abd82ed 100644
--- a/src/main/java/net/onrc/onos/intent/runtime/PlanInstallRuntime.java
+++ b/src/main/java/net/onrc/onos/intent/runtime/PlanInstallRuntime.java
@@ -1,17 +1,21 @@
package net.onrc.onos.intent.runtime;
+import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.ExecutionException;
import net.floodlightcontroller.core.IFloodlightProviderService;
import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.internal.OFMessageFuture;
import net.onrc.onos.intent.FlowEntry;
import net.onrc.onos.ofcontroller.flowprogrammer.IFlowPusherService;
//import net.onrc.onos.ofcontroller.networkgraph.NetworkGraph;
import net.onrc.onos.ofcontroller.util.Pair;
+import org.openflow.protocol.OFBarrierReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -61,9 +65,23 @@
// TODO: insert a barrier after each phase on each modifiedSwitch
// TODO: wait for confirmation messages before proceeding
+ List<Pair<IOFSwitch,OFMessageFuture<OFBarrierReply>>> barriers = new ArrayList<>();
+ for(IOFSwitch sw : modifiedSwitches) {
+ barriers.add(new Pair<>(sw, pusher.barrierAsync(sw)));
+ }
+ for(Pair<IOFSwitch,OFMessageFuture<OFBarrierReply>> pair : barriers) {
+ IOFSwitch sw = pair.first;
+ OFMessageFuture<OFBarrierReply> future = pair.second;
+ try {
+ future.get();
+ } catch (InterruptedException | ExecutionException e) {
+ log.error("Barrier message not received for sw: {}", sw);
+ }
+ }
}
long end = System.nanoTime();
log.error("MEASUREMENT: Install plan: {} ns", (end-start));
+
// TODO: we assume that the plan installation succeeds for now
return true;
}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/networkgraph/DeviceEvent.java b/src/main/java/net/onrc/onos/ofcontroller/networkgraph/DeviceEvent.java
index 628b9d4..8bea7f8 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/networkgraph/DeviceEvent.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/networkgraph/DeviceEvent.java
@@ -30,8 +30,9 @@
/**
- * Default constructor.
+ * Default constructor for Serializer to use.
*/
+ @Deprecated
public DeviceEvent() {
mac = null;
}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/networkgraph/LinkEvent.java b/src/main/java/net/onrc/onos/ofcontroller/networkgraph/LinkEvent.java
index 5fd3b82..03c1a43 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/networkgraph/LinkEvent.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/networkgraph/LinkEvent.java
@@ -15,8 +15,9 @@
protected final SwitchPort dst;
/**
- * Default constructor.
+ * Default constructor for Serializer to use.
*/
+ @Deprecated
public LinkEvent() {
src = null;
dst = null;
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 4bd3ea1..801bc1c 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/networkgraph/PortEvent.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/networkgraph/PortEvent.java
@@ -14,8 +14,9 @@
public final Long number;
/**
- * Default constructor.
+ * Default constructor for Serializer to use.
*/
+ @Deprecated
public SwitchPort() {
dpid = null;
number = null;
@@ -77,8 +78,9 @@
// TODO Add Description
/**
- * Default constructor.
+ * Default constructor for Serializer to use.
*/
+ @Deprecated
public PortEvent() {
id = null;
}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/networkgraph/SwitchEvent.java b/src/main/java/net/onrc/onos/ofcontroller/networkgraph/SwitchEvent.java
index 84b9360..f483e77 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/networkgraph/SwitchEvent.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/networkgraph/SwitchEvent.java
@@ -12,8 +12,9 @@
protected final Long dpid;
/**
- * Default constructor.
+ * Default constructor for Serializer to use.
*/
+ @Deprecated
public SwitchEvent() {
dpid = null;
}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/networkgraph/web/NetworkGraphLinksResource.java b/src/main/java/net/onrc/onos/ofcontroller/networkgraph/web/NetworkGraphLinksResource.java
index a244dc1..16da940 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/networkgraph/web/NetworkGraphLinksResource.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/networkgraph/web/NetworkGraphLinksResource.java
@@ -31,10 +31,13 @@
mapper.registerModule(module);
try {
+ graph.acquireReadLock();
return mapper.writeValueAsString(graph.getLinks());
} catch (IOException e) {
log.error("Error writing link list to JSON", e);
return "";
+ } finally {
+ graph.releaseReadLock();
}
}
}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/networkgraph/web/NetworkGraphSwitchesResource.java b/src/main/java/net/onrc/onos/ofcontroller/networkgraph/web/NetworkGraphSwitchesResource.java
index 92e94f6..3e2a57c 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/networkgraph/web/NetworkGraphSwitchesResource.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/networkgraph/web/NetworkGraphSwitchesResource.java
@@ -33,11 +33,13 @@
mapper.registerModule(module);
try {
+ graph.acquireReadLock();
return mapper.writeValueAsString(graph.getSwitches());
} catch (IOException e) {
log.error("Error writing switch list to JSON", e);
return "";
+ } finally {
+ graph.releaseReadLock();
}
}
-
}
diff --git a/web/get_network_graph.py b/web/get_network_graph.py
new file mode 100755
index 0000000..ed3292b
--- /dev/null
+++ b/web/get_network_graph.py
@@ -0,0 +1,114 @@
+#! /usr/bin/env python
+# -*- Mode: python; py-indent-offset: 4; tab-width: 8; indent-tabs-mode: t; -*-
+
+#
+# Get Network Graph Elements
+#
+
+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/ng/links/json ")
+# @app.route("/wm/onos/ng/switches/json ")
+# Sample output:
+
+def print_parsed_result(parsedResult):
+ print '%s' % (parsedResult),
+
+def get_network_switches():
+ try:
+ command = "curl -s \"http://%s:%s/wm/onos/ng/switches/json\"" % (ControllerIP, ControllerPort)
+ debug("get_network_switches %s" % command)
+
+ result = os.popen(command).read()
+ debug("result %s" % result)
+ if len(result) == 0:
+ print "No Switches found"
+ return;
+
+ # parsedResult = result
+ # parsedResult = json.loads(result)
+ parsedResult = json.dumps(json.loads(result), indent=4)
+ debug("parsed %s" % parsedResult)
+ except:
+ log_error("Controller IF has issue")
+ exit(1)
+
+ print_parsed_result(parsedResult)
+
+def get_network_links():
+ try:
+ command = "curl -s \"http://%s:%s/wm/onos/ng/links/json\"" % (ControllerIP, ControllerPort)
+ debug("get_network_links %s" % command)
+
+ result = os.popen(command).read()
+ debug("result %s" % result)
+ if len(result) == 0:
+ print "No Links found"
+ return;
+
+ # parsedResult = result
+ # parsedResult = json.loads(result)
+ parsedResult = json.dumps(json.loads(result), indent=4)
+ debug("parsed %s" % parsedResult)
+ except:
+ log_error("Controller IF has issue")
+ exit(1)
+
+ print_parsed_result(parsedResult)
+
+
+if __name__ == "__main__":
+ usage_msg1 = "Usage:\n"
+ usage_msg2 = "%s <elements_name> : Print network elements with name of <elements_name>\n" % (sys.argv[0])
+ usage_msg3 = " Valid element names:\n"
+ usage_msg4 = " all : Print all network elements\n"
+ usage_msg5 = " switches : Print all switches and ports\n"
+ usage_msg6 = " links : Print all links\n"
+ usage_msg = usage_msg1 + usage_msg2 + usage_msg3 + usage_msg4 + usage_msg5
+ usage_msg = usage_msg + usage_msg6
+
+ # Usage info
+ if len(sys.argv) > 1 and (sys.argv[1] == "-h" or sys.argv[1] == "--help"):
+ print(usage_msg)
+ exit(0)
+
+ # Check arguments
+ if len(sys.argv) < 2:
+ log_error(usage_msg)
+ exit(1)
+
+ if (sys.argv[1] != "all" and sys.argv[1] != "switches" and sys.argv[1] != "links"):
+ log_error(usage_msg)
+ exit(1)
+
+ # Do the work
+ if (sys.argv[1] == "all" or sys.argv[1] == "switches"):
+ get_network_switches()
+ if (sys.argv[1] == "all" or sys.argv[1] == "links"):
+ get_network_links()