Merge branch 'master' of https://github.com/OPENNETWORKINGLAB/ONOS
Conflicts:
test-network/mininet/dev_network_edge_2.py
diff --git a/README.md b/README.md
index 495a2ed..b71b9aa 100644
--- a/README.md
+++ b/README.md
@@ -1,92 +1,118 @@
-ONOS
-====
+ONOS (Open Networking Operating System)
+=======================================
-Open Networking Operating System
+ONOS (Open Networking Operating System) is an experimental distributed
+SDN OS. Currently, it is under active development. ONOS was announced
+and demonstrated at ONS'13.
-BELOW TO BE WRITTEN IN DETAIL
+Steps to download and setup a development Virtual Machine
+==========================================
+http://wiki.onlab.us/display/Eng/ONOS+Development+VM
Building ONOS
-------------
-0. Install custom jars and dependencies (Only need to be run only once)
+0. Install custom jars and dependencies (needs to be run only once)
$ ./setup-local-maven.sh
-1. Cleanly Build ONOS
+1. Cleanly build ONOS
$ mvn clean
$ mvn compile
- NOTE: installing maven for the first time may switch java version from 1.7 to 1.6 causing cassandra to not run
+ NOTE: installing maven for the first time may switch java version
+ from 1.7 to 1.6. This might prevent Cassandra to run.
Dependencies
------------
1. Zookeeper
- Download and install apache-zookeeper-3.4.5: http://zookeeper.apache.org/releases.html
+ Download and install apache-zookeeper-3.4.5:
+ http://zookeeper.apache.org/releases.html
+
+ Edit file (ONOS-INSTALL-DIR)/start-zk.sh and set variable "ZK_DIR"
+ to point to the Zookeeper directory.
+
2. Cassandra
- Download and install apache-cassandra-1.2.2: http://cassandra.apache.org/download/
+ Download and install apache-cassandra-1.2.4:
+ http://cassandra.apache.org/download/
-Running ONOS
-------------
+ Edit file (ONOS-INSTALL-DIR)/start-cassandra.sh and set variable
+ "CASSANDRA_DIR" to point to the Cassandra directory.
-1. Start zookeeper
+Running ONOS with Cassandra as a separate process
+-------------------------------------------------
+[See below for information how to run ONOS with Embedded Cassandra]
+
+1. Start Zookeeper
$ cd (ONOS-INSTALL-DIR)/
+ $ ./start-zk.sh start
- $ ./start-zk.sh
+ ## Confirm Zookeeper is running:
+ $ ./start.zk.sh status
-2. Start cassandra
+2. Start Cassandra
$ cd (ONOS-INSTALL-DIR)/
-
$ ./start-cassandra.sh start
- 1. Confirm cassandra is running
-
- $ ./start-cassandra.sh status
+ ## Confirm Cassandra is running:
+ $ ./start-cassandra.sh status
-3. Start ONOS instance
+3. Start ONOS
$ cd (ONOS-INSTALL-DIR)/
-
$ ./start-onos.sh start
-
-4. Start ONOS rest apis
+ ## Confirm ONOS is running:
+ $ ./start-onos.sh status
+
+4. Start ONOS REST API server
+
+ $ cd (ONOS-INSTALL-DIR)/
$ ./start-rest.sh start
+ ## Confirm the REST API server is running:
+ $ ./start-rest.sh status
+
Running ONOS with Cassandra embedded (Optional)
-----------------------------------------------
1. Start Zookeeper
$ cd (ONOS-INSTALL-DIR)/
+ $ ./start-zk.sh start
- $ ./zkServer.sh start
+ ## Confirm Zookeeper is running:
+ $ ./start.zk.sh status
2. Start ONOS and Cassandra embedded
$ cd (ONOS-INSTALL_DIR)/
-
$ ./start-onos-embedded.sh start
-
-3. Start ONOS rest apis
+ ## Confirm ONOS is running:
+ $ ./start-onos-embedded.sh status
+
+3. Start ONOS REST API server
+
+ $ cd (ONOS-INSTALL-DIR)/
$ ./start-rest.sh start
+ ## Confirm the REST API server is running:
+ $ ./start-rest.sh status
+
Running in offline mode (Optional)
----------------------------------
-Maven is used to build and run ONOS.
-By default, maven tries to reach the repositories.
-To suppress this behavior '-o' option should be given to `mvn` command.
-
-To give additional option to `mvn` commands used in ONOS,
-use the MVN environment variable.
+Maven is used to build and run ONOS. By default, maven tries to reach
+the repositories. The '-o' option can be given to the 'mvn' command to
+suppress this behavior. The MVN environmental variable can be used to
+set additional options to the 'mvn' command used in ONOS.
* Example: Running in offline mode
$ env MVN="mvn -o" ./start-onos.sh start
-
diff --git a/conf/cassandra-repair.sh b/conf/cassandra-repair.sh
new file mode 100755
index 0000000..2c2638e
--- /dev/null
+++ b/conf/cassandra-repair.sh
@@ -0,0 +1 @@
+<cassandra_dir>/bin/nodetool repair
diff --git a/conf/logback-deployment.xml b/conf/logback-deployment.xml
new file mode 100644
index 0000000..3877f65
--- /dev/null
+++ b/conf/logback-deployment.xml
@@ -0,0 +1,37 @@
+<configuration scan="true" debug="true">
+ <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder>
+ <pattern>%level [%logger:%thread] %msg%n</pattern>
+ </encoder>
+ </appender>
+
+ <appender name="FILE" class="ch.qos.logback.core.FileAppender">
+ <file>./onos-logs/onos.ubuntu.log</file>
+ <encoder>
+ <pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
+ </encoder>
+ </appender>
+
+ <appender name="ROLLINGFILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>./onos-logs/onos.ubuntu.log</file>
+ <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+ <!-- Roll over to a new log file every day -->
+ <fileNamePattern>./onos-logs/onos.ubuntu.%d{yyyy-MM-dd}.log</fileNamePattern>
+ <!-- Keep 10 days worth of logs -->
+ <maxHistory>10</maxHistory>
+ </rollingPolicy>
+
+ <encoder>
+ <pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
+ </encoder>
+
+ </appender>
+
+ <logger name="org" level="WARN"/>
+ <logger name="LogService" level="WARN"/> <!-- Restlet access logging -->
+ <logger name="net.floodlightcontroller.logging" level="WARN"/>
+
+ <root level="DEBUG">
+ <appender-ref ref="ROLLINGFILE" />
+ </root>
+</configuration>
diff --git a/conf/onos-embedded.properties b/conf/onos-embedded.properties
index 83e5ad3..ed85223 100644
--- a/conf/onos-embedded.properties
+++ b/conf/onos-embedded.properties
@@ -1,12 +1,12 @@
floodlight.modules = net.floodlightcontroller.storage.memory.MemoryStorageSource,\
net.floodlightcontroller.core.FloodlightProvider,\
net.floodlightcontroller.threadpool.ThreadPool,\
+net.onrc.onos.ofcontroller.floodlightlistener.NetworkGraphPublisher, \
net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl,\
net.floodlightcontroller.staticflowentry.StaticFlowEntryPusher,\
net.floodlightcontroller.counter.CounterStore,\
net.floodlightcontroller.perfmon.PktInProcessingTime,\
net.floodlightcontroller.ui.web.StaticWebRoutable,\
-net.onrc.onos.ofcontroller.floodlightlistener.NetworkGraphPublisher, \
net.onrc.onos.registry.controller.ZookeeperRegistry
net.floodlightcontroller.restserver.RestApiServer.port = 8080
net.floodlightcontroller.core.FloodlightProvider.openflowport = 6633
diff --git a/conf/onos.properties b/conf/onos.properties
index c1e2d27..283203a 100644
--- a/conf/onos.properties
+++ b/conf/onos.properties
@@ -1,12 +1,12 @@
floodlight.modules = net.floodlightcontroller.storage.memory.MemoryStorageSource,\
net.floodlightcontroller.core.FloodlightProvider,\
net.floodlightcontroller.threadpool.ThreadPool,\
+net.onrc.onos.ofcontroller.floodlightlistener.NetworkGraphPublisher, \
net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl,\
net.floodlightcontroller.staticflowentry.StaticFlowEntryPusher,\
net.floodlightcontroller.counter.CounterStore,\
net.floodlightcontroller.perfmon.PktInProcessingTime,\
net.floodlightcontroller.ui.web.StaticWebRoutable,\
-net.onrc.onos.ofcontroller.floodlightlistener.NetworkGraphPublisher, \
net.onrc.onos.registry.controller.ZookeeperRegistry
net.floodlightcontroller.restserver.RestApiServer.port = 8080
net.floodlightcontroller.core.FloodlightProvider.openflowport = 6633
diff --git a/lib/jamm-0.2.5.jar b/lib/jamm-0.2.5.jar
new file mode 100644
index 0000000..e9baf75
--- /dev/null
+++ b/lib/jamm-0.2.5.jar
Binary files differ
diff --git a/pom.xml b/pom.xml
index 52fe30a..943133d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -34,6 +34,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<powermock.version>1.5</powermock.version>
<restlet.version>2.1-RC1</restlet.version>
+ <github.global.server>github</github.global.server>
</properties>
<build>
<plugins>
@@ -121,6 +122,49 @@
<locale>en</locale>
</configuration>
</plugin>
+ <plugin>
+ <groupId>org.jacoco</groupId>
+ <artifactId>jacoco-maven-plugin</artifactId>
+ <version>0.6.3.201306030806</version>
+ <configuration>
+ <destfile>${basedir}/target/jacoco/jacoco.exec</destfile>
+ <datafile>${basedir}/target/jacoco/jacoco.exec</datafile>
+ </configuration>
+ <executions>
+ <execution>
+ <id>jacoco-initialize</id>
+ <goals>
+ <goal>prepare-agent</goal>
+ </goals>
+ </execution>
+ <execution>
+ <id>jacoco-site</id>
+ <phase>package</phase>
+ <goals>
+ <goal>report</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>com.github.github</groupId>
+ <artifactId>site-maven-plugin</artifactId>
+ <version>0.8</version>
+ <configuration>
+ <message>Creating site for ${project.version}</message>
+ <dryRun>true</dryRun>
+ <repositoryName>ONOS</repositoryName>
+ <repositoryOwner>OPENNETWORKINGLAB</repositoryOwner>
+ </configuration>
+ <executions>
+ <execution>
+ <goals>
+ <goal>site</goal>
+ </goals>
+ <phase>site</phase>
+ </execution>
+ </executions>
+ </plugin>
</plugins>
</build>
<!-- for getting visualization reporting -->
@@ -128,11 +172,13 @@
<excludeDefaults>true</excludeDefaults>
<outputDirectory>${project.build.directory}/site</outputDirectory>
<plugins>
+ <!--
<plugin>
<groupId>org.apache.camel</groupId>
<artifactId>guice-maven-plugin</artifactId>
<version>2.11.0</version>
</plugin>
+ -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId>
@@ -145,6 +191,7 @@
<reportSet>
<reports>
<report>dependencies</report>
+ <!--report>maven-emma-plugin</report-->
<report>scm</report>
</reports>
</reportSet>
@@ -211,12 +258,12 @@
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
- <version>1.9.11</version>
+ <version>1.9.13</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
- <version>1.9.11</version>
+ <version>1.9.13</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
@@ -258,9 +305,9 @@
<version>4.1.21</version>
</dependency>
<dependency>
- <groupId>org.jboss.netty</groupId>
- <artifactId>netty</artifactId>
- <version>3.2.6.Final</version>
+ <groupId>io.netty</groupId>
+ <artifactId>netty-all</artifactId>
+ <version>4.0.8.Final</version>
</dependency>
<dependency>
<groupId>args4j</groupId>
diff --git a/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java b/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java
index 1e3ec6f..22ff029 100644
--- a/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java
+++ b/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java
@@ -206,5 +206,11 @@
* switch over to ACTIVE role
*/
public void setAlwaysClearFlowsOnSwAdd(boolean value);
+
+ /**
+ * Publish updates to Controller updates queue
+ * @param IUpdate
+ */
+ public void publishUpdate(IUpdate update);
}
diff --git a/src/main/java/net/floodlightcontroller/core/IUpdate.java b/src/main/java/net/floodlightcontroller/core/IUpdate.java
new file mode 100644
index 0000000..950bc0f
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/IUpdate.java
@@ -0,0 +1,10 @@
+package net.floodlightcontroller.core;
+
+public interface IUpdate {
+
+ /**
+ * Calls the appropriate listeners
+ */
+ public void dispatch();
+
+}
diff --git a/src/main/java/net/floodlightcontroller/core/internal/Controller.java b/src/main/java/net/floodlightcontroller/core/internal/Controller.java
index ac29983..21eceb3 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/Controller.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/Controller.java
@@ -58,6 +58,7 @@
import net.floodlightcontroller.core.IOFSwitch;
import net.floodlightcontroller.core.IOFSwitchFilter;
import net.floodlightcontroller.core.IOFSwitchListener;
+import net.floodlightcontroller.core.IUpdate;
import net.floodlightcontroller.core.annotations.LogMessageDoc;
import net.floodlightcontroller.core.annotations.LogMessageDocs;
import net.floodlightcontroller.core.internal.OFChannelState.HandshakeState;
@@ -253,17 +254,8 @@
// Perf. related configuration
protected static final int SEND_BUFFER_SIZE = 4 * 1024 * 1024;
protected static final int BATCH_MAX_SIZE = 100;
- protected static final boolean ALWAYS_DECODE_ETH = true;
-
- /**
- * Updates handled by the main loop
- */
- protected interface IUpdate {
- /**
- * Calls the appropriate listeners
- */
- public void dispatch();
- }
+ protected static final boolean ALWAYS_DECODE_ETH = true;
+
public enum SwitchUpdateType {
ADDED,
REMOVED,
@@ -271,6 +263,7 @@
PORTADDED,
PORTREMOVED
}
+
/**
* Update message indicating a switch was added or removed
* ONOS: This message extended to indicate Port add or removed event.
@@ -461,7 +454,13 @@
}
}
-
+ public void publishUpdate(IUpdate update) {
+ try {
+ this.updates.put(update);
+ } catch (InterruptedException e) {
+ log.error("Failure adding update to queue", e);
+ }
+ }
// **********************
// ChannelUpstreamHandler
diff --git a/src/main/java/net/floodlightcontroller/packet/IPv4.java b/src/main/java/net/floodlightcontroller/packet/IPv4.java
index 01f886d..85f21ca 100644
--- a/src/main/java/net/floodlightcontroller/packet/IPv4.java
+++ b/src/main/java/net/floodlightcontroller/packet/IPv4.java
@@ -31,6 +31,7 @@
*
*/
public class IPv4 extends BasePacket {
+ public static final int ADDRESS_LENGTH = 4;
public static final byte PROTOCOL_ICMP = 0x1;
public static final byte PROTOCOL_TCP = 0x6;
public static final byte PROTOCOL_UDP = 0x11;
diff --git a/src/main/java/net/onrc/onos/flow/FlowManagerImpl.java b/src/main/java/net/onrc/onos/flow/FlowManagerImpl.java
index 1f041e6..2e2706c 100644
--- a/src/main/java/net/onrc/onos/flow/FlowManagerImpl.java
+++ b/src/main/java/net/onrc/onos/flow/FlowManagerImpl.java
@@ -28,6 +28,7 @@
import net.onrc.onos.ofcontroller.util.Dpid;
import net.onrc.onos.ofcontroller.util.FlowEntry;
import net.onrc.onos.ofcontroller.util.FlowEntryAction;
+import net.onrc.onos.ofcontroller.util.FlowEntryActions;
import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
import net.onrc.onos.ofcontroller.util.FlowPath;
import net.onrc.onos.ofcontroller.util.Port;
@@ -132,16 +133,12 @@
flowEntry.setOutPort(new Port(src_port.getNumber()));
flowEntry.setFlowEntryMatch(new FlowEntryMatch());
flowEntry.flowEntryMatch().enableInPort(flowEntry.inPort());
-
+
// Set the outgoing port output action
- ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
- if (flowEntryActions == null) {
- flowEntryActions = new ArrayList<FlowEntryAction>();
- flowEntry.setFlowEntryActions(flowEntryActions);
- }
+ FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
FlowEntryAction flowEntryAction = new FlowEntryAction();
flowEntryAction.setActionOutput(flowEntry.outPort());
- flowEntryActions.add(flowEntryAction);
+ flowEntryActions.addAction(flowEntryAction);
dataPath.flowEntries().add(flowEntry);
FlowPath flowPath = new FlowPath();
@@ -254,14 +251,10 @@
flowEntry.flowEntryMatch().enableInPort(flowEntry.inPort());
// Set the outgoing port output action
- ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
- if (flowEntryActions == null) {
- flowEntryActions = new ArrayList<FlowEntryAction>();
- flowEntry.setFlowEntryActions(flowEntryActions);
- }
+ FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
FlowEntryAction flowEntryAction = new FlowEntryAction();
flowEntryAction.setActionOutput(flowEntry.outPort());
- flowEntryActions.add(flowEntryAction);
+ flowEntryActions.addAction(flowEntryAction);
dataPath.flowEntries().add(flowEntry);
continue;
}
@@ -276,14 +269,10 @@
flowEntry.flowEntryMatch().enableInPort(flowEntry.inPort());
// Set the outgoing port output action
- ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
- if (flowEntryActions == null) {
- flowEntryActions = new ArrayList<FlowEntryAction>();
- flowEntry.setFlowEntryActions(flowEntryActions);
- }
+ FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
FlowEntryAction flowEntryAction = new FlowEntryAction();
flowEntryAction.setActionOutput(flowEntry.outPort());
- flowEntryActions.add(flowEntryAction);
+ flowEntryActions.addAction(flowEntryAction);
dataPath.flowEntries().add(flowEntry);
dataPath.flowEntries().add(flowEntry);
}
diff --git a/src/main/java/net/onrc/onos/graph/GraphDBOperation.java b/src/main/java/net/onrc/onos/graph/GraphDBOperation.java
index acfe43b..f1e9b46 100644
--- a/src/main/java/net/onrc/onos/graph/GraphDBOperation.java
+++ b/src/main/java/net/onrc/onos/graph/GraphDBOperation.java
@@ -3,8 +3,6 @@
import java.util.ArrayList;
import java.util.List;
-import org.openflow.protocol.OFPhysicalPort;
-
import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IDeviceObject;
import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowEntry;
import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowPath;
@@ -14,7 +12,6 @@
import net.onrc.onos.ofcontroller.util.FlowEntryId;
import net.onrc.onos.ofcontroller.util.FlowId;
-import com.google.common.base.Stopwatch;
import com.thinkaurelius.titan.core.TitanGraph;
import com.tinkerpop.blueprints.Vertex;
import com.tinkerpop.frames.FramedGraph;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpPeer.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpPeer.java
index 7425a07..fa11c17 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpPeer.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpPeer.java
@@ -2,41 +2,25 @@
import java.net.InetAddress;
-import net.floodlightcontroller.util.MACAddress;
-
import org.codehaus.jackson.annotate.JsonProperty;
import com.google.common.net.InetAddresses;
public class BgpPeer {
- private String interfaceName;
- private InetAddress ipAddress;
- private MACAddress macAddress;
+ private final String interfaceName;
+ private final InetAddress ipAddress;
+
+ public BgpPeer(@JsonProperty("interface") String interfaceName,
+ @JsonProperty("ipAddress") String ipAddress) {
+ this.interfaceName = interfaceName;
+ this.ipAddress = InetAddresses.forString(ipAddress);
+ }
public String getInterfaceName() {
return interfaceName;
}
-
- @JsonProperty("interface")
- public void setInterfaceName(String interfaceName) {
- this.interfaceName = interfaceName;
- }
-
+
public InetAddress getIpAddress() {
return ipAddress;
}
-
- @JsonProperty("ipAddress")
- public void setIpAddress(String ipAddress) {
- this.ipAddress = InetAddresses.forString(ipAddress);
- }
-
- public MACAddress getMacAddress() {
- return macAddress;
- }
-
- @JsonProperty("macAddress")
- public void setMacAddress(String macAddress) {
- this.macAddress = MACAddress.valueOf(macAddress);
- }
}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java
index 2034118..826fd93 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java
@@ -3,14 +3,17 @@
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
-import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@@ -22,18 +25,22 @@
import net.floodlightcontroller.core.module.IFloodlightModule;
import net.floodlightcontroller.core.module.IFloodlightService;
import net.floodlightcontroller.core.util.SingletonTask;
-import net.floodlightcontroller.devicemanager.IDeviceService;
import net.floodlightcontroller.packet.Ethernet;
import net.floodlightcontroller.packet.IPv4;
import net.floodlightcontroller.restserver.IRestApiService;
import net.floodlightcontroller.routing.Link;
import net.floodlightcontroller.topology.ITopologyListener;
import net.floodlightcontroller.topology.ITopologyService;
+import net.floodlightcontroller.util.MACAddress;
+import net.onrc.onos.ofcontroller.bgproute.RibUpdate.Operation;
import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoLinkService;
import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoRouteService;
import net.onrc.onos.ofcontroller.core.internal.TopoLinkServiceImpl;
import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery;
import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery.LDUpdate;
+import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscoveryService;
+import net.onrc.onos.ofcontroller.proxyarp.IArpRequester;
+import net.onrc.onos.ofcontroller.proxyarp.IProxyArpService;
import net.onrc.onos.ofcontroller.proxyarp.ProxyArpManager;
import net.onrc.onos.ofcontroller.routing.TopoRouteService;
import net.onrc.onos.ofcontroller.util.DataPath;
@@ -50,7 +57,6 @@
import org.codehaus.jackson.map.ObjectMapper;
import org.openflow.protocol.OFFlowMod;
import org.openflow.protocol.OFMatch;
-import org.openflow.protocol.OFMessage;
import org.openflow.protocol.OFPacketOut;
import org.openflow.protocol.OFPort;
import org.openflow.protocol.OFType;
@@ -61,20 +67,32 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Multimaps;
+import com.google.common.collect.SetMultimap;
+import com.google.common.net.InetAddresses;
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+
public class BgpRoute implements IFloodlightModule, IBgpRouteService,
- ITopologyListener, IOFSwitchListener {
+ ITopologyListener, IArpRequester,
+ IOFSwitchListener, ILayer3InfoService,
+ IProxyArpService {
protected static Logger log = LoggerFactory.getLogger(BgpRoute.class);
protected IFloodlightProviderService floodlightProvider;
protected ITopologyService topology;
protected ITopoRouteService topoRouteService;
- protected IDeviceService devices;
+ protected ILinkDiscoveryService linkDiscoveryService;
protected IRestApiService restApi;
protected ProxyArpManager proxyArp;
- protected static Ptree ptree;
+ protected IPatriciaTrie<RibEntry> ptree;
+ protected IPatriciaTrie<Interface> interfacePtrie;
+ protected BlockingQueue<RibUpdate> ribUpdates;
+
protected String bgpdRestIp;
protected String routerId;
protected String configFilename = "config.json";
@@ -91,6 +109,7 @@
//Forwarding uses priority 0, and the mac rewrite entries in ingress switches
//need to be higher priority than this otherwise the rewrite may not get done
protected final short SDNIP_PRIORITY = 10;
+ protected final short ARP_PRIORITY = 20;
protected final short BGP_PORT = 179;
@@ -101,6 +120,7 @@
protected Map<String, Interface> interfaces;
protected Map<InetAddress, BgpPeer> bgpPeers;
protected SwitchPort bgpdAttachmentPoint;
+ protected MACAddress bgpdMacAddress;
//True when all switches have connected
protected volatile boolean switchesConnected = false;
@@ -110,6 +130,20 @@
protected ArrayList<LDUpdate> linkUpdates;
protected SingletonTask topologyChangeDetectorTask;
+ protected SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
+
+ protected Map<InetAddress, Path> pathsWaitingOnArp;
+
+ protected ExecutorService bgpUpdatesExecutor;
+
+ protected Map<InetAddress, Path> pushedPaths;
+ protected Map<Prefix, Path> prefixToPath;
+ protected Multimap<Prefix, PushedFlowMod> pushedFlows;
+
+ private FlowCache flowCache;
+
+ protected volatile Map<Long, ?> topoRouteTopology = null;
+
protected class TopologyChangeDetector implements Runnable {
@Override
public void run() {
@@ -119,9 +153,6 @@
ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
List<Link> activeLinks = topoLinkService.getActiveLinks();
- for (Link l : activeLinks){
- log.debug("active link: {}", l);
- }
Iterator<LDUpdate> it = linkUpdates.iterator();
while (it.hasNext()){
@@ -130,22 +161,23 @@
ldu.getDst(), ldu.getDstPort());
if (activeLinks.contains(l)){
- log.debug("Not found: {}", l);
it.remove();
}
}
}
- if (linkUpdates.isEmpty()){
- //All updates have been seen in network map.
- //We can check if topology is ready
- log.debug("No know changes outstanding. Checking topology now");
- checkStatus();
- }
- else {
- //We know of some link updates that haven't propagated to the database yet
- log.debug("Some changes not found in network map- size {}", linkUpdates.size());
- topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
+ if (!topologyReady) {
+ if (linkUpdates.isEmpty()){
+ //All updates have been seen in network map.
+ //We can check if topology is ready
+ log.debug("No known changes outstanding. Checking topology now");
+ checkStatus();
+ }
+ else {
+ //We know of some link updates that haven't propagated to the database yet
+ log.debug("Some changes not found in network map - {} links missing", linkUpdates.size());
+ topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
+ }
}
}
}
@@ -171,6 +203,7 @@
new Dpid(config.getBgpdAttachmentDpid()),
new Port(config.getBgpdAttachmentPort()));
+ bgpdMacAddress = config.getBgpdMacAddress();
} catch (JsonParseException e) {
log.error("Error in JSON file", e);
System.exit(1);
@@ -181,6 +214,12 @@
log.error("Error reading JSON file", e);
System.exit(1);
}
+
+ //Populate the interface Patricia Trie
+ for (Interface intf : interfaces.values()) {
+ Prefix prefix = new Prefix(intf.getIpAddress().getAddress(), intf.getPrefixLength());
+ interfacePtrie.put(prefix, intf);
+ }
}
@Override
@@ -196,6 +235,7 @@
Map<Class<? extends IFloodlightService>, IFloodlightService> m
= new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
m.put(IBgpRouteService.class, this);
+ m.put(IProxyArpService.class, this);
return m;
}
@@ -205,7 +245,6 @@
= new ArrayList<Class<? extends IFloodlightService>>();
l.add(IFloodlightProviderService.class);
l.add(ITopologyService.class);
- l.add(IDeviceService.class);
l.add(IRestApiService.class);
return l;
}
@@ -214,17 +253,20 @@
public void init(FloodlightModuleContext context)
throws FloodlightModuleException {
- ptree = new Ptree(32);
+ ptree = new PatriciaTrie<RibEntry>(32);
+ interfacePtrie = new PatriciaTrie<Interface>(32);
+
+ ribUpdates = new LinkedBlockingQueue<RibUpdate>();
// Register floodlight provider and REST handler.
floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
topology = context.getServiceImpl(ITopologyService.class);
- devices = context.getServiceImpl(IDeviceService.class);
+ linkDiscoveryService = context.getServiceImpl(ILinkDiscoveryService.class);
restApi = context.getServiceImpl(IRestApiService.class);
//TODO We'll initialise this here for now, but it should really be done as
//part of the controller core
- proxyArp = new ProxyArpManager(floodlightProvider, topology);
+ proxyArp = new ProxyArpManager(floodlightProvider, topology, this, restApi);
linkUpdates = new ArrayList<LDUpdate>();
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
@@ -232,6 +274,19 @@
topoRouteService = new TopoRouteService("");
+ pathsWaitingOnArp = new HashMap<InetAddress, Path>();
+ prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
+ HashMultimap.<InetAddress, RibUpdate>create());
+
+ pushedPaths = new HashMap<InetAddress, Path>();
+ prefixToPath = new HashMap<Prefix, Path>();
+ pushedFlows = HashMultimap.<Prefix, PushedFlowMod>create();
+
+ flowCache = new FlowCache(floodlightProvider);
+
+ bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
+ new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
+
//Read in config values
bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
if (bgpdRestIp == null){
@@ -258,17 +313,28 @@
log.debug("Config file set to {}", configFilename);
readGatewaysConfiguration(configFilename);
- // Test.
- //test();
+ }
+
+ @Override
+ public void startUp(FloodlightModuleContext context) {
+ restApi.addRestletRoutable(new BgpRouteWebRoutable());
+ topology.addListener(this);
+ floodlightProvider.addOFSwitchListener(this);
+
+ proxyArp.startUp();
+
+ floodlightProvider.addOFMessageListener(OFType.PACKET_IN, proxyArp);
+
+ //Retrieve the RIB from BGPd during startup
+ retrieveRib();
}
- public Ptree getPtree() {
+ public IPatriciaTrie<RibEntry> getPtree() {
return ptree;
}
public void clearPtree() {
- //ptree = null;
- ptree = new Ptree(32);
+ ptree = new PatriciaTrie<RibEntry>(32);
}
public String getBGPdRestIp() {
@@ -279,98 +345,6 @@
return routerId;
}
- // Return nexthop address as byte array.
- public Rib lookupRib(byte[] dest) {
- if (ptree == null) {
- log.debug("lookupRib: ptree null");
- return null;
- }
-
- PtreeNode node = ptree.match(dest, 32);
- if (node == null) {
- log.debug("lookupRib: ptree node null");
- return null;
- }
-
- if (node.rib == null) {
- log.debug("lookupRib: ptree rib null");
- return null;
- }
-
- ptree.delReference(node);
-
- return node.rib;
- }
-
- //TODO looks like this should be a unit test
- @SuppressWarnings("unused")
- private void test() throws UnknownHostException {
- System.out.println("Here it is");
- Prefix p = new Prefix("128.0.0.0", 8);
- Prefix q = new Prefix("8.0.0.0", 8);
- Prefix r = new Prefix("10.0.0.0", 24);
- Prefix a = new Prefix("10.0.0.1", 32);
-
- ptree.acquire(p.getAddress(), p.masklen);
- ptree.acquire(q.getAddress(), q.masklen);
- ptree.acquire(r.getAddress(), r.masklen);
-
- System.out.println("Traverse start");
- for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
- Prefix p_result = new Prefix(node.key, node.keyBits);
- }
-
- PtreeNode n = ptree.match(a.getAddress(), a.masklen);
- if (n != null) {
- System.out.println("Matched prefix for 10.0.0.1:");
- Prefix x = new Prefix(n.key, n.keyBits);
- ptree.delReference(n);
- }
-
- n = ptree.lookup(p.getAddress(), p.masklen);
- if (n != null) {
- ptree.delReference(n);
- ptree.delReference(n);
- }
- System.out.println("Traverse start");
- for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
- Prefix p_result = new Prefix(node.key, node.keyBits);
- }
-
- n = ptree.lookup(q.getAddress(), q.masklen);
- if (n != null) {
- ptree.delReference(n);
- ptree.delReference(n);
- }
- System.out.println("Traverse start");
- for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
- Prefix p_result = new Prefix(node.key, node.keyBits);
- }
-
- n = ptree.lookup(r.getAddress(), r.masklen);
- if (n != null) {
- ptree.delReference(n);
- ptree.delReference(n);
- }
- System.out.println("Traverse start");
- for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
- Prefix p_result = new Prefix(node.key, node.keyBits);
- }
-
- }
-
- private String getPrefixFromPtree(PtreeNode node){
- InetAddress address = null;
- try {
- address = InetAddress.getByAddress(node.key);
- } catch (UnknownHostException e1) {
- //Should never happen is the reverse conversion has already been done
- log.error("Malformed IP address");
- return "";
- }
- return address.toString() + "/" + node.rib.masklen;
- }
-
private void retrieveRib(){
String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
String response = RestClient.get(url);
@@ -404,81 +378,147 @@
} catch (NumberFormatException e) {
log.warn("Wrong mask format in RIB JSON: {}", mask1);
continue;
- } catch (UnknownHostException e1) {
+ } catch (IllegalArgumentException e1) {
log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
continue;
}
- PtreeNode node = ptree.acquire(p.getAddress(), p.masklen);
- Rib rib = new Rib(router_id, nexthop, p.masklen);
-
- if (node.rib != null) {
- node.rib = null;
- ptree.delReference(node);
+ RibEntry rib = new RibEntry(router_id, nexthop);
+
+ try {
+ ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
+ } catch (InterruptedException e) {
+ log.debug("Interrupted while pushing onto update queue");
}
-
- node.rib = rib;
-
- prefixAdded(node);
}
}
- public void prefixAdded(PtreeNode node) {
- if (!topologyReady){
+ @Override
+ public void newRibUpdate(RibUpdate update) {
+ try {
+ ribUpdates.put(update);
+ } catch (InterruptedException e) {
+ log.debug("Interrupted while putting on ribUpdates queue", e);
+ Thread.currentThread().interrupt();
+ }
+ }
+
+ public synchronized void processRibAdd(RibUpdate update) {
+ Prefix prefix = update.getPrefix();
+
+ log.debug("Processing prefix add {}", prefix);
+
+ RibEntry rib = ptree.put(prefix, update.getRibEntry());
+
+ if (rib != null && !rib.equals(update.getRibEntry())) {
+ //There was an existing nexthop for this prefix. This update supersedes that,
+ //so we need to remove the old flows for this prefix from the switches
+ _processDeletePrefix(prefix, rib);
+ }
+
+ if (update.getRibEntry().getNextHop().equals(
+ InetAddresses.forString("0.0.0.0"))) {
+ //Route originated by SDN domain
+ //We don't handle these at the moment
+ log.debug("Own route {} to {}", prefix,
+ update.getRibEntry().getNextHop().getHostAddress());
return;
}
- String prefix = getPrefixFromPtree(node);
+ _processRibAdd(update);
+ }
+
+ private void _processRibAdd(RibUpdate update) {
+ Prefix prefix = update.getPrefix();
+ RibEntry rib = update.getRibEntry();
- log.debug("New prefix {} added, next hop {}, routerId {}",
- new Object[] {prefix, node.rib.nextHop.toString(),
- node.rib.routerId.getHostAddress()});
+ InetAddress dstIpAddress = rib.getNextHop();
- //TODO this is wrong, we shouldn't be dealing with BGP peers here.
- //We need to figure out where the device is attached and what it's
- //mac address is by learning.
- //The next hop is not necessarily the peer, and the peer's attachment
- //point is not necessarily the next hop's attachment point.
- BgpPeer peer = bgpPeers.get(node.rib.nextHop);
+ //See if we know the MAC address of the next hop
+ MACAddress nextHopMacAddress = proxyArp.getMacAddress(rib.getNextHop());
- if (peer == null){
- //TODO local router isn't in peers list so this will get thrown
- //Need to work out what to do about local prefixes with next hop 0.0.0.0.
-
- //The other scenario is this is a route server route. In that
- //case the next hop is not in our configuration
- log.error("Couldn't find next hop router in router {} in config"
- , node.rib.nextHop.toString());
- return; //just quit out here? This is probably a configuration error
+ //Find the attachment point (egress interface) of the next hop
+ Interface egressInterface = null;
+ if (bgpPeers.containsKey(dstIpAddress)) {
+ //Route to a peer
+ log.debug("Route to peer {}", dstIpAddress);
+ BgpPeer peer = bgpPeers.get(dstIpAddress);
+ egressInterface = interfaces.get(peer.getInterfaceName());
+ }
+ else {
+ //Route to non-peer
+ log.debug("Route to non-peer {}", dstIpAddress);
+ egressInterface = interfacePtrie.match(
+ new Prefix(dstIpAddress.getAddress(), 32));
+ if (egressInterface == null) {
+ log.warn("No outgoing interface found for {}", dstIpAddress.getHostAddress());
+ return;
+ }
}
- Interface peerInterface = interfaces.get(peer.getInterfaceName());
-
- //Add a flow to rewrite mac for this prefix to all border switches
- for (Interface srcInterface : interfaces.values()) {
- if (srcInterface == peerInterface) {
- //Don't push a flow for the switch where this peer is attached
- continue;
+ if (nextHopMacAddress == null) {
+ prefixesWaitingOnArp.put(dstIpAddress,
+ new RibUpdate(Operation.UPDATE, prefix, rib));
+ proxyArp.sendArpRequest(dstIpAddress, this, true);
+ return;
+ }
+ else {
+ if (!bgpPeers.containsKey(dstIpAddress)) {
+ //If the prefix is for a non-peer we need to ensure there's a path,
+ //and push one if there isn't.
+ Path path = pushedPaths.get(dstIpAddress);
+ if (path == null) {
+ path = new Path(egressInterface, dstIpAddress);
+ calculateAndPushPath(path, nextHopMacAddress);
+ pushedPaths.put(dstIpAddress, path);
+ }
+
+ path.incrementUsers();
+ prefixToPath.put(prefix, path);
}
-
- DataPath shortestPath = topoRouteService.getShortestPath(
- srcInterface.getSwitchPort(),
- peerInterface.getSwitchPort());
+
+ //For all prefixes we need to add the first-hop mac-rewriting flows
+ addPrefixFlows(prefix, egressInterface, nextHopMacAddress);
+ }
+ }
+
+ private void addPrefixFlows(Prefix prefix, Interface egressInterface, MACAddress nextHopMacAddress) {
+ log.debug("Adding flows for prefix {} added, next hop mac {}",
+ prefix, nextHopMacAddress);
+
+ //We only need one flow mod per switch, so pick one interface on each switch
+ Map<Long, Interface> srcInterfaces = new HashMap<Long, Interface>();
+ for (Interface intf : interfaces.values()) {
+ if (!srcInterfaces.containsKey(intf.getDpid())
+ && intf != egressInterface) {
+ srcInterfaces.put(intf.getDpid(), intf);
+ }
+ }
+
+ //Add a flow to rewrite mac for this prefix to all other border switches
+ for (Interface srcInterface : srcInterfaces.values()) {
+ DataPath shortestPath;
+ if (topoRouteTopology == null) {
+ shortestPath = topoRouteService.getShortestPath(
+ srcInterface.getSwitchPort(),
+ egressInterface.getSwitchPort());
+ }
+ else {
+ shortestPath = topoRouteService.getTopoShortestPath(
+ topoRouteTopology, srcInterface.getSwitchPort(),
+ egressInterface.getSwitchPort());
+ }
if (shortestPath == null){
log.debug("Shortest path between {} and {} not found",
srcInterface.getSwitchPort(),
- peerInterface.getSwitchPort());
+ egressInterface.getSwitchPort());
return; // just quit here?
}
- //TODO check the shortest path against the cached version we
- //calculated before. If they don't match up that's a problem
-
//Set up the flow mod
- OFFlowMod fm =
- (OFFlowMod) floodlightProvider.getOFMessageFactory()
- .getMessage(OFType.FLOW_MOD);
+ OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
+ .getMessage(OFType.FLOW_MOD);
fm.setIdleTimeout((short)0)
.setHardTimeout((short)0)
@@ -494,32 +534,16 @@
match.setDataLayerType(Ethernet.TYPE_IPv4);
match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
- //match.setDataLayerSource(ingressRouter.getRouterMac().toBytes());
- //match.setDataLayerSource(peer.getMacAddress().toBytes());
- //match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
-
- InetAddress address = null;
- try {
- address = InetAddress.getByAddress(node.key);
- } catch (UnknownHostException e1) {
- //Should never happen is the reverse conversion has already been done
- log.error("Malformed IP address");
- return;
- }
-
- match.setFromCIDR(address.getHostAddress() + "/" + node.rib.masklen, OFMatch.STR_NW_DST);
+ match.setFromCIDR(prefix.toString(), OFMatch.STR_NW_DST);
fm.setMatch(match);
//Set up MAC rewrite action
OFActionDataLayerDestination macRewriteAction = new OFActionDataLayerDestination();
- //TODO use ARP module rather than configured mac addresses
- //TODO the peer's mac address is not necessarily the next hop's...
- macRewriteAction.setDataLayerAddress(peer.getMacAddress().toBytes());
+ macRewriteAction.setDataLayerAddress(nextHopMacAddress.toBytes());
//Set up output action
OFActionOutput outputAction = new OFActionOutput();
outputAction.setMaxLength((short)0xffff);
-
Port outputPort = shortestPath.flowEntries().get(0).outPort();
outputAction.setPort(outputPort.value());
@@ -528,107 +552,101 @@
actions.add(outputAction);
fm.setActions(actions);
- //Write to switch
- IOFSwitch sw = floodlightProvider.getSwitches()
- .get(srcInterface.getDpid());
-
- if (sw == null){
- log.warn("Switch not found when pushing flow mod");
- continue;
- }
-
- List<OFMessage> msglist = new ArrayList<OFMessage>();
- msglist.add(fm);
- try {
- sw.write(msglist, null);
- sw.flush();
- } catch (IOException e) {
- log.error("Failure writing flow mod", e);
+ pushedFlows.put(prefix, new PushedFlowMod(srcInterface.getDpid(), fm));
+ flowCache.write(srcInterface.getDpid(), fm);
+
+ /*
+ * XXX Rate limit hack!
+ * This should be solved properly by adding a rate limiting
+ * layer on top of the switches if we know they need it.
+ */
+ try {
+ Thread.sleep(1);
+ } catch (InterruptedException e) {
+ // TODO handle this properly
+ log.error("Interrupted", e);
}
}
}
- //TODO this is largely untested
- public void prefixDeleted(PtreeNode node) {
- if (!topologyReady) {
- return;
+ public synchronized void processRibDelete(RibUpdate update) {
+ Prefix prefix = update.getPrefix();
+
+ if (ptree.remove(prefix, update.getRibEntry())) {
+ /*
+ * Only delete flows if an entry was actually removed from the trie.
+ * If no entry was removed, the <prefix, nexthop> wasn't there so
+ * it's probably already been removed and we don't need to do anything
+ */
+ _processDeletePrefix(prefix, update.getRibEntry());
}
+ }
+
+ private void _processDeletePrefix(Prefix prefix, RibEntry ribEntry) {
+ deletePrefixFlows(prefix);
- String prefix = getPrefixFromPtree(node);
+ log.debug("Deleting {} to {}", prefix, ribEntry.getNextHop());
- log.debug("Prefix {} deleted, next hop {}",
- prefix, node.rib.nextHop.toString());
-
- //Remove MAC rewriting flows from other border switches
- BgpPeer peer = bgpPeers.get(node.rib.nextHop);
- if (peer == null){
- //either a router server route or local route. Can't handle right now
- return;
- }
-
- Interface peerInterface = interfaces.get(peer.getInterfaceName());
-
- for (Interface srcInterface : interfaces.values()) {
- if (srcInterface == peerInterface) {
- continue;
- }
+ if (!bgpPeers.containsKey(ribEntry.getNextHop())) {
+ log.debug("Getting path for route with non-peer nexthop");
+ Path path = prefixToPath.remove(prefix);
- //Set up the flow mod
- OFFlowMod fm =
- (OFFlowMod) floodlightProvider.getOFMessageFactory()
- .getMessage(OFType.FLOW_MOD);
+ if (path != null) {
+ //path could be null if we added to the Ptree but didn't push
+ //flows yet because we were waiting to resolve ARP
- fm.setIdleTimeout((short)0)
- .setHardTimeout((short)0)
- .setBufferId(OFPacketOut.BUFFER_ID_NONE)
- .setCookie(MAC_RW_COOKIE)
- .setCommand(OFFlowMod.OFPFC_DELETE)
- .setOutPort(OFPort.OFPP_NONE)
- .setPriority(SDNIP_PRIORITY)
- .setLengthU(OFFlowMod.MINIMUM_LENGTH);
- //+ OFActionDataLayerDestination.MINIMUM_LENGTH
- //+ OFActionOutput.MINIMUM_LENGTH);
-
- OFMatch match = new OFMatch();
- match.setDataLayerType(Ethernet.TYPE_IPv4);
- match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
-
- //match.setDataLayerSource(ingressRouter.getRouterMac().toBytes());
- //match.setDataLayerSource(peer.getMacAddress().toBytes());
- //match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
-
- InetAddress address = null;
- try {
- address = InetAddress.getByAddress(node.key);
- } catch (UnknownHostException e1) {
- //Should never happen is the reverse conversion has already been done
- log.error("Malformed IP address");
- return;
- }
-
- match.setFromCIDR(address.getHostAddress() + "/" + node.rib.masklen, OFMatch.STR_NW_DST);
- fm.setMatch(match);
-
- //Write to switch
- IOFSwitch sw = floodlightProvider.getSwitches()
- .get(srcInterface.getDpid());
-
- if (sw == null){
- log.warn("Switch not found when pushing flow mod");
- continue;
- }
-
- List<OFMessage> msglist = new ArrayList<OFMessage>();
- msglist.add(fm);
- try {
- sw.write(msglist, null);
- sw.flush();
- } catch (IOException e) {
- log.error("Failure writing flow mod", e);
+ path.decrementUsers();
+ if (path.getUsers() <= 0 && !path.isPermanent()) {
+ deletePath(path);
+ pushedPaths.remove(path.getDstIpAddress());
+ }
}
}
}
+ private void deletePrefixFlows(Prefix prefix) {
+ log.debug("Deleting flows for prefix {}", prefix);
+
+ Collection<PushedFlowMod> pushedFlowMods
+ = pushedFlows.removeAll(prefix);
+
+ for (PushedFlowMod pfm : pushedFlowMods) {
+ if (log.isTraceEnabled()) {
+ log.trace("Pushing a DELETE flow mod to {}, matches prefix {} with mac-rewrite {}",
+ new Object[] {HexString.toHexString(pfm.getDpid()),
+ pfm.getFlowMod().getMatch().getNetworkDestination() +
+ pfm.getFlowMod().getMatch().getNetworkDestinationMaskLen(),
+ HexString.toHexString(((OFActionDataLayerDestination)pfm.getFlowMod().getActions().get(0))
+ .getDataLayerAddress())});
+ }
+
+ sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
+ }
+ }
+
+ private void deletePath(Path path) {
+ log.debug("Deleting flows for path to {}",
+ path.getDstIpAddress().getHostAddress());
+
+ for (PushedFlowMod pfm : path.getFlowMods()) {
+ if (log.isTraceEnabled()) {
+ log.trace("Pushing a DELETE flow mod to {}, dst MAC {}",
+ new Object[] {HexString.toHexString(pfm.getDpid()),
+ HexString.toHexString(pfm.getFlowMod().getMatch().getDataLayerDestination())
+ });
+ }
+
+ sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
+ }
+ }
+
+ private void sendDeleteFlowMod(OFFlowMod addFlowMod, long dpid) {
+ flowCache.delete(dpid, addFlowMod);
+ }
+
+ //TODO test next-hop changes
+ //TODO check delete/add synchronization
+
/*
* On startup we need to calculate a full mesh of paths between all gateway
* switches
@@ -642,30 +660,68 @@
for (BgpPeer peer : bgpPeers.values()) {
Interface peerInterface = interfaces.get(peer.getInterfaceName());
- //for (Map.Entry<String, Interface> intfEntry : interfaces.entrySet()) {
- for (Interface srcInterface : interfaces.values()) {
- //Interface srcInterface = intfEntry.getValue();
- //if (peer.getInterfaceName().equals(intfEntry.getKey())){
- if (peer.getInterfaceName().equals(srcInterface.getName())){
- continue;
- }
+
+ //We know there's not already a Path here pushed, because this is
+ //called before all other routing
+ Path path = new Path(peerInterface, peer.getIpAddress());
+ path.setPermanent();
+
+ //See if we know the MAC address of the peer. If not we can't
+ //do anything until we learn it
+ MACAddress macAddress = proxyArp.getMacAddress(peer.getIpAddress());
+ if (macAddress == null) {
+ log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
+ //Put in the pending paths list first
+ pathsWaitingOnArp.put(peer.getIpAddress(), path);
- DataPath shortestPath = topoRouteService.getShortestPath(
- srcInterface.getSwitchPort(), peerInterface.getSwitchPort());
-
- if (shortestPath == null){
- log.debug("Shortest path between {} and {} not found",
- srcInterface.getSwitchPort(), peerInterface.getSwitchPort());
- return; // just quit here?
- }
-
- //install flows
- installPath(shortestPath.flowEntries(), peer);
+ proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
+ continue;
}
+
+ //If we know the MAC, lets go ahead and push the paths to this peer
+ calculateAndPushPath(path, macAddress);
}
}
- private void installPath(List<FlowEntry> flowEntries, BgpPeer peer){
+ private void calculateAndPushPath(Path path, MACAddress dstMacAddress) {
+ Interface dstInterface = path.getDstInterface();
+
+ log.debug("Setting up path to {}, {}", path.getDstIpAddress().getHostAddress(),
+ dstMacAddress);
+
+ List<PushedFlowMod> pushedFlows = new ArrayList<PushedFlowMod>();
+
+ for (Interface srcInterface : interfaces.values()) {
+ if (dstInterface.equals(srcInterface.getName())){
+ continue;
+ }
+
+ DataPath shortestPath;
+ if (topoRouteTopology == null) {
+ shortestPath = topoRouteService.getShortestPath(
+ srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
+ }
+ else {
+ shortestPath = topoRouteService.getTopoShortestPath(topoRouteTopology,
+ srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
+ }
+
+ if (shortestPath == null){
+ log.warn("Shortest path between {} and {} not found",
+ srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
+ return;
+ }
+
+ List<PushedFlowMod> pushedFlowMods = installPath(shortestPath.flowEntries(), dstMacAddress);
+ pushedFlows.addAll(pushedFlowMods);
+ }
+
+ path.setFlowMods(pushedFlows);
+ }
+
+ private List<PushedFlowMod> installPath(List<FlowEntry> flowEntries, MACAddress dstMacAddress){
+ List<PushedFlowMod> flowMods = new ArrayList<PushedFlowMod>();
+
//Set up the flow mod
OFFlowMod fm =
(OFFlowMod) floodlightProvider.getOFMessageFactory()
@@ -681,6 +737,7 @@
.setBufferId(OFPacketOut.BUFFER_ID_NONE)
.setCookie(L2_FWD_COOKIE)
.setCommand(OFFlowMod.OFPFC_ADD)
+ .setPriority(SDNIP_PRIORITY)
.setActions(actions)
.setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
@@ -690,35 +747,24 @@
FlowEntry flowEntry = flowEntries.get(i);
OFMatch match = new OFMatch();
- //TODO Again using MAC address from configuration
- match.setDataLayerDestination(peer.getMacAddress().toBytes());
+ match.setDataLayerDestination(dstMacAddress.toBytes());
match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
((OFActionOutput) fm.getActions().get(0)).setPort(flowEntry.outPort().value());
fm.setMatch(match);
- IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
+ flowMods.add(new PushedFlowMod(flowEntry.dpid().value(), fm));
- if (sw == null){
- log.warn("Switch not found when pushing flow mod");
- continue;
- }
-
- List<OFMessage> msglist = new ArrayList<OFMessage>();
- msglist.add(fm);
- try {
- sw.write(msglist, null);
- sw.flush();
- } catch (IOException e) {
- log.error("Failure writing flow mod", e);
- }
-
+ flowCache.write(flowEntry.dpid().value(), fm);
+
try {
fm = fm.clone();
} catch (CloneNotSupportedException e1) {
log.error("Failure cloning flow mod", e1);
}
}
+
+ return flowMods;
}
private void setupBgpPaths(){
@@ -756,17 +802,15 @@
//Forward = gateway -> bgpd, reverse = bgpd -> gateway
OFMatch forwardMatchSrc = new OFMatch();
-
String interfaceCidrAddress = peerInterface.getIpAddress().getHostAddress()
+ "/32";
String peerCidrAddress = bgpPeer.getIpAddress().getHostAddress()
+ "/32";
-
+
//Common match fields
forwardMatchSrc.setDataLayerType(Ethernet.TYPE_IPv4);
- //forwardMatch.setWildcards(forwardMatch.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
forwardMatchSrc.setNetworkProtocol(IPv4.PROTOCOL_TCP);
- forwardMatchSrc.setTransportDestination(BGP_PORT);
+ //forwardMatchSrc.setTransportDestination(BGP_PORT);
forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_IN_PORT
& ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
@@ -795,14 +839,27 @@
fm.setMatch(forwardMatchSrc);
+ OFMatch forwardIcmpMatch = new OFMatch();
+ forwardIcmpMatch.setDataLayerType(Ethernet.TYPE_IPv4);
+ forwardIcmpMatch.setNetworkProtocol(IPv4.PROTOCOL_ICMP);
+ forwardIcmpMatch.setWildcards(forwardIcmpMatch.getWildcards() &
+ ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
+
+ OFMatch reverseIcmpMatch = forwardIcmpMatch.clone();
+ forwardIcmpMatch.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
+ reverseIcmpMatch.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
+
for (FlowEntry flowEntry : path.flowEntries()){
OFFlowMod forwardFlowModSrc, forwardFlowModDst;
OFFlowMod reverseFlowModSrc, reverseFlowModDst;
+ OFFlowMod forwardIcmp, reverseIcmp;
try {
forwardFlowModSrc = fm.clone();
forwardFlowModDst = fm.clone();
reverseFlowModSrc = fm.clone();
reverseFlowModDst = fm.clone();
+ forwardIcmp = fm.clone();
+ reverseIcmp = fm.clone();
} catch (CloneNotSupportedException e) {
log.warn("Clone failed", e);
continue;
@@ -828,36 +885,186 @@
((OFActionOutput)reverseFlowModDst.getActions().get(0))
.setPort(flowEntry.inPort().value());
- IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
+ ((OFActionOutput)forwardIcmp.getActions().get(0))
+ .setPort(flowEntry.outPort().value());
+ forwardIcmp.setMatch(forwardIcmpMatch);
- //Hopefully the switch is there
- List<OFMessage> msgList = new ArrayList<OFMessage>(2);
- msgList.add(forwardFlowModSrc);
- msgList.add(forwardFlowModDst);
- msgList.add(reverseFlowModSrc);
- msgList.add(reverseFlowModDst);
+ ((OFActionOutput)reverseIcmp.getActions().get(0))
+ .setPort(flowEntry.inPort().value());
+ reverseIcmp.setMatch(reverseIcmpMatch);
- try {
- sw.write(msgList, null);
- sw.flush();
- } catch (IOException e) {
- log.error("Failure writing flow mod", e);
+ List<OFFlowMod> flowModList = new ArrayList<OFFlowMod>(6);
+ flowModList.add(forwardFlowModSrc);
+ flowModList.add(forwardFlowModDst);
+ flowModList.add(reverseFlowModSrc);
+ flowModList.add(reverseFlowModDst);
+ flowModList.add(forwardIcmp);
+ flowModList.add(reverseIcmp);
+ flowCache.write(flowEntry.dpid().value(), flowModList);
+ }
+ }
+ }
+
+ @Override
+ public void arpResponse(InetAddress ipAddress, MACAddress macAddress) {
+ log.debug("Received ARP response: {} => {}",
+ ipAddress.getHostAddress(), macAddress);
+
+ /*
+ * We synchronize on this to prevent changes to the ptree while we're pushing
+ * flows to the switches. If the ptree changes, the ptree and switches
+ * could get out of sync.
+ */
+ synchronized (this) {
+ Path path = pathsWaitingOnArp.remove(ipAddress);
+
+ if (path != null) {
+ log.debug("Pushing path to {} at {} on {}", new Object[] {
+ path.getDstIpAddress().getHostAddress(), macAddress,
+ path.getDstInterface().getSwitchPort()});
+ //These paths should always be to BGP peers. Paths to non-peers are
+ //handled once the first prefix is ready to push
+ if (pushedPaths.containsKey(path.getDstInterface())) {
+ //A path already got pushed to this endpoint while we were waiting
+ //for ARP. We'll copy over the permanent attribute if it is set on this path.
+ if (path.isPermanent()) {
+ pushedPaths.get(path.getDstInterface()).setPermanent();
+ }
+ }
+ else {
+ calculateAndPushPath(path, macAddress);
+ pushedPaths.put(path.getDstIpAddress(), path);
+ }
+ }
+
+ Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
+
+ for (RibUpdate update : prefixesToPush) {
+ //These will always be adds
+
+ RibEntry rib = ptree.lookup(update.getPrefix());
+ if (rib != null && rib.equals(update.getRibEntry())) {
+ log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
+ rib.getNextHop().getHostAddress());
+ //We only push prefix flows if the prefix is still in the ptree
+ //and the next hop is the same as our update. The prefix could
+ //have been removed while we were waiting for the ARP, or the
+ //next hop could have changed.
+ _processRibAdd(update);
+ } else {
+ log.debug("Received ARP response, but {},{} is no longer in ptree",
+ update.getPrefix(), update.getRibEntry());
}
}
}
}
+ private void setupArpFlows() {
+ OFMatch match = new OFMatch();
+ match.setDataLayerType(Ethernet.TYPE_ARP);
+ match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
+
+ OFFlowMod fm = new OFFlowMod();
+ fm.setMatch(match);
+
+ OFActionOutput action = new OFActionOutput();
+ action.setPort(OFPort.OFPP_CONTROLLER.getValue());
+ action.setMaxLength((short)0xffff);
+ List<OFAction> actions = new ArrayList<OFAction>(1);
+ actions.add(action);
+ fm.setActions(actions);
+
+ fm.setIdleTimeout((short)0)
+ .setHardTimeout((short)0)
+ .setBufferId(OFPacketOut.BUFFER_ID_NONE)
+ .setCookie(0)
+ .setCommand(OFFlowMod.OFPFC_ADD)
+ .setPriority(ARP_PRIORITY)
+ .setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
+
+ for (String strdpid : switches){
+ flowCache.write(HexString.toLong(strdpid), fm);
+ }
+ }
+
+ private void setupDefaultDropFlows() {
+ OFFlowMod fm = new OFFlowMod();
+ fm.setMatch(new OFMatch());
+ fm.setActions(new ArrayList<OFAction>()); //No action means drop
+
+ fm.setIdleTimeout((short)0)
+ .setHardTimeout((short)0)
+ .setBufferId(OFPacketOut.BUFFER_ID_NONE)
+ .setCookie(0)
+ .setCommand(OFFlowMod.OFPFC_ADD)
+ .setPriority((short)0)
+ .setLengthU(OFFlowMod.MINIMUM_LENGTH);
+
+ OFFlowMod fmLLDP;
+ OFFlowMod fmBDDP;
+ try {
+ fmLLDP = fm.clone();
+ fmBDDP = fm.clone();
+ } catch (CloneNotSupportedException e1) {
+ log.error("Error cloning flow mod", e1);
+ return;
+ }
+
+ OFMatch matchLLDP = new OFMatch();
+ matchLLDP.setDataLayerType((short)0x8942);
+ matchLLDP.setWildcards(matchLLDP.getWildcards() & ~ OFMatch.OFPFW_DL_TYPE);
+ fmLLDP.setMatch(matchLLDP);
+
+ OFMatch matchBDDP = new OFMatch();
+ matchBDDP.setDataLayerType((short)0x88cc);
+ matchBDDP.setWildcards(matchBDDP.getWildcards() & ~ OFMatch.OFPFW_DL_TYPE);
+ fmBDDP.setMatch(matchBDDP);
+
+ OFActionOutput action = new OFActionOutput();
+ action.setPort(OFPort.OFPP_CONTROLLER.getValue());
+ action.setMaxLength((short)0xffff);
+ List<OFAction> actions = new ArrayList<OFAction>(1);
+ actions.add(action);
+
+ fmLLDP.setActions(actions);
+ fmBDDP.setActions(actions);
+
+ fmLLDP.setPriority(ARP_PRIORITY);
+ fmLLDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
+ fmBDDP.setPriority(ARP_PRIORITY);
+ fmBDDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
+
+ List<OFFlowMod> flowModList = new ArrayList<OFFlowMod>(3);
+ flowModList.add(fm);
+ flowModList.add(fmLLDP);
+ flowModList.add(fmBDDP);
+
+ for (String strdpid : switches){
+ flowCache.write(HexString.toLong(strdpid), flowModList);
+ }
+ }
+
private void beginRouting(){
log.debug("Topology is now ready, beginning routing function");
+ topoRouteTopology = topoRouteService.prepareShortestPathTopo();
+
+ setupArpFlows();
+ setupDefaultDropFlows();
+
setupBgpPaths();
setupFullMesh();
- //Traverse ptree and create flows for all routes
- for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)){
- if (node.rib != null){
- prefixAdded(node);
- }
+ //Suppress link discovery on external-facing router ports
+ for (Interface intf : interfaces.values()) {
+ linkDiscoveryService.AddToSuppressLLDPs(intf.getDpid(), intf.getPort());
}
+
+ bgpUpdatesExecutor.execute(new Runnable() {
+ @Override
+ public void run() {
+ doUpdatesThread();
+ }
+ });
}
private void checkSwitchesConnected(){
@@ -893,8 +1100,6 @@
}
private void checkStatus(){
- log.debug("In checkStatus, swC {}, toRe {}", switchesConnected, topologyReady);
-
if (!switchesConnected){
checkSwitchesConnected();
}
@@ -906,29 +1111,46 @@
beginRouting();
}
}
-
- @Override
- public void startUp(FloodlightModuleContext context) {
- restApi.addRestletRoutable(new BgpRouteWebRoutable());
- floodlightProvider.addOFSwitchListener(this);
- topology.addListener(this);
-
- floodlightProvider.addOFMessageListener(OFType.PACKET_IN, proxyArp);
-
- //Retrieve the RIB from BGPd during startup
- retrieveRib();
+
+ private void doUpdatesThread() {
+ boolean interrupted = false;
+ try {
+ while (true) {
+ try {
+ RibUpdate update = ribUpdates.take();
+ switch (update.getOperation()){
+ case UPDATE:
+ processRibAdd(update);
+ break;
+ case DELETE:
+ processRibDelete(update);
+ break;
+ }
+ } catch (InterruptedException e) {
+ log.debug("Interrupted while taking from updates queue", e);
+ interrupted = true;
+ } catch (Exception e) {
+ log.debug("exception", e);
+ }
+ }
+ } finally {
+ if (interrupted) {
+ Thread.currentThread().interrupt();
+ }
+ }
}
@Override
- public void topologyChanged() {
- //There seems to be more topology events than there should be. Lots of link
- //updated, port up and switch updated on what should be a fairly static topology
+ public void topologyChanged() {
+ if (topologyReady) {
+ return;
+ }
boolean refreshNeeded = false;
for (LDUpdate ldu : topology.getLastLinkUpdates()){
if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
//We don't need to recalculate anything for just link updates
- //They happen way too frequently (may be a bug in our link discovery)
+ //They happen very frequently
refreshNeeded = true;
}
@@ -941,21 +1163,22 @@
}
}
- if (refreshNeeded){
+ if (refreshNeeded && !topologyReady){
topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
}
}
- //TODO determine whether we need to listen for switch joins
@Override
public void addedSwitch(IOFSwitch sw) {
- //checkStatus();
+ if (!topologyReady) {
+ sw.clearAllFlowMods();
+ }
+
+ flowCache.switchConnected(sw);
}
@Override
- public void removedSwitch(IOFSwitch sw) {
- // TODO Auto-generated method stub
- }
+ public void removedSwitch(IOFSwitch sw) {}
@Override
public void switchPortChanged(Long switchId) {}
@@ -964,4 +1187,68 @@
public String getName() {
return "BgpRoute";
}
+
+ /*
+ * ILayer3InfoService methods
+ */
+
+ @Override
+ public boolean isInterfaceAddress(InetAddress address) {
+ Interface intf = interfacePtrie.match(new Prefix(address.getAddress(), 32));
+ return (intf != null && intf.getIpAddress().equals(address));
+ }
+
+ @Override
+ public boolean inConnectedNetwork(InetAddress address) {
+ Interface intf = interfacePtrie.match(new Prefix(address.getAddress(), 32));
+ return (intf != null && !intf.getIpAddress().equals(address));
+ }
+
+ @Override
+ public boolean fromExternalNetwork(long inDpid, short inPort) {
+ for (Interface intf : interfaces.values()) {
+ if (intf.getDpid() == inDpid && intf.getPort() == inPort) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public Interface getOutgoingInterface(InetAddress dstIpAddress) {
+ return interfacePtrie.match(new Prefix(dstIpAddress.getAddress(), 32));
+ }
+
+ @Override
+ public boolean hasLayer3Configuration() {
+ return !interfaces.isEmpty();
+ }
+
+ @Override
+ public MACAddress getRouterMacAddress() {
+ return bgpdMacAddress;
+ }
+
+ /*
+ * TODO This is a hack to get the REST API to work for ProxyArpManager.
+ * The REST API is currently tied to the Floodlight module system and we
+ * need to separate it to allow ONOS modules to use it. For now we will
+ * proxy calls through to the ProxyArpManager (which is not a Floodlight
+ * module) through this class which is a module.
+ */
+ @Override
+ public MACAddress getMacAddress(InetAddress ipAddress) {
+ return proxyArp.getMacAddress(ipAddress);
+ }
+
+ @Override
+ public void sendArpRequest(InetAddress ipAddress, IArpRequester requester,
+ boolean retry) {
+ proxyArp.sendArpRequest(ipAddress, requester, retry);
+ }
+
+ @Override
+ public List<String> getMappings() {
+ return proxyArp.getMappings();
+ }
}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRouteResource.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRouteResource.java
index 8355308..8403f71 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRouteResource.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRouteResource.java
@@ -1,6 +1,8 @@
package net.onrc.onos.ofcontroller.bgproute;
-import java.net.UnknownHostException;
+import java.util.Iterator;
+
+import net.onrc.onos.ofcontroller.bgproute.RibUpdate.Operation;
import org.restlet.resource.Delete;
import org.restlet.resource.Get;
@@ -13,20 +15,6 @@
protected static Logger log = LoggerFactory.getLogger(BgpRouteResource.class);
- private String addrToString(byte [] addr) {
- String str = "";
-
- for (int i = 0; i < 4; i++) {
- int val = (addr[i] & 0xff);
- str += val;
- if (i != 3)
- str += ".";
- }
-
- return str;
- }
-
- //@SuppressWarnings("unused")
@Get
public String get(String fmJson) {
String dest = (String) getRequestAttributes().get("dest");
@@ -36,72 +24,50 @@
if (dest != null) {
//TODO Needs to be changed to use the new RestClient.get().
-
-
- //Prefix p;
- //try {
- // p = new Prefix(dest, 32);
- //} catch (UnknownHostException e) {
- //if (p == null) {
- // return "[GET]: dest address format is wrong";
- //}
// the dest here refers to router-id
//bgpdRestIp includes port number, such as 1.1.1.1:8080
String BGPdRestIp = bgpRoute.getBGPdRestIp();
String url="http://"+BGPdRestIp+"/wm/bgp/"+dest;
- RestClient.get(url);
+ //Doesn't actually do anything with the response
+ RestClient.get(url);
output="Get rib from bgpd finished!\n";
return output;
}
else {
- Ptree ptree = bgpRoute.getPtree();
+ IPatriciaTrie<RibEntry> ptree = bgpRoute.getPtree();
output += "{\n \"rib\": [\n";
boolean printed = false;
- for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
- if (node.rib == null) {
- continue;
+ synchronized(ptree) {
+ Iterator<IPatriciaTrie.Entry<RibEntry>> it = ptree.iterator();
+ while (it.hasNext()) {
+ IPatriciaTrie.Entry<RibEntry> entry = it.next();
+
+ if (printed == true) {
+ output += ",\n";
+ }
+
+ output += " {\"prefix\": \"" + entry.getPrefix() +"\", ";
+ output += "\"nexthop\": \"" + entry.getValue().getNextHop().getHostAddress() +"\"}";
+
+ printed = true;
}
- if (printed == true) {
- output += ",\n";
- }
- output += " {\"prefix\": \"" + addrToString(node.key) + "/" + node.keyBits +"\", ";
- output += "\"nexthop\": \"" + addrToString(node.rib.nextHop.getAddress()) +"\"}";
- printed = true;
}
- //output += "{\"router_id\": \"" + addrToString(node.rib.routerId.getAddress()) +"\"}\n";
+
output += "\n ]\n}\n";
}
return output;
}
- //unused?
- /*
- public static ByteBuffer toByteBuffer(String value) throws UnsupportedEncodingException {
- return ByteBuffer.wrap(value.getBytes("UTF-8"));
- }
- */
-
- //unused?
- /*
- public static String toString(ByteBuffer buffer) throws UnsupportedEncodingException {
- byte[] bytes = new byte[buffer.remaining()];
- buffer.get(bytes);
- return new String(bytes, "UTF-8");
- }
- */
-
@Post
public String store(String fmJson) {
IBgpRouteService bgpRoute = (IBgpRouteService) getContext().getAttributes().
get(IBgpRouteService.class.getCanonicalName());
- Ptree ptree = bgpRoute.getPtree();
-
String routerId = (String) getRequestAttributes().get("routerid");
String prefix = (String) getRequestAttributes().get("prefix");
String mask = (String) getRequestAttributes().get("mask");
@@ -119,22 +85,15 @@
reply = "[POST: mask format is wrong]";
log.info(reply);
return reply + "\n";
- } catch (UnknownHostException e1) {
+ } catch (IllegalArgumentException e1) {
reply = "[POST: prefix format is wrong]";
log.info(reply);
return reply + "\n";
}
- PtreeNode node = ptree.acquire(p.getAddress(), p.masklen);
- Rib rib = new Rib(routerId, nexthop, p.masklen);
+ RibEntry rib = new RibEntry(routerId, nexthop);
- if (node.rib != null) {
- node.rib = null;
- ptree.delReference(node);
- }
- node.rib = rib;
-
- bgpRoute.prefixAdded(node);
+ bgpRoute.newRibUpdate(new RibUpdate(Operation.UPDATE, p, rib));
reply = "[POST: " + prefix + "/" + mask + ":" + nexthop + "]";
log.info(reply);
@@ -158,8 +117,6 @@
IBgpRouteService bgpRoute = (IBgpRouteService)getContext().getAttributes().
get(IBgpRouteService.class.getCanonicalName());
- Ptree ptree = bgpRoute.getPtree();
-
String routerId = (String) getRequestAttributes().get("routerid");
String prefix = (String) getRequestAttributes().get("prefix");
String mask = (String) getRequestAttributes().get("mask");
@@ -177,39 +134,22 @@
reply = "[DELE: mask format is wrong]";
log.info(reply);
return reply + "\n";
- } catch (UnknownHostException e1) {
+ } catch (IllegalArgumentException e1) {
reply = "[DELE: prefix format is wrong]";
log.info(reply);
return reply + "\n";
}
-
- PtreeNode node = ptree.lookup(p.getAddress(), p.masklen);
- //Remove the flows from the switches before the rib is lost
- //Theory: we could get a delete for a prefix not in the Ptree.
- //This would result in a null node being returned. We could get a delete for
- //a node that's not actually there, but is a aggregate node. This would result
- //in a non-null node with a null rib. Only a non-null node with a non-null
- //rib is an actual prefix in the Ptree.
- if (node != null && node.rib != null){
- bgpRoute.prefixDeleted(node);
- }
-
- Rib r = new Rib(routerId, nextHop, p.masklen);
-
- if (node != null && node.rib != null) {
- if (r.equals(node.rib)) {
- node.rib = null;
- ptree.delReference(node);
- }
- }
+ RibEntry r = new RibEntry(routerId, nextHop);
+
+ bgpRoute.newRibUpdate(new RibUpdate(Operation.DELETE, p, r));
reply =reply + "[DELE: " + prefix + "/" + mask + ":" + nextHop + "]";
}
else {
// clear the local rib: Ptree
bgpRoute.clearPtree();
- reply = "[DELE-capability: " + capability + "; The local Rib is cleared!]\n";
+ reply = "[DELE-capability: " + capability + "; The local RibEntry is cleared!]\n";
// to store the number in the top node of the Ptree
}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/Configuration.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/Configuration.java
index c3c8cbb..1d90edc 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/Configuration.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/Configuration.java
@@ -1,17 +1,20 @@
package net.onrc.onos.ofcontroller.bgproute;
+import java.util.Collections;
import java.util.List;
+import net.floodlightcontroller.util.MACAddress;
+
import org.codehaus.jackson.annotate.JsonProperty;
import org.openflow.util.HexString;
public class Configuration {
private long bgpdAttachmentDpid;
private short bgpdAttachmentPort;
+ private MACAddress bgpdMacAddress;
private List<String> switches;
private List<Interface> interfaces;
private List<BgpPeer> peers;
- //private Map<String, GatewayRouter> gateways;
public Configuration() {
// TODO Auto-generated constructor stub
@@ -34,9 +37,18 @@
public void setBgpdAttachmentPort(short bgpdAttachmentPort) {
this.bgpdAttachmentPort = bgpdAttachmentPort;
}
+
+ public MACAddress getBgpdMacAddress() {
+ return bgpdMacAddress;
+ }
+
+ @JsonProperty("bgpdMacAddress")
+ public void setBgpdMacAddress(String strMacAddress) {
+ this.bgpdMacAddress = MACAddress.valueOf(strMacAddress);
+ }
public List<String> getSwitches() {
- return switches;
+ return Collections.unmodifiableList(switches);
}
@JsonProperty("switches")
@@ -45,7 +57,7 @@
}
public List<Interface> getInterfaces() {
- return interfaces;
+ return Collections.unmodifiableList(interfaces);
}
@JsonProperty("interfaces")
@@ -54,7 +66,7 @@
}
public List<BgpPeer> getPeers() {
- return peers;
+ return Collections.unmodifiableList(peers);
}
@JsonProperty("bgpPeers")
@@ -62,14 +74,4 @@
this.peers = peers;
}
- /*
- public Map<String, GatewayRouter> getGateways() {
- return gateways;
- }
-
- @JsonProperty("gateways")
- public void setGateways(Map<String, GatewayRouter> gateways) {
- this.gateways = gateways;
- }*/
-
}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/FlowCache.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/FlowCache.java
new file mode 100644
index 0000000..d1cb578
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/FlowCache.java
@@ -0,0 +1,158 @@
+package net.onrc.onos.ofcontroller.bgproute;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import net.floodlightcontroller.core.IFloodlightProviderService;
+import net.floodlightcontroller.core.IOFSwitch;
+
+import org.openflow.protocol.OFFlowMod;
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFPort;
+import org.openflow.util.HexString;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FlowCache {
+ private static Logger log = LoggerFactory.getLogger(FlowCache.class);
+
+ private IFloodlightProviderService floodlightProvider;
+
+ private Map<Long, List<OFFlowMod>> flowCache;
+
+ private Comparator<OFFlowMod> cookieComparator = new Comparator<OFFlowMod>() {
+ @Override
+ public int compare(OFFlowMod fm1, OFFlowMod fm2) {
+ long difference = fm2.getCookie() - fm1.getCookie();
+
+ if (difference > 0) {
+ return 1;
+ }
+ else if (difference < 0) {
+ return -1;
+ }
+ else {
+ return 0;
+ }
+ }
+ };
+
+ public FlowCache(IFloodlightProviderService floodlightProvider) {
+ this.floodlightProvider = floodlightProvider;
+
+ flowCache = new HashMap<Long, List<OFFlowMod>>();
+ }
+
+ public synchronized void write(long dpid, OFFlowMod flowMod) {
+ List<OFFlowMod> flowModList = new ArrayList<OFFlowMod>(1);
+ flowModList.add(flowMod);
+ write(dpid, flowModList);
+ }
+
+ public synchronized void write(long dpid, List<OFFlowMod> flowMods) {
+ ensureCacheForSwitch(dpid);
+
+ List<OFFlowMod> clones = new ArrayList<OFFlowMod>(flowMods.size());
+
+ //Somehow the OFFlowMods we get passed in will change later on.
+ //No idea how this happens, but we can just clone to prevent problems
+ try {
+ for (OFFlowMod fm : flowMods) {
+ clones.add(fm.clone());
+ }
+ } catch (CloneNotSupportedException e) {
+ log.debug("Clone exception", e);
+ }
+
+ flowCache.get(dpid).addAll(clones);
+
+ IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
+
+ if (sw == null) {
+ log.debug("Switch not found when writing flow mods");
+ return;
+ }
+
+ List<OFMessage> msgList = new ArrayList<OFMessage>(clones.size());
+ msgList.addAll(clones);
+
+ try {
+ sw.write(msgList, null);
+ } catch (IOException e) {
+ log.error("Error writing to switch", e);
+ }
+
+
+ }
+
+ public synchronized void delete(long dpid, OFFlowMod flowMod) {
+ List<OFFlowMod> flowModList = new ArrayList<OFFlowMod>(1);
+ flowModList.add(flowMod);
+ delete(dpid, flowModList);
+ }
+
+ public synchronized void delete(long dpid, List<OFFlowMod> flowMods) {
+ ensureCacheForSwitch(dpid);
+
+ //Remove the flow mods from the cache first before we alter them
+ flowCache.get(dpid).removeAll(flowMods);
+
+ //Alter the original flow mods to make them delete flow mods
+ for (OFFlowMod fm : flowMods) {
+ fm.setCommand(OFFlowMod.OFPFC_DELETE_STRICT)
+ .setOutPort(OFPort.OFPP_NONE)
+ .setLengthU(OFFlowMod.MINIMUM_LENGTH);
+
+ fm.getActions().clear();
+ }
+
+ IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
+ if (sw == null) {
+ log.debug("Switch not found when writing flow mods");
+ return;
+ }
+
+ List<OFMessage> msgList = new ArrayList<OFMessage>(flowMods.size());
+ msgList.addAll(flowMods);
+
+ try {
+ sw.write(msgList, null);
+ } catch (IOException e) {
+ log.error("Error writing to switch", e);
+ }
+ }
+
+ //TODO can the Prontos handle being sent all flow mods in one message?
+ public synchronized void switchConnected(IOFSwitch sw) {
+ log.debug("Switch connected: {}", sw);
+
+ ensureCacheForSwitch(sw.getId());
+
+ List<OFFlowMod> flowMods = flowCache.get(sw.getId());
+
+ Collections.sort(flowMods, cookieComparator);
+
+ sw.clearAllFlowMods();
+
+ List<OFMessage> messages = new ArrayList<OFMessage>(flowMods.size());
+ messages.addAll(flowMods);
+
+ try {
+ sw.write(messages, null);
+ } catch (IOException e) {
+ log.error("Failure writing flow mods to switch {}",
+ HexString.toHexString(sw.getId()));
+ }
+ }
+
+ private void ensureCacheForSwitch(long dpid) {
+ if (!flowCache.containsKey(dpid)) {
+ flowCache.put(dpid, new ArrayList<OFFlowMod>());
+ }
+ }
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/GatewayRouter.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/GatewayRouter.java
deleted file mode 100644
index e893acf..0000000
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/GatewayRouter.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package net.onrc.onos.ofcontroller.bgproute;
-
-import net.floodlightcontroller.util.MACAddress;
-import net.onrc.onos.ofcontroller.util.Dpid;
-import net.onrc.onos.ofcontroller.util.IPv4;
-import net.onrc.onos.ofcontroller.util.Port;
-import net.onrc.onos.ofcontroller.util.SwitchPort;
-
-import org.codehaus.jackson.annotate.JsonProperty;
-import org.openflow.util.HexString;
-
-public class GatewayRouter {
- private SwitchPort attachmentPoint = null;
- private long dpid;
- private short port;
- private MACAddress routerMac;
- private IPv4 routerIp;
- private IPv4 myIpAddress;
-
-
- public SwitchPort getAttachmentPoint() {
- if (attachmentPoint == null){
- attachmentPoint = new SwitchPort(new Dpid(dpid), new Port(port));
- }
- return attachmentPoint;
- }
-
- public long getDpid() {
- return dpid;
- }
-
- @JsonProperty("attachmentDpid")
- public void setDpid(String dpid) {
- this.dpid = HexString.toLong(dpid);
- }
-
- public short getPort() {
- return port;
- }
-
- @JsonProperty("attachmentPort")
- public void setPort(short port) {
- this.port = port;
- }
-
- public MACAddress getRouterMac() {
- return routerMac;
- }
-
- @JsonProperty("macAddress")
- public void setRouterMac(String routerMac) {
- this.routerMac = MACAddress.valueOf(routerMac);;
- }
-
- public IPv4 getRouterIp() {
- return routerIp;
- }
-
- @JsonProperty("ipAddress")
- public void setRouterIp(String routerIp) {
- this.routerIp = new IPv4(routerIp);
- }
-
- public IPv4 getMyIpAddress() {
- return myIpAddress;
- }
-
- @JsonProperty("myIpAddress")
- public void setMyIpAddress(String myIpAddress) {
- this.myIpAddress = new IPv4(myIpAddress);
- }
-}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/IBgpRouteService.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/IBgpRouteService.java
index c84a415..954976c 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/IBgpRouteService.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/IBgpRouteService.java
@@ -4,9 +4,10 @@
public interface IBgpRouteService extends IFloodlightService {
- public Rib lookupRib(byte[] dest);
+ //public RibEntry lookupRib(byte[] dest);
- public Ptree getPtree();
+ //public Ptree getPtree();
+ public IPatriciaTrie<RibEntry> getPtree();
public String getBGPdRestIp();
@@ -14,7 +15,13 @@
public void clearPtree();
+ /**
+ * Pass a RIB update to the {@link IBgpRouteService}
+ * @param update
+ */
+ public void newRibUpdate(RibUpdate update);
+
//TODO This functionality should be provided by some sort of Ptree listener framework
- public void prefixAdded(PtreeNode node);
- public void prefixDeleted(PtreeNode node);
+ //public void prefixAdded(PtreeNode node);
+ //public void prefixDeleted(PtreeNode node);
}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/ILayer3InfoService.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/ILayer3InfoService.java
new file mode 100644
index 0000000..00ddd68
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/ILayer3InfoService.java
@@ -0,0 +1,35 @@
+package net.onrc.onos.ofcontroller.bgproute;
+
+import java.net.InetAddress;
+
+import net.floodlightcontroller.util.MACAddress;
+
+/**
+ * Provides information about the layer 3 properties of the network.
+ * This is based on IP addresses configured on ports in the network.
+ *
+ */
+public interface ILayer3InfoService {
+ public boolean isInterfaceAddress(InetAddress address);
+ public boolean inConnectedNetwork(InetAddress address);
+ public boolean fromExternalNetwork(long inDpid, short inPort);
+
+ /**
+ * Retrieves the {@link Interface} object for the interface that packets
+ * to dstIpAddress will be sent out of. Returns null if dstIpAddress is not
+ * in a directly connected network, or if no interfaces are configured.
+ * @param dstIpAddress Destination IP address that we want to match to
+ * an outgoing interface
+ * @return The {@link Interface} object if found, null if not
+ */
+ public Interface getOutgoingInterface(InetAddress dstIpAddress);
+
+ /**
+ * Returns whether this controller has a layer 3 configuration
+ * (i.e. interfaces and IP addresses)
+ * @return True if IP addresses are configured, false if not
+ */
+ public boolean hasLayer3Configuration();
+
+ public MACAddress getRouterMacAddress();
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/IPatriciaTrie.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/IPatriciaTrie.java
new file mode 100644
index 0000000..1fb0716
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/IPatriciaTrie.java
@@ -0,0 +1,20 @@
+package net.onrc.onos.ofcontroller.bgproute;
+
+import java.util.Iterator;
+
+public interface IPatriciaTrie<V> {
+ public V put(Prefix prefix, V value);
+
+ public V lookup(Prefix prefix);
+
+ public V match(Prefix prefix);
+
+ public boolean remove(Prefix prefix, V value);
+
+ public Iterator<Entry<V>> iterator();
+
+ interface Entry<V> {
+ public Prefix getPrefix();
+ public V getValue();
+ }
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/Interface.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/Interface.java
index 088c18e..48b60d8 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/Interface.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/Interface.java
@@ -6,68 +6,57 @@
import net.onrc.onos.ofcontroller.util.Port;
import net.onrc.onos.ofcontroller.util.SwitchPort;
+import org.codehaus.jackson.annotate.JsonCreator;
import org.codehaus.jackson.annotate.JsonProperty;
import org.openflow.util.HexString;
import com.google.common.net.InetAddresses;
public class Interface {
- private String name;
- private SwitchPort switchPort = null;
- private long dpid;
- private short port;
- private InetAddress ipAddress;
- private int prefixLength;
+ private final String name;
+ private final SwitchPort switchPort;
+ private final long dpid;
+ private final short port;
+ private final InetAddress ipAddress;
+ private final int prefixLength;
+
+ @JsonCreator
+ public Interface (@JsonProperty("name") String name,
+ @JsonProperty("dpid") String dpid,
+ @JsonProperty("port") short port,
+ @JsonProperty("ipAddress") String ipAddress,
+ @JsonProperty("prefixLength") int prefixLength) {
+ this.name = name;
+ this.dpid = HexString.toLong(dpid);
+ this.port = port;
+ this.ipAddress = InetAddresses.forString(ipAddress);
+ this.prefixLength = prefixLength;
+ this.switchPort = new SwitchPort(new Dpid(this.dpid), new Port(this.port));
+ }
public String getName() {
return name;
}
- @JsonProperty("name")
- public void setName(String name) {
- this.name = name;
- }
-
- public synchronized SwitchPort getSwitchPort() {
- if (switchPort == null){
- switchPort = new SwitchPort(new Dpid(dpid), new Port(port));
- }
- return switchPort;
+ public SwitchPort getSwitchPort() {
+ //TODO SwitchPort, Dpid and Port are mutable, but they could probably
+ //be made immutable which would prevent the need to copy
+ return new SwitchPort(new Dpid(dpid), new Port(port));
}
public long getDpid() {
return dpid;
}
- @JsonProperty("dpid")
- public void setDpid(String dpid) {
- this.dpid = HexString.toLong(dpid);
- }
-
public short getPort() {
return port;
}
- @JsonProperty("port")
- public void setPort(short port) {
- this.port = port;
- }
-
public InetAddress getIpAddress() {
return ipAddress;
}
- @JsonProperty("ipAddress")
- public void setIpAddress(String ipAddress) {
- this.ipAddress = InetAddresses.forString(ipAddress);
- }
-
public int getPrefixLength() {
return prefixLength;
}
-
- @JsonProperty("prefixLength")
- public void setPrefixLength(int prefixLength) {
- this.prefixLength = prefixLength;
- }
}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/Path.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/Path.java
new file mode 100644
index 0000000..5cf4b09
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/Path.java
@@ -0,0 +1,61 @@
+package net.onrc.onos.ofcontroller.bgproute;
+
+import java.net.InetAddress;
+import java.util.Collections;
+import java.util.List;
+
+/*
+ * A path is always assumed to be from all other interfaces (external-facing
+ * switchports) to the destination interface.
+ */
+
+public class Path {
+
+ private Interface dstInterface;
+ private InetAddress dstIpAddress;
+ private int numUsers = 0;
+
+ private List<PushedFlowMod> flowMods = null;
+ private boolean permanent = false;
+
+ public Path(Interface dstInterface, InetAddress dstIpAddress) {
+ this.dstInterface = dstInterface;
+ this.dstIpAddress = dstIpAddress;
+ }
+
+ public Interface getDstInterface() {
+ return dstInterface;
+ }
+
+ public InetAddress getDstIpAddress() {
+ return dstIpAddress;
+ }
+
+ public void incrementUsers() {
+ numUsers++;
+ }
+
+ public void decrementUsers() {
+ numUsers--;
+ }
+
+ public int getUsers() {
+ return numUsers;
+ }
+
+ public List<PushedFlowMod> getFlowMods() {
+ return Collections.unmodifiableList(flowMods);
+ }
+
+ public void setFlowMods(List<PushedFlowMod> flowMods) {
+ this.flowMods = flowMods;
+ }
+
+ public boolean isPermanent() {
+ return permanent;
+ }
+
+ public void setPermanent() {
+ permanent = true;
+ }
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/PatriciaTrie.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/PatriciaTrie.java
new file mode 100644
index 0000000..89dfb30
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/PatriciaTrie.java
@@ -0,0 +1,506 @@
+package net.onrc.onos.ofcontroller.bgproute;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+public class PatriciaTrie<V> implements IPatriciaTrie<V> {
+ private final byte maskBits[] = {(byte)0x00, (byte)0x80, (byte)0xc0, (byte)0xe0, (byte)0xf0,
+ (byte)0xf8, (byte)0xfc, (byte)0xfe, (byte)0xff};
+
+ private int maxPrefixLength;
+
+ private Node top;
+
+ public PatriciaTrie(int maxPrefixLength) {
+ this.maxPrefixLength = maxPrefixLength;
+ }
+
+ @Override
+ public synchronized V put(Prefix prefix, V value) {
+ if (prefix.getPrefixLength() > maxPrefixLength) {
+ throw new IllegalArgumentException(String.format(
+ "Prefix length %d is greater than max prefix length %d",
+ prefix.getPrefixLength(), maxPrefixLength));
+ }
+
+ if (prefix == null || value == null) {
+ throw new NullPointerException();
+ }
+
+ Node node = top;
+ Node match = null;
+
+ while (node != null
+ && node.prefix.getPrefixLength() <= prefix.getPrefixLength()
+ && key_match(node.prefix.getAddress(), node.prefix.getPrefixLength(), prefix.getAddress(), prefix.getPrefixLength()) == true) {
+ if (node.prefix.getPrefixLength() == prefix.getPrefixLength()) {
+ /*
+ * Prefix is already in tree. This may be an aggregate node, in which case
+ * we are inserting a new prefix, or it could be an actual node, in which
+ * case we are inserting a new nexthop for the prefix and should return
+ * the old nexthop.
+ */
+ V oldValue = node.value;
+ node.value = value;
+ return oldValue;
+ }
+
+ match = node;
+
+ if (bit_check(prefix.getAddress(), node.prefix.getPrefixLength()) == true) {
+ node = node.right;
+ } else {
+ node = node.left;
+ }
+ }
+
+ Node add = null;
+
+ if (node == null) {
+ //add = new Node(p, r);
+ add = new Node(prefix);
+ add.value = value;
+
+ if (match != null) {
+ node_link(match, add);
+ } else {
+ top = add;
+ }
+ } else {
+ add = node_common(node, prefix.getAddress(), prefix.getPrefixLength());
+ if (add == null) {
+ //I think this is -ENOMEM?
+ //return null;
+ }
+
+ if (match != null) {
+ node_link(match, add);
+ } else {
+ top = add;
+ }
+ node_link(add, node);
+
+ if (add.prefix.getPrefixLength() != prefix.getPrefixLength()) {
+ match = add;
+
+ //add = new Node(p, r);
+ add = new Node(prefix);
+ add.value = value;
+ node_link(match, add);
+ }
+ else {
+ add.value = value;
+ }
+ }
+
+ //If we added a new Node, there was no previous mapping
+ return null;
+ //return addReference(add);
+ }
+
+ /*exact match*/
+ @Override
+ public synchronized V lookup(Prefix prefix) {
+ if (prefix.getPrefixLength() > maxPrefixLength) {
+ return null;
+ }
+
+ /*
+ Node node = top;
+
+ while (node != null
+ && node.prefix.getPrefixLength() <= p.getPrefixLength()
+ && key_match(node.prefix.getAddress(), node.prefix.getPrefixLength(), p.getAddress(), p.getPrefixLength()) == true) {
+ if (node.prefix.getPrefixLength() == p.getPrefixLength()) {
+ //return addReference(node);
+ return node.rib;
+ }
+
+ if (bit_check(p.getAddress(), node.prefix.getPrefixLength()) == true) {
+ node = node.right;
+ } else {
+ node = node.left;
+ }
+ }
+ */
+
+ Node node = findNode(prefix);
+
+ return node == null ? null : node.value;
+ }
+
+ /*closest containing prefix*/
+ @Override
+ public synchronized V match(Prefix prefix) {
+ //TODO
+ if (prefix.getPrefixLength() > maxPrefixLength) {
+ return null;
+ }
+
+ Node closestNode = findClosestNode(prefix);
+
+ return closestNode == null ? null : closestNode.value;
+ }
+
+ @Override
+ public synchronized boolean remove(Prefix prefix, V value) {
+ Node child;
+ Node parent;
+
+ if (prefix == null || value == null) {
+ return false;
+ }
+
+ Node node = findNode(prefix);
+
+ if (node == null || node.isAggregate() || !node.value.equals(value)) {
+ //Given <prefix, nexthop> mapping is not in the tree
+ return false;
+ }
+
+ if (node.left != null && node.right != null) {
+ //Remove the RibEntry entry and leave this node as an aggregate node
+ //In the future, maybe we should re-evaluate what the aggregate prefix should be?
+ //It shouldn't necessarily stay the same.
+ //More complicated if the above prefix is also aggregate.
+ node.value = null;
+ return true;
+ }
+
+ if (node.left != null) {
+ child = node.left;
+ } else {
+ child = node.right;
+ }
+
+ parent = node.parent;
+
+ if (child != null) {
+ child.parent = parent;
+ }
+
+ if (parent != null) {
+ if (parent.left == node) {
+ parent.left = child;
+ } else {
+ parent.right = child;
+ }
+ } else {
+ top = child;
+ }
+
+ /*
+ * TODO not sure what to do here. I think this is lazily deleting aggregate nodes,
+ * notice that it used to do nothing if it detected both children were not null earlier.
+ * But here, what we really should do is reevaluate the aggregate prefix of the parent
+ * node (if it is indeed an aggregate). Because at the moment, no aggregate node will ever
+ * be removed. BUT, I don't actually think this presents a correctness problem, at
+ * least from an external point of view.
+ */
+ //if (parent != null && parent.refCount == 0) {
+ //node_remove(parent);
+ //}
+
+ return true;
+ }
+
+ @Override
+ public Iterator<Entry<V>> iterator() {
+ return new PatriciaTrieIterator(top);
+ }
+
+ private Node findNode(Prefix prefix) {
+ Node node = top;
+
+ while (node != null
+ && node.prefix.getPrefixLength() <= prefix.getPrefixLength()
+ && key_match(node.prefix.getAddress(), node.prefix.getPrefixLength(), prefix.getAddress(), prefix.getPrefixLength()) == true) {
+ if (node.prefix.getPrefixLength() == prefix.getPrefixLength()) {
+ //return addReference(node);
+ return node;
+ }
+
+ if (bit_check(prefix.getAddress(), node.prefix.getPrefixLength()) == true) {
+ node = node.right;
+ } else {
+ node = node.left;
+ }
+ }
+
+ return null;
+ }
+
+ private Node findClosestNode(Prefix prefix) {
+ Node node = top;
+ Node match = null;
+
+ while (node != null
+ && node.prefix.getPrefixLength() <= prefix.getPrefixLength()
+ && key_match(node.prefix.getAddress(), node.prefix.getPrefixLength(), prefix.getAddress(), prefix.getPrefixLength()) == true) {
+ if (!node.isAggregate()) {
+ match = node;
+ }
+
+ if (bit_check(prefix.getAddress(), node.prefix.getPrefixLength()) == true) {
+ node = node.right;
+ } else {
+ node = node.left;
+ }
+ }
+
+ return match;
+ }
+
+ /*
+ * Receives a 1-based bit index
+ * Returns a 1-based byte index
+ * eg. (0 => 1), 1 => 1, 8 => 1, 9 => 2, 17 => 3
+ */
+ private int getByteContainingBit(int bitNumber) {
+ return Math.max((bitNumber + 7) / 8, 1);
+ }
+
+ private boolean key_match(byte [] key1, int key1_len, byte [] key2, int key2_len) {
+ //int offset;
+ //int shift;
+
+ if (key1_len > key2_len) {
+ return false;
+ }
+
+ int offset = (Math.min(key1_len, key2_len)) / 8;
+ int shift = (Math.min(key1_len, key2_len)) % 8;
+
+ if (shift != 0) {
+ if ((maskBits[shift] & (key1[offset] ^ key2[offset])) != 0) {
+ return false;
+ }
+ }
+
+ while (offset != 0) {
+ offset--;
+ if (key1[offset] != key2[offset]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean bit_check(byte [] key, int key_bits) {
+ int offset = key_bits / 8;
+ int shift = 7 - (key_bits % 8);
+ int bit = key[offset] & 0xff;
+
+ bit >>= shift;
+
+ if ((bit & 1) == 1) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private void node_link(Node node, Node add) {
+ boolean bit = bit_check(add.prefix.getAddress(), node.prefix.getPrefixLength());
+
+ if (bit == true) {
+ node.right = add;
+ } else {
+ node.left = add;
+ }
+ add.parent = node;
+ }
+
+ private Node node_common(Node node, byte [] key, int key_bits) {
+ int i;
+ int limit = Math.min(node.prefix.getPrefixLength(), key_bits) / 8;
+
+ for (i = 0; i < limit; i++) {
+ if (node.prefix.getAddress()[i] != key[i]) {
+ break;
+ }
+ }
+
+ int common_len = i * 8;
+ int boundary = 0;
+
+ if (common_len != key_bits) {
+ byte diff = (byte)(node.prefix.getAddress()[i] ^ key[i]);
+ byte mask = (byte)0x80;
+ int shift_mask = 0;
+
+ while (common_len < key_bits && ((mask & diff) == 0)) {
+ boundary = 1;
+
+ shift_mask = (mask & 0xff);
+ shift_mask >>= 1;
+ mask = (byte)shift_mask;
+
+ common_len++;
+ }
+ }
+
+ //Node add = new Node(null, common_len, maxKeyOctets);
+ //if (add == null)
+ //Another -ENOMEM;
+ //return null;
+
+ //Creating a new Prefix with a prefix length of common_len
+ //Bits are copied from node's up until the common_len'th bit
+ //RibEntry is null, because this is an aggregate prefix - it's not
+ //actually been added to the trie.
+
+ byte[] newPrefix = new byte[getByteContainingBit(maxPrefixLength)];
+
+ int j;
+ for (j = 0; j < i; j++)
+ newPrefix[j] = node.prefix.getAddress()[j];
+
+ if (boundary != 0)
+ newPrefix[j] = (byte)(node.prefix.getAddress()[j] & maskBits[common_len % 8]);
+
+ //return new Node(new Prefix(newPrefix, common_len), null);
+ return new Node(new Prefix(newPrefix, common_len));
+ //return add;
+ }
+
+ private class Node {
+ public Node parent = null;
+ public Node left = null;
+ public Node right = null;
+
+ public final Prefix prefix;
+ public V value;
+
+ //public Node(Prefix p, RibEntry r) {
+ // this.prefix = p;
+ // this.rib = r;
+ //}
+ public Node(Prefix p) {
+ this.prefix = p;
+ }
+
+ public boolean isAggregate() {
+ return value == null;
+ }
+
+ public Entry<V> getEntry() {
+ return new PatriciaTrieEntry(prefix, value);
+ }
+ }
+
+ private class PatriciaTrieEntry implements Entry<V> {
+ private Prefix prefix;
+ private V value;
+
+ public PatriciaTrieEntry(Prefix prefix, V value) {
+ this.prefix = prefix;
+ this.value = value;
+ }
+
+ @Override
+ public Prefix getPrefix() {
+ return prefix;
+ }
+
+ @Override
+ public V getValue() {
+ return value;
+ }
+ }
+
+ private class PatriciaTrieIterator implements Iterator<Entry<V>> {
+
+ private Node current;
+ private boolean started = false;
+
+ public PatriciaTrieIterator(Node start) {
+ current = start;
+
+ //If the start is an aggregate node fast forward to find the next valid node
+ if (current != null && current.isAggregate()) {
+ current = findNext(current);
+ }
+ }
+
+ @Override
+ public boolean hasNext() {
+ if (current == null) {
+ return false;
+ }
+
+ if (!started) {
+ return true;
+ }
+
+ return findNext(current) != null;
+ }
+
+ @Override
+ public Entry<V> next() {
+ if (current == null) {
+ throw new NoSuchElementException();
+ }
+
+ if (!started) {
+ started = true;
+ return current.getEntry();
+ }
+
+ current = findNext(current);
+ if (current == null) {
+ throw new NoSuchElementException();
+ }
+
+ return current.getEntry();
+ }
+
+ @Override
+ public void remove() {
+ // TODO This could be implemented, if it were needed
+ throw new NoSuchElementException();
+ }
+
+ private Node findNext(Node node) {
+ Node next = null;
+
+ if (node.left != null) {
+ next = node.left;
+ //addReference(next);
+ //delReference(node);
+ //return next;
+ }
+ else if (node.right != null) {
+ next = node.right;
+ //addReference(next);
+ //delReference(node);
+ //return next;
+ }
+ else {
+ //Node start = node;
+ while (node.parent != null) {
+ if (node.parent.left == node && node.parent.right != null) {
+ next = node.parent.right;
+ //addReference(next);
+ //delReference(start);
+ //return next;
+ break;
+ }
+ node = node.parent;
+ }
+ }
+
+ if (next == null) {
+ return null;
+ }
+
+ //If the node doesn't have a value, it's not an actual node, it's an artifically
+ //inserted aggregate node. We don't want to return these to the user.
+ if (next.isAggregate()) {
+ return findNext(next);
+ }
+
+ return next;
+ }
+ }
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/Prefix.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/Prefix.java
index c3baa37..05ce0a4 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/Prefix.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/Prefix.java
@@ -2,33 +2,134 @@
import java.net.InetAddress;
import java.net.UnknownHostException;
+import java.util.Arrays;
+
+import com.google.common.net.InetAddresses;
public class Prefix {
- public int masklen;
- protected InetAddress address;
+ private final int MAX_BYTES = 4;
+
+ private final int prefixLength;
+ private final byte[] address;
+
+ //For verifying the arguments and pretty printing
+ private final InetAddress inetAddress;
+
+ public Prefix(byte[] addr, int prefixLength) {
+ if (addr == null || addr.length != MAX_BYTES ||
+ prefixLength < 0 || prefixLength > MAX_BYTES * Byte.SIZE) {
+ throw new IllegalArgumentException();
+ }
- public Prefix(byte[] addr, int masklen) throws UnknownHostException {
- //try {
- address = InetAddress.getByAddress(addr);
- //} catch (UnknownHostException e) {
- // System.out.println("InetAddress exception");
- // return;
- //}
- this.masklen = masklen;
- //System.out.println(address.toString() + "/" + masklen);
+ address = canonicalizeAddress(addr, prefixLength);
+ this.prefixLength = prefixLength;
+
+ try {
+ inetAddress = InetAddress.getByAddress(address);
+ } catch (UnknownHostException e) {
+ throw new IllegalArgumentException();
+ }
}
- public Prefix(String str, int masklen) throws UnknownHostException {
- //try {
- address = InetAddress.getByName(str);
- //} catch (UnknownHostException e) {
- // System.out.println("InetAddress exception");
- // return;
- //}
- this.masklen = masklen;
+ public Prefix(String strAddress, int prefixLength) {
+ byte[] addr = null;
+ addr = InetAddresses.forString(strAddress).getAddress();
+
+ if (addr == null || addr.length != MAX_BYTES ||
+ prefixLength < 0 || prefixLength > MAX_BYTES * Byte.SIZE) {
+ throw new IllegalArgumentException();
+ }
+
+ address = canonicalizeAddress(addr, prefixLength);
+ this.prefixLength = prefixLength;
+
+ try {
+ inetAddress = InetAddress.getByAddress(address);
+ } catch (UnknownHostException e) {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ private byte[] canonicalizeAddress(byte[] address, int prefixLength) {
+ byte[] result = new byte[address.length];
+
+ if (prefixLength == 0) {
+ for (int i = 0; i < MAX_BYTES; i++) {
+ result[i] = 0;
+ }
+
+ return result;
+ }
+
+ result = Arrays.copyOf(address, address.length);
+
+ //Set all bytes after the end of the prefix to 0
+ int lastByteIndex = (prefixLength - 1) / Byte.SIZE;
+ for (int i = lastByteIndex; i < MAX_BYTES; i++) {
+ result[i] = 0;
+ }
+
+ byte lastByte = address[lastByteIndex];
+ byte mask = 0;
+ byte msb = (byte) 0x80;
+ int lastBit = (prefixLength - 1) % Byte.SIZE;
+ for (int i = 0; i < Byte.SIZE; i++) {
+ if (i <= lastBit) {
+ mask |= (msb >> i);
+ }
+ }
+
+ result[lastByteIndex] = (byte) (lastByte & mask);
+
+ return result;
}
- public byte [] getAddress() {
- return address.getAddress();
+ public int getPrefixLength() {
+ return prefixLength;
+ }
+
+ public byte[] getAddress() {
+ return address;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == null || !(other instanceof Prefix)) {
+ return false;
+ }
+
+ Prefix otherPrefix = (Prefix) other;
+
+ return (Arrays.equals(address, otherPrefix.address)) &&
+ (prefixLength == otherPrefix.prefixLength);
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 17;
+ hash = 31 * hash + prefixLength;
+ hash = 31 * hash + Arrays.hashCode(address);
+ return hash;
+ }
+
+ @Override
+ public String toString() {
+ return inetAddress.getHostAddress() + "/" + prefixLength;
+ }
+
+ public String printAsBits() {
+ String result = "";
+ for (int i = 0; i < address.length; i++) {
+ byte b = address[i];
+ for (int j = 0; j < Byte.SIZE; j++) {
+ byte mask = (byte) (0x80 >>> j);
+ result += ((b & mask) == 0)? "0" : "1";
+ if (i*Byte.SIZE+j == prefixLength-1) {
+ return result;
+ }
+ }
+ result += " ";
+ }
+ return result.substring(0, result.length() - 1);
}
}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/Ptree.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/Ptree.java
index 6741a41..041061c 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/Ptree.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/Ptree.java
@@ -1,24 +1,33 @@
package net.onrc.onos.ofcontroller.bgproute;
+/*
+ * TODO This Ptree needs to be refactored if we're going to use it permenantly.
+ *
+ * The biggest problem is it leaks PTreeNode references - these need to stay within
+ * the Ptree as they contain data fundamental to the structure of the tree.
+ * You should put RIB entries in and get RIB entries out.
+ * Also we need to get rid of the referencing scheme to determine when to delete nodes.
+ * Deletes should be explicit, and there's no need to keep track of references if
+ * we don't leak them out the the Ptree.
+ */
public class Ptree {
- int maxKeyBits;
- int maxKeyOctets;
- int refCount;
- PtreeNode top;
- byte maskBits[] = { (byte)0x00, (byte)0x80, (byte)0xc0, (byte)0xe0, (byte)0xf0, (byte)0xf8, (byte)0xfc, (byte)0xfe, (byte)0xff };
+ private int maxKeyBits;
+ private int maxKeyOctets;
+ //private int refCount;
+ private PtreeNode top;
+ private byte maskBits[] = { (byte)0x00, (byte)0x80, (byte)0xc0, (byte)0xe0, (byte)0xf0, (byte)0xf8, (byte)0xfc, (byte)0xfe, (byte)0xff };
- // Constructor.
- Ptree(int max_key_bits) {
+ public Ptree(int max_key_bits) {
maxKeyBits = max_key_bits;
maxKeyOctets = bit_to_octet(max_key_bits);
- refCount = 0;
+ //refCount = 0;
}
- public PtreeNode acquire(byte [] key) {
+ public synchronized PtreeNode acquire(byte [] key) {
return acquire(key, maxKeyBits);
}
- public PtreeNode acquire(byte [] key, int key_bits) {
+ public synchronized PtreeNode acquire(byte [] key, int key_bits) {
if (key_bits > maxKeyBits) {
return null;
}
@@ -76,7 +85,7 @@
return addReference(add);
}
- public PtreeNode lookup(byte [] key, int key_bits) {
+ public synchronized PtreeNode lookup(byte [] key, int key_bits) {
if (key_bits > maxKeyBits) {
return null;
}
@@ -99,7 +108,7 @@
return null;
}
- public PtreeNode match(byte [] key, int key_bits) {
+ public synchronized PtreeNode match(byte [] key, int key_bits) {
if (key_bits > maxKeyBits) {
return null;
}
@@ -127,14 +136,14 @@
return null;
}
- public PtreeNode begin() {
+ public synchronized PtreeNode begin() {
if (top == null) {
return null;
}
return addReference(top);
}
- public PtreeNode next(PtreeNode node) {
+ public synchronized PtreeNode next(PtreeNode node) {
PtreeNode next;
if (node.left != null) {
@@ -175,7 +184,7 @@
return node;
}
- public void delReference(PtreeNode node) {
+ public synchronized void delReference(PtreeNode node) {
if (node.refCount > 0) {
node.refCount--;
}
@@ -278,10 +287,6 @@
return add;
}
- //add by linpp
- private void clear() {
-
- }
private void node_remove(PtreeNode node) {
PtreeNode child;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/PtreeNode.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/PtreeNode.java
index a4d6996..50b7c7d 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/PtreeNode.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/PtreeNode.java
@@ -13,7 +13,7 @@
public int refCount;
- public Rib rib;
+ public RibEntry rib;
protected static Logger log = LoggerFactory.getLogger(BgpRoute.class);
PtreeNode(byte [] key, int key_bits, int max_key_octet) {
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/PushedFlowMod.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/PushedFlowMod.java
new file mode 100644
index 0000000..fd9ba6f
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/PushedFlowMod.java
@@ -0,0 +1,32 @@
+package net.onrc.onos.ofcontroller.bgproute;
+
+import org.openflow.protocol.OFFlowMod;
+
+/**
+ * Wraps up a DPID and a OFFlowMod so we know how to delete
+ * the flow if we have to.
+ *
+ * TODO This functionality should be handled by ONOS's flow layer in future.
+ *
+ */
+public class PushedFlowMod {
+ private long dpid;
+ private OFFlowMod flowMod;
+
+ public PushedFlowMod(long dpid, OFFlowMod flowMod) {
+ this.dpid = dpid;
+ try {
+ this.flowMod = flowMod.clone();
+ } catch (CloneNotSupportedException e) {
+ this.flowMod = flowMod;
+ }
+ }
+
+ public long getDpid() {
+ return dpid;
+ }
+
+ public OFFlowMod getFlowMod() {
+ return flowMod;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/Rib.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/Rib.java
deleted file mode 100644
index dc5f71d..0000000
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/Rib.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package net.onrc.onos.ofcontroller.bgproute;
-
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-
-public class Rib {
- protected InetAddress routerId;
- protected InetAddress nextHop;
- protected int masklen;
-// protected int distance;
-
- Rib(InetAddress router_id, InetAddress nexthop, int masklen) {
- this.routerId = router_id;
- this.nextHop = nexthop;
- this.masklen = masklen;
-// this.distance = distance;
- }
-
- Rib(String router_id, String nexthop, int masklen) {
- try {
- this.routerId = InetAddress.getByName(router_id);
- } catch (UnknownHostException e) {
- System.out.println("InetAddress exception");
- }
- try {
- this.nextHop = InetAddress.getByName(nexthop);
- } catch (UnknownHostException e) {
- System.out.println("InetAddress exception");
- }
- this.masklen = masklen;
- }
-
- public InetAddress getNextHop() {
- return nextHop;
- }
-
- public int getMasklen(){
- return masklen;
- }
-
- public boolean equals(Rib r) {
-
- return this.routerId.equals(r.routerId) && this.nextHop.equals(r.nextHop) && this.masklen == r.masklen;
-
- }
-}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/RibEntry.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/RibEntry.java
new file mode 100644
index 0000000..1520c60
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/RibEntry.java
@@ -0,0 +1,44 @@
+package net.onrc.onos.ofcontroller.bgproute;
+
+import java.net.InetAddress;
+
+import com.google.common.net.InetAddresses;
+
+public class RibEntry {
+ private final InetAddress routerId;
+ private final InetAddress nextHop;
+
+ public RibEntry(InetAddress routerId, InetAddress nextHop) {
+ this.routerId = routerId;
+ this.nextHop = nextHop;
+ }
+
+ public RibEntry(String routerId, String nextHop) {
+ this.routerId = InetAddresses.forString(routerId);
+ this.nextHop = InetAddresses.forString(nextHop);
+ }
+
+ public InetAddress getNextHop() {
+ return nextHop;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == null || !(other instanceof RibEntry)) {
+ return false;
+ }
+
+ RibEntry otherRibEntry = (RibEntry) other;
+
+ return this.routerId.equals(otherRibEntry.routerId)
+ && this.nextHop.equals(otherRibEntry.nextHop);
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 17;
+ hash = 31 * hash + routerId.hashCode();
+ hash = 31 * hash + nextHop.hashCode();
+ return hash;
+ }
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/RibUpdate.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/RibUpdate.java
new file mode 100644
index 0000000..d866304
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/RibUpdate.java
@@ -0,0 +1,27 @@
+package net.onrc.onos.ofcontroller.bgproute;
+
+public class RibUpdate {
+ public enum Operation {UPDATE, DELETE};
+
+ private final Operation operation;
+ private final Prefix prefix;
+ private final RibEntry ribEntry;
+
+ public RibUpdate(Operation operation, Prefix prefix, RibEntry ribEntry) {
+ this.operation = operation;
+ this.prefix = prefix;
+ this.ribEntry = ribEntry;
+ }
+
+ public Operation getOperation() {
+ return operation;
+ }
+
+ public Prefix getPrefix() {
+ return prefix;
+ }
+
+ public RibEntry getRibEntry() {
+ return ribEntry;
+ }
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjects.java b/src/main/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjects.java
index 04f9384..7b38fef 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjects.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjects.java
@@ -8,7 +8,6 @@
import com.tinkerpop.blueprints.Direction;
import com.tinkerpop.frames.Adjacency;
-import com.tinkerpop.frames.Incidence;
import com.tinkerpop.frames.Property;
import com.tinkerpop.frames.annotations.gremlin.GremlinGroovy;
import com.tinkerpop.frames.annotations.gremlin.GremlinParam;
@@ -200,6 +199,13 @@
@Property("installer_id")
public void setInstallerId(String installerId);
+ @JsonProperty("flowPathFlags")
+ @Property("flow_path_flags")
+ public Long getFlowPathFlags();
+
+ @Property("flow_path_flags")
+ public void setFlowPathFlags(Long flowPathFlags);
+
@JsonProperty("srcDpid")
@Property("src_switch")
public String getSrcSwitch();
@@ -246,6 +252,9 @@
@Adjacency(label="flow", direction=Direction.IN)
public void removeFlowEntry(final IFlowEntry flowEntry);
+ //
+ // Matching fields
+ //
@JsonIgnore
@Property("matchSrcMac")
public String getMatchSrcMac();
@@ -323,6 +332,18 @@
@Property("matchDstTcpUdpPort")
public void setMatchDstTcpUdpPort(Short matchDstTcpUdpPort);
+ //
+ // Action-related fields
+ //
+ @Property("actions")
+ public String getActions();
+
+ @Property("actions")
+ public void setActions(String actionsStr);
+
+ //
+ // Other fields
+ //
@JsonIgnore
@GremlinGroovy("it.in('flow').out('switch')")
public Iterable<ISwitchObject> getSwitches();
@@ -376,6 +397,9 @@
@Property("error_state_code")
public void setErrorStateCode(String errorStateCode);
+ //
+ // Matching fields
+ //
@Property("matchInPort")
public Short getMatchInPort();
@@ -448,12 +472,24 @@
@Property("matchDstTcpUdpPort")
public void setMatchDstTcpUdpPort(Short matchDstTcpUdpPort);
- @Property("actionOutput")
- public Short getActionOutput();
+ //
+ // Action-related fields
+ //
+ @Property("actionOutputPort")
+ public Short getActionOutputPort();
- @Property("actionOutput")
- public void setActionOutput(Short actionOutput);
+ @Property("actionOutputPort")
+ public void setActionOutputPort(Short actionOutputPort);
+ @Property("actions")
+ public String getActions();
+
+ @Property("actions")
+ public void setActions(String actionsStr);
+
+ //
+ // Other fields
+ //
@Adjacency(label="flow")
public IFlowPath getFlow();
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/INetMapTopologyService.java b/src/main/java/net/onrc/onos/ofcontroller/core/INetMapTopologyService.java
index 1992624..954515b 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/core/INetMapTopologyService.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/INetMapTopologyService.java
@@ -83,7 +83,7 @@
* See the documentation for method @ref prepareShortestPathTopo()
* for additional information and usage.
*
- * @shortestPathTopo the Shortest Path info handler to release.
+ * @param shortestPathTopo the Shortest Path info handler to release.
*/
void dropShortestPathTopo(Map<Long, ?> shortestPathTopo);
@@ -95,7 +95,7 @@
* See the documentation for method @ref prepareShortestPathTopo()
* for additional information and usage.
*
- * @paran shortestPathTopoHandler the Shortest Path info handler
+ * @param shortestPathTopo the Shortest Path info handler
* to use.
* @param src the source in the shortest path computation.
* @param dest the destination in the shortest path computation.
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/ISwitchStorage.java b/src/main/java/net/onrc/onos/ofcontroller/core/ISwitchStorage.java
index a4dd528..4fcebb2 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/core/ISwitchStorage.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/ISwitchStorage.java
@@ -1,8 +1,5 @@
package net.onrc.onos.ofcontroller.core;
-import java.util.Collection;
-
-
import net.floodlightcontroller.core.IOFSwitch;
import org.openflow.protocol.OFPhysicalPort;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/internal/LinkStorageImpl.java b/src/main/java/net/onrc/onos/ofcontroller/core/internal/LinkStorageImpl.java
index 6e42771..e5f2f58 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/core/internal/LinkStorageImpl.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/internal/LinkStorageImpl.java
@@ -15,10 +15,7 @@
import org.slf4j.LoggerFactory;
import com.thinkaurelius.titan.core.TitanException;
-import com.tinkerpop.blueprints.Direction;
-import com.tinkerpop.blueprints.Edge;
import com.tinkerpop.blueprints.Vertex;
-import com.tinkerpop.gremlin.java.GremlinPipeline;
import com.tinkerpop.pipes.PipeFunction;
import com.tinkerpop.pipes.transform.PathPipe;
@@ -142,7 +139,7 @@
/**
* Delete a record in the LinkStorage.
- * @param link Record to be deleted.
+ * @param lt Record to be deleted.
*/
@Override
public void deleteLink(Link lt) {
@@ -207,7 +204,7 @@
IPortObject srcPort = dbop.searchPort(HexString.toHexString(dpid), port);
ISwitchObject srcSw = srcPort.getSwitch();
- if(srcSw != null) {
+ if(srcSw != null && srcPort != null) {
for(IPortObject dstPort : srcPort.getLinkedPorts()) {
ISwitchObject dstSw = dstPort.getSwitch();
Link link = new Link(HexString.toLong(srcSw.getDPID()),
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/internal/SwitchStorageImpl.java b/src/main/java/net/onrc/onos/ofcontroller/core/internal/SwitchStorageImpl.java
index 126efb3..b7c97f8 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/core/internal/SwitchStorageImpl.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/internal/SwitchStorageImpl.java
@@ -167,7 +167,11 @@
IPortObject p = op.searchPort(dpid, port.getPortNumber());
log.info("SwitchStorage:addPort dpid:{} port:{}", dpid, port.getPortNumber());
if (p != null) {
- log.error("SwitchStorage:addPort dpid:{} port:{} exists", dpid, port.getPortNumber());
+ log.error("SwitchStorage:addPort dpid:{} port:{} exists setting as ACTIVE", dpid, port.getPortNumber());
+ p.setState("ACTIVE");
+ p.setPortState(port.getState());
+ p.setDesc(port.getName());
+ op.commit();
} else {
p = op.newPort(dpid, port.getPortNumber());
p.setState("ACTIVE");
@@ -200,9 +204,8 @@
if (sw != null) {
IPortObject p = op.searchPort(dpid, port);
if (p != null) {
- log.info("SwitchStorage:deletePort dpid:{} port:{} found and deleted", dpid, port);
- sw.removePort(p);
- op.removePort(p);
+ log.info("SwitchStorage:deletePort dpid:{} port:{} found and set INACTIVE", dpid, port);
+ p.setState("INACTIVE");
op.commit();
}
}
@@ -224,6 +227,9 @@
IPortObject p = op.searchPort(dpid, port.getPortNumber());
if (p != null) {
log.error("SwitchStorage:addPort dpid:{} port:{} exists", dpid, port.getPortNumber());
+ p.setState("ACTIVE");
+ p.setPortState(port.getState());
+ p.setDesc(port.getName());
} else {
p = op.newPort(dpid, port.getPortNumber());
p.setState("ACTIVE");
diff --git a/src/main/java/net/onrc/onos/ofcontroller/floodlightlistener/NetworkGraphPublisher.java b/src/main/java/net/onrc/onos/ofcontroller/floodlightlistener/NetworkGraphPublisher.java
index 8c83a7c..e0ac4e1 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/floodlightlistener/NetworkGraphPublisher.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/floodlightlistener/NetworkGraphPublisher.java
@@ -127,19 +127,22 @@
public void linkDiscoveryUpdate(LDUpdate update) {
// TODO Auto-generated method stub
Link lt = new Link(update.getSrc(),update.getSrcPort(),update.getDst(),update.getDstPort());
- log.debug("{}:LinkDicoveryUpdate(): Updating Link {}",this.getClass(), lt);
- switch (update.getOperation()) {
+ //log.debug("{}:LinkDicoveryUpdate(): Updating Link {}",this.getClass(), lt);
+ switch (update.getOperation()) {
case LINK_REMOVED:
+ log.debug("LinkDiscoveryUpdate(): Removing link {}", lt);
linkStore.update(lt, DM_OPERATION.DELETE);
// TODO: Move network map link removal here
// reconcile paths here
// IPortObject srcPort = conn.utils().searchPort(conn, HexString.toHexString(update.getSrc()), update.getSrcPort());
break;
case LINK_UPDATED:
+ log.debug("LinkDiscoveryUpdate(): Updating link {}", lt);
linkStore.update(lt, DM_OPERATION.UPDATE);
break;
case LINK_ADDED:
+ log.debug("LinkDiscoveryUpdate(): Adding link {}", lt);
linkStore.update(lt, DM_OPERATION.INSERT);
break;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowManager.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowManager.java
index ebef1f4..ce9941e 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowManager.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowManager.java
@@ -42,12 +42,15 @@
import net.onrc.onos.ofcontroller.util.Dpid;
import net.onrc.onos.ofcontroller.util.FlowEntry;
import net.onrc.onos.ofcontroller.util.FlowEntryAction;
+import net.onrc.onos.ofcontroller.util.FlowEntryAction.*;
+import net.onrc.onos.ofcontroller.util.FlowEntryActions;
import net.onrc.onos.ofcontroller.util.FlowEntryId;
import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
import net.onrc.onos.ofcontroller.util.FlowEntrySwitchState;
import net.onrc.onos.ofcontroller.util.FlowEntryUserState;
import net.onrc.onos.ofcontroller.util.FlowId;
import net.onrc.onos.ofcontroller.util.FlowPath;
+import net.onrc.onos.ofcontroller.util.FlowPathFlags;
import net.onrc.onos.ofcontroller.util.IPv4Net;
import net.onrc.onos.ofcontroller.util.Port;
import net.onrc.onos.ofcontroller.util.SwitchPort;
@@ -57,12 +60,13 @@
import org.openflow.protocol.OFPacketOut;
import org.openflow.protocol.OFPort;
import org.openflow.protocol.OFType;
-import org.openflow.protocol.action.OFAction;
-import org.openflow.protocol.action.OFActionOutput;
+import org.openflow.protocol.action.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-
+/**
+ * Flow Manager class for handling the network flows.
+ */
public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
protected GraphDBOperation op;
@@ -95,11 +99,6 @@
private static String measurementFlowIdStr = "0x186a0"; // 100000
private long modifiedMeasurementFlowTime = 0;
//
- private LinkedList<FlowPath> measurementStoredPaths = new LinkedList<FlowPath>();
- private long measurementStartTimeProcessingPaths = 0;
- private long measurementEndTimeProcessingPaths = 0;
- Map<Long, ?> measurementShortestPathTopo = null;
- private String measurementPerFlowStr = new String();
/** The logger. */
private static Logger log = LoggerFactory.getLogger(FlowManager.class);
@@ -108,6 +107,10 @@
private ScheduledExecutorService mapReaderScheduler;
private ScheduledExecutorService shortestPathReconcileScheduler;
+ /**
+ * Periodic task for reading the Flow Entries and pushing changes
+ * into the switches.
+ */
final Runnable mapReader = new Runnable() {
public void run() {
try {
@@ -130,6 +133,10 @@
}
Map<Long, IOFSwitch> mySwitches =
floodlightProvider.getSwitches();
+ if (mySwitches.isEmpty()) {
+ log.trace("No switches controlled");
+ return;
+ }
LinkedList<IFlowEntry> addFlowEntries =
new LinkedList<IFlowEntry>();
LinkedList<IFlowEntry> deleteFlowEntries =
@@ -248,6 +255,10 @@
}
};
+ /**
+ * Periodic task for reading the Flow Paths and recomputing the
+ * shortest paths.
+ */
final Runnable shortestPathReconcile = new Runnable() {
public void run() {
try {
@@ -270,6 +281,10 @@
}
Map<Long, IOFSwitch> mySwitches =
floodlightProvider.getSwitches();
+ if (mySwitches.isEmpty()) {
+ log.trace("No switches controlled");
+ return;
+ }
LinkedList<IFlowPath> deleteFlows = new LinkedList<IFlowPath>();
boolean processed_measurement_flow = false;
@@ -330,9 +345,11 @@
Short srcPortShort = flowPathObj.getSrcPort();
String dstDpidStr = flowPathObj.getDstSwitch();
Short dstPortShort = flowPathObj.getDstPort();
+ Long flowPathFlagsLong = flowPathObj.getFlowPathFlags();
if ((srcPortShort == null) ||
(dstDpidStr == null) ||
- (dstPortShort == null)) {
+ (dstPortShort == null) ||
+ (flowPathFlagsLong == null)) {
continue;
}
@@ -341,6 +358,7 @@
Port dstPort = new Port(dstPortShort);
SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
+ FlowPathFlags flowPathFlags = new FlowPathFlags(flowPathFlagsLong);
counterMyFlowPaths++;
@@ -363,6 +381,7 @@
dataPath.setSrcPort(srcSwitchPort);
dataPath.setDstPort(dstSwitchPort);
}
+ dataPath.applyFlowPathFlags(flowPathFlags);
String newDataPathSummaryStr = dataPath.dataPathSummary();
if (dataPathSummaryStr.equals(newDataPathSummaryStr))
@@ -405,27 +424,38 @@
}
};
- //final ScheduledFuture<?> mapReaderHandle =
- //mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
- //final ScheduledFuture<?> shortestPathReconcileHandle =
- //shortestPathReconcileScheduler.scheduleAtFixedRate(shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
-
+ /**
+ * Initialize the Flow Manager.
+ *
+ * @param conf the Graph Database configuration string.
+ */
@Override
public void init(String conf) {
op = new GraphDBOperation(conf);
topoRouteService = new TopoRouteService(conf);
}
+ /**
+ * Shutdown the Flow Manager operation.
+ */
public void finalize() {
close();
}
+ /**
+ * Shutdown the Flow Manager operation.
+ */
@Override
public void close() {
op.close();
}
+ /**
+ * Get the collection of offered module services.
+ *
+ * @return the collection of offered module services.
+ */
@Override
public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Collection<Class<? extends IFloodlightService>> l =
@@ -434,6 +464,11 @@
return l;
}
+ /**
+ * Get the collection of implemented services.
+ *
+ * @return the collection of implemented services.
+ */
@Override
public Map<Class<? extends IFloodlightService>, IFloodlightService>
getServiceImpls() {
@@ -445,6 +480,11 @@
return m;
}
+ /**
+ * Get the collection of modules this module depends on.
+ *
+ * @return the collection of modules this module depends on.
+ */
@Override
public Collection<Class<? extends IFloodlightService>>
getModuleDependencies() {
@@ -455,6 +495,11 @@
return l;
}
+ /**
+ * Initialize the module.
+ *
+ * @param context the module context to use for the initialization.
+ */
@Override
public void init(FloodlightModuleContext context)
throws FloodlightModuleException {
@@ -469,10 +514,15 @@
String conf = "/tmp/cassandra.titan";
this.init(conf);
- mapReaderScheduler = Executors.newScheduledThreadPool(1);
- shortestPathReconcileScheduler = Executors.newScheduledThreadPool(1);
+ mapReaderScheduler = Executors.newScheduledThreadPool(1);
+ shortestPathReconcileScheduler = Executors.newScheduledThreadPool(1);
}
+ /**
+ * Get the next Flow Entry ID to use.
+ *
+ * @return the next Flow Entry ID to use.
+ */
private synchronized long getNextFlowEntryId() {
//
// Generate the next Flow Entry ID.
@@ -491,17 +541,22 @@
return result;
}
+ /**
+ * Startup module operation.
+ *
+ * @param context the module context to use for the startup.
+ */
@Override
public void startUp(FloodlightModuleContext context) {
- restApi.addRestletRoutable(new FlowWebRoutable());
+ restApi.addRestletRoutable(new FlowWebRoutable());
- // Initialize the Flow Entry ID generator
- nextFlowEntryIdPrefix = randomGenerator.nextInt();
+ // Initialize the Flow Entry ID generator
+ nextFlowEntryIdPrefix = randomGenerator.nextInt();
- mapReaderScheduler.scheduleAtFixedRate(
- mapReader, 3, 3, TimeUnit.SECONDS);
- shortestPathReconcileScheduler.scheduleAtFixedRate(
- shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
+ mapReaderScheduler.scheduleAtFixedRate(
+ mapReader, 3, 3, TimeUnit.SECONDS);
+ shortestPathReconcileScheduler.scheduleAtFixedRate(
+ shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
}
/**
@@ -568,6 +623,7 @@
//
// Set the Flow attributes:
// - flowPath.installerId()
+ // - flowPath.flowPathFlags()
// - flowPath.dataPath().srcPort()
// - flowPath.dataPath().dstPort()
// - flowPath.matchSrcMac()
@@ -581,8 +637,10 @@
// - flowPath.matchIpToS()
// - flowPath.matchSrcTcpUdpPort()
// - flowPath.matchDstTcpUdpPort()
+ // - flowPath.flowEntryActions()
//
flowObj.setInstallerId(flowPath.installerId().toString());
+ flowObj.setFlowPathFlags(flowPath.flowPathFlags().flags());
flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
@@ -620,6 +678,9 @@
if (flowPath.flowEntryMatch().matchDstTcpUdpPort()) {
flowObj.setMatchDstTcpUdpPort(flowPath.flowEntryMatch().dstTcpUdpPort());
}
+ if (! flowPath.flowEntryActions().actions().isEmpty()) {
+ flowObj.setActions(flowPath.flowEntryActions().toString());
+ }
if (dataPathSummaryStr != null) {
flowObj.setDataPathSummary(dataPathSummaryStr);
@@ -713,8 +774,6 @@
// - InPort edge
// - OutPort edge
//
- // - flowEntry.flowEntryMatch()
- // - flowEntry.flowEntryActions()
// - flowEntry.dpid()
// - flowEntry.flowEntryUserState()
// - flowEntry.flowEntrySwitchState()
@@ -731,10 +790,10 @@
// - flowEntry.matchIpToS()
// - flowEntry.matchSrcTcpUdpPort()
// - flowEntry.matchDstTcpUdpPort()
- // - flowEntry.actionOutput()
+ // - flowEntry.actionOutputPort()
+ // - flowEntry.actions()
//
- ISwitchObject sw =
- op.searchSwitch(flowEntry.dpid().toString());
+ ISwitchObject sw = op.searchSwitch(flowEntry.dpid().toString());
flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
flowEntryObj.setSwitch(sw);
if (flowEntry.flowEntryMatch().matchInPort()) {
@@ -778,15 +837,19 @@
flowEntryObj.setMatchDstTcpUdpPort(flowEntry.flowEntryMatch().dstTcpUdpPort());
}
- for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
+ for (FlowEntryAction fa : flowEntry.flowEntryActions().actions()) {
if (fa.actionOutput() != null) {
IPortObject outport =
op.searchPort(flowEntry.dpid().toString(),
fa.actionOutput().port().value());
- flowEntryObj.setActionOutput(fa.actionOutput().port().value());
+ flowEntryObj.setActionOutputPort(fa.actionOutput().port().value());
flowEntryObj.setOutPort(outport);
}
}
+ if (! flowEntry.flowEntryActions().isEmpty()) {
+ flowEntryObj.setActions(flowEntry.flowEntryActions().toString());
+ }
+
// TODO: Hacks with hard-coded state names!
if (found)
flowEntryObj.setUserState("FE_USER_MODIFY");
@@ -1146,21 +1209,22 @@
}
/**
- * Get summary of all installed flows by all installers in a given range
+ * Get summary of all installed flows by all installers in a given range.
*
- * @param flowId the data path endpoints of the flows to get.
- * @param maxFlows: the maximum number of flows to be returned
+ * @param flowId the Flow ID of the first flow in the flow range to get.
+ * @param maxFlows the maximum number of flows to be returned.
* @return the Flow Paths if found, otherwise null.
*/
@Override
public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
- // TODO: The implementation below is not optimal:
- // We fetch all flows, and then return only the subset that match
- // the query conditions.
- // We should use the appropriate Titan/Gremlin query to filter-out
- // the flows as appropriate.
- //
+ //
+ // TODO: The implementation below is not optimal:
+ // We fetch all flows, and then return only the subset that match
+ // the query conditions.
+ // We should use the appropriate Titan/Gremlin query to filter-out
+ // the flows as appropriate.
+ //
//ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
ArrayList<IFlowPath> flowPathsWithoutFlowEntries = getAllFlowsWithoutFlowEntries();
@@ -1260,8 +1324,13 @@
return flowPaths;
}
-
- public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries(){
+
+ /**
+ * Get all Flows information, without the associated Flow Entries.
+ *
+ * @return all Flows information, without the associated Flow Entries.
+ */
+ public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries() {
Iterable<IFlowPath> flowPathsObj = null;
ArrayList<IFlowPath> flowPathsObjArray = new ArrayList<IFlowPath>();
ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
@@ -1314,6 +1383,7 @@
//
String flowIdStr = flowObj.getFlowId();
String installerIdStr = flowObj.getInstallerId();
+ Long flowPathFlags = flowObj.getFlowPathFlags();
String srcSwitchStr = flowObj.getSrcSwitch();
Short srcPortShort = flowObj.getSrcPort();
String dstSwitchStr = flowObj.getDstSwitch();
@@ -1321,6 +1391,7 @@
if ((flowIdStr == null) ||
(installerIdStr == null) ||
+ (flowPathFlags == null) ||
(srcSwitchStr == null) ||
(srcPortShort == null) ||
(dstSwitchStr == null) ||
@@ -1332,6 +1403,7 @@
FlowPath flowPath = new FlowPath();
flowPath.setFlowId(new FlowId(flowIdStr));
flowPath.setInstallerId(new CallerId(installerIdStr));
+ flowPath.setFlowPathFlags(new FlowPathFlags(flowPathFlags));
flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
@@ -1377,6 +1449,16 @@
flowPath.setFlowEntryMatch(match);
}
+ //
+ // Extract the actions for the first Flow Entry
+ //
+ {
+ String actionsStr = flowObj.getActions();
+ if (actionsStr != null) {
+ FlowEntryActions flowEntryActions = new FlowEntryActions(actionsStr);
+ flowPath.setFlowEntryActions(flowEntryActions);
+ }
+ }
//
// Extract all Flow Entries
@@ -1461,19 +1543,15 @@
//
// Extract the actions
//
- ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
- Short actionOutputPort = flowEntryObj.getActionOutput();
- if (actionOutputPort != null) {
- FlowEntryAction action = new FlowEntryAction();
- action.setActionOutput(new Port(actionOutputPort));
- actions.add(action);
- }
+ FlowEntryActions actions = new FlowEntryActions();
+ String actionsStr = flowEntryObj.getActions();
+ if (actionsStr != null)
+ actions = new FlowEntryActions(actionsStr);
flowEntry.setFlowEntryActions(actions);
flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
//
- // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
- // and FlowEntryErrorState.
+ // TODO: Take care of FlowEntryErrorState.
//
return flowEntry;
}
@@ -1505,8 +1583,10 @@
FlowPath computedFlowPath = new FlowPath();
computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
+ computedFlowPath.setFlowPathFlags(new FlowPathFlags(flowPath.flowPathFlags().flags()));
computedFlowPath.setDataPath(dataPath);
computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
+ computedFlowPath.setFlowEntryActions(new FlowEntryActions(flowPath.flowEntryActions()));
FlowId flowId = new FlowId();
String dataPathSummaryStr = dataPath.dataPathSummary();
@@ -1532,21 +1612,35 @@
// Set the incoming port matching and the outgoing port output
// actions for each flow entry.
//
+ int idx = 0;
for (FlowEntry flowEntry : newDataPath.flowEntries()) {
// Set the incoming port matching
FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
flowEntry.setFlowEntryMatch(flowEntryMatch);
flowEntryMatch.enableInPort(flowEntry.inPort());
- // Set the outgoing port output action
- ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
- if (flowEntryActions == null) {
- flowEntryActions = new ArrayList<FlowEntryAction>();
- flowEntry.setFlowEntryActions(flowEntryActions);
+ //
+ // Set the actions
+ //
+ FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
+ //
+ // If the first Flow Entry, copy the Flow Path actions to it
+ //
+ if (idx == 0) {
+ String actionsStr = flowObj.getActions();
+ if (actionsStr != null) {
+ FlowEntryActions flowActions = new FlowEntryActions(actionsStr);
+ for (FlowEntryAction action : flowActions.actions())
+ flowEntryActions.addAction(action);
+ }
}
+ idx++;
+ //
+ // Add the outgoing port output action
+ //
FlowEntryAction flowEntryAction = new FlowEntryAction();
flowEntryAction.setActionOutput(flowEntry.outPort());
- flowEntryActions.add(flowEntryAction);
+ flowEntryActions.addAction(flowEntryAction);
}
//
@@ -1738,16 +1832,115 @@
//
// Fetch the actions
//
- // TODO: For now we support only the "OUTPUT" actions.
- //
- List<OFAction> actions = new ArrayList<OFAction>();
- Short actionOutputPort = flowEntryObj.getActionOutput();
- if (actionOutputPort != null) {
- OFActionOutput action = new OFActionOutput();
- // XXX: The max length is hard-coded for now
- action.setMaxLength((short)0xffff);
- action.setPort(actionOutputPort);
- actions.add(action);
+ Short actionOutputPort = null;
+ List<OFAction> openFlowActions = new ArrayList<OFAction>();
+ int actionsLen = 0;
+ FlowEntryActions flowEntryActions = null;
+ String actionsStr = flowEntryObj.getActions();
+ if (actionsStr != null)
+ flowEntryActions = new FlowEntryActions(actionsStr);
+ for (FlowEntryAction action : flowEntryActions.actions()) {
+ ActionOutput actionOutput = action.actionOutput();
+ ActionSetVlanId actionSetVlanId = action.actionSetVlanId();
+ ActionSetVlanPriority actionSetVlanPriority = action.actionSetVlanPriority();
+ ActionStripVlan actionStripVlan = action.actionStripVlan();
+ ActionSetEthernetAddr actionSetEthernetSrcAddr = action.actionSetEthernetSrcAddr();
+ ActionSetEthernetAddr actionSetEthernetDstAddr = action.actionSetEthernetDstAddr();
+ ActionSetIPv4Addr actionSetIPv4SrcAddr = action.actionSetIPv4SrcAddr();
+ ActionSetIPv4Addr actionSetIPv4DstAddr = action.actionSetIPv4DstAddr();
+ ActionSetIpToS actionSetIpToS = action.actionSetIpToS();
+ ActionSetTcpUdpPort actionSetTcpUdpSrcPort = action.actionSetTcpUdpSrcPort();
+ ActionSetTcpUdpPort actionSetTcpUdpDstPort = action.actionSetTcpUdpDstPort();
+ ActionEnqueue actionEnqueue = action.actionEnqueue();
+
+ if (actionOutput != null) {
+ actionOutputPort = actionOutput.port().value();
+ // XXX: The max length is hard-coded for now
+ OFActionOutput ofa =
+ new OFActionOutput(actionOutput.port().value(),
+ (short)0xffff);
+ openFlowActions.add(ofa);
+ actionsLen += ofa.getLength();
+ }
+
+ if (actionSetVlanId != null) {
+ OFActionVirtualLanIdentifier ofa =
+ new OFActionVirtualLanIdentifier(actionSetVlanId.vlanId());
+ openFlowActions.add(ofa);
+ actionsLen += ofa.getLength();
+ }
+
+ if (actionSetVlanPriority != null) {
+ OFActionVirtualLanPriorityCodePoint ofa =
+ new OFActionVirtualLanPriorityCodePoint(actionSetVlanPriority.vlanPriority());
+ openFlowActions.add(ofa);
+ actionsLen += ofa.getLength();
+ }
+
+ if (actionStripVlan != null) {
+ if (actionStripVlan.stripVlan() == true) {
+ OFActionStripVirtualLan ofa = new OFActionStripVirtualLan();
+ openFlowActions.add(ofa);
+ actionsLen += ofa.getLength();
+ }
+ }
+
+ if (actionSetEthernetSrcAddr != null) {
+ OFActionDataLayerSource ofa =
+ new OFActionDataLayerSource(actionSetEthernetSrcAddr.addr().toBytes());
+ openFlowActions.add(ofa);
+ actionsLen += ofa.getLength();
+ }
+
+ if (actionSetEthernetDstAddr != null) {
+ OFActionDataLayerDestination ofa =
+ new OFActionDataLayerDestination(actionSetEthernetDstAddr.addr().toBytes());
+ openFlowActions.add(ofa);
+ actionsLen += ofa.getLength();
+ }
+
+ if (actionSetIPv4SrcAddr != null) {
+ OFActionNetworkLayerSource ofa =
+ new OFActionNetworkLayerSource(actionSetIPv4SrcAddr.addr().value());
+ openFlowActions.add(ofa);
+ actionsLen += ofa.getLength();
+ }
+
+ if (actionSetIPv4DstAddr != null) {
+ OFActionNetworkLayerDestination ofa =
+ new OFActionNetworkLayerDestination(actionSetIPv4DstAddr.addr().value());
+ openFlowActions.add(ofa);
+ actionsLen += ofa.getLength();
+ }
+
+ if (actionSetIpToS != null) {
+ OFActionNetworkTypeOfService ofa =
+ new OFActionNetworkTypeOfService(actionSetIpToS.ipToS());
+ openFlowActions.add(ofa);
+ actionsLen += ofa.getLength();
+ }
+
+ if (actionSetTcpUdpSrcPort != null) {
+ OFActionTransportLayerSource ofa =
+ new OFActionTransportLayerSource(actionSetTcpUdpSrcPort.port());
+ openFlowActions.add(ofa);
+ actionsLen += ofa.getLength();
+ }
+
+ if (actionSetTcpUdpDstPort != null) {
+ OFActionTransportLayerDestination ofa =
+ new OFActionTransportLayerDestination(actionSetTcpUdpDstPort.port());
+ openFlowActions.add(ofa);
+ actionsLen += ofa.getLength();
+ }
+
+ if (actionEnqueue != null) {
+ OFActionEnqueue ofa =
+ new OFActionEnqueue(actionEnqueue.port().value(),
+ actionEnqueue.queueId());
+ openFlowActions.add(ofa);
+ actionsLen += ofa.getLength();
+ }
}
fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
@@ -1757,8 +1950,8 @@
.setCookie(cookie)
.setCommand(flowModCommand)
.setMatch(match)
- .setActions(actions)
- .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
+ .setActions(openFlowActions)
+ .setLengthU(OFFlowMod.MINIMUM_LENGTH + actionsLen);
fm.setOutPort(OFPort.OFPP_NONE.getValue());
if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
(flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
@@ -1962,27 +2155,113 @@
//
// Fetch the actions
//
- // TODO: For now we support only the "OUTPUT" actions.
+ Short actionOutputPort = null;
+ List<OFAction> openFlowActions = new ArrayList<OFAction>();
+ int actionsLen = 0;
+ FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
//
- fm.setOutPort(OFPort.OFPP_NONE.getValue());
- List<OFAction> actions = new ArrayList<OFAction>();
- ArrayList<FlowEntryAction> flowEntryActions =
- flowEntry.flowEntryActions();
- for (FlowEntryAction flowEntryAction : flowEntryActions) {
- FlowEntryAction.ActionOutput actionOutput =
- flowEntryAction.actionOutput();
+ for (FlowEntryAction action : flowEntryActions.actions()) {
+ ActionOutput actionOutput = action.actionOutput();
+ ActionSetVlanId actionSetVlanId = action.actionSetVlanId();
+ ActionSetVlanPriority actionSetVlanPriority = action.actionSetVlanPriority();
+ ActionStripVlan actionStripVlan = action.actionStripVlan();
+ ActionSetEthernetAddr actionSetEthernetSrcAddr = action.actionSetEthernetSrcAddr();
+ ActionSetEthernetAddr actionSetEthernetDstAddr = action.actionSetEthernetDstAddr();
+ ActionSetIPv4Addr actionSetIPv4SrcAddr = action.actionSetIPv4SrcAddr();
+ ActionSetIPv4Addr actionSetIPv4DstAddr = action.actionSetIPv4DstAddr();
+ ActionSetIpToS actionSetIpToS = action.actionSetIpToS();
+ ActionSetTcpUdpPort actionSetTcpUdpSrcPort = action.actionSetTcpUdpSrcPort();
+ ActionSetTcpUdpPort actionSetTcpUdpDstPort = action.actionSetTcpUdpDstPort();
+ ActionEnqueue actionEnqueue = action.actionEnqueue();
+
if (actionOutput != null) {
- short actionOutputPort = actionOutput.port().value();
- OFActionOutput action = new OFActionOutput();
+ actionOutputPort = actionOutput.port().value();
// XXX: The max length is hard-coded for now
- action.setMaxLength((short)0xffff);
- action.setPort(actionOutputPort);
- actions.add(action);
- if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
- (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
- fm.setOutPort(actionOutputPort);
+ OFActionOutput ofa =
+ new OFActionOutput(actionOutput.port().value(),
+ (short)0xffff);
+ openFlowActions.add(ofa);
+ actionsLen += ofa.getLength();
+ }
+
+ if (actionSetVlanId != null) {
+ OFActionVirtualLanIdentifier ofa =
+ new OFActionVirtualLanIdentifier(actionSetVlanId.vlanId());
+ openFlowActions.add(ofa);
+ actionsLen += ofa.getLength();
+ }
+
+ if (actionSetVlanPriority != null) {
+ OFActionVirtualLanPriorityCodePoint ofa =
+ new OFActionVirtualLanPriorityCodePoint(actionSetVlanPriority.vlanPriority());
+ openFlowActions.add(ofa);
+ actionsLen += ofa.getLength();
+ }
+
+ if (actionStripVlan != null) {
+ if (actionStripVlan.stripVlan() == true) {
+ OFActionStripVirtualLan ofa = new OFActionStripVirtualLan();
+ openFlowActions.add(ofa);
+ actionsLen += ofa.getLength();
}
}
+
+ if (actionSetEthernetSrcAddr != null) {
+ OFActionDataLayerSource ofa =
+ new OFActionDataLayerSource(actionSetEthernetSrcAddr.addr().toBytes());
+ openFlowActions.add(ofa);
+ actionsLen += ofa.getLength();
+ }
+
+ if (actionSetEthernetDstAddr != null) {
+ OFActionDataLayerDestination ofa =
+ new OFActionDataLayerDestination(actionSetEthernetDstAddr.addr().toBytes());
+ openFlowActions.add(ofa);
+ actionsLen += ofa.getLength();
+ }
+
+ if (actionSetIPv4SrcAddr != null) {
+ OFActionNetworkLayerSource ofa =
+ new OFActionNetworkLayerSource(actionSetIPv4SrcAddr.addr().value());
+ openFlowActions.add(ofa);
+ actionsLen += ofa.getLength();
+ }
+
+ if (actionSetIPv4DstAddr != null) {
+ OFActionNetworkLayerDestination ofa =
+ new OFActionNetworkLayerDestination(actionSetIPv4DstAddr.addr().value());
+ openFlowActions.add(ofa);
+ actionsLen += ofa.getLength();
+ }
+
+ if (actionSetIpToS != null) {
+ OFActionNetworkTypeOfService ofa =
+ new OFActionNetworkTypeOfService(actionSetIpToS.ipToS());
+ openFlowActions.add(ofa);
+ actionsLen += ofa.getLength();
+ }
+
+ if (actionSetTcpUdpSrcPort != null) {
+ OFActionTransportLayerSource ofa =
+ new OFActionTransportLayerSource(actionSetTcpUdpSrcPort.port());
+ openFlowActions.add(ofa);
+ actionsLen += ofa.getLength();
+ }
+
+ if (actionSetTcpUdpDstPort != null) {
+ OFActionTransportLayerDestination ofa =
+ new OFActionTransportLayerDestination(actionSetTcpUdpDstPort.port());
+ openFlowActions.add(ofa);
+ actionsLen += ofa.getLength();
+ }
+
+ if (actionEnqueue != null) {
+ OFActionEnqueue ofa =
+ new OFActionEnqueue(actionEnqueue.port().value(),
+ actionEnqueue.queueId());
+ openFlowActions.add(ofa);
+ actionsLen += ofa.getLength();
+ }
}
fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
@@ -1992,8 +2271,14 @@
.setCookie(cookie)
.setCommand(flowModCommand)
.setMatch(match)
- .setActions(actions)
- .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
+ .setActions(openFlowActions)
+ .setLengthU(OFFlowMod.MINIMUM_LENGTH + actionsLen);
+ fm.setOutPort(OFPort.OFPP_NONE.getValue());
+ if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
+ (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
+ if (actionOutputPort != null)
+ fm.setOutPort(actionOutputPort);
+ }
//
// TODO: Set the following flag
@@ -2074,209 +2359,4 @@
//
return (installRemoteFlowEntry(flowPath, flowEntry));
}
-
- /**
- * Store a path flow for measurement purpose.
- *
- * NOTE: The Flow Path argument does NOT contain flow entries.
- * The Shortest Path is computed, and the corresponding Flow Entries
- * are stored in the Flow Path.
- *
- * @param flowPath the Flow Path with the endpoints and the match
- * conditions to store.
- * @return the stored shortest-path flow on success, otherwise null.
- */
- @Override
- public synchronized FlowPath measurementStorePathFlow(FlowPath flowPath) {
- //
- // Prepare the Shortest Path computation if the first Flow Path
- //
- if (measurementStoredPaths.isEmpty())
- measurementShortestPathTopo = topoRouteService.prepareShortestPathTopo();
-
- //
- // Compute the Shortest Path
- //
- DataPath dataPath =
- topoRouteService.getTopoShortestPath(measurementShortestPathTopo,
- flowPath.dataPath().srcPort(),
- flowPath.dataPath().dstPort());
- if (dataPath == null) {
- // We need the DataPath to populate the Network MAP
- dataPath = new DataPath();
- dataPath.setSrcPort(flowPath.dataPath().srcPort());
- dataPath.setDstPort(flowPath.dataPath().dstPort());
- }
-
- //
- // Set the incoming port matching and the outgoing port output
- // actions for each flow entry.
- //
- for (FlowEntry flowEntry : dataPath.flowEntries()) {
- // Set the incoming port matching
- FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
- flowEntry.setFlowEntryMatch(flowEntryMatch);
- flowEntryMatch.enableInPort(flowEntry.inPort());
-
- // Set the outgoing port output action
- ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
- if (flowEntryActions == null) {
- flowEntryActions = new ArrayList<FlowEntryAction>();
- flowEntry.setFlowEntryActions(flowEntryActions);
- }
- FlowEntryAction flowEntryAction = new FlowEntryAction();
- flowEntryAction.setActionOutput(flowEntry.outPort());
- flowEntryActions.add(flowEntryAction);
- }
-
- //
- // Prepare the computed Flow Path
- //
- FlowPath computedFlowPath = new FlowPath();
- computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
- computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
- computedFlowPath.setDataPath(dataPath);
- computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
-
- //
- // Add the computed Flow Path to the internal storage
- //
- measurementStoredPaths.add(computedFlowPath);
-
- log.debug("Measurement storing path {}",
- computedFlowPath.flowId().toString());
-
- return (computedFlowPath);
- }
-
- /**
- * Install path flows for measurement purpose.
- *
- * @param numThreads the number of threads to use to install the path
- * flows.
- * @return true on success, otherwise false.
- */
- @Override
- public boolean measurementInstallPaths(Integer numThreads) {
- // Create a copy of the Flow Paths to install
- final ConcurrentLinkedQueue<FlowPath> measurementProcessingPaths =
- new ConcurrentLinkedQueue<FlowPath>(measurementStoredPaths);
-
- /**
- * A Thread-wrapper class for executing the threads and collecting
- * the measurement data.
- */
- class MyThread extends Thread {
- public long[] execTime = new long[2000];
- public int samples = 0;
- public int threadId = -1;
- @Override
- public void run() {
- while (true) {
- FlowPath flowPath = measurementProcessingPaths.poll();
- if (flowPath == null)
- return;
- // Install the Flow Path
- FlowId flowId = new FlowId();
- String dataPathSummaryStr =
- flowPath.dataPath().dataPathSummary();
- long startTime = System.nanoTime();
- addFlow(flowPath, flowId, dataPathSummaryStr);
- long endTime = System.nanoTime();
- execTime[samples] = endTime - startTime;
- samples++;
- }
- }
- };
-
- List<MyThread> threads = new LinkedList<MyThread>();
-
- log.debug("Measurement Installing {} flows",
- measurementProcessingPaths.size());
-
- //
- // Create the threads to install the Flow Paths
- //
- for (int i = 0; i < numThreads; i++) {
- MyThread thread = new MyThread();
- thread.threadId = i;
- threads.add(thread);
- }
-
- //
- // Start processing
- //
- measurementEndTimeProcessingPaths = 0;
- measurementStartTimeProcessingPaths = System.nanoTime();
- for (Thread thread : threads) {
- thread.start();
- }
-
- // Wait for all threads to complete
- for (Thread thread : threads) {
- try {
- thread.join();
- } catch (InterruptedException e) {
- log.debug("Exception waiting for a thread to install a Flow Path: ", e);
- }
- }
-
- // Record the end of processing
- measurementEndTimeProcessingPaths = System.nanoTime();
-
- //
- // Prepare the string with measurement data per each Flow Path
- // installation.
- // The string is multiple lines: one line per Flow Path installation:
- // ThreadAndTimePerFlow <ThreadId> <TotalThreads> <Time(ns)>
- //
- measurementPerFlowStr = new String();
- String eol = System.getProperty("line.separator");
- for (MyThread thread : threads) {
- for (int i = 0; i < thread.samples; i++) {
- measurementPerFlowStr += "ThreadAndTimePerFlow " + thread.threadId + " " + numThreads + " " + thread.execTime[i] + eol;
- }
- }
-
- return true;
- }
-
- /**
- * Get the measurement time that took to install the path flows.
- *
- * @return the measurement time (in nanoseconds) it took to install
- * the path flows.
- */
- @Override
- public Long measurementGetInstallPathsTimeNsec() {
- return new Long(measurementEndTimeProcessingPaths -
- measurementStartTimeProcessingPaths);
- }
-
- /**
- * Get the measurement install time per Flow.
- *
- * @return a multi-line string with the following format per line:
- * ThreadAndTimePerFlow <ThreadId> <TotalThreads> <Time(ns)>
- */
- @Override
- public String measurementGetPerFlowInstallTime() {
- return new String(measurementPerFlowStr);
- }
-
- /**
- * Clear the path flows stored for measurement purpose.
- *
- * @return true on success, otherwise false.
- */
- @Override
- public boolean measurementClearAllPaths() {
- measurementStoredPaths.clear();
- topoRouteService.dropShortestPathTopo(measurementShortestPathTopo);
- measurementStartTimeProcessingPaths = 0;
- measurementEndTimeProcessingPaths = 0;
- measurementPerFlowStr = new String();
-
- return true;
- }
}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/IFlowService.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/IFlowService.java
index ba9cd1b..df11d6b 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/IFlowService.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/IFlowService.java
@@ -10,7 +10,7 @@
import net.onrc.onos.ofcontroller.util.FlowPath;
/**
- * @short Interface for providing Flow Service to other modules.
+ * Interface for providing Flow Service to other modules.
*/
public interface IFlowService extends IFloodlightService {
/**
@@ -88,8 +88,8 @@
/**
* Get summary of all installed flows by all installers.
*
- * @param flowId: starting flow Id of the range
- * @param maxFlows: number of flows to return
+ * @param flowId starting flow Id of the range
+ * @param maxFlows number of flows to return
* @return the Flow Paths if found, otherwise null.
*/
ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows);
@@ -115,47 +115,4 @@
* @return the added shortest-path flow on success, otherwise null.
*/
public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath);
-
- /**
- * Store a path flow for measurement purpose.
- *
- * NOTE: The Flow Path argument does NOT contain flow entries.
- *
- * @param flowPath the Flow Path with the endpoints and the match
- * conditions to store.
- * @return the stored shortest-path flow on success, otherwise null.
- */
- public FlowPath measurementStorePathFlow(FlowPath flowPath);
-
- /**
- * Install path flows for measurement purpose.
- *
- * @param numThreads the number of threads to use to install the path
- * flows.
- * @return true on success, otherwise false.
- */
- public boolean measurementInstallPaths(Integer numThreads);
-
- /**
- * Get the measurement time that took to install the path flows.
- *
- * @return the measurement time (in nanoseconds) it took to install
- * the path flows.
- */
- public Long measurementGetInstallPathsTimeNsec();
-
- /**
- * Get the measurement install time per Flow.
- *
- * @return a multi-line string with the following format per line:
- * ThreadAndTimePerFlow <ThreadId> <TotalThreads> <Time(ns)>
- */
- public String measurementGetPerFlowInstallTime();
-
- /**
- * Clear the path flows stored for measurement purpose.
- *
- * @return true on success, otherwise false.
- */
- public boolean measurementClearAllPaths();
}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/AddFlowResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/AddFlowResource.java
index 2800305..7464ec5 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/AddFlowResource.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/AddFlowResource.java
@@ -14,10 +14,23 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+/**
+ * Flow Manager REST API implementation: Add a Flow with the Flow
+ * Entries:
+ *
+ * POST /wm/flow/add/json
+ */
public class AddFlowResource extends ServerResource {
protected static Logger log = LoggerFactory.getLogger(AddFlowResource.class);
+ /**
+ * Implement the API.
+ *
+ * @param flowJson a string with the JSON representation of the Flow to
+ * add.
+ * @return the Flow ID of the added flow.
+ */
@Post("json")
public FlowId store(String flowJson) {
FlowId result = new FlowId();
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/AddShortestPathFlowResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/AddShortestPathFlowResource.java
index 9d2e0c9..c454b0f 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/AddShortestPathFlowResource.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/AddShortestPathFlowResource.java
@@ -14,10 +14,23 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+/**
+ * Flow Manager REST API implementation: Add a Flow by delegating
+ * the Shortest Path computation to ONOS:
+ *
+ * POST /wm/flow/add-shortest-path/json
+ */
public class AddShortestPathFlowResource extends ServerResource {
protected static Logger log = LoggerFactory.getLogger(AddShortestPathFlowResource.class);
+ /**
+ * Implement the API.
+ *
+ * @param flowJson a string with the JSON representation of the Flow to
+ * add.
+ * @return the Flow ID of the added flow.
+ */
@Post("json")
public FlowId store(String flowJson) {
FlowId result = new FlowId();
@@ -53,10 +66,11 @@
if (flowPath != null) {
FlowPath addedFlowPath =
flowService.addAndMaintainShortestPathFlow(flowPath);
- if (addedFlowPath == null)
+ if (addedFlowPath == null) {
result = new FlowId(); // Error: Return empty Flow Id
- else
+ } else {
result = addedFlowPath.flowId();
+ }
}
return result;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/ClearFlowResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/ClearFlowResource.java
index 1daa2ab..db591ae 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/ClearFlowResource.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/ClearFlowResource.java
@@ -8,9 +8,22 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+/**
+ * Flow Manager REST API implementation: Clear internal Flow state.
+ *
+ * The "{flow-id}" request attribute value can be either a specific Flow ID,
+ * or the keyword "all" to clear all Flows:
+ *
+ * GET /wm/flow/clear/{flow-id}/json
+ */
public class ClearFlowResource extends ServerResource {
protected static Logger log = LoggerFactory.getLogger(ClearFlowResource.class);
+ /**
+ * Implement the API.
+ *
+ * @return true on success, otehrwise false.
+ */
@Get("json")
public Boolean retrieve() {
Boolean result = false;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/DeleteFlowResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/DeleteFlowResource.java
index 393ff44..5b2bad4 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/DeleteFlowResource.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/DeleteFlowResource.java
@@ -8,9 +8,22 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+/**
+ * Flow Manager REST API implementation: Delete Flow state.
+ *
+ * The "{flow-id}" request attribute value can be either a specific Flow ID,
+ * or the keyword "all" to delete all Flows:
+ *
+ * GET /wm/flow/delete/{flow-id}/json
+ */
public class DeleteFlowResource extends ServerResource {
protected static Logger log = LoggerFactory.getLogger(DeleteFlowResource.class);
+ /**
+ * Implement the API.
+ *
+ * @return true on success, otehrwise false.
+ */
@Get("json")
public Boolean retrieve() {
Boolean result = false;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/FlowWebRoutable.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/FlowWebRoutable.java
index 954c84d..e027270 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/FlowWebRoutable.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/FlowWebRoutable.java
@@ -6,6 +6,9 @@
import org.restlet.Restlet;
import org.restlet.routing.Router;
+/**
+ * REST API implementation for the Flow Manager.
+ */
public class FlowWebRoutable implements RestletRoutable {
/**
* Create the Restlet router and bind to the proper resources.
@@ -22,11 +25,6 @@
router.attach("/getall-by-endpoints/{src-dpid}/{src-port}/{dst-dpid}/{dst-port}/json", GetAllFlowsByEndpointsResource.class);
router.attach("/getall/json", GetAllFlowsResource.class);
router.attach("/getsummary/{flow-id}/{max-flows}/json", GetSummaryFlowsResource.class);
- router.attach("/measurement-store-path/json", MeasurementStorePathFlowResource.class);
- router.attach("/measurement-install-paths/{num-threads}/json", MeasurementInstallPathsFlowResource.class);
- router.attach("/measurement-get-install-paths-time-nsec/json", MeasurementGetInstallPathsTimeNsecFlowResource.class);
- router.attach("/measurement-get-per-flow-install-time/json", MeasurementGetPerFlowInstallTimeFlowResource.class);
- router.attach("/measurement-clear-all-paths/json", MeasurementClearAllPathsFlowResource.class);
return router;
}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetAllFlowsByEndpointsResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetAllFlowsByEndpointsResource.java
index 6142096..0308e89 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetAllFlowsByEndpointsResource.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetAllFlowsByEndpointsResource.java
@@ -14,9 +14,29 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+/**
+ * Flow Manager REST API implementation: Get all Flow state for given
+ * source and destination switches and ports.
+ *
+ * The "{src-dpid}" request attribute value is the source DPID of the flows to
+ * get.
+ * The "{src-port}" request attribute value is the source port of the flows to
+ * get.
+ * The "{dst-dpid}" request attribute value is the destination DPID of the
+ * flows to get.
+ * The "{dst-port}" request attribute value is the destination port of the
+ * flows to get.
+ *
+ * GET /wm/flow/getall-by-endpoints/{src-dpid}/{src-port}/{dst-dpid}/{dst-port}/json"
+ */
public class GetAllFlowsByEndpointsResource extends ServerResource {
protected static Logger log = LoggerFactory.getLogger(GetAllFlowsByEndpointsResource.class);
+ /**
+ * Implement the API.
+ *
+ * @return the collection of Flow states if any found, otherwise null.
+ */
@Get("json")
public ArrayList<FlowPath> retrieve() {
ArrayList<FlowPath> result = null;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetAllFlowsByInstallerIdResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetAllFlowsByInstallerIdResource.java
index 498108f..43f1618 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetAllFlowsByInstallerIdResource.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetAllFlowsByInstallerIdResource.java
@@ -15,9 +15,31 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+/**
+ * Flow Manager REST API implementation: Get all Flow state for a given
+ * Installer ID and given source and destination switches and ports.
+ *
+ * The "{installer-id}" request attribute value is the Installer ID of the
+ * flows to get.
+ * The "{src-dpid}" request attribute value is the source DPID of the flows to
+ * get.
+ * The "{src-port}" request attribute value is the source port of the flows to
+ * get.
+ * The "{dst-dpid}" request attribute value is the destination DPID of the
+ * flows to get.
+ * The "{dst-port}" request attribute value is the destination port of the
+ * flows to get.
+ *
+ * GET /wm/flow/getall-by-installer-id/{installer-id}/{src-dpid}/{src-port}/{dst-dpid}/{dst-port}/json"
+ */
public class GetAllFlowsByInstallerIdResource extends ServerResource {
protected static Logger log = LoggerFactory.getLogger(GetAllFlowsByInstallerIdResource.class);
+ /**
+ * Implement the API.
+ *
+ * @return the collection of Flow states if any found, otherwise null.
+ */
@Get("json")
public ArrayList<FlowPath> retrieve() {
ArrayList<FlowPath> result = null;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetAllFlowsResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetAllFlowsResource.java
index 61eaf27..ab88348 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetAllFlowsResource.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetAllFlowsResource.java
@@ -10,9 +10,19 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+/**
+ * Flow Manager REST API implementation: Get all Flow state.
+ *
+ * GET /wm/flow/getall/json"
+ */
public class GetAllFlowsResource extends ServerResource {
protected static Logger log = LoggerFactory.getLogger(GetAllFlowsResource.class);
+ /**
+ * Implement the API.
+ *
+ * @return the collection of Flow states if any found, otherwise null.
+ */
@Get("json")
public ArrayList<FlowPath> retrieve() {
ArrayList<FlowPath> result = null;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetFlowByIdResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetFlowByIdResource.java
index 48e7369..77a898c 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetFlowByIdResource.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetFlowByIdResource.java
@@ -9,9 +9,21 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+/**
+ * Flow Manager REST API implementation: Get a single Flow state.
+ *
+ * The "{flow-id}" request attribute value is the Flow ID of the flow to get:
+ *
+ * GET /wm/flow/get/{flow-id}/json
+ */
public class GetFlowByIdResource extends ServerResource {
protected static Logger log = LoggerFactory.getLogger(GetFlowByIdResource.class);
+ /**
+ * Implement the API.
+ *
+ * @return the Flow state if the flow is found, otherwise null.
+ */
@Get("json")
public FlowPath retrieve() {
FlowPath result = null;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetSummaryFlowsResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetSummaryFlowsResource.java
index 4b3c00f..67e1ad6 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetSummaryFlowsResource.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetSummaryFlowsResource.java
@@ -11,9 +11,25 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+/**
+ * Flow Manager REST API implementation: Get summary of all installed
+ * flows by all installers in a given range.
+ *
+ * The "{flow-id}" request attribute value is the Flow ID of the flow in the
+ * flow range to get.
+ * The "{max-flows}" request attribute value is the maximum number of flows
+ * to be returned.
+ *
+ * GET /wm/flow/getsummary/{flow-id}/{max-flows}/json"
+ */
public class GetSummaryFlowsResource extends ServerResource {
protected static Logger log = LoggerFactory.getLogger(GetSummaryFlowsResource.class);
+ /**
+ * Implement the API.
+ *
+ * @return the collection of Flow states if any found, otherwise null.
+ */
@Get("json")
public ArrayList<IFlowPath> retrieve() {
ArrayList<IFlowPath> result = null;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/MeasurementClearAllPathsFlowResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/MeasurementClearAllPathsFlowResource.java
deleted file mode 100644
index 07d9fb2..0000000
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/MeasurementClearAllPathsFlowResource.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package net.onrc.onos.ofcontroller.flowmanager.web;
-
-import net.onrc.onos.ofcontroller.flowmanager.IFlowService;
-
-import org.restlet.resource.Get;
-import org.restlet.resource.ServerResource;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class MeasurementClearAllPathsFlowResource extends ServerResource {
- protected static Logger log = LoggerFactory.getLogger(MeasurementClearAllPathsFlowResource.class);
-
- @Get("json")
- public Boolean retrieve() {
- Boolean result = false;
-
- IFlowService flowService =
- (IFlowService)getContext().getAttributes().
- get(IFlowService.class.getCanonicalName());
-
- if (flowService == null) {
- log.debug("ONOS Flow Service not found");
- return result;
- }
-
- // Extract the arguments
- log.debug("Measurement Clear All Paths");
-
- // Process the request
- result = flowService.measurementClearAllPaths();
- return result;
- }
-}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/MeasurementGetInstallPathsTimeNsecFlowResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/MeasurementGetInstallPathsTimeNsecFlowResource.java
deleted file mode 100644
index 467afca..0000000
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/MeasurementGetInstallPathsTimeNsecFlowResource.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package net.onrc.onos.ofcontroller.flowmanager.web;
-
-import net.onrc.onos.ofcontroller.flowmanager.IFlowService;
-
-import org.restlet.resource.Get;
-import org.restlet.resource.ServerResource;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class MeasurementGetInstallPathsTimeNsecFlowResource extends ServerResource {
- protected static Logger log = LoggerFactory.getLogger(MeasurementGetInstallPathsTimeNsecFlowResource.class);
-
- @Get("json")
- public Long retrieve() {
- Long result = null;
-
- IFlowService flowService =
- (IFlowService)getContext().getAttributes().
- get(IFlowService.class.getCanonicalName());
-
- if (flowService == null) {
- log.debug("ONOS Flow Service not found");
- return result;
- }
-
- // Extract the arguments
-
- // Process the request
- result = flowService.measurementGetInstallPathsTimeNsec();
-
- log.debug("Measurement Get Install Paths Time (nsec): " + result);
-
- return result;
- }
-}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/MeasurementGetPerFlowInstallTimeFlowResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/MeasurementGetPerFlowInstallTimeFlowResource.java
deleted file mode 100644
index 92d84ab..0000000
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/MeasurementGetPerFlowInstallTimeFlowResource.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package net.onrc.onos.ofcontroller.flowmanager.web;
-
-import net.onrc.onos.ofcontroller.flowmanager.IFlowService;
-
-import org.restlet.resource.Get;
-import org.restlet.resource.ServerResource;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class MeasurementGetPerFlowInstallTimeFlowResource extends ServerResource {
- protected static Logger log = LoggerFactory.getLogger(MeasurementGetPerFlowInstallTimeFlowResource.class);
-
- @Get("json")
- public String retrieve() {
- String result = null;
-
- IFlowService flowService =
- (IFlowService)getContext().getAttributes().
- get(IFlowService.class.getCanonicalName());
-
- if (flowService == null) {
- log.debug("ONOS Flow Service not found");
- return result;
- }
-
- // Extract the arguments
-
- // Process the request
- result = flowService.measurementGetPerFlowInstallTime();
-
- log.debug("Measurement Get Install Paths Time (nsec): " + result);
-
- return result;
- }
-}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/MeasurementInstallPathsFlowResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/MeasurementInstallPathsFlowResource.java
deleted file mode 100644
index 074dfb4..0000000
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/MeasurementInstallPathsFlowResource.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package net.onrc.onos.ofcontroller.flowmanager.web;
-
-import net.onrc.onos.ofcontroller.flowmanager.IFlowService;
-
-import org.restlet.resource.Get;
-import org.restlet.resource.ServerResource;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class MeasurementInstallPathsFlowResource extends ServerResource {
- protected static Logger log = LoggerFactory.getLogger(MeasurementInstallPathsFlowResource.class);
-
- @Get("json")
- public Boolean retrieve() {
- Boolean result = false;
-
- IFlowService flowService =
- (IFlowService)getContext().getAttributes().
- get(IFlowService.class.getCanonicalName());
-
- if (flowService == null) {
- log.debug("ONOS Flow Service not found");
- return result;
- }
-
- // Extract the arguments
- String numThreadsStr = (String) getRequestAttributes().get("num-threads");
- Integer numThreads = new Integer(numThreadsStr);
- log.debug("Measurement Install Paths Number of Threads " + numThreadsStr);
-
- // Process the request
- result = flowService.measurementInstallPaths(numThreads);
- return result;
- }
-}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/MeasurementStorePathFlowResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/MeasurementStorePathFlowResource.java
deleted file mode 100644
index 0f23663..0000000
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/MeasurementStorePathFlowResource.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package net.onrc.onos.ofcontroller.flowmanager.web;
-
-import java.io.IOException;
-
-import net.onrc.onos.ofcontroller.flowmanager.IFlowService;
-import net.onrc.onos.ofcontroller.util.FlowId;
-import net.onrc.onos.ofcontroller.util.FlowPath;
-
-import org.codehaus.jackson.JsonGenerationException;
-import org.codehaus.jackson.map.JsonMappingException;
-import org.codehaus.jackson.map.ObjectMapper;
-import org.restlet.resource.Post;
-import org.restlet.resource.ServerResource;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class MeasurementStorePathFlowResource extends ServerResource {
-
- protected static Logger log = LoggerFactory.getLogger(MeasurementStorePathFlowResource.class);
-
- @Post("json")
- public FlowId store(String flowJson) {
- FlowId result = new FlowId();
-
- IFlowService flowService =
- (IFlowService)getContext().getAttributes().
- get(IFlowService.class.getCanonicalName());
-
- if (flowService == null) {
- log.debug("ONOS Flow Service not found");
- return result;
- }
-
- //
- // Extract the arguments
- // NOTE: The "flow" is specified in JSON format.
- //
- ObjectMapper mapper = new ObjectMapper();
- String flowPathStr = flowJson;
- FlowPath flowPath = null;
- log.debug("Measurement Store Flow Path: " + flowPathStr);
- try {
- flowPath = mapper.readValue(flowPathStr, FlowPath.class);
- } catch (JsonGenerationException e) {
- e.printStackTrace();
- } catch (JsonMappingException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- // Process the request
- if (flowPath != null) {
- FlowPath addedFlowPath =
- flowService.measurementStorePathFlow(flowPath);
- if (addedFlowPath == null)
- result = new FlowId(); // Error: Return empty Flow Id
- else
- result = addedFlowPath.flowId();
- }
-
- return result;
- }
-}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/ILinkDiscovery.java b/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/ILinkDiscovery.java
index 6113ea8..cdb71be 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/ILinkDiscovery.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/ILinkDiscovery.java
@@ -1,5 +1,7 @@
package net.onrc.onos.ofcontroller.linkdiscovery;
+import net.floodlightcontroller.core.IUpdate;
+
import org.codehaus.jackson.map.annotate.JsonSerialize;
import org.codehaus.jackson.map.ser.std.ToStringSerializer;
import org.openflow.util.HexString;
@@ -27,7 +29,7 @@
}
}
- public class LDUpdate {
+ public class LDUpdate implements IUpdate{
protected long src;
protected short srcPort;
protected long dst;
@@ -129,6 +131,12 @@
return "LDUpdate: Unknown update.";
}
}
+
+ @Override
+ public void dispatch() {
+ // TODO Auto-generated method stub
+
+ }
}
public enum SwitchType {
diff --git a/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/internal/LinkDiscoveryManager.java b/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
index f057a29..c9f3d5e 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
@@ -18,6 +18,7 @@
package net.onrc.onos.ofcontroller.linkdiscovery.internal;
import java.io.IOException;
+
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
@@ -33,7 +34,6 @@
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
-import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@@ -126,6 +126,7 @@
implements IOFMessageListener, IOFSwitchListener,
IStorageSourceListener, ILinkDiscoveryService,
IFloodlightModule, IInfoProvider, IHAListener {
+ protected IFloodlightProviderService controller;
protected static Logger log = LoggerFactory.getLogger(LinkDiscoveryManager.class);
// Names of table/fields for links in the storage API
@@ -157,8 +158,8 @@
private static final long LINK_LOCAL_VALUE = 0x0180c2000000L;
// BigSwitch OUI is 5C:16:C7, so 5D:16:C7 is the multicast version
- private static final String LLDP_BSN_DST_MAC_STRING = "5d:16:c7:00:00:01";
- //private static final String LLDP_BSN_DST_MAC_STRING = "ff:ff:ff:ff:ff:ff";
+ // private static final String LLDP_BSN_DST_MAC_STRING = "5d:16:c7:00:00:01";
+ private static final String LLDP_BSN_DST_MAC_STRING = "ff:ff:ff:ff:ff:ff";
// Direction TLVs are used to indicate if the LLDPs were sent
@@ -232,8 +233,40 @@
/* topology aware components are called in the order they were added to the
* the array */
protected ArrayList<ILinkDiscoveryListener> linkDiscoveryAware;
- protected BlockingQueue<LDUpdate> updates;
- protected Thread updatesThread;
+
+ protected class LinkUpdate extends LDUpdate {
+
+ public LinkUpdate(LDUpdate old) {
+ super(old);
+ }
+ @LogMessageDoc(level="ERROR",
+ message="Error in link discovery updates loop",
+ explanation="An unknown error occured while dispatching " +
+ "link update notifications",
+ recommendation=LogMessageDoc.GENERIC_ACTION)
+ @Override
+ public void dispatch() {
+ if (linkDiscoveryAware != null) {
+ if (log.isTraceEnabled()) {
+ log.trace("Dispatching link discovery update {} {} {} {} {} for {}",
+ new Object[]{this.getOperation(),
+ HexString.toHexString(this.getSrc()), this.getSrcPort(),
+ HexString.toHexString(this.getDst()), this.getDstPort(),
+ linkDiscoveryAware});
+ }
+ try {
+ for (ILinkDiscoveryListener lda : linkDiscoveryAware) { // order maintained
+ lda.linkDiscoveryUpdate(this);
+ }
+ }
+ catch (Exception e) {
+ log.error("Error in link discovery updates loop", e);
+ }
+ }
+
+ }
+
+ }
/**
* List of ports through which LLDP/BDDPs are not sent.
@@ -322,34 +355,7 @@
return ILinkDiscovery.LinkType.INVALID_LINK;
}
- @LogMessageDoc(level="ERROR",
- message="Error in link discovery updates loop",
- explanation="An unknown error occured while dispatching " +
- "link update notifications",
- recommendation=LogMessageDoc.GENERIC_ACTION)
- private void doUpdatesThread() throws InterruptedException {
- do {
- LDUpdate update = updates.take();
-
- if (linkDiscoveryAware != null) {
- if (log.isTraceEnabled()) {
- log.trace("Dispatching link discovery update {} {} {} {} {} for {}",
- new Object[]{update.getOperation(),
- HexString.toHexString(update.getSrc()), update.getSrcPort(),
- HexString.toHexString(update.getDst()), update.getDstPort(),
- linkDiscoveryAware});
- }
- try {
- for (ILinkDiscoveryListener lda : linkDiscoveryAware) { // order maintained
- lda.linkDiscoveryUpdate(update);
- }
- }
- catch (Exception e) {
- log.error("Error in link discovery updates loop", e);
- }
- }
- } while (updates.peek() != null);
- }
+
private boolean isLinkDiscoverySuppressed(long sw, short portNumber) {
return this.suppressLinkDiscovery.contains(new NodePortTuple(sw, portNumber));
}
@@ -490,7 +496,10 @@
if (portUp) operation = UpdateOperation.PORT_UP;
else operation = UpdateOperation.PORT_DOWN;
- updates.add(new LDUpdate(sw, port, operation));
+ LinkUpdate update = new LinkUpdate(new LDUpdate(sw, port, operation));
+
+
+ controller.publishUpdate(update);
}
/**
@@ -1134,10 +1143,11 @@
if (linkChanged) {
// find out if the link was added or removed here.
- updates.add(new LDUpdate(lt.getSrc(), lt.getSrcPort(),
+ LinkUpdate update = new LinkUpdate(new LDUpdate(lt.getSrc(), lt.getSrcPort(),
lt.getDst(), lt.getDstPort(),
getLinkType(lt, newInfo),
updateOperation));
+ controller.publishUpdate(update);
}
} finally {
lock.writeLock().unlock();
@@ -1184,10 +1194,11 @@
}
LinkInfo info = this.links.remove(lt);
- updates.add(new LDUpdate(lt.getSrc(), lt.getSrcPort(),
+ LinkUpdate update = new LinkUpdate(new LDUpdate(lt.getSrc(), lt.getSrcPort(),
lt.getDst(), lt.getDstPort(),
getLinkType(lt, info),
UpdateOperation.LINK_REMOVED));
+ controller.publishUpdate(update);
// Update Event History
evHistTopoLink(lt.getSrc(),
@@ -1251,8 +1262,8 @@
((byte)OFPortReason.OFPPR_MODIFY.ordinal() ==
ps.getReason() && !portEnabled(ps.getDesc()))) {
deleteLinksOnPort(npt, "Port Status Changed");
- LDUpdate update = new LDUpdate(sw, port, UpdateOperation.PORT_DOWN);
- updates.add(update);
+ LinkUpdate update = new LinkUpdate(new LDUpdate(sw, port, UpdateOperation.PORT_DOWN));
+ controller.publishUpdate(update);
linkDeleted = true;
}
else if (ps.getReason() ==
@@ -1284,14 +1295,15 @@
(updatedDstPortState != null)) {
// The link is already known to link discovery
// manager and the status has changed, therefore
- // send an LDUpdate.
+ // send an LinkUpdate.
UpdateOperation operation =
getUpdateOperation(linkInfo.getSrcPortState(),
linkInfo.getDstPortState());
- updates.add(new LDUpdate(lt.getSrc(), lt.getSrcPort(),
+ LinkUpdate update = new LinkUpdate(new LDUpdate(lt.getSrc(), lt.getSrcPort(),
lt.getDst(), lt.getDstPort(),
getLinkType(lt, linkInfo),
operation));
+ controller.publishUpdate(update);
writeLinkToStorage(lt, linkInfo);
linkInfoChanged = true;
}
@@ -1300,7 +1312,8 @@
UpdateOperation operation =
getUpdateOperation(ps.getDesc().getState());
- updates.add(new LDUpdate(sw, port, operation));
+ LinkUpdate update = new LinkUpdate(new LDUpdate(sw, port, operation));
+ controller.publishUpdate(update);
}
if (!linkDeleted && !linkInfoChanged){
@@ -1372,14 +1385,13 @@
}
// Update event history
evHistTopoSwitch(sw, EvAction.SWITCH_CONNECTED, "None");
- LDUpdate update = new LDUpdate(sw.getId(), null,
- UpdateOperation.SWITCH_UPDATED);
- updates.add(update);
+ LinkUpdate update = new LinkUpdate(new LDUpdate(sw.getId(), null,
+ UpdateOperation.SWITCH_UPDATED));
+ controller.publishUpdate(update);
}
/**
* When a switch disconnects we remove any links from our map and notify.
- * @param The id of the switch
*/
@Override
public void removedSwitch(IOFSwitch iofSwitch) {
@@ -1399,8 +1411,8 @@
deleteLinks(eraseList, "Switch Removed");
// Send a switch removed update
- LDUpdate update = new LDUpdate(sw, null, UpdateOperation.SWITCH_REMOVED);
- updates.add(update);
+ LinkUpdate update = new LinkUpdate(new LDUpdate(sw, null, UpdateOperation.SWITCH_REMOVED));
+ controller.publishUpdate(update);
}
} finally {
lock.writeLock().unlock();
@@ -1486,10 +1498,11 @@
UpdateOperation operation;
operation = getUpdateOperation(info.getSrcPortState(),
info.getDstPortState());
- updates.add(new LDUpdate(lt.getSrc(), lt.getSrcPort(),
+ LinkUpdate update = new LinkUpdate(new LDUpdate(lt.getSrc(), lt.getSrcPort(),
lt.getDst(), lt.getDstPort(),
getLinkType(lt, info),
operation));
+ controller.publishUpdate(update);
}
}
@@ -1776,16 +1789,18 @@
if (log.isTraceEnabled()) {
log.trace("SWITCH_IS_CORE_SWITCH set to False for {}", sw);
}
- updates.add(new LDUpdate(sw.getId(), SwitchType.BASIC_SWITCH,
+ LinkUpdate update = new LinkUpdate(new LDUpdate(sw.getId(), SwitchType.BASIC_SWITCH,
UpdateOperation.SWITCH_UPDATED));
+ controller.publishUpdate(update);
}
else {
sw.setAttribute(IOFSwitch.SWITCH_IS_CORE_SWITCH, new Boolean(true));
if (log.isTraceEnabled()) {
log.trace("SWITCH_IS_CORE_SWITCH set to True for {}", sw);
}
- updates.add(new LDUpdate(sw.getId(), SwitchType.CORE_SWITCH,
+ LinkUpdate update = new LinkUpdate(new LDUpdate(sw.getId(), SwitchType.CORE_SWITCH,
UpdateOperation.SWITCH_UPDATED));
+ controller.publishUpdate(update);
}
}
}
@@ -1847,7 +1862,6 @@
// We create this here because there is no ordering guarantee
this.linkDiscoveryAware = new ArrayList<ILinkDiscoveryListener>();
this.lock = new ReentrantReadWriteLock();
- this.updates = new LinkedBlockingQueue<LDUpdate>();
this.links = new HashMap<Link, LinkInfo>();
this.portLinks = new HashMap<NodePortTuple, Set<Link>>();
this.suppressLinkDiscovery =
@@ -1910,6 +1924,8 @@
}
ScheduledExecutorService ses = threadPool.getScheduledExecutor();
+ controller =
+ context.getServiceImpl(IFloodlightProviderService.class);
// To be started by the first switch connection
discoveryTask = new SingletonTask(ses, new Runnable() {
@@ -1953,20 +1969,6 @@
bddpTask = new SingletonTask(ses, new QuarantineWorker());
bddpTask.reschedule(BDDP_TASK_INTERVAL, TimeUnit.MILLISECONDS);
- updatesThread = new Thread(new Runnable () {
- @Override
- public void run() {
- while (true) {
- try {
- doUpdatesThread();
- } catch (InterruptedException e) {
- return;
- }
- }
- }}, "Topology Updates");
- updatesThread.start();
-
-
// Register for the OpenFlow messages we want to receive
floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
diff --git a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ArpCache.java b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ArpCache.java
new file mode 100644
index 0000000..83a3b55
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ArpCache.java
@@ -0,0 +1,99 @@
+package net.onrc.onos.ofcontroller.proxyarp;
+
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import net.floodlightcontroller.util.MACAddress;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Implements a basic ARP cache which maps IPv4 addresses to MAC addresses.
+ * Mappings time out after a short period of time (currently 1 min). We don't
+ * try and refresh the mapping before the entry times out because as a controller
+ * we don't know if the mapping is still needed.
+ */
+
+/* TODO clean out old ARP entries out of the cache periodically. We currently
+ * don't do this which means the cache memory size will never decrease. We already
+ * have a periodic thread that can be used to do this in ProxyArpManager.
+ */
+class ArpCache {
+ private final static Logger log = LoggerFactory.getLogger(ArpCache.class);
+
+ private final static long ARP_ENTRY_TIMEOUT = 60000; //ms (1 min)
+
+ //Protected by locking on the ArpCache object
+ private final Map<InetAddress, ArpCacheEntry> arpCache;
+
+ private static class ArpCacheEntry {
+ private final MACAddress macAddress;
+ private long timeLastSeen;
+
+ public ArpCacheEntry(MACAddress macAddress) {
+ this.macAddress = macAddress;
+ this.timeLastSeen = System.currentTimeMillis();
+ }
+
+ public MACAddress getMacAddress() {
+ return macAddress;
+ }
+
+ public void setTimeLastSeen(long time){
+ timeLastSeen = time;
+ }
+
+ public boolean isExpired() {
+ return System.currentTimeMillis() - timeLastSeen > ARP_ENTRY_TIMEOUT;
+ }
+ }
+
+ ArpCache() {
+ arpCache = new HashMap<InetAddress, ArpCacheEntry>();
+ }
+
+ synchronized MACAddress lookup(InetAddress ipAddress){
+ ArpCacheEntry arpEntry = arpCache.get(ipAddress);
+
+ if (arpEntry == null){
+ return null;
+ }
+
+ if (arpEntry.isExpired()) {
+ //Entry has timed out so we'll remove it and return null
+ log.trace("Removing expired ARP entry for {}", ipAddress.getHostAddress());
+
+ arpCache.remove(ipAddress);
+ return null;
+ }
+
+ return arpEntry.getMacAddress();
+ }
+
+ synchronized void update(InetAddress ipAddress, MACAddress macAddress){
+ ArpCacheEntry arpEntry = arpCache.get(ipAddress);
+
+ if (arpEntry != null && arpEntry.getMacAddress().equals(macAddress)){
+ arpEntry.setTimeLastSeen(System.currentTimeMillis());
+ }
+ else {
+ arpCache.put(ipAddress, new ArpCacheEntry(macAddress));
+ }
+ }
+
+ synchronized List<String> getMappings() {
+ List<String> result = new ArrayList<String>(arpCache.size());
+
+ for (Map.Entry<InetAddress, ArpCacheEntry> entry : arpCache.entrySet()) {
+ result.add(entry.getKey().getHostAddress() + " => " +
+ entry.getValue().getMacAddress().toString() +
+ (entry.getValue().isExpired()?" : EXPIRED":" : VALID"));
+ }
+
+ return result;
+ }
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ArpCacheResource.java b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ArpCacheResource.java
new file mode 100644
index 0000000..252e66e
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ArpCacheResource.java
@@ -0,0 +1,18 @@
+package net.onrc.onos.ofcontroller.proxyarp;
+
+import java.util.List;
+
+import org.restlet.resource.Get;
+import org.restlet.resource.ServerResource;
+
+public class ArpCacheResource extends ServerResource {
+
+ @Get("json")
+ public List<String> getArpCache() {
+ IProxyArpService arp = (IProxyArpService) getContext().getAttributes().
+ get(IProxyArpService.class.getCanonicalName());
+
+ return arp.getMappings();
+ }
+
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ArpTableEntry.java b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ArpTableEntry.java
deleted file mode 100644
index 5830cfd..0000000
--- a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ArpTableEntry.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package net.onrc.onos.ofcontroller.proxyarp;
-
-
-public class ArpTableEntry {
-
- private byte[] macAddress;
- private long timeLastSeen;
-
- public ArpTableEntry(byte[] macAddress, long timeLastSeen) {
- this.macAddress = macAddress;
- this.timeLastSeen = timeLastSeen;
- }
-
- public byte[] getMacAddress() {
- return macAddress;
- }
-
- public long getTimeLastSeen() {
- return timeLastSeen;
- }
-
- public void setTimeLastSeen(long time){
- //TODO thread safety issues?
- timeLastSeen = time;
- }
-
-}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ArpWebRoutable.java b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ArpWebRoutable.java
new file mode 100644
index 0000000..eefa2db
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ArpWebRoutable.java
@@ -0,0 +1,22 @@
+package net.onrc.onos.ofcontroller.proxyarp;
+
+import net.floodlightcontroller.restserver.RestletRoutable;
+
+import org.restlet.Context;
+import org.restlet.Restlet;
+import org.restlet.routing.Router;
+
+public class ArpWebRoutable implements RestletRoutable {
+
+ @Override
+ public Restlet getRestlet(Context context) {
+ Router router = new Router(context);
+ router.attach("/cache/json", ArpCacheResource.class);
+ return router;
+ }
+
+ @Override
+ public String basePath() {
+ return "/wm/arp";
+ }
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/IArpRequester.java b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/IArpRequester.java
new file mode 100644
index 0000000..66a17a2
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/IArpRequester.java
@@ -0,0 +1,21 @@
+package net.onrc.onos.ofcontroller.proxyarp;
+
+import java.net.InetAddress;
+
+import net.floodlightcontroller.util.MACAddress;
+
+/**
+ * Callback interface for modules using the {@link IProxyArpService} to
+ * send ARP requests.
+ *
+ */
+public interface IArpRequester {
+ /**
+ * Callback method that will be called by the {@link IProxyArpService}
+ * when it receives a reply for a request previously submitted by this
+ * {@code IArpRequester}.
+ * @param ipAddress The IP address than an ARP request was sent for
+ * @param macAddress The MAC address mapped to the requested IP address
+ */
+ public void arpResponse(InetAddress ipAddress, MACAddress macAddress);
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/IProxyArpService.java b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/IProxyArpService.java
new file mode 100644
index 0000000..97844d3
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/IProxyArpService.java
@@ -0,0 +1,34 @@
+package net.onrc.onos.ofcontroller.proxyarp;
+
+import java.net.InetAddress;
+import java.util.List;
+
+import net.floodlightcontroller.core.module.IFloodlightService;
+import net.floodlightcontroller.util.MACAddress;
+
+//Extends IFloodlightService so we can access it from REST API resources
+public interface IProxyArpService extends IFloodlightService{
+ /**
+ * Returns the MAC address if there is a valid entry in the cache.
+ * Otherwise returns null.
+ * @param ipAddress
+ * @return
+ */
+ public MACAddress getMacAddress(InetAddress ipAddress);
+
+ /**
+ * Tell the IProxyArpService to send an ARP request for the IP address.
+ * The request will be broadcast out all edge ports in the network.
+ * @param ipAddress
+ * @param requester
+ * @param retry Whether to keep sending requests until the MAC is learnt
+ */
+ public void sendArpRequest(InetAddress ipAddress, IArpRequester requester,
+ boolean retry);
+
+ /**
+ * Returns a snapshot of the entire ARP cache.
+ * @return
+ */
+ public List<String> getMappings();
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java
index a5246c0..b6a9591 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java
@@ -5,10 +5,12 @@
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
import net.floodlightcontroller.core.FloodlightContext;
import net.floodlightcontroller.core.IFloodlightProviderService;
@@ -16,9 +18,12 @@
import net.floodlightcontroller.core.IOFSwitch;
import net.floodlightcontroller.packet.ARP;
import net.floodlightcontroller.packet.Ethernet;
+import net.floodlightcontroller.packet.IPv4;
+import net.floodlightcontroller.restserver.IRestApiService;
import net.floodlightcontroller.topology.ITopologyService;
-import net.floodlightcontroller.topology.NodePortTuple;
import net.floodlightcontroller.util.MACAddress;
+import net.onrc.onos.ofcontroller.bgproute.ILayer3InfoService;
+import net.onrc.onos.ofcontroller.bgproute.Interface;
import org.openflow.protocol.OFMessage;
import org.openflow.protocol.OFPacketIn;
@@ -31,27 +36,153 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-public class ProxyArpManager implements IOFMessageListener {
- private static Logger log = LoggerFactory.getLogger(ProxyArpManager.class);
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimaps;
+import com.google.common.collect.SetMultimap;
+
+public class ProxyArpManager implements IProxyArpService, IOFMessageListener {
+ private final static Logger log = LoggerFactory.getLogger(ProxyArpManager.class);
- private final long ARP_ENTRY_TIMEOUT = 600000; //ms (== 5 mins)
+ private final long ARP_TIMER_PERIOD = 60000; //ms (== 1 min)
- protected IFloodlightProviderService floodlightProvider;
- protected ITopologyService topology;
+ private static final int ARP_REQUEST_TIMEOUT = 2000; //ms
+
+ private final IFloodlightProviderService floodlightProvider;
+ private final ITopologyService topology;
+ private final ILayer3InfoService layer3;
+ private final IRestApiService restApi;
- protected Map<InetAddress, ArpTableEntry> arpTable;
+ private final ArpCache arpCache;
+
+ private final SetMultimap<InetAddress, ArpRequest> arpRequests;
+
+ private static class ArpRequest {
+ private final IArpRequester requester;
+ private final boolean retry;
+ private long requestTime;
+
+ public ArpRequest(IArpRequester requester, boolean retry){
+ this.requester = requester;
+ this.retry = retry;
+ this.requestTime = System.currentTimeMillis();
+ }
+
+ public ArpRequest(ArpRequest old) {
+ this.requester = old.requester;
+ this.retry = old.retry;
+ this.requestTime = System.currentTimeMillis();
+ }
+
+ public boolean isExpired() {
+ return (System.currentTimeMillis() - requestTime) > ARP_REQUEST_TIMEOUT;
+ }
+
+ public boolean shouldRetry() {
+ return retry;
+ }
+
+ public void dispatchReply(InetAddress ipAddress, MACAddress replyMacAddress) {
+ requester.arpResponse(ipAddress, replyMacAddress);
+ }
+ }
+
+ private class HostArpRequester implements IArpRequester {
+ private final ARP arpRequest;
+ private final long dpid;
+ private final short port;
+
+ public HostArpRequester(ARP arpRequest, long dpid, short port) {
+ this.arpRequest = arpRequest;
+ this.dpid = dpid;
+ this.port = port;
+ }
+
+ @Override
+ public void arpResponse(InetAddress ipAddress, MACAddress macAddress) {
+ ProxyArpManager.this.sendArpReply(arpRequest, dpid, port, macAddress);
+ }
+ }
public ProxyArpManager(IFloodlightProviderService floodlightProvider,
- ITopologyService topology){
+ ITopologyService topology, ILayer3InfoService layer3,
+ IRestApiService restApi){
this.floodlightProvider = floodlightProvider;
this.topology = topology;
+ this.layer3 = layer3;
+ this.restApi = restApi;
- arpTable = new HashMap<InetAddress, ArpTableEntry>();
+ arpCache = new ArpCache();
+
+ arpRequests = Multimaps.synchronizedSetMultimap(
+ HashMultimap.<InetAddress, ArpRequest>create());
+ }
+
+ public void startUp() {
+ restApi.addRestletRoutable(new ArpWebRoutable());
+
+ Timer arpTimer = new Timer("arp-processing");
+ arpTimer.scheduleAtFixedRate(new TimerTask() {
+ @Override
+ public void run() {
+ doPeriodicArpProcessing();
+ }
+ }, 0, ARP_TIMER_PERIOD);
+ }
+
+ /*
+ * Function that runs periodically to manage the asynchronous request mechanism.
+ * It basically cleans up old ARP requests if we don't get a response for them.
+ * The caller can designate that a request should be retried indefinitely, and
+ * this task will handle that as well.
+ */
+ private void doPeriodicArpProcessing() {
+ SetMultimap<InetAddress, ArpRequest> retryList
+ = HashMultimap.<InetAddress, ArpRequest>create();
+
+ //Have to synchronize externally on the Multimap while using an iterator,
+ //even though it's a synchronizedMultimap
+ synchronized (arpRequests) {
+ log.debug("Current have {} outstanding requests",
+ arpRequests.size());
+
+ Iterator<Map.Entry<InetAddress, ArpRequest>> it
+ = arpRequests.entries().iterator();
+
+ while (it.hasNext()) {
+ Map.Entry<InetAddress, ArpRequest> entry
+ = it.next();
+ ArpRequest request = entry.getValue();
+ if (request.isExpired()) {
+ log.debug("Cleaning expired ARP request for {}",
+ entry.getKey().getHostAddress());
+
+ it.remove();
+
+ if (request.shouldRetry()) {
+ retryList.put(entry.getKey(), request);
+ }
+ }
+ }
+ }
+
+ for (Map.Entry<InetAddress, Collection<ArpRequest>> entry
+ : retryList.asMap().entrySet()) {
+
+ InetAddress address = entry.getKey();
+
+ log.debug("Resending ARP request for {}", address.getHostAddress());
+
+ sendArpRequestForAddress(address);
+
+ for (ArpRequest request : entry.getValue()) {
+ arpRequests.put(address, new ArpRequest(request));
+ }
+ }
}
@Override
public String getName() {
- return "ProxyArpManager";
+ return "ProxyArpManager";
}
@Override
@@ -78,91 +209,190 @@
IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
if (eth.getEtherType() == Ethernet.TYPE_ARP){
-
-
ARP arp = (ARP) eth.getPayload();
if (arp.getOpCode() == ARP.OP_REQUEST) {
- log.debug("ARP request received for {}", bytesToStringAddr(arp.getTargetProtocolAddress()));
-
- byte[] mac = lookupArpTable(arp.getTargetProtocolAddress());
-
- if (mac == null){
- //Mac address is not in our arp table.
- //We need to flood the request out edge ports
- Set<NodePortTuple> broadcastPorts = topology.getBroadcastDomainPorts();
- log.debug("size {}", broadcastPorts.size());
- for (NodePortTuple nodePort : broadcastPorts){
- log.debug("Port {}", nodePort);
- }
- broadcastArpRequestOutEdge(pi, sw.getId(), pi.getInPort());
- }
- else {
- //We know the address, so send a reply
- log.debug("Sending reply of {}", MACAddress.valueOf(mac).toString());
- sendArpReply(arp, pi, mac, sw);
- }
+ handleArpRequest(sw, pi, arp);
}
else if (arp.getOpCode() == ARP.OP_REPLY) {
- log.debug("ARP reply recieved for {}", bytesToStringAddr(arp.getSenderProtocolAddress()));
-
- log.debug("arp table {}", arpTable.keySet());
-
- updateArpTable(arp);
+ handleArpReply(sw, pi, arp);
}
}
+ //TODO should we propagate ARP or swallow it?
+ //Always propagate for now so DeviceManager can learn the host location
return Command.CONTINUE;
}
-
- private synchronized byte[] lookupArpTable(byte[] ipAddress){
- InetAddress addr;
- try {
- addr = InetAddress.getByAddress(ipAddress);
- } catch (UnknownHostException e) {
- log.warn("Unable to create InetAddress", e);
- return null;
- }
-
- ArpTableEntry arpEntry = arpTable.get(addr);
-
- if (arpEntry == null){
- return null;
- }
-
- if (System.currentTimeMillis() - arpEntry.getTimeLastSeen()
- > ARP_ENTRY_TIMEOUT){
- //Entry has timed out so we'll remove it and return null
- arpTable.remove(addr);
- return null;
- }
-
- return arpEntry.getMacAddress();
- }
- private synchronized void updateArpTable(ARP arp){
- InetAddress addr;
+ private void handleArpRequest(IOFSwitch sw, OFPacketIn pi, ARP arp) {
+ if (log.isTraceEnabled()) {
+ log.trace("ARP request received for {}",
+ inetAddressToString(arp.getTargetProtocolAddress()));
+ }
+
+ InetAddress target;
try {
- addr = InetAddress.getByAddress(arp.getSenderProtocolAddress());
+ target = InetAddress.getByAddress(arp.getTargetProtocolAddress());
} catch (UnknownHostException e) {
- log.warn("Unable to create InetAddress", e);
+ log.debug("Invalid address in ARP request", e);
+ return;
+ }
+
+ if (layer3.fromExternalNetwork(sw.getId(), pi.getInPort())) {
+ //If the request came from outside our network, we only care if
+ //it was a request for one of our interfaces.
+ if (layer3.isInterfaceAddress(target)) {
+ log.trace("ARP request for our interface. Sending reply {} => {}",
+ target.getHostAddress(), layer3.getRouterMacAddress());
+
+ sendArpReply(arp, sw.getId(), pi.getInPort(),
+ layer3.getRouterMacAddress());
+ }
+
return;
}
- ArpTableEntry arpEntry = arpTable.get(addr);
+ MACAddress macAddress = arpCache.lookup(target);
- if (arpEntry != null
- && arpEntry.getMacAddress() == arp.getSenderHardwareAddress()){
- arpEntry.setTimeLastSeen(System.currentTimeMillis());
+ if (macAddress == null){
+ //MAC address is not in our ARP cache.
+
+ //Record where the request came from so we know where to send the reply
+ arpRequests.put(target, new ArpRequest(
+ new HostArpRequester(arp, sw.getId(), pi.getInPort()), false));
+
+ //Flood the request out edge ports
+ sendArpRequestToSwitches(target, pi.getPacketData(), sw.getId(), pi.getInPort());
}
else {
- arpTable.put(addr,
- new ArpTableEntry(arp.getSenderHardwareAddress(),
- System.currentTimeMillis()));
+ //We know the address, so send a reply
+ if (log.isTraceEnabled()) {
+ log.trace("Sending reply: {} => {} to host at {}/{}", new Object [] {
+ inetAddressToString(arp.getTargetProtocolAddress()),
+ macAddress.toString(),
+ HexString.toHexString(sw.getId()), pi.getInPort()});
+ }
+
+ sendArpReply(arp, sw.getId(), pi.getInPort(), macAddress);
}
}
- private void broadcastArpRequestOutEdge(OFPacketIn pi, long inSwitch, short inPort){
+ private void handleArpReply(IOFSwitch sw, OFPacketIn pi, ARP arp){
+ if (log.isTraceEnabled()) {
+ log.trace("ARP reply recieved: {} => {}, on {}/{}", new Object[] {
+ inetAddressToString(arp.getSenderProtocolAddress()),
+ HexString.toHexString(arp.getSenderHardwareAddress()),
+ HexString.toHexString(sw.getId()), pi.getInPort()});
+ }
+
+ InetAddress senderIpAddress;
+ try {
+ senderIpAddress = InetAddress.getByAddress(arp.getSenderProtocolAddress());
+ } catch (UnknownHostException e) {
+ log.debug("Invalid address in ARP reply", e);
+ return;
+ }
+
+ MACAddress senderMacAddress = MACAddress.valueOf(arp.getSenderHardwareAddress());
+
+ arpCache.update(senderIpAddress, senderMacAddress);
+
+ //See if anyone's waiting for this ARP reply
+ Set<ArpRequest> requests = arpRequests.get(senderIpAddress);
+
+ //Synchronize on the Multimap while using an iterator for one of the sets
+ List<ArpRequest> requestsToSend = new ArrayList<ArpRequest>(requests.size());
+ synchronized (arpRequests) {
+ Iterator<ArpRequest> it = requests.iterator();
+ while (it.hasNext()) {
+ ArpRequest request = it.next();
+ it.remove();
+ requestsToSend.add(request);
+ }
+ }
+
+ //Don't hold an ARP lock while dispatching requests
+ for (ArpRequest request : requestsToSend) {
+ request.dispatchReply(senderIpAddress, senderMacAddress);
+ }
+ }
+
+ private void sendArpRequestForAddress(InetAddress ipAddress) {
+ //TODO what should the sender IP address and MAC address be if no
+ //IP addresses are configured? Will there ever be a need to send
+ //ARP requests from the controller in that case?
+ //All-zero MAC address doesn't seem to work - hosts don't respond to it
+
+ byte[] zeroIpv4 = {0x0, 0x0, 0x0, 0x0};
+ byte[] zeroMac = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
+ byte[] genericNonZeroMac = {0x0, 0x0, 0x0, 0x0, 0x0, 0x01};
+ byte[] broadcastMac = {(byte)0xff, (byte)0xff, (byte)0xff,
+ (byte)0xff, (byte)0xff, (byte)0xff};
+
+ ARP arpRequest = new ARP();
+
+ arpRequest.setHardwareType(ARP.HW_TYPE_ETHERNET)
+ .setProtocolType(ARP.PROTO_TYPE_IP)
+ .setHardwareAddressLength((byte)Ethernet.DATALAYER_ADDRESS_LENGTH)
+ .setProtocolAddressLength((byte)IPv4.ADDRESS_LENGTH)
+ .setOpCode(ARP.OP_REQUEST)
+ .setTargetHardwareAddress(zeroMac)
+ .setTargetProtocolAddress(ipAddress.getAddress());
+
+ MACAddress routerMacAddress = layer3.getRouterMacAddress();
+ //TODO hack for now as it's unclear what the MAC address should be
+ byte[] senderMacAddress = genericNonZeroMac;
+ if (routerMacAddress != null) {
+ senderMacAddress = routerMacAddress.toBytes();
+ }
+ arpRequest.setSenderHardwareAddress(senderMacAddress);
+
+ byte[] senderIPAddress = zeroIpv4;
+ Interface intf = layer3.getOutgoingInterface(ipAddress);
+ if (intf != null) {
+ senderIPAddress = intf.getIpAddress().getAddress();
+ }
+
+ arpRequest.setSenderProtocolAddress(senderIPAddress);
+
+ Ethernet eth = new Ethernet();
+ eth.setSourceMACAddress(senderMacAddress)
+ .setDestinationMACAddress(broadcastMac)
+ .setEtherType(Ethernet.TYPE_ARP)
+ .setPayload(arpRequest);
+
+ sendArpRequestToSwitches(ipAddress, eth.serialize());
+ }
+
+ private void sendArpRequestToSwitches(InetAddress dstAddress, byte[] arpRequest) {
+ sendArpRequestToSwitches(dstAddress, arpRequest,
+ 0, OFPort.OFPP_NONE.getValue());
+ }
+
+ private void sendArpRequestToSwitches(InetAddress dstAddress, byte[] arpRequest,
+ long inSwitch, short inPort) {
+
+ if (layer3.hasLayer3Configuration()) {
+ Interface intf = layer3.getOutgoingInterface(dstAddress);
+ if (intf != null) {
+ sendArpRequestOutPort(arpRequest, intf.getDpid(), intf.getPort());
+ }
+ else {
+ //TODO here it should be broadcast out all non-interface edge ports.
+ //I think we can assume that if it's not a request for an external
+ //network, it's an ARP for a host in our own network. So we want to
+ //send it out all edge ports that don't have an interface configured
+ //to ensure it reaches all hosts in our network.
+ log.debug("No interface found to send ARP request for {}",
+ dstAddress.getHostAddress());
+ }
+ }
+ else {
+ broadcastArpRequestOutEdge(arpRequest, inSwitch, inPort);
+ }
+ }
+
+ private void broadcastArpRequestOutEdge(byte[] arpRequest, long inSwitch, short inPort) {
for (IOFSwitch sw : floodlightProvider.getSwitches().values()){
Collection<Short> enabledPorts = sw.getEnabledPortNumbers();
Set<Short> linkPorts = topology.getPortsWithLinks(sw.getId());
@@ -176,7 +406,7 @@
OFPacketOut po = new OFPacketOut();
po.setInPort(OFPort.OFPP_NONE)
.setBufferId(-1)
- .setPacketData(pi.getPacketData());
+ .setPacketData(arpRequest);
List<OFAction> actions = new ArrayList<OFAction>();
@@ -189,14 +419,13 @@
}
actions.add(new OFActionOutput(portNum));
- log.debug("Broadcasting out {}/{}", HexString.toHexString(sw.getId()), portNum);
}
po.setActions(actions);
short actionsLength = (short) (actions.size() * OFActionOutput.MINIMUM_LENGTH);
po.setActionsLength(actionsLength);
po.setLengthU(OFPacketOut.MINIMUM_LENGTH + actionsLength
- + pi.getPacketData().length);
+ + arpRequest.length);
List<OFMessage> msgList = new ArrayList<OFMessage>();
msgList.add(po);
@@ -210,26 +439,67 @@
}
}
- private void sendArpReply(ARP arpRequest, OFPacketIn pi, byte[] macRequested, IOFSwitch sw){
+ private void sendArpRequestOutPort(byte[] arpRequest, long dpid, short port) {
+ if (log.isTraceEnabled()) {
+ log.trace("Sending ARP request out {}/{}",
+ HexString.toHexString(dpid), port);
+ }
+
+ OFPacketOut po = new OFPacketOut();
+ po.setInPort(OFPort.OFPP_NONE)
+ .setBufferId(-1)
+ .setPacketData(arpRequest);
+
+ List<OFAction> actions = new ArrayList<OFAction>();
+ actions.add(new OFActionOutput(port));
+ po.setActions(actions);
+ short actionsLength = (short) (actions.size() * OFActionOutput.MINIMUM_LENGTH);
+ po.setActionsLength(actionsLength);
+ po.setLengthU(OFPacketOut.MINIMUM_LENGTH + actionsLength
+ + arpRequest.length);
+
+ IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
+
+ if (sw == null) {
+ log.warn("Switch not found when sending ARP request");
+ return;
+ }
+
+ try {
+ sw.write(po, null);
+ sw.flush();
+ } catch (IOException e) {
+ log.error("Failure writing packet out to switch", e);
+ }
+ }
+
+ private void sendArpReply(ARP arpRequest, long dpid, short port, MACAddress targetMac) {
+ if (log.isTraceEnabled()) {
+ log.trace("Sending reply {} => {} to {}", new Object[] {
+ inetAddressToString(arpRequest.getTargetProtocolAddress()),
+ targetMac,
+ inetAddressToString(arpRequest.getSenderProtocolAddress())});
+ }
+
ARP arpReply = new ARP();
arpReply.setHardwareType(ARP.HW_TYPE_ETHERNET)
.setProtocolType(ARP.PROTO_TYPE_IP)
.setHardwareAddressLength((byte)Ethernet.DATALAYER_ADDRESS_LENGTH)
- .setProtocolAddressLength((byte)4) //can't find the constant anywhere
+ .setProtocolAddressLength((byte)IPv4.ADDRESS_LENGTH)
.setOpCode(ARP.OP_REPLY)
- .setSenderHardwareAddress(macRequested)
+ .setSenderHardwareAddress(targetMac.toBytes())
.setSenderProtocolAddress(arpRequest.getTargetProtocolAddress())
.setTargetHardwareAddress(arpRequest.getSenderHardwareAddress())
.setTargetProtocolAddress(arpRequest.getSenderProtocolAddress());
Ethernet eth = new Ethernet();
eth.setDestinationMACAddress(arpRequest.getSenderHardwareAddress())
- .setSourceMACAddress(macRequested)
+ .setSourceMACAddress(targetMac.toBytes())
.setEtherType(Ethernet.TYPE_ARP)
.setPayload(arpReply);
List<OFAction> actions = new ArrayList<OFAction>();
- actions.add(new OFActionOutput(pi.getInPort()));
+ actions.add(new OFActionOutput(port));
OFPacketOut po = new OFPacketOut();
po.setInPort(OFPort.OFPP_NONE)
@@ -242,27 +512,54 @@
List<OFMessage> msgList = new ArrayList<OFMessage>();
msgList.add(po);
+
+ IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
+
+ if (sw == null) {
+ log.warn("Switch {} not found when sending ARP reply",
+ HexString.toHexString(dpid));
+ return;
+ }
try {
- log.debug("Sending ARP reply to {}/{}", HexString.toHexString(sw.getId()), pi.getInPort());
sw.write(msgList, null);
sw.flush();
} catch (IOException e) {
- log.warn("Failure writing packet out to switch", e);
+ log.error("Failure writing packet out to switch", e);
}
}
-
- //TODO this should be put somewhere more central. I use it in BgpRoute as well.
- //We need a HexString.toHexString() equivalent.
- private String bytesToStringAddr(byte[] bytes){
- InetAddress addr;
+
+ private String inetAddressToString(byte[] bytes) {
try {
- addr = InetAddress.getByAddress(bytes);
+ return InetAddress.getByAddress(bytes).getHostAddress();
} catch (UnknownHostException e) {
- log.warn(" ", e);
+ log.debug("Invalid IP address", e);
return "";
}
- if (addr == null) return "";
- else return addr.getHostAddress();
+ }
+
+ /*
+ * IProxyArpService methods
+ */
+
+ @Override
+ public MACAddress getMacAddress(InetAddress ipAddress) {
+ return arpCache.lookup(ipAddress);
+ }
+
+ @Override
+ public void sendArpRequest(InetAddress ipAddress, IArpRequester requester,
+ boolean retry) {
+ arpRequests.put(ipAddress, new ArpRequest(requester, retry));
+
+ //Sanity check to make sure we don't send a request for our own address
+ if (!layer3.isInterfaceAddress(ipAddress)) {
+ sendArpRequestForAddress(ipAddress);
+ }
+ }
+
+ @Override
+ public List<String> getMappings() {
+ return arpCache.getMappings();
}
}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/routing/TopoRouteService.java b/src/main/java/net/onrc/onos/ofcontroller/routing/TopoRouteService.java
index 59e76ca..21381d9 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/routing/TopoRouteService.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/routing/TopoRouteService.java
@@ -1,7 +1,5 @@
package net.onrc.onos.ofcontroller.routing;
-import java.util.ArrayList;
-import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@@ -27,8 +25,6 @@
import com.tinkerpop.blueprints.Direction;
import com.tinkerpop.blueprints.Vertex;
-import com.tinkerpop.pipes.PipeFunction;
-import com.tinkerpop.pipes.branch.LoopPipe.LoopBundle;
/**
@@ -202,6 +198,10 @@
// The local Port info
//
for (Vertex myPortVertex : nodeVertex.getVertices(Direction.OUT, "on")) {
+ // Ignore inactive ports
+ if (! myPortVertex.getProperty("state").toString().equals("ACTIVE"))
+ continue;
+
short myPort = 0;
Object obj = myPortVertex.getProperty("number");
if (obj instanceof Short) {
@@ -215,6 +215,10 @@
// The neighbor Port info
//
for (Vertex neighborPortVertex : myPortVertex.getVertices(Direction.OUT, "link")) {
+ // Ignore inactive ports
+ if (! neighborPortVertex.getProperty("state").toString().equals("ACTIVE"))
+ continue;
+
short neighborPort = 0;
obj = neighborPortVertex.getProperty("number");
if (obj instanceof Short) {
@@ -448,7 +452,15 @@
break;
}
for (Vertex parentPort : nextVertex.getVertices(Direction.OUT, "on")) {
+ // Ignore inactive ports
+ if (! parentPort.getProperty("state").toString().equals("ACTIVE"))
+ continue;
+
for (Vertex childPort : parentPort.getVertices(Direction.OUT, "link")) {
+ // Ignore inactive ports
+ if (! childPort.getProperty("state").toString().equals("ACTIVE"))
+ continue;
+
for (Vertex child : childPort.getVertices(Direction.IN, "on")) {
// Ignore inactive switches
String state = child.getProperty("state").toString();
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/DataPath.java b/src/main/java/net/onrc/onos/ofcontroller/util/DataPath.java
index 5f96414..dec70e3 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/DataPath.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/DataPath.java
@@ -5,7 +5,7 @@
import org.codehaus.jackson.annotate.JsonProperty;
/**
- * The class representing the Data Path.
+ * The data forwarding path state from a source to a destination.
*/
public class DataPath {
private SwitchPort srcPort; // The source port
@@ -76,6 +76,31 @@
}
/**
+ * Apply Flow Path Flags to the pre-computed Data Path.
+ *
+ * @param flowPathFlags the Flow Path Flags to apply.
+ */
+ public void applyFlowPathFlags(FlowPathFlags flowPathFlags) {
+ if (flowPathFlags == null)
+ return; // Nothing to do
+
+ // Discard the first Flow Entry
+ if (flowPathFlags.isDiscardFirstHopEntry()) {
+ if (flowEntries.size() > 0)
+ flowEntries.remove(0);
+ }
+
+ // Keep only the first Flow Entry
+ if (flowPathFlags.isKeepOnlyFirstHopEntry()) {
+ if (flowEntries.size() > 1) {
+ FlowEntry flowEntry = flowEntries.get(0);
+ flowEntries.clear();
+ flowEntries.add(flowEntry);
+ }
+ }
+ }
+
+ /**
* Get a string with the summary of the shortest-path data path
* computation.
*
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntry.java b/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntry.java
index 7dd0699..762d272 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntry.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntry.java
@@ -1,6 +1,5 @@
package net.onrc.onos.ofcontroller.util;
-import java.util.ArrayList;
import org.codehaus.jackson.annotate.JsonIgnore;
import org.codehaus.jackson.annotate.JsonProperty;
@@ -12,10 +11,10 @@
* support multiple in-ports and multiple out-ports.
*/
public class FlowEntry {
- private FlowId flowId; // FlowID of flowEntry
+ private FlowId flowId; // FlowID of the Flow Entry
private FlowEntryId flowEntryId; // The Flow Entry ID
private FlowEntryMatch flowEntryMatch; // The Flow Entry Match
- private ArrayList<FlowEntryAction> flowEntryActions; // The Flow Entry Actions
+ private FlowEntryActions flowEntryActions; // The Flow Entry Actions
private Dpid dpid; // The Switch DPID
private Port inPort; // The Switch incoming port. Used only
// when the entry is used to return
@@ -53,64 +52,64 @@
flowEntryMatch.enableDstTcpUdpPort((short)80);
FlowEntryAction action = null;
- ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
+ FlowEntryActions actions = new FlowEntryActions();
action = new FlowEntryAction();
action.setActionOutput(new Port((short)12));
- actions.add(action);
+ actions.addAction(action);
action = new FlowEntryAction();
action.setActionOutputToController((short)13);
- actions.add(action);
+ actions.addAction(action);
action = new FlowEntryAction();
action.setActionSetVlanId((short)14);
- actions.add(action);
+ actions.addAction(action);
action = new FlowEntryAction();
action.setActionSetVlanPriority((byte)15);
- actions.add(action);
+ actions.addAction(action);
action = new FlowEntryAction();
action.setActionStripVlan(true);
- actions.add(action);
+ actions.addAction(action);
action = new FlowEntryAction();
action.setActionSetEthernetSrcAddr(mac);
- actions.add(action);
+ actions.addAction(action);
action = new FlowEntryAction();
action.setActionSetEthernetDstAddr(mac);
- actions.add(action);
+ actions.addAction(action);
action = new FlowEntryAction();
action.setActionSetIPv4SrcAddr(ipv4);
- actions.add(action);
+ actions.addAction(action);
action = new FlowEntryAction();
action.setActionSetIPv4DstAddr(ipv4);
- actions.add(action);
+ actions.addAction(action);
action = new FlowEntryAction();
action.setActionSetIpToS((byte)16);
- actions.add(action);
+ actions.addAction(action);
action = new FlowEntryAction();
action.setActionSetTcpUdpSrcPort((short)17);
- actions.add(action);
+ actions.addAction(action);
action = new FlowEntryAction();
action.setActionSetTcpUdpDstPort((short)18);
- actions.add(action);
+ actions.addAction(action);
action = new FlowEntryAction();
action.setActionEnqueue(new Port((short)19), 20);
- actions.add(action);
+ actions.addAction(action);
setFlowEntryActions(actions);
*/
-
+ flowEntryActions = new FlowEntryActions();
flowEntryUserState = FlowEntryUserState.FE_USER_UNKNOWN;
flowEntrySwitchState = FlowEntrySwitchState.FE_SWITCH_UNKNOWN;
}
@@ -173,7 +172,7 @@
* @return the Flow Entry Actions.
*/
@JsonProperty("flowEntryActions")
- public ArrayList<FlowEntryAction> flowEntryActions() {
+ public FlowEntryActions flowEntryActions() {
return flowEntryActions;
}
@@ -183,7 +182,7 @@
* @param flowEntryActions the Flow Entry Actions to set.
*/
@JsonProperty("flowEntryActions")
- public void setFlowEntryActions(ArrayList<FlowEntryAction> flowEntryActions) {
+ public void setFlowEntryActions(FlowEntryActions flowEntryActions) {
this.flowEntryActions = flowEntryActions;
}
@@ -319,27 +318,39 @@
* Convert the flow entry to a string.
*
* The string has the following form:
- * [flowEntryId=XXX flowEntryMatch=XXX flowEntryAction=XXX
- * flowEntryAction=XXX flowEntryAction=XXX dpid=XXX
+ * [flowEntryId=XXX flowEntryMatch=XXX flowEntryActions=XXX dpid=XXX
* inPort=XXX outPort=XXX flowEntryUserState=XXX flowEntrySwitchState=XXX
* flowEntryErrorState=XXX]
* @return the flow entry as a string.
*/
@Override
public String toString() {
- String ret = "[flowEntryId=" + this.flowEntryId.toString();
- ret += " flowEntryMatch=" + this.flowEntryMatch.toString();
- for (FlowEntryAction fa : flowEntryActions) {
- ret += " flowEntryAction=" + fa.toString();
+ StringBuilder ret = new StringBuilder();
+ if ( flowEntryId != null ) {
+ ret.append("[flowEntryId=" + this.flowEntryId.toString());
+ } else {
+ ret.append("[");
}
- ret += " dpid=" + this.dpid.toString();
- ret += " inPort=" + this.inPort.toString();
- ret += " outPort=" + this.outPort.toString();
- ret += " flowEntryUserState=" + this.flowEntryUserState;
- ret += " flowEntrySwitchState=" + this.flowEntrySwitchState;
- ret += " flowEntryErrorState=" + this.flowEntryErrorState.toString();
- ret += "]";
+ if ( flowEntryMatch != null ) {
+ ret.append(" flowEntryMatch=" + this.flowEntryMatch.toString());
+ }
+ ret.append( " flowEntryActions=" + this.flowEntryActions.toString() );
+ if ( dpid != null ) {
+ ret.append(" dpid=" + this.dpid.toString());
+ }
+ if ( inPort != null ) {
+ ret.append(" inPort=" + this.inPort.toString());
+ }
+ if ( outPort != null ) {
+ ret.append(" outPort=" + this.outPort.toString());
+ }
+ ret.append(" flowEntryUserState=" + this.flowEntryUserState);
+ ret.append(" flowEntrySwitchState=" + this.flowEntrySwitchState);
+ if ( flowEntryErrorState != null ) {
+ ret.append(" flowEntryErrorState=" + this.flowEntryErrorState.toString());
+ }
+ ret.append("]");
- return ret;
+ return ret.toString();
}
}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntryAction.java b/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntryAction.java
index 22aef98..1f8849a 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntryAction.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntryAction.java
@@ -7,7 +7,9 @@
/**
* The class representing a single Flow Entry action.
*
- * A set of Flow Entry actions need to be applied to each packet.
+ * A Flow Entry action that needs to be applied to each packet.
+ * Note that it contains only a single action. Multiple actions are
+ * listed in a list inside @ref FlowEntryActions.
*/
public class FlowEntryAction {
/**
@@ -59,6 +61,28 @@
this.maxLen = 0;
}
+ /**
+ * Copy constructor.
+ *
+ * @param other the object to copy from.
+ */
+ public ActionOutput(ActionOutput other) {
+ if (other.port != null)
+ this.port = new Port(other.port);
+ this.maxLen = other.maxLen;
+ }
+
+ /**
+ * Constructor from a string.
+ *
+ * The string has the following form:
+ * [port=XXX maxLen=XXX]
+ *
+ * @param actionStr the action as a string.
+ */
+ public ActionOutput(String actionStr) {
+ this.fromString(actionStr);
+ }
/**
* Constructor for a given output port and maximum length.
@@ -121,6 +145,54 @@
return ret;
}
+
+ /**
+ * Convert a string to an action.
+ *
+ * The string has the following form:
+ * [port=XXX maxLen=XXX]
+ *
+ * @param actionStr the action as a string.
+ */
+ public void fromString(String actionStr) {
+ String[] parts = actionStr.split(" ");
+ String decode = null;
+
+ // Decode the "port=XXX" part
+ if (parts.length > 0)
+ decode = parts[0];
+ if (decode != null) {
+ String[] tokens = decode.split("port=");
+ if (tokens.length > 1 && tokens[1] != null) {
+ try {
+ Short valueShort = Short.valueOf(tokens[1]);
+ port = new Port(valueShort);
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Invalid action string");
+ }
+ }
+ } else {
+ throw new IllegalArgumentException("Invalid action string");
+ }
+
+ // Decode the "maxLen=XXX" part
+ decode = null;
+ if (parts.length > 1)
+ decode = parts[1];
+ if (decode != null) {
+ decode = decode.replace("]", "");
+ String[] tokens = decode.split("maxLen=");
+ if (tokens.length > 1 && tokens[1] != null) {
+ try {
+ maxLen = Short.valueOf(tokens[1]);
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Invalid action string");
+ }
+ }
+ } else {
+ throw new IllegalArgumentException("Invalid action string");
+ }
+ }
}
/**
@@ -137,6 +209,27 @@
}
/**
+ * Copy constructor.
+ *
+ * @param other the object to copy from.
+ */
+ public ActionSetVlanId(ActionSetVlanId other) {
+ this.vlanId = other.vlanId;
+ }
+
+ /**
+ * Constructor from a string.
+ *
+ * The string has the following form:
+ * [vlanId=XXX]
+ *
+ * @param actionStr the action as a string.
+ */
+ public ActionSetVlanId(String actionStr) {
+ this.fromString(actionStr);
+ }
+
+ /**
* Constructor for a given VLAN ID.
*
* @param vlanId the VLAN ID to set.
@@ -171,6 +264,33 @@
return ret;
}
+
+ /**
+ * Convert a string to an action.
+ *
+ * The string has the following form:
+ * [vlanId=XXX]
+ *
+ * @param actionStr the action as a string.
+ */
+ public void fromString(String actionStr) {
+ String[] parts = actionStr.split("vlanId=");
+ String decode = null;
+
+ // Decode the value
+ if (parts.length > 1)
+ decode = parts[1];
+ if (decode != null) {
+ decode = decode.replace("]", "");
+ try {
+ vlanId = Short.valueOf(decode);
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Invalid action string");
+ }
+ } else {
+ throw new IllegalArgumentException("Invalid action string");
+ }
+ }
}
/**
@@ -187,6 +307,27 @@
}
/**
+ * Copy constructor.
+ *
+ * @param other the object to copy from.
+ */
+ public ActionSetVlanPriority(ActionSetVlanPriority other) {
+ this.vlanPriority = other.vlanPriority;
+ }
+
+ /**
+ * Constructor from a string.
+ *
+ * The string has the following form:
+ * [vlanPriority=XXX]
+ *
+ * @param actionStr the action as a string.
+ */
+ public ActionSetVlanPriority(String actionStr) {
+ this.fromString(actionStr);
+ }
+
+ /**
* Constructor for a given VLAN priority.
*
* @param vlanPriority the VLAN priority to set.
@@ -221,6 +362,33 @@
return ret;
}
+
+ /**
+ * Convert a string to an action.
+ *
+ * The string has the following form:
+ * [vlanPriority=XXX]
+ *
+ * @param actionStr the action as a string.
+ */
+ public void fromString(String actionStr) {
+ String[] parts = actionStr.split("vlanPriority=");
+ String decode = null;
+
+ // Decode the value
+ if (parts.length > 1)
+ decode = parts[1];
+ if (decode != null) {
+ decode = decode.replace("]", "");
+ try {
+ vlanPriority = Byte.valueOf(decode);
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Invalid action string");
+ }
+ } else {
+ throw new IllegalArgumentException("Invalid action string");
+ }
+ }
}
/**
@@ -237,6 +405,27 @@
}
/**
+ * Copy constructor.
+ *
+ * @param other the object to copy from.
+ */
+ public ActionStripVlan(ActionStripVlan other) {
+ this.stripVlan = other.stripVlan;
+ }
+
+ /**
+ * Constructor from a string.
+ *
+ * The string has the following form:
+ * [stripVlan=XXX]
+ *
+ * @param actionStr the action as a string.
+ */
+ public ActionStripVlan(String actionStr) {
+ this.fromString(actionStr);
+ }
+
+ /**
* Constructor for a given boolean flag.
*
* @param stripVlan if true, strip the VLAN header.
@@ -271,6 +460,29 @@
return ret;
}
+
+ /**
+ * Convert a string to an action.
+ *
+ * The string has the following form:
+ * [stripVlan=XXX]
+ *
+ * @param actionStr the action as a string.
+ */
+ public void fromString(String actionStr) {
+ String[] parts = actionStr.split("stripVlan=");
+ String decode = null;
+
+ // Decode the value
+ if (parts.length > 1)
+ decode = parts[1];
+ if (decode != null) {
+ decode = decode.replace("]", "");
+ stripVlan = Boolean.valueOf(decode);
+ } else {
+ throw new IllegalArgumentException("Invalid action string");
+ }
+ }
}
/**
@@ -288,6 +500,28 @@
}
/**
+ * Copy constructor.
+ *
+ * @param other the object to copy from.
+ */
+ public ActionSetEthernetAddr(ActionSetEthernetAddr other) {
+ if (other.addr != null)
+ this.addr = MACAddress.valueOf(other.addr.toLong());
+ }
+
+ /**
+ * Constructor from a string.
+ *
+ * The string has the following form:
+ * [addr=XXX]
+ *
+ * @param actionStr the action as a string.
+ */
+ public ActionSetEthernetAddr(String actionStr) {
+ this.fromString(actionStr);
+ }
+
+ /**
* Constructor for a given MAC address.
*
* @param addr the MAC address to set.
@@ -322,6 +556,33 @@
return ret;
}
+
+ /**
+ * Convert a string to an action.
+ *
+ * The string has the following form:
+ * [addr=XXX]
+ *
+ * @param actionStr the action as a string.
+ */
+ public void fromString(String actionStr) {
+ String[] parts = actionStr.split("addr=");
+ String decode = null;
+
+ // Decode the value
+ if (parts.length > 1)
+ decode = parts[1];
+ if (decode != null) {
+ decode = decode.replace("]", "");
+ try {
+ addr = MACAddress.valueOf(decode);
+ } catch (IllegalArgumentException e) {
+ throw new IllegalArgumentException("Invalid action string");
+ }
+ } else {
+ throw new IllegalArgumentException("Invalid action string");
+ }
+ }
}
/**
@@ -339,6 +600,28 @@
}
/**
+ * Copy constructor.
+ *
+ * @param other the object to copy from.
+ */
+ public ActionSetIPv4Addr(ActionSetIPv4Addr other) {
+ if (other.addr != null)
+ this.addr = new IPv4(other.addr);
+ }
+
+ /**
+ * Constructor from a string.
+ *
+ * The string has the following form:
+ * [addr=XXX]
+ *
+ * @param actionStr the action as a string.
+ */
+ public ActionSetIPv4Addr(String actionStr) {
+ this.fromString(actionStr);
+ }
+
+ /**
* Constructor for a given IPv4 address.
*
* @param addr the IPv4 address to set.
@@ -373,6 +656,33 @@
return ret;
}
+
+ /**
+ * Convert a string to an action.
+ *
+ * The string has the following form:
+ * [addr=XXX]
+ *
+ * @param actionStr the action as a string.
+ */
+ public void fromString(String actionStr) {
+ String[] parts = actionStr.split("addr=");
+ String decode = null;
+
+ // Decode the value
+ if (parts.length > 1)
+ decode = parts[1];
+ if (decode != null) {
+ decode = decode.replace("]", "");
+ try {
+ addr = new IPv4(decode);
+ } catch (IllegalArgumentException e) {
+ throw new IllegalArgumentException("Invalid action string");
+ }
+ } else {
+ throw new IllegalArgumentException("Invalid action string");
+ }
+ }
}
/**
@@ -390,6 +700,27 @@
}
/**
+ * Copy constructor.
+ *
+ * @param other the object to copy from.
+ */
+ public ActionSetIpToS(ActionSetIpToS other) {
+ this.ipToS = other.ipToS;
+ }
+
+ /**
+ * Constructor from a string.
+ *
+ * The string has the following form:
+ * [ipToS=XXX]
+ *
+ * @param actionStr the action as a string.
+ */
+ public ActionSetIpToS(String actionStr) {
+ this.fromString(actionStr);
+ }
+
+ /**
* Constructor for a given IP ToS (DSCP field, 6 bits).
*
* @param ipToS the IP ToS (DSCP field, 6 bits) to set.
@@ -424,6 +755,33 @@
return ret;
}
+
+ /**
+ * Convert a string to an action.
+ *
+ * The string has the following form:
+ * [ipToS=XXX]
+ *
+ * @param actionStr the action as a string.
+ */
+ public void fromString(String actionStr) {
+ String[] parts = actionStr.split("ipToS=");
+ String decode = null;
+
+ // Decode the value
+ if (parts.length > 1)
+ decode = parts[1];
+ if (decode != null) {
+ decode = decode.replace("]", "");
+ try {
+ ipToS = Byte.valueOf(decode);
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Invalid action string");
+ }
+ } else {
+ throw new IllegalArgumentException("Invalid action string");
+ }
+ }
}
/**
@@ -441,6 +799,27 @@
}
/**
+ * Copy constructor.
+ *
+ * @param other the object to copy from.
+ */
+ public ActionSetTcpUdpPort(ActionSetTcpUdpPort other) {
+ this.port = other.port;
+ }
+
+ /**
+ * Constructor from a string.
+ *
+ * The string has the following form:
+ * [port=XXX]
+ *
+ * @param actionStr the action as a string.
+ */
+ public ActionSetTcpUdpPort(String actionStr) {
+ this.fromString(actionStr);
+ }
+
+ /**
* Constructor for a given TCP/UDP port.
*
* @param port the TCP/UDP port to set.
@@ -475,6 +854,33 @@
return ret;
}
+
+ /**
+ * Convert a string to an action.
+ *
+ * The string has the following form:
+ * [port=XXX]
+ *
+ * @param actionStr the action as a string.
+ */
+ public void fromString(String actionStr) {
+ String[] parts = actionStr.split("port=");
+ String decode = null;
+
+ // Decode the value
+ if (parts.length > 1)
+ decode = parts[1];
+ if (decode != null) {
+ decode = decode.replace("]", "");
+ try {
+ port = Short.valueOf(decode);
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Invalid action string");
+ }
+ } else {
+ throw new IllegalArgumentException("Invalid action string");
+ }
+ }
}
/**
@@ -495,6 +901,29 @@
}
/**
+ * Copy constructor.
+ *
+ * @param other the object to copy from.
+ */
+ public ActionEnqueue(ActionEnqueue other) {
+ if (other.port != null)
+ this.port = new Port(other.port);
+ this.queueId = other.queueId;
+ }
+
+ /**
+ * Constructor from a string.
+ *
+ * The string has the following form:
+ * [port=XXX queueId=XXX]
+ *
+ * @param actionStr the action as a string.
+ */
+ public ActionEnqueue(String actionStr) {
+ this.fromString(actionStr);
+ }
+
+ /**
* Constructor for a given port and queue ID.
*
* @param port the port to set.
@@ -542,6 +971,54 @@
return ret;
}
+
+ /**
+ * Convert a string to an action.
+ *
+ * The string has the following form:
+ * [port=XXX queueId=XXX]
+ *
+ * @param actionStr the action as a string.
+ */
+ public void fromString(String actionStr) {
+ String[] parts = actionStr.split(" ");
+ String decode = null;
+
+ // Decode the "port=XXX" part
+ if (parts.length > 0)
+ decode = parts[0];
+ if (decode != null) {
+ String[] tokens = decode.split("port=");
+ if (tokens.length > 1 && tokens[1] != null) {
+ try {
+ Short valueShort = Short.valueOf(tokens[1]);
+ port = new Port(valueShort);
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Invalid action string");
+ }
+ }
+ } else {
+ throw new IllegalArgumentException("Invalid action string");
+ }
+
+ // Decode the "queueId=XXX" part
+ decode = null;
+ if (parts.length > 1)
+ decode = parts[1];
+ if (decode != null) {
+ decode = decode.replace("]", "");
+ String[] tokens = decode.split("queueId=");
+ if (tokens.length > 1 && tokens[1] != null) {
+ try {
+ queueId = Short.valueOf(tokens[1]);
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Invalid action string");
+ }
+ }
+ } else {
+ throw new IllegalArgumentException("Invalid action string");
+ }
+ }
}
private ActionValues actionType; // The action type
@@ -571,6 +1048,88 @@
}
/**
+ * Copy constructor.
+ *
+ * @param other the object to copy from.
+ */
+ public FlowEntryAction(FlowEntryAction other) {
+ this.actionType = other.actionType;
+
+ //
+ if (other.actionOutput != null)
+ this.actionOutput = new ActionOutput(other.actionOutput);
+ else
+ this.actionOutput = null;
+ //
+ if (other.actionSetVlanId != null)
+ this.actionSetVlanId = new ActionSetVlanId(other.actionSetVlanId);
+ else
+ this.actionSetVlanId = null;
+ //
+ if (other.actionSetVlanPriority != null)
+ this.actionSetVlanPriority = new ActionSetVlanPriority(other.actionSetVlanPriority);
+ else
+ this.actionSetVlanPriority = null;
+ //
+ if (other.actionStripVlan != null)
+ this.actionStripVlan = new ActionStripVlan(other.actionStripVlan);
+ else
+ this.actionStripVlan = null;
+ //
+ if (other.actionSetEthernetSrcAddr != null)
+ this.actionSetEthernetSrcAddr = new ActionSetEthernetAddr(other.actionSetEthernetSrcAddr);
+ else
+ this.actionSetEthernetSrcAddr = null;
+ //
+ if (other.actionSetEthernetDstAddr != null)
+ this.actionSetEthernetDstAddr = new ActionSetEthernetAddr(other.actionSetEthernetDstAddr);
+ else
+ this.actionSetEthernetDstAddr = null;
+ //
+ if (other.actionSetIPv4SrcAddr != null)
+ this.actionSetIPv4SrcAddr = new ActionSetIPv4Addr(other.actionSetIPv4SrcAddr);
+ else
+ this.actionSetIPv4SrcAddr = null;
+ //
+ if (other.actionSetIPv4DstAddr != null)
+ this.actionSetIPv4DstAddr = new ActionSetIPv4Addr(other.actionSetIPv4DstAddr);
+ else
+ this.actionSetIPv4DstAddr = null;
+ //
+ if (other.actionSetIpToS != null)
+ this.actionSetIpToS = new ActionSetIpToS(other.actionSetIpToS);
+ else
+ this.actionSetIpToS = null;
+ //
+ if (other.actionSetTcpUdpSrcPort != null)
+ this.actionSetTcpUdpSrcPort = new ActionSetTcpUdpPort(other.actionSetTcpUdpSrcPort);
+ else
+ this.actionSetTcpUdpSrcPort = null;
+ //
+ if (other.actionSetTcpUdpDstPort != null)
+ this.actionSetTcpUdpDstPort = new ActionSetTcpUdpPort(other.actionSetTcpUdpDstPort);
+ else
+ this.actionSetTcpUdpDstPort = null;
+ //
+ if (other.actionEnqueue != null)
+ this.actionEnqueue = new ActionEnqueue(other.actionEnqueue);
+ else
+ this.actionEnqueue = null;
+ }
+
+ /**
+ * Constructor from a string.
+ *
+ * The string has the following form:
+ * [type=XXX action=XXX]
+ *
+ * @param actionStr the action as a string.
+ */
+ public FlowEntryAction(String actionStr) {
+ this.fromString(actionStr);
+ }
+
+ /**
* Get the action type.
*
* @return the action type.
@@ -949,7 +1508,7 @@
* Set the action to output to queue on a port.
*
* @param port the port to set.
- * @param int queueId the queue ID to set.
+ * @param queueId the queue ID to set.
*/
public void setActionEnqueue(Port port, int queueId) {
actionEnqueue = new ActionEnqueue(port, queueId);
@@ -957,12 +1516,12 @@
}
/**
- * Convert the set of actions to a string.
+ * Convert the action to a string.
*
* The string has the following form:
* [type=XXX action=XXX]
*
- * @return the set of actions as a string.
+ * @return the action as a string.
*/
@Override
public String toString() {
@@ -1010,4 +1569,96 @@
return ret;
}
+
+ /**
+ * Convert a string to an action.
+ *
+ * The string has the following form:
+ * [type=XXX action=XXX]
+ *
+ * @param actionStr the action as a string.
+ */
+ public void fromString(String actionStr) {
+ String[] parts = actionStr.split("type=");
+ String decode = null;
+
+ // Extract the string after the "type="
+ if (parts.length > 1)
+ decode = parts[1];
+ if (decode == null)
+ throw new IllegalArgumentException("Invalid action string");
+
+ // Remove the trailing ']'
+ if ((decode.length() > 0) && (decode.charAt(decode.length() - 1) == ']')) {
+ decode = decode.substring(0, decode.length() - 1);
+ } else {
+ throw new IllegalArgumentException("Invalid action string");
+ }
+
+ // Extract the type value and the action value
+ parts = decode.split(" action=");
+
+ // Decode the "type=XXX" payload
+ if (parts.length > 0)
+ decode = parts[0];
+ if (decode != null) {
+ try {
+ actionType = Enum.valueOf(ActionValues.class, decode);
+ } catch (IllegalArgumentException e) {
+ throw new IllegalArgumentException("Invalid action string");
+ }
+ } else {
+ throw new IllegalArgumentException("Invalid action string");
+ }
+
+ // Decode the "action=XXX" payload
+ decode = null;
+ if (parts.length > 1)
+ decode = parts[1];
+ if (decode == null)
+ throw new IllegalArgumentException("Invalid action string");
+ //
+ try {
+ switch (actionType) {
+ case ACTION_OUTPUT:
+ actionOutput = new ActionOutput(decode);
+ break;
+ case ACTION_SET_VLAN_VID:
+ actionSetVlanId = new ActionSetVlanId(decode);
+ break;
+ case ACTION_SET_VLAN_PCP:
+ actionSetVlanPriority = new ActionSetVlanPriority(decode);
+ break;
+ case ACTION_STRIP_VLAN:
+ actionStripVlan = new ActionStripVlan(decode);
+ break;
+ case ACTION_SET_DL_SRC:
+ actionSetEthernetSrcAddr = new ActionSetEthernetAddr(decode);
+ break;
+ case ACTION_SET_DL_DST:
+ actionSetEthernetDstAddr = new ActionSetEthernetAddr(decode);
+ break;
+ case ACTION_SET_NW_SRC:
+ actionSetIPv4SrcAddr = new ActionSetIPv4Addr(decode);
+ break;
+ case ACTION_SET_NW_DST:
+ actionSetIPv4DstAddr = new ActionSetIPv4Addr(decode);
+ break;
+ case ACTION_SET_NW_TOS:
+ actionSetIpToS = new ActionSetIpToS(decode);
+ break;
+ case ACTION_SET_TP_SRC:
+ actionSetTcpUdpSrcPort = new ActionSetTcpUdpPort(decode);
+ break;
+ case ACTION_SET_TP_DST:
+ actionSetTcpUdpDstPort = new ActionSetTcpUdpPort(decode);
+ break;
+ case ACTION_ENQUEUE:
+ actionEnqueue = new ActionEnqueue(decode);
+ break;
+ }
+ } catch (IllegalArgumentException e) {
+ throw new IllegalArgumentException("Invalid action string");
+ }
+ }
}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntryActions.java b/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntryActions.java
new file mode 100644
index 0000000..53aab66
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntryActions.java
@@ -0,0 +1,146 @@
+package net.onrc.onos.ofcontroller.util;
+
+import java.util.ArrayList;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+/**
+ * The class representing multiple Flow Entry actions.
+ *
+ * A set of Flow Entry actions need to be applied to each packet.
+ */
+public class FlowEntryActions {
+ private ArrayList<FlowEntryAction> actions; // The Flow Entry Actions
+
+ /**
+ * Default constructor.
+ */
+ public FlowEntryActions() {
+ actions = new ArrayList<FlowEntryAction>();
+ }
+
+ /**
+ * Constructor from a string.
+ *
+ * The string has the following form:
+ * [[type=XXX action=XXX];[type=XXX action=XXX];...;]
+ *
+ * @param actionsStr the set of actions as a string.
+ */
+ public FlowEntryActions(String actionsStr) {
+ this.fromString(actionsStr);
+ }
+
+ /**
+ * Copy constructor.
+ *
+ * @param other the object to copy from.
+ */
+ public FlowEntryActions(FlowEntryActions other) {
+ actions = new ArrayList<FlowEntryAction>();
+
+ for (FlowEntryAction action : other.actions) {
+ FlowEntryAction newAction = new FlowEntryAction(action);
+ actions.add(newAction);
+ }
+ }
+
+ /**
+ * Get the Flow Entry Actions.
+ *
+ * @return the Flow Entry Actions.
+ */
+ @JsonProperty("actions")
+ public ArrayList<FlowEntryAction> actions() {
+ return actions;
+ }
+
+ /**
+ * Set the Flow Entry Actions.
+ *
+ * @param actions the Flow Entry Actions to set.
+ */
+ @JsonProperty("actions")
+ public void setActions(ArrayList<FlowEntryAction> actions) {
+ this.actions = actions;
+ }
+
+ /**
+ * Add a Flow Entry Action.
+ *
+ * @param flowEntryAction the Flow Entry Action to add.
+ */
+ public void addAction(FlowEntryAction flowEntryAction) {
+ actions.add(flowEntryAction);
+ }
+
+ /**
+ * Test whether the set of actions is empty.
+ *
+ * @return true if the set of actions is empty, otherwise false.
+ */
+ public Boolean isEmpty() {
+ return actions.isEmpty();
+ }
+
+ /**
+ * Convert the set of actions to a string.
+ *
+ * The string has the following form:
+ * [[type=XXX action=XXX];[type=XXX action=XXX];...;]
+ *
+ * @return the set of actions as a string.
+ */
+ @Override
+ public String toString() {
+ String ret = "[";
+ for (FlowEntryAction action : actions) {
+ ret += action.toString() + ";";
+ }
+ ret += "]";
+
+ return ret;
+ }
+
+ /**
+ * Convert a string to a set of actions.
+ *
+ * The string has the following form:
+ * [[type=XXX action=XXX];[type=XXX action=XXX];...;]
+ *
+ * @param actionsStr the set of actions as a string.
+ */
+ public void fromString(String actionsStr) {
+ String decode = actionsStr;
+
+ actions = new ArrayList<FlowEntryAction>();
+
+ if (decode.isEmpty())
+ return; // Nothing to do
+
+ // Remove the '[' and ']' in the beginning and the end of the string
+ if ((decode.length() > 1) && (decode.charAt(0) == '[') &&
+ (decode.charAt(decode.length() - 1) == ']')) {
+ decode = decode.substring(1, decode.length() - 1);
+ } else {
+ throw new IllegalArgumentException("Invalid action string");
+ }
+
+ // Split the string, and decode each action
+ String[] parts = decode.split(";");
+ for (int i = 0; i < parts.length; i++) {
+ decode = parts[i];
+ if ((decode == null) || decode.isEmpty())
+ continue;
+ FlowEntryAction flowEntryAction = null;
+ try {
+ flowEntryAction = new FlowEntryAction(decode);
+ } catch (IllegalArgumentException e) {
+ // TODO: Ignore invalid actions for now
+ continue;
+ }
+ if (flowEntryAction != null)
+ actions.add(flowEntryAction);
+ }
+ }
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/FlowPath.java b/src/main/java/net/onrc/onos/ofcontroller/util/FlowPath.java
index 4a8fc7b..a56dbff 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/FlowPath.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/FlowPath.java
@@ -1,10 +1,9 @@
package net.onrc.onos.ofcontroller.util;
-import java.util.ArrayList;
-
import net.floodlightcontroller.util.MACAddress;
import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowEntry;
import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowPath;
+import net.onrc.onos.ofcontroller.util.FlowPathFlags;
import org.codehaus.jackson.annotate.JsonProperty;
@@ -14,15 +13,20 @@
public class FlowPath implements Comparable<FlowPath> {
private FlowId flowId; // The Flow ID
private CallerId installerId; // The Caller ID of the path installer
+ private FlowPathFlags flowPathFlags; // The Flow Path flags
private DataPath dataPath; // The data path
private FlowEntryMatch flowEntryMatch; // Common Flow Entry Match for all
// Flow Entries
+ private FlowEntryActions flowEntryActions; // The Flow Entry Actions for
+ // the first Flow Entry
/**
* Default constructor.
*/
public FlowPath() {
+ flowPathFlags = new FlowPathFlags();
dataPath = new DataPath();
+ flowEntryActions = new FlowEntryActions();
}
/**
@@ -32,6 +36,7 @@
dataPath = new DataPath();
this.setFlowId(new FlowId(flowObj.getFlowId()));
this.setInstallerId(new CallerId(flowObj.getInstallerId()));
+ this.setFlowPathFlags(new FlowPathFlags(flowObj.getFlowPathFlags()));
this.dataPath().srcPort().setDpid(new Dpid(flowObj.getSrcSwitch()));
this.dataPath().srcPort().setPort(new Port(flowObj.getSrcPort()));
this.dataPath().dstPort().setDpid(new Dpid(flowObj.getDstSwitch()));
@@ -78,6 +83,19 @@
this.setFlowEntryMatch(match);
}
+ //
+ // Extract the actions for the first Flow Entry
+ //
+ {
+ FlowEntryActions actions = new FlowEntryActions();
+
+ String actionsStr = flowObj.getActions();
+ if (actions != null)
+ actions = new FlowEntryActions(actionsStr);
+
+ this.setFlowEntryActions(actions);
+ }
+
//
// Extract all Flow Entries
//
@@ -91,64 +109,77 @@
// Extract the match conditions
//
FlowEntryMatch match = new FlowEntryMatch();
+ //
Short matchInPort = flowEntryObj.getMatchInPort();
if (matchInPort != null)
match.enableInPort(new Port(matchInPort));
+ //
String matchSrcMac = flowEntryObj.getMatchSrcMac();
if (matchSrcMac != null)
match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
+ //
String matchDstMac = flowEntryObj.getMatchDstMac();
if (matchDstMac != null)
match.enableDstMac(MACAddress.valueOf(matchDstMac));
+ //
Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
if (matchEthernetFrameType != null)
match.enableEthernetFrameType(matchEthernetFrameType);
+ //
Short matchVlanId = flowEntryObj.getMatchVlanId();
if (matchVlanId != null)
match.enableVlanId(matchVlanId);
+ //
Byte matchVlanPriority = flowEntryObj.getMatchVlanPriority();
if (matchVlanPriority != null)
match.enableVlanPriority(matchVlanPriority);
+ //
String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
if (matchSrcIPv4Net != null)
match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
+ //
String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
if (matchDstIPv4Net != null)
match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
+ //
Byte matchIpProto = flowEntryObj.getMatchIpProto();
if (matchIpProto != null)
match.enableIpProto(matchIpProto);
+ //
Byte matchIpToS = flowEntryObj.getMatchIpToS();
if (matchIpToS != null)
match.enableIpToS(matchIpToS);
+ //
Short matchSrcTcpUdpPort = flowEntryObj.getMatchSrcTcpUdpPort();
if (matchSrcTcpUdpPort != null)
match.enableSrcTcpUdpPort(matchSrcTcpUdpPort);
+ //
Short matchDstTcpUdpPort = flowEntryObj.getMatchDstTcpUdpPort();
if (matchDstTcpUdpPort != null)
match.enableDstTcpUdpPort(matchDstTcpUdpPort);
+ //
flowEntry.setFlowEntryMatch(match);
- //
- // Extract the actions
- //
- ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
- Short actionOutputPort = flowEntryObj.getActionOutput();
- if (actionOutputPort != null) {
- FlowEntryAction action = new FlowEntryAction();
- action.setActionOutput(new Port(actionOutputPort));
- actions.add(action);
- }
- flowEntry.setFlowEntryActions(actions);
+ //
+ // Extract the actions
+ //
+ {
+ FlowEntryActions actions = new FlowEntryActions();
+
+ String actionsStr = flowEntryObj.getActions();
+ if (actions != null)
+ actions = new FlowEntryActions(actionsStr);
+
+ flowEntry.setFlowEntryActions(actions);
+ }
String userState = flowEntryObj.getUserState();
flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
String switchState = flowEntryObj.getSwitchState();
flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
- //
- // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
- // and FlowEntryErrorState.
- //
+ //
+ // TODO: Take care of the FlowEntryErrorState.
+ //
this.dataPath().flowEntries().add(flowEntry);
}
}
@@ -190,6 +221,24 @@
}
/**
+ * Get the flow path flags.
+ *
+ * @return the flow path flags.
+ */
+ @JsonProperty("flowPathFlags")
+ public FlowPathFlags flowPathFlags() { return flowPathFlags; }
+
+ /**
+ * Set the flow path flags.
+ *
+ * @param flowPathFlags the flow path flags to set.
+ */
+ @JsonProperty("flowPathFlags")
+ public void setFlowPathFlags(FlowPathFlags flowPathFlags) {
+ this.flowPathFlags = flowPathFlags;
+ }
+
+ /**
* Get the flow path's data path.
*
* @return the flow path's data path.
@@ -227,10 +276,32 @@
}
/**
+ * Get the flow path's flow entry actions for the first Flow Entry.
+ *
+ * @return the flow path's flow entry actions for the first Flow Entry.
+ */
+ @JsonProperty("flowEntryActions")
+ public FlowEntryActions flowEntryActions() {
+ return flowEntryActions;
+ }
+
+ /**
+ * Set the flow path's flow entry actions for the first Flow Entry.
+ *
+ * @param flowEntryActions the flow path's flow entry actions for the first
+ * Flow Entry.
+ */
+ @JsonProperty("flowEntryActions")
+ public void setFlowEntryActions(FlowEntryActions flowEntryActions) {
+ this.flowEntryActions = flowEntryActions;
+ }
+
+ /**
* Convert the flow path to a string.
*
* The string has the following form:
- * [flowId=XXX installerId=XXX dataPath=XXX]
+ * [flowId=XXX installerId=XXX flowPathFlags=XXX dataPath=XXX
+ * flowEntryMatch=XXX flowEntryActions=XXX]
*
* @return the flow path as a string.
*/
@@ -238,10 +309,13 @@
public String toString() {
String ret = "[flowId=" + this.flowId.toString();
ret += " installerId=" + this.installerId.toString();
+ ret += " flowPathFlags=" + this.flowPathFlags.toString();
if (dataPath != null)
ret += " dataPath=" + this.dataPath.toString();
if (flowEntryMatch != null)
ret += " flowEntryMatch=" + this.flowEntryMatch.toString();
+ if (flowEntryActions != null)
+ ret += " flowEntryActions=" + this.flowEntryActions.toString();
ret += "]";
return ret;
}
@@ -253,5 +327,4 @@
public int compareTo(FlowPath f) {
return (int) (this.flowId.value() - f.flowId.value());
}
-
}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/FlowPathFlags.java b/src/main/java/net/onrc/onos/ofcontroller/util/FlowPathFlags.java
new file mode 100644
index 0000000..63241f0
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/FlowPathFlags.java
@@ -0,0 +1,128 @@
+package net.onrc.onos.ofcontroller.util;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+/**
+ * The class representing the Flow Path flags.
+ */
+public class FlowPathFlags {
+ private long flags;
+
+ // Discard the first-hop Flow Entry
+ private final long DISCARD_FIRST_HOP_ENTRY = (1 << 0);
+
+ // Keep only the first-hop Flow Entry
+ private final long KEEP_ONLY_FIRST_HOP_ENTRY = (1 << 1);
+
+ /**
+ * Default constructor.
+ */
+ public FlowPathFlags() {
+ this.flags = 0;
+ }
+
+ /**
+ * Constructor for given flags.
+ *
+ * @param flags the flags value to set.
+ */
+ public FlowPathFlags(long flags) {
+ this.flags = flags;
+ }
+
+ /**
+ * Constructor for given flags as a string.
+ *
+ * The string value should contain the name of each flags to set. E.g.:
+ * "DISCARD_FIRST_HOP_ENTRY,KEEP_ONLY_FIRST_HOP_ENTRY"
+ * @param flagsStr the string value of the flags to set.
+ */
+ public FlowPathFlags(String flagsStr) {
+ this.setFlagsStr(flagsStr);
+ }
+
+ /**
+ * Get the flags.
+ *
+ * @return the flags.
+ */
+ @JsonProperty("flags")
+ public long flags() { return flags; }
+
+ /**
+ * Set the flags.
+ *
+ * @param flags the flags value to set.
+ */
+ @JsonProperty("flags")
+ public void setFlags(long flags) {
+ this.flags = flags;
+ }
+
+ /**
+ * Set the flags as a string.
+ *
+ * The string value should contain the name of each flags to set. E.g.:
+ * "DISCARD_FIRST_HOP_ENTRY,KEEP_ONLY_FIRST_HOP_ENTRY"
+ * @param flagsStr the string value of the flags to set.
+ */
+ @JsonProperty("flagsStr")
+ public void setFlagsStr(String flagsStr) {
+ this.flags = 0L;
+
+ // Test all flags
+ if (flagsStr.contains("DISCARD_FIRST_HOP_ENTRY"))
+ this.flags |= DISCARD_FIRST_HOP_ENTRY;
+ if (flagsStr.contains("KEEP_ONLY_FIRST_HOP_ENTRY"))
+ this.flags |= KEEP_ONLY_FIRST_HOP_ENTRY;
+ }
+
+ /**
+ * Test whether the DISCARD_FIRST_HOP_ENTRY flag is set.
+ *
+ * @return true if the DISCARD_FIRST_HOP_ENTRY flag is set,
+ * otherwise false.
+ */
+ public boolean isDiscardFirstHopEntry() {
+ return ((flags & DISCARD_FIRST_HOP_ENTRY) != 0);
+ }
+
+ /**
+ * Test whether the KEEP_ONLY_FIRST_HOP_ENTRY flag is set.
+ *
+ * @return true if the KEEP_ONLY_FIRST_HOP_ENTRY flag is set,
+ * otherwise false.
+ */
+ public boolean isKeepOnlyFirstHopEntry() {
+ return ((flags & KEEP_ONLY_FIRST_HOP_ENTRY) != 0);
+ }
+
+ /**
+ * Convert the Flow Path Flags to a string.
+ *
+ * The string has the following form:
+ * [flags=DISCARD_FIRST_HOP_ENTRY,KEEP_ONLY_FIRST_HOP_ENTRY]
+ *
+ * @return the Flow Path flags as a string.
+ */
+ @Override
+ public String toString() {
+ String flagsStr = null;
+ String ret = "[flags=";
+
+ // Test all flags
+ if ((this.flags & DISCARD_FIRST_HOP_ENTRY) != 0) {
+ if (flagsStr != null)
+ flagsStr += ",";
+ flagsStr += "DISCARD_FIRST_HOP_ENTRY";
+ }
+ if ((this.flags & KEEP_ONLY_FIRST_HOP_ENTRY) != 0) {
+ if (flagsStr != null)
+ flagsStr += ",";
+ flagsStr += "KEEP_ONLY_FIRST_HOP_ENTRY";
+ }
+ ret += "]";
+
+ return ret;
+ }
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/IPv4.java b/src/main/java/net/onrc/onos/ofcontroller/util/IPv4.java
index 2081bbe..119165c 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/IPv4.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/IPv4.java
@@ -22,6 +22,15 @@
}
/**
+ * Copy constructor.
+ *
+ * @param other the object to copy from.
+ */
+ public IPv4(IPv4 other) {
+ this.value = other.value;
+ }
+
+ /**
* Constructor from an integer value.
*
* @param value the value to use.
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/IPv4Net.java b/src/main/java/net/onrc/onos/ofcontroller/util/IPv4Net.java
index 52e6535..9ce247c 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/IPv4Net.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/IPv4Net.java
@@ -23,6 +23,17 @@
}
/**
+ * Copy constructor.
+ *
+ * @param other the object to copy from.
+ */
+ public IPv4Net(IPv4Net other) {
+ if (other.address != null)
+ this.address = new IPv4(other.address);
+ this.prefixLen = other.prefixLen;
+ }
+
+ /**
* Constructor for a given address and prefix length.
*
* @param address the address to use.
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/IPv6.java b/src/main/java/net/onrc/onos/ofcontroller/util/IPv6.java
index 2d28db8..f5dae11 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/IPv6.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/IPv6.java
@@ -25,6 +25,16 @@
}
/**
+ * Copy constructor.
+ *
+ * @param other the object to copy from.
+ */
+ public IPv6(IPv6 other) {
+ this.valueHigh = other.valueHigh;
+ this.valueLow = other.valueLow;
+ }
+
+ /**
* Constructor from integer values.
*
* @param valueHigh the higher (more significant) 64 bits of the address.
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/IPv6Net.java b/src/main/java/net/onrc/onos/ofcontroller/util/IPv6Net.java
index bafff24..65ffe54 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/IPv6Net.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/IPv6Net.java
@@ -23,6 +23,17 @@
}
/**
+ * Copy constructor.
+ *
+ * @param other the object to copy from.
+ */
+ public IPv6Net(IPv6Net other) {
+ if (other.address != null)
+ this.address = new IPv6(other.address);
+ this.prefixLen = other.prefixLen;
+ }
+
+ /**
* Constructor for a given address and prefix length.
*
* @param address the address to use.
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/Port.java b/src/main/java/net/onrc/onos/ofcontroller/util/Port.java
index 34c807d..bb4851c 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/Port.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/Port.java
@@ -78,9 +78,9 @@
}
/**
- * Constructor from another entry.
+ * Copy constructor.
*
- * @param other the other entry to use.
+ * @param other the object to copy from.
*/
public Port(Port other) {
this.value = other.value();
diff --git a/src/main/java/net/onrc/onos/registry/controller/IControllerRegistryService.java b/src/main/java/net/onrc/onos/registry/controller/IControllerRegistryService.java
index 21da47e..33ba272 100644
--- a/src/main/java/net/onrc/onos/registry/controller/IControllerRegistryService.java
+++ b/src/main/java/net/onrc/onos/registry/controller/IControllerRegistryService.java
@@ -80,7 +80,7 @@
/**
* Register a controller to the ONOS cluster. Must be called before
* the registry can be used to take control of any switches.
- * @param controller A unique string ID identifying this controller
+ * @param controllerId A unique string ID identifying this controller
* in the cluster
* @throws errors connecting to registry service,
* controllerId already registered
diff --git a/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule b/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule
index a9ff0b8..f552de5 100644
--- a/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule
+++ b/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule
@@ -1,5 +1,6 @@
net.floodlightcontroller.core.FloodlightProvider
net.floodlightcontroller.storage.memory.MemoryStorageSource
+net.onrc.onos.ofcontroller.floodlightlistener.NetworkGraphPublisher
net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl
net.onrc.onos.ofcontroller.linkdiscovery.internal.LinkDiscoveryManager
net.floodlightcontroller.topology.TopologyManager
@@ -17,7 +18,6 @@
net.floodlightcontroller.devicemanager.test.MockDeviceManager
net.floodlightcontroller.core.test.MockFloodlightProvider
net.floodlightcontroller.core.test.MockThreadPoolService
-net.onrc.onos.ofcontroller.floodlightlistener.NetworkGraphPublisher
net.onrc.onos.ofcontroller.flowmanager.FlowManager
net.onrc.onos.ofcontroller.routing.TopoRouteService
net.onrc.onos.ofcontroller.bgproute.BgpRoute
diff --git a/src/test/java/net/floodlightcontroller/core/internal/ControllerTest.java b/src/test/java/net/floodlightcontroller/core/internal/ControllerTest.java
index ecdc2d7..4516ece 100644
--- a/src/test/java/net/floodlightcontroller/core/internal/ControllerTest.java
+++ b/src/test/java/net/floodlightcontroller/core/internal/ControllerTest.java
@@ -49,7 +49,7 @@
import net.floodlightcontroller.core.IOFMessageListener;
import net.floodlightcontroller.core.IOFSwitch;
import net.floodlightcontroller.core.IOFSwitchListener;
-import net.floodlightcontroller.core.internal.Controller.IUpdate;
+import net.floodlightcontroller.core.IUpdate;
import net.floodlightcontroller.core.internal.Controller.SwitchUpdate;
import net.floodlightcontroller.core.internal.Controller.SwitchUpdateType;
import net.floodlightcontroller.core.internal.OFChannelState.HandshakeState;
@@ -659,7 +659,7 @@
controller.setRole(Role.SLAVE);
verify(roleChanger);
- Controller.IUpdate upd = controller.updates.poll();
+ IUpdate upd = controller.updates.poll();
assertNotNull("Check that update queue has an update", upd);
assertTrue("Check that update is HARoleUpdate",
upd instanceof Controller.HARoleUpdate);
diff --git a/src/test/java/net/floodlightcontroller/core/test/MockFloodlightProvider.java b/src/test/java/net/floodlightcontroller/core/test/MockFloodlightProvider.java
index e83fc58..b37451a 100644
--- a/src/test/java/net/floodlightcontroller/core/test/MockFloodlightProvider.java
+++ b/src/test/java/net/floodlightcontroller/core/test/MockFloodlightProvider.java
@@ -38,6 +38,7 @@
import net.floodlightcontroller.core.IOFSwitchFilter;
import net.floodlightcontroller.core.IOFSwitchListener;
import net.floodlightcontroller.core.IListener.Command;
+import net.floodlightcontroller.core.IUpdate;
import net.floodlightcontroller.core.module.FloodlightModuleContext;
import net.floodlightcontroller.core.module.FloodlightModuleException;
import net.floodlightcontroller.core.module.IFloodlightModule;
@@ -347,4 +348,10 @@
// TODO Auto-generated method stub
}
+
+ @Override
+ public void publishUpdate(IUpdate update) {
+ // TODO Auto-generated method stub
+
+ }
}
diff --git a/src/test/java/net/onrc/onos/ofcontroller/bgproute/PatriciaTrieTest.java b/src/test/java/net/onrc/onos/ofcontroller/bgproute/PatriciaTrieTest.java
new file mode 100644
index 0000000..571d37d
--- /dev/null
+++ b/src/test/java/net/onrc/onos/ofcontroller/bgproute/PatriciaTrieTest.java
@@ -0,0 +1,204 @@
+package net.onrc.onos.ofcontroller.bgproute;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class PatriciaTrieTest {
+
+ IPatriciaTrie<RibEntry> ptrie;
+ Prefix[] prefixes;
+ Map<Prefix, RibEntry> mappings;
+
+ @Before
+ public void setUp() throws Exception {
+ ptrie = new PatriciaTrie<RibEntry>(32);
+ mappings = new HashMap<Prefix, RibEntry>();
+
+ prefixes = new Prefix[] {
+ new Prefix("192.168.10.0", 24),
+ new Prefix("192.168.8.0", 23),
+ new Prefix("192.168.8.0", 22),
+ new Prefix("192.0.0.0", 7),
+ new Prefix("192.168.11.0", 24),
+ new Prefix("10.0.23.128", 25),
+ new Prefix("206.17.144.0", 20),
+ new Prefix("9.17.0.0", 12),
+ new Prefix("192.168.0.0", 16)
+ };
+
+ for (int i = 0; i < prefixes.length; i++) {
+ mappings.put(prefixes[i], new RibEntry("192.168.10.101", "192.168.20." + i));
+ ptrie.put(prefixes[i], new RibEntry("192.168.10.101", "192.168.20." + i));
+ }
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ @Test
+ public void testPut() {
+ IPatriciaTrie<RibEntry> ptrie = new PatriciaTrie<RibEntry>(32);
+
+ Prefix p1 = new Prefix("192.168.240.0", 20);
+ RibEntry r1 = new RibEntry("192.168.10.101", "192.168.60.2");
+ RibEntry retval = ptrie.put(p1, r1);
+ assertNull(retval);
+ retval = ptrie.lookup(p1);
+ assertTrue(r1 == retval); //should be the same object
+
+ Prefix p2 = new Prefix("192.160.0.0", 12);
+ RibEntry r2 = new RibEntry("192.168.10.101", "192.168.20.1");
+ retval = ptrie.put(p2, r2);
+ assertNull(retval);
+
+ Prefix p3 = new Prefix("192.168.208.0", 20);
+ RibEntry r3 = new RibEntry("192.168.10.101", "192.168.30.1");
+ retval = ptrie.put(p3, r3);
+ assertNull(retval);
+
+ //Insert a new RibEntry entry over a previous one
+ RibEntry r3new = new RibEntry("192.168.10.101", "192.168.60.2");
+ retval = ptrie.put(p3, r3new);
+ assertNotNull(retval);
+ assertTrue(retval.equals(r3));
+ assertTrue(retval == r3); //should be the same object
+
+ //Now we have an aggregate node with prefix 192.168.192.0/18.
+ //We will insert a RibEntry at this prefix
+ Prefix p4 = new Prefix("192.168.192.0", 18);
+ RibEntry r4 = new RibEntry("192.168.10.101", "192.168.40.1");
+ retval = ptrie.put(p4, r4);
+ assertNull(retval);
+ retval = ptrie.lookup(p4);
+ assertTrue(retval == r4); //should be the same object
+ }
+
+ @Test
+ public void testLookup() {
+ for (Map.Entry<Prefix, RibEntry> entry : mappings.entrySet()) {
+ RibEntry r = ptrie.lookup(entry.getKey());
+ assertTrue(entry.getValue().equals(r));
+ }
+
+ //These are aggregate nodes in the tree. Shouldn't be returned by lookup
+ Prefix p1 = new Prefix("0.0.0.0", 0);
+ RibEntry retval = ptrie.lookup(p1);
+ assertNull(retval);
+
+ //We'll put a RibEntry at an aggregate node and check if lookup returns correctly
+ Prefix p2 = new Prefix("192.0.0.0", 4);
+ RibEntry r2 = new RibEntry("192.168.10.101", "192.168.60.1");
+ retval = ptrie.put(p2, r2);
+ assertNull(retval);
+ retval = ptrie.lookup(p2);
+ assertTrue(retval.equals(r2));
+ }
+
+ //@Ignore
+ @Test
+ public void testMatch() {
+ Prefix p1 = new Prefix("192.168.10.30", 32);
+ Prefix p2 = new Prefix("192.168.10.30", 31);
+ Prefix p3 = new Prefix("192.168.8.241", 32);
+ Prefix p4 = new Prefix("1.0.0.0", 32);
+ Prefix p5 = new Prefix("192.168.8.0", 22);
+ Prefix p6 = new Prefix("192.168.8.0", 21);
+
+ assertTrue(ptrie.match(p1).equals(mappings.get(prefixes[0])));
+ assertTrue(ptrie.match(p2).equals(mappings.get(prefixes[0])));
+ assertTrue(ptrie.match(p3).equals(mappings.get(prefixes[1])));
+ assertNull(ptrie.match(p4));
+ assertTrue(ptrie.match(p5).equals(mappings.get(prefixes[2])));
+ //System.out.println(ptrie.match(p6).getNextHop().getHostAddress());
+ assertTrue(ptrie.match(p6).equals(mappings.get(prefixes[8])));
+
+
+ //TODO more extensive tests
+ //fail("Not yet implemented");
+ }
+
+ @Test
+ public void testRemove() {
+ Prefix p1 = new Prefix("192.168.8.0", 23);
+ RibEntry retval = ptrie.lookup(p1);
+ assertNotNull(retval);
+ boolean success = ptrie.remove(p1, retval);
+ assertTrue(success);
+
+ Prefix p2 = new Prefix("192.168.8.0", 22);
+ Prefix p3 = new Prefix("192.168.10.0", 24);
+
+ //Test it does the right thing with null arguments
+ success = ptrie.remove(null, null);
+ assertFalse(success);
+ success = ptrie.remove(p2, null);
+ assertFalse(success);
+
+ //Check other prefixes are still there
+ retval = ptrie.lookup(p2);
+ assertNotNull(retval);
+ retval = ptrie.lookup(p3);
+ assertNotNull(retval);
+
+ Prefix p4 = new Prefix("9.17.0.0", 12);
+ retval = ptrie.lookup(p4);
+ assertNotNull(retval);
+ success = ptrie.remove(p4, retval);
+ assertTrue(success);
+ success = ptrie.remove(p4, retval);
+ assertFalse(success);
+
+ //Check other prefixes are still there
+ retval = ptrie.lookup(p2);
+ assertNotNull(retval);
+ retval = ptrie.lookup(p3);
+ assertNotNull(retval);
+
+ Prefix p5 = new Prefix("192.0.0.0", 7);
+ retval = ptrie.lookup(p5);
+ assertNotNull(retval);
+ success = ptrie.remove(p5, retval);
+ assertTrue(success);
+
+ //Check other prefixes are still there
+ retval = ptrie.lookup(p2);
+ assertNotNull(retval);
+ retval = ptrie.lookup(p3);
+ assertNotNull(retval);
+
+
+ }
+
+ @Test(expected=java.util.NoSuchElementException.class)
+ public void testIterator() {
+ int[] order = new int[] {7, 5, 3, 8, 2, 1, 0, 4, 6};
+
+ Iterator<IPatriciaTrie.Entry<RibEntry>> it = ptrie.iterator();
+ int i = 0;
+ assertTrue(it.hasNext());
+ while (it.hasNext()) {
+ IPatriciaTrie.Entry<RibEntry> entry = it.next();
+ assertTrue(entry.getPrefix().equals(prefixes[order[i]]));
+ i++;
+ }
+ assertFalse(it.hasNext());
+ assertTrue(i == order.length);
+
+ IPatriciaTrie<RibEntry> pt = new PatriciaTrie<RibEntry>(32);
+ Iterator<IPatriciaTrie.Entry<RibEntry>> it2 = pt.iterator();
+ assertFalse(it2.hasNext());
+ it.next(); //throws NoSuchElementException
+ }
+
+}
diff --git a/src/test/java/net/onrc/onos/ofcontroller/bgproute/PrefixTest.java b/src/test/java/net/onrc/onos/ofcontroller/bgproute/PrefixTest.java
new file mode 100644
index 0000000..6ebaf0f
--- /dev/null
+++ b/src/test/java/net/onrc/onos/ofcontroller/bgproute/PrefixTest.java
@@ -0,0 +1,101 @@
+package net.onrc.onos.ofcontroller.bgproute;
+
+import static org.junit.Assert.*;
+
+import java.util.Arrays;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class PrefixTest {
+
+ @Before
+ public void setUp() throws Exception {
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ @Test
+ public void testPrefixByteArray() {
+ byte[] b1 = new byte[] {(byte)0x8f, (byte)0xa0, (byte)0x00, (byte)0x00};
+ byte[] b2 = new byte[] {(byte)0x8f, (byte)0xa0, (byte)0xff, (byte)0xff};
+ byte[] b3 = new byte[] {(byte)0x8f, (byte)0xac, (byte)0x00, (byte)0x00};
+ byte[] b4 = new byte[] {(byte)0x8f, (byte)0xa0, (byte)0x00, (byte)0x00};
+
+ Prefix p1 = new Prefix(b1, 12);
+ Prefix p2 = new Prefix(b2, 12);
+ Prefix p3 = new Prefix(b3, 12);
+ Prefix p4 = new Prefix(b4, 11);
+
+ //Have different byte arrays, but should be equal after construction
+ assertTrue(p1.equals(p2));
+ assertTrue(p2.equals(p3));
+
+ //Same byte array, but should be false
+ assertFalse(p1.equals(p4));
+
+ assertTrue(Arrays.equals(p1.getAddress(), p3.getAddress()));
+ assertTrue(p1.toString().equals(p2.toString()));
+ assertTrue(Arrays.equals(p1.getAddress(), p4.getAddress()));
+ assertFalse(p1.toString().equals(p4.toString()));
+ }
+
+ @Test
+ public void testPrefixString() {
+ Prefix p1 = new Prefix("192.168.166.0", 24);
+ Prefix p2 = new Prefix("192.168.166.0", 23);
+ Prefix p3 = new Prefix("192.168.166.128", 24);
+ Prefix p4 = new Prefix("192.168.166.128", 25);
+
+ assertFalse(p1.equals(p2));
+ assertTrue(Arrays.equals(p1.getAddress(), p2.getAddress()));
+
+ assertTrue(p1.equals(p3));
+ assertTrue(Arrays.equals(p1.getAddress(), p2.getAddress()));
+
+ assertFalse(p3.equals(p4));
+ assertFalse(Arrays.equals(p3.getAddress(), p4.getAddress()));
+
+ assertTrue(p1.toString().equals(p3.toString()));
+ assertEquals(p1.hashCode(), p3.hashCode());
+ }
+
+ @Test
+ public void testPrefixReturnsSame() {
+ //Create a prefix of all 1s for each prefix length.
+ //Check that Prefix doesn't mangle it
+ int MAX_PREFIX_LENGTH = 32;
+ for (int prefixLength = 1; prefixLength <= MAX_PREFIX_LENGTH; prefixLength++) {
+ byte address[] = new byte[MAX_PREFIX_LENGTH/Byte.SIZE];
+
+ int lastByte = (prefixLength - 1) / Byte.SIZE;
+ int lastBit = (prefixLength - 1) % Byte.SIZE;
+
+ for (int j = 0; j < address.length; j++) {
+ if (j < lastByte) {
+ address[j] = (byte)0xff;
+ }
+ else if (j == lastByte) {
+ byte b = 0;
+ byte msb = (byte) 0x80;
+ for (int k = 0; k < Byte.SIZE; k++) {
+ if (k <= lastBit) {
+ b |= (msb >> k);
+ }
+ }
+ address[j] = b;
+ }
+ else {
+ address[j] = 0;
+ }
+ }
+
+ Prefix p = new Prefix(address, prefixLength);
+ System.out.println(p.printAsBits());
+ assertTrue(Arrays.equals(address, p.getAddress()));
+ }
+ }
+}
diff --git a/src/test/java/net/onrc/onos/ofcontroller/bgproute/PtreeTest.java b/src/test/java/net/onrc/onos/ofcontroller/bgproute/PtreeTest.java
new file mode 100644
index 0000000..1135407
--- /dev/null
+++ b/src/test/java/net/onrc/onos/ofcontroller/bgproute/PtreeTest.java
@@ -0,0 +1,228 @@
+package net.onrc.onos.ofcontroller.bgproute;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.net.InetAddresses;
+
+public class PtreeTest {
+
+ private Logger log = LoggerFactory.getLogger(PtreeTest.class);
+
+ private Ptree ptree;
+ private PatriciaTrie<RibEntry> ooptrie;
+
+ private Map<String, byte[]> byteAddresses;
+
+ @Before
+ public void setUp() throws Exception {
+ ptree = new Ptree(32);
+ ooptrie = new PatriciaTrie<RibEntry>(32);
+
+ String[] strPrefixes = {
+ "192.168.10.0/24",
+ "192.168.10.0/23",
+ "192.168.10.0/22",
+ "192.0.0.0/7",
+ "192.168.11.0/24",
+ "10.0.23.128/25",
+ "206.17.144.0/20",
+ "9.17.0.0/12",
+ "192.168.0.0/16"
+ };
+
+ byteAddresses = new HashMap<String, byte[]>(strPrefixes.length+10);
+ for (String prefix : strPrefixes) {
+ String address = prefix.split("/")[0];
+ int prefixLength = Integer.parseInt(prefix.split("/")[1]);
+ byteAddresses.put(prefix, InetAddresses.forString(address).getAddress());
+
+ PtreeNode node = ptree.acquire(byteAddresses.get(prefix), prefixLength);
+ node.rib = new RibEntry("192.168.10.101", "192.168.60.1");
+ ooptrie.put(new Prefix(byteAddresses.get(prefix), prefixLength),
+ new RibEntry("192.168.10.101", "192.168.60.1"));
+ }
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ @Ignore
+ @Test
+ public void testAcquireByteArray() {
+ fail("Not yet implemented");
+ }
+
+ @Ignore
+ @Test
+ public void testAcquireByteArrayInt() {
+ //First let's test an empty Ptree
+ Ptree localPtree = new Ptree(32);
+ PtreeNode node = localPtree.acquire(new byte[] {0x00, 0x00, 0x00, 0x00});
+ assertTrue(node != null && node.rib == null);
+
+ //Now let's look at the prepopulated tree
+ String testPrefix = "206.17.144.0/20";
+ PtreeNode existingNode = ptree.acquire(byteAddresses.get(testPrefix), 20);
+ printByteArray(existingNode.key);
+ printByteArray(byteAddresses.get(testPrefix));
+ assertTrue(existingNode != null && existingNode.rib == null);
+
+ assertTrue(Arrays.equals(existingNode.key, byteAddresses.get(testPrefix)));
+ }
+
+ @Test
+ public void testLookup() {
+ String prefix1 = "192.168.10.12";
+ int length1 = 29;
+ PtreeNode node1 = ptree.lookup(InetAddresses.forString(prefix1).getAddress(), length1);
+
+ //There should be no direct match
+ assertTrue(node1 == null);
+
+ log.debug("{} null: {}", "node1", node1 == null ? "true" : "false");
+
+ String prefix2 = "206.17.144.0";
+ int length2 = 20;
+ PtreeNode node2 = ptree.lookup(InetAddresses.forString(prefix2).getAddress(), length2);
+
+ assertTrue(node2 != null);
+ assertTrue(Arrays.equals(node2.key, byteAddresses.get(prefix2 + "/" + length2)));
+
+ log.debug("{} null: {}", "node2", node2 == null ? "true" : "false");
+ if (node2 != null) {
+ log.debug("{} key: {}, keybits: {}", new Object[] {"node2", node2.key, node2.keyBits});
+ }
+
+ String prefix3 = "192.0.0.0";
+ int length3 = 7;
+ PtreeNode node3 = ptree.lookup(InetAddresses.forString(prefix3).getAddress(), length3);
+ assertTrue(node3 != null);
+ }
+
+ @Test
+ public void testMatch() {
+ String prefix1 = "192.168.10.12";
+ int length1 = 29;
+ PtreeNode node1 = ptree.match(InetAddresses.forString(prefix1).getAddress(), length1);
+
+ //There should be no direct match, but we should get the covering prefix
+ assertTrue(node1 != null);
+ assertTrue(Arrays.equals(node1.key, byteAddresses.get("192.168.10.0/24")));
+
+ log.debug("{} null: {}", "node1", node1 == null ? "true" : "false");
+ if (node1 != null) {
+ log.debug("{} key: {}, keybits: {}", new Object[] {"node1", node1.key, node1.keyBits});
+ }
+ }
+
+ @Ignore
+ @Test
+ public void testTraverse() {
+
+ String expected = "[0, 0, 0, 0]/0\n";
+ expected += "[8, 0, 0, 0]/6\n";
+ expected += "[9, 17, 0, 0]/12\n";
+ expected += "[10, 0, 23, -128]/25\n";
+ expected += "[-64, 0, 0, 0]/4\n";
+ expected += "[-64, -88, 0, 0]/16\n";
+ expected += "[-64, -88, 8, 0]/22\n";
+ expected += "[-64, -88, 10, 0]/23\n";
+ expected += "[-64, -88, 10, 0]/24\n";
+ expected += "[-64, -88, 11, 0]/24\n";
+ expected += "[-50, 17, -112, 0]/20\n";
+
+ PtreeNode node;
+ String result = "";
+
+ for (node = ptree.begin(); node != null; node = ptree.next(node)) {
+ result += printByteArray(node.key) + "/" + node.keyBits + "\n";
+ }
+
+ assertEquals(expected, result);
+ }
+
+ @Ignore
+ @Test
+ public void testBegin() {
+ fail("Not yet implemented");
+ }
+
+ @Ignore
+ @Test
+ public void testNext() {
+ fail("Not yet implemented");
+ }
+
+ @Ignore
+ @Test
+ public void testDelReference() {
+ fail("Not yet implemented");
+ }
+
+ @Ignore
+ @Test
+ public void testMisc() {
+ int bitIndex = -1;
+ int index = (int)(bitIndex / Byte.SIZE);
+ int bit = (int)(bitIndex % Byte.SIZE);
+
+ log.debug("index {} bit {}", index, bit);
+ log.debug("percent {}", 1%8);
+
+ //PtreeNode node1 = new PtreeNode(new byte[] {0x0, 0x0, 0x0, 0x0}, 0, 4);
+ PtreeNode node1 = new PtreeNode(null, 0, 4);
+ log.debug("node1: key {}, keybits {}", printByteArray(node1.key), node1.keyBits);
+
+ //PtreeNode node2 = new PtreeNode(new byte[] {(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff},
+ PtreeNode node2 = new PtreeNode(null,
+ 32, 4);
+ log.debug("node2: key {}, keybits {}", printByteArray(node2.key), node2.keyBits);
+ }
+
+ @Test
+ public void testIteration() {
+ Iterator<IPatriciaTrie.Entry<RibEntry>> it = ooptrie.iterator();
+
+ while (it.hasNext()) {
+ IPatriciaTrie.Entry<RibEntry> entry = it.next();
+ log.debug("PatriciaTrie prefix {} \t {}", entry.getPrefix(), entry.getPrefix().printAsBits());
+ }
+
+ try {
+ PtreeNode node;
+ for (node = ptree.begin(); node != null; node = ptree.next(node)) {
+ log.debug("Ptree prefix {}/{}", InetAddress.getByAddress(node.key).getHostAddress(), node.keyBits);
+ }
+ } catch (UnknownHostException e) {
+
+ }
+ }
+
+ private String printByteArray(byte[] array) {
+ String result = "[";
+ for (byte b : array) {
+ result += b + ", ";
+ }
+ result = result.substring(0, result.length() - 2);
+ result += "]";
+ return result;
+ }
+
+}
diff --git a/src/test/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjectsIDeviceObjectTest.java b/src/test/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjectsIDeviceObjectTest.java
index 3ea90ba..323a0eb 100644
--- a/src/test/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjectsIDeviceObjectTest.java
+++ b/src/test/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjectsIDeviceObjectTest.java
@@ -7,8 +7,6 @@
import net.onrc.onos.graph.GraphDBConnection;
import net.onrc.onos.graph.GraphDBOperation;
import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IDeviceObject;
-import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowEntry;
-import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowPath;
import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IPortObject;
import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
import net.onrc.onos.ofcontroller.core.internal.SwitchStorageImpl;
diff --git a/src/test/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjectsIFlowEntryTest.java b/src/test/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjectsIFlowEntryTest.java
index 717d688..06d8522 100644
--- a/src/test/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjectsIFlowEntryTest.java
+++ b/src/test/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjectsIFlowEntryTest.java
@@ -353,18 +353,18 @@
/**
* Desc:
- * Test method for set and get ActionOutput.
+ * Test method for set and get ActionOutputPort.
* Condition:
* N/A
* Expect:
- * 1. Should set ActionOutput.
- * 2. Should get ActionOutput.
+ * 1. Should set ActionOutputPort.
+ * 2. Should get ActionOutputPort.
*/
@Test
- public void testSetGetActionOutput() {
- Short actionOutput = 1;
- flowEntry.setActionOutput(actionOutput);
- assertEquals(flowEntry.getActionOutput(), actionOutput);
+ public void testSetGetActionOutputPort() {
+ Short actionOutputPort = 1;
+ flowEntry.setActionOutputPort(actionOutputPort);
+ assertEquals(flowEntry.getActionOutputPort(), actionOutputPort);
}
/**
diff --git a/src/test/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjectsIFlowPathTest.java b/src/test/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjectsIFlowPathTest.java
index 85072e3..bb0dbbf 100644
--- a/src/test/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjectsIFlowPathTest.java
+++ b/src/test/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjectsIFlowPathTest.java
@@ -104,6 +104,24 @@
/**
* Desc:
+ * Test method for get and set FlowPathFlags method.
+ * Condition:
+ * N/A
+ * Expect:
+ * 1. Should set the Flow Path Flags.
+ * 2. Should get the Flow Path Flags.
+ */
+ @Test
+ public void testSetGetFlowPathFlags() {
+ String flowId = "xx";
+ Long flowPathFlags = new Long(0x3);
+ flowPath.setFlowId(flowId);
+ flowPath.setFlowPathFlags(flowPathFlags);
+ assertEquals(flowPath.getFlowPathFlags(), flowPathFlags);
+ }
+
+ /**
+ * Desc:
* Test method for get and set SourceSwitch method.
* Condition:
* N/A
diff --git a/src/test/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjectsIPortObjectTest.java b/src/test/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjectsIPortObjectTest.java
index 2ddab3d..74f9758 100644
--- a/src/test/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjectsIPortObjectTest.java
+++ b/src/test/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjectsIPortObjectTest.java
@@ -11,10 +11,6 @@
import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
import net.onrc.onos.ofcontroller.core.internal.SwitchStorageImpl;
import net.onrc.onos.ofcontroller.core.internal.TestDatabaseManager;
-import net.onrc.onos.ofcontroller.flowmanager.FlowManager;
-import net.onrc.onos.ofcontroller.util.FlowId;
-import net.onrc.onos.ofcontroller.util.FlowPath;
-
import org.easymock.EasyMock;
import org.junit.After;
import org.junit.Before;
diff --git a/src/test/java/net/onrc/onos/ofcontroller/core/internal/SwitchStorageImplTest.java b/src/test/java/net/onrc/onos/ofcontroller/core/internal/SwitchStorageImplTest.java
index 4956136..f276680 100644
--- a/src/test/java/net/onrc/onos/ofcontroller/core/internal/SwitchStorageImplTest.java
+++ b/src/test/java/net/onrc/onos/ofcontroller/core/internal/SwitchStorageImplTest.java
@@ -13,7 +13,6 @@
import org.easymock.EasyMock;
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.openflow.protocol.OFPhysicalPort;
@@ -469,7 +468,8 @@
public void testAddPortWithPortLinkDown() {
String dpid = "00:00:00:00:00:00:0a:01";
short portNumber = 5;
- String state = "ACTIVE";
+ String swState = "ACTIVE";
+ String portState = "INACTIVE";
String name = "port 5 at SEA switch";
OFPhysicalPort portToAdd = new OFPhysicalPort();
@@ -480,15 +480,15 @@
//Expectation of mock Port
IPortObject mockIPort = createMock(IPortObject.class);
- mockIPort.setState(state);
+ mockIPort.setState(portState);
mockIPort.setPortState(OFPortState.OFPPS_STP_FORWARD.getValue());
mockIPort.setDesc(name);
replay(mockIPort);
//Expectation of mock Switch
ISwitchObject mockISw = createMock(ISwitchObject.class);
- mockISw.setState(state);
- mockISw.removePort(mockIPort);
+ mockISw.setState(swState);
+// mockISw.removePort(mockIPort);
replay(mockISw);
//Expectation of mock operation.
@@ -497,7 +497,7 @@
mockOpe.commit();
expect(mockOpe.searchSwitch(dpid)).andReturn(mockISw);
expect(mockOpe.searchPort(dpid, portNumber)).andReturn(mockIPort);
- mockOpe.removePort(mockIPort);
+// mockOpe.removePort(mockIPort);
mockOpe.commit();
mockOpe.close();
replay(mockOpe);
@@ -663,7 +663,8 @@
public void testDeletePort() {
String dpid = "00:00:00:00:00:00:0a:01";
short portNumber = 5;
- String state = "ACTIVE";
+ String portState = "INACTIVE";
+ String swState = "ACTIVE";
String name = "port 5 at SEA switch";
OFPhysicalPort portToAdd = new OFPhysicalPort();
@@ -674,18 +675,21 @@
//Expectation of mock Port
IPortObject mockIPort = createMock(IPortObject.class);
- mockIPort.setState(state);
+ mockIPort.setState(swState);
mockIPort.setPortState(OFPortState.OFPPS_STP_FORWARD.getValue());
mockIPort.setDesc(name);
+ mockIPort.setState(portState);
replay(mockIPort);
//Expectation of mock Switch
ISwitchObject mockISw = createMock(ISwitchObject.class);
- mockISw.setState(state);
+ mockISw.setState(swState);
mockISw.addPort(mockIPort);
- mockISw.removePort(mockIPort);
+// mockISw.removePort(mockIPort);
replay(mockISw);
+
+
//Expectation of mock operation.
expect(mockOpe.searchSwitch(dpid)).andReturn(null);
expect(mockOpe.newSwitch(dpid)).andReturn(mockISw);
@@ -696,7 +700,7 @@
mockOpe.commit();
expect(mockOpe.searchSwitch(dpid)).andReturn(mockISw);
expect(mockOpe.searchPort(dpid, portNumber)).andReturn(mockIPort);
- mockOpe.removePort(mockIPort);
+// mockOpe.removePort(mockIPort);
mockOpe.commit();
mockOpe.close();
replay(mockOpe);
@@ -720,7 +724,8 @@
public void testDeletePortException() {
String dpid = "00:00:00:00:00:00:0a:01";
short portNumber = 5;
- String state = "ACTIVE";
+ String swState = "ACTIVE";
+ String portState = "INACTIVE";
String name = "port 5 at SEA switch";
OFPhysicalPort portToAdd = new OFPhysicalPort();
@@ -731,16 +736,17 @@
//Expectation of mock Port
IPortObject mockIPort = createMock(IPortObject.class);
- mockIPort.setState(state);
+ mockIPort.setState(swState);
mockIPort.setPortState(OFPortState.OFPPS_STP_FORWARD.getValue());
mockIPort.setDesc(name);
+ mockIPort.setState(portState);
replay(mockIPort);
//Expectation of mock Switch
ISwitchObject mockISw = createMock(ISwitchObject.class);
- mockISw.setState(state);
+ mockISw.setState(swState);
mockISw.addPort(mockIPort);
- mockISw.removePort(mockIPort);
+// mockISw.removePort(mockIPort);
replay(mockISw);
//Expectation of mock operation.
@@ -753,9 +759,10 @@
mockOpe.commit();
expect(mockOpe.searchSwitch(dpid)).andReturn(mockISw);
expect(mockOpe.searchPort(dpid, portNumber)).andReturn(mockIPort);
- mockOpe.removePort(mockIPort);
- expectLastCall().andThrow(new RuntimeException());
- mockOpe.rollback();
+ mockOpe.commit(); // Cannot generate exception..need to revisit this test
+// mockOpe.removePort(mockIPort);
+// expectLastCall().andThrow(new RuntimeException());
+// mockOpe.rollback();
mockOpe.close();
replay(mockOpe);
diff --git a/src/test/java/net/onrc/onos/ofcontroller/core/internal/SwitchStorageImplTestBB.java b/src/test/java/net/onrc/onos/ofcontroller/core/internal/SwitchStorageImplTestBB.java
index 57aefd3..19ac709 100644
--- a/src/test/java/net/onrc/onos/ofcontroller/core/internal/SwitchStorageImplTestBB.java
+++ b/src/test/java/net/onrc/onos/ofcontroller/core/internal/SwitchStorageImplTestBB.java
@@ -15,7 +15,6 @@
import org.easymock.EasyMock;
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.openflow.protocol.OFPhysicalPort;
diff --git a/src/test/java/net/onrc/onos/ofcontroller/core/internal/TestableGraphDBOperation.java b/src/test/java/net/onrc/onos/ofcontroller/core/internal/TestableGraphDBOperation.java
index fb5227f..bcff36a 100644
--- a/src/test/java/net/onrc/onos/ofcontroller/core/internal/TestableGraphDBOperation.java
+++ b/src/test/java/net/onrc/onos/ofcontroller/core/internal/TestableGraphDBOperation.java
@@ -415,6 +415,7 @@
public static class TestFlowPath implements IFlowPath {
private String state,type,flowId,installerId,srcSw,dstSw;
+ private Long flowPathFlags;
private String dataPathSummary,userState;
private Short srcPort,dstPort;
private String matchSrcMac,matchDstMac;
@@ -424,11 +425,13 @@
private String matchSrcIpaddr,matchDstIpaddr;
private Byte matchIpProto, matchIpToS;
private Short matchSrcTcpUdpPort, matchDstTcpUdpPort;
+ private String actions;
private List<IFlowEntry> entries;
private List<ISwitchObject> switches;
private String stateToUpdate,typeToUpdate,flowIdToUpdate,installerIdToUpdate,srcSwToUpdate,dstSwToUpdate;
+ private Long flowPathFlagsToUpdate;
private String dataPathSummaryToUpdate,userStateToUpdate;
private Short srcPortToUpdate,dstPortToUpdate;
private String matchSrcMacToUpdate,matchDstMacToUpdate;
@@ -438,6 +441,7 @@
private String matchSrcIpaddrToUpdate,matchDstIpaddrToUpdate;
private Byte matchIpProtoToUpdate, matchIpToSToUpdate;
private Short matchSrcTcpUdpPortToUpdate, matchDstTcpUdpPortToUpdate;
+ private String actionsToUpdate;
private List<IFlowEntry> flowsToAdd;
private List<IFlowEntry> flowsToRemove;
@@ -465,6 +469,7 @@
if(typeToUpdate != null) { type = typeToUpdate; }
if(flowIdToUpdate != null) { flowId = flowIdToUpdate; }
if(installerIdToUpdate != null) { installerId = installerIdToUpdate; }
+ if(flowPathFlagsToUpdate != null) { flowPathFlags = flowPathFlagsToUpdate; }
if(srcSwToUpdate != null) { srcSw = srcSwToUpdate; }
if(dstSwToUpdate != null) { dstSw = dstSwToUpdate; }
if(dataPathSummaryToUpdate != null) { dataPathSummary = dataPathSummaryToUpdate; }
@@ -482,6 +487,7 @@
if(matchIpToSToUpdate != null) { matchIpToS = matchIpToSToUpdate; }
if(matchSrcTcpUdpPortToUpdate != null) { matchSrcTcpUdpPort = matchSrcTcpUdpPortToUpdate; }
if(matchDstTcpUdpPortToUpdate != null) { matchDstTcpUdpPort = matchDstTcpUdpPortToUpdate; }
+ if(actionsToUpdate != null) { actions = actionsToUpdate; }
}
public void rollback() {
@@ -493,6 +499,7 @@
flowsToRemove.clear();
stateToUpdate = typeToUpdate = flowIdToUpdate = installerIdToUpdate = null;
+ flowPathFlagsToUpdate = null;
srcSwToUpdate = dstSwToUpdate = dataPathSummaryToUpdate = userStateToUpdate = null;
srcPortToUpdate = dstPortToUpdate = null;
matchSrcMacToUpdate = matchDstMacToUpdate = null;
@@ -502,6 +509,7 @@
matchSrcIpaddrToUpdate = matchDstIpaddrToUpdate = null;
matchIpProtoToUpdate = matchIpToSToUpdate = null;
matchSrcTcpUdpPortToUpdate = matchDstTcpUdpPortToUpdate = null;
+ actionsToUpdate = null;
}
// Setter methods for test
@@ -509,6 +517,7 @@
public void setTypeForTest(String type) { this.type = type; }
public void setFlowIdForTest(String flowId) { this.flowId = flowId; }
public void setInstallerIdForTest(String installerId) { this.installerId = installerId; }
+ public void setFlowPathFlagsForTest(Long flowPathFlags) { this.flowPathFlags = flowPathFlags; }
public void setSrcSwForTest(String srcSw) { this.srcSw = srcSw; }
public void setDstSwForTest(String dstSw) { this.dstSw = dstSw; }
public void setDataPathSummaryForTest(String dataPathSummary) { this.dataPathSummary = dataPathSummary; }
@@ -526,6 +535,7 @@
public void setMatchIpToSForTest(Byte matchIpToS) { this.matchIpToS = matchIpToS; }
public void setMatchSrcTcpUdpPortForTest(Short matchSrcTcpUdpPort) { this.matchSrcTcpUdpPort = matchSrcTcpUdpPort; }
public void setMatchDstTcpUdpPortForTest(Short matchDstTcpUdpPort) { this.matchDstTcpUdpPort = matchDstTcpUdpPort; }
+ public void setActionsForTest(String actions) { this.actions = actions; }
public void addFlowEntryForTest(IFlowEntry entry) { entries.add(entry); }
public void addSwitchForTest(ISwitchObject sw) { switches.add(sw); }
@@ -560,6 +570,12 @@
public void setInstallerId(String installerId) { installerIdToUpdate = installerId; }
@Override
+ public Long getFlowPathFlags() { return flowPathFlags; }
+
+ @Override
+ public void setFlowPathFlags(Long flowPathFlags) { flowPathFlagsToUpdate = flowPathFlags; }
+
+ @Override
public String getSrcSwitch() { return srcSw; }
@Override
@@ -682,6 +698,13 @@
matchDstTcpUdpPortToUpdate = matchDstTcpUdpPort; }
@Override
+ public String getActions() { return actions; }
+
+ @Override
+ public void setActions(String actions) {
+ actionsToUpdate = actions; }
+
+ @Override
public Iterable<ISwitchObject> getSwitches() { return switches; }
@Override
@@ -701,7 +724,8 @@
private String matchSrcIpaddr,matchDstIpaddr;
private Byte matchIpProto, matchIpToS;
private Short matchSrcTcpUdpPort, matchDstTcpUdpPort;
- private Short actionOutput;
+ private Short actionOutputPort;
+ private String actions;
private IFlowPath flowPath;
private ISwitchObject sw;
@@ -717,7 +741,8 @@
private String matchSrcIpaddrToUpdate,matchDstIpaddrToUpdate;
private Byte matchIpProtoToUpdate, matchIpToSToUpdate;
private Short matchSrcTcpUdpPortToUpdate, matchDstTcpUdpPortToUpdate;
- private Short actionOutputToUpdate;
+ private Short actionOutputPortToUpdate;
+ private String actionsToUpdate;
private IFlowPath flowPathToUpdate;
private ISwitchObject swToUpdate;
@@ -750,7 +775,8 @@
if(matchIpToSToUpdate != null) { matchIpToS = matchIpToSToUpdate; }
if(matchSrcTcpUdpPortToUpdate != null) { matchSrcTcpUdpPort = matchSrcTcpUdpPortToUpdate; }
if(matchDstTcpUdpPortToUpdate != null) { matchDstTcpUdpPort = matchDstTcpUdpPortToUpdate; }
- if(actionOutputToUpdate != null) { actionOutput = actionOutputToUpdate; }
+ if(actionOutputPortToUpdate != null) { actionOutputPort = actionOutputPortToUpdate; }
+ if(actionsToUpdate != null) { actions = actionsToUpdate; }
if(flowPathToUpdate != null) { flowPath = flowPathToUpdate; }
if(swToUpdate != null) { sw = swToUpdate; }
@@ -775,7 +801,8 @@
matchSrcIpaddrToUpdate = matchDstIpaddrToUpdate = null;
matchIpProtoToUpdate = matchIpToSToUpdate = null;
matchSrcTcpUdpPortToUpdate = matchDstTcpUdpPortToUpdate = null;
- actionOutputToUpdate = null;
+ actionOutputPortToUpdate = null;
+ actionsToUpdate = null;
flowPathToUpdate = null;
swToUpdate = null;
inportToUpdate = outportToUpdate = null;
@@ -802,7 +829,8 @@
public void setMatchIpToSForTest(Byte matchIpToS) { this.matchIpToS = matchIpToS; }
public void setMatchSrcTcpUdpPortForTest(Short matchSrcTcpUdpPort) { this.matchSrcTcpUdpPort = matchSrcTcpUdpPort; }
public void setMatchDstTcpUdpPortForTest(Short matchDstTcpUdpPort) { this.matchDstTcpUdpPort = matchDstTcpUdpPort; }
- public void setActionOutputForTest(Short actionOutput) { this.actionOutput = actionOutput; }
+ public void setActionOutputPortForTest(Short actionOutputPort) { this.actionOutputPort = actionOutputPort; }
+ public void setActionsForTest(String actions) { this.actions = actions; }
public void setFlowPathForTest(IFlowPath flowPath) { this.flowPath = flowPath; }
public void setSwitchForTest(ISwitchObject sw) { this.sw = sw; }
public void setInportForTest(IPortObject inport) { this.inport = inport; }
@@ -935,10 +963,16 @@
public void setMatchDstTcpUdpPort(Short matchDstTcpUdpPort) { matchDstTcpUdpPortToUpdate = matchDstTcpUdpPort; }
@Override
- public Short getActionOutput() { return actionOutput; }
+ public Short getActionOutputPort() { return actionOutputPort; }
@Override
- public void setActionOutput(Short actionOutput) { actionOutputToUpdate = actionOutput; }
+ public void setActionOutputPort(Short actionOutputPort) { actionOutputPortToUpdate = actionOutputPort; }
+
+ @Override
+ public String getActions() { return actions; }
+
+ @Override
+ public void setActions(String actions) { actionsToUpdate = actions; }
@Override
public IFlowPath getFlow() { return flowPath; }
diff --git a/src/test/java/net/onrc/onos/ofcontroller/core/internal/TestableSwitchStorageImpl.java b/src/test/java/net/onrc/onos/ofcontroller/core/internal/TestableSwitchStorageImpl.java
index e78a1b6..e0b34e1 100644
--- a/src/test/java/net/onrc/onos/ofcontroller/core/internal/TestableSwitchStorageImpl.java
+++ b/src/test/java/net/onrc/onos/ofcontroller/core/internal/TestableSwitchStorageImpl.java
@@ -1,13 +1,7 @@
package net.onrc.onos.ofcontroller.core.internal;
-import java.util.Set;
-
import net.onrc.onos.ofcontroller.core.internal.SwitchStorageImpl;
-import com.thinkaurelius.titan.core.TitanGraph;
-import com.tinkerpop.blueprints.Vertex;
-import com.tinkerpop.blueprints.TransactionalGraph.Conclusion;
-
/**
* Seam that allows me to set up a testable instance of SwitchStorageImpl that
* writes to a file database rather than a Cassandra cluster.
diff --git a/src/test/java/net/onrc/onos/ofcontroller/flowmanager/FlowManagerTest.java b/src/test/java/net/onrc/onos/ofcontroller/flowmanager/FlowManagerTest.java
index 750bfba..83a5fab 100644
--- a/src/test/java/net/onrc/onos/ofcontroller/flowmanager/FlowManagerTest.java
+++ b/src/test/java/net/onrc/onos/ofcontroller/flowmanager/FlowManagerTest.java
@@ -80,10 +80,12 @@
}
private IFlowPath createIFlowPathMock(long flowId, String installerID,
+ long flowPathFlags,
long srcDpid, int srcPort, long dstDpid, int dstPort) {
IFlowPath iFlowPath = createNiceMock(IFlowPath.class);
expect(iFlowPath.getFlowId()).andReturn(new FlowId(flowId).toString()).anyTimes();
expect(iFlowPath.getInstallerId()).andReturn(installerID).anyTimes();
+ expect(iFlowPath.getFlowPathFlags()).andReturn(new Long(flowPathFlags)).anyTimes();
expect(iFlowPath.getSrcSwitch()).andReturn(new Dpid(srcDpid).toString()).anyTimes();
expect(iFlowPath.getSrcPort()).andReturn(new Short((short)srcPort)).anyTimes();
expect(iFlowPath.getDstSwitch()).andReturn(new Dpid(dstDpid).toString()).anyTimes();
@@ -92,12 +94,14 @@
}
private FlowPath createTestFlowPath(long flowId, String installerId,
+ final long flowPathFlags,
final long srcDpid, final int srcPort,
final long dstDpid, final int dstPort
) {
FlowPath flowPath = new FlowPath();
flowPath.setFlowId(new FlowId(flowId));
flowPath.setInstallerId(new CallerId(installerId));
+ flowPath.setFlowPathFlags(new FlowPathFlags(flowPathFlags));
flowPath.setDataPath(new DataPath() {{
setSrcPort(new SwitchPort(new Dpid(srcDpid), new Port((short)srcPort)));
setDstPort(new SwitchPort(new Dpid(dstDpid), new Port((short)dstPort)));
@@ -107,9 +111,9 @@
}
private ArrayList<FlowPath> createTestFlowPaths() {
- FlowPath flowPath1 = createTestFlowPath(1, "foo caller id", 1, 1, 2, 2);
- FlowPath flowPath2 = createTestFlowPath(2, "caller id", 1, 1, 2, 2);
- FlowPath flowPath3 = createTestFlowPath(3, "caller id", 1, 5, 2, 2);
+ FlowPath flowPath1 = createTestFlowPath(1, "foo caller id", 0, 1, 1, 2, 2);
+ FlowPath flowPath2 = createTestFlowPath(2, "caller id", 0, 1, 1, 2, 2);
+ FlowPath flowPath3 = createTestFlowPath(3, "caller id", 0, 1, 5, 2, 2);
ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
flowPaths.add(flowPath1);
@@ -182,6 +186,7 @@
FlowPath flowPath = new FlowPath();
flowPath.setFlowId(new FlowId(0x100));
flowPath.setInstallerId(new CallerId("installer id"));
+ flowPath.setFlowPathFlags(new FlowPathFlags(0));
flowPath.setDataPath(dataPath);
flowPath.setFlowEntryMatch(match);
@@ -192,6 +197,7 @@
createdFlowPath.setFlowId("0x100");
createdFlowPath.setType("flow");
createdFlowPath.setInstallerId("installer id");
+ createdFlowPath.setFlowPathFlags(new Long((long)0));
createdFlowPath.setSrcSwitch("00:00:00:00:00:00:12:34");
createdFlowPath.setSrcPort(new Short((short)1));
createdFlowPath.setDstSwitch("00:00:00:00:00:00:56:78");
@@ -339,7 +345,7 @@
public final void testGetFlowSuccessNormally() throws Exception {
// instantiate required objects
FlowManager fm = new FlowManager();
- IFlowPath iFlowPath = createIFlowPathMock(1, "caller id", 1, 1, 2, 2);
+ IFlowPath iFlowPath = createIFlowPathMock(1, "caller id", 0, 1, 1, 2, 2);
// setup expectations
expectInitWithContext();
@@ -351,11 +357,14 @@
replayAll();
fm.init(context);
- String result = fm.getFlow(new FlowId(1)).installerId().toString();
+ FlowPath flowPath = fm.getFlow(new FlowId(1));
+ String installerId = flowPath.installerId().toString();
+ long flowPathFlags = flowPath.flowPathFlags().flags();
//verify the test
verifyAll();
- assertEquals("caller id", result);
+ assertEquals("caller id", installerId);
+ assertEquals(0L, flowPathFlags);
}
/**
@@ -437,9 +446,9 @@
final String getAllFlowsWithoutFlowEntries = "getAllFlowsWithoutFlowEntries";
// create mock objects
FlowManager fm = createPartialMockAndInvokeDefaultConstructor(FlowManager.class, getAllFlowsWithoutFlowEntries);
- IFlowPath flowPath1 = createIFlowPathMock(1, "", 1, 2, 3, 4);
- IFlowPath flowPath2 = createIFlowPathMock(5, "", 2, 3, 4, 5);
- IFlowPath flowPath3 = createIFlowPathMock(10, "", 3, 4, 5, 6);
+ IFlowPath flowPath1 = createIFlowPathMock(1, "", 0, 1, 2, 3, 4);
+ IFlowPath flowPath2 = createIFlowPathMock(5, "", 0, 2, 3, 4, 5);
+ IFlowPath flowPath3 = createIFlowPathMock(10, "", 0, 3, 4, 5, 6);
// instantiate required objects
ArrayList<IFlowPath> flows = new ArrayList<IFlowPath>();
@@ -472,8 +481,8 @@
@Test
public final void testGetAllFlowsSuccessNormally() throws Exception {
// create mock objects
- IFlowPath iFlowPath1 = createIFlowPathMock(1, "caller id", 1, 1, 2, 2);
- IFlowPath iFlowPath2 = createIFlowPathMock(2, "caller id", 2, 5, 3, 5);
+ IFlowPath iFlowPath1 = createIFlowPathMock(1, "caller id", 0, 1, 1, 2, 2);
+ IFlowPath iFlowPath2 = createIFlowPathMock(2, "caller id", 0, 2, 5, 3, 5);
// instantiate required objects
ArrayList<IFlowPath> flowPaths = new ArrayList<IFlowPath>();
@@ -524,6 +533,7 @@
FlowPath paramFlow = new FlowPath();
paramFlow.setFlowId(new FlowId(100));
paramFlow.setInstallerId(new CallerId("installer id"));
+ paramFlow.setFlowPathFlags(new FlowPathFlags(0));
paramFlow.setDataPath(dataPath);
paramFlow.setFlowEntryMatch(match);
@@ -538,6 +548,7 @@
FlowPath flowPath = (FlowPath)EasyMock.getCurrentArguments()[0];
assertEquals(flowPath.flowId().value(), 100);
assertEquals(flowPath.installerId().toString(), "installer id");
+ assertEquals(flowPath.flowPathFlags().flags(), 0);
assertEquals(flowPath.dataPath().srcPort().toString(),
new SwitchPort(new Dpid(1), new Port((short)3)).toString());
@@ -558,237 +569,13 @@
verifyAll();
assertEquals(paramFlow.flowId().value(), resultFlow.flowId().value());
assertEquals(paramFlow.installerId().toString(), resultFlow.installerId().toString());
+ assertEquals(paramFlow.flowPathFlags().flags(), resultFlow.flowPathFlags().flags());
assertEquals(paramFlow.dataPath().toString(), resultFlow.dataPath().toString());
assertEquals(paramFlow.flowEntryMatch().toString(), resultFlow.flowEntryMatch().toString());
}
- /**
- * Test method for {@link FlowManager#measurementStorePathFlow(FlowPath)}.
- * @throws Exception
- */
- @Test
- public final void testMeasurementStorePathFlowSuccessNormally() throws Exception {
- // instantiate required objects
- FlowPath paramFlow = createTestFlowPath(100, "installer id", 1, 3, 2, 4);
- Map<Long, Object> shortestPathMap = new HashMap<Long, Object>();
- FlowManager fm = new FlowManager();
-
- // setup expectations
- expectInitWithContext();
- expect((Map<Long,Object>)topoRouteService.prepareShortestPathTopo()
- ).andReturn(shortestPathMap);
- expect(topoRouteService.getTopoShortestPath(
- shortestPathMap,
- paramFlow.dataPath().srcPort(),
- paramFlow.dataPath().dstPort())).andReturn(null);
-
- // start the test
- replayAll();
-
- fm.init(context);
- FlowPath resultFlowPath = fm.measurementStorePathFlow(paramFlow);
-
- // verify the test
- verifyAll();
- assertEquals(paramFlow.flowId().value(), resultFlowPath.flowId().value());
- assertEquals(paramFlow.installerId().toString(), resultFlowPath.installerId().toString());
- assertEquals(paramFlow.dataPath().toString(), resultFlowPath.dataPath().toString());
- assertEquals(paramFlow.flowEntryMatch().toString(), resultFlowPath.flowEntryMatch().toString());
- }
-
- /**
- * Test method for {@link FlowManager#measurementInstallPaths(Integer)}.
- * @throws Exception
- */
- @Test
- public final void testMeasurementInstallPathsSuccessNormally() throws Exception {
- final String addFlow = "addFlow";
-
- // create mock objects
- FlowManager fm = createPartialMockAndInvokeDefaultConstructor(FlowManager.class, addFlow);
-
- // instantiate required objects
- FlowPath flow1 = createTestFlowPath(1, "installer id", 1, 2, 3, 4);
- FlowPath flow2 = createTestFlowPath(2, "installer id", 2, 3, 4, 5);
- FlowPath flow3 = createTestFlowPath(3, "installer id", 3, 4, 5, 6);
- Map<Long, Object> shortestPathMap = new HashMap<Long, Object>();
-
- // setup expectations
- expectInitWithContext();
- expect((Map<Long,Object>)topoRouteService.prepareShortestPathTopo()
- ).andReturn(shortestPathMap);
-
- expect(topoRouteService.getTopoShortestPath(
- shortestPathMap,
- flow1.dataPath().srcPort(),
- flow1.dataPath().dstPort())).andReturn(null);
-
- expect(topoRouteService.getTopoShortestPath(
- shortestPathMap,
- flow2.dataPath().srcPort(),
- flow2.dataPath().dstPort())).andReturn(null);
-
- expect(topoRouteService.getTopoShortestPath(
- shortestPathMap,
- flow3.dataPath().srcPort(),
- flow3.dataPath().dstPort())).andReturn(null);
-
- expectPrivate(fm, addFlow,
- EasyMock.cmpEq(flow1),
- EasyMock.anyObject(FlowId.class),
- EasyMock.anyObject(String.class)).andReturn(true);
-
- expectPrivate(fm, addFlow,
- EasyMock.cmpEq(flow2),
- EasyMock.anyObject(FlowId.class),
- EasyMock.anyObject(String.class)).andReturn(true);
-
- expectPrivate(fm, addFlow,
- EasyMock.cmpEq(flow3),
- EasyMock.anyObject(FlowId.class),
- EasyMock.anyObject(String.class)).andReturn(true);
-
- // start the test
- replayAll();
-
- fm.init(context);
- fm.measurementStorePathFlow(flow1);
- fm.measurementStorePathFlow(flow2);
- fm.measurementStorePathFlow(flow3);
- Boolean result = fm.measurementInstallPaths(3);
-
- // verify the test
- verifyAll();
- assertTrue(result);
- }
-
- /**
- * Test method for {@link FlowManager#measurementGetInstallPathsTimeNsec()}.
- * @throws Exception
- */
- @Test
- public final void testMeasurementGetInstallPathsTimeNsecSuccessNormally() throws Exception {
- final String addFlow = "addFlow";
-
- // create mock objects
- FlowManager fm = createPartialMockAndInvokeDefaultConstructor(FlowManager.class, addFlow);
- mockStaticPartial(System.class, "nanoTime");
-
- // instantiate required objects
- FlowPath flow1 = createTestFlowPath(1, "installer id", 1, 2, 3, 4);
- Map<Long, Object> shortestPathMap = new HashMap<Long, Object>();
-
- // setup expectations
- expectInitWithContext();
- expect(System.nanoTime()).andReturn(new Long(100000));
- expect(System.nanoTime()).andReturn(new Long(110000));
- expect((Map<Long,Object>)topoRouteService.prepareShortestPathTopo()
- ).andReturn(shortestPathMap);
- expect(topoRouteService.getTopoShortestPath(
- shortestPathMap,
- flow1.dataPath().srcPort(),
- flow1.dataPath().dstPort())).andReturn(null);
- expectPrivate(fm, addFlow,
- EasyMock.cmpEq(flow1),
- EasyMock.anyObject(FlowId.class),
- EasyMock.anyObject(String.class)).andReturn(true);
-
- // start the test
- replayAll();
-
- fm.init(context);
- fm.measurementStorePathFlow(flow1).toString();
- fm.measurementInstallPaths(1);
- Long result = fm.measurementGetInstallPathsTimeNsec();
-
- // verify the test
- verifyAll();
- assertEquals(new Long(10000), result);
- }
-
- /**
- * Test method for {@link FlowManager#measurementGetPerFlowInstallTime()}.
- * @throws Exception
- */
- @Test
- public final void testMeasurementGetPerFlowInstallTimeSuccessNormally() throws Exception {
- final String addFlow = "addFlow";
-
- // create mock objects
- FlowManager fm = createPartialMockAndInvokeDefaultConstructor(FlowManager.class, addFlow);
-
- // instantiate required objects
- FlowPath flow1 = createTestFlowPath(1, "installer id", 1, 2, 3, 4);
- Map<Long, Object> shortestPathMap = new HashMap<Long, Object>();
-
- // setup expectations
- expectInitWithContext();
- expect((Map<Long,Object>)topoRouteService.prepareShortestPathTopo()
- ).andReturn(shortestPathMap);
-
- expect(topoRouteService.getTopoShortestPath(
- shortestPathMap,
- flow1.dataPath().srcPort(),
- flow1.dataPath().dstPort())).andReturn(null);
-
- expectPrivate(fm, addFlow,
- EasyMock.cmpEq(flow1),
- EasyMock.anyObject(FlowId.class),
- EasyMock.anyObject(String.class)).andReturn(true);
-
-
- // start the test
- replayAll();
-
- fm.init(context);
- fm.measurementStorePathFlow(flow1);
- fm.measurementInstallPaths(10);
- String result = fm.measurementGetPerFlowInstallTime();
-
- // verify the test
- verifyAll();
- assertTrue(result.startsWith("ThreadAndTimePerFlow"));
- }
-
- /**
- * Test method for {@link FlowManager#measurementClearAllPaths()}.
- * @throws Exception
- */
- @Test
- public final void testMeasurementClearAllPathsSuccessNormally() throws Exception {
- // instantiate required objects
- FlowPath paramFlow = createTestFlowPath(100, "installer id", 1, 3, 2, 4);
- Map<Long, Object> shortestPathMap = new HashMap<Long, Object>();
- FlowManager fm = new FlowManager();
-
- // setup expectations
- expectInitWithContext();
- expect((Map<Long,Object>)topoRouteService.prepareShortestPathTopo()
- ).andReturn(shortestPathMap);
- expect(topoRouteService.getTopoShortestPath(
- shortestPathMap,
- paramFlow.dataPath().srcPort(),
- paramFlow.dataPath().dstPort())).andReturn(null);
- topoRouteService.dropShortestPathTopo(shortestPathMap);
-
- // start the test
- replayAll();
-
- fm.init(context);
- fm.measurementStorePathFlow(paramFlow);
- Boolean result = fm.measurementClearAllPaths();
-
- // verify the test
- verifyAll();
- assertTrue(result);
- assertEquals(new Long(0), fm.measurementGetInstallPathsTimeNsec());
- assertEquals("", fm.measurementGetPerFlowInstallTime());
- }
-
-
// INetMapStorage methods
-
/**
* Test method for {@link FlowManager#init(String)}.
* @throws Exception
@@ -980,7 +767,7 @@
@Test
public final void testClearFlowSuccessNormally() throws Exception {
// create mock objects
- IFlowPath flowPath = createIFlowPathMock(123, "id", 1, 2, 3, 4);
+ IFlowPath flowPath = createIFlowPathMock(123, "id", 0, 1, 2, 3, 4);
IFlowEntry flowEntry1 = createMock(IFlowEntry.class);
IFlowEntry flowEntry2 = createMock(IFlowEntry.class);
IFlowEntry flowEntry3 = createMock(IFlowEntry.class);
@@ -1023,8 +810,8 @@
@Test
public final void testGetAllFlowsWithoutFlowEntriesSuccessNormally() throws Exception {
// create mock objects
- IFlowPath iFlowPath1 = createIFlowPathMock(1, "caller id", 1, 1, 2, 2);
- IFlowPath iFlowPath2 = createIFlowPathMock(2, "caller id", 2, 5, 3, 5);
+ IFlowPath iFlowPath1 = createIFlowPathMock(1, "caller id", 0, 1, 1, 2, 2);
+ IFlowPath iFlowPath2 = createIFlowPathMock(2, "caller id", 0, 2, 5, 3, 5);
// instantiate required objects
ArrayList<IFlowPath> flowPaths = new ArrayList<IFlowPath>();
@@ -1060,7 +847,7 @@
final String addFlowEntry = "addFlowEntry";
// create mock objects
- IFlowPath iFlowPath1 = createIFlowPathMock(1, "caller id", 1, 1, 2, 2);
+ IFlowPath iFlowPath1 = createIFlowPathMock(1, "caller id", 0, 1, 1, 2, 2);
IFlowEntry iFlowEntry1 = createMock(IFlowEntry.class);
IFlowEntry iFlowEntry2 = createMock(IFlowEntry.class);
FlowManager fm = createPartialMockAndInvokeDefaultConstructor(FlowManager.class, addFlowEntry);
@@ -1073,7 +860,7 @@
flowEntry1.setOutPort(new Port((short) 11));
flowEntry1.setFlowEntryId(new FlowEntryId(1));
flowEntry1.setFlowEntryMatch(new FlowEntryMatch());
- flowEntry1.setFlowEntryActions(new ArrayList<FlowEntryAction>());
+ flowEntry1.setFlowEntryActions(new FlowEntryActions());
flowEntry1.setFlowEntryErrorState(new FlowEntryErrorState());
FlowEntry flowEntry2 = new FlowEntry();
@@ -1083,7 +870,7 @@
flowEntry2.setOutPort(new Port((short) 2));
flowEntry2.setFlowEntryId(new FlowEntryId(2));
flowEntry2.setFlowEntryMatch(new FlowEntryMatch());
- flowEntry2.setFlowEntryActions(new ArrayList<FlowEntryAction>());
+ flowEntry2.setFlowEntryActions(new FlowEntryActions());
flowEntry2.setFlowEntryErrorState(new FlowEntryErrorState());
DataPath dataPath = new DataPath();
@@ -1127,13 +914,18 @@
public final void testInstallFlowEntryWithIFlowPathSuccessNormally() throws Exception {
// create mock object
IOFSwitch iofSwitch = createNiceMock(IOFSwitch.class);
- IFlowPath iFlowPath = createIFlowPathMock(1, "id", 1, 2, 3, 4);
+ IFlowPath iFlowPath = createIFlowPathMock(1, "id", 0, 1, 2, 3, 4);
IFlowEntry iFlowEntry = createMock(IFlowEntry.class);
BasicFactory basicFactory = createMock(BasicFactory.class);
// instantiate required objects
FlowManager fm = new FlowManager();
+ FlowEntryAction action = new FlowEntryAction();
+ action.setActionOutput(new Port((short)2));
+ FlowEntryActions actions = new FlowEntryActions();
+ actions.addAction(action);
+
// setup expectations
expectInitWithContext();
expect(iFlowEntry.getFlowEntryId()).andReturn(new FlowEntryId(123).toString());
@@ -1151,7 +943,7 @@
expect(iFlowEntry.getMatchIpToS()).andReturn(new Byte((byte)0x3));
expect(iFlowEntry.getMatchSrcTcpUdpPort()).andReturn(new Short((short)40000));
expect(iFlowEntry.getMatchDstTcpUdpPort()).andReturn(new Short((short)80));
- expect(iFlowEntry.getActionOutput()).andReturn(new Short((short) 2));
+ expect(iFlowEntry.getActions()).andReturn(actions.toString());
expect(floodlightProvider.getOFMessageFactory()).andReturn(basicFactory);
expect(basicFactory.getMessage(OFType.FLOW_MOD)).andReturn(new OFFlowMod());
expect(iofSwitch.getStringId()).andReturn(new Dpid(100).toString());
diff --git a/src/test/java/net/onrc/onos/ofcontroller/routing/TopoRouteServiceTest.java b/src/test/java/net/onrc/onos/ofcontroller/routing/TopoRouteServiceTest.java
index e6d7d16..7929eb1 100644
--- a/src/test/java/net/onrc/onos/ofcontroller/routing/TopoRouteServiceTest.java
+++ b/src/test/java/net/onrc/onos/ofcontroller/routing/TopoRouteServiceTest.java
@@ -1,21 +1,13 @@
package net.onrc.onos.ofcontroller.routing;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
import java.util.Map;
import org.easymock.EasyMock;
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -25,29 +17,19 @@
import com.thinkaurelius.titan.core.TitanGraph;
import com.thinkaurelius.titan.core.TitanFactory;
-import com.tinkerpop.blueprints.Vertex;
-import com.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine;
-import com.tinkerpop.gremlin.java.GremlinPipeline;
-import com.tinkerpop.pipes.PipeFunction;
-import com.tinkerpop.pipes.branch.LoopPipe.LoopBundle;
-
-import javax.script.ScriptContext;
-import javax.script.ScriptEngine;
-import javax.script.ScriptException;
-
import net.onrc.onos.graph.GraphDBConnection;
import net.onrc.onos.graph.GraphDBOperation;
import net.onrc.onos.ofcontroller.core.internal.TestDatabaseManager;
import net.onrc.onos.ofcontroller.routing.TopoRouteService;
import net.onrc.onos.ofcontroller.util.DataPath;
import net.onrc.onos.ofcontroller.util.Dpid;
+import net.onrc.onos.ofcontroller.util.FlowPathFlags;
import net.onrc.onos.ofcontroller.util.Port;
import net.onrc.onos.ofcontroller.util.SwitchPort;
/**
* A class for testing the TopoRouteService class.
* @see net.onrc.onos.ofcontroller.routing.TopoRouteService
- * @author Pavlin Radoslavov (pavlin@onlab.us)
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({TitanFactory.class, GraphDBConnection.class, GraphDBOperation.class, TopoRouteService.class})
@@ -132,6 +114,20 @@
String expectedResult = "1/00:00:00:00:00:00:0a:01/2;1/00:00:00:00:00:00:0a:03/2;2/00:00:00:00:00:00:0a:04/3;1/00:00:00:00:00:00:0a:06/1;";
assertEquals(dataPathSummaryStr, expectedResult);
+ // Test if we apply various Flow Path Flags
+ String expectedResult2 = "1/00:00:00:00:00:00:0a:03/2;2/00:00:00:00:00:00:0a:04/3;1/00:00:00:00:00:00:0a:06/1;";
+ String expectedResult3 = "1/00:00:00:00:00:00:0a:03/2;";
+ FlowPathFlags flowPathFlags2 = new FlowPathFlags("DISCARD_FIRST_HOP_ENTRY");
+ FlowPathFlags flowPathFlags3 = new FlowPathFlags("KEEP_ONLY_FIRST_HOP_ENTRY");
+ //
+ dataPath.applyFlowPathFlags(flowPathFlags2);
+ dataPathSummaryStr = dataPath.dataPathSummary();
+ assertEquals(dataPathSummaryStr, expectedResult2);
+ //
+ dataPath.applyFlowPathFlags(flowPathFlags3);
+ dataPathSummaryStr = dataPath.dataPathSummary();
+ assertEquals(dataPathSummaryStr, expectedResult3);
+
//
// Test Shortest-Path computation to non-existing destination
//
@@ -180,6 +176,20 @@
String expectedResult = "1/00:00:00:00:00:00:0a:01/2;1/00:00:00:00:00:00:0a:03/2;2/00:00:00:00:00:00:0a:04/3;1/00:00:00:00:00:00:0a:06/1;";
assertEquals(dataPathSummaryStr, expectedResult);
+ // Test if we apply various Flow Path Flags
+ String expectedResult2 = "1/00:00:00:00:00:00:0a:03/2;2/00:00:00:00:00:00:0a:04/3;1/00:00:00:00:00:00:0a:06/1;";
+ String expectedResult3 = "1/00:00:00:00:00:00:0a:03/2;";
+ FlowPathFlags flowPathFlags2 = new FlowPathFlags("DISCARD_FIRST_HOP_ENTRY");
+ FlowPathFlags flowPathFlags3 = new FlowPathFlags("KEEP_ONLY_FIRST_HOP_ENTRY");
+ //
+ dataPath.applyFlowPathFlags(flowPathFlags2);
+ dataPathSummaryStr = dataPath.dataPathSummary();
+ assertEquals(dataPathSummaryStr, expectedResult2);
+ //
+ dataPath.applyFlowPathFlags(flowPathFlags3);
+ dataPathSummaryStr = dataPath.dataPathSummary();
+ assertEquals(dataPathSummaryStr, expectedResult3);
+
//
// Test Shortest-Path computation to non-existing destination
//
diff --git a/src/test/java/net/onrc/onos/ofcontroller/util/FlowEntryActionTest.java b/src/test/java/net/onrc/onos/ofcontroller/util/FlowEntryActionTest.java
new file mode 100644
index 0000000..4db734c
--- /dev/null
+++ b/src/test/java/net/onrc/onos/ofcontroller/util/FlowEntryActionTest.java
@@ -0,0 +1,427 @@
+package net.onrc.onos.ofcontroller.util;
+
+import static org.junit.Assert.assertEquals;
+import net.floodlightcontroller.util.MACAddress;
+import net.onrc.onos.ofcontroller.util.FlowEntryAction.ActionEnqueue;
+import net.onrc.onos.ofcontroller.util.FlowEntryAction.ActionOutput;
+import net.onrc.onos.ofcontroller.util.FlowEntryAction.ActionSetEthernetAddr;
+import net.onrc.onos.ofcontroller.util.FlowEntryAction.ActionSetIPv4Addr;
+import net.onrc.onos.ofcontroller.util.FlowEntryAction.ActionSetIpToS;
+import net.onrc.onos.ofcontroller.util.FlowEntryAction.ActionSetTcpUdpPort;
+import net.onrc.onos.ofcontroller.util.FlowEntryAction.ActionSetVlanId;
+import net.onrc.onos.ofcontroller.util.FlowEntryAction.ActionSetVlanPriority;
+import net.onrc.onos.ofcontroller.util.FlowEntryAction.ActionStripVlan;
+
+import org.junit.Test;
+
+public class FlowEntryActionTest {
+
+ @Test
+ public void testSetActionOutputActionOutput(){
+ FlowEntryAction act = new FlowEntryAction();
+ ActionOutput actout = act.new ActionOutput(new Port((short)42));
+ act.setActionOutput(actout);
+
+ assertEquals("action output",FlowEntryAction.ActionValues.ACTION_OUTPUT , act.actionType());
+ assertEquals("actionOutput port should be the same", actout.port(), act.actionOutput().port());
+ assertEquals("actionOutput maxlen should be the same", actout.maxLen(), act.actionOutput().maxLen());
+
+ FlowEntryAction act_copy = new FlowEntryAction(act);
+ FlowEntryAction act_copy2 = new FlowEntryAction(act.toString());
+
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy.toString());
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy2.toString());
+ }
+
+ @Test
+ public void testSetActionOutputPort(){
+ FlowEntryAction act = new FlowEntryAction();
+ act.setActionOutput(new Port((short)42));
+
+ FlowEntryAction act_copy = new FlowEntryAction(act);
+ FlowEntryAction act_copy2 = new FlowEntryAction(act.toString());
+
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy.toString());
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy2.toString());
+ }
+
+ @Test
+ public void testSetActionOutputToController(){
+ FlowEntryAction act = new FlowEntryAction();
+ act.setActionOutputToController((short)0);
+
+ FlowEntryAction act_copy = new FlowEntryAction();
+ act_copy.setActionOutput(new Port(Port.PortValues.PORT_CONTROLLER));
+ ;
+ FlowEntryAction act_copy2 = new FlowEntryAction(act.toString());
+
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy.toString());
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy2.toString());
+ }
+
+ @Test
+ public void testSetActionSetVlanIdActionSetVlanId(){
+ FlowEntryAction act = new FlowEntryAction();
+ ActionSetVlanId actVlan = act.new ActionSetVlanId((short)42);
+ act.setActionSetVlanId(actVlan);
+
+ assertEquals("action type",FlowEntryAction.ActionValues.ACTION_SET_VLAN_VID , act.actionType());
+ assertEquals("vlanid should be the same", actVlan.vlanId(), act.actionSetVlanId().vlanId());
+
+ FlowEntryAction act_copy = new FlowEntryAction(act);
+ FlowEntryAction act_copy2 = new FlowEntryAction(act.toString());
+
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy.toString());
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy2.toString());
+ }
+
+ @Test
+ public void testSetActionSetVlanIdShort(){
+ FlowEntryAction act = new FlowEntryAction();
+ act.setActionSetVlanId((short)42);
+
+ FlowEntryAction act_copy = new FlowEntryAction(act);
+ FlowEntryAction act_copy2 = new FlowEntryAction(act.toString());
+
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy.toString());
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy2.toString());
+ }
+
+ @Test
+ public void testSetActionSetVlanPriorityActionSetVlanPriority(){
+ FlowEntryAction act = new FlowEntryAction();
+ ActionSetVlanPriority actVlan = act.new ActionSetVlanPriority((byte)42);
+ act.setActionSetVlanPriority(actVlan);
+
+ assertEquals("action type",FlowEntryAction.ActionValues.ACTION_SET_VLAN_PCP , act.actionType());
+ assertEquals("vlan priority should be the same", actVlan.vlanPriority(), act.actionSetVlanPriority().vlanPriority());
+
+ FlowEntryAction act_copy = new FlowEntryAction(act);
+ FlowEntryAction act_copy2 = new FlowEntryAction(act.toString());
+
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy.toString());
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy2.toString());
+ }
+
+ @Test
+ public void testSetActionSetVlanPriorityByte(){
+ FlowEntryAction act = new FlowEntryAction();
+ act.setActionSetVlanPriority((byte)42);
+
+ FlowEntryAction act_copy = new FlowEntryAction(act);
+ FlowEntryAction act_copy2 = new FlowEntryAction(act.toString());
+
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy.toString());
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy2.toString());
+ }
+
+ @Test
+ public void testSetActionStripVlanActionStripVlan(){
+ FlowEntryAction act = new FlowEntryAction();
+ ActionStripVlan actVlan = act.new ActionStripVlan();
+ act.setActionStripVlan(actVlan);
+
+ assertEquals("action type",FlowEntryAction.ActionValues.ACTION_STRIP_VLAN , act.actionType());
+ assertEquals("vlanid should be the same", actVlan.stripVlan(), act.actionStripVlan().stripVlan());
+
+ FlowEntryAction act_copy = new FlowEntryAction(act);
+ FlowEntryAction act_copy2 = new FlowEntryAction(act.toString());
+
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy.toString());
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy2.toString());
+ }
+
+ @Test
+ public void testSetActionStripVlanBoolean(){
+ FlowEntryAction act = new FlowEntryAction();
+ act.setActionStripVlan(true);
+
+ FlowEntryAction act_copy = new FlowEntryAction(act);
+ FlowEntryAction act_copy2 = new FlowEntryAction(act.toString());
+
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy.toString());
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy2.toString());
+ }
+
+ @Test
+ public void testSetActionSetEthernetSrcAddrActionSetEthernetAddr(){
+ FlowEntryAction act = new FlowEntryAction();
+ byte[] mac = { 1, 2, 3, 4, 5, 6 };
+ ActionSetEthernetAddr setEth = act.new ActionSetEthernetAddr(new MACAddress(mac));
+ act.setActionSetEthernetSrcAddr( setEth );
+
+ assertEquals("action type",FlowEntryAction.ActionValues.ACTION_SET_DL_SRC , act.actionType());
+ assertEquals("addr should be the same", setEth.addr(), act.actionSetEthernetSrcAddr().addr());
+
+
+ FlowEntryAction act_copy = new FlowEntryAction(act);
+ FlowEntryAction act_copy2 = new FlowEntryAction(act.toString());
+
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy.toString());
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy2.toString());
+ }
+
+ @Test
+ public void testSetActionSetEthernetSrcAddrMACAddress(){
+ FlowEntryAction act = new FlowEntryAction();
+ byte[] mac = { 1, 2, 3, 4, 5, 6 };
+ act.setActionSetEthernetSrcAddr(new MACAddress(mac));
+
+ FlowEntryAction act_copy = new FlowEntryAction(act);
+ FlowEntryAction act_copy2 = new FlowEntryAction(act.toString());
+
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy.toString());
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy2.toString());
+ }
+
+ @Test
+ public void testSetActionSetEthernetDstAddrActionSetEthernetAddr(){
+ FlowEntryAction act = new FlowEntryAction();
+ byte[] mac = { 1, 2, 3, 4, 5, 6 };
+ ActionSetEthernetAddr setEth = act.new ActionSetEthernetAddr(new MACAddress(mac));
+ act.setActionSetEthernetDstAddr( setEth );
+
+ assertEquals("action type",FlowEntryAction.ActionValues.ACTION_SET_DL_DST , act.actionType());
+ assertEquals("addr should be the same", setEth.addr(), act.actionSetEthernetDstAddr().addr());
+
+ FlowEntryAction act_copy = new FlowEntryAction(act);
+ FlowEntryAction act_copy2 = new FlowEntryAction(act.toString());
+
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy.toString());
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy2.toString());
+ }
+
+ @Test
+ public void testSetActionSetEthernetDstAddrMACAddress(){
+ FlowEntryAction act = new FlowEntryAction();
+ byte[] mac = { 1, 2, 3, 4, 5, 6 };
+ act.setActionSetEthernetDstAddr(new MACAddress(mac));
+
+ FlowEntryAction act_copy = new FlowEntryAction(act);
+ FlowEntryAction act_copy2 = new FlowEntryAction(act.toString());
+
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy.toString());
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy2.toString());
+ }
+
+ @Test
+ public void testSetActionSetIPv4SrcAddrActionSetIPv4Addr(){
+ FlowEntryAction act = new FlowEntryAction();
+ ActionSetIPv4Addr setIp = act.new ActionSetIPv4Addr(new IPv4("127.0.0.1"));
+ act.setActionSetIPv4SrcAddr( setIp );
+
+ assertEquals("action type",FlowEntryAction.ActionValues.ACTION_SET_NW_SRC , act.actionType());
+ assertEquals("addr should be the same", setIp.addr(), act.actionSetIPv4SrcAddr().addr());
+
+ FlowEntryAction act_copy = new FlowEntryAction(act);
+ FlowEntryAction act_copy2 = new FlowEntryAction(act.toString());
+
+
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy.toString());
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy2.toString());
+ }
+
+ @Test
+ public void testSetActionSetIPv4SrcAddrIPv4(){
+ FlowEntryAction act = new FlowEntryAction();
+ act.setActionSetIPv4SrcAddr(new IPv4("127.0.0.1"));
+
+ FlowEntryAction act_copy = new FlowEntryAction(act);
+ FlowEntryAction act_copy2 = new FlowEntryAction(act.toString());
+
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy.toString());
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy2.toString());
+ }
+
+ @Test
+ public void testSetActionSetIPv4DstAddrActionSetIPv4Addr(){
+ FlowEntryAction act = new FlowEntryAction();
+ ActionSetIPv4Addr setIp = act.new ActionSetIPv4Addr(new IPv4("127.0.0.1"));
+ act.setActionSetIPv4DstAddr( setIp );
+
+ assertEquals("action type",FlowEntryAction.ActionValues.ACTION_SET_NW_DST , act.actionType());
+ assertEquals("addr should be the same", setIp.addr(), act.actionSetIPv4DstAddr().addr());
+
+ FlowEntryAction act_copy = new FlowEntryAction(act);
+ FlowEntryAction act_copy2 = new FlowEntryAction(act.toString());
+
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy.toString());
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy2.toString());
+ }
+
+ @Test
+ public void testSetActionSetIPv4DstAddrIPv4(){
+ FlowEntryAction act = new FlowEntryAction();
+ act.setActionSetIPv4DstAddr(new IPv4("127.0.0.1"));
+
+ FlowEntryAction act_copy = new FlowEntryAction(act);
+ FlowEntryAction act_copy2 = new FlowEntryAction(act.toString());
+
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy.toString());
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy2.toString());
+ }
+
+ @Test
+ public void testSetActionSetIpToSActionSetIpToS(){
+ FlowEntryAction act = new FlowEntryAction();
+ ActionSetIpToS setIpTos = act.new ActionSetIpToS((byte)42);
+ act.setActionSetIpToS( setIpTos );
+
+ assertEquals("action type",FlowEntryAction.ActionValues.ACTION_SET_NW_TOS , act.actionType());
+ assertEquals("tos should be the same", setIpTos.ipToS(), act.actionSetIpToS().ipToS());
+
+ FlowEntryAction act_copy = new FlowEntryAction(act);
+ FlowEntryAction act_copy2 = new FlowEntryAction(act.toString());
+
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy.toString());
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy2.toString());
+ }
+
+ @Test
+ public void testSetActionSetIpToSByte(){
+ FlowEntryAction act = new FlowEntryAction();
+ act.setActionSetIpToS((byte)1);
+
+ FlowEntryAction act_copy = new FlowEntryAction(act);
+ FlowEntryAction act_copy2 = new FlowEntryAction(act.toString());
+
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy.toString());
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy2.toString());
+ }
+
+ @Test
+ public void testSetActionSetTcpUdpSrcPortActionSetTcpUdpPort(){
+ FlowEntryAction act = new FlowEntryAction();
+ ActionSetTcpUdpPort setPorts = act.new ActionSetTcpUdpPort((short)42);
+ act.setActionSetTcpUdpSrcPort( setPorts );
+
+ assertEquals("action type",FlowEntryAction.ActionValues.ACTION_SET_TP_SRC , act.actionType());
+ assertEquals("port should be the same", setPorts.port(), act.actionSetTcpUdpSrcPort().port());
+
+ FlowEntryAction act_copy = new FlowEntryAction(act);
+ FlowEntryAction act_copy2 = new FlowEntryAction(act.toString());
+
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy.toString());
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy2.toString());
+ }
+
+ @Test
+ public void testSetActionSetTcpUdpSrcPortShort(){
+ FlowEntryAction act = new FlowEntryAction();
+ act.setActionSetTcpUdpSrcPort((short)1);
+
+ FlowEntryAction act_copy = new FlowEntryAction(act);
+ FlowEntryAction act_copy2 = new FlowEntryAction(act.toString());
+
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy.toString());
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy2.toString());
+ }
+
+ @Test
+ public void testSetActionSetTcpUdpDstPortActionSetTcpUdpPort(){
+ FlowEntryAction act = new FlowEntryAction();
+ ActionSetTcpUdpPort setPorts = act.new ActionSetTcpUdpPort((short)42);
+ act.setActionSetTcpUdpDstPort( setPorts );
+
+ assertEquals("action type",FlowEntryAction.ActionValues.ACTION_SET_TP_DST , act.actionType());
+ assertEquals("port should be the same", setPorts.port(), act.actionSetTcpUdpDstPort().port());
+
+ FlowEntryAction act_copy = new FlowEntryAction(act);
+ FlowEntryAction act_copy2 = new FlowEntryAction(act.toString());
+
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy.toString());
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy2.toString());
+ }
+
+ @Test
+ public void testSetActionSetTcpUdpDstPortShort(){
+ FlowEntryAction act = new FlowEntryAction();
+ act.setActionSetTcpUdpDstPort((short)1);
+
+ FlowEntryAction act_copy = new FlowEntryAction(act);
+ FlowEntryAction act_copy2 = new FlowEntryAction(act.toString());
+
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy.toString());
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy2.toString());
+ }
+
+ @Test
+ public void testSetActionEnqueueActionEnqueue(){
+ FlowEntryAction act = new FlowEntryAction();
+ ActionEnqueue enq = act.new ActionEnqueue(new Port((short)42), 1);
+ act.setActionEnqueue( enq );
+
+ assertEquals("action type",FlowEntryAction.ActionValues.ACTION_ENQUEUE , act.actionType());
+ assertEquals("port should be the same", enq.port(), act.actionEnqueue().port());
+ assertEquals("queue id should be the same", enq.queueId(), act.actionEnqueue().queueId());
+
+ FlowEntryAction act_copy = new FlowEntryAction(act);
+ FlowEntryAction act_copy2 = new FlowEntryAction(act.toString());
+
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy.toString());
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy2.toString());
+ }
+
+ @Test
+ public void testSetActionEnqueuePortInt(){
+ FlowEntryAction act = new FlowEntryAction();
+ act.setActionEnqueue(new Port((short)42), 1);
+
+ FlowEntryAction act_copy = new FlowEntryAction(act);
+ FlowEntryAction act_copy2 = new FlowEntryAction(act.toString());
+
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy.toString());
+ assertEquals("toString must match between copies", act.toString(),
+ act_copy2.toString());
+ }
+
+}
diff --git a/src/test/java/net/onrc/onos/ofcontroller/util/FlowEntryMatchTest.java b/src/test/java/net/onrc/onos/ofcontroller/util/FlowEntryMatchTest.java
new file mode 100644
index 0000000..4381208
--- /dev/null
+++ b/src/test/java/net/onrc/onos/ofcontroller/util/FlowEntryMatchTest.java
@@ -0,0 +1,312 @@
+package net.onrc.onos.ofcontroller.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import net.floodlightcontroller.util.MACAddress;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class FlowEntryMatchTest {
+
+ FlowEntryMatch match;
+
+ Port inport = new Port((short)1);
+ byte[] byte1 = { 1, 2, 3, 4, 5, 6 };
+ byte[] byte2 = { 6, 5, 4, 3, 2, 1 };
+ MACAddress mac1 = new MACAddress(byte1);
+ MACAddress mac2 = new MACAddress(byte2);
+ Short ether = Short.valueOf((short)2);
+ Short vlanid = Short.valueOf((short)3);
+ Byte vlanprio = Byte.valueOf((byte)4);
+ IPv4Net ip1 = new IPv4Net("127.0.0.1/32");
+ IPv4Net ip2 = new IPv4Net("127.0.0.2/32");
+ Byte ipproto = Byte.valueOf((byte)5);
+ Byte ipToS = Byte.valueOf((byte)6);
+ Short tport1 = Short.valueOf((short)7);
+ Short tport2 = Short.valueOf((short)8);
+
+ @Before
+ public void setUp() throws Exception{
+ match = new FlowEntryMatch();
+ match.enableInPort( inport);
+ match.enableSrcMac( mac1 );
+ match.enableDstMac( mac2 );
+ match.enableEthernetFrameType( ether );
+ match.enableVlanId( vlanid );
+ match.enableVlanPriority( vlanprio );
+ match.enableSrcIPv4Net( ip1 );
+ match.enableDstIPv4Net( ip2 );
+ match.enableIpProto( ipproto );
+ match.enableIpToS( ipToS );
+ match.enableSrcTcpUdpPort( tport1 );
+ match.enableDstTcpUdpPort( tport2 );
+ }
+
+ @Test
+ public void testFlowEntryMatch(){
+ FlowEntryMatch def = new FlowEntryMatch();
+
+ assertEquals("default null", null, def.inPort() );
+ assertEquals("default null", null, def.srcMac() );
+ assertEquals("default null", null, def.dstMac() );
+ assertEquals("default null", null, def.ethernetFrameType() );
+ assertEquals("default null", null, def.vlanId() );
+ assertEquals("default null", null, def.vlanPriority() );
+ assertEquals("default null", null, def.srcIPv4Net() );
+ assertEquals("default null", null, def.dstIPv4Net() );
+ assertEquals("default null", null, def.ipProto() );
+ assertEquals("default null", null, def.ipToS() );
+ assertEquals("default null", null, def.srcTcpUdpPort() );
+ assertEquals("default null", null, def.dstTcpUdpPort() );
+ }
+
+ @Test
+ public void testFlowEntryMatchFlowEntryMatch(){
+ FlowEntryMatch def_base = new FlowEntryMatch();
+ FlowEntryMatch def = new FlowEntryMatch(def_base);
+
+ assertEquals("default null", null, def.inPort() );
+ assertEquals("default null", null, def.srcMac() );
+ assertEquals("default null", null, def.dstMac() );
+ assertEquals("default null", null, def.ethernetFrameType() );
+ assertEquals("default null", null, def.vlanId() );
+ assertEquals("default null", null, def.vlanPriority() );
+ assertEquals("default null", null, def.srcIPv4Net() );
+ assertEquals("default null", null, def.dstIPv4Net() );
+ assertEquals("default null", null, def.ipProto() );
+ assertEquals("default null", null, def.ipToS() );
+ assertEquals("default null", null, def.srcTcpUdpPort() );
+ assertEquals("default null", null, def.dstTcpUdpPort() );
+
+ FlowEntryMatch copy = new FlowEntryMatch( match );
+
+ assertEquals("inport", inport, copy.inPort() );
+ assertEquals("mac1", mac1, copy.srcMac() );
+ assertEquals("mac2", mac2, copy.dstMac() );
+ assertEquals("ether", ether, copy.ethernetFrameType() );
+ assertEquals("vlan id", vlanid, copy.vlanId() );
+ assertEquals("vlan prio", vlanprio, copy.vlanPriority() );
+ assertEquals("ip1", ip1, copy.srcIPv4Net() );
+ assertEquals("ip2", ip2, copy.dstIPv4Net() );
+ assertEquals("ip proto", ipproto, copy.ipProto() );
+ assertEquals("tos", ipToS, copy.ipToS() );
+ assertEquals("src port", tport1, copy.srcTcpUdpPort() );
+ assertEquals("dst port", tport2, copy.dstTcpUdpPort() );
+
+ }
+
+ @Test
+ public void testInPort(){
+ assertEquals("inport", inport, match.inPort() );
+ }
+
+ @Test
+ public void testDisableInPort(){
+ match.disableInPort();
+ assertEquals("inport", null, match.inPort() );
+ assertFalse( match.matchInPort() );
+ }
+
+ @Test
+ public void testMatchInPort(){
+ assertTrue( match.matchInPort() );
+ }
+
+ @Test
+ public void testSrcMac(){
+ assertEquals("mac1", mac1, match.srcMac() );
+ }
+
+ @Test
+ public void testDisableSrcMac(){
+ match.disableSrcMac();
+ assertEquals("srcMac", null, match.srcMac() );
+ assertFalse( match.matchSrcMac() );
+ }
+
+ @Test
+ public void testMatchSrcMac(){
+ assertTrue( match.matchSrcMac() );
+ }
+
+ @Test
+ public void testDstMac(){
+ assertEquals("mac2", mac2, match.dstMac() );
+ }
+
+ @Test
+ public void testDisableDstMac(){
+ match.disableDstMac();
+ assertEquals("dstMac", null, match.dstMac() );
+ assertFalse( match.matchDstMac() );
+ }
+
+ @Test
+ public void testMatchDstMac(){
+ assertTrue( match.matchDstMac() );
+ }
+
+ @Test
+ public void testEthernetFrameType(){
+ assertEquals("ether", ether, match.ethernetFrameType() );
+ }
+
+ @Test
+ public void testDisableEthernetFrameType(){
+ match.disableEthernetFrameType();
+ assertEquals("ethernetFrameType", null, match.ethernetFrameType() );
+ assertFalse( match.matchEthernetFrameType() );
+ }
+
+ @Test
+ public void testMatchEthernetFrameType(){
+ assertTrue( match.matchEthernetFrameType() );
+ }
+
+ @Test
+ public void testVlanId(){
+ assertEquals("vlan id", vlanid, match.vlanId() );
+ }
+
+ @Test
+ public void testDisableVlanId(){
+ match.disableVlanId();
+ assertEquals("vlanId", null, match.vlanId() );
+ assertFalse( match.matchVlanId() );
+ }
+
+ @Test
+ public void testMatchVlanId(){
+ assertTrue( match.matchVlanId() );
+ }
+
+ @Test
+ public void testVlanPriority(){
+ assertEquals("vlan prio", vlanprio, match.vlanPriority() );
+ }
+
+ @Test
+ public void testDisableVlanPriority(){
+ match.disableVlanPriority();
+ assertEquals("vlanPriority", null, match.vlanPriority() );
+ assertFalse( match.matchVlanPriority() );
+ }
+
+ @Test
+ public void testMatchVlanPriority(){
+ assertTrue( match.matchVlanPriority() );
+ }
+
+ @Test
+ public void testSrcIPv4Net(){
+ assertEquals("ip1", ip1, match.srcIPv4Net() );
+ }
+
+ @Test
+ public void testDisableSrcIPv4Net(){
+ match.disableSrcIPv4Net();
+ assertEquals("srcIPv4Net", null, match.srcIPv4Net() );
+ assertFalse( match.matchSrcIPv4Net() );
+ }
+
+ @Test
+ public void testMatchSrcIPv4Net(){
+ assertTrue( match.matchSrcIPv4Net() );
+ }
+
+ @Test
+ public void testDstIPv4Net(){
+ assertEquals("ip2", ip2, match.dstIPv4Net() );
+ }
+
+ @Test
+ public void testDisableDstIPv4Net(){
+ match.disableDstIPv4Net();
+ assertEquals("dstIPv4Net", null, match.dstIPv4Net() );
+ assertFalse( match.matchDstIPv4Net() );
+ }
+
+ @Test
+ public void testMatchDstIPv4Net(){
+ assertTrue( match.matchDstIPv4Net() );
+ }
+
+ @Test
+ public void testIpProto(){
+ assertEquals("ip proto", ipproto, match.ipProto() );
+ }
+
+ @Test
+ public void testDisableIpProto(){
+ match.disableIpProto();
+ assertEquals("ipProto", null, match.ipProto() );
+ assertFalse( match.matchIpProto() );
+ }
+
+ @Test
+ public void testMatchIpProto(){
+ assertTrue( match.matchIpProto() );
+ }
+
+ @Test
+ public void testIpToS(){
+ assertEquals("tos", ipToS, match.ipToS() );
+ }
+
+ @Test
+ public void testDisableIpToS(){
+ match.disableIpToS();
+ assertEquals("ipToS", null, match.ipToS() );
+ assertFalse( match.matchIpToS() );
+ }
+
+ @Test
+ public void testMatchIpToS(){
+ assertTrue( match.matchIpToS() );
+ }
+
+ @Test
+ public void testSrcTcpUdpPort(){
+ assertEquals("src port", tport1, match.srcTcpUdpPort() );
+ }
+
+ @Test
+ public void testDisableSrcTcpUdpPort(){
+ match.disableSrcTcpUdpPort();
+ assertEquals("srcTcpUdpPort", null, match.srcTcpUdpPort() );
+ assertFalse( match.matchSrcTcpUdpPort() );
+ }
+
+ @Test
+ public void testMatchSrcTcpUdpPort(){
+ assertTrue( match.matchSrcTcpUdpPort() );
+ }
+
+ @Test
+ public void testDstTcpUdpPort(){
+ assertEquals("dst port", tport2, match.dstTcpUdpPort() );
+ }
+
+ @Test
+ public void testDisableDstTcpUdpPort(){
+ match.disableDstTcpUdpPort();
+ assertEquals("dstTcpUdpPort", null, match.dstTcpUdpPort() );
+ assertFalse( match.matchDstTcpUdpPort() );
+ }
+
+ @Test
+ public void testMatchDstTcpUdpPort(){
+ assertTrue( match.matchDstTcpUdpPort() );
+ }
+
+ @Test
+ public void testToString(){
+ FlowEntryMatch def = new FlowEntryMatch();
+ assertEquals("match default", def.toString(), "[]");
+
+ assertEquals("match set", match.toString(), "[inPort=1 srcMac=01:02:03:04:05:06 dstMac=06:05:04:03:02:01 ethernetFrameType=2 vlanId=3 vlanPriority=4 srcIPv4Net=127.0.0.1/32 dstIPv4Net=127.0.0.2/32 ipProto=5 ipToS=6 srcTcpUdpPort=7 dstTcpUdpPort=8]");
+ }
+
+}
diff --git a/src/test/java/net/onrc/onos/ofcontroller/util/FlowEntryTest.java b/src/test/java/net/onrc/onos/ofcontroller/util/FlowEntryTest.java
new file mode 100644
index 0000000..1d193c4
--- /dev/null
+++ b/src/test/java/net/onrc/onos/ofcontroller/util/FlowEntryTest.java
@@ -0,0 +1,210 @@
+package net.onrc.onos.ofcontroller.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import net.floodlightcontroller.util.MACAddress;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class FlowEntryTest {
+
+ FlowEntry entry;
+
+ FlowId flowId = new FlowId(0x1234);
+ FlowEntryId flowEntryId = new FlowEntryId(0x5678);
+ FlowEntryMatch match;
+ FlowEntryActions actions;
+
+ Dpid dpid = new Dpid(0xCAFE);
+
+ Port inport = new Port((short)1);
+ byte[] byte1 = { 1, 2, 3, 4, 5, 6 };
+ byte[] byte2 = { 6, 5, 4, 3, 2, 1 };
+ MACAddress mac1 = new MACAddress(byte1);
+ MACAddress mac2 = new MACAddress(byte2);
+ Short ether = Short.valueOf((short)2);
+ Short vlanid = Short.valueOf((short)3);
+ Byte vlanprio = Byte.valueOf((byte)4);
+ IPv4Net ip1 = new IPv4Net("127.0.0.1/32");
+ IPv4Net ip2 = new IPv4Net( new IPv4("127.0.0.2"), (short)32);
+ IPv4 ipaddr1 = new IPv4("127.0.0.3");
+ IPv4 ipaddr2 = new IPv4("127.0.0.4");
+ Byte ipproto = Byte.valueOf((byte)5);
+ Byte ipToS = Byte.valueOf((byte)6);
+ Short tport1 = Short.valueOf((short)7);
+ Short tport2 = Short.valueOf((short)8);
+ Port outport = new Port((short)9);
+ Port queueport = new Port((short)10);
+ int queueId = 11;
+
+ FlowEntryErrorState errorState = new FlowEntryErrorState( (short)12, (short)13);
+
+
+ @Before
+ public void setUp() throws Exception{
+ entry = new FlowEntry();
+
+ flowId = new FlowId("0x1234");
+ entry.setFlowId( flowId );
+
+ flowEntryId = new FlowEntryId("0x5678");
+ entry.setFlowEntryId(flowEntryId);
+
+ dpid = new Dpid("CA:FE");
+ entry.setDpid( dpid );
+
+ entry.setInPort( inport );
+ entry.setOutPort( outport );
+
+ match = new FlowEntryMatch();
+ match.enableInPort( inport);
+ match.enableSrcMac( mac1 );
+ match.enableDstMac( mac2 );
+ match.enableEthernetFrameType( ether );
+ match.enableVlanId( vlanid );
+ match.enableVlanPriority( vlanprio );
+ match.enableSrcIPv4Net( ip1 );
+ match.enableDstIPv4Net( ip2 );
+ match.enableIpProto( ipproto );
+ match.enableIpToS( ipToS );
+ match.enableSrcTcpUdpPort( tport1 );
+ match.enableDstTcpUdpPort( tport2 );
+
+ entry.setFlowEntryMatch( match );
+
+ FlowEntryAction action = null;
+ actions = entry.flowEntryActions();
+
+ action = new FlowEntryAction();
+ action.setActionOutput(outport);
+ actions.addAction(action);
+
+ action = new FlowEntryAction();
+ action.setActionOutputToController((short)0);
+ actions.addAction(action);
+
+ action = new FlowEntryAction();
+ action.setActionSetVlanId(vlanid);
+ actions.addAction(action);
+
+ action = new FlowEntryAction();
+ action.setActionSetVlanPriority(vlanprio);
+ actions.addAction(action);
+
+ action = new FlowEntryAction();
+ action.setActionStripVlan(true);
+ actions.addAction(action);
+
+ action = new FlowEntryAction();
+ action.setActionSetEthernetSrcAddr(mac1);
+ actions.addAction(action);
+
+ action = new FlowEntryAction();
+ action.setActionSetEthernetDstAddr(mac2);
+ actions.addAction(action);
+
+ action = new FlowEntryAction();
+ action.setActionSetIPv4SrcAddr(ipaddr1);
+ actions.addAction(action);
+
+ action = new FlowEntryAction();
+ action.setActionSetIPv4DstAddr(ipaddr2);
+ actions.addAction(action);
+
+ action = new FlowEntryAction();
+ action.setActionSetIpToS(ipToS);
+ actions.addAction(action);
+
+ action = new FlowEntryAction();
+ action.setActionSetTcpUdpSrcPort(tport1);
+ actions.addAction(action);
+
+ action = new FlowEntryAction();
+ action.setActionSetTcpUdpDstPort(tport2);
+ actions.addAction(action);
+
+ action = new FlowEntryAction();
+ action.setActionEnqueue(queueport, queueId);
+ actions.addAction(action);
+
+ entry.setFlowEntryUserState( FlowEntryUserState.FE_USER_ADD );
+ entry.setFlowEntrySwitchState( FlowEntrySwitchState.FE_SWITCH_UPDATED );
+ entry.setFlowEntryErrorState( errorState );
+
+ }
+
+ @Test
+ public void testFlowEntry(){
+ FlowEntry e = new FlowEntry();
+
+ assertTrue( e.flowEntryActions().isEmpty() );
+ assertEquals("flowEntryUserState", FlowEntryUserState.FE_USER_UNKNOWN, e.flowEntryUserState() );
+ assertEquals("flowEntrySwitchState", FlowEntrySwitchState.FE_SWITCH_UNKNOWN, e.flowEntrySwitchState() );
+ }
+
+ @Test
+ public void testGetFlowId(){
+ assertEquals("flowId", flowId, entry.getFlowId() );
+ }
+
+ @Test
+ public void testFlowEntryId(){
+ assertEquals("flowEntryId", flowEntryId, entry.flowEntryId() );
+ }
+
+ @Test
+ public void testFlowEntryMatch(){
+ assertEquals("flowEntryMatch", match, entry.flowEntryMatch() );
+ }
+
+ @Test
+ public void testFlowEntryActions(){
+ assertEquals("flowEntryActions", actions, entry.flowEntryActions() );
+ }
+
+ @Test
+ public void testSetFlowEntryActions(){
+ FlowEntryActions actions = new FlowEntryActions();
+ entry.setFlowEntryActions( actions );
+ assertEquals("flowEntryActions", actions, entry.flowEntryActions() );
+ }
+
+ @Test
+ public void testDpid(){
+ assertEquals("dpid", dpid, entry.dpid() );
+ }
+
+ @Test
+ public void testInPort(){
+ assertEquals("inPort", inport, entry.inPort() );
+ }
+
+ @Test
+ public void testOutPort(){
+ assertEquals("outPort", outport, entry.outPort() );
+ }
+
+ @Test
+ public void testFlowEntryUserState(){
+ assertEquals("flowEntryUserState", FlowEntryUserState.FE_USER_ADD, entry.flowEntryUserState() );
+ }
+
+ @Test
+ public void testFlowEntrySwitchState(){
+ assertEquals("flowEntrySwitchState", FlowEntrySwitchState.FE_SWITCH_UPDATED, entry.flowEntrySwitchState() );
+ }
+
+ @Test
+ public void testFlowEntryErrorState(){
+ assertEquals("flowEntryErrorState", errorState, entry.flowEntryErrorState() );
+ }
+
+ @Test
+ public void testToString(){
+ FlowEntry def = new FlowEntry();
+ assertEquals( def.toString(), "[ flowEntryActions=[] flowEntryUserState=FE_USER_UNKNOWN flowEntrySwitchState=FE_SWITCH_UNKNOWN]" );
+ assertEquals( entry.toString(), "[flowEntryId=0x5678 flowEntryMatch=[inPort=1 srcMac=01:02:03:04:05:06 dstMac=06:05:04:03:02:01 ethernetFrameType=2 vlanId=3 vlanPriority=4 srcIPv4Net=127.0.0.1/32 dstIPv4Net=127.0.0.2/32 ipProto=5 ipToS=6 srcTcpUdpPort=7 dstTcpUdpPort=8] flowEntryActions=[[type=ACTION_OUTPUT action=[port=9 maxLen=0]];[type=ACTION_OUTPUT action=[port=-3 maxLen=0]];[type=ACTION_SET_VLAN_VID action=[vlanId=3]];[type=ACTION_SET_VLAN_PCP action=[vlanPriority=4]];[type=ACTION_STRIP_VLAN action=[stripVlan=true]];[type=ACTION_SET_DL_SRC action=[addr=01:02:03:04:05:06]];[type=ACTION_SET_DL_DST action=[addr=06:05:04:03:02:01]];[type=ACTION_SET_NW_SRC action=[addr=127.0.0.3]];[type=ACTION_SET_NW_DST action=[addr=127.0.0.4]];[type=ACTION_SET_NW_TOS action=[ipToS=6]];[type=ACTION_SET_TP_SRC action=[port=7]];[type=ACTION_SET_TP_DST action=[port=8]];[type=ACTION_ENQUEUE action=[port=10 queueId=11]];] dpid=00:00:00:00:00:00:ca:fe inPort=1 outPort=9 flowEntryUserState=FE_USER_ADD flowEntrySwitchState=FE_SWITCH_UPDATED flowEntryErrorState=[type=12 code=13]]" );
+ }
+
+}
diff --git a/src/test/java/net/onrc/onos/ofcontroller/util/FlowPathTest.java b/src/test/java/net/onrc/onos/ofcontroller/util/FlowPathTest.java
new file mode 100644
index 0000000..89a12e5
--- /dev/null
+++ b/src/test/java/net/onrc/onos/ofcontroller/util/FlowPathTest.java
@@ -0,0 +1,182 @@
+package net.onrc.onos.ofcontroller.util;
+
+import static org.junit.Assert.*;
+import net.onrc.onos.ofcontroller.core.internal.TestableGraphDBOperation.TestFlowEntry;
+import net.onrc.onos.ofcontroller.core.internal.TestableGraphDBOperation.TestFlowPath;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class FlowPathTest {
+
+ FlowPath flowPath;
+
+ @Before
+ public void setUp() throws Exception{
+ TestFlowPath iFlowPath = new TestFlowPath();
+ iFlowPath.setFlowIdForTest("0x1234");
+ iFlowPath.setInstallerIdForTest("installerId");
+ iFlowPath.setFlowPathFlagsForTest(0L);
+ iFlowPath.setSrcSwForTest("CA:FE");
+ iFlowPath.setSrcPortForTest((short)1);
+ iFlowPath.setDstSwForTest("BA:BE");
+ iFlowPath.setDstPortForTest((short)2);
+
+ iFlowPath.setActionsForTest("[[type=ACTION_OUTPUT action=[port=10 maxLen=11]];[type=ACTION_OUTPUT action=[port=12 maxLen=13]];]");
+
+ TestFlowEntry iFlowEntry = new TestFlowEntry();
+ iFlowEntry.setEntryIdForTest("0x14");
+ iFlowEntry.setDpidForTest("BE:EF");
+ iFlowEntry.setActionsForTest("[[type=ACTION_OUTPUT action=[port=23 maxLen=24]];[type=ACTION_OUTPUT action=[port=25 maxLen=26]];]");
+ iFlowEntry.setUserStateForTest("FE_USER_MODIFY");
+ iFlowEntry.setSwitchStateForTest("FE_SWITCH_UPDATE_IN_PROGRESS");
+ iFlowPath.addFlowEntryForTest(iFlowEntry);
+
+ flowPath = new FlowPath(iFlowPath);
+ }
+
+ @Test
+ public void testFlowPath(){
+ FlowPath flowPath = new FlowPath();
+ assertFalse( flowPath.flowPathFlags().isDiscardFirstHopEntry() );
+ assertFalse( flowPath.flowPathFlags().isKeepOnlyFirstHopEntry() );
+ assertTrue( flowPath.flowEntryActions().isEmpty() );
+ }
+
+ @Test
+ public void testFlowPathIFlowPath(){
+ TestFlowPath iFlowPath = new TestFlowPath();
+ iFlowPath.setFlowIdForTest("0x1234");
+ iFlowPath.setInstallerIdForTest("installerId");
+ iFlowPath.setFlowPathFlagsForTest(0L);
+ iFlowPath.setSrcSwForTest("CA:FE");
+ iFlowPath.setSrcPortForTest((short)1);
+ iFlowPath.setDstSwForTest("BA:BE");
+ iFlowPath.setDstPortForTest((short)2);
+
+ iFlowPath.setMatchSrcMacForTest("01:02:03:04:05:06");
+ iFlowPath.setMatchDstMacForTest("06:05:04:03:02:01");
+ iFlowPath.setMatchEthernetFrameTypeForTest((short)3);
+ iFlowPath.setMatchVlanIdForTest((short)4);
+ iFlowPath.setMatchVlanPriorityForTest((byte)5);
+ iFlowPath.setMatchSrcIpaddrForTest("127.0.0.1/32");
+ iFlowPath.setMatchDstIpaddrForTest("127.0.0.2/32");
+ iFlowPath.setMatchIpProtoForTest((byte)6);
+ iFlowPath.setMatchIpToSForTest((byte)7);
+ iFlowPath.setMatchSrcTcpUdpPortForTest((short)8);
+ iFlowPath.setMatchDstTcpUdpPortForTest((short)9);
+
+ iFlowPath.setActionsForTest("[[type=ACTION_OUTPUT action=[port=10 maxLen=11]];[type=ACTION_OUTPUT action=[port=12 maxLen=13]];]");
+
+ TestFlowEntry iFlowEntry = new TestFlowEntry();
+ iFlowEntry.setEntryIdForTest("0x14");
+ iFlowEntry.setDpidForTest("BE:EF");
+ iFlowEntry.setMatchInPortForTest((short)15);
+ iFlowEntry.setMatchSrcMacForTest("11:22:33:44:55:66");
+ iFlowEntry.setMatchDstMacForTest("66:55:44:33:22:11");
+ iFlowEntry.setMatchEtherFrameTypeForTest((short)16);
+ iFlowEntry.setMatchVlanIdForTest((short)17);
+ iFlowEntry.setMatchVlanPriorityForTest((byte)18);
+ iFlowEntry.setMatchSrcIpaddrForTest("127.0.0.3/32");
+ iFlowEntry.setMatchDstIpaddrForTest("127.0.0.4/32");
+ iFlowEntry.setMatchIpProtoForTest((byte)19);
+ iFlowEntry.setMatchIpToSForTest((byte)20);
+ iFlowEntry.setMatchSrcTcpUdpPortForTest((short)21);
+ iFlowEntry.setMatchDstTcpUdpPortForTest((short)22);
+ iFlowEntry.setActionsForTest("[[type=ACTION_OUTPUT action=[port=23 maxLen=24]];[type=ACTION_OUTPUT action=[port=25 maxLen=26]];]");
+ iFlowEntry.setUserStateForTest("FE_USER_MODIFY");
+ iFlowEntry.setSwitchStateForTest("FE_SWITCH_UPDATE_IN_PROGRESS");
+ iFlowPath.addFlowEntryForTest(iFlowEntry);
+
+ FlowPath flowPath = new FlowPath(iFlowPath);
+ assertEquals(flowPath.flowId().value(), 0x1234);
+ assertEquals(flowPath.installerId().value(), "installerId");
+ assertEquals(flowPath.flowPathFlags().flags(), 0);
+ assertEquals(flowPath.dataPath().srcPort().dpid().value(), 0xCAFE);
+ assertEquals(flowPath.dataPath().srcPort().port().value(), 1);
+ assertEquals(flowPath.dataPath().dstPort().dpid().value(), 0xBABE);
+ assertEquals(flowPath.dataPath().dstPort().port().value(), 2);
+
+ assertEquals(flowPath.flowEntryMatch().srcMac().toString(), "01:02:03:04:05:06");
+ assertEquals(flowPath.flowEntryMatch().dstMac().toString(), "06:05:04:03:02:01");
+ assertEquals(flowPath.flowEntryMatch().ethernetFrameType().shortValue(), 3);
+ assertEquals(flowPath.flowEntryMatch().vlanId().shortValue(), 4);
+ assertEquals(flowPath.flowEntryMatch().vlanPriority().shortValue(), 5);
+ assertEquals(flowPath.flowEntryMatch().srcIPv4Net().address().toString(), "127.0.0.1");
+ assertEquals(flowPath.flowEntryMatch().srcIPv4Net().prefixLen() , 32);
+ assertEquals(flowPath.flowEntryMatch().dstIPv4Net().address().toString(), "127.0.0.2");
+ assertEquals(flowPath.flowEntryMatch().dstIPv4Net().prefixLen() , 32);
+ assertEquals(flowPath.flowEntryMatch().ipProto().byteValue(), 6);
+ assertEquals(flowPath.flowEntryMatch().ipToS().byteValue(), 7);
+ assertEquals(flowPath.flowEntryMatch().srcTcpUdpPort().shortValue(), 8);
+ assertEquals(flowPath.flowEntryMatch().dstTcpUdpPort().shortValue(), 9);
+
+ assertEquals(flowPath.flowEntryActions().toString(),"[[type=ACTION_OUTPUT action=[port=10 maxLen=11]];[type=ACTION_OUTPUT action=[port=12 maxLen=13]];]");
+
+ assertEquals(0x14, flowPath.dataPath().flowEntries().get(0).flowEntryId().value() );
+ assertEquals(0xBEEF, flowPath.dataPath().flowEntries().get(0).dpid().value() );
+ assertEquals(15, flowPath.dataPath().flowEntries().get(0).flowEntryMatch().inPort().value() );
+ assertEquals("11:22:33:44:55:66", flowPath.dataPath().flowEntries().get(0).flowEntryMatch().srcMac().toString());
+ assertEquals("66:55:44:33:22:11", flowPath.dataPath().flowEntries().get(0).flowEntryMatch().dstMac().toString());
+ assertEquals(16, flowPath.dataPath().flowEntries().get(0).flowEntryMatch().ethernetFrameType().shortValue());
+ assertEquals(17, flowPath.dataPath().flowEntries().get(0).flowEntryMatch().vlanId().shortValue());
+ assertEquals(18, flowPath.dataPath().flowEntries().get(0).flowEntryMatch().vlanPriority().byteValue());
+ assertEquals("127.0.0.3", flowPath.dataPath().flowEntries().get(0).flowEntryMatch().srcIPv4Net().address().toString());
+ assertEquals(32, flowPath.dataPath().flowEntries().get(0).flowEntryMatch().srcIPv4Net().prefixLen());
+ assertEquals("127.0.0.4", flowPath.dataPath().flowEntries().get(0).flowEntryMatch().dstIPv4Net().address().toString());
+ assertEquals(32, flowPath.dataPath().flowEntries().get(0).flowEntryMatch().dstIPv4Net().prefixLen());
+ assertEquals(19, flowPath.dataPath().flowEntries().get(0).flowEntryMatch().ipProto().byteValue());
+ assertEquals(20, flowPath.dataPath().flowEntries().get(0).flowEntryMatch().ipToS().byteValue());
+ assertEquals(21, flowPath.dataPath().flowEntries().get(0).flowEntryMatch().srcTcpUdpPort().shortValue());
+ assertEquals(22, flowPath.dataPath().flowEntries().get(0).flowEntryMatch().dstTcpUdpPort().shortValue());
+ assertEquals("[[type=ACTION_OUTPUT action=[port=23 maxLen=24]];[type=ACTION_OUTPUT action=[port=25 maxLen=26]];]", flowPath.dataPath().flowEntries().get(0).flowEntryActions().toString());
+ assertEquals("FE_USER_MODIFY", flowPath.dataPath().flowEntries().get(0).flowEntryUserState().toString());
+ assertEquals("FE_SWITCH_UPDATE_IN_PROGRESS", flowPath.dataPath().flowEntries().get(0).flowEntrySwitchState().toString());
+ }
+
+
+ @Test
+ public void testFlowPathFlags(){
+ FlowPath flowPath = new FlowPath();
+ FlowPathFlags flags = new FlowPathFlags();
+ flags.setFlags(0);
+ flowPath.setFlowPathFlags( flags );
+ assertFalse( flowPath.flowPathFlags().isDiscardFirstHopEntry() );
+ assertFalse( flowPath.flowPathFlags().isKeepOnlyFirstHopEntry() );
+ }
+
+ @Test
+ public void testSetFlowPathFlags(){
+ FlowPath flowPath = new FlowPath();
+ FlowPathFlags flags = new FlowPathFlags("DISCARD_FIRST_HOP_ENTRY");
+ flags.setFlagsStr("KEEP_ONLY_FIRST_HOP_ENTRY");
+ flowPath.setFlowPathFlags( flags );
+ assertFalse( flowPath.flowPathFlags().isDiscardFirstHopEntry() );
+ assertTrue( flowPath.flowPathFlags().isKeepOnlyFirstHopEntry() );
+ }
+
+ @Test
+ public void testSetDataPath(){
+ FlowPath flowPath = new FlowPath();
+ DataPath dataPath = new DataPath();
+ flowPath.setDataPath( dataPath );
+ assertEquals(flowPath.dataPath(), dataPath );
+ }
+
+ @Test
+ public void testToString(){
+
+ assertEquals("[flowId=0x1234 installerId=installerId flowPathFlags=[flags=] dataPath=[src=00:00:00:00:00:00:ca:fe/1 flowEntry=[flowEntryId=0x14 flowEntryMatch=[] flowEntryActions=[[type=ACTION_OUTPUT action=[port=23 maxLen=24]];[type=ACTION_OUTPUT action=[port=25 maxLen=26]];] dpid=00:00:00:00:00:00:be:ef flowEntryUserState=FE_USER_MODIFY flowEntrySwitchState=FE_SWITCH_UPDATE_IN_PROGRESS] dst=00:00:00:00:00:00:ba:be/2] flowEntryMatch=[] flowEntryActions=[[type=ACTION_OUTPUT action=[port=10 maxLen=11]];[type=ACTION_OUTPUT action=[port=12 maxLen=13]];]]", flowPath.toString());
+ }
+
+ @Test
+ public void testCompareTo(){
+ FlowPath flowPath1 = new FlowPath();
+ flowPath1.setFlowId( new FlowId(1));
+ FlowPath flowPath2 = new FlowPath();
+ flowPath2.setFlowId( new FlowId(2));
+
+ assertTrue( flowPath1.compareTo(flowPath2) < 0);
+ }
+
+}
diff --git a/start-onos-embedded.sh b/start-onos-embedded.sh
index b98510c..f607c8e 100755
--- a/start-onos-embedded.sh
+++ b/start-onos-embedded.sh
@@ -17,6 +17,7 @@
#JVM_OPTS="$JVM_OPTS -XX:+UseParallelGC -XX:+AggressiveOpts -XX:+UseFastAccessorMethods"
JVM_OPTS="$JVM_OPTS -XX:+UseConcMarkSweepGC -XX:+UseAdaptiveSizePolicy -XX:+AggressiveOpts -XX:+UseFastAccessorMethods"
JVM_OPTS="$JVM_OPTS -XX:MaxInlineSize=8192 -XX:FreqInlineSize=8192"
+JVM_OPTS="$JVM_OPTS -javaagent:lib/jamm-0.2.5.jar"
JVM_OPTS="$JVM_OPTS -XX:CompileThreshold=1500 -XX:PreBlockSpin=8 \
-XX:+UseThreadPriorities \
-XX:ThreadPriorityPolicy=42 \
diff --git a/start-onos.sh b/start-onos.sh
index 13ea0ac..14adfb0 100755
--- a/start-onos.sh
+++ b/start-onos.sh
@@ -16,6 +16,8 @@
# Set JVM options
JVM_OPTS=""
+## If you want JaCoCo Code Coverage reports... uncomment line below
+JVM_OPTS="$JVM_OPTS -javaagent:${ONOS_HOME}/lib/jacocoagent.jar=dumponexit=true,output=file,destfile=${LOGDIR}/jacoco.exec"
JVM_OPTS="$JVM_OPTS -server -d64"
#JVM_OPTS="$JVM_OPTS -Xmx2g -Xms2g -Xmn800m"
JVM_OPTS="$JVM_OPTS -Xmx1g -Xms1g -Xmn800m"
@@ -69,7 +71,8 @@
done
# Create a logback file if required
- cat <<EOF_LOGBACK >${ONOS_LOGBACK}
+ if [ ! -f ${ONOS_LOGBACK} ]; then
+ cat <<EOF_LOGBACK >${ONOS_LOGBACK}
<configuration scan="true" debug="true">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
@@ -93,6 +96,7 @@
</root>
</configuration>
EOF_LOGBACK
+ fi
# Run floodlight
echo "Starting ONOS controller ..."
@@ -134,7 +138,7 @@
pids="$flpid $tdpid"
for p in ${pids}; do
if [ x$p != "x" ]; then
- kill -KILL $p
+ kill -TERM $p
echo "Killed existing process (pid: $p)"
fi
done
diff --git a/test-network/mininet/dev_network_core_1.py b/test-network/mininet/dev_network_core_1.py
new file mode 100755
index 0000000..a0e184e
--- /dev/null
+++ b/test-network/mininet/dev_network_core_1.py
@@ -0,0 +1,157 @@
+#!/usr/bin/python
+
+"""
+Start up a Simple topology
+"""
+from mininet.net import Mininet
+from mininet.node import Controller, RemoteController
+from mininet.log import setLogLevel, info, error, warn, debug
+from mininet.cli import CLI
+from mininet.topo import Topo
+from mininet.util import quietRun
+from mininet.moduledeps import pathCheck
+from mininet.link import Link, TCLink
+
+from sys import exit
+import os.path
+from subprocess import Popen, STDOUT, PIPE
+
+import sys
+
+
+#import argparse
+
+class MyController( Controller ):
+ def __init__( self, name, ip='127.0.0.1', port=6633, **kwargs):
+ """Init.
+ name: name to give controller
+ ip: the IP address where the remote controller is
+ listening
+ port: the port where the remote controller is listening"""
+ Controller.__init__( self, name, ip=ip, port=port, **kwargs )
+
+ def start( self ):
+ "Overridden to do nothing."
+ return
+
+ def stop( self ):
+ "Overridden to do nothing."
+ return
+
+ def checkListening( self ):
+ "Warn if remote controller is not accessible"
+ listening = self.cmd( "echo A | telnet -e A %s %d" %
+ ( self.ip, self.port ) )
+ if 'Unable' in listening:
+ warn( "Unable to contact the remote controller"
+ " at %s:%d\n" % ( self.ip, self.port ) )
+
+class SDNTopo( Topo ):
+ "SDN Topology"
+
+ def __init__( self, *args, **kwargs ):
+ Topo.__init__( self, *args, **kwargs )
+ sw1 = self.addSwitch('sw1', dpid='0000000000000101')
+ sw2 = self.addSwitch('sw2', dpid='0000000000000102')
+ sw3 = self.addSwitch('sw3', dpid='0000000000000103')
+ sw4 = self.addSwitch('sw4', dpid='0000000000000104')
+ sw5 = self.addSwitch('sw5', dpid='0000000000000105')
+ sw6 = self.addSwitch('sw6', dpid='0000000000000106')
+
+ host1 = self.addHost( 'host1' )
+ host2 = self.addHost( 'host2' )
+ host3 = self.addHost( 'host3' )
+ host4 = self.addHost( 'host4' )
+ host5 = self.addHost( 'host5' )
+ host6 = self.addHost( 'host6' )
+
+ self.addLink( host1, sw1 )
+ self.addLink( host2, sw2 )
+ self.addLink( host3, sw3 )
+ self.addLink( host4, sw4 )
+ self.addLink( host5, sw5 )
+ self.addLink( host6, sw6 )
+
+ self.addLink( sw1, sw2 )
+ self.addLink( sw1, sw6 )
+ self.addLink( sw2, sw3 )
+ self.addLink( sw3, sw4 )
+ self.addLink( sw3, sw6 )
+ self.addLink( sw4, sw5 )
+ self.addLink( sw5, sw6 )
+ self.addLink( sw4, sw6 )
+
+def startsshd( host ):
+ "Start sshd on host"
+ info( '*** Starting sshd\n' )
+ name, intf, ip = host.name, host.defaultIntf(), host.IP()
+ banner = '/tmp/%s.banner' % name
+ host.cmd( 'echo "Welcome to %s at %s" > %s' % ( name, ip, banner ) )
+ host.cmd( '/usr/sbin/sshd -o "Banner %s"' % banner, '-o "UseDNS no"' )
+ info( '***', host.name, 'is running sshd on', intf, 'at', ip, '\n' )
+
+def startsshds ( hosts ):
+ for h in hosts:
+ startsshd( h )
+
+def stopsshd( ):
+ "Stop *all* sshd processes with a custom banner"
+ info( '*** Shutting down stale sshd/Banner processes ',
+ quietRun( "pkill -9 -f Banner" ), '\n' )
+
+def sdnnet(opt):
+# os.system('/home/ubuntu/openflow/controller/controller ptcp: &')
+# os.system('/home/ubuntu/openflow/controller/controller ptcp:7000 &')
+
+ topo = SDNTopo()
+ info( '*** Creating network\n' )
+# net = Mininet( topo=topo, controller=RemoteController )
+ net = Mininet( topo=topo, controller=MyController, link=TCLink)
+# dc = DebugController('c3', ip='127.0.0.1', port=7000)
+# net.addController(dc)
+# net.addController(controller=RemoteController)
+
+ host1, host2, host3, host4, host5, host6 = net.get( 'host1', 'host2', 'host3', 'host4', 'host5', 'host6')
+
+ ## Adding 2nd, 3rd and 4th interface to host1 connected to sw1 (for another BGP peering)
+ sw1 = net.get('sw1')
+ sw2 = net.get('sw2')
+ sw3 = net.get('sw3')
+ sw4 = net.get('sw4')
+ sw5 = net.get('sw5')
+ sw6 = net.get('sw6')
+
+ net.start()
+
+ sw2.attach('tap01_2')
+ sw3.attach('tap01_3')
+ sw4.attach('tap01_4')
+ sw4.attach('tap01_5')
+ sw5.attach('tap01_6')
+ sw6.attach('tap01_7')
+ sw1.attach('tap01_8')
+
+ host1.defaultIntf().setIP('192.168.100.141/16')
+ host2.defaultIntf().setIP('192.168.100.142/16')
+ host3.defaultIntf().setIP('192.168.100.143/16')
+ host4.defaultIntf().setIP('192.168.100.144/16')
+ host5.defaultIntf().setIP('192.168.100.145/16')
+ host6.defaultIntf().setIP('192.168.100.146/16')
+
+ hosts = [ host1, host2, host3, host4, host5, host6 ]
+ stopsshd ()
+ startsshds ( hosts )
+
+ if opt=="cli":
+ CLI(net)
+ stopsshd()
+ net.stop()
+
+if __name__ == '__main__':
+ setLogLevel( 'info' )
+ if len(sys.argv) == 1:
+ sdnnet("cli")
+ elif len(sys.argv) == 2 and sys.argv[1] == "-n":
+ sdnnet("nocli")
+ else:
+ print "%s [-n]" % sys.argv[0]
diff --git a/test-network/mininet/dev_network_edge_2.py b/test-network/mininet/dev_network_edge_2.py
index a9026c4..50dc00c 100755
--- a/test-network/mininet/dev_network_edge_2.py
+++ b/test-network/mininet/dev_network_edge_2.py
@@ -124,7 +124,7 @@
sw=net.get('sw%02x.%02x' % (NWID,1))
print "center sw", sw
sw.attach('tap%02x_1' % NWID)
- sw.attach('tap%02x_5' % NWID)
+ sw.attach('tap%02x_2' % NWID)
for i in range (NR_NODES):
host[i].defaultIntf().setIP('192.168.%d.%d/16' % (NWID,(int(i)+1)))
diff --git a/titan/schema/test-network.xml b/titan/schema/test-network.xml
index 630c5da..2c3b993 100644
--- a/titan/schema/test-network.xml
+++ b/titan/schema/test-network.xml
@@ -55,106 +55,126 @@
<node id="100">
<data key="type">port</data>
<data key="number">1</data>
+ <data key="state">ACTIVE</data>
<data key="desc">port 1 at SEA Switch</data>
</node>
<node id="101">
<data key="type">port</data>
<data key="number">2</data>
+ <data key="state">ACTIVE</data>
<data key="desc">port 2 at SEA Switch</data>
</node>
<node id="102">
<data key="type">port</data>
<data key="number">3</data>
+ <data key="state">ACTIVE</data>
<data key="desc">port 3 at SEA Switch</data>
</node>
<node id="103">
<data key="type">port</data>
<data key="number">4</data>
+ <data key="state">ACTIVE</data>
<data key="desc">port 4 at SEA Switch</data>
</node>
<node id="104">
<data key="type">port</data>
<data key="number">1</data>
+ <data key="state">ACTIVE</data>
<data key="desc">port 1 at LAX Switch</data>
</node>
<node id="105">
<data key="type">port</data>
<data key="number">2</data>
+ <data key="state">ACTIVE</data>
<data key="desc">port 2 at LAX Switch</data>
</node>
<node id="106">
<data key="type">port</data>
<data key="number">3</data>
+ <data key="state">ACTIVE</data>
<data key="desc">port 3 at LAX Switch</data>
</node>
<node id="107">
<data key="type">port</data>
<data key="number">1</data>
+ <data key="state">ACTIVE</data>
<data key="desc">port 1 at CHI Switch</data>
</node>
<node id="108">
<data key="type">port</data>
<data key="number">2</data>
+ <data key="state">ACTIVE</data>
<data key="desc">port 2 at CHI Switch</data>
</node>
<node id="109">
<data key="type">port</data>
<data key="number">3</data>
+ <data key="state">ACTIVE</data>
<data key="desc">port 3 at CHI Switch</data>
</node>
<node id="110">
<data key="type">port</data>
<data key="number">4</data>
+ <data key="state">ACTIVE</data>
<data key="desc">port 4 at CHI Switch</data>
</node>
<node id="111">
<data key="type">port</data>
<data key="number">1</data>
+ <data key="state">ACTIVE</data>
<data key="desc">port 1 at IAH Switch</data>
</node>
<node id="112">
<data key="type">port</data>
<data key="number">2</data>
+ <data key="state">ACTIVE</data>
<data key="desc">port 2 at IAH Switch</data>
</node>
<node id="113">
<data key="type">port</data>
<data key="number">3</data>
+ <data key="state">ACTIVE</data>
<data key="desc">port 3 at IAH Switch</data>
</node>
<node id="114">
<data key="type">port</data>
<data key="number">1</data>
+ <data key="state">ACTIVE</data>
<data key="desc">port 1 at NYC Switch</data>
</node>
<node id="115">
<data key="type">port</data>
<data key="number">2</data>
+ <data key="state">ACTIVE</data>
<data key="desc">port 2 at NYC Switch</data>
</node>
<node id="116">
<data key="type">port</data>
<data key="number">3</data>
+ <data key="state">ACTIVE</data>
<data key="desc">port 3 at NYC Switch</data>
</node>
<node id="117">
<data key="type">port</data>
<data key="number">1</data>
+ <data key="state">ACTIVE</data>
<data key="desc">port 1 at ATL Switch</data>
</node>
<node id="118">
<data key="type">port</data>
<data key="number">2</data>
+ <data key="state">ACTIVE</data>
<data key="desc">port 2 at ATL Switch</data>
</node>
<node id="119">
<data key="type">port</data>
<data key="number">3</data>
+ <data key="state">ACTIVE</data>
<data key="desc">port 3 at ATL Switch</data>
</node>
diff --git a/web/add_flow.py b/web/add_flow.py
index ec84744..8100f22 100755
--- a/web/add_flow.py
+++ b/web/add_flow.py
@@ -129,8 +129,9 @@
my_dst_port = my_args[5]
#
- # Extract the "match" and "action" arguments
+ # Extract the "flowPathFlags", "match" and "action" arguments
#
+ flowPathFlags = 0L
match = {}
matchInPortEnabled = True # NOTE: Enabled by default
actions = []
@@ -149,7 +150,12 @@
arg2 = my_args[idx]
idx = idx + 1
- if arg1 == "matchInPort":
+ if arg1 == "flowPathFlags":
+ if "DISCARD_FIRST_HOP_ENTRY" in arg2:
+ flowPathFlags = flowPathFlags + 0x1
+ if "KEEP_ONLY_FIRST_HOP_ENTRY" in arg2:
+ flowPathFlags = flowPathFlags + 0x2
+ elif arg1 == "matchInPort":
# Just mark whether inPort matching is enabled
matchInPortEnabled = arg2 in ['True', 'true']
# inPort = {}
@@ -198,18 +204,19 @@
match['dstTcpUdpPort'] = int(arg2, 0)
# match['matchDstTcpUdpPort'] = True
elif arg1 == "actionOutput":
- # Just mark whether ACTION_OUTPUT action is enabled
+ # Mark whether ACTION_OUTPUT action is enabled
actionOutputEnabled = arg2 in ['True', 'true']
- #
- # TODO: Complete the implementation for ACTION_OUTPUT
- # actionOutput = {}
- # outPort = {}
- # outPort['value'] = int(arg2, 0)
- # actionOutput['port'] = outPort
- # actionOutput['maxLen'] = int(arg3, 0)
- # action['actionOutput'] = actionOutput
- # # action['actionType'] = 'ACTION_OUTPUT'
- # actions.append(action)
+ # If ACTION_OUTPUT is explicitly enabled, add an entry with a fake
+ # port number. We need this entry to preserve the action ordering.
+ if actionOutputEnabled == True:
+ actionOutput = {}
+ outPort = {}
+ outPort['value'] = 0xffff
+ actionOutput['port'] = outPort
+ actionOutput['maxLen'] = 0
+ action['actionOutput'] = actionOutput
+ # action['actionType'] = 'ACTION_OUTPUT'
+ actions.append(action)
#
elif arg1 == "actionSetVlanId":
vlanId = {}
@@ -302,6 +309,7 @@
'my_src_port' : my_src_port,
'my_dst_dpid' : my_dst_dpid,
'my_dst_port' : my_dst_port,
+ 'flowPathFlags' : flowPathFlags,
'match' : match,
'matchInPortEnabled' : matchInPortEnabled,
'actions' : actions,
@@ -325,6 +333,7 @@
my_flow_id = parsed_args['my_flow_id']
my_installer_id = parsed_args['my_installer_id']
+ myFlowPathFlags = parsed_args['flowPathFlags']
match = parsed_args['match']
matchInPortEnabled = parsed_args['matchInPortEnabled']
actions = parsed_args['actions']
@@ -335,10 +344,15 @@
flow_id['value'] = my_flow_id
installer_id = {}
installer_id['value'] = my_installer_id
+ flowPathFlags = {}
+ flowPathFlags['flags'] = myFlowPathFlags
+
+ flowEntryActions = {}
flow_path = {}
flow_path['flowId'] = flow_id
flow_path['installerId'] = installer_id
+ flow_path['flowPathFlags'] = flowPathFlags
if (len(match) > 0):
flow_path['flowEntryMatch'] = copy.deepcopy(match)
@@ -356,6 +370,11 @@
my_data_path['flowEntries'][idx]['flowEntryMatch'] = copy.deepcopy(match)
idx = idx + 1
+
+ if (len(actions) > 0):
+ flowEntryActions['actions'] = copy.deepcopy(actions)
+ flow_path['flowEntryActions'] = flowEntryActions
+
#
# Set the actions for each flow entry
# NOTE: The actions from the command line are aplied
@@ -377,11 +396,12 @@
action['actionOutput'] = copy.deepcopy(actionOutput)
# action['actionType'] = 'ACTION_OUTPUT'
actions.append(copy.deepcopy(action))
+ flowEntryActions = {}
+ flowEntryActions['actions'] = copy.deepcopy(actions)
- my_data_path['flowEntries'][idx]['flowEntryActions'] = copy.deepcopy(actions)
+ my_data_path['flowEntries'][idx]['flowEntryActions'] = flowEntryActions
idx = idx + 1
-
flow_path['dataPath'] = my_data_path
debug("Flow Path: %s" % flow_path)
return flow_path
@@ -461,7 +481,7 @@
if __name__ == "__main__":
- usage_msg = "Usage: %s [Flags] <flow-id> <installer-id> <src-dpid> <src-port> <dest-dpid> <dest-port> [Match Conditions] [Actions]\n" % (sys.argv[0])
+ usage_msg = "Usage: %s [Flags] <flow-id> <installer-id> <src-dpid> <src-port> <dest-dpid> <dest-port> [Flow Path Flags] [Match Conditions] [Actions]\n" % (sys.argv[0])
usage_msg = usage_msg + "\n"
usage_msg = usage_msg + " Flags:\n"
usage_msg = usage_msg + " -m [monitorname] Monitor and maintain the installed shortest path(s)\n"
@@ -472,6 +492,13 @@
usage_msg = usage_msg + " -f <filename> Read the flow(s) to install from a file\n"
usage_msg = usage_msg + " File format: one line per flow starting with <flow-id>\n"
usage_msg = usage_msg + "\n"
+ usage_msg = usage_msg + " Flow Path Flags:\n"
+ usage_msg = usage_msg + " flowPathFlags <Flags> (flag names separated by ',')\n"
+ usage_msg = usage_msg + "\n"
+ usage_msg = usage_msg + " Known flags:\n"
+ usage_msg = usage_msg + " DISCARD_FIRST_HOP_ENTRY : Discard the first-hop flow entry\n"
+ usage_msg = usage_msg + " KEEP_ONLY_FIRST_HOP_ENTRY : Keep only the first-hop flow entry\n"
+ usage_msg = usage_msg + "\n"
usage_msg = usage_msg + " Match Conditions:\n"
usage_msg = usage_msg + " matchInPort <True|False> (default to True)\n"
usage_msg = usage_msg + " matchSrcMac <source MAC address>\n"
@@ -488,18 +515,17 @@
usage_msg = usage_msg + "\n"
usage_msg = usage_msg + " Actions:\n"
usage_msg = usage_msg + " actionOutput <True|False> (default to True)\n"
+ usage_msg = usage_msg + " actionSetVlanId <VLAN ID>\n"
+ usage_msg = usage_msg + " actionSetVlanPriority <VLAN priority>\n"
+ usage_msg = usage_msg + " actionStripVlan <True|False>\n"
usage_msg = usage_msg + " actionSetEthernetSrcAddr <source MAC address>\n"
usage_msg = usage_msg + " actionSetEthernetDstAddr <destination MAC address>\n"
usage_msg = usage_msg + " actionSetIPv4SrcAddr <source IPv4 address>\n"
usage_msg = usage_msg + " actionSetIPv4DstAddr <destination IPv4 address>\n"
- usage_msg = usage_msg + "\n"
- usage_msg = usage_msg + " Actions (not implemented yet):\n"
- usage_msg = usage_msg + " actionSetVlanId <VLAN ID>\n"
- usage_msg = usage_msg + " actionSetVlanPriority <VLAN priority>\n"
usage_msg = usage_msg + " actionSetIpToS <IP ToS (DSCP field, 6 bits)>\n"
usage_msg = usage_msg + " actionSetTcpUdpSrcPort <source TCP/UDP port>\n"
usage_msg = usage_msg + " actionSetTcpUdpDstPort <destination TCP/UDP port>\n"
- usage_msg = usage_msg + " actionStripVlan <True|False>\n"
+ usage_msg = usage_msg + " Actions (not implemented yet):\n"
usage_msg = usage_msg + " actionEnqueue <dummy argument>\n"
# app.debug = False;
diff --git a/web/get_flow.py b/web/get_flow.py
index 9e954fe..9ab55da 100755
--- a/web/get_flow.py
+++ b/web/get_flow.py
@@ -33,78 +33,182 @@
# Sample output:
# {"flowId":{"value":"0x5"},"installerId":{"value":"FOOBAR"},"dataPath":{"srcPort":{"dpid":{"value":"00:00:00:00:00:00:00:01"},"port":{"value":0}},"dstPort":{"dpid":{"value":"00:00:00:00:00:00:00:02"},"port":{"value":0}},"flowEntries":[{"flowEntryId":"0x1389","flowEntryMatch":null,"flowEntryActions":null,"dpid":{"value":"00:00:00:00:00:00:00:01"},"inPort":{"value":0},"outPort":{"value":1},"flowEntryUserState":"FE_USER_DELETE","flowEntrySwitchState":"FE_SWITCH_NOT_UPDATED","flowEntryErrorState":null},{"flowEntryId":"0x138a","flowEntryMatch":null,"flowEntryActions":null,"dpid":{"value":"00:00:00:00:00:00:00:02"},"inPort":{"value":9},"outPort":{"value":0},"flowEntryUserState":"FE_USER_DELETE","flowEntrySwitchState":"FE_SWITCH_NOT_UPDATED","flowEntryErrorState":null}]}}
+def parse_match(match):
+ result = []
+
+ inPort = match['inPort']
+ matchInPort = match['matchInPort']
+ srcMac = match['srcMac']
+ matchSrcMac = match['matchSrcMac']
+ dstMac = match['dstMac']
+ matchDstMac = match['matchDstMac']
+ ethernetFrameType = match['ethernetFrameType']
+ matchEthernetFrameType = match['matchEthernetFrameType']
+ vlanId = match['vlanId']
+ matchVlanId = match['matchVlanId']
+ vlanPriority = match['vlanPriority']
+ matchVlanPriority = match['matchVlanPriority']
+ srcIPv4Net = match['srcIPv4Net']
+ matchSrcIPv4Net = match['matchSrcIPv4Net']
+ dstIPv4Net = match['dstIPv4Net']
+ matchDstIPv4Net = match['matchDstIPv4Net']
+ ipProto = match['ipProto']
+ matchIpProto = match['matchIpProto']
+ ipToS = match['ipToS']
+ matchIpToS = match['matchIpToS']
+ srcTcpUdpPort = match['srcTcpUdpPort']
+ matchSrcTcpUdpPort = match['matchSrcTcpUdpPort']
+ dstTcpUdpPort = match['dstTcpUdpPort']
+ matchDstTcpUdpPort = match['matchDstTcpUdpPort']
+ if matchInPort == True:
+ r = "inPort: %s" % inPort['value']
+ result.append(r)
+ if matchSrcMac == True:
+ r = "srcMac: %s" % srcMac['value']
+ result.append(r)
+ if matchDstMac == True:
+ r = "dstMac: %s" % dstMac['value']
+ result.append(r)
+ if matchEthernetFrameType == True:
+ r = "ethernetFrameType: %s" % hex(ethernetFrameType)
+ result.append(r)
+ if matchVlanId == True:
+ r = "vlanId: %s" % vlanId
+ result.append(r)
+ if matchVlanPriority == True:
+ r = "vlanPriority: %s" % vlanPriority
+ result.append(r)
+ if matchSrcIPv4Net == True:
+ r = "srcIPv4Net: %s" % srcIPv4Net['value']
+ result.append(r)
+ if matchDstIPv4Net == True:
+ r = "dstIPv4Net: %s" % dstIPv4Net['value']
+ result.append(r)
+ if matchIpProto == True:
+ r = "ipProto: %s" % ipProto
+ result.append(r)
+ if matchIpToS == True:
+ r = "ipToS: %s" % ipToS
+ result.append(r)
+ if matchSrcTcpUdpPort == True:
+ r = "srcTcpUdpPort: %s" % srcTcpUdpPort
+ result.append(r)
+ if matchDstTcpUdpPort == True:
+ r = "dstTcpUdpPort: %s" % dstTcpUdpPort
+ result.append(r)
+
+ return result
+
+
+def parse_actions(actions):
+ result = []
+ for a in actions:
+ actionType = a['actionType']
+ if actionType == "ACTION_OUTPUT":
+ port = a['actionOutput']['port']['value']
+ maxLen = a['actionOutput']['maxLen']
+ r = "actionType: %s port: %s maxLen: %s" % (actionType, port, maxLen)
+ result.append(r)
+ if actionType == "ACTION_SET_VLAN_VID":
+ vlanId = a['actionSetVlanId']['vlanId']
+ r = "actionType: %s vlanId: %s" % (actionType, vlanId)
+ result.append(r)
+ if actionType == "ACTION_SET_VLAN_PCP":
+ vlanPriority = a['actionSetVlanPriority']['vlanPriority']
+ r = "actionType: %s vlanPriority: %s" % (actionType, vlanPriority)
+ result.append(r)
+ if actionType == "ACTION_STRIP_VLAN":
+ stripVlan = a['actionStripVlan']['stripVlan']
+ r = "actionType: %s stripVlan: %s" % (actionType, stripVlan)
+ result.append(r)
+ if actionType == "ACTION_SET_DL_SRC":
+ setEthernetSrcAddr = a['actionSetEthernetSrcAddr']['addr']['value']
+ r = "actionType: %s setEthernetSrcAddr: %s" % (actionType, setEthernetSrcAddr)
+ result.append(r)
+ if actionType == "ACTION_SET_DL_DST":
+ setEthernetDstAddr = a['actionSetEthernetDstAddr']['addr']['value']
+ r = "actionType: %s setEthernetDstAddr: %s" % (actionType, setEthernetDstAddr)
+ result.append(r)
+ if actionType == "ACTION_SET_NW_SRC":
+ setIPv4SrcAddr = a['actionSetIPv4SrcAddr']['addr']['value']
+ r = "actionType: %s setIPv4SrcAddr: %s" % (actionType, setIPv4SrcAddr)
+ result.append(r)
+ if actionType == "ACTION_SET_NW_DST":
+ setIPv4DstAddr = a['actionSetIPv4DstAddr']['addr']['value']
+ r = "actionType: %s setIPv4DstAddr: %s" % (actionType, setIPv4DstAddr)
+ result.append(r)
+ if actionType == "ACTION_SET_NW_TOS":
+ setIpToS = a['actionSetIpToS']['ipToS']
+ r = "actionType: %s setIpToS: %s" % (actionType, setIpToS)
+ result.append(r)
+ if actionType == "ACTION_SET_TP_SRC":
+ setTcpUdpSrcPort = a['actionSetTcpUdpSrcPort']['port']
+ r = "actionType: %s setTcpUdpSrcPort: %s" % (actionType, setTcpUdpSrcPort)
+ result.append(r)
+ if actionType == "ACTION_SET_TP_DST":
+ setTcpUdpDstPort = a['actionSetTcpUdpDstPort']['port']
+ r = "actionType: %s setTcpUdpDstPort: %s" % (actionType, setTcpUdpDstPort)
+ result.append(r)
+ if actionType == "ACTION_ENQUEUE":
+ port = a['actionEnqueue']['port']['value']
+ queueId = a['actionEnqueue']['queueId']
+ r = "actionType: %s port: %s queueId: %s" % (actionType, port, queueId)
+ result.append(r)
+
+ return result
+
+
def print_flow_path(parsedResult):
flowId = parsedResult['flowId']['value']
installerId = parsedResult['installerId']['value']
+ flowPathFlags = parsedResult['flowPathFlags']['flags']
srcSwitch = parsedResult['dataPath']['srcPort']['dpid']['value']
srcPort = parsedResult['dataPath']['srcPort']['port']['value']
dstSwitch = parsedResult['dataPath']['dstPort']['dpid']['value']
dstPort = parsedResult['dataPath']['dstPort']['port']['value']
-
- print "FlowPath: (flowId = %s installerId = %s src = %s/%s dst = %s/%s)" % (flowId, installerId, srcSwitch, srcPort, dstSwitch, dstPort)
match = parsedResult['flowEntryMatch'];
+ actions = parsedResult['flowEntryActions']['actions']
+
+ flowPathFlagsStr = ""
+ if (flowPathFlags & 0x1):
+ if flowPathFlagsStr:
+ flowPathFlagsStr += ","
+ flowPathFlagsStr += "DISCARD_FIRST_HOP_ENTRY"
+ if (flowPathFlags & 0x2):
+ if flowPathFlagsStr:
+ flowPathFlagsStr += ","
+ flowPathFlagsStr += "KEEP_ONLY_FIRST_HOP_ENTRY"
+
+ print "FlowPath: (flowId = %s installerId = %s flowPathFlags = 0x%x(%s) src = %s/%s dst = %s/%s)" % (flowId, installerId, flowPathFlags, flowPathFlagsStr, srcSwitch, srcPort, dstSwitch, dstPort)
+
#
- # Print the common conditions
+ # Print the common match conditions
#
if match == None:
print " Match: %s" % (match)
else:
- # inPort = match['inPort']
- # matchInPort = match['matchInPort']
- srcMac = match['srcMac']
- matchSrcMac = match['matchSrcMac']
- dstMac = match['dstMac']
- matchDstMac = match['matchDstMac']
- ethernetFrameType = match['ethernetFrameType']
- matchEthernetFrameType = match['matchEthernetFrameType']
- vlanId = match['vlanId']
- matchVlanId = match['matchVlanId']
- vlanPriority = match['vlanPriority']
- matchVlanPriority = match['matchVlanPriority']
- srcIPv4Net = match['srcIPv4Net']
- matchSrcIPv4Net = match['matchSrcIPv4Net']
- dstIPv4Net = match['dstIPv4Net']
- matchDstIPv4Net = match['matchDstIPv4Net']
- ipProto = match['ipProto']
- matchIpProto = match['matchIpProto']
- ipToS = match['ipToS']
- matchIpToS = match['matchIpToS']
- srcTcpUdpPort = match['srcTcpUdpPort']
- matchSrcTcpUdpPort = match['matchSrcTcpUdpPort']
- dstTcpUdpPort = match['dstTcpUdpPort']
- matchDstTcpUdpPort = match['matchDstTcpUdpPort']
- # if matchInPort == True:
- # print " inPort: %s" % inPort['value']
- if matchSrcMac == True:
- print " srcMac: %s" % srcMac['value']
- if matchDstMac == True:
- print " dstMac: %s" % dstMac['value']
- if matchEthernetFrameType == True:
- print " ethernetFrameType: %s" % hex(ethernetFrameType)
- if matchVlanId == True:
- print " vlanId: %s" % vlanId
- if matchVlanPriority == True:
- print " vlanPriority: %s" % vlanPriority
- if matchSrcIPv4Net == True:
- print " srcIPv4Net: %s" % srcIPv4Net['value']
- if matchDstIPv4Net == True:
- print " dstIPv4Net: %s" % dstIPv4Net['value']
- if matchIpProto == True:
- print " ipProto: %s" % ipProto
- if matchIpToS == True:
- print " ipToS: %s" % ipToS
- if matchSrcTcpUdpPort == True:
- print " srcTcpUdpPort: %s" % srcTcpUdpPort
- if matchDstTcpUdpPort == True:
- print " dstTcpUdpPort: %s" % dstTcpUdpPort
+ parsedMatch = parse_match(match)
+ for l in parsedMatch:
+ print " %s" % l
+ #
+ # Print the actions
+ #
+ parsedActions = parse_actions(actions)
+ for l in parsedActions:
+ print " %s" % l
+
+ #
+ # Print each Flow Entry
+ #
for f in parsedResult['dataPath']['flowEntries']:
flowEntryId = f['flowEntryId']
dpid = f['dpid']['value']
userState = f['flowEntryUserState']
switchState = f['flowEntrySwitchState']
match = f['flowEntryMatch'];
- actions = f['flowEntryActions']
+ actions = f['flowEntryActions']['actions']
+
print " FlowEntry: (%s, %s, %s, %s)" % (flowEntryId, dpid, userState, switchState)
#
@@ -113,101 +217,16 @@
if match == None:
print " Match: %s" % (match)
else:
- inPort = match['inPort']
- matchInPort = match['matchInPort']
- srcMac = match['srcMac']
- matchSrcMac = match['matchSrcMac']
- dstMac = match['dstMac']
- matchDstMac = match['matchDstMac']
- ethernetFrameType = match['ethernetFrameType']
- matchEthernetFrameType = match['matchEthernetFrameType']
- vlanId = match['vlanId']
- matchVlanId = match['matchVlanId']
- vlanPriority = match['vlanPriority']
- matchVlanPriority = match['matchVlanPriority']
- srcIPv4Net = match['srcIPv4Net']
- matchSrcIPv4Net = match['matchSrcIPv4Net']
- dstIPv4Net = match['dstIPv4Net']
- matchDstIPv4Net = match['matchDstIPv4Net']
- ipProto = match['ipProto']
- matchIpProto = match['matchIpProto']
- ipToS = match['ipToS']
- matchIpToS = match['matchIpToS']
- srcTcpUdpPort = match['srcTcpUdpPort']
- matchSrcTcpUdpPort = match['matchSrcTcpUdpPort']
- dstTcpUdpPort = match['dstTcpUdpPort']
- matchDstTcpUdpPort = match['matchDstTcpUdpPort']
- if matchInPort == True:
- print " inPort: %s" % inPort['value']
- if matchSrcMac == True:
- print " srcMac: %s" % srcMac['value']
- if matchDstMac == True:
- print " dstMac: %s" % dstMac['value']
- if matchEthernetFrameType == True:
- print " ethernetFrameType: %s" % hex(ethernetFrameType)
- if matchVlanId == True:
- print " vlanId: %s" % vlanId
- if matchVlanPriority == True:
- print " vlanPriority: %s" % vlanPriority
- if matchSrcIPv4Net == True:
- print " srcIPv4Net: %s" % srcIPv4Net['value']
- if matchDstIPv4Net == True:
- print " dstIPv4Net: %s" % dstIPv4Net['value']
- if matchIpProto == True:
- print " ipProto: %s" % ipProto
- if matchIpToS == True:
- print " ipToS: %s" % ipToS
- if matchSrcTcpUdpPort == True:
- print " srcTcpUdpPort: %s" % srcTcpUdpPort
- if matchDstTcpUdpPort == True:
- print " dstTcpUdpPort: %s" % dstTcpUdpPort
-
+ parsedMatch = parse_match(match)
+ for l in parsedMatch:
+ print " %s" % l
#
# Print the actions
#
- if actions == None:
- print " Actions: %s" % (actions)
- else:
- for a in actions:
- actionType = a['actionType']
- if actionType == "ACTION_OUTPUT":
- port = a['actionOutput']['port']['value']
- maxLen = a['actionOutput']['maxLen']
- print " actionType: %s port: %s maxLen: %s" % (actionType, port, maxLen)
- if actionType == "ACTION_SET_VLAN_VID":
- vlanId = a['actionSetVlanId']['vlanId']
- print " actionType: %s vlanId: %s" % (actionType, vlanId)
- if actionType == "ACTION_SET_VLAN_PCP":
- vlanPriority = a['actionSetVlanPriority']['vlanPriority']
- print " actionType: %s vlanPriority: %s" % (actionType, vlanPriority)
- if actionType == "ACTION_STRIP_VLAN":
- stripVlan = a['actionStripVlan']['stripVlan']
- print " actionType: %s stripVlan: %s" % (actionType, stripVlan)
- if actionType == "ACTION_SET_DL_SRC":
- setEthernetSrcAddr = a['actionSetEthernetSrcAddr']['addr']['value']
- print " actionType: %s setEthernetSrcAddr: %s" % (actionType, setEthernetSrcAddr)
- if actionType == "ACTION_SET_DL_DST":
- setEthernetDstAddr = a['actionSetEthernetDstAddr']['addr']['value']
- print " actionType: %s setEthernetDstAddr: %s" % (actionType, setEthernetDstAddr)
- if actionType == "ACTION_SET_NW_SRC":
- setIPv4SrcAddr = a['actionSetIPv4SrcAddr']['addr']['value']
- print " actionType: %s setIPv4SrcAddr: %s" % (actionType, setIPv4SrcAddr)
- if actionType == "ACTION_SET_NW_DST":
- setIPv4DstAddr = a['actionSetIPv4DstAddr']['addr']['value']
- print " actionType: %s setIPv4DstAddr: %s" % (actionType, setIPv4DstAddr)
- if actionType == "ACTION_SET_NW_TOS":
- setIpToS = a['actionSetIpToS']['ipToS']
- print " actionType: %s setIpToS: %s" % (actionType, setIpToS)
- if actionType == "ACTION_SET_TP_SRC":
- setTcpUdpSrcPort = a['actionSetTcpUdpSrcPort']['port']
- print " actionType: %s setTcpUdpSrcPort: %s" % (actionType, setTcpUdpSrcPort)
- if actionType == "ACTION_SET_TP_DST":
- setTcpUdpDstPort = a['actionSetTcpUdpDstPort']['port']
- print " actionType: %s setTcpUdpDstPort: %s" % (actionType, setTcpUdpDstPort)
- if actionType == "ACTION_ENQUEUE":
- port = a['actionEnqueue']['port']['value']
- queueId = a['actionEnqueue']['queueId']
- print " actionType: %s port: %s queueId: %s" % (actionType, port, queueId)
+ parsedActions = parse_actions(actions)
+ for l in parsedActions:
+ print " %s" % l
+
def get_flow_path(flow_id):
try:
diff --git a/web/measurement_clear_all_paths.py b/web/measurement_clear_all_paths.py
deleted file mode 100755
index 5bb73c5..0000000
--- a/web/measurement_clear_all_paths.py
+++ /dev/null
@@ -1,61 +0,0 @@
-#! /usr/bin/env python
-# -*- Mode: python; py-indent-offset: 4; tab-width: 8; indent-tabs-mode: t; -*-
-
-import pprint
-import os
-import sys
-import subprocess
-import json
-import argparse
-import io
-import time
-
-from flask import Flask, json, Response, render_template, make_response, request
-
-#
-# TODO: remove this! We don't use JSON argument here!
-# curl http://127.0.0.1:8080/wm/flow/delete/{"value":"0xf"}/json'
-#
-
-## Global Var ##
-ControllerIP="127.0.0.1"
-ControllerPort=8080
-
-DEBUG=0
-pp = pprint.PrettyPrinter(indent=4)
-
-app = Flask(__name__)
-
-## Worker Functions ##
-def log_error(txt):
- print '%s' % (txt)
-
-def debug(txt):
- if DEBUG:
- print '%s' % (txt)
-
-# @app.route("/wm/flow/measurement-clear-all-paths/json")
-def measurement_clear_all_paths():
- command = "curl -s \"http://%s:%s/wm/flow/measurement-clear-all-paths/json\"" % (ControllerIP, ControllerPort)
- debug("measurement_clear_all_paths %s" % command)
- result = os.popen(command).read()
- debug("result %s" % result)
- # parsedResult = json.loads(result)
- # debug("parsed %s" % parsedResult)
-
-if __name__ == "__main__":
- usage_msg = "Clear the paths that have been stored for measurement purpose\n"
- usage_msg = usage_msg + "Usage: %s\n" % (sys.argv[0])
- usage_msg = usage_msg + "\n"
-
- # app.debug = False;
-
- # Usage info
- if len(sys.argv) > 1 and (sys.argv[1] == "-h" or sys.argv[1] == "--help"):
- print(usage_msg)
- exit(0)
-
- # Check arguments
-
- # Do the work
- measurement_clear_all_paths()
diff --git a/web/measurement_get_install_paths_time_nsec.py b/web/measurement_get_install_paths_time_nsec.py
deleted file mode 100755
index d64dc49..0000000
--- a/web/measurement_get_install_paths_time_nsec.py
+++ /dev/null
@@ -1,61 +0,0 @@
-#! /usr/bin/env python
-# -*- Mode: python; py-indent-offset: 4; tab-width: 8; indent-tabs-mode: t; -*-
-
-import pprint
-import os
-import sys
-import subprocess
-import json
-import argparse
-import io
-import time
-
-from flask import Flask, json, Response, render_template, make_response, request
-
-#
-# TODO: remove this! We don't use JSON argument here!
-# curl http://127.0.0.1:8080/wm/flow/delete/{"value":"0xf"}/json'
-#
-
-## Global Var ##
-ControllerIP="127.0.0.1"
-ControllerPort=8080
-
-DEBUG=0
-pp = pprint.PrettyPrinter(indent=4)
-
-app = Flask(__name__)
-
-## Worker Functions ##
-def log_error(txt):
- print '%s' % (txt)
-
-def debug(txt):
- if DEBUG:
- print '%s' % (txt)
-
-# @app.route("/wm/flow/measurement-get-install-paths-time-nsec/json")
-def measurement_get_install_paths_time_nsec():
- command = "curl -s \"http://%s:%s/wm/flow/measurement-get-install-paths-time-nsec/json\"" % (ControllerIP, ControllerPort)
- debug("measurement_get_install_paths_time_nsec %s" % command)
- result = os.popen(command).read()
- print '%s nsec' % (result)
- # parsedResult = json.loads(result)
- # debug("parsed %s" % parsedResult)
-
-if __name__ == "__main__":
- usage_msg = "Get the measured time to install the stored flow paths\n"
- usage_msg = usage_msg + "Usage: %s\n" % (sys.argv[0])
- usage_msg = usage_msg + "\n"
-
- # app.debug = False;
-
- # Usage info
- if len(sys.argv) > 1 and (sys.argv[1] == "-h" or sys.argv[1] == "--help"):
- print(usage_msg)
- exit(0)
-
- # Check arguments
-
- # Do the work
- measurement_get_install_paths_time_nsec()
diff --git a/web/measurement_get_per_flow_install_time.py b/web/measurement_get_per_flow_install_time.py
deleted file mode 100755
index bf2bcc7..0000000
--- a/web/measurement_get_per_flow_install_time.py
+++ /dev/null
@@ -1,61 +0,0 @@
-#! /usr/bin/env python
-# -*- Mode: python; py-indent-offset: 4; tab-width: 8; indent-tabs-mode: t; -*-
-
-import pprint
-import os
-import sys
-import subprocess
-import json
-import argparse
-import io
-import time
-
-from flask import Flask, json, Response, render_template, make_response, request
-
-#
-# TODO: remove this! We don't use JSON argument here!
-# curl http://127.0.0.1:8080/wm/flow/delete/{"value":"0xf"}/json'
-#
-
-## Global Var ##
-ControllerIP="127.0.0.1"
-ControllerPort=8080
-
-DEBUG=0
-pp = pprint.PrettyPrinter(indent=4)
-
-app = Flask(__name__)
-
-## Worker Functions ##
-def log_error(txt):
- print '%s' % (txt)
-
-def debug(txt):
- if DEBUG:
- print '%s' % (txt)
-
-# @app.route("/wm/flow/measurement-get-per-flow-install-time/json")
-def measurement_get_per_flow_install_time():
- command = "curl -s \"http://%s:%s/wm/flow/measurement-get-per-flow-install-time/json\"" % (ControllerIP, ControllerPort)
- debug("measurement_get_per_flow_install_time %s" % command)
- result = os.popen(command).read()
- print '%s' % (result)
- # parsedResult = json.loads(result)
- # debug("parsed %s" % parsedResult)
-
-if __name__ == "__main__":
- usage_msg = "Get the measured time per flow to install each stored flow path\n"
- usage_msg = usage_msg + "Usage: %s\n" % (sys.argv[0])
- usage_msg = usage_msg + "\n"
-
- # app.debug = False;
-
- # Usage info
- if len(sys.argv) > 1 and (sys.argv[1] == "-h" or sys.argv[1] == "--help"):
- print(usage_msg)
- exit(0)
-
- # Check arguments
-
- # Do the work
- measurement_get_per_flow_install_time()
diff --git a/web/measurement_install_paths.py b/web/measurement_install_paths.py
deleted file mode 100755
index d99070e..0000000
--- a/web/measurement_install_paths.py
+++ /dev/null
@@ -1,67 +0,0 @@
-#! /usr/bin/env python
-# -*- Mode: python; py-indent-offset: 4; tab-width: 8; indent-tabs-mode: t; -*-
-
-import pprint
-import os
-import sys
-import subprocess
-import json
-import argparse
-import io
-import time
-
-from flask import Flask, json, Response, render_template, make_response, request
-
-#
-# TODO: remove this! We don't use JSON argument here!
-# curl http://127.0.0.1:8080/wm/flow/delete/{"value":"0xf"}/json'
-#
-
-## Global Var ##
-ControllerIP="127.0.0.1"
-ControllerPort=8080
-
-DEBUG=0
-pp = pprint.PrettyPrinter(indent=4)
-
-app = Flask(__name__)
-
-## Worker Functions ##
-def log_error(txt):
- print '%s' % (txt)
-
-def debug(txt):
- if DEBUG:
- print '%s' % (txt)
-
-# @app.route("/wm/flow/measurement-install-paths/<num-threads>/json")
-def measurement_install_paths(num_threads):
- command = "curl -s \"http://%s:%s/wm/flow/measurement-install-paths/%s/json\"" % (ControllerIP, ControllerPort, num_threads)
- debug("measurement_install_paths %s" % command)
- result = os.popen(command).read()
- debug("result %s" % result)
- # parsedResult = json.loads(result)
- # debug("parsed %s" % parsedResult)
-
-if __name__ == "__main__":
- usage_msg = "Install flow paths and start measurements\n"
- usage_msg = usage_msg + "Usage: %s <num-threads>\n" % (sys.argv[0])
- usage_msg = usage_msg + "\n"
- usage_msg = usage_msg + " Arguments:\n"
- usage_msg = usage_msg + " <num-threads> Number of threads to use to install the flows\n"
-
- # app.debug = False;
-
- # Usage info
- if len(sys.argv) > 1 and (sys.argv[1] == "-h" or sys.argv[1] == "--help"):
- print(usage_msg)
- exit(0)
-
- # Check arguments
- if len(sys.argv) < 2:
- log_error(usage_msg)
- exit(1)
- num_threads = int(sys.argv[1], 0)
-
- # Do the work
- measurement_install_paths(num_threads)
diff --git a/web/measurement_process.py b/web/measurement_process.py
deleted file mode 100755
index 3187299..0000000
--- a/web/measurement_process.py
+++ /dev/null
@@ -1,59 +0,0 @@
-#! /usr/bin/env python
-# -*- Mode: python; py-indent-offset: 4; tab-width: 8; indent-tabs-mode: t; -*-
-
-import functools
-import math
-import sys
-
-## {{{ http://code.activestate.com/recipes/511478/ (r1)
-
-def percentile(N, percent, key=lambda x:x):
- """
- Find the percentile of a list of values.
-
- @parameter N - is a list of values. Note N MUST BE already sorted.
- @parameter percent - a float value from 0.0 to 1.0.
- @parameter key - optional key function to compute value from each element of N.
-
- @return - the percentile of the values
- """
- if not N:
- return None
- k = (len(N)-1) * percent
- f = math.floor(k)
- c = math.ceil(k)
- if f == c:
- return key(N[int(k)])
- d0 = key(N[int(f)]) * (c-k)
- d1 = key(N[int(c)]) * (k-f)
- return d0+d1
-
-# median is 50th percentile.
-# median = functools.partial(percentile, percent=0.5)
-## end of http://code.activestate.com/recipes/511478/ }}}
-
-if __name__ == "__main__":
-
- dict = {}
-
- #
- # Read the data from the stdin, and store it in a dictionary.
- # The dictionary uses lists as values.
- #
- data = sys.stdin.readlines()
- for line in data:
- words = line.split()
- thread_n = int(words[0])
- msec = float(words[1])
- dict.setdefault(thread_n, []).append(msec)
-
- #
- # Compute and print the values: median (50-th), 10-th, and 90-th
- # percentile:
- # <key> <median> <10-percentile> <90-percentile>
- #
- for key, val_list in sorted(dict.items()):
- val_10 = percentile(sorted(val_list), 0.1)
- val_50 = percentile(sorted(val_list), 0.5)
- val_90 = percentile(sorted(val_list), 0.9)
- print "%s %s %s %s" % (str(key), str(val_50), str(val_10), str(val_90))
diff --git a/web/measurement_run.py b/web/measurement_run.py
deleted file mode 100755
index 80d0517..0000000
--- a/web/measurement_run.py
+++ /dev/null
@@ -1,104 +0,0 @@
-#! /usr/bin/env python
-# -*- Mode: python; py-indent-offset: 4; tab-width: 8; indent-tabs-mode: t; -*-
-
-import os
-import string
-import subprocess
-import time
-
-# flow_n = 252
-# threads_n = [1, 2, 3, 4, 5, 10, 20, 30, 40, 50, 100]
-# iterations_n = 10
-
-flow_n = 1
-threads_n = [1]
-iterations_n = 10
-# iterations_n = 100
-
-# flow_n = 42
-# flow_n = 420
-# flow_n = 1008
-
-def run_command(cmd):
- """
- - Run an external command, and return a tuple: stdout as the
- first argument, and stderr as the second argument.
- - Returns None if error.
- """
- try:
- pr = subprocess.Popen(cmd, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
- ret_tuple = pr.communicate();
- if pr.returncode:
- print "%s failed with error code: %s" % (cmd, str(pr.returncode))
- return ret_tuple
- except OSError:
- print "OS Error running %s" % cmd
-
-def run_install_paths(flowdef_filename):
- # Prepare the flows to measure
- cmd = "web/measurement_store_flow.py -f " + flowdef_filename
- os.system(cmd)
-
-def run_measurement(thread_n):
- # Install the Flow Paths
- cmd = ["web/measurement_install_paths.py", str(thread_n)]
- run_command(cmd)
-
- # Get the measurement data and print it
- cmd = "web/measurement_get_install_paths_time_nsec.py"
- r = run_command(cmd) # Tuple: [<stdout>, <stderr>]
- res = r[0].split() # Tuple: [<num>, nsec]
- nsec_str = res[0]
- msec = float(nsec_str) / (1000 * 1000)
-
- # Get the measurement data and print it
- cmd = "web/measurement_get_per_flow_install_time.py"
- r = run_command(cmd) # Tuple: [<stdout>, <stderr>]
- res = r[0]
- print res
-
- # Keep checking until all Flow Paths are installed
- while True:
- # time.sleep(3)
- cmd = ["web/get_flow.py", "all"]
- r = run_command(cmd)
- if string.count(r[0], "FlowPath") != flow_n:
- continue
- if string.find(r[0], "NOT") == -1:
- break
-
- # Remove the installed Flow Paths
- cmd = ["web/delete_flow.py", "all"]
- run_command(cmd)
-
- # Keep checking until all Flows are removed
- while True:
- # time.sleep(3)
- cmd = ["web/get_flow.py", "all"]
- r = run_command(cmd)
- if r[0] == "":
- break
-
- return msec
-
-
-if __name__ == "__main__":
-
- # Initial cleanup
- cmd = "web/measurement_clear_all_paths.py"
- run_command(cmd)
-
- # Install the Flow Paths to measure
- flowdef_filename = "web/flowdef_8node_" + str(flow_n) + ".txt"
- run_install_paths(flowdef_filename)
-
- # Do the work
- for thread_n in threads_n:
- for n in range(iterations_n):
- msec = run_measurement(thread_n)
- # Format: <number of threads> <time in ms>
- print "%d %f" % (thread_n, msec / flow_n)
-
- # Cleanup on exit
- cmd = "web/measurement_clear_all_paths.py"
- run_command(cmd)
diff --git a/web/measurement_store_flow.py b/web/measurement_store_flow.py
deleted file mode 100755
index dda7fbd..0000000
--- a/web/measurement_store_flow.py
+++ /dev/null
@@ -1,446 +0,0 @@
-#! /usr/bin/env python
-# -*- Mode: python; py-indent-offset: 4; tab-width: 8; indent-tabs-mode: t; -*-
-
-import copy
-import pprint
-import os
-import sys
-import subprocess
-import json
-import argparse
-import io
-import time
-
-from flask import Flask, json, Response, render_template, make_response, request
-
-## Global Var ##
-ControllerIP = "127.0.0.1"
-ControllerPort = 8080
-ReadFromFile = ""
-
-DEBUG=0
-pp = pprint.PrettyPrinter(indent=4)
-
-app = Flask(__name__)
-
-## Worker Functions ##
-def log_error(txt):
- print '%s' % (txt)
-
-def debug(txt):
- if DEBUG:
- print '%s' % (txt)
-
-def measurement_store_path_flow(flow_path):
- flow_path_json = json.dumps(flow_path)
-
- try:
- command = "curl -s -H 'Content-Type: application/json' -d '%s' http://%s:%s/wm/flow/measurement-store-path/json" % (flow_path_json, ControllerIP, ControllerPort)
- debug("measurement_store_path_flow %s" % command)
- result = os.popen(command).read()
- debug("result %s" % result)
- # parsedResult = json.loads(result)
- # debug("parsed %s" % parsedResult)
- except:
- log_error("Controller IF has issue")
- exit(1)
-
-def extract_flow_args(my_args):
- # Check the arguments
- if len(my_args) < 6:
- log_error(usage_msg)
- exit(1)
-
- # Extract the mandatory arguments
- my_flow_id = my_args[0]
- my_installer_id = my_args[1]
- my_src_dpid = my_args[2]
- my_src_port = my_args[3]
- my_dst_dpid = my_args[4]
- my_dst_port = my_args[5]
-
- #
- # Extract the "match" and "action" arguments
- #
- match = {}
- matchInPortEnabled = True # NOTE: Enabled by default
- actions = []
- actionOutputEnabled = True # NOTE: Enabled by default
- idx = 6
- while idx < len(my_args):
- action = {}
- arg1 = my_args[idx]
- idx = idx + 1
- # Extract the second argument
- if idx >= len(my_args):
- error_arg = "ERROR: Missing or invalid '" + arg1 + "' argument"
- log_error(error_arg)
- log_error(usage_msg)
- exit(1)
- arg2 = my_args[idx]
- idx = idx + 1
-
- if arg1 == "matchInPort":
- # Just mark whether inPort matching is enabled
- matchInPortEnabled = arg2 in ['True', 'true']
- # inPort = {}
- # inPort['value'] = int(arg2, 0)
- # match['inPort'] = inPort
- ## match['matchInPort'] = True
- elif arg1 == "matchSrcMac":
- srcMac = {}
- srcMac['value'] = arg2
- match['srcMac'] = srcMac
- # match['matchSrcMac'] = True
- elif arg1 == "matchDstMac":
- dstMac = {}
- dstMac['value'] = arg2
- match['dstMac'] = dstMac
- # match['matchDstMac'] = True
- elif arg1 == "matchEthernetFrameType":
- match['ethernetFrameType'] = int(arg2, 0)
- # match['matchEthernetFrameType'] = True
- elif arg1 == "matchVlanId":
- match['vlanId'] = int(arg2, 0)
- # match['matchVlanId'] = True
- elif arg1 == "matchVlanPriority":
- match['vlanPriority'] = int(arg2, 0)
- # match['matchVlanPriority'] = True
- elif arg1 == "matchSrcIPv4Net":
- srcIPv4Net = {}
- srcIPv4Net['value'] = arg2
- match['srcIPv4Net'] = srcIPv4Net
- # match['matchSrcIPv4Net'] = True
- elif arg1 == "matchDstIPv4Net":
- dstIPv4Net = {}
- dstIPv4Net['value'] = arg2
- match['dstIPv4Net'] = dstIPv4Net
- # match['matchDstIPv4Net'] = True
- elif arg1 == "matchIpProto":
- match['ipProto'] = int(arg2, 0)
- # match['matchIpProto'] = True
- elif arg1 == "matchIpToS":
- match['ipToS'] = int(arg2, 0)
- # match['matchIpToS'] = True
- elif arg1 == "matchSrcTcpUdpPort":
- match['srcTcpUdpPort'] = int(arg2, 0)
- # match['matchSrcTcpUdpPort'] = True
- elif arg1 == "matchDstTcpUdpPort":
- match['dstTcpUdpPort'] = int(arg2, 0)
- # match['matchDstTcpUdpPort'] = True
- elif arg1 == "actionOutput":
- # Just mark whether ACTION_OUTPUT action is enabled
- actionOutputEnabled = arg2 in ['True', 'true']
- #
- # TODO: Complete the implementation for ACTION_OUTPUT
- # actionOutput = {}
- # outPort = {}
- # outPort['value'] = int(arg2, 0)
- # actionOutput['port'] = outPort
- # actionOutput['maxLen'] = int(arg3, 0)
- # action['actionOutput'] = actionOutput
- # # action['actionType'] = 'ACTION_OUTPUT'
- # actions.append(action)
- #
- elif arg1 == "actionSetVlanId":
- vlanId = {}
- vlanId['vlanId'] = int(arg2, 0)
- action['actionSetVlanId'] = vlanId
- # action['actionType'] = 'ACTION_SET_VLAN_VID'
- actions.append(copy.deepcopy(action))
- elif arg1 == "actionSetVlanPriority":
- vlanPriority = {}
- vlanPriority['vlanPriority'] = int(arg2, 0)
- action['actionSetVlanPriority'] = vlanPriority
- # action['actionType'] = 'ACTION_SET_VLAN_PCP'
- actions.append(copy.deepcopy(action))
- elif arg1 == "actionStripVlan":
- stripVlan = {}
- stripVlan['stripVlan'] = arg2 in ['True', 'true']
- action['actionStripVlan'] = stripVlan
- # action['actionType'] = 'ACTION_STRIP_VLAN'
- actions.append(copy.deepcopy(action))
- elif arg1 == "actionSetEthernetSrcAddr":
- ethernetSrcAddr = {}
- ethernetSrcAddr['value'] = arg2
- setEthernetSrcAddr = {}
- setEthernetSrcAddr['addr'] = ethernetSrcAddr
- action['actionSetEthernetSrcAddr'] = setEthernetSrcAddr
- # action['actionType'] = 'ACTION_SET_DL_SRC'
- actions.append(copy.deepcopy(action))
- elif arg1 == "actionSetEthernetDstAddr":
- ethernetDstAddr = {}
- ethernetDstAddr['value'] = arg2
- setEthernetDstAddr = {}
- setEthernetDstAddr['addr'] = ethernetDstAddr
- action['actionSetEthernetDstAddr'] = setEthernetDstAddr
- # action['actionType'] = 'ACTION_SET_DL_DST'
- actions.append(copy.deepcopy(action))
- elif arg1 == "actionSetIPv4SrcAddr":
- IPv4SrcAddr = {}
- IPv4SrcAddr['value'] = arg2
- setIPv4SrcAddr = {}
- setIPv4SrcAddr['addr'] = IPv4SrcAddr
- action['actionSetIPv4SrcAddr'] = setIPv4SrcAddr
- # action['actionType'] = 'ACTION_SET_NW_SRC'
- actions.append(copy.deepcopy(action))
- elif arg1 == "actionSetIPv4DstAddr":
- IPv4DstAddr = {}
- IPv4DstAddr['value'] = arg2
- setIPv4DstAddr = {}
- setIPv4DstAddr['addr'] = IPv4DstAddr
- action['actionSetIPv4DstAddr'] = setIPv4DstAddr
- # action['actionType'] = 'ACTION_SET_NW_DST'
- actions.append(copy.deepcopy(action))
- elif arg1 == "actionSetIpToS":
- ipToS = {}
- ipToS['ipToS'] = int(arg2, 0)
- action['actionSetIpToS'] = ipToS
- # action['actionType'] = 'ACTION_SET_NW_TOS'
- actions.append(copy.deepcopy(action))
- elif arg1 == "actionSetTcpUdpSrcPort":
- tcpUdpSrcPort = {}
- tcpUdpSrcPort['port'] = int(arg2, 0)
- action['actionSetTcpUdpSrcPort'] = tcpUdpSrcPort
- # action['actionType'] = 'ACTION_SET_TP_SRC'
- actions.append(copy.deepcopy(action))
- elif arg1 == "actionSetTcpUdpDstPort":
- tcpUdpDstPort = {}
- tcpUdpDstPort['port'] = int(arg2, 0)
- action['actionSetTcpUdpDstPort'] = tcpUdpDstPort
- # action['actionType'] = 'ACTION_SET_TP_DST'
- actions.append(copy.deepcopy(action))
- elif arg1 == "actionEnqueue":
- # TODO: Implement ACTION_ENQUEUE
- actionEnqueue = {}
- # actionEnqueue['queueId'] = int(arg2, 0)
- # enqueuePort = {}
- # enqueuePort['value'] = int(arg3, 0)
- # actionEnqueue['port'] = enqueuePort
- # action['actionEnqueue'] = actionEnqueue
- # # action['actionType'] = 'ACTION_ENQUEUE'
- # actions.append(copy.deepcopy(action))
- #
- else:
- log_error("ERROR: Unknown argument '%s'" % (arg1))
- log_error(usage_msg)
- exit(1)
-
- return {
- 'my_flow_id' : my_flow_id,
- 'my_installer_id' : my_installer_id,
- 'my_src_dpid' : my_src_dpid,
- 'my_src_port' : my_src_port,
- 'my_dst_dpid' : my_dst_dpid,
- 'my_dst_port' : my_dst_port,
- 'match' : match,
- 'matchInPortEnabled' : matchInPortEnabled,
- 'actions' : actions,
- 'actionOutputEnabled' : actionOutputEnabled
- }
-
-def compute_flow_path(parsed_args, data_path):
-
- my_flow_id = parsed_args['my_flow_id']
- my_installer_id = parsed_args['my_installer_id']
- match = parsed_args['match']
- matchInPortEnabled = parsed_args['matchInPortEnabled']
- actions = parsed_args['actions']
- actionOutputEnabled = parsed_args['actionOutputEnabled']
- my_data_path = copy.deepcopy(data_path)
-
- flow_id = {}
- flow_id['value'] = my_flow_id
- installer_id = {}
- installer_id['value'] = my_installer_id
-
- flow_path = {}
- flow_path['flowId'] = flow_id
- flow_path['installerId'] = installer_id
-
- if (len(match) > 0):
- flow_path['flowEntryMatch'] = copy.deepcopy(match)
-
- #
- # Add the match conditions to each flow entry
- #
- if (len(match) > 0) or matchInPortEnabled:
- idx = 0
- while idx < len(my_data_path['flowEntries']):
- if matchInPortEnabled:
- inPort = my_data_path['flowEntries'][idx]['inPort']
- match['inPort'] = copy.deepcopy(inPort)
- # match['matchInPort'] = True
- my_data_path['flowEntries'][idx]['flowEntryMatch'] = copy.deepcopy(match)
- idx = idx + 1
-
- #
- # Set the actions for each flow entry
- # NOTE: The actions from the command line are aplied
- # ONLY to the first flow entry.
- #
- # If ACTION_OUTPUT action is enabled, then apply it
- # to each flow entry.
- #
- if (len(actions) > 0) or actionOutputEnabled:
- idx = 0
- while idx < len(my_data_path['flowEntries']):
- if idx > 0:
- actions = [] # Reset the actions for all but first entry
- action = {}
- outPort = my_data_path['flowEntries'][idx]['outPort']
- actionOutput = {}
- actionOutput['port'] = copy.deepcopy(outPort)
- # actionOutput['maxLen'] = 0 # TODO: not used for now
- action['actionOutput'] = copy.deepcopy(actionOutput)
- # action['actionType'] = 'ACTION_OUTPUT'
- actions.append(copy.deepcopy(action))
-
- my_data_path['flowEntries'][idx]['flowEntryActions'] = copy.deepcopy(actions)
- idx = idx + 1
-
-
- flow_path['dataPath'] = my_data_path
- debug("Flow Path: %s" % flow_path)
- return flow_path
-
-def measurement_store_paths(parsed_args):
- idx = 0
- while idx < len(parsed_args):
- data_path = {}
- src_dpid = {}
- src_port = {}
- dst_dpid = {}
- dst_port = {}
- src_switch_port = {}
- dst_switch_port = {}
- flow_entries = []
-
- src_dpid['value'] = parsed_args[idx]['my_src_dpid']
- src_port['value'] = parsed_args[idx]['my_src_port']
- dst_dpid['value'] = parsed_args[idx]['my_dst_dpid']
- dst_port['value'] = parsed_args[idx]['my_dst_port']
- src_switch_port['dpid'] = src_dpid
- src_switch_port['port'] = src_port
- dst_switch_port['dpid'] = dst_dpid
- dst_switch_port['port'] = dst_port
-
- data_path['srcPort'] = copy.deepcopy(src_switch_port)
- data_path['dstPort'] = copy.deepcopy(dst_switch_port)
- data_path['flowEntries'] = copy.deepcopy(flow_entries)
-
- #
- # XXX: Explicitly disable the InPort matching, and
- # the Output action, because they get in the way
- # during the compute_flow_path() processing.
- #
- parsed_args[idx]['matchInPortEnabled'] = False
- parsed_args[idx]['actionOutputEnabled'] = False
-
- flow_path = compute_flow_path(parsed_args[idx], data_path)
- measurement_store_path_flow(flow_path)
-
- idx = idx + 1
-
-
-if __name__ == "__main__":
- usage_msg = "Store Flow Paths into ONOS for measurement purpose.\n"
- usage_msg = usage_msg + "\n"
- usage_msg = usage_msg + "Usage: %s [Flags] <flow-id> <installer-id> <src-dpid> <src-port> <dest-dpid> <dest-port> [Match Conditions] [Actions]\n" % (sys.argv[0])
- usage_msg = usage_msg + "\n"
- usage_msg = usage_msg + " Flags:\n"
- usage_msg = usage_msg + " -f <filename> Read the flow(s) to install from a file\n"
- usage_msg = usage_msg + " File format: one line per flow starting with <flow-id>\n"
- usage_msg = usage_msg + "\n"
- usage_msg = usage_msg + " Match Conditions:\n"
- usage_msg = usage_msg + " matchInPort <True|False> (default to True)\n"
- usage_msg = usage_msg + " matchSrcMac <source MAC address>\n"
- usage_msg = usage_msg + " matchDstMac <destination MAC address>\n"
- usage_msg = usage_msg + " matchEthernetFrameType <Ethernet frame type>\n"
- usage_msg = usage_msg + " matchVlanId <VLAN ID>\n"
- usage_msg = usage_msg + " matchVlanPriority <VLAN priority>\n"
- usage_msg = usage_msg + " matchSrcIPv4Net <source IPv4 network address>\n"
- usage_msg = usage_msg + " matchDstIPv4Net <destination IPv4 network address>\n"
- usage_msg = usage_msg + "\n"
- usage_msg = usage_msg + " matchIpProto <IP protocol>\n"
- usage_msg = usage_msg + " matchIpToS <IP ToS (DSCP field, 6 bits)>\n"
- usage_msg = usage_msg + " matchSrcTcpUdpPort <source TCP/UDP port>\n"
- usage_msg = usage_msg + " matchDstTcpUdpPort <destination TCP/UDP port>\n"
- usage_msg = usage_msg + "\n"
- usage_msg = usage_msg + " Actions:\n"
- usage_msg = usage_msg + " actionOutput <True|False> (default to True)\n"
- usage_msg = usage_msg + " actionSetEthernetSrcAddr <source MAC address>\n"
- usage_msg = usage_msg + " actionSetEthernetDstAddr <destination MAC address>\n"
- usage_msg = usage_msg + " actionSetIPv4SrcAddr <source IPv4 address>\n"
- usage_msg = usage_msg + " actionSetIPv4DstAddr <destination IPv4 address>\n"
- usage_msg = usage_msg + "\n"
- usage_msg = usage_msg + " Actions (not implemented yet):\n"
- usage_msg = usage_msg + " actionSetVlanId <VLAN ID>\n"
- usage_msg = usage_msg + " actionSetVlanPriority <VLAN priority>\n"
- usage_msg = usage_msg + " actionSetIpToS <IP ToS (DSCP field, 6 bits)>\n"
- usage_msg = usage_msg + " actionSetTcpUdpSrcPort <source TCP/UDP port>\n"
- usage_msg = usage_msg + " actionSetTcpUdpDstPort <destination TCP/UDP port>\n"
- usage_msg = usage_msg + " actionStripVlan <True|False>\n"
- usage_msg = usage_msg + " actionEnqueue <dummy argument>\n"
-
- # app.debug = False;
-
- # Usage info
- if len(sys.argv) > 1 and (sys.argv[1] == "-h" or sys.argv[1] == "--help"):
- print(usage_msg)
- exit(0)
-
- #
- # Check the flags
- #
- start_argv_index = 1
- idx = 1
- while idx < len(sys.argv):
- arg1 = sys.argv[idx]
- idx = idx + 1
- if arg1 == "-f":
- if idx >= len(sys.argv):
- error_arg = "ERROR: Missing or invalid '" + arg1 + "' argument"
- log_error(error_arg)
- log_error(usage_msg)
- exit(1)
- ReadFromFile = sys.argv[idx]
- idx = idx + 1
- start_argv_index = idx
- else:
- break;
-
- #
- # Read the arguments from a file or from the remaining command line options
- #
- my_lines = []
- if len(ReadFromFile) > 0:
- f = open(ReadFromFile, "rt")
- my_line = f.readline()
- while my_line:
- if len(my_line.rstrip()) > 0 and my_line[0] != "#":
- my_token_line = my_line.rstrip().split()
- my_lines.append(my_token_line)
- my_line = f.readline()
- else:
- my_lines.append(copy.deepcopy(sys.argv[start_argv_index:]))
-
- #
- # Initialization
- #
- last_data_paths = []
- parsed_args = []
- idx = 0
- while idx < len(my_lines):
- last_data_path = []
- last_data_paths.append(copy.deepcopy(last_data_path))
- #
- # Parse the flow arguments
- #
- my_args = my_lines[idx]
- parsed_args.append(copy.deepcopy(extract_flow_args(my_args)))
-
- idx = idx + 1
-
- #
- measurement_store_paths(parsed_args)
diff --git a/web/topology_rest.py b/web/topology_rest.py
index 53f46bc..ea33a00 100755
--- a/web/topology_rest.py
+++ b/web/topology_rest.py
@@ -216,19 +216,6 @@
resp = Response(result, status=200, mimetype='application/json')
return resp
-@app.route("/proxy/gui/switchctrl/<cmd>")
-def proxy_switch_controller_setting(cmd):
- try:
- command = "curl -s %s/gui/switchctrl/%s" % (ONOS_GUI3_CONTROL_HOST, cmd)
- print command
- result = os.popen(command).read()
- except:
- print "REST IF has issue"
- exit
-
- resp = Response(result, status=200, mimetype='application/json')
- return resp
-
@app.route("/proxy/gui/reset")
def proxy_gui_reset():
result = ""