Madan Jampani

Merge branch 'master' of ssh://gerrit.onlab.us:29418/onos-next

Showing 117 changed files with 1603 additions and 351 deletions
......@@ -8,5 +8,6 @@
.checkstyle
target
*.iml
*.pyc
dependency-reduced-pom.xml
.idea
......
......@@ -16,14 +16,24 @@
package org.onlab.onos.calendar;
import java.net.URI;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.intent.Intent;
import org.onlab.onos.net.intent.IntentEvent;
import org.onlab.onos.net.intent.IntentId;
import org.onlab.onos.net.intent.IntentListener;
import org.onlab.onos.net.intent.IntentService;
import org.onlab.onos.net.intent.IntentState;
import org.onlab.rest.BaseResource;
import javax.ws.rs.POST;
import javax.ws.rs.DELETE;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.Response;
import org.onlab.onos.core.ApplicationId;
import org.onlab.onos.core.CoreService;
import org.onlab.onos.net.flow.DefaultTrafficSelector;
......@@ -31,10 +41,15 @@ import org.onlab.onos.net.flow.TrafficSelector;
import org.onlab.onos.net.flow.TrafficTreatment;
import org.onlab.onos.net.intent.PointToPointIntent;
import org.onlab.packet.Ethernet;
import static org.onlab.onos.net.PortNumber.portNumber;
import static org.onlab.onos.net.flow.DefaultTrafficTreatment.builder;
import static org.onlab.onos.net.intent.IntentState.FAILED;
import static org.onlab.onos.net.intent.IntentState.INSTALLED;
import static org.onlab.onos.net.intent.IntentState.WITHDRAWN;
import static org.slf4j.LoggerFactory.getLogger;
import org.slf4j.Logger;
/**
......@@ -44,6 +59,7 @@ import org.slf4j.Logger;
public class BandwidthCalendarResource extends BaseResource {
private static final Logger log = getLogger(BandwidthCalendarResource.class);
private static final long TIMEOUT = 5; // seconds
@javax.ws.rs.Path("/{src}/{dst}/{srcPort}/{dstPort}/{bandwidth}")
@POST
......@@ -55,7 +71,7 @@ public class BandwidthCalendarResource extends BaseResource {
log.info("Receiving Create Intent request...");
log.info("Path Constraints: Src = {} SrcPort = {} Dest = {} DestPort = {} BW = {}",
src, srcPort, dst, dstPort, bandwidth);
src, srcPort, dst, dstPort, bandwidth);
IntentService service = get(IntentService.class);
......@@ -66,36 +82,50 @@ public class BandwidthCalendarResource extends BaseResource {
TrafficTreatment treatment = builder().build();
PointToPointIntent intentP2P =
new PointToPointIntent(appId(), selector, treatment,
srcPoint, dstPoint);
service.submit(intentP2P);
log.info("Submitted Calendar App intent: src = " + src + "dest = " + dst
+ "srcPort = " + srcPort + "destPort" + dstPort + "intentID = " + intentP2P.id().toString());
String reply = intentP2P.id().toString() + "\n";
new PointToPointIntent(appId(), selector, treatment,
srcPoint, dstPoint);
return Response.ok(reply).build();
CountDownLatch latch = new CountDownLatch(1);
InternalIntentListener listener = new InternalIntentListener(intentP2P, service, latch);
service.addListener(listener);
service.submit(intentP2P);
try {
if (latch.await(TIMEOUT, TimeUnit.SECONDS)) {
log.info("Submitted Calendar App intent: src = {}; dst = {}; " +
"srcPort = {}; dstPort = {}; intentID = {}",
src, dst, srcPort, dstPort, intentP2P.id());
String reply = intentP2P.id() + " " + listener.getState() + "\n";
return Response.ok(reply).build();
}
} catch (InterruptedException e) {
log.warn("Interrupted while waiting for intent {} status", intentP2P.id());
}
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
}
@javax.ws.rs.Path("/cancellation/{intentId}")
@DELETE
public Response withdrawIntent(@PathParam("intentId") String intentId) {
log.info("Receiving Teardown request...");
log.info("Withdraw intentId = {} ", intentId);
String reply = "ok\n";
return Response.ok(reply).build();
log.info("Receiving Teardown request for {}", intentId);
IntentService service = get(IntentService.class);
Intent intent = service.getIntent(IntentId.valueOf(Long.parseLong(intentId)));
if (intent != null) {
service.withdraw(intent);
String reply = "ok\n";
return Response.ok(reply).build();
}
return Response.status(Response.Status.NOT_FOUND).build();
}
@javax.ws.rs.Path("/modification/{intentId}/{bandwidth}")
@POST
public Response modifyBandwidth(@PathParam("intentId") String intentId,
@PathParam("bandwidth") String bandwidth) {
@PathParam("bandwidth") String bandwidth) {
log.info("Receiving Modify request...");
log.info("Modify bw for intentId = {} with new bandwidth = {}", intentId, bandwidth);
String reply = "ok\n";
String reply = "ok\n";
return Response.ok(reply).build();
}
......@@ -115,4 +145,34 @@ public class BandwidthCalendarResource extends BaseResource {
protected ApplicationId appId() {
return get(CoreService.class).registerApplication("org.onlab.onos.calendar");
}
// Auxiliary listener to wait until the given intent reaches the installed or failed states.
private final class InternalIntentListener implements IntentListener {
private final Intent intent;
private final IntentService service;
private final CountDownLatch latch;
private IntentState state;
private InternalIntentListener(Intent intent, IntentService service,
CountDownLatch latch) {
this.intent = intent;
this.service = service;
this.latch = latch;
}
@Override
public void event(IntentEvent event) {
if (event.subject().equals(intent)) {
state = service.getIntentState(intent.id());
if (state == INSTALLED || state == FAILED || state == WITHDRAWN) {
latch.countDown();
}
service.removeListener(this);
}
}
public IntentState getState() {
return state;
}
}
}
......
......@@ -50,7 +50,10 @@ public class NetworkConfigReader {
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 @@ public class NetworkConfigReader {
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 @@ public class NetworkConfigReader {
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 @@ public class NetworkConfigReader {
} 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(":", "");
}
......
{
"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"
}
]
}
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.onlab.onos</groupId>
<artifactId>onos-apps</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>onos-app-demo</artifactId>
<packaging>bundle</packaging>
<description>ONOS demo app bundle</description>
<properties>
<web.context>/onos/demo</web.context>
</properties>
<dependencies>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.compendium</artifactId>
</dependency>
<dependency>
<groupId>org.onlab.onos</groupId>
<artifactId>onlab-rest</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.onlab.onos</groupId>
<artifactId>onos-rest</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-servlet</artifactId>
</dependency>
<dependency>
<groupId>com.sun.jersey.jersey-test-framework</groupId>
<artifactId>jersey-test-framework-core</artifactId>
<version>1.18.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.sun.jersey.jersey-test-framework</groupId>
<artifactId>jersey-test-framework-grizzly2</artifactId>
<version>1.18.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<_wab>src/main/webapp/</_wab>
<Bundle-SymbolicName>
${project.groupId}.${project.artifactId}
</Bundle-SymbolicName>
<Import-Package>
org.slf4j,
org.osgi.framework,
javax.ws.rs,javax.ws.rs.core,
com.sun.jersey.api.core,
com.sun.jersey.spi.container.servlet,
com.sun.jersey.server.impl.container.servlet,
com.fasterxml.jackson.databind,
com.fasterxml.jackson.databind.node,
com.google.common.*,
org.onlab.packet.*,
org.onlab.rest.*,
org.onlab.onos.*
</Import-Package>
<Web-ContextPath>${web.context}</Web-ContextPath>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
</project>
package org.onlab.onos.demo;
/**
* Simple demo api interface.
*/
public interface DemoAPI {
enum InstallType { MESH, RANDOM };
/**
* Installs intents based on the installation type.
* @param type the installation type.
*/
void setup(InstallType type);
/**
* Uninstalls all existing intents.
*/
void tearDown();
}
/*
* 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.demo;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Service;
import org.onlab.onos.core.ApplicationId;
import org.onlab.onos.core.CoreService;
import org.onlab.onos.net.Host;
import org.onlab.onos.net.flow.DefaultTrafficSelector;
import org.onlab.onos.net.flow.DefaultTrafficTreatment;
import org.onlab.onos.net.flow.TrafficSelector;
import org.onlab.onos.net.flow.TrafficTreatment;
import org.onlab.onos.net.host.HostService;
import org.onlab.onos.net.intent.HostToHostIntent;
import org.onlab.onos.net.intent.Intent;
import org.onlab.onos.net.intent.IntentService;
import org.slf4j.Logger;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Application to set up demos.
*/
@Component(immediate = true)
@Service
public class DemoInstaller implements DemoAPI {
private final Logger log = getLogger(getClass());
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected CoreService coreService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected IntentService intentService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected HostService hostService;
private ExecutorService worker;
private ApplicationId appId;
private final Set<Intent> existingIntents = new HashSet<>();
@Activate
public void activate() {
appId = coreService.registerApplication("org.onlab.onos.demo.installer");
worker = Executors.newFixedThreadPool(1,
new ThreadFactoryBuilder()
.setNameFormat("demo-app-worker")
.build());
log.info("Started with Application ID {}", appId.id());
}
@Deactivate
public void deactivate() {
worker.shutdownNow();
log.info("Stopped");
}
@Override
public void setup(InstallType type) {
switch (type) {
case MESH:
log.debug("Installing mesh intents");
worker.execute(new MeshInstaller());
break;
case RANDOM:
throw new IllegalArgumentException("Not yet implemented.");
default:
throw new IllegalArgumentException("What is it you want exactly?");
}
}
@Override
public void tearDown() {
worker.submit(new UnInstaller());
}
private class MeshInstaller implements Runnable {
@Override
public void run() {
TrafficSelector selector = DefaultTrafficSelector.builder().build();
TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
List<Host> hosts = Lists.newArrayList(hostService.getHosts());
while (!hosts.isEmpty()) {
Host src = hosts.remove(0);
for (Host dst : hosts) {
HostToHostIntent intent = new HostToHostIntent(appId, src.id(), dst.id(),
selector, treatment,
null);
existingIntents.add(intent);
intentService.submit(intent);
}
}
}
}
private class UnInstaller implements Runnable {
@Override
public void run() {
for (Intent i : existingIntents) {
intentService.withdraw(i);
}
}
}
}
package org.onlab.onos.demo;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.onlab.rest.BaseResource;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.io.InputStream;
/**
* Rest API for demos.
*/
@Path("intents")
public class DemoResource extends BaseResource {
@POST
@Path("setup")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response setup(InputStream input) throws IOException {
ObjectMapper mapper = new ObjectMapper();
JsonNode cfg = mapper.readTree(input);
if (!cfg.has("type")) {
return Response.status(Response.Status.BAD_REQUEST)
.entity("Expected type field containing either mesh or random.").build();
}
DemoAPI.InstallType type = DemoAPI.InstallType.valueOf(
cfg.get("type").asText().toUpperCase());
DemoAPI demo = get(DemoAPI.class);
demo.setup(type);
return Response.ok(mapper.createObjectNode().toString()).build();
}
@GET
@Path("teardown")
@Produces(MediaType.APPLICATION_JSON)
public Response tearDown() throws IOException {
ObjectMapper mapper = new ObjectMapper();
DemoAPI demo = get(DemoAPI.class);
demo.tearDown();
return Response.ok(mapper.createObjectNode().toString()).build();
}
}
/*
* 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.
*/
/**
* Demo applications live here.
*/
package org.onlab.onos.demo;
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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.
-->
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="ONOS" version="2.5">
<display-name>ONOS DEMO APP API v1.0</display-name>
<servlet>
<servlet-name>JAX-RS Service</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.resourceConfigClass</param-name>
<param-value>com.sun.jersey.api.core.ClassNamesResourceConfig</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.config.property.classnames</param-name>
<param-value>
org.onlab.onos.demo.DemoResource
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>JAX-RS Service</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
\ No newline at end of file
......@@ -44,6 +44,7 @@
<module>optical</module>
<module>metrics</module>
<module>oecfg</module>
<module>demo</module>
</modules>
<properties>
......
......@@ -37,24 +37,31 @@ import com.fasterxml.jackson.databind.ObjectMapper;
*/
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 @@ public class SdnIpConfigReader implements SdnIpConfigService {
} 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);
}
......
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.
......
......@@ -27,6 +27,7 @@ import org.onlab.onos.net.intent.constraint.BandwidthConstraint;
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 @@ public abstract class ConnectivityIntentCommand extends AbstractShellCommand {
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 @@ public abstract class ConnectivityIntentCommand extends AbstractShellCommand {
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();
}
......
/*
* 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;
}
}
......@@ -80,6 +80,7 @@ public class DefaultFlowEntry extends DefaultFlowRule
this.state = FlowEntryState.FAILED;
this.errType = errType;
this.errCode = errCode;
this.lastSeen = System.currentTimeMillis();
}
@Override
......
......@@ -58,7 +58,7 @@ public class DefaultFlowRule implements FlowRule {
}
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 @@ public class DefaultFlowRule implements FlowRule {
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;
......
......@@ -63,7 +63,7 @@ public final class DefaultTrafficSelector implements TrafficSelector {
@Override
public int hashCode() {
return Objects.hash(criteria);
return criteria.hashCode();
}
@Override
......
......@@ -18,7 +18,7 @@ package org.onlab.onos.net.flow;
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 @@ public interface FlowRuleProvider extends Provider {
* @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);
}
......
......@@ -196,7 +196,7 @@ public final class Criteria {
@Override
public int hashCode() {
return Objects.hash(port, type());
return Objects.hash(type(), port);
}
@Override
......@@ -242,7 +242,7 @@ public final class Criteria {
@Override
public int hashCode() {
return Objects.hash(mac, type);
return Objects.hash(type, mac);
}
@Override
......@@ -288,7 +288,7 @@ public final class Criteria {
@Override
public int hashCode() {
return Objects.hash(ethType, type());
return Objects.hash(type(), ethType);
}
@Override
......@@ -336,7 +336,7 @@ public final class Criteria {
@Override
public int hashCode() {
return Objects.hash(ip, type);
return Objects.hash(type, ip);
}
@Override
......@@ -382,7 +382,7 @@ public final class Criteria {
@Override
public int hashCode() {
return Objects.hash(proto, type());
return Objects.hash(type(), proto);
}
@Override
......@@ -427,7 +427,7 @@ public final class Criteria {
@Override
public int hashCode() {
return Objects.hash(vlanPcp);
return Objects.hash(type(), vlanPcp);
}
@Override
......@@ -474,7 +474,7 @@ public final class Criteria {
@Override
public int hashCode() {
return Objects.hash(vlanId, type());
return Objects.hash(type(), vlanId);
}
@Override
......@@ -522,7 +522,7 @@ public final class Criteria {
@Override
public int hashCode() {
return Objects.hash(tcpPort, type);
return Objects.hash(type, tcpPort);
}
@Override
......@@ -568,7 +568,7 @@ public final class Criteria {
@Override
public int hashCode() {
return Objects.hash(lambda, type);
return Objects.hash(type, lambda);
}
@Override
......@@ -612,7 +612,7 @@ public final class Criteria {
@Override
public int hashCode() {
return Objects.hash(signalType, type);
return Objects.hash(type, signalType);
}
@Override
......
......@@ -190,7 +190,7 @@ public final class Instructions {
@Override
public int hashCode() {
return Objects.hash(port, type());
return Objects.hash(type(), port);
}
@Override
......
......@@ -70,7 +70,7 @@ public abstract class L0ModificationInstruction implements Instruction {
@Override
public int hashCode() {
return Objects.hash(lambda, type(), subtype);
return Objects.hash(type(), subtype, lambda);
}
@Override
......
......@@ -93,7 +93,7 @@ public abstract class L2ModificationInstruction implements Instruction {
@Override
public int hashCode() {
return Objects.hash(mac, type(), subtype);
return Objects.hash(type(), subtype, mac);
}
@Override
......@@ -142,7 +142,7 @@ public abstract class L2ModificationInstruction implements Instruction {
@Override
public int hashCode() {
return Objects.hash(vlanId, type(), subtype());
return Objects.hash(type(), subtype(), vlanId);
}
@Override
......@@ -191,7 +191,7 @@ public abstract class L2ModificationInstruction implements Instruction {
@Override
public int hashCode() {
return Objects.hash(vlanPcp, type(), subtype());
return Objects.hash(type(), subtype(), vlanPcp);
}
@Override
......
......@@ -85,7 +85,7 @@ public abstract class L3ModificationInstruction implements Instruction {
@Override
public int hashCode() {
return Objects.hash(ip, type(), subtype());
return Objects.hash(type(), subtype(), ip);
}
@Override
......
......@@ -23,6 +23,7 @@ import org.onlab.onos.net.flow.TrafficSelector;
import org.onlab.onos.net.flow.TrafficTreatment;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
......@@ -61,7 +62,7 @@ public abstract class ConnectivityIntent extends Intent {
Collection<NetworkResource> resources,
TrafficSelector selector,
TrafficTreatment treatment) {
this(id, appId, resources, selector, treatment, null);
this(id, appId, resources, selector, treatment, Collections.emptyList());
}
/**
......@@ -87,7 +88,7 @@ public abstract class ConnectivityIntent extends Intent {
super(id, appId, resources);
this.selector = checkNotNull(selector);
this.treatment = checkNotNull(treatment);
this.constraints = constraints;
this.constraints = checkNotNull(constraints);
}
/**
......@@ -97,7 +98,7 @@ public abstract class ConnectivityIntent extends Intent {
super();
this.selector = null;
this.treatment = null;
this.constraints = null;
this.constraints = Collections.emptyList();
}
/**
......
......@@ -21,6 +21,7 @@ import org.onlab.onos.net.HostId;
import org.onlab.onos.net.flow.TrafficSelector;
import org.onlab.onos.net.flow.TrafficTreatment;
import java.util.Collections;
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
......@@ -46,7 +47,7 @@ public final class HostToHostIntent extends ConnectivityIntent {
public HostToHostIntent(ApplicationId appId, HostId one, HostId two,
TrafficSelector selector,
TrafficTreatment treatment) {
this(appId, one, two, selector, treatment, null);
this(appId, one, two, selector, treatment, Collections.emptyList());
}
/**
......
......@@ -22,6 +22,7 @@ import org.onlab.onos.net.Link;
import org.onlab.onos.net.flow.TrafficSelector;
import org.onlab.onos.net.flow.TrafficTreatment;
import java.util.Collections;
import java.util.List;
import java.util.Set;
......@@ -51,7 +52,7 @@ public final class LinkCollectionIntent extends ConnectivityIntent {
TrafficTreatment treatment,
Set<Link> links,
ConnectPoint egressPoint) {
this(appId, selector , treatment, links, egressPoint, null);
this(appId, selector , treatment, links, egressPoint, Collections.emptyList());
}
/**
......
......@@ -22,6 +22,7 @@ import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.flow.TrafficSelector;
import org.onlab.onos.net.flow.TrafficTreatment;
import java.util.Collections;
import java.util.List;
import java.util.Set;
......@@ -55,14 +56,7 @@ public final class MultiPointToSinglePointIntent extends ConnectivityIntent {
TrafficTreatment treatment,
Set<ConnectPoint> ingressPoints,
ConnectPoint egressPoint) {
super(id(MultiPointToSinglePointIntent.class, selector, treatment,
ingressPoints, egressPoint), appId, null, selector, treatment);
checkNotNull(ingressPoints);
checkArgument(!ingressPoints.isEmpty(), "Ingress point set cannot be empty");
this.ingressPoints = Sets.newHashSet(ingressPoints);
this.egressPoint = checkNotNull(egressPoint);
this(appId, selector, treatment, ingressPoints, egressPoint, Collections.emptyList());
}
/**
......
......@@ -15,6 +15,7 @@
*/
package org.onlab.onos.net.intent;
import java.util.Collections;
import java.util.List;
import com.google.common.base.MoreObjects;
......@@ -42,9 +43,7 @@ public class PathIntent extends ConnectivityIntent {
*/
public PathIntent(ApplicationId appId, TrafficSelector selector,
TrafficTreatment treatment, Path path) {
super(id(PathIntent.class, selector, treatment, path), appId,
resources(path.links()), selector, treatment);
this.path = path;
this(appId, selector, treatment, path, Collections.emptyList());
}
/**
......
......@@ -21,6 +21,8 @@ import org.onlab.onos.net.resource.LinkResourceService;
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 @@ public class AnnotationConstraint extends BooleanConstraint {
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 @@ public class AnnotationConstraint extends BooleanConstraint {
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)) {
......
......@@ -25,14 +25,14 @@ import java.time.Duration;
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 @@ public class LatencyConstraint implements Constraint {
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
......
......@@ -21,6 +21,7 @@ import org.onlab.onos.net.DeviceId;
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 @@ public class ObstacleConstraint extends BooleanConstraint {
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();
......
......@@ -17,12 +17,13 @@ package org.onlab.onos.net.intent.constraint;
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 @@ import static com.google.common.base.Preconditions.checkNotNull;
*/
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 @@ public class WaypointConstraint implements Constraint {
@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)) {
......
......@@ -37,6 +37,7 @@ import static org.easymock.EasyMock.createMock;
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 @@ public class LatencyConstraintTest {
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 class LatencyConstraintTest {
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);
......
......@@ -15,21 +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;
......@@ -64,14 +55,22 @@ import org.onlab.onos.net.provider.AbstractProviderRegistry;
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.HashSet;
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 &amp; SB APIs.
......@@ -92,8 +91,7 @@ public class FlowRuleManager
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 +104,7 @@ public class FlowRuleManager
@Activate
public void activate() {
futureService = Executors.newCachedThreadPool(namedThreads("provider-future-listeners"));
store.setDelegate(delegate);
eventDispatcher.addSink(FlowRuleEvent.class, listenerRegistry);
log.info("Started");
......@@ -113,7 +112,7 @@ public class FlowRuleManager
@Deactivate
public void deactivate() {
futureListeners.shutdownNow();
futureService.shutdownNow();
store.unsetDelegate(delegate);
eventDispatcher.removeSink(FlowRuleEvent.class);
......@@ -364,6 +363,9 @@ public class FlowRuleManager
// 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 +386,28 @@ public class FlowRuleManager
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;
try {
res = result.get(TIMEOUT, TimeUnit.MILLISECONDS);
store.batchOperationComplete(FlowRuleBatchEvent.completed(request, res));
} catch (TimeoutException | InterruptedException | ExecutionException e) {
log.warn("Something went wrong with the batch operation {}",
request.batchId(), e);
Set<FlowRule> failures = new HashSet<>(batchOperation.size());
for (FlowRuleBatchEntry op : batchOperation.getOperations()) {
failures.add(op.getTarget());
}
res = new CompletedBatchOperation(false, failures);
store.batchOperationComplete(FlowRuleBatchEvent.completed(request, res));
}
}
}, futureListeners);
});
break;
case BATCH_OPERATION_COMPLETED:
......
......@@ -15,6 +15,8 @@
*/
package org.onlab.onos.net.intent.impl;
import com.google.common.base.Predicate;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
......@@ -94,11 +96,19 @@ public abstract class ConnectivityIntentCompiler<T extends ConnectivityIntent>
protected Path getPath(ConnectivityIntent intent,
ElementId one, ElementId two) {
Set<Path> paths = pathService.getPaths(one, two, weight(intent.constraints()));
if (paths.isEmpty()) {
throw new PathNotFoundException("No packet path from " + one + " to " + two);
final List<Constraint> constraints = intent.constraints();
ImmutableList<Path> filtered = FluentIterable.from(paths)
.filter(new Predicate<Path>() {
@Override
public boolean apply(Path path) {
return checkPath(path, constraints);
}
}).toList();
if (filtered.isEmpty()) {
throw new PathNotFoundException("No packet path form " + one + " to " + two);
}
// TODO: let's be more intelligent about this eventually
return paths.iterator().next();
return filtered.iterator().next();
}
/**
......
/*
* 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)));
}
}
/*
* 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));
}
}
......@@ -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.DeviceId;
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 @@ public class IntentTestsMocks {
}
}
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;
}
}
}
......
......@@ -85,6 +85,8 @@ import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.cache.RemovalListener;
import com.google.common.cache.RemovalNotification;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
......@@ -132,8 +134,7 @@ public class DistributedFlowRuleStore
private Cache<Integer, SettableFuture<CompletedBatchOperation>> pendingFutures =
CacheBuilder.newBuilder()
.expireAfterWrite(pendingFutureTimeoutMinutes, TimeUnit.MINUTES)
// TODO Explicitly fail the future if expired?
//.removalListener(listener)
.removalListener(new TimeoutFuture())
.build();
// Cache of SMaps used for backup data. each SMap contain device flow table
......@@ -541,6 +542,17 @@ public class DistributedFlowRuleStore
log.debug("removedFromPrimary {}", removed);
}
private static final class TimeoutFuture
implements RemovalListener<Integer, SettableFuture<CompletedBatchOperation>> {
@Override
public void onRemoval(RemovalNotification<Integer, SettableFuture<CompletedBatchOperation>> notification) {
// wrapping in ExecutionException to support Future.get
notification.getValue()
.setException(new ExecutionException("Timed out",
new TimeoutException()));
}
}
private final class OnStoreBatch implements ClusterMessageHandler {
private final NodeId local;
......@@ -580,7 +592,18 @@ public class DistributedFlowRuleStore
@Override
public void run() {
CompletedBatchOperation result = Futures.getUnchecked(f);
CompletedBatchOperation result;
try {
result = f.get();
} catch (InterruptedException | ExecutionException e) {
log.error("Batch operation failed", e);
// create everything failed response
Set<FlowRule> failures = new HashSet<>(operation.size());
for (FlowRuleBatchEntry op : operation.getOperations()) {
failures.add(op.getTarget());
}
result = new CompletedBatchOperation(false, failures);
}
try {
message.respond(SERIALIZER.encode(result));
} catch (IOException e) {
......
......@@ -72,7 +72,7 @@ public class DatabaseManager implements DatabaseService, DatabaseAdminService {
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";
......
......@@ -75,10 +75,14 @@ import org.onlab.onos.net.intent.OpticalConnectivityIntent;
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 @@ public final class KryoNamespaces {
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())
......
......@@ -18,6 +18,8 @@ package org.onlab.onos.store.trivial.impl;
import com.google.common.base.Function;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.RemovalListener;
import com.google.common.cache.RemovalNotification;
import com.google.common.collect.FluentIterable;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.SettableFuture;
......@@ -53,8 +55,10 @@ import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
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.AtomicInteger;
import static org.apache.commons.lang3.concurrent.ConcurrentUtils.createIfAbsentUnchecked;
......@@ -86,8 +90,7 @@ public class SimpleFlowRuleStore
private Cache<Integer, SettableFuture<CompletedBatchOperation>> pendingFutures =
CacheBuilder.newBuilder()
.expireAfterWrite(pendingFutureTimeoutMinutes, TimeUnit.MINUTES)
// TODO Explicitly fail the future if expired?
//.removalListener(listener)
.removalListener(new TimeoutFuture())
.build();
@Activate
......@@ -303,4 +306,15 @@ public class SimpleFlowRuleStore
}
notifyDelegate(event);
}
private static final class TimeoutFuture
implements RemovalListener<Integer, SettableFuture<CompletedBatchOperation>> {
@Override
public void onRemoval(RemovalNotification<Integer, SettableFuture<CompletedBatchOperation>> notification) {
// wrapping in ExecutionException to support Future.get
notification.getValue()
.setException(new ExecutionException("Timed out",
new TimeoutException()));
}
}
}
......
......@@ -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>
......@@ -225,4 +227,12 @@
<bundle>mvn:org.onlab.onos/onos-app-metrics-topology/1.0.0-SNAPSHOT</bundle>
</feature>
<feature name="onos-app-demo" version="1.0.0"
description="ONOS demo applications">
<feature>onos-api</feature>
<bundle>mvn:org.onlab.onos/onos-app-demo/1.0.0-SNAPSHOT</bundle>
</feature>
</features>
......
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.
......
......@@ -10,4 +10,5 @@
[ "$1" = "-w" ] && shift && onos-wait-for-start $1
[ -n "$1" ] && OCI=$(find_node $1) && shift
unset KARAF_HOME
client -h $OCI -u karaf "$@" 2>/dev/null
......
......@@ -3,10 +3,7 @@
# Launches ONOS GUI on the specified node.
# -----------------------------------------------------------------------------
[ ! -d "$ONOS_ROOT" ] && echo "ONOS_ROOT is not defined" >&2 && exit 1
. $ONOS_ROOT/tools/build/envDefaults
host=${1:-$OCI}
host=${host:-localhost}
open http://$host:8181/onos/tvue
open http://$host:8181/onos/ui
......
......@@ -40,6 +40,7 @@ fi
# 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}"
......
......@@ -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
}
......
......@@ -43,9 +43,9 @@ public class ImmutableClassChecker {
* @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 @@ public class ImmutableClassChecker {
}
/**
* 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 @@ public class ImmutableClassChecker {
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);
}
}
}
......
......@@ -24,6 +24,7 @@ import org.onlab.onos.cluster.ClusterService;
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.link.LinkService;
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 @@ import static org.onlab.onos.net.link.LinkEvent.Type.LINK_REMOVED;
*/
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 @@ public abstract class TopologyMessages {
.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 @@ public abstract class TopologyMessages {
// 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 @@ public abstract class TopologyMessages {
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 @@ public abstract class TopologyMessages {
.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 @@ public abstract class TopologyMessages {
}
// 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 @@ public abstract class TopologyMessages {
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,10 +292,28 @@ public abstract class TopologyMessages {
}
}
// 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);
metaUi.put(string(payload, "id"), payload);
metaUi.put(string(payload, "id"), (ObjectNode) payload.path("memento"));
}
// Returns device details response.
......@@ -289,7 +321,6 @@ public abstract class TopologyMessages {
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 @@ public abstract class TopologyMessages {
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.
......@@ -319,16 +350,15 @@ public abstract class TopologyMessages {
new Prop("Longitude", annot.value("longitude"))));
}
// 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;
}
......
......@@ -110,8 +110,8 @@ public class TopologyWebSocket
try {
ObjectNode event = (ObjectNode) mapper.reader().readTree(data);
String type = string(event, "event", "unknown");
if (type.equals("showDetails")) {
showDetails(event);
if (type.equals("requestDetails")) {
requestDetails(event);
} else if (type.equals("updateMeta")) {
updateMetaUi(event);
} else if (type.equals("requestPath")) {
......@@ -122,7 +122,7 @@ public class TopologyWebSocket
cancelTraffic(event);
}
} catch (Exception e) {
System.out.println("WTF?! " + data);
log.warn("Unable to parse GUI request {} due to {}", data, e);
e.printStackTrace();
}
}
......@@ -165,9 +165,9 @@ public class TopologyWebSocket
}
// Sends back device or host details.
private void showDetails(ObjectNode event) {
private void requestDetails(ObjectNode event) {
ObjectNode payload = payload(event);
String type = string(payload, "type", "unknown");
String type = string(payload, "class", "unknown");
if (type.equals("device")) {
sendMessage(deviceDetails(deviceId(string(payload, "id")),
number(event, "sid")));
......@@ -282,7 +282,8 @@ public class TopologyWebSocket
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));
}
}
......
......@@ -21,7 +21,7 @@
<display-name>ONOS GUI</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index2.html</welcome-file>
</welcome-file-list>
<servlet>
......
/*
* 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.
*/
/*
ONOS GUI -- Floating Panels -- CSS file
@author Simon Hunt
*/
.fpanel {
position: absolute;
z-index: 100;
display: block;
top: 10%;
width: 280px;
right: -300px;
opacity: 0;
background-color: rgba(255,255,255,0.8);
padding: 10px;
color: black;
font-size: 10pt;
box-shadow: 2px 2px 16px #777;
}
/* TODO: light/dark themes */
.light .fpanel {
}
.dark .fpanel {
}
......@@ -40,6 +40,7 @@
<link rel="stylesheet" href="base.css">
<link rel="stylesheet" href="onos2.css">
<link rel="stylesheet" href="mast2.css">
<link rel="stylesheet" href="floatPanel.css">
<!-- This is where contributed stylesheets get INJECTED -->
<!-- TODO: replace with template marker and inject refs server-side -->
......@@ -62,8 +63,9 @@
<div id="view">
<!-- NOTE: views injected here by onos.js -->
</div>
<div id="overlays">
<!-- NOTE: overlays injected here, as needed -->
<div id="floatPanels">
<!-- NOTE: floating panels injected here, as needed -->
<!-- see onos.ui.addFloatingPanel -->
</div>
<div id="alerts">
<!-- NOTE: alert content injected here, as needed -->
......
......@@ -10,6 +10,10 @@
"",
null
],
"props": {}
"props": {
"latitude": 123.5,
"longitude": 67.8,
"anotherProp": "foobar"
}
}
}
......
{
"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..."
}
}
}
{
"event": "showDetails",
"sid": 9,
"payload": {
"id": "CA:4B:EE:A4:B0:33/-1",
"type": "host",
"propOrder": [
"MAC",
"IP",
"-",
"Latitude",
"Longitude"
],
"props": {
"MAC": "CA:4B:EE:A4:B0:33",
"IP": "[10.0.0.1]",
"-": "",
"Latitude": null,
"Longitude": null
}
}
}
{
"event": "showDetails",
"sid": 37,
"payload": {
"id": "of:000000000000000a",
"type": "switch",
"propOrder": [
"Name",
"Vendor",
"H/W Version",
"S/W Version",
"Serial Number",
"-",
"Latitude",
"Longitude",
"Ports",
"-",
"Master"
],
"props": {
"Name": null,
"Vendor": "Nicira, Inc.",
"H/W Version": "Open vSwitch",
"S/W Version": "2.0.1",
"Serial Number": "None",
"-": "",
"Latitude": null,
"Longitude": null,
"Ports": "5",
"Master":"local"
}
}
}
{
"event": "noop",
"event": "requestDetails",
"sid": 15,
"payload": {
"id": "xyyzy"
"id": "of:0000000000000003",
"class": "device"
}
}
......
{
"event": "requestDetails",
"sid": 9,
"payload": {
"id": "CA:4B:EE:A4:B0:33/-1",
"class": "host"
}
}
......@@ -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..."
}
}
}
......
......@@ -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
......
{
"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": {}
}
}
......@@ -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",
......
......@@ -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
}
......
......@@ -3,7 +3,7 @@
"payload": {
"id": "of:0000ffffffffff04",
"type": "roadm",
"online": false,
"online": true,
"labels": [
"0000ffffffffff04",
"FF:FF:FF:FF:FF:04",
......
......@@ -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
}
}
}
......
......@@ -3,7 +3,7 @@
"payload": {
"id": "of:0000ffffffff0001",
"type": "switch",
"online": false,
"online": true,
"labels": [
"0000ffffffff0001",
"FF:FF:FF:FF:00:01",
......
......@@ -3,7 +3,7 @@
"payload": {
"id": "of:0000ffffffffff01",
"type": "roadm",
"online": false,
"online": true,
"labels": [
"0000ffffffffff01",
"FF:FF:FF:FF:FF:01",
......
......@@ -3,7 +3,7 @@
"payload": {
"id": "of:0000ffffffff0004",
"type": "switch",
"online": false,
"online": true,
"labels": [
"0000ffffffff0004",
"FF:FF:FF:FF:00:04",
......
......@@ -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
}
}
}
......
......@@ -3,7 +3,7 @@
"payload": {
"id": "of:0000ffffffffff09",
"type": "roadm",
"online": false,
"online": true,
"labels": [
"0000ffffffffff09",
"FF:FF:FF:FF:FF:09",
......
{
"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"
}
......
{
"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"
}
......
{
"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"
}
......
......@@ -3,7 +3,7 @@
"payload": {
"id": "of:0000ffffffffff08",
"type": "roadm",
"online": false,
"online": true,
"labels": [
"0000ffffffffff08",
"FF:FF:FF:FF:FF:08",
......
{
"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"
}
......
{
"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"
}
......
{
"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"
}
......
{
"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"
}
......
{
"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"
}
......
{
"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"
}
}
}
......
{
"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"
}
......
{
"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"
}
......
{
"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"
}
......
{
"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"
}
......
......@@ -3,7 +3,7 @@
"payload": {
"id": "of:0000ffffffffff03",
"type": "roadm",
"online": false,
"online": true,
"labels": [
"0000ffffffffff03",
"FF:FF:FF:FF:FF:03",
......
{
"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"
}
......
{
"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"
}
......
{
"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"
}
......
{
"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
}
}
}
......
{
"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"
}
......
{
"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"
}
}
}
......
{
"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"
}
}
}
{
"event": "updateDevice",
"payload": {
"id": "of:0000ffffffffff08",
"type": "roadm",
"online": false,
"labels": [
"0000ffffffffff08",
"FF:FF:FF:FF:FF:08",
"?"
],
"metaUi": {
"x": 539,
"y": 186
}
}
}
{
"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"
}
}
}
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.