merged
diff --git a/perf-scripts/flow-sync-perf.py b/perf-scripts/flow-sync-perf.py
new file mode 100755
index 0000000..d552404
--- /dev/null
+++ b/perf-scripts/flow-sync-perf.py
@@ -0,0 +1,194 @@
+#!/usr/bin/python
+'''
+ Script that tests Flow Synchronizer performance
+ Author: Brian O'Connor <bocon@onlab.us>
+
+ Usage: 
+   1. Ensure that ONOS is running
+   2. sudo ./flow-sync-perf.sh <list of tests>
+      e.g. sudo ./flow-sync-perf.sh 1 10 100 1000 
+      or to run the default tests:
+      sudo ./flow-sync-perf.sh
+   3. Results are CSV files in a date stamped directory
+'''
+
+import csv
+import os
+import sys
+from time import sleep, strftime
+from subprocess import Popen, call, check_output, PIPE
+from mininet.net import Mininet
+from mininet.topo import SingleSwitchTopo
+from mininet.node import RemoteController
+from mininet.cli import CLI
+from mininet.log import setLogLevel
+try:
+  import pexpect
+except:
+  # install pexpect if it cannot be found and re-import
+  print '* Installing Pexpect'
+  call( 'apt-get install -y python-pexpect', stdout=PIPE, shell=True )
+  import pexpect
+
+ONOS_HOME = '..'
+
+# Verify that tcpkill is installed
+if not Popen( 'which tcpkill', stdout=PIPE, shell=True).communicate():
+  print '* Installing tcpkill'
+  call( 'apt-get install -y dsniff', stdout=PIPE, shell=True )
+
+# ----------------- Tests scenarios -------------------------
+def doNothing(n):
+  print "Doing nothing with %d flows..." % n
+
+def addFakeFlows(n):
+  print "Adding %d random flows..." % n
+  for i in range( 1, (n+1) ):
+    a = i / (256*256) % 256
+    b = i / 256 % 256
+    c = i % 256
+    ip = '10.%d.%d.%d' % (a,b,c)
+    call( 'ovs-ofctl add-flow s1 "ip, nw_src=%s/32, idle_timeout=0, hard_timeout=0, cookie=%d, actions=output:2"' % ( ip, i ), shell=True )
+
+def delFlowsFromSwitch(n):
+  print "Removing all %d flows from switch..." % n
+  call( 'ovs-ofctl del-flows s1', shell=True )
+
+
+# ----------------- Utility Functions -------------------------
+def disconnect():
+  tail = Popen( "exec tail -0f ../onos-logs/onos.onosdev1.log", stdout=PIPE, shell=True )
+  tcp  = Popen( 'exec tcpkill -i lo -9 port 6633 > /dev/null 2>&1', shell=True )
+  tcp  = Popen( 'exec tcpkill -i lo -9 port 6633 > /tmp/tcp 2>&1', shell=True )
+  sleep(1)
+  tcp.kill()
+  results = waitForResult(tail)
+  tail.kill()
+  return results
+
+def startNet(net):
+  tail = pexpect.spawn( 'tail -0f %s/onos-logs/onos.onosdev1.log' % ONOS_HOME )
+  net.start()
+  index = tail.expect(['Sync time \(ms\)', pexpect.EOF, pexpect.TIMEOUT])
+  if index >= 1:
+    print '* ONOS not started'
+    net.stop()
+    exit(1)
+  tail.terminate()
+
+def dumpFlows():
+  return check_output( 'ovs-ofctl dump-flows s1', shell=True )
+
+def addFlowsToONOS(n):
+  call( './generate_flows.py 1 %d > /tmp/flows.txt' % n, shell=True )
+  call( '%s/web/add_flow.py -m onos -f /tmp/flows.txt' % ONOS_HOME, shell=True )
+  while True:
+    output = check_output( 'ovs-ofctl dump-flows s1', shell=True )
+    lines = len(output.split('\n'))
+    if lines >= (n+2):
+      break
+    sleep(1)
+  count = 0
+  while True:
+    output = pexpect.spawn( '%s/web/get_flow.py all' % ONOS_HOME )
+    while count < n:
+      if output.expect(['FlowEntry', pexpect.EOF], timeout=2000) == 1:
+        break
+      count += 1 
+      return
+    sleep(5)
+
+def removeFlowsFromONOS():
+  call( '%s/web/delete_flow.py all' % ONOS_HOME, shell=True )
+  while True:
+    output = check_output( 'ovs-ofctl dump-flows s1', shell=True )
+    lines = len(output.split('\n'))
+    if lines == 2:
+      break
+    sleep(1)
+  while True:
+    output = pexpect.spawn( '%s/web/get_flow.py all' % ONOS_HOME )
+    if output.expect(['FlowEntry', pexpect.EOF], timeout=2000) == 1:
+      break
+    sleep(5)
+
+
+# ----------------- Running the test and output  -------------------------
+def test(i, fn):
+  # Start tailing the onos log
+  tail = pexpect.spawn( "tail -0f %s/onos-logs/onos.onosdev1.log" % ONOS_HOME )
+  # disconnect the switch from the controller using tcpkill
+  tcp  = Popen( 'exec tcpkill -i lo -9 port 6633 > /dev/null 2>&1', shell=True )
+  # wait until the switch has been disconnected
+  tail.expect( 'Switch removed' )
+  # call the test function
+  fn(i) 
+  # dump to flows to ensure they have all made it to ovs
+  dumpFlows() 
+  # end tcpkill process to reconnect the switch to the controller
+  tcp.terminate()
+  tail.expect('Sync time \(ms\):', timeout=6000)
+  tail.expect('([\d.]+,?)+\s')
+  print tail.match.group(0)
+  tail.terminate()
+  sleep(3)
+  return tail.match.group(0).strip().split(',')
+
+def initResults(files):
+  headers = ['# of FEs', 'Flow IDs from Graph', 'FEs from Switch', 'Compare', 
+             'Read FE from graph', 'Extract FE', 'Push', 'Total' ]
+  for filename in files.values():
+    with open(filename, 'w') as csvfile:
+      writer = csv.writer(csvfile)
+      writer.writerow(headers)
+
+def outputResults(filename, n, results):
+  results.insert(0, n)
+  print results
+  with open(filename, 'a') as csvfile:
+    writer = csv.writer(csvfile)
+    writer.writerow(results)
+
+def runPerf( resultDir, tests):
+  fileMap = { 'add':    os.path.join(resultDir, 'add.csv'),
+              'delete': os.path.join(resultDir, 'delete.csv'),
+              'sync':   os.path.join(resultDir, 'sync.csv') }
+  initResults(fileMap)
+  # start Mininet
+  topo = SingleSwitchTopo()
+  net = Mininet(topo=topo, controller=RemoteController)
+  startNet(net)
+  removeFlowsFromONOS() # clear ONOS before starting
+  sleep(30) # let ONOS "warm-up"
+  for i in tests:
+    addFlowsToONOS(i)
+    outputResults(fileMap['sync'],   i, test(i, doNothing))
+    outputResults(fileMap['delete'], i, test(i, delFlowsFromSwitch))
+    removeFlowsFromONOS()
+    outputResults(fileMap['add'],    i, test(i, addFakeFlows)) # test needs empty DB
+  net.stop()
+
+def waitForResult(tail):
+  while True:
+    line = tail.stdout.readline()
+    index = line.find('n.o.o.o.f.FlowSynchronizer')
+    if index > 0:
+      print line,
+    index = line.find('Sync time (ms):')
+    if index > 0:
+      line = line[index + 15:].strip()
+      line = line.replace('-->', '')
+      return line.split() # graph, switch, compare, total
+
+if __name__ == '__main__':
+  setLogLevel( 'output' )
+  resultDir = strftime( '%Y%m%d-%H%M%S' )
+  os.mkdir( resultDir )
+  tests = sys.argv[1:]
+  if not tests:
+    tests = [1, 10, 100, 1000, 10000]
+  runPerf( resultDir, tests )
+
+exit()
+
+# ---------------------------
diff --git a/perf-scripts/generate_flows.py b/perf-scripts/generate_flows.py
new file mode 100755
index 0000000..11d9c19
--- /dev/null
+++ b/perf-scripts/generate_flows.py
@@ -0,0 +1,90 @@
+#! /usr/bin/env python
+# -*- Mode: python; py-indent-offset: 4; tab-width: 8; indent-tabs-mode: t; -*-
+
+#
+# A script for generating a number of flows.
+#
+# The output of the script should be saved to a file, and the flows from
+# that file should be added by the following command:
+#
+#   web/add_flow.py -f filename
+# 
+# NOTE: Currently, some of the parameters fo the flows are hard-coded,
+# and all flows are between same source and destination DPID and ports
+# (differentiated by different matchSrcMac and matchDstMac).
+#
+
+import copy
+import pprint
+import os
+import sys
+import subprocess
+import json
+import argparse
+import io
+import time
+
+## Global Var ##
+
+DEBUG=0
+pp = pprint.PrettyPrinter(indent=4)
+
+## Worker Functions ##
+def log_error(txt):
+  print '%s' % (txt)
+
+def debug(txt):
+  if DEBUG:
+    print '%s' % (txt)
+
+
+if __name__ == "__main__":
+  usage_msg = "Generate a number of flows by using a pre-defined template.\n"
+  usage_msg = usage_msg + "\n"
+  usage_msg = usage_msg + "NOTE: This script is work-in-progress. Currently all flows are within same\n"
+  usage_msg = usage_msg + "pair of switch ports and contain auto-generated MAC-based matching conditions.\n"
+  usage_msg = usage_msg + "\n"
+  usage_msg = usage_msg + "Usage: %s <begin-flow-id> <end-flow-id>\n" % (sys.argv[0])
+  usage_msg = usage_msg + "\n"
+  usage_msg = usage_msg + "    The output should be saved to a file, and the flows should be installed\n"
+  usage_msg = usage_msg + "    by using the command './add_flow.py -f filename'\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) < 3:
+    log_error(usage_msg)
+    exit(1)
+
+  # Extract the arguments
+  begin_flow_id = int(sys.argv[1], 0)
+  end_flow_id = int(sys.argv[2], 0)
+  if begin_flow_id > end_flow_id:
+    log_error(usage_msg)
+    exit(1)
+
+  #
+  # Do the work
+  #
+  # NOTE: Currently, up to 65536 flows are supported.
+  # More flows can be supported by iterating by, say, iterating over some of
+  # the other bytes of the autogenereated source/destination MAC addresses.
+  #
+  flow_id = begin_flow_id
+  idx = 0
+  while flow_id <= end_flow_id:
+    mac3 = idx / 255
+    mac4 = idx % 255
+    str_mac3 = "%0.2x" % mac3
+    str_mac4 = "%0.2x" % mac4
+    src_mac = "00:00:" + str_mac3 + ":" + str_mac4 + ":00:00";
+    dst_mac = "00:01:" + str_mac3 + ":" + str_mac4 + ":00:00";
+    print "%s FOOBAR 00:00:00:00:00:00:00:01 1 00:00:00:00:00:00:00:01 2 matchSrcMac %s matchDstMac %s" % (flow_id, src_mac, dst_mac)
+    flow_id = flow_id + 1
+    idx = idx + 1
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..256a98e 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjects.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjects.java
@@ -251,6 +251,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 +419,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/flowmanager/FlowDatabaseOperation.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowDatabaseOperation.java
index 1babafa..c8fd56f 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowDatabaseOperation.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowDatabaseOperation.java
@@ -90,6 +90,8 @@
 	// - flowPath.flowPathType()
 	// - flowPath.flowPathUserState()
 	// - flowPath.flowPathFlags()
