merge from upstream/master
diff --git a/src/main/java/net/onrc/onos/datagrid/HazelcastDatagrid.java b/src/main/java/net/onrc/onos/datagrid/HazelcastDatagrid.java
index 775f952..6483121 100644
--- a/src/main/java/net/onrc/onos/datagrid/HazelcastDatagrid.java
+++ b/src/main/java/net/onrc/onos/datagrid/HazelcastDatagrid.java
@@ -27,7 +27,6 @@
import net.onrc.onos.ofcontroller.util.FlowPath;
import net.onrc.onos.ofcontroller.util.serializers.KryoFactory;
-import org.openflow.util.HexString;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -99,8 +98,7 @@
*
* @param event the notification event for the entry.
*/
- public void entryAdded(EntryEvent event) {
- Long keyLong = (Long)event.getKey();
+ public void entryAdded(EntryEvent<Long, byte[]> event) {
byte[] valueBytes = (byte[])event.getValue();
//
@@ -118,8 +116,7 @@
*
* @param event the notification event for the entry.
*/
- public void entryRemoved(EntryEvent event) {
- Long keyLong = (Long)event.getKey();
+ public void entryRemoved(EntryEvent<Long, byte[]> event) {
byte[] valueBytes = (byte[])event.getValue();
//
@@ -137,8 +134,7 @@
*
* @param event the notification event for the entry.
*/
- public void entryUpdated(EntryEvent event) {
- Long keyLong = (Long)event.getKey();
+ public void entryUpdated(EntryEvent<Long, byte[]> event) {
byte[] valueBytes = (byte[])event.getValue();
//
@@ -156,7 +152,7 @@
*
* @param event the notification event for the entry.
*/
- public void entryEvicted(EntryEvent event) {
+ public void entryEvicted(EntryEvent<Long, byte[]> event) {
// NOTE: We don't use eviction for this map
}
}
@@ -174,14 +170,7 @@
*
* @param event the notification event for the entry.
*/
- public void entryAdded(EntryEvent event) {
- //
- // NOTE: Ignore Flow Entries Events originated by this instance
- //
- if (event.getMember().localMember())
- return;
-
- Long keyLong = (Long)event.getKey();
+ public void entryAdded(EntryEvent<Long, byte[]> event) {
byte[] valueBytes = (byte[])event.getValue();
//
@@ -199,14 +188,7 @@
*
* @param event the notification event for the entry.
*/
- public void entryRemoved(EntryEvent event) {
- //
- // NOTE: Ignore Flow Entries Events originated by this instance
- //
- if (event.getMember().localMember())
- return;
-
- Long keyLong = (Long)event.getKey();
+ public void entryRemoved(EntryEvent<Long, byte[]> event) {
byte[] valueBytes = (byte[])event.getValue();
//
@@ -224,14 +206,7 @@
*
* @param event the notification event for the entry.
*/
- public void entryUpdated(EntryEvent event) {
- //
- // NOTE: Ignore Flow Entries Events originated by this instance
- //
- if (event.getMember().localMember())
- return;
-
- Long keyLong = (Long)event.getKey();
+ public void entryUpdated(EntryEvent<Long, byte[]> event) {
byte[] valueBytes = (byte[])event.getValue();
//
@@ -249,7 +224,7 @@
*
* @param event the notification event for the entry.
*/
- public void entryEvicted(EntryEvent event) {
+ public void entryEvicted(EntryEvent<Long, byte[]> event) {
// NOTE: We don't use eviction for this map
}
}
@@ -267,8 +242,7 @@
*
* @param event the notification event for the entry.
*/
- public void entryAdded(EntryEvent event) {
- String keyString = (String)event.getKey();
+ public void entryAdded(EntryEvent<String, byte[]> event) {
byte[] valueBytes = (byte[])event.getValue();
//
@@ -287,8 +261,7 @@
*
* @param event the notification event for the entry.
*/
- public void entryRemoved(EntryEvent event) {
- String keyString = (String)event.getKey();
+ public void entryRemoved(EntryEvent<String, byte[]> event) {
byte[] valueBytes = (byte[])event.getValue();
//
@@ -307,8 +280,7 @@
*
* @param event the notification event for the entry.
*/
- public void entryUpdated(EntryEvent event) {
- String keyString = (String)event.getKey();
+ public void entryUpdated(EntryEvent<String, byte[]> event) {
byte[] valueBytes = (byte[])event.getValue();
//
@@ -327,7 +299,7 @@
*
* @param event the notification event for the entry.
*/
- public void entryEvicted(EntryEvent event) {
+ public void entryEvicted(EntryEvent<String, byte[]> event) {
// NOTE: We don't use eviction for this map
}
}
diff --git a/src/main/java/net/onrc/onos/graph/GraphDBOperation.java b/src/main/java/net/onrc/onos/graph/GraphDBOperation.java
index bfd9046..03b4c96 100644
--- a/src/main/java/net/onrc/onos/graph/GraphDBOperation.java
+++ b/src/main/java/net/onrc/onos/graph/GraphDBOperation.java
@@ -176,9 +176,14 @@
*/
public IPortObject searchPort(String dpid, Short number) {
FramedGraph<TitanGraph> fg = conn.getFramedGraph();
+ if ( fg == null ) return null;
String id = dpid + number.toString();
- return (fg != null && fg.getVertices("port_id",id).iterator().hasNext()) ?
- fg.getVertices("port_id",id,IPortObject.class).iterator().next() : null;
+ Iterator<IPortObject> ports = fg.getVertices("port_id",id,IPortObject.class).iterator();
+ if ( ports.hasNext() ) {
+ return ports.next();
+ } else {
+ return null;
+ }
}
/**
@@ -206,10 +211,14 @@
* @param macAddr MAC address to search and get
*/
public IDeviceObject searchDevice(String macAddr) {
- // TODO Auto-generated method stub
- FramedGraph<TitanGraph> fg = conn.getFramedGraph();
- return (fg != null && fg.getVertices("dl_addr",macAddr).iterator().hasNext()) ?
- fg.getVertices("dl_addr",macAddr, IDeviceObject.class).iterator().next() : null;
+ FramedGraph<TitanGraph> fg = conn.getFramedGraph();
+ if ( fg == null ) return null;
+ Iterator<IDeviceObject> devices = fg.getVertices("dl_addr",macAddr, IDeviceObject.class).iterator();
+ if ( devices.hasNext() ) {
+ return devices.next();
+ } else {
+ return null;
+ }
}
/**
@@ -288,10 +297,13 @@
*/
public IFlowPath searchFlowPath(FlowId flowId) {
FramedGraph<TitanGraph> fg = conn.getFramedGraph();
-
- return fg.getVertices("flow_id", flowId.toString()).iterator().hasNext() ?
- fg.getVertices("flow_id", flowId.toString(),
- IFlowPath.class).iterator().next() : null;
+ if ( fg == null ) return null;
+ Iterator<IFlowPath> flowpaths = fg.getVertices("flow_id", flowId.toString(), IFlowPath.class).iterator();
+ if ( flowpaths.hasNext() ) {
+ return flowpaths.next();
+ } else {
+ return null;
+ }
}
/**
@@ -299,10 +311,10 @@
* @param flowEntry flow entry object
*/
public IFlowPath getFlowPathByFlowEntry(IFlowEntry flowEntry) {
- GremlinPipeline<Vertex, IFlowPath> pipe = new GremlinPipeline<Vertex, IFlowPath>();
- pipe.start(flowEntry.asVertex());
- pipe.out("flow");
- FramedVertexIterable<IFlowPath> r = new FramedVertexIterable(conn.getFramedGraph(), (Iterable) pipe, IFlowPath.class);
+ GremlinPipeline<Vertex, Vertex> pipe = new GremlinPipeline<Vertex, Vertex>();
+ pipe.start(flowEntry.asVertex()).out("flow");
+ FramedVertexIterable<IFlowPath> r = new FramedVertexIterable<IFlowPath>(conn.getFramedGraph(),
+ (Iterable<Vertex>) pipe, IFlowPath.class);
return r.iterator().hasNext() ? r.iterator().next() : null;
}
@@ -348,10 +360,13 @@
*/
public IFlowEntry searchFlowEntry(FlowEntryId flowEntryId) {
FramedGraph<TitanGraph> fg = conn.getFramedGraph();
-
- return fg.getVertices("flow_entry_id", flowEntryId.toString()).iterator().hasNext() ?
- fg.getVertices("flow_entry_id", flowEntryId.toString(),
- IFlowEntry.class).iterator().next() : null;
+ if ( fg == null ) return null;
+ Iterator<IFlowEntry> flowentries = fg.getVertices("flow_entry_id", flowEntryId.toString(), IFlowEntry.class).iterator();
+ if ( flowentries.hasNext() ) {
+ return flowentries.next();
+ } else {
+ return null;
+ }
}
/**
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 5db8f0a..cc454ec 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/Interface.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/Interface.java
@@ -14,7 +14,6 @@
public class Interface {
private final String name;
- private final SwitchPort switchPort;
private final long dpid;
private final short port;
private final InetAddress ipAddress;
@@ -31,7 +30,6 @@
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() {
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 041061c..c80d055 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/Ptree.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/Ptree.java
@@ -244,7 +244,6 @@
add.parent = node;
}
- @SuppressWarnings("unused")
private PtreeNode node_common(PtreeNode node, byte [] key, int key_bits) {
int i;
int limit = Math.min(node.keyBits, key_bits) / 8;
@@ -275,8 +274,6 @@
}
PtreeNode add = new PtreeNode(null, common_len, maxKeyOctets);
- if (add == null)
- return null;
int j;
for (j = 0; j < i; j++)
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 49ffd4e..29c4377 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjects.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjects.java
@@ -1,7 +1,5 @@
package net.onrc.onos.ofcontroller.core;
-import net.onrc.onos.ofcontroller.flowmanager.web.DatapathSummarySerializer;
-
import org.codehaus.jackson.annotate.JsonIgnore;
import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.map.annotate.JsonSerialize;
@@ -13,6 +11,9 @@
import com.tinkerpop.frames.annotations.gremlin.GremlinParam;
import com.tinkerpop.frames.VertexFrame;
+import net.onrc.onos.ofcontroller.flowmanager.web.DatapathSummarySerializer;
+import net.floodlightcontroller.core.web.serializers.IPv4Serializer;
+
/*
* This is the interfaces to make the objects for Cassandra DB.
* They are interfaces, but it is also implementation,
@@ -205,6 +206,7 @@
@JsonProperty("ipv4")
@Property("ipv4_address")
+ @JsonSerialize(using=IPv4Serializer.class)
public int getIpv4Address();
@Property("ipv4_address")
@@ -251,6 +253,20 @@
@Property("flow_path_flags")
public void setFlowPathFlags(Long flowPathFlags);
+ @JsonProperty("idleTimeout")
+ @Property("idle_timeout")
+ public Integer getIdleTimeout();
+
+ @Property("idle_timeout")
+ public void setIdleTimeout(Integer idleTimeout);
+
+ @JsonProperty("hardTimeout")
+ @Property("hard_timeout")
+ public Integer getHardTimeout();
+
+ @Property("hard_timeout")
+ public void setHardTimeout(Integer hardTimeout);
+
@JsonProperty("srcDpid")
@Property("src_switch")
public String getSrcSwitch();
@@ -405,6 +421,20 @@
@Property("flow_entry_id")
public void setFlowEntryId(String flowEntryId);
+ @JsonProperty("idleTimeout")
+ @Property("idle_timeout")
+ public Integer getIdleTimeout();
+
+ @Property("idle_timeout")
+ public void setIdleTimeout(Integer idleTimeout);
+
+ @JsonProperty("hardTimeout")
+ @Property("hard_timeout")
+ public Integer getHardTimeout();
+
+ @Property("hard_timeout")
+ public void setHardTimeout(Integer hardTimeout);
+
@Property("switch_dpid")
public String getSwitchDpid();
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/internal/DeviceStorageImpl.java b/src/main/java/net/onrc/onos/ofcontroller/core/internal/DeviceStorageImpl.java
index f5f8b00..4bbc054 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/core/internal/DeviceStorageImpl.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/internal/DeviceStorageImpl.java
@@ -80,6 +80,10 @@
log.debug("Adding device {}: creating new device", device.getMACAddressString());
}
+ if (obj == null) {
+ return null;
+ }
+
changeDeviceAttachments(device, obj);
changeDeviceIpv4Addresses(device, obj);
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 7a3d43e..635e24e 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
@@ -14,10 +14,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.tinkerpop.blueprints.Vertex;
-import com.tinkerpop.pipes.PipeFunction;
-import com.tinkerpop.pipes.transform.PathPipe;
-
/**
* This is the class for storing the information of links into GraphDB
*/
@@ -490,33 +486,4 @@
return success;
}
-
- // TODO should be moved to TopoLinkServiceImpl (never used in this class)
- static class ExtractLink implements PipeFunction<PathPipe<Vertex>, Link> {
-
- @SuppressWarnings("unchecked")
- @Override
- public Link compute(PathPipe<Vertex> pipe ) {
- long s_dpid = 0;
- long d_dpid = 0;
- short s_port = 0;
- short d_port = 0;
- List<Vertex> V = new ArrayList<Vertex>();
- V = (List<Vertex>)pipe.next();
- Vertex src_sw = V.get(0);
- Vertex dest_sw = V.get(3);
- Vertex src_port = V.get(1);
- Vertex dest_port = V.get(2);
- s_dpid = HexString.toLong((String) src_sw.getProperty("dpid"));
- d_dpid = HexString.toLong((String) dest_sw.getProperty("dpid"));
- s_port = (Short) src_port.getProperty("number");
- d_port = (Short) dest_port.getProperty("number");
-
- Link l = new Link(s_dpid,s_port,d_dpid,d_port);
-
- return l;
- }
- }
-
-
}
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 dcfdc73..5f51b58 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
@@ -348,7 +348,6 @@
IPortObject p = sw.getPort(port);
if (p != null) {
log.info("SwitchStorage:deletePort dpid:{} port:{} found and set INACTIVE", dpid, port);
- //deletePortImpl(p);
p.setState("INACTIVE");
// XXX for now delete devices when we change a port to prevent
@@ -492,12 +491,4 @@
new Object[] {port.getPortId(), state, desc});
}
}
-
- private void deletePortImpl(IPortObject port) {
- if (port != null) {
- op.removePort(port);
- log.info("SwitchStorage:deletePortImpl port:{} done",
- port.getPortId());
- }
- }
}
\ No newline at end of file
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/internal/TopoLinkServiceImpl.java b/src/main/java/net/onrc/onos/ofcontroller/core/internal/TopoLinkServiceImpl.java
index b692e8e..f1f015a 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/core/internal/TopoLinkServiceImpl.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/internal/TopoLinkServiceImpl.java
@@ -7,13 +7,15 @@
import net.onrc.onos.graph.GraphDBOperation;
import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoLinkService;
-import net.onrc.onos.ofcontroller.core.internal.LinkStorageImpl.ExtractLink;
+import org.openflow.util.HexString;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.tinkerpop.blueprints.Vertex;
import com.tinkerpop.gremlin.java.GremlinPipeline;
+import com.tinkerpop.pipes.PipeFunction;
+import com.tinkerpop.pipes.transform.PathPipe;
public class TopoLinkServiceImpl implements ITopoLinkService {
@@ -31,7 +33,6 @@
@Override
public List<Link> getActiveLinks() {
- // TODO Auto-generated method stub
op = new GraphDBOperation("");
op.commit(); //Commit to ensure we see latest data
Iterable<ISwitchObject> switches = op.getActiveSwitches();
@@ -56,7 +57,6 @@
@Override
public List<Link> getLinksOnSwitch(String dpid) {
- // TODO Auto-generated method stub
List<Link> links = new ArrayList<Link>();
ISwitchObject sw = op.searchSwitch(dpid);
GremlinPipeline<Vertex, Link> pipe = new GremlinPipeline<Vertex, Link>();
@@ -73,5 +73,29 @@
return links;
}
-
+
+ private class ExtractLink implements PipeFunction<PathPipe<Vertex>, Link> {
+ @Override
+ public Link compute(PathPipe<Vertex> pipe) {
+ long s_dpid = 0;
+ long d_dpid = 0;
+ short s_port = 0;
+ short d_port = 0;
+
+ @SuppressWarnings("unchecked")
+ List<Vertex> V = pipe.next();
+ Vertex src_sw = V.get(0);
+ Vertex dest_sw = V.get(3);
+ Vertex src_port = V.get(1);
+ Vertex dest_port = V.get(2);
+ s_dpid = HexString.toLong((String) src_sw.getProperty("dpid"));
+ d_dpid = HexString.toLong((String) dest_sw.getProperty("dpid"));
+ s_port = (Short) src_port.getProperty("number");
+ d_port = (Short) dest_port.getProperty("number");
+
+ Link l = new Link(s_dpid,s_port,d_dpid,d_port);
+
+ return l;
+ }
+ }
}
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 50fe8f8..4b31667 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/floodlightlistener/NetworkGraphPublisher.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/floodlightlistener/NetworkGraphPublisher.java
@@ -39,7 +39,6 @@
import net.onrc.onos.ofcontroller.core.ISwitchStorage;
import net.onrc.onos.ofcontroller.core.INetMapStorage.DM_OPERATION;
import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
-import net.onrc.onos.ofcontroller.core.ISwitchStorage.SwitchState;
import net.onrc.onos.ofcontroller.core.internal.DeviceStorageImpl;
import net.onrc.onos.ofcontroller.core.internal.LinkStorageImpl;
import net.onrc.onos.ofcontroller.core.internal.SwitchStorageImpl;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowDatabaseOperation.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowDatabaseOperation.java
index 1babafa..da407ab 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowDatabaseOperation.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowDatabaseOperation.java
@@ -3,10 +3,8 @@
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
-import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
-import java.util.concurrent.ConcurrentLinkedQueue;
import net.floodlightcontroller.util.MACAddress;
@@ -90,6 +88,8 @@
// - flowPath.flowPathType()
// - flowPath.flowPathUserState()
// - flowPath.flowPathFlags()
+ // - flowPath.idleTimeout()
+ // - flowPath.hardTimeout()
// - flowPath.dataPath().srcPort()
// - flowPath.dataPath().dstPort()
// - flowPath.matchSrcMac()
@@ -109,6 +109,8 @@
flowObj.setFlowPathType(flowPath.flowPathType().toString());
flowObj.setFlowPathUserState(flowPath.flowPathUserState().toString());
flowObj.setFlowPathFlags(flowPath.flowPathFlags().flags());
+ flowObj.setIdleTimeout(flowPath.idleTimeout());
+ flowObj.setHardTimeout(flowPath.hardTimeout());
flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
@@ -225,6 +227,8 @@
// - InPort edge
// - OutPort edge
//
+ // - flowEntry.idleTimeout()
+ // - flowEntry.hardTimeout()
// - flowEntry.dpid()
// - flowEntry.flowEntryUserState()
// - flowEntry.flowEntrySwitchState()
@@ -245,6 +249,8 @@
// - flowEntry.actions()
//
ISwitchObject sw = dbHandler.searchSwitch(flowEntry.dpid().toString());
+ flowEntryObj.setIdleTimeout(flowEntry.idleTimeout());
+ flowEntryObj.setHardTimeout(flowEntry.hardTimeout());
flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
flowEntryObj.setSwitch(sw);
if (flowEntry.flowEntryMatch().matchInPort()) {
@@ -509,6 +515,8 @@
String flowPathType = flowObj.getFlowPathType();
String flowPathUserState = flowObj.getFlowPathUserState();
Long flowPathFlags = flowObj.getFlowPathFlags();
+ Integer idleTimeout = flowObj.getIdleTimeout();
+ Integer hardTimeout = flowObj.getHardTimeout();
String srcSwitchStr = flowObj.getSrcSwitch();
Short srcPortShort = flowObj.getSrcPort();
String dstSwitchStr = flowObj.getDstSwitch();
@@ -519,6 +527,8 @@
(flowPathType == null) ||
(flowPathUserState == null) ||
(flowPathFlags == null) ||
+ (idleTimeout == null) ||
+ (hardTimeout == null) ||
(srcSwitchStr == null) ||
(srcPortShort == null) ||
(dstSwitchStr == null) ||
@@ -533,6 +543,8 @@
flowPath.setFlowPathType(FlowPathType.valueOf(flowPathType));
flowPath.setFlowPathUserState(FlowPathUserState.valueOf(flowPathUserState));
flowPath.setFlowPathFlags(new FlowPathFlags(flowPathFlags));
+ flowPath.setIdleTimeout(idleTimeout);
+ flowPath.setHardTimeout(hardTimeout);
flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
@@ -611,11 +623,15 @@
*/
public static FlowEntry extractFlowEntry(IFlowEntry flowEntryObj) {
String flowEntryIdStr = flowEntryObj.getFlowEntryId();
+ Integer idleTimeout = flowEntryObj.getIdleTimeout();
+ Integer hardTimeout = flowEntryObj.getHardTimeout();
String switchDpidStr = flowEntryObj.getSwitchDpid();
String userState = flowEntryObj.getUserState();
String switchState = flowEntryObj.getSwitchState();
if ((flowEntryIdStr == null) ||
+ (idleTimeout == null) ||
+ (hardTimeout == null) ||
(switchDpidStr == null) ||
(userState == null) ||
(switchState == null)) {
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowEventHandler.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowEventHandler.java
index 6c200fa..3538eb4 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowEventHandler.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowEventHandler.java
@@ -75,11 +75,14 @@
// Transient state for processing the Flow Paths:
// - The Flow Paths that should be recomputed
// - The Flow Paths with modified Flow Entries
+ // - The Flow Paths that we should check if installed in all switches
//
private Map<Long, FlowPath> shouldRecomputeFlowPaths =
new HashMap<Long, FlowPath>();
private Map<Long, FlowPath> modifiedFlowPaths =
new HashMap<Long, FlowPath>();
+ private Map<Long, FlowPath> checkIfInstalledFlowPaths =
+ new HashMap<Long, FlowPath>();
/**
* Constructor for a given Flow Manager and Datagrid Service.
@@ -239,6 +242,12 @@
for (FlowPath flowPath : modifiedFlowPaths.values())
flowPath.dataPath().removeDeletedFlowEntries();
+ //
+ // Check if Flow Paths have been installed into all switches,
+ // and generate the appropriate events.
+ //
+ checkInstalledFlowPaths(checkIfInstalledFlowPaths.values());
+
// Cleanup
topologyEvents.clear();
flowPathEvents.clear();
@@ -246,6 +255,44 @@
//
shouldRecomputeFlowPaths.clear();
modifiedFlowPaths.clear();
+ checkIfInstalledFlowPaths.clear();
+ }
+
+ /**
+ * Check if Flow Paths have been installed into all switches,
+ * and generate the appropriate events.
+ *
+ * @param flowPaths the flowPaths to process.
+ */
+ private void checkInstalledFlowPaths(Collection<FlowPath> flowPaths) {
+ List<FlowPath> installedFlowPaths = new LinkedList<FlowPath>();
+
+ Kryo kryo = kryoFactory.newKryo();
+
+ for (FlowPath flowPath : flowPaths) {
+ boolean isInstalled = true;
+
+ //
+ // Check whether all Flow Entries have been installed
+ //
+ for (FlowEntry flowEntry : flowPath.flowEntries()) {
+ if (flowEntry.flowEntrySwitchState() !=
+ FlowEntrySwitchState.FE_SWITCH_UPDATED) {
+ isInstalled = false;
+ break;
+ }
+ }
+
+ if (isInstalled) {
+ // Create a copy and add it to the list
+ FlowPath copyFlowPath = kryo.copy(flowPath);
+ installedFlowPaths.add(copyFlowPath);
+ }
+ }
+ kryoFactory.deleteKryo(kryo);
+
+ // Generate an event for the installed Flow Path.
+ flowManager.notificationFlowPathsInstalled(installedFlowPaths);
}
/**
@@ -340,6 +387,9 @@
}
modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
break;
+ case FP_TYPE_UNKNOWN:
+ log.error("FlowPath event with unknown type");
+ break;
}
allFlowPaths.put(flowPath.flowId().value(), flowPath);
@@ -526,10 +576,12 @@
}
//
- // Update the local Flow Entry.
+ // Update the local Flow Entry, and keep state to check
+ // if the Flow Path has been installed.
//
localFlowEntry.setFlowEntryUserState(flowEntry.flowEntryUserState());
localFlowEntry.setFlowEntrySwitchState(flowEntry.flowEntrySwitchState());
+ checkIfInstalledFlowPaths.put(flowPath.flowId().value(), flowPath);
return localFlowEntry;
}
@@ -700,6 +752,12 @@
newFlowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
//
+ // Copy the Flow timeouts
+ //
+ newFlowEntry.setIdleTimeout(flowPath.idleTimeout());
+ newFlowEntry.setHardTimeout(flowPath.hardTimeout());
+
+ //
// Allocate the FlowEntryMatch by copying the default one
// from the FlowPath (if set).
//
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 7ef49ef..41cf670 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowManager.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowManager.java
@@ -10,8 +10,6 @@
import java.util.SortedMap;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
import net.floodlightcontroller.core.IFloodlightProviderService;
import net.floodlightcontroller.core.IOFSwitch;
@@ -23,15 +21,13 @@
import net.onrc.onos.datagrid.IDatagridService;
import net.onrc.onos.graph.GraphDBOperation;
import net.onrc.onos.ofcontroller.core.INetMapStorage;
-import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowEntry;
-import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowPath;
import net.onrc.onos.ofcontroller.floodlightlistener.INetworkGraphService;
import net.onrc.onos.ofcontroller.flowmanager.web.FlowWebRoutable;
import net.onrc.onos.ofcontroller.flowprogrammer.IFlowPusherService;
+import net.onrc.onos.ofcontroller.forwarding.IForwardingService;
import net.onrc.onos.ofcontroller.topology.Topology;
import net.onrc.onos.ofcontroller.util.*;
-import org.openflow.protocol.OFType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -49,6 +45,7 @@
protected FlowEventHandler flowEventHandler;
protected IFlowPusherService pusher;
+ protected IForwardingService forwardingService;
// Flow Entry ID generation state
private static Random randomGenerator = new Random();
@@ -134,7 +131,8 @@
l.add(INetworkGraphService.class);
l.add(IDatagridService.class);
l.add(IRestApiService.class);
- l.add(IFlowPusherService.class);
+ l.add(IFlowPusherService.class);
+ l.add(IForwardingService.class);
return l;
}
@@ -151,6 +149,7 @@
datagridService = context.getServiceImpl(IDatagridService.class);
restApi = context.getServiceImpl(IRestApiService.class);
pusher = context.getServiceImpl(IFlowPusherService.class);
+ forwardingService = context.getServiceImpl(IForwardingService.class);
this.init("");
}
@@ -352,8 +351,25 @@
* @param sw the switch the Flow Entry expired on.
* @param flowEntryId the Flow Entry ID of the expired Flow Entry.
*/
- public void flowEntryOnSwitchExpired(IOFSwitch sw, FlowEntryId flowEntryId) {
- // TODO: Not implemented yet
+ public void flowEntryOnSwitchExpired(IOFSwitch sw,
+ FlowEntryId flowEntryId) {
+ // Find the Flow Entry
+ FlowEntry flowEntry = datagridService.getFlowEntry(flowEntryId);
+ if (flowEntryId == null)
+ return; // Flow Entry not found
+
+ // Find the Flow Path
+ FlowPath flowPath = datagridService.getFlow(flowEntry.flowId());
+ if (flowPath == null)
+ return; // Flow Path not found
+
+ //
+ // Remove the Flow if the Flow Entry expired on the first switch
+ //
+ Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
+ if (srcDpid.value() != sw.getId())
+ return;
+ deleteFlow(flowPath.flowId());
}
/**
@@ -370,7 +386,6 @@
// Process all entries
//
for (Pair<IOFSwitch, FlowEntry> entry : entries) {
- IOFSwitch sw = entry.first;
FlowEntry flowEntry = entry.second;
//
@@ -391,11 +406,24 @@
case FE_USER_DELETE:
datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
break;
+ case FE_USER_UNKNOWN:
+ assert(false);
+ break;
}
}
}
/**
+ * Generate a notification that a collection of Flow Paths has been
+ * installed in the network.
+ *
+ * @param flowPaths the collection of installed Flow Paths.
+ */
+ void notificationFlowPathsInstalled(Collection<FlowPath> flowPaths) {
+ forwardingService.flowsInstalled(flowPaths);
+ }
+
+ /**
* Push modified Flow-related state as appropriate.
*
* @param modifiedFlowPaths the collection of modified Flow Paths.
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 a25602d..549a0fc 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/IFlowService.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/IFlowService.java
@@ -6,8 +6,6 @@
import net.floodlightcontroller.core.IOFSwitch;
import net.floodlightcontroller.core.module.IFloodlightService;
import net.onrc.onos.ofcontroller.topology.Topology;
-import net.onrc.onos.ofcontroller.util.CallerId;
-import net.onrc.onos.ofcontroller.util.DataPathEndpoints;
import net.onrc.onos.ofcontroller.util.FlowEntry;
import net.onrc.onos.ofcontroller.util.FlowEntryId;
import net.onrc.onos.ofcontroller.util.FlowId;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowProgrammer.java b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowProgrammer.java
index 461d231..a4f0a8c 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowProgrammer.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowProgrammer.java
@@ -42,9 +42,8 @@
public class FlowProgrammer implements IFloodlightModule,
IOFMessageListener,
IOFSwitchListener {
- @SuppressWarnings("unused")
// flag to enable FlowSynchronizer
- private static final boolean enableFlowSync = false;
+ private static final boolean enableFlowSync = true;
protected static Logger log = LoggerFactory.getLogger(FlowProgrammer.class);
protected volatile IFloodlightProviderService floodlightProvider;
protected volatile IControllerRegistryService registryService;
@@ -155,8 +154,10 @@
public void addedSwitch(IOFSwitch sw) {
log.debug("Switch added: {}", sw.getId());
- if (enableFlowSync && registryService.hasControl(sw.getId())) {
- synchronizer.synchronize(sw);
+ if (enableFlowSync) {
+ if (registryService.hasControl(sw.getId())) {
+ synchronizer.synchronize(sw);
+ }
}
}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowPusher.java b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowPusher.java
index c3c7107..3f61248 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowPusher.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowPusher.java
@@ -34,7 +34,6 @@
import net.onrc.onos.ofcontroller.util.FlowEntryAction.*;
import net.onrc.onos.ofcontroller.util.FlowEntry;
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.FlowEntryUserState;
import net.onrc.onos.ofcontroller.util.IPv4Net;
@@ -68,8 +67,6 @@
protected static final int MAX_MESSAGE_SEND = 100;
public static final short PRIORITY_DEFAULT = 100;
- public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 0; // infinity
- public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
public enum QueueState {
READY,
@@ -82,8 +79,9 @@
* @author Naoki Shiota
*
*/
- @SuppressWarnings("serial")
private class SwitchQueue extends ArrayDeque<OFMessage> {
+ private static final long serialVersionUID = 1L;
+
QueueState state;
// Max rate of sending message (bytes/ms). 0 implies no limitation.
@@ -722,8 +720,8 @@
}
}
- fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
- .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
+ fm.setIdleTimeout((short)flowEntry.idleTimeout())
+ .setHardTimeout((short)flowEntry.hardTimeout())
.setPriority(PRIORITY_DEFAULT)
.setBufferId(OFPacketOut.BUFFER_ID_NONE).setCookie(cookie)
.setCommand(flowModCommand).setMatch(match)
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowSynchronizer.java b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowSynchronizer.java
index 7d5527b..6ef44be 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowSynchronizer.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowSynchronizer.java
@@ -7,8 +7,10 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
import org.openflow.protocol.OFFlowMod;
import org.openflow.protocol.OFMatch;
@@ -44,26 +46,27 @@
private GraphDBOperation dbHandler;
protected IFlowPusherService pusher;
- private Map<IOFSwitch, Thread> switchThreads;
+ private Map<IOFSwitch, FutureTask<SyncResult>> switchThreads;
public FlowSynchronizer() {
dbHandler = new GraphDBOperation("");
- switchThreads = new HashMap<IOFSwitch, Thread>();
+ switchThreads = new HashMap<IOFSwitch, FutureTask<SyncResult>>();
}
@Override
- public void synchronize(IOFSwitch sw) {
+ public Future<SyncResult> synchronize(IOFSwitch sw) {
Synchronizer sync = new Synchronizer(sw);
- Thread t = new Thread(sync);
- switchThreads.put(sw, t);
- t.start();
+ FutureTask<SyncResult> task = new FutureTask<SyncResult>(sync);
+ switchThreads.put(sw, task);
+ task.run();
+ return task;
}
@Override
public void interrupt(IOFSwitch sw) {
- Thread t = switchThreads.remove(sw);
+ FutureTask<SyncResult> t = switchThreads.remove(sw);
if(t != null) {
- t.interrupt();
+ t.cancel(true);
}
}
@@ -80,7 +83,7 @@
* @author Brian
*
*/
- protected class Synchronizer implements Runnable {
+ protected class Synchronizer implements Callable<SyncResult> {
IOFSwitch sw;
ISwitchObject swObj;
@@ -90,14 +93,45 @@
this.swObj = dbHandler.searchSwitch(dpid.toString());
}
+ double graphIDTime, switchTime, compareTime, graphEntryTime, extractTime, pushTime, totalTime;
@Override
- public void run() {
+ public SyncResult call() {
// TODO: stop adding other flow entries while synchronizing
//pusher.suspend(sw);
+ long start = System.nanoTime();
Set<FlowEntryWrapper> graphEntries = getFlowEntriesFromGraph();
+ long step1 = System.nanoTime();
Set<FlowEntryWrapper> switchEntries = getFlowEntriesFromSwitch();
- compare(graphEntries, switchEntries);
+ long step2 = System.nanoTime();
+ SyncResult result = compare(graphEntries, switchEntries);
+ long step3 = System.nanoTime();
+ graphIDTime = (step1 - start);
+ switchTime = (step2 - step1);
+ compareTime = (step3 - step2);
+ totalTime = (step3 - start);
+ outputTime();
//pusher.resume(sw);
+
+ return result;
+ }
+
+ private void outputTime() {
+ double div = Math.pow(10, 6); //convert nanoseconds to ms
+ graphIDTime /= div;
+ switchTime /= div;
+ compareTime = (compareTime - graphEntryTime - extractTime - pushTime) / div;
+ graphEntryTime /= div;
+ extractTime /= div;
+ pushTime /= div;
+ totalTime /= div;
+ log.debug("Sync time (ms):" +
+ graphIDTime + "," +
+ switchTime + "," +
+ compareTime + "," +
+ graphEntryTime + "," +
+ extractTime + "," +
+ pushTime + "," +
+ totalTime);
}
/**
@@ -107,7 +141,7 @@
* @param graphEntries Flow entries in GraphDB.
* @param switchEntries Flow entries in switch.
*/
- private void compare(Set<FlowEntryWrapper> graphEntries, Set<FlowEntryWrapper> switchEntries) {
+ private SyncResult compare(Set<FlowEntryWrapper> graphEntries, Set<FlowEntryWrapper> switchEntries) {
int added = 0, removed = 0, skipped = 0;
for(FlowEntryWrapper entry : switchEntries) {
if(graphEntries.contains(entry)) {
@@ -123,11 +157,16 @@
for(FlowEntryWrapper entry : graphEntries) {
// add flow entry to switch
entry.addToSwitch(sw);
+ graphEntryTime += entry.dbTime;
+ extractTime += entry.extractTime;
+ pushTime += entry.pushTime;
added++;
}
log.debug("Flow entries added "+ added + ", " +
"Flow entries removed "+ removed + ", " +
"Flow entries skipped " + skipped);
+
+ return new SyncResult(added, removed, skipped);
}
/**
@@ -216,6 +255,7 @@
* Install this FlowEntry to a switch via FlowPusher.
* @param sw Switch to which flow will be installed.
*/
+ double dbTime, extractTime, pushTime;
public void addToSwitch(IOFSwitch sw) {
if (statisticsReply != null) {
log.error("Error adding existing flow entry {} to sw {}",
@@ -223,6 +263,7 @@
return;
}
+ double startDB = System.nanoTime();
// Get the Flow Entry state from the Network Graph
IFlowEntry iFlowEntry = null;
try {
@@ -237,7 +278,9 @@
flowEntryId, sw.getId());
return;
}
+ dbTime = System.nanoTime() - startDB;
+ double startExtract = System.nanoTime();
FlowEntry flowEntry =
FlowDatabaseOperation.extractFlowEntry(iFlowEntry);
if (flowEntry == null) {
@@ -245,8 +288,11 @@
flowEntryId, sw.getId());
return;
}
-
+ extractTime = System.nanoTime() - startExtract;
+
+ double startPush = System.nanoTime();
pusher.pushFlowEntry(sw, flowEntry);
+ pushTime = System.nanoTime() - startPush;
}
/**
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/IFlowSyncService.java b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/IFlowSyncService.java
index 4e6efaf..4fe0857 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/IFlowSyncService.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/IFlowSyncService.java
@@ -1,7 +1,8 @@
package net.onrc.onos.ofcontroller.flowprogrammer;
+import java.util.concurrent.Future;
+
import net.floodlightcontroller.core.IOFSwitch;
-import net.floodlightcontroller.core.IOFSwitchListener;
import net.floodlightcontroller.core.module.IFloodlightService;
/**
@@ -11,7 +12,19 @@
*
*/
public interface IFlowSyncService extends IFloodlightService {
- public void synchronize(IOFSwitch sw);
+ public Future<SyncResult> synchronize(IOFSwitch sw);
public void interrupt(IOFSwitch sw);
+
+ public class SyncResult {
+ public final int flowAdded;
+ public final int flowRemoved;
+ public final int flowSkipped;
+
+ public SyncResult(int added, int removed, int skipped) {
+ flowAdded = added;
+ flowRemoved = removed;
+ flowSkipped = skipped;
+ }
+ }
}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/forwarding/Forwarding.java b/src/main/java/net/onrc/onos/ofcontroller/forwarding/Forwarding.java
index f33f986..3725d5e 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/forwarding/Forwarding.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/forwarding/Forwarding.java
@@ -3,9 +3,11 @@
import java.io.IOException;
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.concurrent.ConcurrentHashMap;
import net.floodlightcontroller.core.FloodlightContext;
import net.floodlightcontroller.core.IFloodlightProviderService;
@@ -46,28 +48,80 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-public class Forwarding implements IOFMessageListener, IFloodlightModule {
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Multimaps;
+
+public class Forwarding implements IOFMessageListener, IFloodlightModule,
+ IForwardingService {
private final static Logger log = LoggerFactory.getLogger(Forwarding.class);
private IFloodlightProviderService floodlightProvider;
private IFlowService flowService;
+ @SuppressWarnings("unused")
private IDatagridService datagridService;
private IDeviceStorage deviceStorage;
private TopologyManager topologyService;
- public Forwarding() {
+ private Map<Path, Long> pendingFlows;
+ private Multimap<Long, PacketToPush> waitingPackets;
+
+ public class PacketToPush {
+ public final OFPacketOut packet;
+ public final long dpid;
+ public PacketToPush(OFPacketOut packet, long dpid) {
+ this.packet = packet;
+ this.dpid = dpid;
+ }
+ }
+
+ public final class Path {
+ public final SwitchPort srcPort;
+ public final SwitchPort dstPort;
+
+ public Path(SwitchPort src, SwitchPort dst) {
+ srcPort = new SwitchPort(new Dpid(src.dpid().value()),
+ new Port(src.port().value()));
+ dstPort = new SwitchPort(new Dpid(dst.dpid().value()),
+ new Port(dst.port().value()));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof Path)) {
+ return false;
+ }
+
+ Path otherPath = (Path) other;
+ return srcPort.equals(otherPath.srcPort) &&
+ dstPort.equals(otherPath.dstPort);
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 17;
+ hash = 31 * hash + srcPort.hashCode();
+ hash = 31 * hash + dstPort.hashCode();
+ return hash;
+ }
}
@Override
public Collection<Class<? extends IFloodlightService>> getModuleServices() {
- return null;
+ List<Class<? extends IFloodlightService>> services =
+ new ArrayList<Class<? extends IFloodlightService>>(1);
+ services.add(IForwardingService.class);
+ return services;
}
@Override
public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
- return null;
+ Map<Class<? extends IFloodlightService>, IFloodlightService> impls =
+ new HashMap<Class<? extends IFloodlightService>, IFloodlightService>(1);
+ impls.put(IForwardingService.class, this);
+ return impls;
}
@Override
@@ -89,6 +143,10 @@
floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
+ pendingFlows = new ConcurrentHashMap<Path, Long>();
+ waitingPackets = Multimaps.synchronizedSetMultimap(
+ HashMultimap.<Long, PacketToPush>create());
+
deviceStorage = new DeviceStorageImpl();
deviceStorage.init("");
topologyService = new TopologyManager();
@@ -141,7 +199,8 @@
}
private void handlePacketIn(IOFSwitch sw, OFPacketIn pi, Ethernet eth) {
- String destinationMac = HexString.toHexString(eth.getDestinationMACAddress());
+ String destinationMac =
+ HexString.toHexString(eth.getDestinationMACAddress());
IDeviceObject deviceObject = deviceStorage.getDeviceByMac(
destinationMac);
@@ -151,7 +210,7 @@
return;
}
- Iterator<IPortObject> ports = deviceObject.getAttachedPorts().iterator();
+ Iterator<IPortObject> ports = deviceObject.getAttachedPorts().iterator();
if (!ports.hasNext()) {
log.debug("No attachment point found for device {}", destinationMac);
return;
@@ -171,46 +230,32 @@
MACAddress srcMacAddress = MACAddress.valueOf(eth.getSourceMACAddress());
MACAddress dstMacAddress = MACAddress.valueOf(eth.getDestinationMACAddress());
- if (flowExists(srcSwitchPort, srcMacAddress,
- dstSwitchPort, dstMacAddress)) {
- log.debug("Not adding flow because it already exists");
+
+ DataPath datapath = new DataPath();
+ datapath.setSrcPort(srcSwitchPort);
+ datapath.setDstPort(dstSwitchPort);
+
+
+
+ Path pathspec = new Path(srcSwitchPort, dstSwitchPort);
+ // TODO check concurrency
+ Long existingFlowId = pendingFlows.get(pathspec);
+
+ if (existingFlowId != null) {
+ log.debug("Found existing flow {}",
+ HexString.toHexString(existingFlowId));
- // TODO check reverse flow as well
-
- DataPath shortestPath =
- topologyService.getDatabaseShortestPath(srcSwitchPort, dstSwitchPort);
-
- if (shortestPath == null || shortestPath.flowEntries().isEmpty()) {
- log.warn("No path found between {} and {} - not handling packet",
- srcSwitchPort, dstSwitchPort);
- return;
- }
-
- Port outPort = shortestPath.flowEntries().get(0).outPort();
- forwardPacket(pi, sw, outPort.value());
+ // TODO do stuff.
+ OFPacketOut po = constructPacketOut(datapath, pi, sw);
+ waitingPackets.put(existingFlowId, new PacketToPush(po, sw.getId()));
return;
}
- // Calculate a shortest path before pushing flow mods.
- // This will be used later by the packet-out processing, but it uses
- // the database so will be slow, and we should do it before flow mods.
- DataPath shortestPath =
- topologyService.getDatabaseShortestPath(srcSwitchPort, dstSwitchPort);
-
- if (shortestPath == null || shortestPath.flowEntries().isEmpty()) {
- log.warn("No path found between {} and {} - not handling packet",
- srcSwitchPort, dstSwitchPort);
- return;
- }
log.debug("Adding new flow between {} at {} and {} at {}",
new Object[]{srcMacAddress, srcSwitchPort, dstMacAddress, dstSwitchPort});
- DataPath dataPath = new DataPath();
- dataPath.setSrcPort(srcSwitchPort);
- dataPath.setDstPort(dstSwitchPort);
-
CallerId callerId = new CallerId("Forwarding");
//FlowId flowId = new FlowId(flowService.getNextFlowEntryId());
@@ -226,18 +271,13 @@
// For now just forward IPv4 packets. This prevents accidentally
// forwarding other stuff like ARP.
flowPath.flowEntryMatch().enableEthernetFrameType(Ethernet.TYPE_IPv4);
- flowPath.setDataPath(dataPath);
+ flowPath.setDataPath(datapath);
- FlowId flowId = flowService.addFlow(flowPath);
- //flowService.addFlow(flowPath, flowId);
-
-
DataPath reverseDataPath = new DataPath();
// Reverse the ports for the reverse path
reverseDataPath.setSrcPort(dstSwitchPort);
reverseDataPath.setDstPort(srcSwitchPort);
- //FlowId reverseFlowId = new FlowId(flowService.getNextFlowEntryId());
// TODO implement copy constructor for FlowPath
FlowPath reverseFlowPath = new FlowPath();
//reverseFlowPath.setFlowId(reverseFlowId);
@@ -253,13 +293,25 @@
reverseFlowPath.dataPath().srcPort().dpid().toString();
// TODO what happens if no path exists?
- //flowService.addFlow(reverseFlowPath, reverseFlowId);
- FlowId reverseFlowId = flowService.addFlow(reverseFlowPath);
+ FlowId flowId = new FlowId(flowService.getNextFlowEntryId());
+ FlowId reverseFlowId = new FlowId(flowService.getNextFlowEntryId());
- Port outPort = shortestPath.flowEntries().get(0).outPort();
- forwardPacket(pi, sw, outPort.value());
+ flowPath.setFlowId(flowId);
+ reverseFlowPath.setFlowId(reverseFlowId);
+
+ OFPacketOut po = constructPacketOut(datapath, pi, sw);
+ Path reversePathSpec = new Path(dstSwitchPort, srcSwitchPort);
+
+ // Add to waiting lists
+ pendingFlows.put(pathspec, flowId.value());
+ pendingFlows.put(reversePathSpec, reverseFlowId.value());
+ waitingPackets.put(flowId.value(), new PacketToPush(po, sw.getId()));
+
+ flowService.addFlow(reverseFlowPath);
+ flowService.addFlow(flowPath);
}
+ /*
private boolean flowExists(SwitchPort srcPort, MACAddress srcMac,
SwitchPort dstPort, MACAddress dstMac) {
for (FlowPath flow : datagridService.getAllFlows()) {
@@ -285,17 +337,18 @@
return false;
}
+ */
- private void forwardPacket(OFPacketIn pi, IOFSwitch sw, short port) {
- List<OFAction> actions = new ArrayList<OFAction>(1);
- actions.add(new OFActionOutput(port));
+ private OFPacketOut constructPacketOut(DataPath datapath, OFPacketIn pi,
+ IOFSwitch sw) {
+ //List<OFAction> actions = new ArrayList<OFAction>(1);
+ //actions.add(new OFActionOutput(port));
OFPacketOut po = new OFPacketOut();
po.setInPort(OFPort.OFPP_NONE)
.setInPort(pi.getInPort())
- .setActions(actions)
- .setActionsLength((short)OFActionOutput.MINIMUM_LENGTH)
- .setLengthU(OFPacketOut.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
+ .setActions(new ArrayList<OFAction>())
+ .setLengthU(OFPacketOut.MINIMUM_LENGTH);
if (sw.getBuffers() == 0) {
po.setBufferId(OFPacketOut.BUFFER_ID_NONE)
@@ -306,11 +359,45 @@
po.setBufferId(pi.getBufferId());
}
- try {
- sw.write(po, null);
- sw.flush();
- } catch (IOException e) {
- log.error("Error writing packet out to switch: {}", e);
+ return po;
+ }
+
+ @Override
+ public void flowsInstalled(Collection<FlowPath> installedFlowPaths) {
+ for (FlowPath flowPath : installedFlowPaths) {
+ flowInstalled(flowPath);
+ }
+ }
+
+ private void flowInstalled(FlowPath installedFlowPath) {
+ // TODO check concurrency
+ // will need to sync and access both collections at once.
+ long flowId = installedFlowPath.flowId().value();
+ Collection<PacketToPush> packets = waitingPackets.removeAll(flowId);
+
+ //remove pending flows entry
+ Path pathToRemove = new Path(installedFlowPath.dataPath().srcPort(),
+ installedFlowPath.dataPath().dstPort());
+ pendingFlows.remove(pathToRemove);
+
+ for (PacketToPush packet : packets) {
+ IOFSwitch sw = floodlightProvider.getSwitches().get(packet.dpid);
+
+ OFPacketOut po = packet.packet;
+ short outPort =
+ installedFlowPath.flowEntries().get(0).outPort().value();
+ po.getActions().add(new OFActionOutput(outPort));
+ po.setActionsLength((short)
+ (po.getActionsLength() + OFActionOutput.MINIMUM_LENGTH));
+ po.setLengthU(po.getLengthU() + OFActionOutput.MINIMUM_LENGTH);
+
+ try {
+ sw.write(packet.packet, null);
+ sw.flush();
+ } catch (IOException e) {
+ log.error("Error writing packet out to switch {}:",
+ sw.getId(), e);
+ }
}
}
}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/forwarding/IForwardingService.java b/src/main/java/net/onrc/onos/ofcontroller/forwarding/IForwardingService.java
new file mode 100644
index 0000000..e5bd714
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/forwarding/IForwardingService.java
@@ -0,0 +1,25 @@
+package net.onrc.onos.ofcontroller.forwarding;
+
+import java.util.Collection;
+
+import net.floodlightcontroller.core.module.IFloodlightService;
+import net.onrc.onos.ofcontroller.util.FlowPath;
+
+/**
+ * Temporary interface that allows the Forwarding module to be
+ * notified when a flow has been installed by the FlowManager.
+ *
+ * This should be refactored to a listener framework in the future.
+ * @author jono
+ *
+ */
+public interface IForwardingService extends IFloodlightService {
+ /**
+ * Notify the Forwarding module that a collection of flows has been
+ * installed in the network.
+ *
+ * @param installedFlowPaths the collection of FlowPaths that have
+ * been installed in the network.
+ */
+ public void flowsInstalled(Collection<FlowPath> installedFlowPaths);
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ArpMessage.java b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ArpMessage.java
index 6ce5ade..ee8f23d 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ArpMessage.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ArpMessage.java
@@ -2,11 +2,7 @@
import java.io.Serializable;
import java.net.InetAddress;
-import java.util.ArrayList;
-import java.util.List;
-
import net.floodlightcontroller.util.MACAddress;
-import net.onrc.onos.ofcontroller.util.SwitchPort;
public class ArpMessage implements Serializable {
@@ -25,9 +21,8 @@
private final long outSwitch;
private final short outPort;
-
- private final List<SwitchPort> switchPorts = new ArrayList<SwitchPort>();
-
+
+
public enum Type {
REQUEST,
REPLY
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 b2b3c48..c53e8e1 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java
@@ -394,6 +394,7 @@
}
+ @SuppressWarnings("unused")
private void handleArpReply(IOFSwitch sw, OFPacketIn pi, ARP arp){
if (log.isTraceEnabled()) {
log.trace("ARP reply recieved: {} => {}, on {}/{}", new Object[] {
diff --git a/src/main/java/net/onrc/onos/ofcontroller/topology/ITopologyNetService.java b/src/main/java/net/onrc/onos/ofcontroller/topology/ITopologyNetService.java
index 9585366..4269eac 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/topology/ITopologyNetService.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/topology/ITopologyNetService.java
@@ -1,7 +1,5 @@
package net.onrc.onos.ofcontroller.topology;
-import java.util.Map;
-
import net.floodlightcontroller.core.module.IFloodlightService;
import net.onrc.onos.ofcontroller.util.DataPath;
import net.onrc.onos.ofcontroller.util.SwitchPort;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/topology/Topology.java b/src/main/java/net/onrc/onos/ofcontroller/topology/Topology.java
index dbf9ada..fc75591 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/topology/Topology.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/topology/Topology.java
@@ -265,6 +265,9 @@
break;
}
+ case ELEMENT_UNKNOWN:
+ // TODO: Adding "assert(false);" here can be dangerous
+ break;
}
return isModified;
@@ -315,6 +318,9 @@
}
break;
}
+ case ELEMENT_UNKNOWN:
+ // TODO: Adding "assert(false);" here can be dangerous
+ break;
}
return isModified;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/topology/TopologyElement.java b/src/main/java/net/onrc/onos/ofcontroller/topology/TopologyElement.java
index b01c7d3..0fefa3a 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/topology/TopologyElement.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/topology/TopologyElement.java
@@ -1,8 +1,5 @@
package net.onrc.onos.ofcontroller.topology;
-import java.util.Map;
-import java.util.TreeMap;
-
/**
* Class for storing information about a Topology Element: Switch, Port or
* Link.
@@ -165,6 +162,8 @@
return "Link=" +
Long.toHexString(fromSwitchDpid) + "/" + fromSwitchPort + "/" +
Long.toHexString(toSwitchDpid) + "/" + toSwitchPort;
+ case ELEMENT_UNKNOWN:
+ return "Element=UNKNOWN";
}
assert(false);
diff --git a/src/main/java/net/onrc/onos/ofcontroller/topology/TopologyManager.java b/src/main/java/net/onrc/onos/ofcontroller/topology/TopologyManager.java
index c0e04f2..02e0ffb 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/topology/TopologyManager.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/topology/TopologyManager.java
@@ -225,8 +225,12 @@
SwitchPort dest = flowPath.dataPath().dstPort();
return ShortestPath.getTopologyShortestPath(topology, src, dest);
}
+
case FP_TYPE_EXPLICIT_PATH:
return flowPath.dataPath();
+
+ case FP_TYPE_UNKNOWN:
+ return null;
}
return null;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/topology/web/RouteResource.java b/src/main/java/net/onrc/onos/ofcontroller/topology/web/RouteResource.java
index 0d33b27..d8997dc 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/topology/web/RouteResource.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/topology/web/RouteResource.java
@@ -2,7 +2,6 @@
import net.onrc.onos.ofcontroller.flowmanager.IFlowService;
import net.onrc.onos.ofcontroller.topology.ITopologyNetService;
-import net.onrc.onos.ofcontroller.topology.TopologyManager;
import net.onrc.onos.ofcontroller.util.DataPath;
import net.onrc.onos.ofcontroller.util.Dpid;
import net.onrc.onos.ofcontroller.util.Port;
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 98dbd88..c8b206f 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntry.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntry.java
@@ -13,6 +13,8 @@
public class FlowEntry {
private FlowId flowId; // FlowID of the Flow Entry
private FlowEntryId flowEntryId; // The Flow Entry ID
+ private int idleTimeout; // The Flow idle timeout
+ private int hardTimeout; // The Flow hard timeout
private FlowEntryMatch flowEntryMatch; // The Flow Entry Match
private FlowEntryActions flowEntryActions; // The Flow Entry Actions
private Dpid dpid; // The Switch DPID
@@ -174,6 +176,54 @@
}
/**
+ * Get the flow idle timeout in seconds.
+ *
+ * It should be an unsigned integer in the interval [0, 65535].
+ * If zero, the timeout is not set.
+ *
+ * @return the flow idle timeout.
+ */
+ @JsonProperty("idleTimeout")
+ public int idleTimeout() { return idleTimeout; }
+
+ /**
+ * Set the flow idle timeout in seconds.
+ *
+ * It should be an unsigned integer in the interval [0, 65535].
+ * If zero, the timeout is not set.
+ *
+ * @param idleTimeout the flow idle timeout to set.
+ */
+ @JsonProperty("idleTimeout")
+ public void setIdleTimeout(int idleTimeout) {
+ this.idleTimeout = 0xffff & idleTimeout;
+ }
+
+ /**
+ * Get the flow hard timeout in seconds.
+ *
+ * It should be an unsigned integer in the interval [0, 65535].
+ * If zero, the timeout is not set.
+ *
+ * @return the flow hard timeout.
+ */
+ @JsonProperty("hardTimeout")
+ public int hardTimeout() { return hardTimeout; }
+
+ /**
+ * Set the flow hard timeout in seconds.
+ *
+ * It should be an unsigned integer in the interval [0, 65535].
+ * If zero, the timeout is not set.
+ *
+ * @param hardTimeout the flow hard timeout to set.
+ */
+ @JsonProperty("hardTimeout")
+ public void setHardTimeout(int hardTimeout) {
+ this.hardTimeout = 0xffff & hardTimeout;
+ }
+
+ /**
* Get the Flow Entry Match.
*
* @return the Flow Entry Match.
@@ -343,7 +393,8 @@
* Convert the flow entry to a string.
*
* The string has the following form:
- * [flowEntryId=XXX flowEntryMatch=XXX flowEntryActions=XXX dpid=XXX
+ * [flowEntryId=XXX idleTimeout=XXX hardTimeout=XXX
+ * flowEntryMatch=XXX flowEntryActions=XXX dpid=XXX
* inPort=XXX outPort=XXX flowEntryUserState=XXX flowEntrySwitchState=XXX
* flowEntryErrorState=XXX]
* @return the flow entry as a string.
@@ -359,10 +410,12 @@
if ( flowId != null ) {
ret.append(" flowId=" + this.flowId.toString());
}
+ ret.append(" idleTimeout=" + this.idleTimeout);
+ ret.append(" hardTimeout=" + this.hardTimeout);
if ( flowEntryMatch != null ) {
ret.append(" flowEntryMatch=" + this.flowEntryMatch.toString());
}
- ret.append( " flowEntryActions=" + this.flowEntryActions.toString() );
+ ret.append(" flowEntryActions=" + this.flowEntryActions.toString() );
if ( dpid != null ) {
ret.append(" dpid=" + this.dpid.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 a1163c8..e431f8a 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntryAction.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntryAction.java
@@ -43,6 +43,13 @@
private ActionValues(short value) {
this.value = value;
}
+
+ /**
+ * Get the value.
+ *
+ * @return the value.
+ */
+ public short getValue() { return value; }
}
/**
@@ -1564,6 +1571,9 @@
case ACTION_ENQUEUE:
ret += " action=" + actionEnqueue.toString();
break;
+ case ACTION_VENDOR:
+ ret += " action=VENDOR";
+ break;
}
ret += "]";
@@ -1656,6 +1666,9 @@
case ACTION_ENQUEUE:
actionEnqueue = new ActionEnqueue(decode);
break;
+ case ACTION_VENDOR:
+ // TODO: Handle it as appropriate
+ break;
}
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("Invalid action string");
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 ab3edb1..7c87a10 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/FlowPath.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/FlowPath.java
@@ -18,7 +18,9 @@
private FlowPathType flowPathType; // The Flow Path type
private FlowPathUserState flowPathUserState; // The Flow Path User state
private FlowPathFlags flowPathFlags; // The Flow Path flags
- private DataPath dataPath; // The data path
+ private int idleTimeout; // The Flow idle timeout
+ private int hardTimeout; // The Flow hard timeout
+ 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
@@ -45,6 +47,8 @@
this.setFlowPathType(FlowPathType.valueOf(flowObj.getFlowPathType()));
this.setFlowPathUserState(FlowPathUserState.valueOf(flowObj.getFlowPathUserState()));
this.setFlowPathFlags(new FlowPathFlags(flowObj.getFlowPathFlags()));
+ this.setIdleTimeout(flowObj.getIdleTimeout());
+ this.setHardTimeout(flowObj.getHardTimeout());
this.dataPath().srcPort().setDpid(new Dpid(flowObj.getSrcSwitch()));
this.dataPath().srcPort().setPort(new Port(flowObj.getSrcPort()));
this.dataPath().dstPort().setDpid(new Dpid(flowObj.getDstSwitch()));
@@ -295,6 +299,54 @@
}
/**
+ * Get the flow idle timeout in seconds.
+ *
+ * It should be an unsigned integer in the interval [0, 65535].
+ * If zero, the timeout is not set.
+ *
+ * @return the flow idle timeout.
+ */
+ @JsonProperty("idleTimeout")
+ public int idleTimeout() { return idleTimeout; }
+
+ /**
+ * Set the flow idle timeout in seconds.
+ *
+ * It should be an unsigned integer in the interval [0, 65535].
+ * If zero, the timeout is not set.
+ *
+ * @param idleTimeout the flow idle timeout to set.
+ */
+ @JsonProperty("idleTimeout")
+ public void setIdleTimeout(int idleTimeout) {
+ this.idleTimeout = 0xffff & idleTimeout;
+ }
+
+ /**
+ * Get the flow hard timeout in seconds.
+ *
+ * It should be an unsigned integer in the interval [0, 65535].
+ * If zero, the timeout is not set.
+ *
+ * @return the flow hard timeout.
+ */
+ @JsonProperty("hardTimeout")
+ public int hardTimeout() { return hardTimeout; }
+
+ /**
+ * Set the flow hard timeout.
+ *
+ * It should be an unsigned integer in the interval [0, 65535].
+ * If zero, the timeout is not set.
+ *
+ * @param hardTimeout the flow hard timeout to set.
+ */
+ @JsonProperty("hardTimeout")
+ public void setHardTimeout(int hardTimeout) {
+ this.hardTimeout = 0xffff & hardTimeout;
+ }
+
+ /**
* Get the flow path's data path.
*
* @return the flow path's data path.
@@ -366,8 +418,8 @@
*
* The string has the following form:
* [flowId=XXX installerId=XXX flowPathType = XXX flowPathUserState = XXX
- * flowPathFlags=XXX dataPath=XXX flowEntryMatch=XXX
- * flowEntryActions=XXX]
+ * flowPathFlags=XXX idleTimeout=XXX hardTimeout=XXX dataPath=XXX
+ * flowEntryMatch=XXX flowEntryActions=XXX]
*
* @return the flow path as a string.
*/
@@ -378,6 +430,8 @@
ret += " flowPathType=" + this.flowPathType;
ret += " flowPathUserState=" + this.flowPathUserState;
ret += " flowPathFlags=" + this.flowPathFlags.toString();
+ ret += " idleTimeout=" + this.idleTimeout;
+ ret += " hardTimeout=" + this.hardTimeout;
if (dataPath != null)
ret += " dataPath=" + this.dataPath.toString();
if (flowEntryMatch != null)
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/FlowPathFlags.java b/src/main/java/net/onrc/onos/ofcontroller/util/FlowPathFlags.java
index 4bbd399..595eb5f 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/FlowPathFlags.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/FlowPathFlags.java
@@ -112,8 +112,6 @@
// 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) {
@@ -121,6 +119,8 @@
flagsStr += ",";
flagsStr += "KEEP_ONLY_FIRST_HOP_ENTRY";
}
+ if (flagsStr != null)
+ ret += flagsStr;
ret += "]";
return ret;