Merge "added demo rest api for adding and withdrawing intents in a mesh"
diff --git a/.gitignore b/.gitignore
index 0b28617..8f725d6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,5 +8,6 @@
.checkstyle
target
*.iml
+*.pyc
dependency-reduced-pom.xml
.idea
diff --git a/apps/config/src/main/java/org/onlab/onos/config/NetworkConfigReader.java b/apps/config/src/main/java/org/onlab/onos/config/NetworkConfigReader.java
index f015e36..846e83c 100644
--- a/apps/config/src/main/java/org/onlab/onos/config/NetworkConfigReader.java
+++ b/apps/config/src/main/java/org/onlab/onos/config/NetworkConfigReader.java
@@ -50,7 +50,10 @@
private final Logger log = getLogger(getClass());
- private static final String DEFAULT_CONFIG_FILE = "config/addresses.json";
+ // Current working dir seems to be /opt/onos/apache-karaf-3.0.2
+ // TODO: Set the path to /opt/onos/config
+ private static final String CONFIG_DIR = "../config";
+ private static final String DEFAULT_CONFIG_FILE = "addresses.json";
private String configFileName = DEFAULT_CONFIG_FILE;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
@@ -60,52 +63,9 @@
protected void activate() {
log.info("Started network config reader");
- log.info("Config file set to {}", configFileName);
-
AddressConfiguration config = readNetworkConfig();
-
if (config != null) {
- for (AddressEntry entry : config.getAddresses()) {
-
- ConnectPoint cp = new ConnectPoint(
- DeviceId.deviceId(dpidToUri(entry.getDpid())),
- PortNumber.portNumber(entry.getPortNumber()));
-
- Set<InterfaceIpAddress> interfaceIpAddresses = new HashSet<>();
-
- for (String strIp : entry.getIpAddresses()) {
- // Get the IP address and the subnet mask length
- try {
- String[] splits = strIp.split("/");
- if (splits.length != 2) {
- throw new IllegalArgumentException("Invalid IP address and prefix length format");
- }
- // NOTE: IpPrefix will mask-out the bits after the prefix length.
- IpPrefix subnet = IpPrefix.valueOf(strIp);
- IpAddress addr = IpAddress.valueOf(splits[0]);
- InterfaceIpAddress ia =
- new InterfaceIpAddress(addr, subnet);
- interfaceIpAddresses.add(ia);
- } catch (IllegalArgumentException e) {
- log.warn("Bad format for IP address in config: {}", strIp);
- }
- }
-
- MacAddress macAddress = null;
- if (entry.getMacAddress() != null) {
- try {
- macAddress = MacAddress.valueOf(entry.getMacAddress());
- } catch (IllegalArgumentException e) {
- log.warn("Bad format for MAC address in config: {}",
- entry.getMacAddress());
- }
- }
-
- PortAddresses addresses = new PortAddresses(cp,
- interfaceIpAddresses, macAddress);
-
- hostAdminService.bindAddressesToPort(addresses);
- }
+ applyNetworkConfig(config);
}
}
@@ -114,12 +74,17 @@
log.info("Stopped");
}
+ /**
+ * Reads the network configuration.
+ *
+ * @return the network configuration on success, otherwise null
+ */
private AddressConfiguration readNetworkConfig() {
- File configFile = new File(configFileName);
-
+ File configFile = new File(CONFIG_DIR, configFileName);
ObjectMapper mapper = new ObjectMapper();
try {
+ log.info("Loading config: {}", configFile.getAbsolutePath());
AddressConfiguration config =
mapper.readValue(configFile, AddressConfiguration.class);
@@ -127,12 +92,58 @@
} catch (FileNotFoundException e) {
log.warn("Configuration file not found: {}", configFileName);
} catch (IOException e) {
- log.error("Unable to read config from file:", e);
+ log.error("Error loading configuration", e);
}
return null;
}
+ /**
+ * Applies the network configuration.
+ *
+ * @param config the network configuration to apply
+ */
+ private void applyNetworkConfig(AddressConfiguration config) {
+ for (AddressEntry entry : config.getAddresses()) {
+ ConnectPoint cp = new ConnectPoint(
+ DeviceId.deviceId(dpidToUri(entry.getDpid())),
+ PortNumber.portNumber(entry.getPortNumber()));
+
+ Set<InterfaceIpAddress> interfaceIpAddresses = new HashSet<>();
+ for (String strIp : entry.getIpAddresses()) {
+ // Get the IP address and the subnet mask length
+ try {
+ String[] splits = strIp.split("/");
+ if (splits.length != 2) {
+ throw new IllegalArgumentException("Invalid IP address and prefix length format");
+ }
+ // NOTE: IpPrefix will mask-out the bits after the prefix length.
+ IpPrefix subnet = IpPrefix.valueOf(strIp);
+ IpAddress addr = IpAddress.valueOf(splits[0]);
+ InterfaceIpAddress ia =
+ new InterfaceIpAddress(addr, subnet);
+ interfaceIpAddresses.add(ia);
+ } catch (IllegalArgumentException e) {
+ log.warn("Bad format for IP address in config: {}", strIp);
+ }
+ }
+
+ MacAddress macAddress = null;
+ if (entry.getMacAddress() != null) {
+ try {
+ macAddress = MacAddress.valueOf(entry.getMacAddress());
+ } catch (IllegalArgumentException e) {
+ log.warn("Bad format for MAC address in config: {}",
+ entry.getMacAddress());
+ }
+ }
+
+ PortAddresses addresses = new PortAddresses(cp,
+ interfaceIpAddresses, macAddress);
+ hostAdminService.bindAddressesToPort(addresses);
+ }
+ }
+
private static String dpidToUri(String dpid) {
return "of:" + dpid.replace(":", "");
}
diff --git a/apps/sdnip/src/main/resources/config-examples/addresses.json b/apps/config/src/main/resources/addresses.json
similarity index 100%
rename from apps/sdnip/src/main/resources/config-examples/addresses.json
rename to apps/config/src/main/resources/addresses.json
diff --git a/apps/config/src/main/resources/config.json b/apps/config/src/main/resources/config.json
deleted file mode 100644
index ca4be83..0000000
--- a/apps/config/src/main/resources/config.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "interfaces" : [
- {
- "dpid" : "00:00:00:00:00:00:01",
- "port" : "1",
- "ips" : ["192.168.10.101/24"],
- "mac" : "00:00:00:11:22:33"
- },
- {
- "dpid" : "00:00:00:00:00:00:02",
- "port" : "1",
- "ips" : ["192.168.20.101/24", "192.168.30.101/24"]
- },
- {
- "dpid" : "00:00:00:00:00:00:03",
- "port" : "1",
- "ips" : ["10.1.0.1/16"],
- "mac" : "00:00:00:00:00:01"
- }
- ]
-}
diff --git a/apps/sdnip/src/main/java/org/onlab/onos/sdnip/config/SdnIpConfigReader.java b/apps/sdnip/src/main/java/org/onlab/onos/sdnip/config/SdnIpConfigReader.java
index 2fcd1fe..7262c42 100644
--- a/apps/sdnip/src/main/java/org/onlab/onos/sdnip/config/SdnIpConfigReader.java
+++ b/apps/sdnip/src/main/java/org/onlab/onos/sdnip/config/SdnIpConfigReader.java
@@ -37,24 +37,31 @@
*/
public class SdnIpConfigReader implements SdnIpConfigService {
- private static final Logger log = LoggerFactory.getLogger(SdnIpConfigReader.class);
+ private final Logger log = LoggerFactory.getLogger(getClass());
- private static final String DEFAULT_CONFIG_FILE = "config/sdnip.json";
+ // Current working dir seems to be /opt/onos/apache-karaf-3.0.2
+ // TODO: Set the path to /opt/onos/config
+ private static final String CONFIG_DIR = "../config";
+ private static final String DEFAULT_CONFIG_FILE = "sdnip.json";
private String configFileName = DEFAULT_CONFIG_FILE;
+
private Map<String, BgpSpeaker> bgpSpeakers = new ConcurrentHashMap<>();
private Map<IpAddress, BgpPeer> bgpPeers = new ConcurrentHashMap<>();
/**
- * Reads the info contained in the configuration file.
+ * Reads SDN-IP related information contained in the configuration file.
*
- * @param configFilename The name of configuration file for SDN-IP application.
+ * @param configFilename the name of the configuration file for the SDN-IP
+ * application
*/
private void readConfiguration(String configFilename) {
- File gatewaysFile = new File(configFilename);
+ File configFile = new File(CONFIG_DIR, configFilename);
ObjectMapper mapper = new ObjectMapper();
try {
- Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
+ log.info("Loading config: {}", configFile.getAbsolutePath());
+ Configuration config = mapper.readValue(configFile,
+ Configuration.class);
for (BgpSpeaker speaker : config.getBgpSpeakers()) {
bgpSpeakers.put(speaker.name(), speaker);
}
@@ -64,13 +71,11 @@
} catch (FileNotFoundException e) {
log.warn("Configuration file not found: {}", configFileName);
} catch (IOException e) {
- log.error("Error reading JSON file", e);
+ log.error("Error loading configuration", e);
}
}
public void init() {
- log.debug("Config file set to {}", configFileName);
-
readConfiguration(configFileName);
}
diff --git a/apps/sdnip/src/main/resources/config-examples/README b/apps/sdnip/src/main/resources/config-examples/README
index 502285e..7642a4d 100644
--- a/apps/sdnip/src/main/resources/config-examples/README
+++ b/apps/sdnip/src/main/resources/config-examples/README
@@ -1 +1,5 @@
-ONOS looks for these config files by default in $KARAF_LOG/config/
\ No newline at end of file
+The SDN-IP configuration files should be copied to directory
+ $ONOS_HOME/tools/package/config
+
+After deployment and starting up the ONOS cluster, ONOS looks for these
+configuration files in /opt/onos/config on each cluster member.
diff --git a/cli/src/main/java/org/onlab/onos/cli/net/ConnectivityIntentCommand.java b/cli/src/main/java/org/onlab/onos/cli/net/ConnectivityIntentCommand.java
index e4fc5aa..5c513e3 100644
--- a/cli/src/main/java/org/onlab/onos/cli/net/ConnectivityIntentCommand.java
+++ b/cli/src/main/java/org/onlab/onos/cli/net/ConnectivityIntentCommand.java
@@ -27,6 +27,7 @@
import org.onlab.onos.net.intent.constraint.LambdaConstraint;
import org.onlab.onos.net.resource.Bandwidth;
import org.onlab.packet.Ethernet;
+import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import static com.google.common.base.Strings.isNullOrEmpty;
@@ -48,6 +49,26 @@
required = false, multiValued = false)
private String ethTypeString = "";
+ @Option(name = "--ipProto", description = "IP Protocol",
+ required = false, multiValued = false)
+ private String ipProtoString = null;
+
+ @Option(name = "--ipSrc", description = "Source IP Address",
+ required = false, multiValued = false)
+ private String srcIpString = null;
+
+ @Option(name = "--ipDst", description = "Destination IP Address",
+ required = false, multiValued = false)
+ private String dstIpString = null;
+
+ @Option(name = "--tcpSrc", description = "Source TCP Port",
+ required = false, multiValued = false)
+ private String srcTcpString = null;
+
+ @Option(name = "--tcpDst", description = "Destination TCP Port",
+ required = false, multiValued = false)
+ private String dstTcpString = null;
+
@Option(name = "-b", aliases = "--bandwidth", description = "Bandwidth",
required = false, multiValued = false)
private String bandwidthString = "";
@@ -79,6 +100,26 @@
selectorBuilder.matchEthDst(MacAddress.valueOf(dstMacString));
}
+ if (!isNullOrEmpty(ipProtoString)) {
+ selectorBuilder.matchIPProtocol((byte) Short.parseShort(ipProtoString));
+ }
+
+ if (!isNullOrEmpty(srcIpString)) {
+ selectorBuilder.matchIPSrc(IpPrefix.valueOf(srcIpString));
+ }
+
+ if (!isNullOrEmpty(dstIpString)) {
+ selectorBuilder.matchIPDst(IpPrefix.valueOf(dstIpString));
+ }
+
+ if (!isNullOrEmpty(srcTcpString)) {
+ selectorBuilder.matchTcpSrc((short) Integer.parseInt(srcTcpString));
+ }
+
+ if (!isNullOrEmpty(dstTcpString)) {
+ selectorBuilder.matchTcpSrc((short) Integer.parseInt(dstTcpString));
+ }
+
return selectorBuilder.build();
}
diff --git a/core/api/src/main/java/org/onlab/onos/net/AnnotationKeys.java b/core/api/src/main/java/org/onlab/onos/net/AnnotationKeys.java
new file mode 100644
index 0000000..5777022
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/AnnotationKeys.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2014 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onlab.onos.net;
+
+/**
+ * Collection of keys for annotation.
+ * Definitions of annotation keys needs to be here to avoid scattering.
+ */
+public final class AnnotationKeys {
+
+ // Prohibit instantiation
+ private AnnotationKeys() {}
+
+ /**
+ * Annotation key for latency.
+ */
+ public static final String LATENCY = "latency";
+
+ /**
+ * Returns the value annotated object for the specified annotation key.
+ * The annotated value is expected to be String that can be parsed as double.
+ * If parsing fails, the returned value will be 1.0.
+ *
+ * @param annotated annotated object whose annotated value is obtained
+ * @param key key of annotation
+ * @return double value of annotated object for the specified key
+ */
+ public static double getAnnotatedValue(Annotated annotated, String key) {
+ double value;
+ try {
+ value = Double.parseDouble(annotated.annotations().value(key));
+ } catch (NumberFormatException e) {
+ value = 1.0;
+ }
+ return value;
+ }
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/DefaultFlowEntry.java b/core/api/src/main/java/org/onlab/onos/net/flow/DefaultFlowEntry.java
index c2d901b..c6cb361 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/DefaultFlowEntry.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/DefaultFlowEntry.java
@@ -80,6 +80,7 @@
this.state = FlowEntryState.FAILED;
this.errType = errType;
this.errCode = errCode;
+ this.lastSeen = System.currentTimeMillis();
}
@Override
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/DefaultFlowRule.java b/core/api/src/main/java/org/onlab/onos/net/flow/DefaultFlowRule.java
index 6e59cf5..f31f3c3 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/DefaultFlowRule.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/DefaultFlowRule.java
@@ -58,7 +58,7 @@
}
public DefaultFlowRule(DeviceId deviceId, TrafficSelector selector,
- TrafficTreatment treatement, int priority, ApplicationId appId,
+ TrafficTreatment treatment, int priority, ApplicationId appId,
int timeout, boolean permanent) {
if (priority < FlowRule.MIN_PRIORITY) {
@@ -68,7 +68,7 @@
this.deviceId = deviceId;
this.priority = priority;
this.selector = selector;
- this.treatment = treatement;
+ this.treatment = treatment;
this.appId = appId.id();
this.timeout = timeout;
this.permanent = permanent;
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/DefaultTrafficSelector.java b/core/api/src/main/java/org/onlab/onos/net/flow/DefaultTrafficSelector.java
index 413473f..673773a 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/DefaultTrafficSelector.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/DefaultTrafficSelector.java
@@ -63,7 +63,7 @@
@Override
public int hashCode() {
- return Objects.hash(criteria);
+ return criteria.hashCode();
}
@Override
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleProvider.java b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleProvider.java
index de2c7fd..64a56ca 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleProvider.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleProvider.java
@@ -18,7 +18,7 @@
import org.onlab.onos.core.ApplicationId;
import org.onlab.onos.net.provider.Provider;
-import com.google.common.util.concurrent.ListenableFuture;
+import java.util.concurrent.Future;
/**
* Abstraction of a flow rule provider.
@@ -58,6 +58,6 @@
* @param batch a batch of flow rules
* @return a future indicating the status of this execution
*/
- ListenableFuture<CompletedBatchOperation> executeBatch(BatchOperation<FlowRuleBatchEntry> batch);
+ Future<CompletedBatchOperation> executeBatch(BatchOperation<FlowRuleBatchEntry> batch);
}
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/criteria/Criteria.java b/core/api/src/main/java/org/onlab/onos/net/flow/criteria/Criteria.java
index bac1bab..61fe54d 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/criteria/Criteria.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/criteria/Criteria.java
@@ -196,7 +196,7 @@
@Override
public int hashCode() {
- return Objects.hash(port, type());
+ return Objects.hash(type(), port);
}
@Override
@@ -242,7 +242,7 @@
@Override
public int hashCode() {
- return Objects.hash(mac, type);
+ return Objects.hash(type, mac);
}
@Override
@@ -288,7 +288,7 @@
@Override
public int hashCode() {
- return Objects.hash(ethType, type());
+ return Objects.hash(type(), ethType);
}
@Override
@@ -336,7 +336,7 @@
@Override
public int hashCode() {
- return Objects.hash(ip, type);
+ return Objects.hash(type, ip);
}
@Override
@@ -382,7 +382,7 @@
@Override
public int hashCode() {
- return Objects.hash(proto, type());
+ return Objects.hash(type(), proto);
}
@Override
@@ -427,7 +427,7 @@
@Override
public int hashCode() {
- return Objects.hash(vlanPcp);
+ return Objects.hash(type(), vlanPcp);
}
@Override
@@ -474,7 +474,7 @@
@Override
public int hashCode() {
- return Objects.hash(vlanId, type());
+ return Objects.hash(type(), vlanId);
}
@Override
@@ -522,7 +522,7 @@
@Override
public int hashCode() {
- return Objects.hash(tcpPort, type);
+ return Objects.hash(type, tcpPort);
}
@Override
@@ -568,7 +568,7 @@
@Override
public int hashCode() {
- return Objects.hash(lambda, type);
+ return Objects.hash(type, lambda);
}
@Override
@@ -612,7 +612,7 @@
@Override
public int hashCode() {
- return Objects.hash(signalType, type);
+ return Objects.hash(type, signalType);
}
@Override
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/instructions/Instructions.java b/core/api/src/main/java/org/onlab/onos/net/flow/instructions/Instructions.java
index 0e77f4a..7dc0f8d 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/instructions/Instructions.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/instructions/Instructions.java
@@ -190,7 +190,7 @@
@Override
public int hashCode() {
- return Objects.hash(port, type());
+ return Objects.hash(type(), port);
}
@Override
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/instructions/L0ModificationInstruction.java b/core/api/src/main/java/org/onlab/onos/net/flow/instructions/L0ModificationInstruction.java
index 0d5cd81..25fe79f 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/instructions/L0ModificationInstruction.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/instructions/L0ModificationInstruction.java
@@ -70,7 +70,7 @@
@Override
public int hashCode() {
- return Objects.hash(lambda, type(), subtype);
+ return Objects.hash(type(), subtype, lambda);
}
@Override
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/instructions/L2ModificationInstruction.java b/core/api/src/main/java/org/onlab/onos/net/flow/instructions/L2ModificationInstruction.java
index abe19e3..20eaf6e 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/instructions/L2ModificationInstruction.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/instructions/L2ModificationInstruction.java
@@ -93,7 +93,7 @@
@Override
public int hashCode() {
- return Objects.hash(mac, type(), subtype);
+ return Objects.hash(type(), subtype, mac);
}
@Override
@@ -142,7 +142,7 @@
@Override
public int hashCode() {
- return Objects.hash(vlanId, type(), subtype());
+ return Objects.hash(type(), subtype(), vlanId);
}
@Override
@@ -191,7 +191,7 @@
@Override
public int hashCode() {
- return Objects.hash(vlanPcp, type(), subtype());
+ return Objects.hash(type(), subtype(), vlanPcp);
}
@Override
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/instructions/L3ModificationInstruction.java b/core/api/src/main/java/org/onlab/onos/net/flow/instructions/L3ModificationInstruction.java
index 89a8cda..e8b72e7 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/instructions/L3ModificationInstruction.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/instructions/L3ModificationInstruction.java
@@ -85,7 +85,7 @@
@Override
public int hashCode() {
- return Objects.hash(ip, type(), subtype());
+ return Objects.hash(type(), subtype(), ip);
}
@Override
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/constraint/AnnotationConstraint.java b/core/api/src/main/java/org/onlab/onos/net/intent/constraint/AnnotationConstraint.java
index ac76303..1767a41 100644
--- a/core/api/src/main/java/org/onlab/onos/net/intent/constraint/AnnotationConstraint.java
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/constraint/AnnotationConstraint.java
@@ -21,6 +21,8 @@
import java.util.Objects;
+import static org.onlab.onos.net.AnnotationKeys.getAnnotatedValue;
+
/**
* Constraint that evaluates an arbitrary link annotated value is under the specified threshold.
*/
@@ -41,6 +43,12 @@
this.threshold = threshold;
}
+ // Constructor for serialization
+ private AnnotationConstraint() {
+ this.key = "";
+ this.threshold = 0;
+ }
+
/**
* Returns the key of link annotation this constraint designates.
* @return key of link annotation
@@ -65,25 +73,6 @@
return value <= threshold;
}
- /**
- * Returns the annotated value of the specified link. The annotated value
- * is expected to be String that can be parsed as double. If parsing fails,
- * the returned value will be 1.0.
- *
- * @param link link whose annotated value is obtained
- * @param key key of link annotation
- * @return double value of link annotation for the specified key
- */
- private double getAnnotatedValue(Link link, String key) {
- double value;
- try {
- value = Double.parseDouble(link.annotations().value(key));
- } catch (NumberFormatException e) {
- value = 1.0;
- }
- return value;
- }
-
@Override
public double cost(Link link, LinkResourceService resourceService) {
if (isValid(link, resourceService)) {
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/constraint/LatencyConstraint.java b/core/api/src/main/java/org/onlab/onos/net/intent/constraint/LatencyConstraint.java
index fcdf330..e4b4432 100644
--- a/core/api/src/main/java/org/onlab/onos/net/intent/constraint/LatencyConstraint.java
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/constraint/LatencyConstraint.java
@@ -25,14 +25,14 @@
import java.time.temporal.ChronoUnit;
import java.util.Objects;
+import static org.onlab.onos.net.AnnotationKeys.LATENCY;
+import static org.onlab.onos.net.AnnotationKeys.getAnnotatedValue;
+
/**
* Constraint that evaluates the latency through a path.
*/
public class LatencyConstraint implements Constraint {
- // TODO: formalize the key for latency all over the codes.
- private static final String LATENCY_KEY = "latency";
-
private final Duration latency;
/**
@@ -43,22 +43,18 @@
this.latency = latency;
}
+ // Constructor for serialization
+ private LatencyConstraint() {
+ this.latency = Duration.ZERO;
+ }
+
public Duration latency() {
return latency;
}
@Override
public double cost(Link link, LinkResourceService resourceService) {
- String value = link.annotations().value(LATENCY_KEY);
-
- double latencyInMicroSec;
- try {
- latencyInMicroSec = Double.parseDouble(value);
- } catch (NumberFormatException e) {
- latencyInMicroSec = 1.0;
- }
-
- return latencyInMicroSec;
+ return getAnnotatedValue(link, LATENCY);
}
@Override
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/constraint/ObstacleConstraint.java b/core/api/src/main/java/org/onlab/onos/net/intent/constraint/ObstacleConstraint.java
index 6d73fc2..8472f3c 100644
--- a/core/api/src/main/java/org/onlab/onos/net/intent/constraint/ObstacleConstraint.java
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/constraint/ObstacleConstraint.java
@@ -21,6 +21,7 @@
import org.onlab.onos.net.Link;
import org.onlab.onos.net.resource.LinkResourceService;
+import java.util.Collections;
import java.util.Objects;
import java.util.Set;
@@ -39,6 +40,11 @@
this.obstacles = ImmutableSet.copyOf(obstacles);
}
+ // Constructor for serialization
+ private ObstacleConstraint() {
+ this.obstacles = Collections.emptySet();
+ }
+
@Override
public boolean isValid(Link link, LinkResourceService resourceService) {
DeviceId src = link.src().deviceId();
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/constraint/WaypointConstraint.java b/core/api/src/main/java/org/onlab/onos/net/intent/constraint/WaypointConstraint.java
index 2a1e3e3..9e3cc20 100644
--- a/core/api/src/main/java/org/onlab/onos/net/intent/constraint/WaypointConstraint.java
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/constraint/WaypointConstraint.java
@@ -17,12 +17,13 @@
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableList;
-import org.onlab.onos.net.ElementId;
+import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.Path;
import org.onlab.onos.net.intent.Constraint;
import org.onlab.onos.net.resource.LinkResourceService;
+import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
@@ -35,20 +36,25 @@
*/
public class WaypointConstraint implements Constraint {
- private final List<ElementId> waypoints;
+ private final List<DeviceId> waypoints;
/**
* Creates a new waypoint constraint.
*
* @param waypoints waypoints
*/
- public WaypointConstraint(ElementId... waypoints) {
+ public WaypointConstraint(DeviceId... waypoints) {
checkNotNull(waypoints, "waypoints cannot be null");
checkArgument(waypoints.length > 0, "length of waypoints should be more than 0");
this.waypoints = ImmutableList.copyOf(waypoints);
}
- public List<ElementId> waypoints() {
+ // Constructor for serialization
+ private WaypointConstraint() {
+ this.waypoints = Collections.emptyList();
+ }
+
+ public List<DeviceId> waypoints() {
return waypoints;
}
@@ -60,8 +66,8 @@
@Override
public boolean validate(Path path, LinkResourceService resourceService) {
- LinkedList<ElementId> waypoints = new LinkedList<>(this.waypoints);
- ElementId current = waypoints.poll();
+ LinkedList<DeviceId> waypoints = new LinkedList<>(this.waypoints);
+ DeviceId current = waypoints.poll();
// This is safe because Path class ensures the number of links are more than 0
Link firstLink = path.links().get(0);
if (firstLink.src().elementId().equals(current)) {
diff --git a/core/api/src/test/java/org/onlab/onos/net/intent/constraint/LatencyConstraintTest.java b/core/api/src/test/java/org/onlab/onos/net/intent/constraint/LatencyConstraintTest.java
index b9fa3ee..d1a280c 100644
--- a/core/api/src/test/java/org/onlab/onos/net/intent/constraint/LatencyConstraintTest.java
+++ b/core/api/src/test/java/org/onlab/onos/net/intent/constraint/LatencyConstraintTest.java
@@ -37,6 +37,7 @@
import static org.hamcrest.Matchers.closeTo;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
+import static org.onlab.onos.net.AnnotationKeys.LATENCY;
import static org.onlab.onos.net.DefaultLinkTest.cp;
import static org.onlab.onos.net.DeviceId.deviceId;
import static org.onlab.onos.net.Link.Type.DIRECT;
@@ -51,7 +52,6 @@
private static final PortNumber PN3 = PortNumber.portNumber(3);
private static final PortNumber PN4 = PortNumber.portNumber(4);
private static final ProviderId PROVIDER_ID = new ProviderId("of", "foo");
- private static final String LATENCY_KEY = "latency";
private static final String LATENCY1 = "3.0";
private static final String LATENCY2 = "4.0";
@@ -66,8 +66,8 @@
public void setUp() {
linkResourceService = createMock(LinkResourceService.class);
- Annotations annotations1 = DefaultAnnotations.builder().set(LATENCY_KEY, LATENCY1).build();
- Annotations annotations2 = DefaultAnnotations.builder().set(LATENCY_KEY, LATENCY2).build();
+ Annotations annotations1 = DefaultAnnotations.builder().set(LATENCY, LATENCY1).build();
+ Annotations annotations2 = DefaultAnnotations.builder().set(LATENCY, LATENCY2).build();
link1 = new DefaultLink(PROVIDER_ID, cp(DID1, PN1), cp(DID2, PN2), DIRECT, annotations1);
link2 = new DefaultLink(PROVIDER_ID, cp(DID2, PN3), cp(DID3, PN4), DIRECT, annotations2);
diff --git a/core/net/src/main/java/org/onlab/onos/net/flow/impl/FlowRuleManager.java b/core/net/src/main/java/org/onlab/onos/net/flow/impl/FlowRuleManager.java
index e996dfc..7e5f049 100644
--- a/core/net/src/main/java/org/onlab/onos/net/flow/impl/FlowRuleManager.java
+++ b/core/net/src/main/java/org/onlab/onos/net/flow/impl/FlowRuleManager.java
@@ -15,22 +15,12 @@
*/
package org.onlab.onos.net.flow.impl;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static org.slf4j.LoggerFactory.getLogger;
-import static org.onlab.util.Tools.namedThreads;
-
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.CancellationException;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicReference;
-
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Sets;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
@@ -64,14 +54,21 @@
import org.onlab.onos.net.provider.AbstractProviderService;
import org.slf4j.Logger;
-import com.google.common.collect.ArrayListMultimap;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Multimap;
-import com.google.common.collect.Sets;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicReference;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onlab.util.Tools.namedThreads;
+import static org.slf4j.LoggerFactory.getLogger;
/**
* Provides implementation of the flow NB & SB APIs.
@@ -92,8 +89,7 @@
private final FlowRuleStoreDelegate delegate = new InternalStoreDelegate();
- private final ExecutorService futureListeners =
- Executors.newCachedThreadPool(namedThreads("provider-future-listeners"));
+ private ExecutorService futureService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected FlowRuleStore store;
@@ -106,6 +102,7 @@
@Activate
public void activate() {
+ futureService = Executors.newCachedThreadPool(namedThreads("provider-future-listeners"));
store.setDelegate(delegate);
eventDispatcher.addSink(FlowRuleEvent.class, listenerRegistry);
log.info("Started");
@@ -113,7 +110,7 @@
@Deactivate
public void deactivate() {
- futureListeners.shutdownNow();
+ futureService.shutdownNow();
store.unsetDelegate(delegate);
eventDispatcher.removeSink(FlowRuleEvent.class);
@@ -364,6 +361,9 @@
// Store delegate to re-post events emitted from the store.
private class InternalStoreDelegate implements FlowRuleStoreDelegate {
+
+ private static final int TIMEOUT = 5000; // ms
+
// TODO: Right now we only dispatch events at individual flowEntry level.
// It may be more efficient for also dispatch events as a batch.
@Override
@@ -384,15 +384,21 @@
FlowRuleProvider flowRuleProvider =
getProvider(batchOperation.getOperations().get(0).getTarget().deviceId());
- final ListenableFuture<CompletedBatchOperation> result =
+ final Future<CompletedBatchOperation> result =
flowRuleProvider.executeBatch(batchOperation);
- result.addListener(new Runnable() {
+ futureService.submit(new Runnable() {
@Override
public void run() {
- store.batchOperationComplete(FlowRuleBatchEvent.completed(request,
- Futures.getUnchecked(result)));
+ CompletedBatchOperation res = null;
+ try {
+ res = result.get(TIMEOUT, TimeUnit.MILLISECONDS);
+ } catch (TimeoutException | InterruptedException | ExecutionException e) {
+ log.warn("Something went wrong with the batch operation {}",
+ request.batchId());
+ }
+ store.batchOperationComplete(FlowRuleBatchEvent.completed(request, res));
}
- }, futureListeners);
+ });
break;
case BATCH_OPERATION_COMPLETED:
diff --git a/core/net/src/test/java/org/onlab/onos/net/flow/DefaultFlowEntryTest.java b/core/net/src/test/java/org/onlab/onos/net/flow/DefaultFlowEntryTest.java
new file mode 100644
index 0000000..b8d7799
--- /dev/null
+++ b/core/net/src/test/java/org/onlab/onos/net/flow/DefaultFlowEntryTest.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2014 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onlab.onos.net.flow;
+
+import java.util.concurrent.TimeUnit;
+
+import org.junit.Test;
+import org.onlab.onos.net.intent.IntentTestsMocks;
+
+import com.google.common.testing.EqualsTester;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.greaterThan;
+import static org.hamcrest.Matchers.is;
+import static org.onlab.onos.net.NetTestTools.did;
+
+/**
+ * Unit tests for the DefaultFlowEntry class.
+ */
+public class DefaultFlowEntryTest {
+ private static final IntentTestsMocks.MockSelector SELECTOR =
+ new IntentTestsMocks.MockSelector();
+ private static final IntentTestsMocks.MockTreatment TREATMENT =
+ new IntentTestsMocks.MockTreatment();
+
+ private static DefaultFlowEntry makeFlowEntry(int uniqueValue) {
+ return new DefaultFlowEntry(did("id" + Integer.toString(uniqueValue)),
+ SELECTOR,
+ TREATMENT,
+ uniqueValue,
+ FlowEntry.FlowEntryState.ADDED,
+ uniqueValue,
+ uniqueValue,
+ uniqueValue,
+ uniqueValue,
+ uniqueValue);
+ }
+
+ final DefaultFlowEntry defaultFlowEntry1 = makeFlowEntry(1);
+ final DefaultFlowEntry sameAsDefaultFlowEntry1 = makeFlowEntry(1);
+ final DefaultFlowEntry defaultFlowEntry2 = makeFlowEntry(2);
+
+ /**
+ * Tests the equals, hashCode and toString methods using Guava EqualsTester.
+ */
+ @Test
+ public void testEquals() {
+ new EqualsTester()
+ .addEqualityGroup(defaultFlowEntry1, sameAsDefaultFlowEntry1)
+ .addEqualityGroup(defaultFlowEntry2)
+ .testEquals();
+ }
+
+ /**
+ * Tests the construction of a default flow entry from a device id.
+ */
+ @Test
+ public void testDeviceBasedObject() {
+ assertThat(defaultFlowEntry1.deviceId(), is(did("id1")));
+ assertThat(defaultFlowEntry1.selector(), is(SELECTOR));
+ assertThat(defaultFlowEntry1.treatment(), is(TREATMENT));
+ assertThat(defaultFlowEntry1.timeout(), is(1));
+ assertThat(defaultFlowEntry1.life(), is(1L));
+ assertThat(defaultFlowEntry1.packets(), is(1L));
+ assertThat(defaultFlowEntry1.bytes(), is(1L));
+ assertThat(defaultFlowEntry1.state(), is(FlowEntry.FlowEntryState.ADDED));
+ assertThat(defaultFlowEntry1.lastSeen(),
+ greaterThan(System.currentTimeMillis() -
+ TimeUnit.MILLISECONDS.convert(1, TimeUnit.SECONDS)));
+ }
+
+ /**
+ * Tests the setters on a default flow entry object.
+ */
+ @Test
+ public void testSetters() {
+ final DefaultFlowEntry entry = makeFlowEntry(1);
+
+ entry.setLastSeen();
+ entry.setState(FlowEntry.FlowEntryState.PENDING_REMOVE);
+ entry.setPackets(11);
+ entry.setBytes(22);
+ entry.setLife(33);
+
+ assertThat(entry.deviceId(), is(did("id1")));
+ assertThat(entry.selector(), is(SELECTOR));
+ assertThat(entry.treatment(), is(TREATMENT));
+ assertThat(entry.timeout(), is(1));
+ assertThat(entry.life(), is(33L));
+ assertThat(entry.packets(), is(11L));
+ assertThat(entry.bytes(), is(22L));
+ assertThat(entry.state(), is(FlowEntry.FlowEntryState.PENDING_REMOVE));
+ assertThat(entry.lastSeen(),
+ greaterThan(System.currentTimeMillis() -
+ TimeUnit.MILLISECONDS.convert(1, TimeUnit.SECONDS)));
+ }
+
+ /**
+ * Tests a default flow rule built for an error.
+ */
+ @Test
+ public void testErrorObject() {
+ final DefaultFlowEntry errorEntry =
+ new DefaultFlowEntry(new IntentTestsMocks.MockFlowRule(1),
+ 111,
+ 222);
+ assertThat(errorEntry.errType(), is(111));
+ assertThat(errorEntry.errCode(), is(222));
+ assertThat(errorEntry.state(), is(FlowEntry.FlowEntryState.FAILED));
+ assertThat(errorEntry.lastSeen(),
+ greaterThan(System.currentTimeMillis() -
+ TimeUnit.MILLISECONDS.convert(1, TimeUnit.SECONDS)));
+ }
+
+ /**
+ * Tests a default flow entry constructed from a flow rule.
+ */
+ @Test
+ public void testFlowBasedObject() {
+ final DefaultFlowEntry entry =
+ new DefaultFlowEntry(new IntentTestsMocks.MockFlowRule(1));
+ assertThat(entry.priority(), is(1));
+ assertThat(entry.appId(), is((short) 0));
+ assertThat(entry.lastSeen(),
+ greaterThan(System.currentTimeMillis() -
+ TimeUnit.MILLISECONDS.convert(1, TimeUnit.SECONDS)));
+ }
+
+ /**
+ * Tests a default flow entry constructed from a flow rule plus extra
+ * parameters.
+ */
+ @Test
+ public void testFlowBasedObjectWithParameters() {
+ final DefaultFlowEntry entry =
+ new DefaultFlowEntry(new IntentTestsMocks.MockFlowRule(33),
+ FlowEntry.FlowEntryState.REMOVED,
+ 101, 102, 103);
+ assertThat(entry.state(), is(FlowEntry.FlowEntryState.REMOVED));
+ assertThat(entry.life(), is(101L));
+ assertThat(entry.packets(), is(102L));
+ assertThat(entry.bytes(), is(103L));
+ assertThat(entry.lastSeen(),
+ greaterThan(System.currentTimeMillis() -
+ TimeUnit.MILLISECONDS.convert(1, TimeUnit.SECONDS)));
+ }
+}
diff --git a/core/net/src/test/java/org/onlab/onos/net/flow/DefaultFlowRuleTest.java b/core/net/src/test/java/org/onlab/onos/net/flow/DefaultFlowRuleTest.java
new file mode 100644
index 0000000..f2c418f
--- /dev/null
+++ b/core/net/src/test/java/org/onlab/onos/net/flow/DefaultFlowRuleTest.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2014 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onlab.onos.net.flow;
+
+import org.junit.Test;
+import org.onlab.onos.net.intent.IntentTestsMocks;
+
+import com.google.common.testing.EqualsTester;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutableBaseClass;
+import static org.onlab.onos.net.NetTestTools.APP_ID;
+import static org.onlab.onos.net.NetTestTools.did;
+
+/**
+ * Unit tests for the default flow rule class.
+ */
+public class DefaultFlowRuleTest {
+ private static final IntentTestsMocks.MockSelector SELECTOR =
+ new IntentTestsMocks.MockSelector();
+ private static final IntentTestsMocks.MockTreatment TREATMENT =
+ new IntentTestsMocks.MockTreatment();
+
+ final FlowRule flowRule1 = new IntentTestsMocks.MockFlowRule(1);
+ final FlowRule sameAsFlowRule1 = new IntentTestsMocks.MockFlowRule(1);
+ final FlowRule flowRule2 = new IntentTestsMocks.MockFlowRule(2);
+ final DefaultFlowRule defaultFlowRule1 = new DefaultFlowRule(flowRule1);
+ final DefaultFlowRule sameAsDefaultFlowRule1 = new DefaultFlowRule(sameAsFlowRule1);
+ final DefaultFlowRule defaultFlowRule2 = new DefaultFlowRule(flowRule2);
+
+ /**
+ * Checks that the DefaultFlowRule class is immutable but can be inherited
+ * from.
+ */
+ @Test
+ public void testImmutability() {
+ assertThatClassIsImmutableBaseClass(DefaultFlowRule.class);
+ }
+
+ /**
+ * Tests the equals, hashCode and toString methods using Guava EqualsTester.
+ */
+ @Test
+ public void testEquals() {
+ new EqualsTester()
+ .addEqualityGroup(defaultFlowRule1, sameAsDefaultFlowRule1)
+ .addEqualityGroup(defaultFlowRule2)
+ .testEquals();
+ }
+
+ /**
+ * Tests creation of a DefaultFlowRule using a FlowRule constructor.
+ */
+ @Test
+ public void testCreationFromFlowRule() {
+ assertThat(defaultFlowRule1.deviceId(), is(flowRule1.deviceId()));
+ assertThat(defaultFlowRule1.appId(), is(flowRule1.appId()));
+ assertThat(defaultFlowRule1.id(), is(flowRule1.id()));
+ assertThat(defaultFlowRule1.isPermanent(), is(flowRule1.isPermanent()));
+ assertThat(defaultFlowRule1.priority(), is(flowRule1.priority()));
+ assertThat(defaultFlowRule1.selector(), is(flowRule1.selector()));
+ assertThat(defaultFlowRule1.treatment(), is(flowRule1.treatment()));
+ assertThat(defaultFlowRule1.timeout(), is(flowRule1.timeout()));
+ }
+
+ /**
+ * Tests creation of a DefaultFlowRule using a FlowId constructor.
+ */
+ @Test
+ public void testCreationWithFlowId() {
+ final DefaultFlowRule rule =
+ new DefaultFlowRule(did("1"), SELECTOR,
+ TREATMENT, 22, 33,
+ 44, false);
+ assertThat(rule.deviceId(), is(did("1")));
+ assertThat(rule.id().value(), is(33L));
+ assertThat(rule.isPermanent(), is(false));
+ assertThat(rule.priority(), is(22));
+ assertThat(rule.selector(), is(SELECTOR));
+ assertThat(rule.treatment(), is(TREATMENT));
+ assertThat(rule.timeout(), is(44));
+ }
+
+ /**
+ * Tests the creation of a DefaultFlowRule using an AppId constructor.
+ */
+ @Test
+ public void testCreationWithAppId() {
+ final DefaultFlowRule rule =
+ new DefaultFlowRule(did("1"), SELECTOR,
+ TREATMENT, 22, APP_ID,
+ 44, false);
+ assertThat(rule.deviceId(), is(did("1")));
+ assertThat(rule.isPermanent(), is(false));
+ assertThat(rule.priority(), is(22));
+ assertThat(rule.selector(), is(SELECTOR));
+ assertThat(rule.treatment(), is(TREATMENT));
+ assertThat(rule.timeout(), is(44));
+ }
+}
diff --git a/core/net/src/test/java/org/onlab/onos/net/intent/IntentTestsMocks.java b/core/net/src/test/java/org/onlab/onos/net/intent/IntentTestsMocks.java
index e0fe09e..65df6b2 100644
--- a/core/net/src/test/java/org/onlab/onos/net/intent/IntentTestsMocks.java
+++ b/core/net/src/test/java/org/onlab/onos/net/intent/IntentTestsMocks.java
@@ -16,6 +16,7 @@
package org.onlab.onos.net.intent;
import static org.onlab.onos.net.NetTestTools.createPath;
+import static org.onlab.onos.net.NetTestTools.did;
import static org.onlab.onos.net.NetTestTools.link;
import java.util.ArrayList;
@@ -31,6 +32,8 @@
import org.onlab.onos.net.ElementId;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.Path;
+import org.onlab.onos.net.flow.FlowId;
+import org.onlab.onos.net.flow.FlowRule;
import org.onlab.onos.net.flow.TrafficSelector;
import org.onlab.onos.net.flow.TrafficTreatment;
import org.onlab.onos.net.flow.criteria.Criterion;
@@ -271,4 +274,60 @@
}
}
+ private static final IntentTestsMocks.MockSelector SELECTOR =
+ new IntentTestsMocks.MockSelector();
+ private static final IntentTestsMocks.MockTreatment TREATMENT =
+ new IntentTestsMocks.MockTreatment();
+
+ public static class MockFlowRule implements FlowRule {
+
+ int priority;
+ public MockFlowRule(int priority) {
+ this.priority = priority;
+ }
+
+ @Override
+ public FlowId id() {
+ return FlowId.valueOf(1);
+ }
+
+ @Override
+ public short appId() {
+ return 0;
+ }
+
+ @Override
+ public int priority() {
+ return priority;
+ }
+
+ @Override
+ public DeviceId deviceId() {
+ return did("1");
+ }
+
+ @Override
+ public TrafficSelector selector() {
+ return SELECTOR;
+ }
+
+ @Override
+ public TrafficTreatment treatment() {
+ return TREATMENT;
+ }
+
+ @Override
+ public int timeout() {
+ return 0;
+ }
+
+ @Override
+ public boolean isPermanent() {
+ return false;
+ }
+
+
+ }
+
+
}
diff --git a/core/store/dist/src/main/java/org/onlab/onos/store/service/impl/DatabaseManager.java b/core/store/dist/src/main/java/org/onlab/onos/store/service/impl/DatabaseManager.java
index 0d06e08..afeaef9 100644
--- a/core/store/dist/src/main/java/org/onlab/onos/store/service/impl/DatabaseManager.java
+++ b/core/store/dist/src/main/java/org/onlab/onos/store/service/impl/DatabaseManager.java
@@ -72,7 +72,7 @@
public static final String LOG_FILE_PREFIX = "/tmp/onos-copy-cat-log_";
// Current working dir seems to be /opt/onos/apache-karaf-3.0.2
- // TODO: Get the path to /opt/onos/config
+ // TODO: Set the path to /opt/onos/config
private static final String CONFIG_DIR = "../config";
private static final String DEFAULT_MEMBER_FILE = "tablets.json";
diff --git a/core/store/serializers/src/main/java/org/onlab/onos/store/serializers/KryoNamespaces.java b/core/store/serializers/src/main/java/org/onlab/onos/store/serializers/KryoNamespaces.java
index 4cba9f0..5d689a3 100644
--- a/core/store/serializers/src/main/java/org/onlab/onos/store/serializers/KryoNamespaces.java
+++ b/core/store/serializers/src/main/java/org/onlab/onos/store/serializers/KryoNamespaces.java
@@ -75,10 +75,14 @@
import org.onlab.onos.net.intent.OpticalPathIntent;
import org.onlab.onos.net.intent.PathIntent;
import org.onlab.onos.net.intent.PointToPointIntent;
+import org.onlab.onos.net.intent.constraint.AnnotationConstraint;
import org.onlab.onos.net.intent.constraint.BandwidthConstraint;
import org.onlab.onos.net.intent.constraint.BooleanConstraint;
import org.onlab.onos.net.intent.constraint.LambdaConstraint;
+import org.onlab.onos.net.intent.constraint.LatencyConstraint;
import org.onlab.onos.net.intent.constraint.LinkTypeConstraint;
+import org.onlab.onos.net.intent.constraint.ObstacleConstraint;
+import org.onlab.onos.net.intent.constraint.WaypointConstraint;
import org.onlab.onos.net.link.DefaultLinkDescription;
import org.onlab.onos.net.packet.DefaultOutboundPacket;
import org.onlab.onos.net.provider.ProviderId;
@@ -208,9 +212,14 @@
LinkResourceRequest.class,
Lambda.class,
Bandwidth.class,
+ // Constraints
LambdaConstraint.class,
BandwidthConstraint.class,
LinkTypeConstraint.class,
+ LatencyConstraint.class,
+ WaypointConstraint.class,
+ ObstacleConstraint.class,
+ AnnotationConstraint.class,
BooleanConstraint.class
)
.register(DefaultApplicationId.class, new DefaultApplicationIdSerializer())
diff --git a/features/features.xml b/features/features.xml
index 3eb0d90..5ede89c 100644
--- a/features/features.xml
+++ b/features/features.xml
@@ -197,6 +197,8 @@
<feature name="onos-app-sdnip" version="1.0.0"
description="SDN-IP peering application">
<feature>onos-api</feature>
+ <feature>onos-app-proxyarp</feature>
+ <feature>onos-app-config</feature>
<bundle>mvn:org.onlab.onos/onos-app-sdnip/1.0.0-SNAPSHOT</bundle>
</feature>
diff --git a/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/OpenFlowRuleProvider.java b/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/OpenFlowRuleProvider.java
index 018d6f3..214bde3 100644
--- a/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/OpenFlowRuleProvider.java
+++ b/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/OpenFlowRuleProvider.java
@@ -15,21 +15,11 @@
*/
package org.onlab.onos.provider.of.flow.impl;
-import static org.slf4j.LoggerFactory.getLogger;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Executor;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicBoolean;
-
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Sets;
+import com.google.common.util.concurrent.ExecutionList;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
@@ -80,15 +70,23 @@
import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
import org.projectfloodlight.openflow.protocol.instruction.OFInstructionApplyActions;
import org.projectfloodlight.openflow.types.OFPort;
-import org.projectfloodlight.openflow.types.U32;
import org.slf4j.Logger;
-import com.google.common.collect.ArrayListMultimap;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Multimap;
-import com.google.common.collect.Sets;
-import com.google.common.util.concurrent.ExecutionList;
-import com.google.common.util.concurrent.ListenableFuture;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+
+import static org.slf4j.LoggerFactory.getLogger;
/**
* Provider which uses an OpenFlow controller to detect network
@@ -124,6 +122,8 @@
private final Map<Dpid, FlowStatsCollector> collectors = Maps.newHashMap();
+ private final AtomicLong xidCounter = new AtomicLong(0);
+
/**
* Creates an OpenFlow host provider.
*/
@@ -154,6 +154,7 @@
log.info("Stopped");
}
+
@Override
public void applyFlowRule(FlowRule... flowRules) {
for (int i = 0; i < flowRules.length; i++) {
@@ -167,7 +168,6 @@
}
-
@Override
public void removeFlowRule(FlowRule... flowRules) {
for (int i = 0; i < flowRules.length; i++) {
@@ -188,11 +188,15 @@
}
@Override
- public ListenableFuture<CompletedBatchOperation> executeBatch(BatchOperation<FlowRuleBatchEntry> batch) {
+ public Future<CompletedBatchOperation> executeBatch(BatchOperation<FlowRuleBatchEntry> batch) {
final Set<Dpid> sws =
Collections.newSetFromMap(new ConcurrentHashMap<Dpid, Boolean>());
final Map<Long, FlowRuleBatchEntry> fmXids = new HashMap<Long, FlowRuleBatchEntry>();
- OFFlowMod mod = null;
+ /*
+ * Use identity hash map for reference equality as we could have equal
+ * flow mods for different switches.
+ */
+ Map<OFFlowMod, OpenFlowSwitch> mods = Maps.newIdentityHashMap();
for (FlowRuleBatchEntry fbe : batch.getOperations()) {
FlowRule flowRule = fbe.getTarget();
OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri()));
@@ -208,6 +212,7 @@
}
sws.add(new Dpid(sw.getId()));
FlowModBuilder builder = FlowModBuilder.builder(flowRule, sw.factory());
+ OFFlowMod mod = null;
switch (fbe.getOperator()) {
case ADD:
mod = builder.buildFlowAdd();
@@ -222,25 +227,29 @@
log.error("Unsupported batch operation {}", fbe.getOperator());
}
if (mod != null) {
- sw.sendMsg(mod);
- fmXids.put(mod.getXid(), fbe);
+ mods.put(mod, sw);
+ fmXids.put(xidCounter.getAndIncrement(), fbe);
} else {
log.error("Conversion of flowrule {} failed.", flowRule);
}
-
}
InstallationFuture installation = new InstallationFuture(sws, fmXids);
for (Long xid : fmXids.keySet()) {
pendingFMs.put(xid, installation);
}
- pendingFutures.put(U32.f(batch.hashCode()), installation);
- installation.verify(U32.f(batch.hashCode()));
+ pendingFutures.put(installation.xid(), installation);
+ for (Map.Entry<OFFlowMod, OpenFlowSwitch> entry : mods.entrySet()) {
+ OpenFlowSwitch sw = entry.getValue();
+ OFFlowMod mod = entry.getKey();
+ sw.sendMsg(mod);
+ }
+ installation.verify();
return installation;
}
private class InternalFlowProvider
- implements OpenFlowSwitchListener, OpenFlowEventListener {
+ implements OpenFlowSwitchListener, OpenFlowEventListener {
private final Multimap<DeviceId, FlowEntry> completeEntries =
@@ -274,36 +283,36 @@
public void handleMessage(Dpid dpid, OFMessage msg) {
InstallationFuture future = null;
switch (msg.getType()) {
- case FLOW_REMOVED:
- OFFlowRemoved removed = (OFFlowRemoved) msg;
+ case FLOW_REMOVED:
+ OFFlowRemoved removed = (OFFlowRemoved) msg;
- FlowEntry fr = new FlowEntryBuilder(dpid, removed).build();
- providerService.flowRemoved(fr);
- break;
- case STATS_REPLY:
- pushFlowMetrics(dpid, (OFStatsReply) msg);
- break;
- case BARRIER_REPLY:
- future = pendingFutures.get(msg.getXid());
- if (future != null) {
- future.satisfyRequirement(dpid);
- }
- break;
- case ERROR:
- future = pendingFMs.get(msg.getXid());
- if (future != null) {
- future.fail((OFErrorMsg) msg, dpid);
- }
- break;
- default:
- log.debug("Unhandled message type: {}", msg.getType());
+ FlowEntry fr = new FlowEntryBuilder(dpid, removed).build();
+ providerService.flowRemoved(fr);
+ break;
+ case STATS_REPLY:
+ pushFlowMetrics(dpid, (OFStatsReply) msg);
+ break;
+ case BARRIER_REPLY:
+ future = pendingFutures.get(msg.getXid());
+ if (future != null) {
+ future.satisfyRequirement(dpid);
+ }
+ break;
+ case ERROR:
+ future = pendingFMs.get(msg.getXid());
+ if (future != null) {
+ future.fail((OFErrorMsg) msg, dpid);
+ }
+ break;
+ default:
+ log.debug("Unhandled message type: {}", msg.getType());
}
}
@Override
public void receivedRoleReply(Dpid dpid, RoleState requested,
- RoleState response) {
+ RoleState response) {
// Do nothing here for now.
}
@@ -352,8 +361,9 @@
}
- private class InstallationFuture implements ListenableFuture<CompletedBatchOperation> {
+ private class InstallationFuture implements Future<CompletedBatchOperation> {
+ private final Long xid;
private final Set<Dpid> sws;
private final AtomicBoolean ok = new AtomicBoolean(true);
private final Map<Long, FlowRuleBatchEntry> fms;
@@ -361,18 +371,22 @@
private final Set<FlowEntry> offendingFlowMods = Sets.newHashSet();
private final CountDownLatch countDownLatch;
- private Long pendingXid;
private BatchState state;
private final ExecutionList executionList = new ExecutionList();
public InstallationFuture(Set<Dpid> sws, Map<Long, FlowRuleBatchEntry> fmXids) {
+ this.xid = xidCounter.getAndIncrement();
this.state = BatchState.STARTED;
this.sws = sws;
this.fms = fmXids;
countDownLatch = new CountDownLatch(sws.size());
}
+ public Long xid() {
+ return xid;
+ }
+
public void fail(OFErrorMsg msg, Dpid dpid) {
ok.set(false);
@@ -385,27 +399,27 @@
case BAD_ACTION:
OFBadActionErrorMsg bad = (OFBadActionErrorMsg) msg;
fe = new DefaultFlowEntry(offending, bad.getErrType().ordinal(),
- bad.getCode().ordinal());
+ bad.getCode().ordinal());
break;
case BAD_INSTRUCTION:
OFBadInstructionErrorMsg badins = (OFBadInstructionErrorMsg) msg;
fe = new DefaultFlowEntry(offending, badins.getErrType().ordinal(),
- badins.getCode().ordinal());
+ badins.getCode().ordinal());
break;
case BAD_MATCH:
OFBadMatchErrorMsg badMatch = (OFBadMatchErrorMsg) msg;
fe = new DefaultFlowEntry(offending, badMatch.getErrType().ordinal(),
- badMatch.getCode().ordinal());
+ badMatch.getCode().ordinal());
break;
case BAD_REQUEST:
OFBadRequestErrorMsg badReq = (OFBadRequestErrorMsg) msg;
fe = new DefaultFlowEntry(offending, badReq.getErrType().ordinal(),
- badReq.getCode().ordinal());
+ badReq.getCode().ordinal());
break;
case FLOW_MOD_FAILED:
OFFlowModFailedErrorMsg fmFail = (OFFlowModFailedErrorMsg) msg;
fe = new DefaultFlowEntry(offending, fmFail.getErrType().ordinal(),
- fmFail.getCode().ordinal());
+ fmFail.getCode().ordinal());
break;
case EXPERIMENTER:
case GROUP_MOD_FAILED:
@@ -434,13 +448,12 @@
}
- public void verify(Long id) {
- pendingXid = id;
+ public void verify() {
for (Dpid dpid : sws) {
OpenFlowSwitch sw = controller.getSwitch(dpid);
OFBarrierRequest.Builder builder = sw.factory()
.buildBarrierRequest()
- .setXid(id);
+ .setXid(xid);
sw.sendMsg(builder.build());
}
}
@@ -462,7 +475,6 @@
}
}
- invokeCallbacks();
return true;
}
@@ -481,6 +493,7 @@
countDownLatch.await();
this.state = BatchState.FINISHED;
CompletedBatchOperation result = new CompletedBatchOperation(ok.get(), offendingFlowMods);
+ //FIXME do cleanup here
return result;
}
@@ -491,6 +504,7 @@
if (countDownLatch.await(timeout, unit)) {
this.state = BatchState.FINISHED;
CompletedBatchOperation result = new CompletedBatchOperation(ok.get(), offendingFlowMods);
+ // FIXME do cleanup here
return result;
}
throw new TimeoutException();
@@ -498,9 +512,7 @@
private void cleanUp() {
if (isDone() || isCancelled()) {
- if (pendingXid != null) {
- pendingFutures.remove(pendingXid);
- }
+ pendingFutures.remove(xid);
for (Long xid : fms.keySet()) {
pendingFMs.remove(xid);
}
@@ -509,21 +521,10 @@
private void removeRequirement(Dpid dpid) {
countDownLatch.countDown();
- if (countDownLatch.getCount() == 0) {
- invokeCallbacks();
- }
sws.remove(dpid);
+ //FIXME don't do cleanup here
cleanUp();
}
-
- @Override
- public void addListener(Runnable runnable, Executor executor) {
- executionList.add(runnable, executor);
- }
-
- private void invokeCallbacks() {
- executionList.execute();
- }
}
}
diff --git a/tools/package/config/README b/tools/package/config/README
index 62b758d..970f87a 100644
--- a/tools/package/config/README
+++ b/tools/package/config/README
@@ -1,2 +1,2 @@
-onos-config command will copy files contained in this directory to ONOS instances according to cell definition
-
+The onos-config command will copy files contained in this directory to ONOS
+instances according to cell definition.
diff --git a/tools/test/bin/onos-show-cell b/tools/test/bin/onos-show-cell
index eedea9e..5aee338 100755
--- a/tools/test/bin/onos-show-cell
+++ b/tools/test/bin/onos-show-cell
@@ -40,6 +40,7 @@
# Load the cell setup
. $ONOS_ROOT/tools/test/cells/${cell}
+echo "ONOS_CELL=${ONOS_CELL}"
echo "ONOS_NIC=${ONOS_NIC}"
for n in {0..9}; do
ocn="OC${n}"
diff --git a/tools/test/topos/oe-nonlinear-10.json b/tools/test/topos/oe-nonlinear-10.json
index f23bb9b..522215b 100644
--- a/tools/test/topos/oe-nonlinear-10.json
+++ b/tools/test/topos/oe-nonlinear-10.json
@@ -108,33 +108,26 @@
],
"links" : [
- { "src": "of:0000ffffffffff01/10", "dst": "of:0000ffffffffff02/10", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000, "durable": "true" } },
- { "src": "of:0000ffffffffff02/10", "dst": "of:0000ffffffffff03/10", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000, "durable": "true" } },
- { "src": "of:0000ffffffffff03/30", "dst": "of:0000ffffffffff04/10", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000, "durable": "true" } },
- { "src": "of:0000ffffffffff02/20", "dst": "of:0000ffffffffff05/10", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000, "durable": "true" } },
- { "src": "of:0000ffffffffff03/20", "dst": "of:0000ffffffffff06/10", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000, "durable": "true" } },
- { "src": "of:0000ffffffffff05/30", "dst": "of:0000ffffffffff06/20", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000, "durable": "true" } },
- { "src": "of:0000ffffffffff05/20", "dst": "of:0000ffffffffff07/21", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000, "durable": "true" } },
- { "src": "of:0000ffffffffff06/30", "dst": "of:0000ffffffffff08/10", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000, "durable": "true" } },
- { "src": "of:0000ffffffffff07/30", "dst": "of:0000ffffffffff08/20", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000, "durable": "true" } },
- { "src": "of:0000ffffffffff07/20", "dst": "of:0000ffffffffff09/10", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000, "durable": "true" } },
- { "src": "of:0000ffffffffff08/30", "dst": "of:0000ffffffffff0A/10", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000, "durable": "true" } },
+ { "src": "of:0000ffffffffff01/50", "dst": "of:0000ffffffffff02/30","type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000, "durable": "true" } },
+ { "src": "of:0000ffffffffff02/50", "dst": "of:0000ffffffffff03/30","type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000, "durable": "true" } },
+ { "src": "of:0000ffffffffff03/50", "dst": "of:0000ffffffffff04/50","type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000, "durable": "true" } },
+ { "src": "of:0000ffffffffff01/20", "dst": "of:0000ffffffffff05/50","type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000, "durable": "true" } },
+ { "src": "of:0000ffffffffff02/20", "dst": "of:0000ffffffffff05/20","type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000, "durable": "true" } },
+ { "src": "of:0000ffffffffff03/20", "dst": "of:0000ffffffffff06/50","type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000, "durable": "true" } },
+ { "src": "of:0000ffffffffff04/20", "dst": "of:0000ffffffffff06/20","type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000, "durable": "true" } },
+ { "src": "of:0000ffffffffff05/30", "dst": "of:0000ffffffffff06/40","type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000, "durable": "true" } },
+ { "src": "of:0000ffffffffff05/40", "dst": "of:0000ffffffffff07/50", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000, "durable": "true" } },
+ { "src": "of:0000ffffffffff06/30", "dst": "of:0000ffffffffff08/50", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000, "durable": "true" } },
+ { "src": "of:0000ffffffffff07/20", "dst": "of:0000ffffffffff08/30", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000, "durable": "true" } },
+ { "src": "of:0000ffffffffff07/30", "dst": "of:0000ffffffffff09/50", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000, "durable": "true" } },
+ { "src": "of:0000ffffffffff08/20", "dst": "of:0000ffffffffff0A/50", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000, "durable": "true" } },
{ "src": "of:0000ffffffffff09/20", "dst": "of:0000ffffffffff0A/20", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000, "durable": "true" } },
- { "src": "of:0000ffffffff0001/2", "dst": "of:0000ffffffffff01/1", "type": "OPTICAL", "annotations": { "bandwidth": 100000, "optical.type": "cross-connect", "durable": "true" } },
- { "src": "of:0000ffffffff0003/2", "dst": "of:0000ffffffffff03/1", "type": "OPTICAL", "annotations": { "bandwidth": 100000, "optical.type": "cross-connect", "durable": "true" } },
- { "src": "of:0000ffffffff0004/2", "dst": "of:0000ffffffffff04/1", "type": "OPTICAL", "annotations": { "bandwidth": 100000, "optical.type": "cross-connect", "durable": "true" } },
- { "src": "of:0000ffffffff0007/2", "dst": "of:0000ffffffffff07/1", "type": "OPTICAL", "annotations": { "bandwidth": 100000, "optical.type": "cross-connect", "durable": "true" } },
- { "src": "of:0000ffffffff0009/2", "dst": "of:0000ffffffffff09/1", "type": "OPTICAL", "annotations": { "bandwidth": 100000, "optical.type": "cross-connect", "durable": "true" } },
- { "src": "of:0000ffffffff000A/2", "dst": "of:0000ffffffffff0A/1", "type": "OPTICAL", "annotations": { "bandwidth": 100000, "optical.type": "cross-connect", "durable": "true" } }
- ],
-
- "hosts" : [
- { "mac": "00:00:00:00:00:01", "vlan": -1, "location": "of:0000ffffffff0001/1", "ip": "10.0.0.1" },
- { "mac": "00:00:00:00:00:03", "vlan": -1, "location": "of:0000ffffffff0003/1", "ip": "10.0.0.3" },
- { "mac": "00:00:00:00:00:04", "vlan": -1, "location": "of:0000ffffffff0004/1", "ip": "10.0.0.4" },
- { "mac": "00:00:00:00:00:07", "vlan": -1, "location": "of:0000ffffffff0007/1", "ip": "10.0.0.7" },
- { "mac": "00:00:00:00:00:09", "vlan": -1, "location": "of:0000ffffffff0009/1", "ip": "10.0.0.9" },
- { "mac": "00:00:00:00:00:0A", "vlan": -1, "location": "of:0000ffffffff000A/1", "ip": "10.0.0.10" }
+ { "src": "of:0000ffffffff0001/2", "dst": "of:0000ffffffffff01/10", "type": "OPTICAL", "annotations": { "bandwidth": 100000, "optical.type": "cross-connect", "durable": "true" } },
+ { "src": "of:0000ffffffff0002/2", "dst": "of:0000ffffffffff04/10", "type": "OPTICAL", "annotations": { "bandwidth": 100000, "optical.type": "cross-connect", "durable": "true" } },
+ { "src": "of:0000ffffffff0003/2", "dst": "of:0000ffffffffff06/10", "type": "OPTICAL", "annotations": { "bandwidth": 100000, "optical.type": "cross-connect", "durable": "true" } },
+ { "src": "of:0000ffffffff0004/2", "dst": "of:0000ffffffffff07/10", "type": "OPTICAL", "annotations": { "bandwidth": 100000, "optical.type": "cross-connect", "durable": "true" } },
+ { "src": "of:0000ffffffff0005/2", "dst": "of:0000ffffffffff09/10", "type": "OPTICAL", "annotations": { "bandwidth": 100000, "optical.type": "cross-connect", "durable": "true" } },
+ { "src": "of:0000ffffffff0006/2", "dst": "of:0000ffffffffff0A/10", "type": "OPTICAL", "annotations": { "bandwidth": 100000, "optical.type": "cross-connect", "durable": "true" } }
]
-}
\ No newline at end of file
+}
diff --git a/utils/junit/src/main/java/org/onlab/junit/ImmutableClassChecker.java b/utils/junit/src/main/java/org/onlab/junit/ImmutableClassChecker.java
index 2ac20b7..421a3e9 100644
--- a/utils/junit/src/main/java/org/onlab/junit/ImmutableClassChecker.java
+++ b/utils/junit/src/main/java/org/onlab/junit/ImmutableClassChecker.java
@@ -43,9 +43,9 @@
* @param clazz the class to check
* @return true if the given class is a properly specified immutable class.
*/
- private boolean isImmutableClass(Class<?> clazz) {
+ private boolean isImmutableClass(Class<?> clazz, boolean allowNonFinalClass) {
// class must be declared final
- if (!Modifier.isFinal(clazz.getModifiers())) {
+ if (!allowNonFinalClass && !Modifier.isFinal(clazz.getModifiers())) {
failureReason = "a class that is not final";
return false;
}
@@ -113,16 +113,16 @@
}
/**
- * Assert that the given class adheres to the utility class rules.
+ * Assert that the given class adheres to the immutable class rules.
*
* @param clazz the class to check
*
- * @throws java.lang.AssertionError if the class is not a valid
- * utility class
+ * @throws java.lang.AssertionError if the class is not an
+ * immutable class
*/
public static void assertThatClassIsImmutable(Class<?> clazz) {
final ImmutableClassChecker checker = new ImmutableClassChecker();
- if (!checker.isImmutableClass(clazz)) {
+ if (!checker.isImmutableClass(clazz, false)) {
final Description toDescription = new StringDescription();
final Description mismatchDescription = new StringDescription();
@@ -136,4 +136,31 @@
throw new AssertionError(reason);
}
}
+
+ /**
+ * Assert that the given class adheres to the immutable class rules, but
+ * is not declared final. Classes that need to be inherited from cannot be
+ * declared final.
+ *
+ * @param clazz the class to check
+ *
+ * @throws java.lang.AssertionError if the class is not an
+ * immutable class
+ */
+ public static void assertThatClassIsImmutableBaseClass(Class<?> clazz) {
+ final ImmutableClassChecker checker = new ImmutableClassChecker();
+ if (!checker.isImmutableClass(clazz, true)) {
+ final Description toDescription = new StringDescription();
+ final Description mismatchDescription = new StringDescription();
+
+ checker.describeTo(toDescription);
+ checker.describeMismatch(mismatchDescription);
+ final String reason =
+ "\n" +
+ "Expected: is \"" + toDescription.toString() + "\"\n" +
+ " but : was \"" + mismatchDescription.toString() + "\"";
+
+ throw new AssertionError(reason);
+ }
+ }
}
diff --git a/web/gui/src/main/java/org/onlab/onos/gui/TopologyMessages.java b/web/gui/src/main/java/org/onlab/onos/gui/TopologyMessages.java
index 0b54dd8..d68e8fa 100644
--- a/web/gui/src/main/java/org/onlab/onos/gui/TopologyMessages.java
+++ b/web/gui/src/main/java/org/onlab/onos/gui/TopologyMessages.java
@@ -24,6 +24,7 @@
import org.onlab.onos.cluster.ControllerNode;
import org.onlab.onos.cluster.NodeId;
import org.onlab.onos.mastership.MastershipService;
+import org.onlab.onos.net.Annotated;
import org.onlab.onos.net.Annotations;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.DefaultEdgeLink;
@@ -45,6 +46,8 @@
import org.onlab.onos.net.provider.ProviderId;
import org.onlab.osgi.ServiceDirectory;
import org.onlab.packet.IpAddress;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.util.Iterator;
import java.util.Map;
@@ -68,6 +71,8 @@
*/
public abstract class TopologyMessages {
+ protected static final Logger log = LoggerFactory.getLogger(TopologyMessages.class);
+
private static final ProviderId PID = new ProviderId("core", "org.onlab.onos.core", true);
private static final String COMPACT = "%s/%s-%s/%s";
@@ -195,7 +200,7 @@
.put("id", device.id().toString())
.put("type", device.type().toString().toLowerCase())
.put("online", deviceService.isAvailable(device.id()))
- .put("master", mastershipService.getMasterFor(device.id()).toString());
+ .put("master", master(device.id()));
// Generate labels: id, chassis id, no-label, optional-name
ArrayNode labels = mapper.createArrayNode();
@@ -207,6 +212,7 @@
// Add labels, props and stuff the payload into envelope.
payload.set("labels", labels);
payload.set("props", props(device.annotations()));
+ addGeoLocation(device, payload);
addMetaUi(device.id().toString(), payload);
String type = (event.type() == DEVICE_ADDED) ? "addDevice" :
@@ -220,6 +226,7 @@
ObjectNode payload = mapper.createObjectNode()
.put("id", compactLinkString(link))
.put("type", link.type().toString().toLowerCase())
+ .put("online", true) // TODO: add link state field
.put("linkWidth", 2)
.put("src", link.src().deviceId().toString())
.put("srcPort", link.src().port().toString())
@@ -237,10 +244,11 @@
.put("id", host.id().toString())
.put("ingress", compactLinkString(edgeLink(host, true)))
.put("egress", compactLinkString(edgeLink(host, false)));
- payload.set("cp", location(mapper, host.location()));
+ payload.set("cp", hostConnect(mapper, host.location()));
payload.set("labels", labels(mapper, ip(host.ipAddresses()),
host.mac().toString()));
payload.set("props", props(host.annotations()));
+ addGeoLocation(host, payload);
addMetaUi(host.id().toString(), payload);
String type = (event.type() == HOST_ADDED) ? "addHost" :
@@ -249,7 +257,7 @@
}
// Encodes the specified host location into a JSON object.
- private ObjectNode location(ObjectMapper mapper, HostLocation location) {
+ private ObjectNode hostConnect(ObjectMapper mapper, HostLocation location) {
return mapper.createObjectNode()
.put("device", location.deviceId().toString())
.put("port", location.port().toLong());
@@ -264,6 +272,12 @@
return json;
}
+ // Returns the name of the master node for the specified device id.
+ private String master(DeviceId deviceId) {
+ NodeId master = mastershipService.getMasterFor(deviceId);
+ return master != null ? master.toString() : "";
+ }
+
// Generates an edge link from the specified host location.
private EdgeLink edgeLink(Host host, boolean ingress) {
return new DefaultEdgeLink(PID, new ConnectPoint(host.id(), portNumber(0)),
@@ -278,6 +292,24 @@
}
}
+ // Adds a geo location JSON to the specified payload object.
+ private void addGeoLocation(Annotated annotated, ObjectNode payload) {
+ Annotations annotations = annotated.annotations();
+ String slat = annotations.value("latitude");
+ String slng = annotations.value("longitude");
+ try {
+ if (slat != null && slng != null && !slat.isEmpty() && !slng.isEmpty()) {
+ double lat = Double.parseDouble(slat);
+ double lng = Double.parseDouble(slng);
+ ObjectNode loc = mapper.createObjectNode()
+ .put("type", "latlng").put("lat", lat).put("lng", lng);
+ payload.set("location", loc);
+ }
+ } catch (NumberFormatException e) {
+ log.warn("Invalid geo data latitude={}; longiture={}", slat, slng);
+ }
+ }
+
// Updates meta UI information for the specified object.
protected void updateMetaUi(ObjectNode event) {
ObjectNode payload = payload(event);
@@ -289,7 +321,6 @@
Device device = deviceService.getDevice(deviceId);
Annotations annot = device.annotations();
int portCount = deviceService.getPorts(deviceId).size();
- NodeId master = mastershipService.getMasterFor(device.id());
return envelope("showDetails", sid,
json(deviceId.toString(),
device.type().toString().toLowerCase(),
@@ -303,7 +334,7 @@
new Prop("Longitude", annot.value("longitude")),
new Prop("Ports", Integer.toString(portCount)),
new Separator(),
- new Prop("Master", master.toString())));
+ new Prop("Master", master(deviceId))));
}
// Returns host details response.
@@ -321,14 +352,14 @@
// Produces a path message to the client.
- protected ObjectNode pathMessage(Path path) {
+ protected ObjectNode pathMessage(Path path, String type) {
ObjectNode payload = mapper.createObjectNode();
ArrayNode links = mapper.createArrayNode();
for (Link link : path.links()) {
links.add(compactLinkString(link));
}
- payload.set("links", links);
+ payload.put("type", type).set("links", links);
return payload;
}
diff --git a/web/gui/src/main/java/org/onlab/onos/gui/TopologyWebSocket.java b/web/gui/src/main/java/org/onlab/onos/gui/TopologyWebSocket.java
index 83e54b4..212f14d 100644
--- a/web/gui/src/main/java/org/onlab/onos/gui/TopologyWebSocket.java
+++ b/web/gui/src/main/java/org/onlab/onos/gui/TopologyWebSocket.java
@@ -122,7 +122,7 @@
cancelTraffic(event);
}
} catch (Exception e) {
- System.out.println("WTF?! " + data);
+ log.warn("Unable to parse GUI request {} due to {}", data, e);
e.printStackTrace();
}
}
@@ -282,7 +282,8 @@
if (installable != null && !installable.isEmpty()) {
PathIntent pathIntent = (PathIntent) installable.iterator().next();
Path path = pathIntent.path();
- ObjectNode payload = pathMessage(path).put("intentId", intent.id().toString());
+ ObjectNode payload = pathMessage(path, "host")
+ .put("intentId", intent.id().toString());
sendMessage(envelope("showPath", sid, payload));
}
}
diff --git a/web/gui/src/main/webapp/json/ev/_capture/rx/addDevice_ex1.json b/web/gui/src/main/webapp/json/ev/_capture/rx/addDevice_ex1.json
index f00cf2c..b82fda8 100644
--- a/web/gui/src/main/webapp/json/ev/_capture/rx/addDevice_ex1.json
+++ b/web/gui/src/main/webapp/json/ev/_capture/rx/addDevice_ex1.json
@@ -10,6 +10,10 @@
"",
null
],
- "props": {}
+ "props": {
+ "latitude": 123.5,
+ "longitude": 67.8,
+ "anotherProp": "foobar"
+ }
}
}
diff --git a/web/gui/src/main/webapp/json/ev/_capture/rx/addDevice_ex2_memo.json b/web/gui/src/main/webapp/json/ev/_capture/rx/addDevice_ex2_memo.json
new file mode 100644
index 0000000..5f519ff
--- /dev/null
+++ b/web/gui/src/main/webapp/json/ev/_capture/rx/addDevice_ex2_memo.json
@@ -0,0 +1,24 @@
+{
+ "event": "addDevice",
+ "payload": {
+ "id": "of:0000000000000003",
+ "type": "switch",
+ "online": true,
+ "labels": [
+ "of:0000000000000003",
+ "3",
+ "",
+ null
+ ],
+ "props": {
+ "latitude": 123.5,
+ "longitude": 67.8,
+ "anotherProp": "foobar"
+ },
+ "metaUi": {
+ "xpc": 57.3,
+ "ypc": 24.86,
+ "and": "other properties the UI wishes to remember..."
+ }
+ }
+}
diff --git a/web/gui/src/main/webapp/json/ev/_capture/tx/updateMeta_ex1.json b/web/gui/src/main/webapp/json/ev/_capture/tx/updateMeta_ex1.json
index c04727e..6114583 100644
--- a/web/gui/src/main/webapp/json/ev/_capture/tx/updateMeta_ex1.json
+++ b/web/gui/src/main/webapp/json/ev/_capture/tx/updateMeta_ex1.json
@@ -4,7 +4,11 @@
"payload": {
"id": "62:4F:65:BF:FF:B3/-1",
"class": "host",
- "x": 197,
- "y": 177
+ "memento": {
+ "xpc": 57.3,
+ "ypc": 24.86,
+ "and": "other properties the UI wishes to remember..."
+ }
}
}
+
diff --git a/web/gui/src/main/webapp/json/ev/intentSketch/scenario.json b/web/gui/src/main/webapp/json/ev/intentSketch/scenario.json
index 136d027..f109dde 100644
--- a/web/gui/src/main/webapp/json/ev/intentSketch/scenario.json
+++ b/web/gui/src/main/webapp/json/ev/intentSketch/scenario.json
@@ -5,5 +5,9 @@
"title": "Host Intent Scenario",
"params": {
"lastAuto": 0
- }
+ },
+ "description": [
+ "Currently this is just a sketch of the event sequence,",
+ " but is NOT YET a runnable scenario."
+ ]
}
\ No newline at end of file
diff --git a/web/gui/src/main/webapp/json/ev/simple/ev_13_onos.json b/web/gui/src/main/webapp/json/ev/simple/ev_13_onos.json
new file mode 100644
index 0000000..5320841
--- /dev/null
+++ b/web/gui/src/main/webapp/json/ev/simple/ev_13_onos.json
@@ -0,0 +1,17 @@
+{
+ "event": "removeHost",
+ "payload": {
+ "id": "A6:96:E5:03:52:5F/-1",
+ "ingress": "A6:96:E5:03:52:5F/-1/0-of:0000ffffffff0008/1",
+ "egress": "of:0000ffffffff0008/1-A6:96:E5:03:52:5F/-1/0",
+ "cp": {
+ "device": "of:0000ffffffff0008",
+ "port": 1
+ },
+ "labels": [
+ "10.0.0.17",
+ "A6:96:E5:03:52:5F"
+ ],
+ "props": {}
+ }
+}
diff --git a/web/gui/src/main/webapp/json/ev/simple/ev_13_ui.json b/web/gui/src/main/webapp/json/ev/simple/ev_13_ui.json
deleted file mode 100644
index 9d6e737..0000000
--- a/web/gui/src/main/webapp/json/ev/simple/ev_13_ui.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "event": "noop",
- "payload": {
- "id": "xyyzy"
- }
-}
diff --git a/web/gui/src/main/webapp/json/ev/simple/ev_1_onos.json b/web/gui/src/main/webapp/json/ev/simple/ev_1_onos.json
index 8656a90..fa7ae6e 100644
--- a/web/gui/src/main/webapp/json/ev/simple/ev_1_onos.json
+++ b/web/gui/src/main/webapp/json/ev/simple/ev_1_onos.json
@@ -4,6 +4,11 @@
"id": "of:0000ffffffff0008",
"type": "switch",
"online": false,
+ "location": {
+ "type": "latlng",
+ "lat": 37.6,
+ "lng": 122.3
+ },
"labels": [
"0000ffffffff0008",
"FF:FF:FF:FF:00:08",
diff --git a/web/gui/src/main/webapp/json/ev/simple/scenario.json b/web/gui/src/main/webapp/json/ev/simple/scenario.json
index 5fb8869..4c55b2d 100644
--- a/web/gui/src/main/webapp/json/ev/simple/scenario.json
+++ b/web/gui/src/main/webapp/json/ev/simple/scenario.json
@@ -20,6 +20,6 @@
"10. update link (increase width, update props)",
"11. update link (reduce width, update props)",
"12. remove link",
- ""
+ "13. remove host (10.0.0.17)"
]
-}
\ No newline at end of file
+}
diff --git a/web/gui/src/main/webapp/json/ev/startup/ev_10_onos.json b/web/gui/src/main/webapp/json/ev/startup/ev_10_onos.json
index 9b30b4a..ec0f258 100644
--- a/web/gui/src/main/webapp/json/ev/startup/ev_10_onos.json
+++ b/web/gui/src/main/webapp/json/ev/startup/ev_10_onos.json
@@ -3,7 +3,7 @@
"payload": {
"id": "of:0000ffffffffff04",
"type": "roadm",
- "online": false,
+ "online": true,
"labels": [
"0000ffffffffff04",
"FF:FF:FF:FF:FF:04",
diff --git a/web/gui/src/main/webapp/json/ev/startup/ev_11_onos.json b/web/gui/src/main/webapp/json/ev/startup/ev_11_onos.json
index 3b361d5..04e6754 100644
--- a/web/gui/src/main/webapp/json/ev/startup/ev_11_onos.json
+++ b/web/gui/src/main/webapp/json/ev/startup/ev_11_onos.json
@@ -3,15 +3,15 @@
"payload": {
"id": "of:0000ffffffff000A",
"type": "switch",
- "online": false,
+ "online": true,
"labels": [
"0000ffffffff000A",
"FF:FF:FF:FF:00:0A",
"?"
],
"metaUi": {
- "Zx": 832,
- "Zy": 223
+ "x": 832,
+ "y": 223
}
}
}
diff --git a/web/gui/src/main/webapp/json/ev/startup/ev_12_onos.json b/web/gui/src/main/webapp/json/ev/startup/ev_12_onos.json
index e53a6cd..c778cd5 100644
--- a/web/gui/src/main/webapp/json/ev/startup/ev_12_onos.json
+++ b/web/gui/src/main/webapp/json/ev/startup/ev_12_onos.json
@@ -3,7 +3,7 @@
"payload": {
"id": "of:0000ffffffff0001",
"type": "switch",
- "online": false,
+ "online": true,
"labels": [
"0000ffffffff0001",
"FF:FF:FF:FF:00:01",
diff --git a/web/gui/src/main/webapp/json/ev/startup/ev_13_onos.json b/web/gui/src/main/webapp/json/ev/startup/ev_13_onos.json
index 6d2341f..a0cc21f 100644
--- a/web/gui/src/main/webapp/json/ev/startup/ev_13_onos.json
+++ b/web/gui/src/main/webapp/json/ev/startup/ev_13_onos.json
@@ -3,7 +3,7 @@
"payload": {
"id": "of:0000ffffffffff01",
"type": "roadm",
- "online": false,
+ "online": true,
"labels": [
"0000ffffffffff01",
"FF:FF:FF:FF:FF:01",
diff --git a/web/gui/src/main/webapp/json/ev/startup/ev_14_onos.json b/web/gui/src/main/webapp/json/ev/startup/ev_14_onos.json
index e196148..93127a8 100644
--- a/web/gui/src/main/webapp/json/ev/startup/ev_14_onos.json
+++ b/web/gui/src/main/webapp/json/ev/startup/ev_14_onos.json
@@ -3,7 +3,7 @@
"payload": {
"id": "of:0000ffffffff0004",
"type": "switch",
- "online": false,
+ "online": true,
"labels": [
"0000ffffffff0004",
"FF:FF:FF:FF:00:04",
diff --git a/web/gui/src/main/webapp/json/ev/startup/ev_15_onos.json b/web/gui/src/main/webapp/json/ev/startup/ev_15_onos.json
index 30ba9f3..f2d6891 100644
--- a/web/gui/src/main/webapp/json/ev/startup/ev_15_onos.json
+++ b/web/gui/src/main/webapp/json/ev/startup/ev_15_onos.json
@@ -3,15 +3,15 @@
"payload": {
"id": "of:0000ffffffffff0A",
"type": "roadm",
- "online": false,
+ "online": true,
"labels": [
"0000ffffffffff0A",
"FF:FF:FF:FF:FF:0A",
"?"
],
"metaUi": {
- "Zx": 840,
- "Zy": 290
+ "x": 840,
+ "y": 290
}
}
}
diff --git a/web/gui/src/main/webapp/json/ev/startup/ev_16_onos.json b/web/gui/src/main/webapp/json/ev/startup/ev_16_onos.json
index 274adc1..3b0db4b 100644
--- a/web/gui/src/main/webapp/json/ev/startup/ev_16_onos.json
+++ b/web/gui/src/main/webapp/json/ev/startup/ev_16_onos.json
@@ -3,7 +3,7 @@
"payload": {
"id": "of:0000ffffffffff09",
"type": "roadm",
- "online": false,
+ "online": true,
"labels": [
"0000ffffffffff09",
"FF:FF:FF:FF:FF:09",
diff --git a/web/gui/src/main/webapp/json/ev/startup/ev_17_onos.json b/web/gui/src/main/webapp/json/ev/startup/ev_17_onos.json
index 82272a4..69c62b9 100644
--- a/web/gui/src/main/webapp/json/ev/startup/ev_17_onos.json
+++ b/web/gui/src/main/webapp/json/ev/startup/ev_17_onos.json
@@ -1,12 +1,13 @@
{
"event": "addLink",
"payload": {
+ "id": "of:0000ffffffffff02/20-of:0000ffffffffff05/10",
+ "type": "optical",
+ "linkWidth": 4,
"src": "of:0000ffffffffff02",
"srcPort": "20",
"dst": "of:0000ffffffffff05",
"dstPort": "10",
- "type": "optical",
- "linkWidth": 6,
"props" : {
"BW": "80 G"
}
diff --git a/web/gui/src/main/webapp/json/ev/startup/ev_18_onos.json b/web/gui/src/main/webapp/json/ev/startup/ev_18_onos.json
index 5687698..d11f13e 100644
--- a/web/gui/src/main/webapp/json/ev/startup/ev_18_onos.json
+++ b/web/gui/src/main/webapp/json/ev/startup/ev_18_onos.json
@@ -1,12 +1,13 @@
{
"event": "addLink",
"payload": {
+ "id": "of:0000ffffffff000A/2-of:0000ffffffffff0A/1",
+ "type": "optical",
+ "linkWidth": 2,
"src": "of:0000ffffffff000A",
"srcPort": "2",
"dst": "of:0000ffffffffff0A",
"dstPort": "1",
- "type": "optical",
- "linkWidth": 2,
"props" : {
"BW": "100 G"
}
diff --git a/web/gui/src/main/webapp/json/ev/startup/ev_19_onos.json b/web/gui/src/main/webapp/json/ev/startup/ev_19_onos.json
index 24aeb2d..1349a3b 100644
--- a/web/gui/src/main/webapp/json/ev/startup/ev_19_onos.json
+++ b/web/gui/src/main/webapp/json/ev/startup/ev_19_onos.json
@@ -1,12 +1,13 @@
{
"event": "addLink",
"payload": {
+ "id": "of:0000ffffffffff03/10-of:0000ffffffffff02/10",
+ "type": "optical",
+ "linkWidth": 2,
"src": "of:0000ffffffffff03",
"srcPort": "10",
"dst": "of:0000ffffffffff02",
"dstPort": "10",
- "type": "optical",
- "linkWidth": 2,
"props" : {
"BW": "70 G"
}
diff --git a/web/gui/src/main/webapp/json/ev/startup/ev_1_onos.json b/web/gui/src/main/webapp/json/ev/startup/ev_1_onos.json
index d4c8ddb..00a3e17 100644
--- a/web/gui/src/main/webapp/json/ev/startup/ev_1_onos.json
+++ b/web/gui/src/main/webapp/json/ev/startup/ev_1_onos.json
@@ -3,7 +3,7 @@
"payload": {
"id": "of:0000ffffffffff08",
"type": "roadm",
- "online": false,
+ "online": true,
"labels": [
"0000ffffffffff08",
"FF:FF:FF:FF:FF:08",
diff --git a/web/gui/src/main/webapp/json/ev/startup/ev_20_onos.json b/web/gui/src/main/webapp/json/ev/startup/ev_20_onos.json
index f42b50e..e4d2161 100644
--- a/web/gui/src/main/webapp/json/ev/startup/ev_20_onos.json
+++ b/web/gui/src/main/webapp/json/ev/startup/ev_20_onos.json
@@ -1,12 +1,13 @@
{
"event": "addLink",
"payload": {
+ "id": "of:0000ffffffffff07/21-of:0000ffffffffff05/20",
+ "type": "optical",
+ "linkWidth": 2,
"src": "of:0000ffffffffff07",
"srcPort": "21",
"dst": "of:0000ffffffffff05",
"dstPort": "20",
- "type": "optical",
- "linkWidth": 2,
"props" : {
"BW": "70 G"
}
diff --git a/web/gui/src/main/webapp/json/ev/startup/ev_21_onos.json b/web/gui/src/main/webapp/json/ev/startup/ev_21_onos.json
index 5af0ac7..ccdad88 100644
--- a/web/gui/src/main/webapp/json/ev/startup/ev_21_onos.json
+++ b/web/gui/src/main/webapp/json/ev/startup/ev_21_onos.json
@@ -1,12 +1,13 @@
{
"event": "addLink",
"payload": {
+ "id": "of:0000ffffffff0001/2-of:0000ffffffffff01/1",
+ "type": "optical",
+ "linkWidth": 2,
"src": "of:0000ffffffff0001",
"srcPort": "2",
"dst": "of:0000ffffffffff01",
"dstPort": "1",
- "type": "optical",
- "linkWidth": 2,
"props" : {
"BW": "70 G"
}
diff --git a/web/gui/src/main/webapp/json/ev/startup/ev_22_onos.json b/web/gui/src/main/webapp/json/ev/startup/ev_22_onos.json
index 0d4cf2b..52a4a02 100644
--- a/web/gui/src/main/webapp/json/ev/startup/ev_22_onos.json
+++ b/web/gui/src/main/webapp/json/ev/startup/ev_22_onos.json
@@ -1,12 +1,13 @@
{
"event": "addLink",
"payload": {
+ "id": "of:0000ffffffffff09/20-of:0000ffffffffff0A/20",
+ "type": "optical",
+ "linkWidth": 2,
"src": "of:0000ffffffffff09",
"srcPort": "20",
"dst": "of:0000ffffffffff0A",
"dstPort": "20",
- "type": "optical",
- "linkWidth": 2,
"props" : {
"BW": "70 G"
}
diff --git a/web/gui/src/main/webapp/json/ev/startup/ev_23_onos.json b/web/gui/src/main/webapp/json/ev/startup/ev_23_onos.json
index fff0f2b..be778551 100644
--- a/web/gui/src/main/webapp/json/ev/startup/ev_23_onos.json
+++ b/web/gui/src/main/webapp/json/ev/startup/ev_23_onos.json
@@ -1,12 +1,13 @@
{
"event": "addLink",
"payload": {
- "src": "of:0000ffffffffff06",
- "srcPort": "20",
- "dst": "of:0000ffffffffff05",
- "dstPort": "30",
+ "id": "of:0000ffffffffff07/30-of:0000ffffffffff08/20",
"type": "optical",
- "linkWidth": 6,
+ "linkWidth": 4,
+ "src": "of:0000ffffffffff07",
+ "srcPort": "30",
+ "dst": "of:0000ffffffffff08",
+ "dstPort": "20",
"props" : {
"BW": "70 G"
}
diff --git a/web/gui/src/main/webapp/json/ev/startup/ev_24_onos.json b/web/gui/src/main/webapp/json/ev/startup/ev_24_onos.json
index 756b6c1..6ae5192 100644
--- a/web/gui/src/main/webapp/json/ev/startup/ev_24_onos.json
+++ b/web/gui/src/main/webapp/json/ev/startup/ev_24_onos.json
@@ -1,12 +1,13 @@
{
"event": "addLink",
"payload": {
- "src": "of:0000ffffffffff07",
- "srcPort": "30",
- "dst": "of:0000ffffffffff08",
- "dstPort": "20",
+ "id": "of:0000ffffffffff02/10-of:0000ffffffffff01/10",
"type": "optical",
- "linkWidth": 6,
+ "linkWidth": 2,
+ "src": "of:0000ffffffffff02",
+ "srcPort": "10",
+ "dst": "of:0000ffffffffff01",
+ "dstPort": "10",
"props" : {
"BW": "70 G"
}
diff --git a/web/gui/src/main/webapp/json/ev/startup/ev_25_onos.json b/web/gui/src/main/webapp/json/ev/startup/ev_25_onos.json
index adad8a6..7fabce6 100644
--- a/web/gui/src/main/webapp/json/ev/startup/ev_25_onos.json
+++ b/web/gui/src/main/webapp/json/ev/startup/ev_25_onos.json
@@ -1,14 +1,15 @@
{
"event": "addLink",
"payload": {
- "src": "of:0000ffffffffff03",
- "srcPort": "20",
- "dst": "of:0000ffffffffff06",
+ "id": "of:0000ffffffffff04/27-of:0000ffffffffff08/10",
+ "src": "of:0000ffffffffff04",
+ "srcPort": "27",
+ "dst": "of:0000ffffffffff08",
"dstPort": "10",
"type": "optical",
"linkWidth": 2,
"props" : {
- "BW": "70 G"
+ "BW": "30 G"
}
}
}
diff --git a/web/gui/src/main/webapp/json/ev/startup/ev_26_onos.json b/web/gui/src/main/webapp/json/ev/startup/ev_26_onos.json
index 245c823..b89a287 100644
--- a/web/gui/src/main/webapp/json/ev/startup/ev_26_onos.json
+++ b/web/gui/src/main/webapp/json/ev/startup/ev_26_onos.json
@@ -1,12 +1,13 @@
{
"event": "addLink",
"payload": {
- "src": "of:0000ffffffffff02",
- "srcPort": "10",
- "dst": "of:0000ffffffffff01",
- "dstPort": "10",
+ "id": "of:0000ffffffff0003/2-of:0000ffffffffff03/1",
"type": "optical",
"linkWidth": 2,
+ "src": "of:0000ffffffff0003",
+ "srcPort": "2",
+ "dst": "of:0000ffffffffff03",
+ "dstPort": "1",
"props" : {
"BW": "70 G"
}
diff --git a/web/gui/src/main/webapp/json/ev/startup/ev_27_onos.json b/web/gui/src/main/webapp/json/ev/startup/ev_27_onos.json
index b856573..112a33e 100644
--- a/web/gui/src/main/webapp/json/ev/startup/ev_27_onos.json
+++ b/web/gui/src/main/webapp/json/ev/startup/ev_27_onos.json
@@ -1,12 +1,13 @@
{
"event": "addLink",
"payload": {
+ "id": "of:0000ffffffffff09/1-of:0000ffffffff0009/2",
+ "type": "optical",
+ "linkWidth": 2,
"src": "of:0000ffffffffff09",
"srcPort": "1",
"dst": "of:0000ffffffff0009",
"dstPort": "2",
- "type": "optical",
- "linkWidth": 2,
"props" : {
"BW": "70 G"
}
diff --git a/web/gui/src/main/webapp/json/ev/startup/ev_28_onos.json b/web/gui/src/main/webapp/json/ev/startup/ev_28_onos.json
index 232dc3b..52207df 100644
--- a/web/gui/src/main/webapp/json/ev/startup/ev_28_onos.json
+++ b/web/gui/src/main/webapp/json/ev/startup/ev_28_onos.json
@@ -1,12 +1,13 @@
{
"event": "addLink",
"payload": {
+ "id": "of:0000ffffffffff03/30-of:0000ffffffffff04/10",
+ "type": "optical",
+ "linkWidth": 2,
"src": "of:0000ffffffffff03",
"srcPort": "30",
"dst": "of:0000ffffffffff04",
"dstPort": "10",
- "type": "optical",
- "linkWidth": 2,
"props" : {
"BW": "70 G"
}
diff --git a/web/gui/src/main/webapp/json/ev/startup/ev_29_onos.json b/web/gui/src/main/webapp/json/ev/startup/ev_29_onos.json
index 1a845ce..c4660a3 100644
--- a/web/gui/src/main/webapp/json/ev/startup/ev_29_onos.json
+++ b/web/gui/src/main/webapp/json/ev/startup/ev_29_onos.json
@@ -1,12 +1,13 @@
{
"event": "addLink",
"payload": {
+ "id": "of:0000ffffffffff07/20-of:0000ffffffffff09/10",
+ "type": "optical",
+ "linkWidth": 2,
"src": "of:0000ffffffffff07",
"srcPort": "20",
"dst": "of:0000ffffffffff09",
"dstPort": "10",
- "type": "optical",
- "linkWidth": 2,
"props" : {
"BW": "70 G"
}
diff --git a/web/gui/src/main/webapp/json/ev/startup/ev_2_onos.json b/web/gui/src/main/webapp/json/ev/startup/ev_2_onos.json
index fd446ba..8d4fbfa 100644
--- a/web/gui/src/main/webapp/json/ev/startup/ev_2_onos.json
+++ b/web/gui/src/main/webapp/json/ev/startup/ev_2_onos.json
@@ -3,7 +3,7 @@
"payload": {
"id": "of:0000ffffffffff03",
"type": "roadm",
- "online": false,
+ "online": true,
"labels": [
"0000ffffffffff03",
"FF:FF:FF:FF:FF:03",
diff --git a/web/gui/src/main/webapp/json/ev/startup/ev_30_onos.json b/web/gui/src/main/webapp/json/ev/startup/ev_30_onos.json
index a617f45..e23cc2a 100644
--- a/web/gui/src/main/webapp/json/ev/startup/ev_30_onos.json
+++ b/web/gui/src/main/webapp/json/ev/startup/ev_30_onos.json
@@ -1,12 +1,13 @@
{
"event": "addLink",
"payload": {
+ "id": "of:0000ffffffffff0A/10-of:0000ffffffffff08/30",
+ "type": "optical",
+ "linkWidth": 4,
"src": "of:0000ffffffffff0A",
"srcPort": "10",
"dst": "of:0000ffffffffff08",
"dstPort": "30",
- "type": "optical",
- "linkWidth": 6,
"props" : {
"BW": "70 G"
}
diff --git a/web/gui/src/main/webapp/json/ev/startup/ev_31_onos.json b/web/gui/src/main/webapp/json/ev/startup/ev_31_onos.json
index 438aa1b..a798e53 100644
--- a/web/gui/src/main/webapp/json/ev/startup/ev_31_onos.json
+++ b/web/gui/src/main/webapp/json/ev/startup/ev_31_onos.json
@@ -1,12 +1,13 @@
{
"event": "addLink",
"payload": {
+ "id": "of:0000ffffffff0004/2-of:0000ffffffffff04/1",
+ "type": "optical",
+ "linkWidth": 2,
"src": "of:0000ffffffff0004",
"srcPort": "2",
"dst": "of:0000ffffffffff04",
"dstPort": "1",
- "type": "optical",
- "linkWidth": 2,
"props" : {
"BW": "70 G"
}
diff --git a/web/gui/src/main/webapp/json/ev/startup/ev_32_onos.json b/web/gui/src/main/webapp/json/ev/startup/ev_32_onos.json
index c479f01..aac204f 100644
--- a/web/gui/src/main/webapp/json/ev/startup/ev_32_onos.json
+++ b/web/gui/src/main/webapp/json/ev/startup/ev_32_onos.json
@@ -1,12 +1,13 @@
{
"event": "addLink",
"payload": {
+ "id": "of:0000ffffffffff07/1-of:0000ffffffff0007/2",
+ "type": "optical",
+ "linkWidth": 2,
"src": "of:0000ffffffffff07",
"srcPort": "1",
"dst": "of:0000ffffffff0007",
"dstPort": "2",
- "type": "optical",
- "linkWidth": 2,
"props" : {
"BW": "70 G"
}
diff --git a/web/gui/src/main/webapp/json/ev/startup/ev_33_onos.json b/web/gui/src/main/webapp/json/ev/startup/ev_33_onos.json
index 2cc3a32..ab23e93 100644
--- a/web/gui/src/main/webapp/json/ev/startup/ev_33_onos.json
+++ b/web/gui/src/main/webapp/json/ev/startup/ev_33_onos.json
@@ -1,14 +1,17 @@
{
- "event": "addLink",
+ "event": "updateDevice",
"payload": {
- "src": "of:0000ffffffff0003",
- "srcPort": "2",
- "dst": "of:0000ffffffffff03",
- "dstPort": "1",
- "type": "optical",
- "linkWidth": 2,
- "props" : {
- "BW": "70 G"
+ "id": "of:0000ffffffffff06",
+ "type": "roadm",
+ "online": true,
+ "labels": [
+ "0000ffffffffff06",
+ "FF:FF:FF:FF:FF:06",
+ "?"
+ ],
+ "metaUi": {
+ "x": 336,
+ "y": 254
}
}
}
diff --git a/web/gui/src/main/webapp/json/ev/startup/ev_34_onos.json b/web/gui/src/main/webapp/json/ev/startup/ev_34_onos.json
index fa5e3bc..09be8e6 100644
--- a/web/gui/src/main/webapp/json/ev/startup/ev_34_onos.json
+++ b/web/gui/src/main/webapp/json/ev/startup/ev_34_onos.json
@@ -1,12 +1,13 @@
{
"event": "addLink",
"payload": {
+ "id": "of:0000ffffffffff06/20-of:0000ffffffffff05/30",
"src": "of:0000ffffffffff06",
- "srcPort": "30",
- "dst": "of:0000ffffffffff08",
- "dstPort": "10",
+ "srcPort": "20",
+ "dst": "of:0000ffffffffff05",
+ "dstPort": "30",
"type": "optical",
- "linkWidth": 6,
+ "linkWidth": 4,
"props" : {
"BW": "70 G"
}
diff --git a/web/gui/src/main/webapp/json/ev/startup/ev_35_onos.json b/web/gui/src/main/webapp/json/ev/startup/ev_35_onos.json
index c579e59..4b612e9 100644
--- a/web/gui/src/main/webapp/json/ev/startup/ev_35_onos.json
+++ b/web/gui/src/main/webapp/json/ev/startup/ev_35_onos.json
@@ -1,14 +1,15 @@
{
"event": "addLink",
"payload": {
- "src": "of:0000ffffffffff04",
- "srcPort": "27",
- "dst": "of:0000ffffffffff08",
- "dstPort": "10",
+ "id": "of:0000ffffffffff03/20-of:0000ffffffffff06/10",
"type": "optical",
"linkWidth": 2,
+ "src": "of:0000ffffffffff03",
+ "srcPort": "20",
+ "dst": "of:0000ffffffffff06",
+ "dstPort": "10",
"props" : {
- "BW": "30 G"
+ "BW": "70 G"
}
}
}
diff --git a/web/gui/src/main/webapp/json/ev/startup/ev_36_onos.json b/web/gui/src/main/webapp/json/ev/startup/ev_36_onos.json
new file mode 100644
index 0000000..cddb929
--- /dev/null
+++ b/web/gui/src/main/webapp/json/ev/startup/ev_36_onos.json
@@ -0,0 +1,15 @@
+{
+ "event": "addLink",
+ "payload": {
+ "id": "of:0000ffffffffff06/30-of:0000ffffffffff08/10",
+ "type": "optical",
+ "linkWidth": 4,
+ "src": "of:0000ffffffffff06",
+ "srcPort": "30",
+ "dst": "of:0000ffffffffff08",
+ "dstPort": "10",
+ "props" : {
+ "BW": "70 G"
+ }
+ }
+}
diff --git a/web/gui/src/main/webapp/json/ev/startup/ev_37_onos.json b/web/gui/src/main/webapp/json/ev/startup/ev_37_onos.json
new file mode 100644
index 0000000..6f608cd
--- /dev/null
+++ b/web/gui/src/main/webapp/json/ev/startup/ev_37_onos.json
@@ -0,0 +1,17 @@
+{
+ "event": "updateDevice",
+ "payload": {
+ "id": "of:0000ffffffffff08",
+ "type": "roadm",
+ "online": false,
+ "labels": [
+ "0000ffffffffff08",
+ "FF:FF:FF:FF:FF:08",
+ "?"
+ ],
+ "metaUi": {
+ "x": 539,
+ "y": 186
+ }
+ }
+}
diff --git a/web/gui/src/main/webapp/json/ev/startup/ev_38_onos.json b/web/gui/src/main/webapp/json/ev/startup/ev_38_onos.json
new file mode 100644
index 0000000..09a0339
--- /dev/null
+++ b/web/gui/src/main/webapp/json/ev/startup/ev_38_onos.json
@@ -0,0 +1,15 @@
+{
+ "event": "removeLink",
+ "payload": {
+ "id": "of:0000ffffffffff07/30-of:0000ffffffffff08/20",
+ "type": "optical",
+ "linkWidth": 4,
+ "src": "of:0000ffffffffff07",
+ "srcPort": "30",
+ "dst": "of:0000ffffffffff08",
+ "dstPort": "20",
+ "props" : {
+ "BW": "70 G"
+ }
+ }
+}
diff --git a/web/gui/src/main/webapp/json/ev/startup/ev_39_onos.json b/web/gui/src/main/webapp/json/ev/startup/ev_39_onos.json
new file mode 100644
index 0000000..a85cee6
--- /dev/null
+++ b/web/gui/src/main/webapp/json/ev/startup/ev_39_onos.json
@@ -0,0 +1,15 @@
+{
+ "event": "removeLink",
+ "payload": {
+ "id": "of:0000ffffffffff04/27-of:0000ffffffffff08/10",
+ "src": "of:0000ffffffffff04",
+ "srcPort": "27",
+ "dst": "of:0000ffffffffff08",
+ "dstPort": "10",
+ "type": "optical",
+ "linkWidth": 2,
+ "props" : {
+ "BW": "30 G"
+ }
+ }
+}
diff --git a/web/gui/src/main/webapp/json/ev/startup/ev_3_onos.json b/web/gui/src/main/webapp/json/ev/startup/ev_3_onos.json
index 23bf26a..b4c3537 100644
--- a/web/gui/src/main/webapp/json/ev/startup/ev_3_onos.json
+++ b/web/gui/src/main/webapp/json/ev/startup/ev_3_onos.json
@@ -3,7 +3,7 @@
"payload": {
"id": "of:0000ffffffff0007",
"type": "switch",
- "online": false,
+ "online": true,
"labels": [
"0000ffffffff0007",
"FF:FF:FF:FF:00:07",
diff --git a/web/gui/src/main/webapp/json/ev/startup/ev_40_onos.json b/web/gui/src/main/webapp/json/ev/startup/ev_40_onos.json
new file mode 100644
index 0000000..1b95d24
--- /dev/null
+++ b/web/gui/src/main/webapp/json/ev/startup/ev_40_onos.json
@@ -0,0 +1,15 @@
+{
+ "event": "removeLink",
+ "payload": {
+ "id": "of:0000ffffffffff0A/10-of:0000ffffffffff08/30",
+ "type": "optical",
+ "linkWidth": 4,
+ "src": "of:0000ffffffffff0A",
+ "srcPort": "10",
+ "dst": "of:0000ffffffffff08",
+ "dstPort": "30",
+ "props" : {
+ "BW": "70 G"
+ }
+ }
+}
diff --git a/web/gui/src/main/webapp/json/ev/startup/ev_41_onos.json b/web/gui/src/main/webapp/json/ev/startup/ev_41_onos.json
new file mode 100644
index 0000000..1efc1f6
--- /dev/null
+++ b/web/gui/src/main/webapp/json/ev/startup/ev_41_onos.json
@@ -0,0 +1,15 @@
+{
+ "event": "removeLink",
+ "payload": {
+ "id": "of:0000ffffffffff06/30-of:0000ffffffffff08/10",
+ "type": "optical",
+ "linkWidth": 4,
+ "src": "of:0000ffffffffff06",
+ "srcPort": "30",
+ "dst": "of:0000ffffffffff08",
+ "dstPort": "10",
+ "props" : {
+ "BW": "70 G"
+ }
+ }
+}
diff --git a/web/gui/src/main/webapp/json/ev/startup/ev_4_onos.json b/web/gui/src/main/webapp/json/ev/startup/ev_4_onos.json
index c600401..053b963 100644
--- a/web/gui/src/main/webapp/json/ev/startup/ev_4_onos.json
+++ b/web/gui/src/main/webapp/json/ev/startup/ev_4_onos.json
@@ -3,7 +3,7 @@
"payload": {
"id": "of:0000ffffffff0009",
"type": "switch",
- "online": false,
+ "online": true,
"labels": [
"0000ffffffff0009",
"FF:FF:FF:FF:00:09",
diff --git a/web/gui/src/main/webapp/json/ev/startup/ev_5_onos.json b/web/gui/src/main/webapp/json/ev/startup/ev_5_onos.json
index af912a7..332bfdb 100644
--- a/web/gui/src/main/webapp/json/ev/startup/ev_5_onos.json
+++ b/web/gui/src/main/webapp/json/ev/startup/ev_5_onos.json
@@ -3,7 +3,7 @@
"payload": {
"id": "of:0000ffffffffff02",
"type": "roadm",
- "online": false,
+ "online": true,
"labels": [
"0000ffffffffff02",
"FF:FF:FF:FF:FF:02",
diff --git a/web/gui/src/main/webapp/json/ev/startup/ev_6_onos.json b/web/gui/src/main/webapp/json/ev/startup/ev_6_onos.json
index 50273bc..c764bc1 100644
--- a/web/gui/src/main/webapp/json/ev/startup/ev_6_onos.json
+++ b/web/gui/src/main/webapp/json/ev/startup/ev_6_onos.json
@@ -3,7 +3,7 @@
"payload": {
"id": "of:0000ffffffff0003",
"type": "switch",
- "online": false,
+ "online": true,
"labels": [
"0000ffffffff0003",
"FF:FF:FF:FF:00:03",
diff --git a/web/gui/src/main/webapp/json/ev/startup/ev_7_onos.json b/web/gui/src/main/webapp/json/ev/startup/ev_7_onos.json
index 7cd29b0..25a6dce 100644
--- a/web/gui/src/main/webapp/json/ev/startup/ev_7_onos.json
+++ b/web/gui/src/main/webapp/json/ev/startup/ev_7_onos.json
@@ -3,7 +3,7 @@
"payload": {
"id": "of:0000ffffffffff07",
"type": "roadm",
- "online": false,
+ "online": true,
"labels": [
"0000ffffffffff07",
"FF:FF:FF:FF:FF:07",
diff --git a/web/gui/src/main/webapp/json/ev/startup/ev_9_onos.json b/web/gui/src/main/webapp/json/ev/startup/ev_9_onos.json
index 1e0f427..0f497c0 100644
--- a/web/gui/src/main/webapp/json/ev/startup/ev_9_onos.json
+++ b/web/gui/src/main/webapp/json/ev/startup/ev_9_onos.json
@@ -3,7 +3,7 @@
"payload": {
"id": "of:0000ffffffffff05",
"type": "roadm",
- "online": false,
+ "online": true,
"labels": [
"0000ffffffffff05",
"FF:FF:FF:FF:FF:05",
diff --git a/web/gui/src/main/webapp/json/ev/startup/scenario.json b/web/gui/src/main/webapp/json/ev/startup/scenario.json
index 37939ca0..089d53a 100644
--- a/web/gui/src/main/webapp/json/ev/startup/scenario.json
+++ b/web/gui/src/main/webapp/json/ev/startup/scenario.json
@@ -6,5 +6,15 @@
"title": "Startup Scenario",
"params": {
"lastAuto": 32
- }
+ },
+ "description": [
+ "Loads 16 devices (10 optical, 6 packet)",
+ " and their associated links.",
+ "",
+ "Press 'S' to load initial events.",
+ "",
+ "Press spacebar to complete the scenario...",
+ " * 4 events - device online, add 3 links",
+ " * 5 events - device offline, remove 4 links"
+ ]
}
\ No newline at end of file
diff --git a/web/gui/src/main/webapp/json/of_0000000000000001.json b/web/gui/src/main/webapp/json/of_0000000000000001.json
index 719af80..1f5c8e9 100644
--- a/web/gui/src/main/webapp/json/of_0000000000000001.json
+++ b/web/gui/src/main/webapp/json/of_0000000000000001.json
@@ -3,6 +3,11 @@
"id": "of:0000000000000001",
"type": "roadm",
"propOrder": [ "name", "type", "-", "dpid", "latitude", "longitude", "allowed" ],
+ "location": {
+ "type": "latlng",
+ "lat": 37.6,
+ "lng": 122.3
+ },
"props": {
"allowed": true,
"latitude": 37.6,
diff --git a/web/gui/src/main/webapp/json/of_0000000000000002.json b/web/gui/src/main/webapp/json/of_0000000000000002.json
index a6b0e7c..87fd1f2 100644
--- a/web/gui/src/main/webapp/json/of_0000000000000002.json
+++ b/web/gui/src/main/webapp/json/of_0000000000000002.json
@@ -3,6 +3,11 @@
"id": "of:0000000000000002",
"type": "switch",
"propOrder": [ "name", "type", "dpid", "latitude", "longitude", "allowed" ],
+ "location": {
+ "type": "latlng",
+ "lat": 37.6,
+ "lng": 122.3
+ },
"props": {
"allowed": true,
"latitude": 37.3,
diff --git a/web/gui/src/main/webapp/json/of_0000000000000003.json b/web/gui/src/main/webapp/json/of_0000000000000003.json
index 9fd2790..1315961 100644
--- a/web/gui/src/main/webapp/json/of_0000000000000003.json
+++ b/web/gui/src/main/webapp/json/of_0000000000000003.json
@@ -3,6 +3,11 @@
"id": "of:0000000000000003",
"type": "switch",
"propOrder": [ "name", "type", "dpid", "latitude", "longitude", "allowed" ],
+ "location": {
+ "type": "latlng",
+ "lat": 33.9,
+ "lng": 118.4
+ },
"props": {
"allowed": true,
"latitude": 33.9,
diff --git a/web/gui/src/main/webapp/json/of_0000000000000004.json b/web/gui/src/main/webapp/json/of_0000000000000004.json
index f3f2132..ba243baf 100644
--- a/web/gui/src/main/webapp/json/of_0000000000000004.json
+++ b/web/gui/src/main/webapp/json/of_0000000000000004.json
@@ -3,6 +3,11 @@
"id": "of:0000000000000004",
"type": "switch",
"propOrder": [ "name", "type", "dpid", "latitude", "longitude", "allowed" ],
+ "location": {
+ "type": "latlng",
+ "lat": 32.8,
+ "lng": 117.1
+ },
"props": {
"allowed": true,
"latitude": 32.8,
diff --git a/web/gui/src/main/webapp/topo2.js b/web/gui/src/main/webapp/topo2.js
index 94b2e9e..24053d8 100644
--- a/web/gui/src/main/webapp/topo2.js
+++ b/web/gui/src/main/webapp/topo2.js
@@ -30,6 +30,7 @@
// configuration data
var config = {
useLiveData: true,
+ fnTrace: true,
debugOn: false,
debug: {
showNodeXY: true,
@@ -180,6 +181,11 @@
return config.debugOn && config.debug[what];
}
+ function fnTrace(msg, id) {
+ if (config.fnTrace) {
+ console.log('FN: ' + msg + ' [' + id + ']');
+ }
+ }
// ==============================
// Key Callbacks
@@ -220,7 +226,7 @@
var v = scenario.view,
frame;
if (stack.length === 0) {
- v.alert('Error:\n\nNo event #' + evn + ' found.');
+ v.alert('Oops!\n\nNo event #' + evn + ' found.');
return;
}
frame = stack.shift();
@@ -334,6 +340,7 @@
function logicError(msg) {
// TODO, report logic error to server, via websock, so it can be logged
network.view.alert('Logic Error:\n\n' + msg);
+ console.warn(msg);
}
var eventDispatch = {
@@ -345,11 +352,12 @@
updateHost: updateHost,
removeDevice: stillToImplement,
removeLink: removeLink,
- removeHost: stillToImplement,
+ removeHost: removeHost,
showPath: showPath
};
function addDevice(data) {
+ fnTrace('addDevice', data.payload.id);
var device = data.payload,
nodeData = createDeviceNode(device);
network.nodes.push(nodeData);
@@ -359,6 +367,7 @@
}
function addLink(data) {
+ fnTrace('addLink', data.payload.id);
var link = data.payload,
lnk = createLink(link);
if (lnk) {
@@ -370,6 +379,7 @@
}
function addHost(data) {
+ fnTrace('addHost', data.payload.id);
var host = data.payload,
node = createHostNode(host),
lnk;
@@ -379,6 +389,7 @@
lnk = createHostLink(host);
if (lnk) {
+ node.linkData = lnk; // cache ref on its host
network.links.push(lnk);
network.lookup[host.ingress] = lnk;
network.lookup[host.egress] = lnk;
@@ -387,7 +398,9 @@
network.force.start();
}
+ // TODO: fold updateX(...) methods into one base method; remove duplication
function updateDevice(data) {
+ fnTrace('updateDevice', data.payload.id);
var device = data.payload,
id = device.id,
nodeData = network.lookup[id];
@@ -400,6 +413,7 @@
}
function updateLink(data) {
+ fnTrace('updateLink', data.payload.id);
var link = data.payload,
id = link.id,
linkData = network.lookup[id];
@@ -412,6 +426,7 @@
}
function updateHost(data) {
+ fnTrace('updateHost', data.payload.id);
var host = data.payload,
id = host.id,
hostData = network.lookup[id];
@@ -423,7 +438,9 @@
}
}
+ // TODO: fold removeX(...) methods into base method - remove dup code
function removeLink(data) {
+ fnTrace('removeLink', data.payload.id);
var link = data.payload,
id = link.id,
linkData = network.lookup[id];
@@ -434,7 +451,20 @@
}
}
+ function removeHost(data) {
+ fnTrace('removeHost', data.payload.id);
+ var host = data.payload,
+ id = host.id,
+ hostData = network.lookup[id];
+ if (hostData) {
+ removeHostElement(hostData);
+ } else {
+ logicError('removeHost lookup fail. ID = "' + id + '"');
+ }
+ }
+
function showPath(data) {
+ fnTrace('showPath', data.payload.id);
var links = data.payload.links,
s = [ data.event + "\n" + links.length ];
links.forEach(function (d, i) {
@@ -589,19 +619,18 @@
//link .foo() .bar() ...
// operate on exiting links:
- // TODO: better transition (longer as a dashed, grey line)
link.exit()
.attr({
'stroke-dasharray': '3, 3'
})
.style('opacity', 0.4)
.transition()
- .duration(2000)
+ .duration(1500)
.attr({
'stroke-dasharray': '3, 12'
})
.transition()
- .duration(1000)
+ .duration(500)
.style('opacity', 0.0)
.remove();
}
@@ -855,17 +884,37 @@
//node .foo() .bar() ...
// operate on exiting nodes:
- // TODO: figure out how to remove the node 'g' AND its children
- node.exit()
+ // Note that the node is removed after 2 seconds.
+ // Sub element animations should be shorter than 2 seconds.
+ var exiting = node.exit()
.transition()
- .duration(750)
- .attr({
- opacity: 0,
- cx: 0,
- cy: 0,
- r: 0
- })
+ .duration(2000)
+ .style('opacity', 0)
.remove();
+
+ // host node exits....
+ exiting.filter('.host').each(function (d) {
+ var node = d3.select(this);
+
+ node.select('text')
+ .style('opacity', 0.5)
+ .transition()
+ .duration(1000)
+ .style('opacity', 0);
+ // note, leave <g>.remove to remove this element
+
+ node.select('circle')
+ .style('stroke-fill', '#555')
+ .style('fill', '#888')
+ .style('opacity', 0.5)
+ .transition()
+ .duration(1500)
+ .attr('r', 0);
+ // note, leave <g>.remove to remove this element
+
+ });
+
+ // TODO: device node exits
}
function find(id, array) {
@@ -882,12 +931,27 @@
delete network.lookup[linkData.id];
// remove from links array
var idx = find(linkData.id, network.links);
-
- network.links.splice(linkData.index, 1);
+ network.links.splice(idx, 1);
// remove from SVG
updateLinks();
+ network.force.resume();
}
+ function removeHostElement(hostData) {
+ // first, remove associated hostLink...
+ removeLinkElement(hostData.linkData);
+
+ // remove from lookup cache
+ delete network.lookup[hostData.id];
+ // remove from nodes array
+ var idx = find(hostData.id, network.nodes);
+ network.nodes.splice(idx, 1);
+ // remove from SVG
+ updateNodes();
+ network.force.resume();
+ }
+
+
function tick() {
node.attr({
transform: function (d) { return translate(d.x, d.y); }
@@ -1058,13 +1122,12 @@
d3.json(urlSc, function(err, data) {
var p = data && data.params || {},
desc = data && data.description || null,
- intro;
+ intro = data && data.title;
if (err) {
view.alert('No scenario found:\n\n' + urlSc + '\n\n' + err);
} else {
sc.params = p;
- intro = "Scenario loaded: " + ctx + '\n\n' + data.title;
if (desc) {
intro += '\n\n ' + desc.join('\n ');
}
@@ -1140,16 +1203,18 @@
d.fixed = true;
d3.select(self).classed('fixed', true);
if (config.useLiveData) {
- tellServerCoords(d);
+ sendUpdateMeta(d);
}
}
- function tellServerCoords(d) {
+ function sendUpdateMeta(d) {
sendMessage('updateMeta', {
id: d.id,
'class': d.class,
- x: Math.floor(d.x),
- y: Math.floor(d.y)
+ 'memento': {
+ x: Math.floor(d.x),
+ y: Math.floor(d.y)
+ }
});
}