+	// - flowPath.idleTimeout()
+	// - flowPath.hardTimeout()
 	// - flowPath.dataPath().srcPort()
 	// - flowPath.dataPath().dstPort()
 	// - flowPath.matchSrcMac()
@@ -109,6 +111,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 +229,8 @@
 	// - InPort edge
 	// - OutPort edge
 	//
+	// - flowEntry.idleTimeout()
+	// - flowEntry.hardTimeout()
 	// - flowEntry.dpid()
 	// - flowEntry.flowEntryUserState()
 	// - flowEntry.flowEntrySwitchState()
@@ -245,6 +251,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 +517,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 +529,8 @@
 	    (flowPathType == null) ||
 	    (flowPathUserState == null) ||
 	    (flowPathFlags == null) ||
+	    (idleTimeout == null) ||
+	    (hardTimeout == null) ||
 	    (srcSwitchStr == null) ||
 	    (srcPortShort == null) ||
 	    (dstSwitchStr == null) ||
@@ -533,6 +545,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 +625,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..49ec46a 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowEventHandler.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowEventHandler.java
@@ -700,6 +700,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/flowprogrammer/FlowProgrammer.java b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowProgrammer.java
index 461d231..f7d7b0e 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowProgrammer.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowProgrammer.java
@@ -44,7 +44,7 @@
 				       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;
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..630d0f4 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowPusher.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowPusher.java
@@ -68,8 +68,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,
@@ -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 415b1b1..64f6cac 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowSynchronizer.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowSynchronizer.java
@@ -93,17 +93,45 @@
 	    this.swObj = dbHandler.searchSwitch(dpid.toString());
 	}
 
+	double graphIDTime, switchTime, compareTime, graphEntryTime, extractTime, pushTime, totalTime;
 	@Override
 	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();
+	    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;
+	    log.debug("Sync time (ms):" +
+	    		  graphIDTime + "," +
+	     		  switchTime + "," + 
+	    		  compareTime + "," +
+	     		  graphEntryTime + "," +
+	    		  extractTime + "," + 
+	     		  pushTime + "," +
+	              totalTime);
+	}
 
 	/**
 	 * Compare flows entries in GraphDB and switch to pick up necessary
@@ -128,6 +156,9 @@
 	    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 + ", " +
@@ -223,6 +254,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 {}", 
@@ -230,6 +262,7 @@
 		return;
 	    }
 
+	    double startDB = System.nanoTime();
 	    // Get the Flow Entry state from the Network Graph
 	    IFlowEntry iFlowEntry = null;
 	    try {
@@ -244,7 +277,9 @@
 			  flowEntryId, sw.getId());
 		return;
 	    }
+	    dbTime = System.nanoTime() - startDB;
 
+	    double startExtract = System.nanoTime();
 	    FlowEntry flowEntry =
 		FlowDatabaseOperation.extractFlowEntry(iFlowEntry);
 	    if (flowEntry == null) {
@@ -252,8 +287,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/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/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/test/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjectsIFlowEntryTest.java b/src/test/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjectsIFlowEntryTest.java
index 06d8522..f1c2c71 100644
--- a/src/test/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjectsIFlowEntryTest.java
+++ b/src/test/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjectsIFlowEntryTest.java
@@ -78,6 +78,38 @@
 		flowEntry.setFlowEntryId(flowEntryId);
 		assertEquals(flowEntry.getFlowEntryId(), flowEntryId);
 	}
+
+	/**
+	 * Desc:
+	 *  Test method for set and get Idle Timeout.
+	 * Condition:
+	 *  N/A
+	 * Expect:
+	 * 1. Should set Idle Timeout.
+	 * 2. Should get Idle Timeout.
+	 */
+	@Test
+	public void testSetGetIdleTimeout() {
+		Integer idleTimeout = 5;
+		flowEntry.setIdleTimeout(idleTimeout);
+		assertEquals(flowEntry.getIdleTimeout(), idleTimeout);
+	}
+
+	/**
+	 * Desc:
+	 *  Test method for set and get Hard Timeout.
+	 * Condition:
+	 *  N/A
+	 * Expect:
+	 * 1. Should set Hard Timeout.
+	 * 2. Should get Hard Timeout.
+	 */
+	@Test
+	public void testSetGetHardTimeout() {
+		Integer hardTimeout = 5;
+		flowEntry.setHardTimeout(hardTimeout);
+		assertEquals(flowEntry.getHardTimeout(), hardTimeout);
+	}
 	
 	/**
 	 * Desc:
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 9a1e34a..39e4955 100644
--- a/src/test/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjectsIFlowPathTest.java
+++ b/src/test/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjectsIFlowPathTest.java
@@ -158,6 +158,42 @@
 
 	/**
 	 * Desc:
+	 *  Test method for get and set Idle Timeout method.
+	 * Condition:
+	 *  N/A
+	 * Expect:
+	 * 1. Should set the Idle Timeout.
+	 * 2. Should get the Idle Timeout.
+	 */
+	@Test
+	public void testSetGetIdleTimeout() {
+		String flowId = "xx";
+		Integer idleTimeout = 5;
+		flowPath.setFlowId(flowId);
+		flowPath.setIdleTimeout(idleTimeout);
+		assertEquals(flowPath.getIdleTimeout(), idleTimeout);
+	}
+
+	/**
+	 * Desc:
+	 *  Test method for get and set Hard Timeout method.
+	 * Condition:
+	 *  N/A
+	 * Expect:
+	 * 1. Should set the Hard Timeout.
+	 * 2. Should get the Hard Timeout.
+	 */
+	@Test
+	public void testSetGetHardTimeout() {
+		String flowId = "xx";
+		Integer hardTimeout = 5;
+		flowPath.setFlowId(flowId);
+		flowPath.setHardTimeout(hardTimeout);
+		assertEquals(flowPath.getHardTimeout(), hardTimeout);
+	}
+
+	/**
+	 * Desc:
 	 *  Test method for get and set SourceSwitch method.
 	 * Condition:
 	 *  N/A
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 d7724ae..03418c8 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
@@ -456,6 +456,8 @@
 		private String flowPathType;
 		private String flowPathUserState;
 		private Long flowPathFlags;
+		private Integer idleTimeout;
+		private Integer hardTimeout;
 		private String dataPathSummary;
 		private Short srcPort,dstPort;
 		private String matchSrcMac,matchDstMac;
@@ -474,6 +476,8 @@
 		private String flowPathTypeToUpdate;
 		private String flowPathUserStateToUpdate;
 		private Long flowPathFlagsToUpdate;
+		private Integer idleTimeoutToUpdate;
+		private Integer hardTimeoutToUpdate;
 		private String dataPathSummaryToUpdate;
 		private Short srcPortToUpdate,dstPortToUpdate;
 		private String matchSrcMacToUpdate,matchDstMacToUpdate;
@@ -514,6 +518,8 @@
 			if(flowPathTypeToUpdate != null) { flowPathType = flowPathTypeToUpdate; }
 			if(flowPathUserStateToUpdate != null) { flowPathUserState = flowPathUserStateToUpdate; }
 			if(flowPathFlagsToUpdate != null) { flowPathFlags = flowPathFlagsToUpdate; }
+			if(idleTimeoutToUpdate != null) { idleTimeout = idleTimeoutToUpdate; }
+			if(hardTimeoutToUpdate != null) { hardTimeout = hardTimeoutToUpdate; }
 			if(srcSwToUpdate != null) { srcSw = srcSwToUpdate; }
 			if(dstSwToUpdate != null) { dstSw = dstSwToUpdate; }
 			if(dataPathSummaryToUpdate != null) { dataPathSummary = dataPathSummaryToUpdate; }
@@ -545,6 +551,8 @@
 			flowPathTypeToUpdate = null;
 			flowPathUserStateToUpdate = null;
 			flowPathFlagsToUpdate = null;
+			idleTimeoutToUpdate = null;
+			hardTimeoutToUpdate = null;
 			srcSwToUpdate = dstSwToUpdate = dataPathSummaryToUpdate = null;
 			srcPortToUpdate = dstPortToUpdate = null;
 			matchSrcMacToUpdate = matchDstMacToUpdate = null;
@@ -565,6 +573,8 @@
 		public void setFlowPathTypeForTest(String flowPathType) { this.flowPathType = flowPathType; }
 		public void setFlowPathUserStateForTest(String flowPathUserState) { this.flowPathUserState = flowPathUserState; }
 		public void setFlowPathFlagsForTest(Long flowPathFlags) { this.flowPathFlags = flowPathFlags; }
+		public void setIdleTimeoutForTest(Integer idleTimeout) { this.idleTimeout = idleTimeout; }
+		public void setHardTimeoutForTest(Integer hardTimeout) { this.hardTimeout = hardTimeout; }
 		public void setSrcSwForTest(String srcSw) { this.srcSw = srcSw; }
 		public void setDstSwForTest(String dstSw) { this.dstSw = dstSw; }
 		public void setDataPathSummaryForTest(String dataPathSummary) { this.dataPathSummary = dataPathSummary; }
@@ -634,6 +644,18 @@
 		public void setFlowPathFlags(Long flowPathFlags) { flowPathFlagsToUpdate = flowPathFlags; }
 
 		@Override
+		public Integer getIdleTimeout() { return idleTimeout; }
+
+		@Override
+		public void setIdleTimeout(Integer idleTimeout) { idleTimeoutToUpdate = idleTimeout; }
+
+		@Override
+		public Integer getHardTimeout() { return hardTimeout; }
+
+		@Override
+		public void setHardTimeout(Integer hardTimeout) { hardTimeoutToUpdate = hardTimeout; }
+
+		@Override
 		public String getSrcSwitch() { return srcSw; }
 
 		@Override
@@ -768,6 +790,8 @@
 
 	public static class TestFlowEntry implements IFlowEntry {
 		private String state,type,entryId,dpid,userState,switchState,errorStateType,errorStateCode;
+		private Integer idleTimeout;
+		private Integer hardTimeout;
 		private Short matchInPort;
 		private String matchSrcMac,matchDstMac;
 		private Short matchEtherFrameType;
@@ -785,6 +809,8 @@
 	
 		private String stateToUpdate,typeToUpdate,entryIdToUpdate,dpidToUpdate,
 			userStateToUpdate,switchStateToUpdate,errorStateTypeToUpdate,errorStateCodeToUpdate;
+		private Integer idleTimeoutToUpdate;
+		private Integer hardTimeoutToUpdate;
 		private Short matchInPortToUpdate;
 		private String matchSrcMacToUpdate,matchDstMacToUpdate;
 		private Short matchEtherFrameTypeToUpdate;
@@ -810,6 +836,8 @@
 			if(stateToUpdate != null) { state = stateToUpdate; }
 			if(typeToUpdate != null) { type = typeToUpdate; }
 			if(entryIdToUpdate != null) { entryId = entryIdToUpdate; }
+			if(idleTimeoutToUpdate != null) { idleTimeout = idleTimeoutToUpdate; }
+			if(hardTimeoutToUpdate != null) { hardTimeout = hardTimeoutToUpdate; }
 			if(dpidToUpdate != null) { dpid = dpidToUpdate; }
 			if(userStateToUpdate != null) { userState = userStateToUpdate; }
 			if(switchStateToUpdate != null) { switchState = switchStateToUpdate; }
@@ -844,6 +872,7 @@
 		
 		public void clearUncommitedData() {
 			stateToUpdate = typeToUpdate = entryIdToUpdate = dpidToUpdate = null;
+			idleTimeoutToUpdate = hardTimeoutToUpdate = null;
 			userStateToUpdate = switchStateToUpdate = errorStateTypeToUpdate = errorStateCodeToUpdate = null;
 			matchInPortToUpdate = null;
 			matchSrcMacToUpdate = matchDstMacToUpdate = null;
@@ -864,6 +893,8 @@
 		public void setStateForTest(String state) { this.state = state; }
 		public void setTypeForTest(String type) { this.type = type; }
 		public void setEntryIdForTest(String entryId) { this.entryId = entryId; }
+		public void setIdleTimeoutForTest(Integer idleTimeout) { this.idleTimeout = idleTimeout; }
+		public void setHardTimeoutForTest(Integer hardTimeout) { this.hardTimeout = hardTimeout; }
 		public void setDpidForTest(String dpid) { this.dpid = dpid; }
 		public void setUserStateForTest(String userState) { this.userState = userState; }
 		public void setSwitchStateForTest(String switchState) { this.switchState = switchState; }
@@ -911,6 +942,18 @@
 	
 		@Override
 		public void setFlowEntryId(String flowEntryId) { entryIdToUpdate = flowEntryId; }
+
+		@Override
+		public Integer getIdleTimeout() { return idleTimeout; }
+	
+		@Override
+		public void setIdleTimeout(Integer idleTimeout) { idleTimeoutToUpdate = idleTimeout; }
+
+		@Override
+		public Integer getHardTimeout() { return hardTimeout; }
+	
+		@Override
+		public void setHardTimeout(Integer hardTimeout) { hardTimeoutToUpdate = hardTimeout; }
 	
 		@Override
 		public String getSwitchDpid() { return dpid; }
diff --git a/src/test/java/net/onrc/onos/ofcontroller/util/FlowEntryTest.java b/src/test/java/net/onrc/onos/ofcontroller/util/FlowEntryTest.java
index fc17178..696f9e5 100644
--- a/src/test/java/net/onrc/onos/ofcontroller/util/FlowEntryTest.java
+++ b/src/test/java/net/onrc/onos/ofcontroller/util/FlowEntryTest.java
@@ -13,6 +13,8 @@
 	
 	FlowId flowId = new FlowId(0x1234);
 	FlowEntryId flowEntryId = new FlowEntryId(0x5678);
+	int idleTimeout = 5;
+	int hardTimeout = 10;
 	FlowEntryMatch match;
 	FlowEntryActions actions;
 	
@@ -50,6 +52,9 @@
 
 		flowEntryId = new FlowEntryId("0x5678");
 		entry.setFlowEntryId(flowEntryId);
+
+		entry.setIdleTimeout(5);
+		entry.setHardTimeout(10);
 		
 		dpid = new Dpid("CA:FE");
 		entry.setDpid( dpid );
@@ -188,6 +193,16 @@
 	}
 
 	@Test
+	public void testIdleTimeout(){
+		assertEquals("idleTimeout", idleTimeout, entry.idleTimeout() );
+	}
+
+	@Test
+	public void testHardTimeout(){
+		assertEquals("hardTimeout", hardTimeout, entry.hardTimeout() );
+	}
+
+	@Test
 	public void testFlowEntryMatch(){
 		assertEquals("flowEntryMatch", match, entry.flowEntryMatch() );
 	}
@@ -237,8 +252,8 @@
 	@Test
 	public void testToString(){
 		FlowEntry def = new FlowEntry();
-		assertEquals("toString", def.toString(), "[ flowEntryActions=[] flowEntryUserState=FE_USER_UNKNOWN flowEntrySwitchState=FE_SWITCH_UNKNOWN]" );
-		assertEquals("toString", entry.toString(), "[flowEntryId=0x5678 flowId=0x1234 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]]" );
+		assertEquals("toString", def.toString(), "[ idleTimeout=0 hardTimeout=0 flowEntryActions=[] flowEntryUserState=FE_USER_UNKNOWN flowEntrySwitchState=FE_SWITCH_UNKNOWN]" );
+		assertEquals("toString", entry.toString(), "[flowEntryId=0x5678 flowId=0x1234 idleTimeout=5 hardTimeout=10 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
index bd42ac8..76ccf9f 100644
--- a/src/test/java/net/onrc/onos/ofcontroller/util/FlowPathTest.java
+++ b/src/test/java/net/onrc/onos/ofcontroller/util/FlowPathTest.java
@@ -19,6 +19,8 @@
 		iFlowPath.setFlowPathTypeForTest("FP_TYPE_SHORTEST_PATH");
 		iFlowPath.setFlowPathUserStateForTest("FP_USER_ADD");
 		iFlowPath.setFlowPathFlagsForTest(0L);
+		iFlowPath.setIdleTimeoutForTest(5);
+		iFlowPath.setHardTimeoutForTest(10);
 		iFlowPath.setSrcSwForTest("CA:FE");
 		iFlowPath.setSrcPortForTest((short)1);
 		iFlowPath.setDstSwForTest("BA:BE");
@@ -44,6 +46,8 @@
 		assertTrue ( flowPath.flowPathUserState() == FlowPathUserState.FP_USER_UNKNOWN);
 		assertFalse( flowPath.flowPathFlags().isDiscardFirstHopEntry() );
 		assertFalse( flowPath.flowPathFlags().isKeepOnlyFirstHopEntry() );
+		assertTrue (flowPath.idleTimeout() == 0);
+		assertTrue (flowPath.hardTimeout() == 0);
 		assertTrue( flowPath.flowEntryActions().isEmpty() );
 	}
 
@@ -55,6 +59,8 @@
 		iFlowPath.setFlowPathTypeForTest("FP_TYPE_SHORTEST_PATH");
 		iFlowPath.setFlowPathUserStateForTest("FP_USER_ADD");
 		iFlowPath.setFlowPathFlagsForTest(0L);
+		iFlowPath.setIdleTimeoutForTest(5);
+		iFlowPath.setHardTimeoutForTest(10);
 		iFlowPath.setSrcSwForTest("CA:FE");
 		iFlowPath.setSrcPortForTest((short)1);
 		iFlowPath.setDstSwForTest("BA:BE");
@@ -100,6 +106,8 @@
 		assertEquals(flowPath.flowPathType(), FlowPathType.FP_TYPE_SHORTEST_PATH);
 		assertEquals(flowPath.flowPathUserState(), FlowPathUserState.FP_USER_ADD);
 		assertEquals(flowPath.flowPathFlags().flags(), 0);
+		assertEquals(flowPath.idleTimeout(), 5);
+		assertEquals(flowPath.hardTimeout(), 10);
 		assertEquals(flowPath.dataPath().srcPort().dpid().value(), 0xCAFE);
 		assertEquals(flowPath.dataPath().srcPort().port().value(), 1);
 		assertEquals(flowPath.dataPath().dstPort().dpid().value(), 0xBABE);
@@ -123,6 +131,8 @@
 		
 		assertEquals(0x14, flowPath.dataPath().flowEntries().get(0).flowEntryId().value() );
 		assertEquals(0xBEEF, flowPath.dataPath().flowEntries().get(0).dpid().value() );
+		assertEquals(0, flowPath.dataPath().flowEntries().get(0).idleTimeout() );
+		assertEquals(0, flowPath.dataPath().flowEntries().get(0).hardTimeout() );
 		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());
@@ -179,6 +189,22 @@
 	}
 
 	@Test
+	public void testSetIdleTimeout(){
+		FlowPath flowPath = new FlowPath();
+		int idleTimeout = 15;
+		flowPath.setIdleTimeout( idleTimeout );
+		assertTrue( flowPath.idleTimeout() == 15 );
+	}
+
+	@Test
+	public void testSetHardTimeout(){
+		FlowPath flowPath = new FlowPath();
+		int hardTimeout = 20;
+		flowPath.setHardTimeout( hardTimeout );
+		assertTrue( flowPath.hardTimeout() == 20 );
+	}
+
+	@Test
 	public void testSetDataPath(){
 		FlowPath flowPath = new FlowPath();
 		DataPath dataPath = new DataPath();
@@ -189,7 +215,7 @@
 	@Test
 	public void testToString(){
 
-		assertEquals("[flowId=0x1234 installerId=installerId flowPathType=FP_TYPE_SHORTEST_PATH flowPathUserState=FP_USER_ADD 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());
+		assertEquals("[flowId=0x1234 installerId=installerId flowPathType=FP_TYPE_SHORTEST_PATH flowPathUserState=FP_USER_ADD flowPathFlags=[flags=] idleTimeout=5 hardTimeout=10 dataPath=[src=00:00:00:00:00:00:ca:fe/1 flowEntry=[flowEntryId=0x14 idleTimeout=0 hardTimeout=0 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
diff --git a/web/add_flow.py b/web/add_flow.py
index c621c30..9690024 100755
--- a/web/add_flow.py
+++ b/web/add_flow.py
@@ -129,9 +129,12 @@
   my_dst_port = my_args[5]
 
   #
-  # Extract the "flowPathFlags", "match" and "action" arguments
+  # Extract the "flowPathFlags", "idleTimeout", "hardTimeout",
+  # "match" and "action" arguments.
   #
   flowPathFlags = 0L
+  idleTimeout = 0
+  hardTimeout = 0
   match = {}
   matchInPortEnabled = True		# NOTE: Enabled by default
   actions = []
@@ -155,6 +158,10 @@
 	flowPathFlags = flowPathFlags + 0x1
       if "KEEP_ONLY_FIRST_HOP_ENTRY" in arg2:
 	flowPathFlags = flowPathFlags + 0x2
+    elif arg1 == "idleTimeout":
+     idleTimeout = arg2
+    elif arg1 == "hardTimeout":
+     hardTimeout = arg2
     elif arg1 == "matchInPort":
       # Just mark whether inPort matching is enabled
       matchInPortEnabled = arg2 in ['True', 'true']
@@ -310,6 +317,8 @@
     'my_dst_dpid' : my_dst_dpid,
     'my_dst_port' : my_dst_port,
     'flowPathFlags' : flowPathFlags,
+    'idleTimeout' : idleTimeout,
+    'hardTimeout' : hardTimeout,
     'match' : match,
     'matchInPortEnabled' : matchInPortEnabled,
     'actions' : actions,
@@ -334,6 +343,8 @@
   my_flow_id = parsed_args['my_flow_id']
   my_installer_id = parsed_args['my_installer_id']
   myFlowPathFlags = parsed_args['flowPathFlags']
+  myIdleTimeout = parsed_args['idleTimeout']
+  myHardTimeout = parsed_args['hardTimeout']
   match = parsed_args['match']
   matchInPortEnabled = parsed_args['matchInPortEnabled']
   actions = parsed_args['actions']
@@ -356,6 +367,8 @@
   flow_path['flowPathType'] = 'FP_TYPE_EXPLICIT_PATH'
   flow_path['flowPathUserState'] = 'FP_USER_ADD'
   flow_path['flowPathFlags'] = flowPathFlags
+  flow_path['idleTimeout'] = myIdleTimeout
+  flow_path['hardTimeout'] = myHardTimeout
 
   if (len(match) > 0):
     flow_path['flowEntryMatch'] = copy.deepcopy(match)
@@ -506,6 +519,10 @@
   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 + "    Timeouts (in seconds in the [0, 65535] interval):\n"
+  usage_msg = usage_msg + "        idleTimeout <idleTimeoutInSeconds> (default to 0: no timeout)\n"
+  usage_msg = usage_msg + "        hardTimeout <hardTimeoutInSeconds> (default to 0: no timeout)\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"
@@ -516,7 +533,7 @@
   usage_msg = usage_msg + "        matchSrcIPv4Net <source IPv4 network address>\n"
   usage_msg = usage_msg + "        matchDstIPv4Net <destination IPv4 network address>\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 + "        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"
@@ -529,7 +546,7 @@
   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 + "        actionSetIpToS <IP ToS (DSCP field, 6 bits)>\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 + "    Actions (not implemented yet):\n"