merge
authorGustavo J. A. M. Carneiro <gjc@inescporto.pt>
Sat, 12 Mar 2011 18:35:56 +0000
changeset 6894 0c7a09810b07
parent 6893 5dccd86f90cf (current diff)
parent 6892 dc8533a99c63 (diff)
child 6895 9d9939611d71
merge
bindings/python/apidefs/gcc-ILP32/ns3modulegen_generated.py
bindings/python/apidefs/gcc-LP64/ns3modulegen_generated.py
src/wscript
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/apidefs/gcc-ILP32/ns3_module_openflow.py	Sat Mar 12 18:35:56 2011 +0000
@@ -0,0 +1,139 @@
+from pybindgen import Module, FileCodeSink, param, retval, cppclass, typehandlers
+
+def register_types(module):
+    root_module = module.get_root()
+    
+    
+    ## Register a nested module for the namespace Config
+    
+    nested_module = module.add_cpp_namespace('Config')
+    register_types_ns3_Config(nested_module)
+    
+    
+    ## Register a nested module for the namespace FatalImpl
+    
+    nested_module = module.add_cpp_namespace('FatalImpl')
+    register_types_ns3_FatalImpl(nested_module)
+    
+    
+    ## Register a nested module for the namespace addressUtils
+    
+    nested_module = module.add_cpp_namespace('addressUtils')
+    register_types_ns3_addressUtils(nested_module)
+    
+    
+    ## Register a nested module for the namespace aodv
+    
+    nested_module = module.add_cpp_namespace('aodv')
+    register_types_ns3_aodv(nested_module)
+    
+    
+    ## Register a nested module for the namespace dot11s
+    
+    nested_module = module.add_cpp_namespace('dot11s')
+    register_types_ns3_dot11s(nested_module)
+    
+    
+    ## Register a nested module for the namespace dsdv
+    
+    nested_module = module.add_cpp_namespace('dsdv')
+    register_types_ns3_dsdv(nested_module)
+    
+    
+    ## Register a nested module for the namespace flame
+    
+    nested_module = module.add_cpp_namespace('flame')
+    register_types_ns3_flame(nested_module)
+    
+    
+    ## Register a nested module for the namespace internal
+    
+    nested_module = module.add_cpp_namespace('internal')
+    register_types_ns3_internal(nested_module)
+    
+    
+    ## Register a nested module for the namespace olsr
+    
+    nested_module = module.add_cpp_namespace('olsr')
+    register_types_ns3_olsr(nested_module)
+    
+
+def register_types_ns3_Config(module):
+    root_module = module.get_root()
+    
+
+def register_types_ns3_FatalImpl(module):
+    root_module = module.get_root()
+    
+
+def register_types_ns3_addressUtils(module):
+    root_module = module.get_root()
+    
+
+def register_types_ns3_aodv(module):
+    root_module = module.get_root()
+    
+
+def register_types_ns3_dot11s(module):
+    root_module = module.get_root()
+    
+
+def register_types_ns3_dsdv(module):
+    root_module = module.get_root()
+    
+
+def register_types_ns3_flame(module):
+    root_module = module.get_root()
+    
+
+def register_types_ns3_internal(module):
+    root_module = module.get_root()
+    
+
+def register_types_ns3_olsr(module):
+    root_module = module.get_root()
+    
+
+def register_methods(root_module):
+    return
+
+def register_functions(root_module):
+    module = root_module
+    register_functions_ns3_Config(module.get_submodule('Config'), root_module)
+    register_functions_ns3_FatalImpl(module.get_submodule('FatalImpl'), root_module)
+    register_functions_ns3_addressUtils(module.get_submodule('addressUtils'), root_module)
+    register_functions_ns3_aodv(module.get_submodule('aodv'), root_module)
+    register_functions_ns3_dot11s(module.get_submodule('dot11s'), root_module)
+    register_functions_ns3_dsdv(module.get_submodule('dsdv'), root_module)
+    register_functions_ns3_flame(module.get_submodule('flame'), root_module)
+    register_functions_ns3_internal(module.get_submodule('internal'), root_module)
+    register_functions_ns3_olsr(module.get_submodule('olsr'), root_module)
+    return
+
+def register_functions_ns3_Config(module, root_module):
+    return
+
+def register_functions_ns3_FatalImpl(module, root_module):
+    return
+
+def register_functions_ns3_addressUtils(module, root_module):
+    return
+
+def register_functions_ns3_aodv(module, root_module):
+    return
+
+def register_functions_ns3_dot11s(module, root_module):
+    return
+
+def register_functions_ns3_dsdv(module, root_module):
+    return
+
+def register_functions_ns3_flame(module, root_module):
+    return
+
+def register_functions_ns3_internal(module, root_module):
+    return
+
+def register_functions_ns3_olsr(module, root_module):
+    return
+
--- a/bindings/python/apidefs/gcc-ILP32/ns3_module_spectrum.py	Sat Mar 12 18:34:30 2011 +0000
+++ b/bindings/python/apidefs/gcc-ILP32/ns3_module_spectrum.py	Sat Mar 12 18:35:56 2011 +0000
@@ -86,15 +86,15 @@
     typehandlers.add_type_alias('std::map< unsigned int, ns3::TxSpectrumModelInfo, std::less< unsigned int >, std::allocator< std::pair< unsigned int const, ns3::TxSpectrumModelInfo > > >', 'ns3::TxSpectrumModelInfoMap_t')
     typehandlers.add_type_alias('std::map< unsigned int, ns3::TxSpectrumModelInfo, std::less< unsigned int >, std::allocator< std::pair< unsigned int const, ns3::TxSpectrumModelInfo > > >*', 'ns3::TxSpectrumModelInfoMap_t*')
     typehandlers.add_type_alias('std::map< unsigned int, ns3::TxSpectrumModelInfo, std::less< unsigned int >, std::allocator< std::pair< unsigned int const, ns3::TxSpectrumModelInfo > > >&', 'ns3::TxSpectrumModelInfoMap_t&')
+    typehandlers.add_type_alias('std::vector< ns3::BandInfo, std::allocator< ns3::BandInfo > >', 'ns3::Bands')
+    typehandlers.add_type_alias('std::vector< ns3::BandInfo, std::allocator< ns3::BandInfo > >*', 'ns3::Bands*')
+    typehandlers.add_type_alias('std::vector< ns3::BandInfo, std::allocator< ns3::BandInfo > >&', 'ns3::Bands&')
     typehandlers.add_type_alias('std::map< unsigned int, ns3::RxSpectrumModelInfo, std::less< unsigned int >, std::allocator< std::pair< unsigned int const, ns3::RxSpectrumModelInfo > > >', 'ns3::RxSpectrumModelInfoMap_t')
     typehandlers.add_type_alias('std::map< unsigned int, ns3::RxSpectrumModelInfo, std::less< unsigned int >, std::allocator< std::pair< unsigned int const, ns3::RxSpectrumModelInfo > > >*', 'ns3::RxSpectrumModelInfoMap_t*')
     typehandlers.add_type_alias('std::map< unsigned int, ns3::RxSpectrumModelInfo, std::less< unsigned int >, std::allocator< std::pair< unsigned int const, ns3::RxSpectrumModelInfo > > >&', 'ns3::RxSpectrumModelInfoMap_t&')
     typehandlers.add_type_alias('uint32_t', 'ns3::SpectrumModelUid_t')
     typehandlers.add_type_alias('uint32_t*', 'ns3::SpectrumModelUid_t*')
     typehandlers.add_type_alias('uint32_t&', 'ns3::SpectrumModelUid_t&')
-    typehandlers.add_type_alias('std::vector< ns3::BandInfo, std::allocator< ns3::BandInfo > >', 'ns3::Bands')
-    typehandlers.add_type_alias('std::vector< ns3::BandInfo, std::allocator< ns3::BandInfo > >*', 'ns3::Bands*')
-    typehandlers.add_type_alias('std::vector< ns3::BandInfo, std::allocator< ns3::BandInfo > >&', 'ns3::Bands&')
     
     ## Register a nested module for the namespace Config
     
--- a/bindings/python/apidefs/gcc-ILP32/ns3modulegen_generated.py	Sat Mar 12 18:34:30 2011 +0000
+++ b/bindings/python/apidefs/gcc-ILP32/ns3modulegen_generated.py	Sat Mar 12 18:35:56 2011 +0000
@@ -31,6 +31,7 @@
 import ns3_module_click
 import ns3_module_flow_monitor
 import ns3_module_nix_vector_routing
+import ns3_module_openflow
 import ns3_module_tap_bridge
 import ns3_module_virtual_net_device
 import ns3_module_netanim
@@ -263,6 +264,17 @@
         ns3_module_nix_vector_routing__local.register_types(module)
     
     root_module.end_section('ns3_module_nix_vector_routing')
+    root_module.begin_section('ns3_module_openflow')
+    ns3_module_openflow.register_types(module)
+    
+    try:
+        import ns3_module_openflow__local
+    except ImportError:
+        pass
+    else:
+        ns3_module_openflow__local.register_types(module)
+    
+    root_module.end_section('ns3_module_openflow')
     root_module.begin_section('ns3_module_tap_bridge')
     ns3_module_tap_bridge.register_types(module)
     
@@ -750,6 +762,17 @@
         ns3_module_nix_vector_routing__local.register_methods(root_module)
     
     root_module.end_section('ns3_module_nix_vector_routing')
+    root_module.begin_section('ns3_module_openflow')
+    ns3_module_openflow.register_methods(root_module)
+    
+    try:
+        import ns3_module_openflow__local
+    except ImportError:
+        pass
+    else:
+        ns3_module_openflow__local.register_methods(root_module)
+    
+    root_module.end_section('ns3_module_openflow')
     root_module.begin_section('ns3_module_tap_bridge')
     ns3_module_tap_bridge.register_methods(root_module)
     
@@ -1128,6 +1151,17 @@
         ns3_module_nix_vector_routing__local.register_functions(root_module)
     
     root_module.end_section('ns3_module_nix_vector_routing')
+    root_module.begin_section('ns3_module_openflow')
+    ns3_module_openflow.register_functions(root_module)
+    
+    try:
+        import ns3_module_openflow__local
+    except ImportError:
+        pass
+    else:
+        ns3_module_openflow__local.register_functions(root_module)
+    
+    root_module.end_section('ns3_module_openflow')
     root_module.begin_section('ns3_module_tap_bridge')
     ns3_module_tap_bridge.register_functions(root_module)
     
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/apidefs/gcc-LP64/ns3_module_openflow.py	Sat Mar 12 18:35:56 2011 +0000
@@ -0,0 +1,139 @@
+from pybindgen import Module, FileCodeSink, param, retval, cppclass, typehandlers
+
+def register_types(module):
+    root_module = module.get_root()
+    
+    
+    ## Register a nested module for the namespace Config
+    
+    nested_module = module.add_cpp_namespace('Config')
+    register_types_ns3_Config(nested_module)
+    
+    
+    ## Register a nested module for the namespace FatalImpl
+    
+    nested_module = module.add_cpp_namespace('FatalImpl')
+    register_types_ns3_FatalImpl(nested_module)
+    
+    
+    ## Register a nested module for the namespace addressUtils
+    
+    nested_module = module.add_cpp_namespace('addressUtils')
+    register_types_ns3_addressUtils(nested_module)
+    
+    
+    ## Register a nested module for the namespace aodv
+    
+    nested_module = module.add_cpp_namespace('aodv')
+    register_types_ns3_aodv(nested_module)
+    
+    
+    ## Register a nested module for the namespace dot11s
+    
+    nested_module = module.add_cpp_namespace('dot11s')
+    register_types_ns3_dot11s(nested_module)
+    
+    
+    ## Register a nested module for the namespace dsdv
+    
+    nested_module = module.add_cpp_namespace('dsdv')
+    register_types_ns3_dsdv(nested_module)
+    
+    
+    ## Register a nested module for the namespace flame
+    
+    nested_module = module.add_cpp_namespace('flame')
+    register_types_ns3_flame(nested_module)
+    
+    
+    ## Register a nested module for the namespace internal
+    
+    nested_module = module.add_cpp_namespace('internal')
+    register_types_ns3_internal(nested_module)
+    
+    
+    ## Register a nested module for the namespace olsr
+    
+    nested_module = module.add_cpp_namespace('olsr')
+    register_types_ns3_olsr(nested_module)
+    
+
+def register_types_ns3_Config(module):
+    root_module = module.get_root()
+    
+
+def register_types_ns3_FatalImpl(module):
+    root_module = module.get_root()
+    
+
+def register_types_ns3_addressUtils(module):
+    root_module = module.get_root()
+    
+
+def register_types_ns3_aodv(module):
+    root_module = module.get_root()
+    
+
+def register_types_ns3_dot11s(module):
+    root_module = module.get_root()
+    
+
+def register_types_ns3_dsdv(module):
+    root_module = module.get_root()
+    
+
+def register_types_ns3_flame(module):
+    root_module = module.get_root()
+    
+
+def register_types_ns3_internal(module):
+    root_module = module.get_root()
+    
+
+def register_types_ns3_olsr(module):
+    root_module = module.get_root()
+    
+
+def register_methods(root_module):
+    return
+
+def register_functions(root_module):
+    module = root_module
+    register_functions_ns3_Config(module.get_submodule('Config'), root_module)
+    register_functions_ns3_FatalImpl(module.get_submodule('FatalImpl'), root_module)
+    register_functions_ns3_addressUtils(module.get_submodule('addressUtils'), root_module)
+    register_functions_ns3_aodv(module.get_submodule('aodv'), root_module)
+    register_functions_ns3_dot11s(module.get_submodule('dot11s'), root_module)
+    register_functions_ns3_dsdv(module.get_submodule('dsdv'), root_module)
+    register_functions_ns3_flame(module.get_submodule('flame'), root_module)
+    register_functions_ns3_internal(module.get_submodule('internal'), root_module)
+    register_functions_ns3_olsr(module.get_submodule('olsr'), root_module)
+    return
+
+def register_functions_ns3_Config(module, root_module):
+    return
+
+def register_functions_ns3_FatalImpl(module, root_module):
+    return
+
+def register_functions_ns3_addressUtils(module, root_module):
+    return
+
+def register_functions_ns3_aodv(module, root_module):
+    return
+
+def register_functions_ns3_dot11s(module, root_module):
+    return
+
+def register_functions_ns3_dsdv(module, root_module):
+    return
+
+def register_functions_ns3_flame(module, root_module):
+    return
+
+def register_functions_ns3_internal(module, root_module):
+    return
+
+def register_functions_ns3_olsr(module, root_module):
+    return
+
--- a/bindings/python/apidefs/gcc-LP64/ns3_module_spectrum.py	Sat Mar 12 18:34:30 2011 +0000
+++ b/bindings/python/apidefs/gcc-LP64/ns3_module_spectrum.py	Sat Mar 12 18:35:56 2011 +0000
@@ -86,15 +86,15 @@
     typehandlers.add_type_alias('std::map< unsigned int, ns3::TxSpectrumModelInfo, std::less< unsigned int >, std::allocator< std::pair< unsigned int const, ns3::TxSpectrumModelInfo > > >', 'ns3::TxSpectrumModelInfoMap_t')
     typehandlers.add_type_alias('std::map< unsigned int, ns3::TxSpectrumModelInfo, std::less< unsigned int >, std::allocator< std::pair< unsigned int const, ns3::TxSpectrumModelInfo > > >*', 'ns3::TxSpectrumModelInfoMap_t*')
     typehandlers.add_type_alias('std::map< unsigned int, ns3::TxSpectrumModelInfo, std::less< unsigned int >, std::allocator< std::pair< unsigned int const, ns3::TxSpectrumModelInfo > > >&', 'ns3::TxSpectrumModelInfoMap_t&')
+    typehandlers.add_type_alias('std::vector< ns3::BandInfo, std::allocator< ns3::BandInfo > >', 'ns3::Bands')
+    typehandlers.add_type_alias('std::vector< ns3::BandInfo, std::allocator< ns3::BandInfo > >*', 'ns3::Bands*')
+    typehandlers.add_type_alias('std::vector< ns3::BandInfo, std::allocator< ns3::BandInfo > >&', 'ns3::Bands&')
     typehandlers.add_type_alias('std::map< unsigned int, ns3::RxSpectrumModelInfo, std::less< unsigned int >, std::allocator< std::pair< unsigned int const, ns3::RxSpectrumModelInfo > > >', 'ns3::RxSpectrumModelInfoMap_t')
     typehandlers.add_type_alias('std::map< unsigned int, ns3::RxSpectrumModelInfo, std::less< unsigned int >, std::allocator< std::pair< unsigned int const, ns3::RxSpectrumModelInfo > > >*', 'ns3::RxSpectrumModelInfoMap_t*')
     typehandlers.add_type_alias('std::map< unsigned int, ns3::RxSpectrumModelInfo, std::less< unsigned int >, std::allocator< std::pair< unsigned int const, ns3::RxSpectrumModelInfo > > >&', 'ns3::RxSpectrumModelInfoMap_t&')
     typehandlers.add_type_alias('uint32_t', 'ns3::SpectrumModelUid_t')
     typehandlers.add_type_alias('uint32_t*', 'ns3::SpectrumModelUid_t*')
     typehandlers.add_type_alias('uint32_t&', 'ns3::SpectrumModelUid_t&')
-    typehandlers.add_type_alias('std::vector< ns3::BandInfo, std::allocator< ns3::BandInfo > >', 'ns3::Bands')
-    typehandlers.add_type_alias('std::vector< ns3::BandInfo, std::allocator< ns3::BandInfo > >*', 'ns3::Bands*')
-    typehandlers.add_type_alias('std::vector< ns3::BandInfo, std::allocator< ns3::BandInfo > >&', 'ns3::Bands&')
     
     ## Register a nested module for the namespace Config
     
--- a/bindings/python/apidefs/gcc-LP64/ns3modulegen_generated.py	Sat Mar 12 18:34:30 2011 +0000
+++ b/bindings/python/apidefs/gcc-LP64/ns3modulegen_generated.py	Sat Mar 12 18:35:56 2011 +0000
@@ -31,6 +31,7 @@
 import ns3_module_click
 import ns3_module_flow_monitor
 import ns3_module_nix_vector_routing
+import ns3_module_openflow
 import ns3_module_tap_bridge
 import ns3_module_virtual_net_device
 import ns3_module_netanim
@@ -263,6 +264,17 @@
         ns3_module_nix_vector_routing__local.register_types(module)
     
     root_module.end_section('ns3_module_nix_vector_routing')
+    root_module.begin_section('ns3_module_openflow')
+    ns3_module_openflow.register_types(module)
+    
+    try:
+        import ns3_module_openflow__local
+    except ImportError:
+        pass
+    else:
+        ns3_module_openflow__local.register_types(module)
+    
+    root_module.end_section('ns3_module_openflow')
     root_module.begin_section('ns3_module_tap_bridge')
     ns3_module_tap_bridge.register_types(module)
     
@@ -750,6 +762,17 @@
         ns3_module_nix_vector_routing__local.register_methods(root_module)
     
     root_module.end_section('ns3_module_nix_vector_routing')
+    root_module.begin_section('ns3_module_openflow')
+    ns3_module_openflow.register_methods(root_module)
+    
+    try:
+        import ns3_module_openflow__local
+    except ImportError:
+        pass
+    else:
+        ns3_module_openflow__local.register_methods(root_module)
+    
+    root_module.end_section('ns3_module_openflow')
     root_module.begin_section('ns3_module_tap_bridge')
     ns3_module_tap_bridge.register_methods(root_module)
     
@@ -1128,6 +1151,17 @@
         ns3_module_nix_vector_routing__local.register_functions(root_module)
     
     root_module.end_section('ns3_module_nix_vector_routing')
+    root_module.begin_section('ns3_module_openflow')
+    ns3_module_openflow.register_functions(root_module)
+    
+    try:
+        import ns3_module_openflow__local
+    except ImportError:
+        pass
+    else:
+        ns3_module_openflow__local.register_functions(root_module)
+    
+    root_module.end_section('ns3_module_openflow')
     root_module.begin_section('ns3_module_tap_bridge')
     ns3_module_tap_bridge.register_functions(root_module)
     
--- a/examples/ipv6/radvd-two-prefix.cc	Sat Mar 12 18:34:30 2011 +0000
+++ b/examples/ipv6/radvd-two-prefix.cc	Sat Mar 12 18:35:56 2011 +0000
@@ -46,7 +46,7 @@
 
 using namespace ns3;
 
-NS_LOG_COMPONENT_DEFINE ("RadvdExample");
+NS_LOG_COMPONENT_DEFINE ("RadvdTwoPrefixExample");
 
 /**
  * \class StackHelper
--- a/src/csma/examples/csma-raw-ip-socket.cc	Sat Mar 12 18:34:30 2011 +0000
+++ b/src/csma/examples/csma-raw-ip-socket.cc	Sat Mar 12 18:35:56 2011 +0000
@@ -38,7 +38,7 @@
 
 using namespace ns3;
 
-NS_LOG_COMPONENT_DEFINE ("CsmaPacketSocketExample");
+NS_LOG_COMPONENT_DEFINE ("CsmaRawIpSocketExample");
 
 static void SinkRx (Ptr<const Packet> p, const Address &ad)
 {
--- a/src/nix-vector-routing/examples/nix-simple.cc	Sat Mar 12 18:34:30 2011 +0000
+++ b/src/nix-vector-routing/examples/nix-simple.cc	Sat Mar 12 18:35:56 2011 +0000
@@ -40,7 +40,7 @@
 
 using namespace ns3;
 
-NS_LOG_COMPONENT_DEFINE ("FirstScriptExample");
+NS_LOG_COMPONENT_DEFINE ("NixSimpleExample");
 
   int 
 main (int argc, char *argv[])
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/openflow/doc/openflow-switch.h	Sat Mar 12 18:35:56 2011 +0000
@@ -0,0 +1,158 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 Blake Hurd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307  USA
+ *
+ * Author: Blake Hurd  <naimorai@gmail.com>
+ */
+
+/**
+ * \ingroup devices
+ * \defgroup OpenFlowSwitchModel OpenFlow Switch Model
+ *
+ * \section OpenFlowSwitchModelOverview OpenFlow Switch Model Overview
+ *
+ * The ns-3 OpenFlowSwitch device models an OpenFlow-enabled switch. It is designed to
+ * express basic use of the OpenFlow protocol, with the maintaining of a virtual
+ * Flow Table and TCAM to provide OpenFlow-like results.
+ *
+ * The functionality comes down to the Controllers, which send messages to the
+ * switch that configure its flows, producing different effects. Controllers can
+ * be added by the user, under the ofi namespace extends ofi::Controller. To 
+ * demonstrate this, a DropController, which creates flows for ignoring every single
+ * packet, and LearningController, which effectively makes the switch a more complicated
+ * BridgeNetDevice. A user versed in a standard OFSID, and/or OF protocol, can write
+ * virtual controllers to create switches of all kinds of types.
+ *
+ * \section OpenFlowSwitchModel OpenFlow Switch Model
+ *
+ * The OpenFlowSwitch device behaves somewhat according to the diagram setup as a classical OFSID
+ * switch, with a few modifications made for a proper simulation environment.
+ *
+ * Normal OF-enabled Switch
+ * -----------------------------------
+ * | Secure Channel                  | <--OF Protocol--> | Controller is external |
+ * | Hardware or Software Flow Table |
+ * -----------------------------------
+ *
+ * ns-3 OF-enabled Switch (module)
+ * -------------------------------------
+ * | m_controller->ReceiveFromSwitch() | <--OF Protocol--> | Controller is internal |
+ * | Software Flow Table, virtual TCAM |
+ * -------------------------------------
+ *
+ * In essence, there are two differences:
+ * # No SSL, Embedded Controller: Instead of a secure channel and connecting to an
+ * outside location for the Controller program/machine, we currently only allow a
+ * Controller extended from ofi::Controller, an extension of an ns3::Object. This
+ * means ns-3 programmers cannot model the SSL part of the interface or possibility
+ * of network failure. The connection to the OpenFlowSwitch is local and there aren't any
+ * reasons for the channel/connection to break down. <<This difference may be an
+ * option in the future. Using EmuNetDevices, it should be possible to engage an
+ * external Controller program/machine, and thus work with controllers designed
+ * outside of the ns-3 environment, that simply use the proper OF protocol when
+ * communicating messages to the switch through a tap device.>>
+ *
+ * # Virtual Flow Table, TCAM: Typical OF-enabled switches are implemented on a hardware
+ * TCAM. The OFSID we turn into a library includes a modelled software TCAM, that produces
+ * the same results as a hardware TCAM. We include an attribute FlowTableLookupDelay, which
+ * allows a simple delay of using the TCAM to be modelled. We don't endeavor to make this
+ * delay more complicated, based on the tasks we are running on the TCAM, that is a possible
+ * future improvement.
+ *
+ * \section OpenFlowSwitchNetDeviceModel OpenFlow Switch Net Device Model
+ *
+ * The OpenFlowSwitch network device is aimed to model an OpenFlow switch, with a TCAM and a connection
+ * to a controller program. With some tweaking, it can model every switch type, as per OpenFlow's
+ * extensibility. It outsources the complexity of the switch ports to NetDevices of the user's choosing.
+ * It should be noted that these NetDevices must behave like practical switch ports, i.e. a Mac Address
+ * is assigned, and nothing more. It also must support a SendFrom function so
+ * that the OpenFlowSwitch can forward across that port.
+ *
+ * The OpenFlowSwitchNetDevice provides following Attributes:
+ *
+ * - FlowTableLookUpDelay:      This time gets run off the clock when making a lookup in our Flow Table.
+ * - Flags:        		OpenFlow specific configuration flags. They are defined in the ofp_config_flags enum. Choices include:
+ *				OFPC_SEND_FLOW_EXP (OpenFlowSwitch notifies controller when a flow has expired),
+ *				OFPC_FRAG_NORMAL (Match fragment against Flow table),
+ *				OFPC_FRAG_DROP (Drop fragments),
+ *				OFPC_FRAG_REASM (Reassemble only if OFPC_IP_REASM set, which is currently impossible,
+ *				because switch implementation does not support IP reassembly)
+ *				OFPC_FRAG_MASK (Mask Fragments)
+ * - FlowTableMissSendLength:   When the packet doesn't match in our Flow Table, and we forward to the controller,
+ *				this sets # of bytes forwarded (packet is not forwarded in its entirety, unless specified).
+ *
+ * \section OpenFlowSwitchModelSummary OpenFlow Switch Model Summary
+ *
+ * The ns-3 OpenFlowSwitch device models an OpenFlow-enabled switch. It is designed to
+ * express basic use of the OpenFlow protocol, with the maintaining of a virtual
+ * Flow Table and TCAM to provide OpenFlow-like results.
+ *
+ * The functionality comes down to the Controllers, which send messages to the
+ * switch that configure its flows, producing different effects. Controllers can
+ * be added by the user, under the ofi namespace extends ofi::Controller. To 
+ * demonstrate this, a DropController, which creates flows for ignoring every single
+ * packet, and LearningController, which effectively makes the switch a more complicated
+ * BridgeNetDevice. A user versed in a standard OFSID, and/or OF protocol, can write
+ * virtual controllers to create switches of all kinds of types.
+ *
+ * In order to use the OpenFlowSwitch module, you must create and link the
+ * OFSID (OpenFlow Software Implementation Distribution) to ns-3.
+ * To do this:
+ *
+ * #1 Obtain the OFSID code. An ns-3 specific OFSID branch is provided 
+ *    to ensure operation with ns-3. The OFSID has several dependencies 
+ *    include libxml2, libdl, and the boost libraries. Use mercurial to 
+ *    download this branch and waf to build the library:
+ *
+ * $ hg clone http://code.nsnam.org/bhurd/openflow
+ * $ cd openflow
+ * $ ./waf configure
+ * $ ./waf build
+ *
+ * #2 Your OFSID is now built into a libopenflow.a library! To
+ * link to an ns-3 build with this switch module, run from the ns-3-dev
+ * (or whatever you have named your distribution):
+ *
+ * $ ./waf configure --with-openflow=path/to/openflow
+ *
+ * #3 Under "---- Summary of optional NS-3 features:", you should see
+ * "NS-3 OpenFlow Integration     : enabled", indicating the library
+ * has been linked to ns-3. Run:
+ *
+ * $ ./waf build
+ *
+ * to build ns-3 and activate the OpenFlowSwitch module.
+ *
+ * Once set up, you have access to some tests:
+ *	
+ * For a test suite for the switch module, run:
+ *
+ * $ ./test.py --suite=openflow
+ *
+ * For an example demonstrating its use in a simple learning controller/switch, run:
+ *
+ * $ ./waf --run openflow-switch
+ *
+ * To see it in detailed logging, run:
+ *
+ * $ ./waf --run "openflow-switch -v"
+ *
+ * If you have any questions, read the wiki <http://www.nsnam.org/wiki/index.php/GSOC2010OpenFlow>
+ * first, and consider posting to the ns-3 developers mailing list <http://www.isi.edu/nsnam/ns/ns-dev-list.html>,
+ * but feel free to reach me at <naimorai@gmail.com>
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/openflow/examples/openflow-switch.cc	Sat Mar 12 18:35:56 2011 +0000
@@ -0,0 +1,215 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+// Network topology
+//
+//        n0     n1
+//        |      |
+//       ----------
+//       | Switch |
+//       ----------
+//        |      |
+//        n2     n3
+//
+//
+// - CBR/UDP flows from n0 to n1 and from n3 to n0
+// - DropTail queues
+// - Tracing of queues and packet receptions to file "openflow-switch.tr"
+// - If order of adding nodes and netdevices is kept:
+//      n0 = 00:00:00;00:00:01, n1 = 00:00:00:00:00:03, n3 = 00:00:00:00:00:07
+//	and port number corresponds to node number, so port 0 is connected to n0, for example.
+
+#include <iostream>
+#include <fstream>
+
+#include "ns3/core-module.h"
+#include "ns3/network-module.h"
+#include "ns3/csma-module.h"
+#include "ns3/internet-module.h"
+#include "ns3/applications-module.h"
+#include "ns3/openflow-module.h"
+#include "ns3/log.h"
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE ("OpenFlowCsmaSwitchExample");
+
+bool verbose = false;
+bool use_drop = false;
+ns3::Time timeout = ns3::Seconds (0);
+
+bool
+SetVerbose (std::string value)
+{
+  verbose = true;
+  return true;
+}
+
+bool
+SetDrop (std::string value)
+{
+  use_drop = true;
+  return true;
+}
+
+bool
+SetTimeout (std::string value)
+{
+  try {
+    timeout = ns3::Seconds (atof (value.c_str ()));
+    return true;
+  }
+  catch (...) { return false; }
+  return false;
+}
+
+int
+main (int argc, char *argv[])
+{
+  #ifdef NS3_OPENFLOW
+  //
+  // Allow the user to override any of the defaults and the above Bind() at
+  // run-time, via command-line arguments
+  //
+  CommandLine cmd;
+  cmd.AddValue ("v", "Verbose (turns on logging).", MakeCallback (&SetVerbose));
+  cmd.AddValue ("verbose", "Verbose (turns on logging).", MakeCallback (&SetVerbose));
+  cmd.AddValue ("d", "Use Drop Controller (Learning if not specified).", MakeCallback (&SetDrop));
+  cmd.AddValue ("drop", "Use Drop Controller (Learning if not specified).", MakeCallback (&SetDrop));
+  cmd.AddValue ("t", "Learning Controller Timeout (has no effect if drop controller is specified).", MakeCallback( &SetTimeout));
+  cmd.AddValue ("timeout", "Learning Controller Timeout (has no effect if drop controller is specified).", MakeCallback( &SetTimeout));
+  
+  cmd.Parse (argc, argv);
+
+  if (verbose)
+    {
+      LogComponentEnable ("OpenFlowCsmaSwitchExample", LOG_LEVEL_INFO);
+      LogComponentEnable ("OpenFlowInterface", LOG_LEVEL_INFO);
+      LogComponentEnable ("OpenFlowSwitchNetDevice", LOG_LEVEL_INFO);
+    }
+
+  //
+  // Explicitly create the nodes required by the topology (shown above).
+  //
+  NS_LOG_INFO ("Create nodes.");
+  NodeContainer terminals;
+  terminals.Create (4);
+
+  NodeContainer csmaSwitch;
+  csmaSwitch.Create (1);
+
+  NS_LOG_INFO ("Build Topology");
+  CsmaHelper csma;
+  csma.SetChannelAttribute ("DataRate", DataRateValue (5000000));
+  csma.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (2)));
+
+  // Create the csma links, from each terminal to the switch
+  NetDeviceContainer terminalDevices;
+  NetDeviceContainer switchDevices;
+  for (int i = 0; i < 4; i++)
+    {
+      NetDeviceContainer link = csma.Install (NodeContainer (terminals.Get (i), csmaSwitch));
+      terminalDevices.Add (link.Get (0));
+      switchDevices.Add (link.Get (1));
+    }
+
+  // Create the switch netdevice, which will do the packet switching
+  Ptr<Node> switchNode = csmaSwitch.Get (0);
+  OpenFlowSwitchHelper swtch;
+  
+  if (use_drop)
+  {
+    Ptr<ns3::ofi::DropController> controller = CreateObject<ns3::ofi::DropController> ();
+    swtch.Install (switchNode, switchDevices, controller);
+  }
+  else
+  {
+    Ptr<ns3::ofi::LearningController> controller = CreateObject<ns3::ofi::LearningController> ();
+    if (!timeout.IsZero ()) controller->SetAttribute ("ExpirationTime", TimeValue (timeout));
+    swtch.Install (switchNode, switchDevices, controller);
+  }
+
+  // Add internet stack to the terminals
+  InternetStackHelper internet;
+  internet.Install (terminals);
+
+  // We've got the "hardware" in place.  Now we need to add IP addresses.
+  NS_LOG_INFO ("Assign IP Addresses.");
+  Ipv4AddressHelper ipv4;
+  ipv4.SetBase ("10.1.1.0", "255.255.255.0");
+  ipv4.Assign (terminalDevices);
+
+  // Create an OnOff application to send UDP datagrams from n0 to n1.
+  NS_LOG_INFO ("Create Applications.");
+  uint16_t port = 9;   // Discard port (RFC 863)
+
+  OnOffHelper onoff ("ns3::UdpSocketFactory",
+                     Address (InetSocketAddress (Ipv4Address ("10.1.1.2"), port)));
+  onoff.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable (1)));
+  onoff.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (0)));
+
+  ApplicationContainer app = onoff.Install (terminals.Get (0));
+  // Start the application
+  app.Start (Seconds (1.0));
+  app.Stop (Seconds (10.0));
+
+  // Create an optional packet sink to receive these packets
+  PacketSinkHelper sink ("ns3::UdpSocketFactory",
+                         Address (InetSocketAddress (Ipv4Address::GetAny (), port)));
+  app = sink.Install (terminals.Get (1));
+  app.Start (Seconds (0.0));
+
+  //
+  // Create a similar flow from n3 to n0, starting at time 1.1 seconds
+  //
+  onoff.SetAttribute ("Remote",
+                      AddressValue (InetSocketAddress (Ipv4Address ("10.1.1.1"), port)));
+  app = onoff.Install (terminals.Get (3));
+  app.Start (Seconds (1.1));
+  app.Stop (Seconds (10.0));
+
+  app = sink.Install (terminals.Get (0));
+  app.Start (Seconds (0.0));
+
+  NS_LOG_INFO ("Configure Tracing.");
+
+  //
+  // Configure tracing of all enqueue, dequeue, and NetDevice receive events.
+  // Trace output will be sent to the file "openflow-switch.tr"
+  //
+  AsciiTraceHelper ascii;
+  csma.EnableAsciiAll (ascii.CreateFileStream ("openflow-switch.tr"));
+
+  //
+  // Also configure some tcpdump traces; each interface will be traced.
+  // The output files will be named:
+  //     openflow-switch-<nodeId>-<interfaceId>.pcap
+  // and can be read by the "tcpdump -r" command (use "-tt" option to
+  // display timestamps correctly)
+  //
+  csma.EnablePcapAll ("openflow-switch", false);
+
+  //
+  // Now, do the actual simulation.
+  //
+  NS_LOG_INFO ("Run Simulation.");
+  Simulator::Run ();
+  Simulator::Destroy ();
+  NS_LOG_INFO ("Done.");
+  #else
+  NS_LOG_INFO ("NS-3 OpenFlow is not enabled. Cannot run simulation.");
+  #endif // NS3_OPENFLOW
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/openflow/examples/wscript	Sat Mar 12 18:35:56 2011 +0000
@@ -0,0 +1,6 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+def build(bld):
+   obj = bld.create_ns3_program('openflow-switch',
+                                ['openflow', 'csma', 'internet', 'applications'])
+   obj.source = 'openflow-switch.cc'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/openflow/helper/openflow-switch-helper.cc	Sat Mar 12 18:35:56 2011 +0000
@@ -0,0 +1,97 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 Blake Hurd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Blake Hurd  <naimorai@gmail.com>
+ */
+#ifdef NS3_OPENFLOW
+
+#include "openflow-switch-helper.h"
+#include "ns3/log.h"
+#include "ns3/openflow-switch-net-device.h"
+#include "ns3/openflow-interface.h"
+#include "ns3/node.h"
+#include "ns3/names.h"
+
+NS_LOG_COMPONENT_DEFINE ("OpenFlowSwitchHelper");
+
+namespace ns3 {
+
+OpenFlowSwitchHelper::OpenFlowSwitchHelper ()
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  m_deviceFactory.SetTypeId ("ns3::OpenFlowSwitchNetDevice");
+}
+
+void
+OpenFlowSwitchHelper::SetDeviceAttribute (std::string n1, const AttributeValue &v1)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  m_deviceFactory.Set (n1, v1);
+}
+
+NetDeviceContainer
+OpenFlowSwitchHelper::Install (Ptr<Node> node, NetDeviceContainer c, Ptr<ns3::ofi::Controller> controller)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_INFO ("**** Install switch device on node " << node->GetId ());
+
+  NetDeviceContainer devs;
+  Ptr<OpenFlowSwitchNetDevice> dev = m_deviceFactory.Create<OpenFlowSwitchNetDevice> ();
+  devs.Add (dev);
+  node->AddDevice (dev);
+
+  NS_LOG_INFO ("**** Set up Controller");
+  dev->SetController (controller);
+
+  for (NetDeviceContainer::Iterator i = c.Begin (); i != c.End (); ++i)
+    {
+      NS_LOG_INFO ("**** Add SwitchPort " << *i);
+      dev->AddSwitchPort (*i);
+    }
+  return devs;
+}
+
+NetDeviceContainer
+OpenFlowSwitchHelper::Install (Ptr<Node> node, NetDeviceContainer c)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_INFO ("**** Install switch device on node " << node->GetId ());
+
+  NetDeviceContainer devs;
+  Ptr<OpenFlowSwitchNetDevice> dev = m_deviceFactory.Create<OpenFlowSwitchNetDevice> ();
+  devs.Add (dev);
+  node->AddDevice (dev);
+
+  for (NetDeviceContainer::Iterator i = c.Begin (); i != c.End (); ++i)
+    {
+      NS_LOG_INFO ("**** Add SwitchPort " << *i);
+      dev->AddSwitchPort (*i);
+    }
+  return devs;
+}
+
+NetDeviceContainer
+OpenFlowSwitchHelper::Install (std::string nodeName, NetDeviceContainer c)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  Ptr<Node> node = Names::Find<Node> (nodeName);
+  return Install (node, c);
+}
+
+} // namespace ns3
+
+#endif // NS3_OPENFLOW
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/openflow/helper/openflow-switch-helper.h	Sat Mar 12 18:35:56 2011 +0000
@@ -0,0 +1,105 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 Blake Hurd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Blake Hurd  <naimorai@gmail.com>
+ */
+#ifdef NS3_OPENFLOW
+
+#ifndef OPENFLOW_SWITCH_HELPER_H
+#define OPENFLOW_SWITCH_HELPER_H
+
+#include "ns3/openflow-interface.h"
+#include "ns3/net-device-container.h"
+#include "ns3/object-factory.h"
+#include <string>
+
+namespace ns3 {
+
+class Node;
+class AttributeValue;
+class Controller;
+
+/**
+ * \brief Add capability to switch multiple LAN segments (IEEE 802.1D bridging)
+ */
+class OpenFlowSwitchHelper
+{
+public:
+  /*
+   * Construct a OpenFlowSwitchHelper
+   */
+  OpenFlowSwitchHelper ();
+  
+  /**
+   * Set an attribute on each ns3::OpenFlowSwitchNetDevice created by
+   * OpenFlowSwitchHelper::Install
+   *
+   * \param n1 the name of the attribute to set
+   * \param v1 the value of the attribute to set
+   */
+  void
+  SetDeviceAttribute (std::string n1, const AttributeValue &v1);
+
+  /**
+   * This method creates an ns3::OpenFlowSwitchNetDevice with the attributes
+   * configured by OpenFlowSwitchHelper::SetDeviceAttribute, adds the device
+   * to the node, attaches the given NetDevices as ports of the
+   * switch, and sets up a controller connection using the provided
+   * Controller.
+   *
+   * \param node The node to install the device in
+   * \param c Container of NetDevices to add as switch ports
+   * \param controller The controller connection.
+   * \returns A container holding the added net device.
+   */
+  NetDeviceContainer
+  Install (Ptr<Node> node, NetDeviceContainer c, Ptr<ns3::ofi::Controller> controller);
+
+  /**
+   * This method creates an ns3::OpenFlowSwitchNetDevice with the attributes
+   * configured by OpenFlowSwitchHelper::SetDeviceAttribute, adds the device
+   * to the node, and attaches the given NetDevices as ports of the
+   * switch.
+   *
+   * \param node The node to install the device in
+   * \param c Container of NetDevices to add as switch ports
+   * \returns A container holding the added net device.
+   */
+  NetDeviceContainer
+  Install (Ptr<Node> node, NetDeviceContainer c);
+  
+  /**
+   * This method creates an ns3::OpenFlowSwitchNetDevice with the attributes
+   * configured by OpenFlowSwitchHelper::SetDeviceAttribute, adds the device
+   * to the node, and attaches the given NetDevices as ports of the
+   * switch.
+   *
+   * \param nodeName The name of the node to install the device in
+   * \param c Container of NetDevices to add as switch ports
+   * \returns A container holding the added net device.
+   */
+  NetDeviceContainer
+  Install (std::string nodeName, NetDeviceContainer c);
+  
+private:
+  ObjectFactory m_deviceFactory;
+};
+
+} // namespace ns3
+
+#endif // NS3_OPENFLOW
+#endif /* OPENFLOW_SWITCH_HELPER_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/openflow/model/openflow-interface.cc	Sat Mar 12 18:35:56 2011 +0000
@@ -0,0 +1,1135 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Blake Hurd  <naimorai@gmail.com>
+ */
+#ifdef NS3_OPENFLOW
+
+#include "openflow-interface.h"
+#include "openflow-switch-net-device.h"
+
+namespace ns3 {
+
+namespace ofi {
+
+NS_LOG_COMPONENT_DEFINE ("OpenFlowInterface");
+  
+Stats::Stats (ofp_stats_types _type, size_t body_len)
+{
+  type = _type;
+  size_t min_body = 0, max_body = 0;
+  
+  switch (type)
+  {
+    case OFPST_DESC:
+      break;
+    case OFPST_FLOW:
+      min_body = max_body = sizeof(ofp_flow_stats_request);
+      break;
+    case OFPST_AGGREGATE:
+      min_body = max_body = sizeof(ofp_aggregate_stats_request);
+      break;
+    case OFPST_TABLE:
+      break;
+    case OFPST_PORT:
+      min_body = 0;
+      max_body = std::numeric_limits<size_t>::max (); // Not sure about this one. This would guarantee that the body_len is always acceptable.
+      break;
+    case OFPST_PORT_TABLE:
+      break;
+    default:
+      NS_LOG_ERROR ("received stats request of unknown type " << type);
+      return;// -EINVAL;
+  }
+  
+  if ((min_body != 0 || max_body != 0) && (body_len < min_body || body_len > max_body))
+    {
+      NS_LOG_ERROR ("stats request type " << type << " with bad body length " << body_len);
+      return;// -EINVAL;
+    }
+}
+
+int
+Stats::DoInit (const void *body, int body_len, void **state)
+{
+  switch (type)
+  {
+    case OFPST_DESC:
+      return 0;
+    case OFPST_FLOW:
+      return FlowStatsInit (body, body_len, state);
+    case OFPST_AGGREGATE:
+      return AggregateStatsInit (body, body_len, state);
+    case OFPST_TABLE:
+      return 0;
+    case OFPST_PORT:
+      return PortStatsInit (body, body_len, state);
+    case OFPST_PORT_TABLE:
+      return 0;
+    case OFPST_VENDOR:
+      return 0;
+  }
+  
+  return 0;
+}
+
+int
+Stats::DoDump (Ptr<OpenFlowSwitchNetDevice> swtch, void *state, ofpbuf *buffer)
+{
+  switch (type)
+  {
+    case OFPST_DESC:
+      return DescStatsDump (state, buffer);
+    case OFPST_FLOW:
+      return FlowStatsDump (swtch, (FlowStatsState *)state, buffer);
+    case OFPST_AGGREGATE:
+      return AggregateStatsDump (swtch, (ofp_aggregate_stats_request *)state, buffer);
+    case OFPST_TABLE:
+      return TableStatsDump (swtch, state, buffer);
+    case OFPST_PORT:
+      return PortStatsDump (swtch, (PortStatsState *)state, buffer);
+    case OFPST_PORT_TABLE:
+      return PortTableStatsDump (swtch, state, buffer);
+    case OFPST_VENDOR:
+      return 0;
+  }
+  
+  return 0;
+}
+
+void
+Stats::DoCleanup (void *state)
+{
+  switch (type)
+  {
+    case OFPST_DESC:
+      break;
+    case OFPST_FLOW:
+      free ((FlowStatsState *)state);
+      break;
+    case OFPST_AGGREGATE:
+      free ((ofp_aggregate_stats_request *)state);
+      break;
+    case OFPST_TABLE:
+      break;
+    case OFPST_PORT:
+      free (((PortStatsState *)state)->ports);
+      free ((PortStatsState *)state);
+      break;
+    case OFPST_PORT_TABLE:
+      break;
+    case OFPST_VENDOR:
+      break;
+  }
+}
+  
+int
+Stats::DescStatsDump (void *state, ofpbuf *buffer)
+{
+  ofp_desc_stats *ods = (ofp_desc_stats*)ofpbuf_put_zeros (buffer, sizeof *ods);
+  strncpy (ods->mfr_desc, OpenFlowSwitchNetDevice::GetManufacturerDescription (), sizeof ods->mfr_desc);
+  strncpy (ods->hw_desc, OpenFlowSwitchNetDevice::GetHardwareDescription (), sizeof ods->hw_desc);
+  strncpy (ods->sw_desc, OpenFlowSwitchNetDevice::GetSoftwareDescription (), sizeof ods->sw_desc);
+  strncpy (ods->serial_num, OpenFlowSwitchNetDevice::GetSerialNumber (), sizeof ods->serial_num);
+  return 0;
+}
+
+#define MAX_FLOW_STATS_BYTES 4096
+
+int
+Stats::FlowStatsInit (const void *body, int body_len, void **state)
+{
+  const ofp_flow_stats_request *fsr = (ofp_flow_stats_request*)body;
+  FlowStatsState *s = (FlowStatsState*)xmalloc (sizeof *s);
+
+  s->table_idx = fsr->table_id == 0xff ? 0 : fsr->table_id;
+  memset (&s->position, 0, sizeof s->position);
+  s->rq = *fsr;
+  *state = s;
+  return 0;
+}
+
+int
+Stats_FlowDumpCallback (sw_flow *flow, void* state)
+{
+  Stats::FlowStatsState *s = (Stats::FlowStatsState*)state;
+
+  // Fill Flow Stats
+  ofp_flow_stats *ofs;
+  int length = sizeof *ofs + flow->sf_acts->actions_len;
+  ofs = (ofp_flow_stats*)ofpbuf_put_zeros (s->buffer, length);
+  ofs->length          = htons (length);
+  ofs->table_id        = s->table_idx;
+  ofs->match.wildcards = htonl (flow->key.wildcards);
+  ofs->match.in_port   = flow->key.flow.in_port;
+  memcpy (ofs->match.dl_src, flow->key.flow.dl_src, ETH_ADDR_LEN);
+  memcpy (ofs->match.dl_dst, flow->key.flow.dl_dst, ETH_ADDR_LEN);
+  ofs->match.dl_vlan   = flow->key.flow.dl_vlan;
+  ofs->match.dl_type   = flow->key.flow.dl_type;
+  ofs->match.nw_src    = flow->key.flow.nw_src;
+  ofs->match.nw_dst    = flow->key.flow.nw_dst;
+  ofs->match.nw_proto  = flow->key.flow.nw_proto;
+  ofs->match.tp_src    = flow->key.flow.tp_src;
+  ofs->match.tp_dst    = flow->key.flow.tp_dst;
+  ofs->duration        = htonl (s->now - flow->created);
+  ofs->priority        = htons (flow->priority);
+  ofs->idle_timeout    = htons (flow->idle_timeout);
+  ofs->hard_timeout    = htons (flow->hard_timeout);
+  ofs->packet_count    = htonll (flow->packet_count);
+  ofs->byte_count      = htonll (flow->byte_count);
+  memcpy (ofs->actions, flow->sf_acts->actions, flow->sf_acts->actions_len);
+
+  return s->buffer->size >= MAX_FLOW_STATS_BYTES;
+}
+
+int
+Stats::FlowStatsDump (Ptr<OpenFlowSwitchNetDevice> swtch, FlowStatsState* s, ofpbuf *buffer)
+{
+  sw_flow_key match_key;
+
+  flow_extract_match (&match_key, &s->rq.match);
+
+  s->buffer = buffer;
+  s->now = time_now ();
+  while (s->table_idx < swtch->GetChain ()->n_tables
+         && (s->rq.table_id == 0xff || s->rq.table_id == s->table_idx))
+    {
+      sw_table *table = swtch->GetChain ()->tables[s->table_idx];
+
+      if (table->iterate (table, &match_key, s->rq.out_port, &s->position, Stats::FlowDumpCallback, s))
+        {
+          break;
+        }
+
+      s->table_idx++;
+      memset (&s->position, 0, sizeof s->position);
+    }
+  return s->buffer->size >= MAX_FLOW_STATS_BYTES;
+}
+
+int
+Stats::AggregateStatsInit (const void *body, int body_len, void **state)
+{
+  //ofp_aggregate_stats_request *s = (ofp_aggregate_stats_request*)body;
+  *state = (ofp_aggregate_stats_request*)body;
+  return 0;
+}
+
+int
+Stats_AggregateDumpCallback (sw_flow *flow, void *state)
+{
+  ofp_aggregate_stats_reply *s = (ofp_aggregate_stats_reply*)state;
+  s->packet_count += flow->packet_count;
+  s->byte_count += flow->byte_count;
+  s->flow_count++;
+  return 0;
+}
+
+int
+Stats::AggregateStatsDump (Ptr<OpenFlowSwitchNetDevice> swtch, ofp_aggregate_stats_request *s, ofpbuf *buffer)
+{
+  ofp_aggregate_stats_request *rq = s;
+  ofp_aggregate_stats_reply *rpy = (ofp_aggregate_stats_reply*)ofpbuf_put_zeros (buffer, sizeof *rpy);
+  sw_flow_key match_key;
+  flow_extract_match (&match_key, &rq->match);
+  int table_idx = rq->table_id == 0xff ? 0 : rq->table_id;
+  
+  sw_table_position position;
+  memset (&position, 0, sizeof position);
+  
+  while (table_idx < swtch->GetChain ()->n_tables
+         && (rq->table_id == 0xff || rq->table_id == table_idx))
+    {
+      sw_table *table = swtch->GetChain ()->tables[table_idx];
+      int error = table->iterate (table, &match_key, rq->out_port, &position, Stats::AggregateDumpCallback, rpy);
+      if (error)
+        {
+          return error;
+        }
+
+      table_idx++;
+      memset (&position, 0, sizeof position);
+    }
+
+  rpy->packet_count = htonll (rpy->packet_count);
+  rpy->byte_count = htonll (rpy->byte_count);
+  rpy->flow_count = htonl (rpy->flow_count);
+  return 0;
+}
+
+int
+Stats::TableStatsDump (Ptr<OpenFlowSwitchNetDevice> swtch, void *state, ofpbuf *buffer)
+{
+  sw_chain* ft = swtch->GetChain ();
+  for (int i = 0; i < ft->n_tables; i++)
+    {
+      ofp_table_stats *ots = (ofp_table_stats*)ofpbuf_put_zeros (buffer, sizeof *ots);
+      sw_table_stats stats;
+      ft->tables[i]->stats (ft->tables[i], &stats);
+      strncpy (ots->name, stats.name, sizeof ots->name);
+      ots->table_id = i;
+      ots->wildcards = htonl (stats.wildcards);
+      ots->max_entries = htonl (stats.max_flows);
+      ots->active_count = htonl (stats.n_flows);
+      ots->lookup_count = htonll (stats.n_lookup);
+      ots->matched_count = htonll (stats.n_matched);
+    }
+  return 0;
+}
+
+// stats for the port table which is similar to stats for the flow tables
+int
+Stats::PortTableStatsDump (Ptr<OpenFlowSwitchNetDevice> swtch, void *state, ofpbuf *buffer)
+{
+  ofp_vport_table_stats *opts = (ofp_vport_table_stats*)ofpbuf_put_zeros (buffer, sizeof *opts);
+  opts->max_vports = htonl (swtch->GetVPortTable ().max_vports);
+  opts->active_vports = htonl (swtch->GetVPortTable ().active_vports);
+  opts->lookup_count = htonll (swtch->GetVPortTable ().lookup_count);
+  opts->port_match_count = htonll (swtch->GetVPortTable ().port_match_count);
+  opts->chain_match_count = htonll (swtch->GetVPortTable ().chain_match_count);
+
+  return 0;
+}
+
+int
+Stats::PortStatsInit (const void *body, int body_len, void **state)
+{
+  PortStatsState *s = (PortStatsState*)xmalloc (sizeof *s);
+
+  // the body contains a list of port numbers
+  s->ports = (uint32_t*)xmalloc (body_len);
+  memcpy (s->ports, body, body_len);
+  s->num_ports = body_len / sizeof(uint32_t);
+
+  *state = s;
+  return 0;
+}
+
+int
+Stats::PortStatsDump (Ptr<OpenFlowSwitchNetDevice> swtch, PortStatsState *s, ofpbuf *buffer)
+{
+  ofp_port_stats *ops;
+  uint32_t port;
+
+  // port stats are different depending on whether port is physical or virtual
+  for (size_t i = 0; i < s->num_ports; i++)
+    {
+      port = ntohl (s->ports[i]);
+      // physical port?
+      if (port <= OFPP_MAX)
+        {
+          Port p = swtch->GetSwitchPort (port);
+
+          if (p.netdev == 0)
+            {
+              continue;
+            }
+
+          ops = (ofp_port_stats*)ofpbuf_put_zeros (buffer, sizeof *ops);
+          ops->port_no = htonl (swtch->GetSwitchPortIndex (p));
+          ops->rx_packets   = htonll (p.rx_packets);
+          ops->tx_packets   = htonll (p.tx_packets);
+          ops->rx_bytes     = htonll (p.rx_bytes);
+          ops->tx_bytes     = htonll (p.tx_bytes);
+          ops->rx_dropped   = htonll (-1);
+          ops->tx_dropped   = htonll (p.tx_dropped);
+          ops->rx_errors    = htonll (-1);
+          ops->tx_errors    = htonll (-1);
+          ops->rx_frame_err = htonll (-1);
+          ops->rx_over_err  = htonll (-1);
+          ops->rx_crc_err   = htonll (-1);
+          ops->collisions   = htonll (-1);
+          ops->mpls_ttl0_dropped = htonll (p.mpls_ttl0_dropped);
+          ops++;
+        } 
+      else if (port >= OFPP_VP_START && port <= OFPP_VP_END) // virtual port?
+        {
+          // lookup the virtual port
+          vport_table_t vt = swtch->GetVPortTable ();
+          vport_table_entry *vpe = vport_table_lookup (&vt, port);
+          if (vpe == 0)
+            {
+              NS_LOG_ERROR ("vport entry not found!");
+              continue;
+            }
+          // only tx_packets and tx_bytes are really relevant for virtual ports
+          ops = (ofp_port_stats*)ofpbuf_put_zeros (buffer, sizeof *ops);
+          ops->port_no = htonl (vpe->vport);
+          ops->rx_packets   = htonll (-1);
+          ops->tx_packets   = htonll (vpe->packet_count);
+          ops->rx_bytes     = htonll (-1);
+          ops->tx_bytes     = htonll (vpe->byte_count);
+          ops->rx_dropped   = htonll (-1);
+          ops->tx_dropped   = htonll (-1);
+          ops->rx_errors    = htonll (-1);
+          ops->tx_errors    = htonll (-1);
+          ops->rx_frame_err = htonll (-1);
+          ops->rx_over_err  = htonll (-1);
+          ops->rx_crc_err   = htonll (-1);
+          ops->collisions   = htonll (-1);
+          ops->mpls_ttl0_dropped = htonll (-1);
+          ops++;
+        }
+    }
+  return 0;
+}
+
+bool
+Action::IsValidType (ofp_action_type type)
+{
+  switch (type)
+    {
+    case OFPAT_OUTPUT:
+    case OFPAT_SET_VLAN_VID:
+    case OFPAT_SET_VLAN_PCP:
+    case OFPAT_STRIP_VLAN:
+    case OFPAT_SET_DL_SRC:
+    case OFPAT_SET_DL_DST:
+    case OFPAT_SET_NW_SRC:
+    case OFPAT_SET_NW_DST:
+    case OFPAT_SET_TP_SRC:
+    case OFPAT_SET_TP_DST:
+    case OFPAT_SET_MPLS_LABEL:
+    case OFPAT_SET_MPLS_EXP:
+      return true;
+    default:
+      return false;
+    }
+}
+
+uint16_t
+Action::Validate (ofp_action_type type, size_t len, const sw_flow_key *key, const ofp_action_header *ah)
+{
+  size_t size = 0;
+
+  switch (type)
+    {
+    case OFPAT_OUTPUT:
+      {
+        if (len != sizeof(ofp_action_output))
+          {
+            return OFPBAC_BAD_LEN;
+          }
+
+        ofp_action_output *oa = (ofp_action_output *)ah;
+
+        // To prevent loops, make sure there's no action to send to the OFP_TABLE virtual port.
+
+        // port is now 32-bit
+        if (oa->port == OFPP_NONE || oa->port == key->flow.in_port) // htonl(OFPP_NONE);
+          { // if (oa->port == htons(OFPP_NONE) || oa->port == key->flow.in_port)
+            return OFPBAC_BAD_OUT_PORT;
+          }
+
+        return ACT_VALIDATION_OK;
+      }
+    case OFPAT_SET_VLAN_VID:
+      size = sizeof(ofp_action_vlan_vid);
+      break;
+    case OFPAT_SET_VLAN_PCP:
+      size = sizeof(ofp_action_vlan_pcp);
+      break;
+    case OFPAT_STRIP_VLAN:
+      size = sizeof(ofp_action_header);
+      break;
+    case OFPAT_SET_DL_SRC:
+    case OFPAT_SET_DL_DST:
+      size = sizeof(ofp_action_dl_addr);
+      break;
+    case OFPAT_SET_NW_SRC:
+    case OFPAT_SET_NW_DST:
+      size = sizeof(ofp_action_nw_addr);
+      break;
+    case OFPAT_SET_TP_SRC:
+    case OFPAT_SET_TP_DST:
+      size = sizeof(ofp_action_tp_port);
+      break;
+    case OFPAT_SET_MPLS_LABEL:
+      size = sizeof(ofp_action_mpls_label);
+      break;
+    case OFPAT_SET_MPLS_EXP:
+      size = sizeof(ofp_action_mpls_exp);
+      break;
+    default:
+      break;
+    }
+
+  if (len != size)
+    {
+      return OFPBAC_BAD_LEN;
+    }
+  return ACT_VALIDATION_OK;
+}
+
+void
+Action::Execute (ofp_action_type type, ofpbuf *buffer, sw_flow_key *key, const ofp_action_header *ah)
+{
+  switch (type)
+    {
+    case OFPAT_OUTPUT:
+      break;
+    case OFPAT_SET_VLAN_VID:
+      set_vlan_vid (buffer, key, ah);
+      break;
+    case OFPAT_SET_VLAN_PCP:
+      set_vlan_pcp (buffer, key, ah);
+      break;
+    case OFPAT_STRIP_VLAN:
+      strip_vlan (buffer, key, ah);
+      break;
+    case OFPAT_SET_DL_SRC:
+    case OFPAT_SET_DL_DST:
+      set_dl_addr (buffer, key, ah);
+      break;
+    case OFPAT_SET_NW_SRC:
+    case OFPAT_SET_NW_DST:
+      set_nw_addr (buffer, key, ah);
+      break;
+    case OFPAT_SET_TP_SRC:
+    case OFPAT_SET_TP_DST:
+      set_tp_port (buffer, key, ah);
+      break;
+    case OFPAT_SET_MPLS_LABEL:
+      set_mpls_label (buffer, key, ah);
+      break;
+    case OFPAT_SET_MPLS_EXP:
+      set_mpls_exp (buffer, key, ah);
+      break;
+    default:
+      break;
+    }
+}
+
+bool
+VPortAction::IsValidType (ofp_vport_action_type type)
+{
+  switch (type)
+    {
+    case OFPPAT_POP_MPLS:
+    case OFPPAT_PUSH_MPLS:
+    case OFPPAT_SET_MPLS_LABEL:
+    case OFPPAT_SET_MPLS_EXP:
+      return true;
+    default:
+      return false;
+    }
+}
+
+uint16_t
+VPortAction::Validate (ofp_vport_action_type type, size_t len, const ofp_action_header *ah)
+{
+  size_t size = 0;
+
+  switch (type)
+    {
+    case OFPPAT_POP_MPLS:
+      size = sizeof(ofp_vport_action_pop_mpls);
+      break;
+    case OFPPAT_PUSH_MPLS:
+      size = sizeof(ofp_vport_action_push_mpls);
+      break;
+    case OFPPAT_SET_MPLS_LABEL:
+      size = sizeof(ofp_vport_action_set_mpls_label);
+      break;
+    case OFPPAT_SET_MPLS_EXP:
+      size = sizeof(ofp_vport_action_set_mpls_exp);
+      break;
+    default:
+      break;
+    }
+
+  if (len != size)
+    {
+      return OFPBAC_BAD_LEN;
+    }
+  return ACT_VALIDATION_OK;
+}
+
+void
+VPortAction::Execute (ofp_vport_action_type type, ofpbuf *buffer, const sw_flow_key *key, const ofp_action_header *ah)
+{
+  switch (type)
+    {
+    case OFPPAT_POP_MPLS:
+      {
+        ofp_vport_action_pop_mpls *opapm = (ofp_vport_action_pop_mpls *)ah;
+        pop_mpls_act (0, buffer, key, &opapm->apm);
+        break;
+      }
+    case OFPPAT_PUSH_MPLS:
+      {
+        ofp_vport_action_push_mpls *opapm = (ofp_vport_action_push_mpls *)ah;
+        push_mpls_act (0, buffer, key, &opapm->apm);
+        break;
+      }
+    case OFPPAT_SET_MPLS_LABEL:
+      {
+        ofp_vport_action_set_mpls_label *oparml = (ofp_vport_action_set_mpls_label *)ah;
+        set_mpls_label_act (buffer, key, oparml->label_out);
+        break;
+      }
+    case OFPPAT_SET_MPLS_EXP:
+      {
+        ofp_vport_action_set_mpls_exp *oparme = (ofp_vport_action_set_mpls_exp *)ah;
+        set_mpls_exp_act (buffer, key, oparme->exp);
+        break;
+      }
+    default:
+      break;
+    }
+}
+
+bool
+EricssonAction::IsValidType (er_action_type type)
+{
+  switch (type)
+    {
+    case ERXT_POP_MPLS:
+    case ERXT_PUSH_MPLS:
+      return true;
+    default:
+      return false;
+    }
+}
+
+uint16_t
+EricssonAction::Validate (er_action_type type, size_t len)
+{
+  size_t size = 0;
+
+  switch (type)
+    {
+    case ERXT_POP_MPLS:
+      size = sizeof(er_action_pop_mpls);
+      break;
+    case ERXT_PUSH_MPLS:
+      size = sizeof(er_action_push_mpls);
+      break;
+    default:
+      break;
+    }
+
+  if (len != size)
+    {
+      return OFPBAC_BAD_LEN;
+    }
+  return ACT_VALIDATION_OK;
+}
+
+void
+EricssonAction::Execute (er_action_type type, ofpbuf *buffer, const sw_flow_key *key, const er_action_header *ah)
+{
+  switch (type)
+    {
+    case ERXT_POP_MPLS:
+      {
+        er_action_pop_mpls *erapm = (er_action_pop_mpls *)ah;
+        pop_mpls_act (0, buffer, key, &erapm->apm);
+        break;
+      }
+    case ERXT_PUSH_MPLS:
+      {
+        er_action_push_mpls *erapm = (er_action_push_mpls *)ah;
+        push_mpls_act (0, buffer, key, &erapm->apm);
+        break;
+      }
+    default:
+      break;
+    }
+}
+
+void
+Controller::AddSwitch (Ptr<OpenFlowSwitchNetDevice> swtch)
+{
+  if (m_switches.find (swtch) != m_switches.end ())
+    {
+      NS_LOG_INFO ("This Controller has already registered this switch!");
+    }
+  else
+    {
+      m_switches.insert (swtch);
+    }
+}
+
+void
+Controller::SendToSwitch (Ptr<OpenFlowSwitchNetDevice> swtch, void * msg, size_t length)
+{
+  if (m_switches.find (swtch) == m_switches.end ())
+    {
+      NS_LOG_ERROR ("Can't send to this switch, not registered to the Controller.");
+      return;
+    }
+
+  swtch->ForwardControlInput (msg, length);
+}
+
+ofp_flow_mod*
+Controller::BuildFlow (sw_flow_key key, uint32_t buffer_id, uint16_t command, void* acts, size_t actions_len, int idle_timeout, int hard_timeout)
+{
+  ofp_flow_mod* ofm = (ofp_flow_mod*)malloc (sizeof(ofp_flow_mod) + actions_len);
+  ofm->header.version = OFP_VERSION;
+  ofm->header.type = OFPT_FLOW_MOD;
+  ofm->header.length = htons (sizeof(ofp_flow_mod) + actions_len);
+  ofm->command = htons (command);
+  ofm->idle_timeout = htons (idle_timeout);
+  ofm->hard_timeout = htons (hard_timeout);
+  ofm->buffer_id = htonl (buffer_id);
+  ofm->priority = OFP_DEFAULT_PRIORITY;
+  memcpy (ofm->actions,acts,actions_len);
+
+  ofm->match.wildcards = key.wildcards;                                 // Wildcard fields
+  ofm->match.in_port = key.flow.in_port;                                // Input switch port
+  memcpy (ofm->match.dl_src, key.flow.dl_src, sizeof ofm->match.dl_src); // Ethernet source address.
+  memcpy (ofm->match.dl_dst, key.flow.dl_dst, sizeof ofm->match.dl_dst); // Ethernet destination address.
+  ofm->match.dl_vlan = key.flow.dl_vlan;                                // Input VLAN OFP_VLAN_NONE;
+  ofm->match.dl_type = key.flow.dl_type;                                // Ethernet frame type ETH_TYPE_IP;
+  ofm->match.nw_proto = key.flow.nw_proto;                              // IP Protocol
+  ofm->match.nw_src = key.flow.nw_src;                                  // IP source address
+  ofm->match.nw_dst = key.flow.nw_dst;                                  // IP destination address
+  ofm->match.tp_src = key.flow.tp_src;                                  // TCP/UDP source port
+  ofm->match.tp_dst = key.flow.tp_dst;                                  // TCP/UDP destination port
+  ofm->match.mpls_label1 = key.flow.mpls_label1;                        // Top of label stack htonl(MPLS_INVALID_LABEL);
+  ofm->match.mpls_label2 = key.flow.mpls_label1;                        // Second label (if available) htonl(MPLS_INVALID_LABEL);
+
+  return ofm;
+}
+
+uint8_t
+Controller::GetPacketType (ofpbuf* buffer)
+{
+  ofp_header* hdr = (ofp_header*)ofpbuf_try_pull (buffer, sizeof (ofp_header));
+  uint8_t type = hdr->type;
+  ofpbuf_push_uninit (buffer, sizeof (ofp_header));
+  return type;
+}
+
+void
+Controller::StartDump (StatsDumpCallback* cb)
+{
+  if (cb != 0)
+    {
+      int error = 1;
+      while (error > 0) // Switch's StatsDump returns 1 if the reply isn't complete.
+	{
+	  error = cb->swtch->StatsDump (cb);
+	}
+	
+      if (error != 0) // When the reply is complete, error will equal zero if there's no errors.
+	{
+	  NS_LOG_WARN ("Dump Callback Error: " << strerror (-error));
+	}
+	
+      // Clean up
+      cb->swtch->StatsDone (cb);
+    }
+}
+
+void
+DropController::ReceiveFromSwitch (Ptr<OpenFlowSwitchNetDevice> swtch, ofpbuf* buffer)
+{
+  if (m_switches.find (swtch) == m_switches.end ())
+    {
+      NS_LOG_ERROR ("Can't receive from this switch, not registered to the Controller.");
+      return;
+    }
+
+  // We have received any packet at this point, so we pull the header to figure out what type of packet we're handling.
+  uint8_t type = GetPacketType(buffer);
+
+  if (type == OFPT_PACKET_IN) // The switch didn't understand the packet it received, so it forwarded it to the controller.
+    {
+      ofp_packet_in * opi = (ofp_packet_in*)ofpbuf_try_pull (buffer, offsetof (ofp_packet_in, data));
+      int port = ntohs (opi->in_port);
+
+      // Create matching key.
+      sw_flow_key key;
+      key.wildcards = 0;
+      flow_extract (buffer, port != -1 ? port : OFPP_NONE, &key.flow);
+
+      ofp_flow_mod* ofm = BuildFlow (key, opi->buffer_id, OFPFC_ADD, 0, 0, OFP_FLOW_PERMANENT, OFP_FLOW_PERMANENT);
+      SendToSwitch (swtch, ofm, ofm->header.length);
+    }
+}
+
+TypeId LearningController::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::ofi::LearningController")
+  .SetParent (Controller::GetTypeId())
+  .AddConstructor<LearningController> ()
+  .AddAttribute ("ExpirationTime",
+		  "Time it takes for learned MAC state entry/created flow to expire.",
+		  TimeValue (Seconds (0)),
+		  MakeTimeAccessor (&LearningController::m_expirationTime),
+		  MakeTimeChecker ())
+  ;
+  return tid;
+}
+
+void
+LearningController::ReceiveFromSwitch (Ptr<OpenFlowSwitchNetDevice> swtch, ofpbuf* buffer)
+{
+  if (m_switches.find (swtch) == m_switches.end ())
+    {
+      NS_LOG_ERROR ("Can't receive from this switch, not registered to the Controller.");
+      return;
+    }
+
+  // We have received any packet at this point, so we pull the header to figure out what type of packet we're handling.
+  uint8_t type = GetPacketType(buffer);
+
+  if (type == OFPT_PACKET_IN) // The switch didn't understand the packet it received, so it forwarded it to the controller.
+    {
+      ofp_packet_in * opi = (ofp_packet_in*)ofpbuf_try_pull (buffer, offsetof (ofp_packet_in, data));
+      int port = ntohs (opi->in_port);
+
+      // Create matching key.
+      sw_flow_key key;
+      key.wildcards = 0;
+      flow_extract (buffer, port != -1 ? port : OFPP_NONE, &key.flow);
+
+      uint16_t out_port = OFPP_FLOOD;
+      uint16_t in_port = ntohs (key.flow.in_port);
+
+      // If the destination address is learned to a specific port, find it.
+      Mac48Address dst_addr;
+      dst_addr.CopyFrom (key.flow.dl_dst);
+      if (!dst_addr.IsBroadcast ())
+        {
+          LearnState_t::iterator st = m_learnState.find (dst_addr);
+          if (st != m_learnState.end ())
+            {
+	      out_port = st->second.port;
+            }
+          else
+            {
+              NS_LOG_INFO ("Setting to flood; don't know yet what port " << dst_addr << " is connected to");
+            }
+        }
+      else
+        {
+          NS_LOG_INFO ("Setting to flood; this packet is a broadcast");
+        }
+
+      // Create output-to-port action
+      ofp_action_output x[1];
+      x[0].type = htons (OFPAT_OUTPUT);
+      x[0].len = htons (sizeof(ofp_action_output));
+      x[0].port = out_port;
+
+      // Create a new flow that outputs matched packets to a learned port, OFPP_FLOOD if there's no learned port.
+      ofp_flow_mod* ofm = BuildFlow (key, opi->buffer_id, OFPFC_ADD, x, sizeof(x), OFP_FLOW_PERMANENT, m_expirationTime.IsZero ()?OFP_FLOW_PERMANENT:m_expirationTime.GetSeconds ());
+      SendToSwitch (swtch, ofm, ofm->header.length);
+
+      // We can learn a specific port for the source address for future use.
+      Mac48Address src_addr;
+      src_addr.CopyFrom (key.flow.dl_src);
+      LearnState_t::iterator st = m_learnState.find (src_addr);
+      if (st == m_learnState.end ()) // We haven't learned our source MAC yet.
+        {
+          LearnedState ls;
+          ls.port = in_port;
+          m_learnState.insert (std::make_pair (src_addr,ls));
+          NS_LOG_INFO ("Learned that " << src_addr << " can be found over port " << in_port);
+
+          // Learn src_addr goes to a certain port.
+          ofp_action_output x2[1];
+          x2[0].type = htons (OFPAT_OUTPUT);
+          x2[0].len = htons (sizeof(ofp_action_output));
+          x2[0].port = in_port;
+
+          // Switch MAC Addresses and ports to the flow we're modifying
+          src_addr.CopyTo (key.flow.dl_dst);
+          dst_addr.CopyTo (key.flow.dl_src);
+          key.flow.in_port = out_port;
+          ofp_flow_mod* ofm2 = BuildFlow (key, -1, OFPFC_MODIFY, x2, sizeof(x2), OFP_FLOW_PERMANENT, m_expirationTime.IsZero ()?OFP_FLOW_PERMANENT:m_expirationTime.GetSeconds ());
+          SendToSwitch (swtch, ofm2, ofm2->header.length);
+        }
+    }
+}
+
+void
+ExecuteActions (Ptr<OpenFlowSwitchNetDevice> swtch, uint64_t packet_uid, ofpbuf* buffer, sw_flow_key *key, const ofp_action_header *actions, size_t actions_len, int ignore_no_fwd)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  /* Every output action needs a separate clone of 'buffer', but the common
+   * case is just a single output action, so that doing a clone and then
+   * freeing the original buffer is wasteful.  So the following code is
+   * slightly obscure just to avoid that. */
+  int prev_port;
+  size_t max_len = 0;     // Initialze to make compiler happy
+  uint16_t in_port = key->flow.in_port; // ntohs(key->flow.in_port);
+  uint8_t *p = (uint8_t *)actions;
+
+  prev_port = -1;
+
+  if (actions_len == 0)
+    {
+      NS_LOG_INFO ("No actions set to this flow. Dropping packet.");
+      return;
+    }
+
+  /* The action list was already validated, so we can be a bit looser
+   * in our sanity-checking. */
+  while (actions_len > 0)
+    {
+      ofp_action_header *ah = (ofp_action_header *)p;
+      size_t len = htons (ah->len);
+
+      if (prev_port != -1)
+        {
+          swtch->DoOutput (packet_uid, in_port, max_len, prev_port, ignore_no_fwd);
+          prev_port = -1;
+        }
+
+      if (ah->type == htons (OFPAT_OUTPUT))
+        {
+          ofp_action_output *oa = (ofp_action_output *)p;
+
+          // port is now 32-bits
+          prev_port = oa->port; // ntohl(oa->port);
+          // prev_port = ntohs(oa->port);
+          max_len = ntohs (oa->max_len);
+        }
+      else
+        {
+          uint16_t type = ntohs (ah->type);
+          if (Action::IsValidType ((ofp_action_type)type)) // Execute a built-in OpenFlow action against 'buffer'.
+            {
+              Action::Execute ((ofp_action_type)type, buffer, key, ah);
+            }
+          else if (type == OFPAT_VENDOR)
+            {
+              ExecuteVendor (buffer, key, ah);
+            }
+        }
+
+      p += len;
+      actions_len -= len;
+    }
+
+  if (prev_port != -1)
+    {
+      swtch->DoOutput (packet_uid, in_port, max_len, prev_port, ignore_no_fwd);
+    }
+}
+
+uint16_t
+ValidateActions (const sw_flow_key *key, const ofp_action_header *actions, size_t actions_len)
+{
+  uint8_t *p = (uint8_t *)actions;
+  int err;
+
+  while (actions_len >= sizeof(ofp_action_header))
+    {
+      ofp_action_header *ah = (ofp_action_header *)p;
+      size_t len = ntohs (ah->len);
+      uint16_t type;
+
+      /* Make there's enough remaining data for the specified length
+        * and that the action length is a multiple of 64 bits. */
+      if ((actions_len < len) || (len % 8) != 0)
+        {
+          return OFPBAC_BAD_LEN;
+        }
+
+      type = ntohs (ah->type);
+      if (Action::IsValidType ((ofp_action_type)type)) // Validate built-in OpenFlow actions.
+        {
+          err = Action::Validate ((ofp_action_type)type, len, key, ah);
+          if (err != ACT_VALIDATION_OK)
+            {
+              return err;
+            }
+        }
+      else if (type == OFPAT_VENDOR)
+        {
+          err = ValidateVendor (key, ah, len);
+          if (err != ACT_VALIDATION_OK)
+            {
+              return err;
+            }
+        }
+      else
+        {
+          return OFPBAC_BAD_TYPE;
+        }
+
+      p += len;
+      actions_len -= len;
+    }
+
+  // Check if there's any trailing garbage.
+  if (actions_len != 0)
+    {
+      return OFPBAC_BAD_LEN;
+    }
+
+  return ACT_VALIDATION_OK;
+}
+
+void
+ExecuteVPortActions (Ptr<OpenFlowSwitchNetDevice> swtch, uint64_t packet_uid, ofpbuf* buffer, sw_flow_key *key, const ofp_action_header *actions, size_t actions_len)
+{
+  /* Every output action needs a separate clone of 'buffer', but the common
+   * case is just a single output action, so that doing a clone and then
+   * freeing the original buffer is wasteful.  So the following code is
+   * slightly obscure just to avoid that. */
+  int prev_port;
+  size_t max_len = 0;     // Initialize to make compiler happy
+  uint16_t in_port = ntohs (key->flow.in_port);
+  uint8_t *p = (uint8_t *)actions;
+  uint16_t type;
+  ofp_action_output *oa;
+
+  prev_port = -1;
+  /* The action list was already validated, so we can be a bit looser
+   * in our sanity-checking. */
+  while (actions_len > 0)
+    {
+      ofp_action_header *ah = (ofp_action_header *)p;
+      size_t len = htons (ah->len);
+      if (prev_port != -1)
+        {
+          swtch->DoOutput (packet_uid, in_port, max_len, prev_port, false);
+          prev_port = -1;
+        }
+
+      if (ah->type == htons (OFPAT_OUTPUT))
+        {
+          oa = (ofp_action_output *)p;
+          prev_port = ntohl (oa->port);
+          max_len = ntohs (oa->max_len);
+        }
+      else
+        {
+          type = ah->type; // ntohs(ah->type);
+          VPortAction::Execute ((ofp_vport_action_type)type, buffer, key, ah);
+        }
+
+      p += len;
+      actions_len -= len;
+    }
+
+  if (prev_port != -1)
+    {
+      swtch->DoOutput (packet_uid, in_port, max_len, prev_port, false);
+    }
+}
+
+uint16_t
+ValidateVPortActions (const ofp_action_header *actions, size_t actions_len)
+{
+  uint8_t *p = (uint8_t *)actions;
+  int err;
+
+  while (actions_len >= sizeof(ofp_action_header))
+    {
+      ofp_action_header *ah = (ofp_action_header *)p;
+      size_t len = ntohs (ah->len);
+      uint16_t type;
+
+      /* Make there's enough remaining data for the specified length
+        * and that the action length is a multiple of 64 bits. */
+      if ((actions_len < len) || (len % 8) != 0)
+        {
+          return OFPBAC_BAD_LEN;
+        }
+
+      type = ntohs (ah->type);
+      if (VPortAction::IsValidType ((ofp_vport_action_type)type)) // Validate "built-in" OpenFlow port table actions.
+        {
+          err = VPortAction::Validate ((ofp_vport_action_type)type, len, ah);
+          if (err != ACT_VALIDATION_OK)
+            {
+              return err;
+            }
+        }
+      else
+        {
+          return OFPBAC_BAD_TYPE;
+        }
+
+      p += len;
+      actions_len -= len;
+    }
+
+  // Check if there's any trailing garbage.
+  if (actions_len != 0)
+    {
+      return OFPBAC_BAD_LEN;
+    }
+
+  return ACT_VALIDATION_OK;
+}
+
+void
+ExecuteVendor (ofpbuf *buffer, const sw_flow_key *key, const ofp_action_header *ah)
+{
+  ofp_action_vendor_header *avh = (ofp_action_vendor_header *)ah;
+
+  switch (ntohl (avh->vendor))
+    {
+    case NX_VENDOR_ID:
+      // Nothing to execute yet.
+      break;
+    case ER_VENDOR_ID:
+      {
+        const er_action_header *erah = (const er_action_header *)avh;
+        EricssonAction::Execute ((er_action_type)ntohs (erah->subtype), buffer, key, erah);
+        break;
+      }
+    default:
+      // This should not be possible due to prior validation.
+      NS_LOG_INFO ("attempt to execute action with unknown vendor: " << ntohl (avh->vendor));
+      break;
+    }
+}
+
+uint16_t
+ValidateVendor (const sw_flow_key *key, const ofp_action_header *ah, uint16_t len)
+{
+  ofp_action_vendor_header *avh;
+  int ret = ACT_VALIDATION_OK;
+
+  if (len < sizeof(ofp_action_vendor_header))
+    {
+      return OFPBAC_BAD_LEN;
+    }
+
+  avh = (ofp_action_vendor_header *)ah;
+
+  switch (ntohl (avh->vendor))
+    {
+    case NX_VENDOR_ID:   // Validate Nicara OpenFlow actions.
+      ret = OFPBAC_BAD_VENDOR_TYPE;   // Nothing to validate yet.
+      break;
+    case ER_VENDOR_ID:   // Validate Ericsson OpenFlow actions.
+      {
+        const er_action_header *erah = (const er_action_header *)avh;
+        ret = EricssonAction::Validate ((er_action_type)ntohs (erah->subtype), len);
+        break;
+      }
+    default:
+      return OFPBAC_BAD_VENDOR;
+    }
+
+  return ret;
+}
+
+}
+
+}
+
+#endif // NS3_OPENFLOW
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/openflow/model/openflow-interface.h	Sat Mar 12 18:35:56 2011 +0000
@@ -0,0 +1,567 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Blake Hurd  <naimorai@gmail.com>
+ */
+#ifndef OPENFLOW_INTERFACE_H
+#define OPENFLOW_INTERFACE_H
+
+#ifdef NS3_OPENFLOW
+
+#include <assert.h>
+#include <errno.h>
+
+// Include OFSI code
+#include "ns3/simulator.h"
+#include "ns3/log.h"
+#include "ns3/net-device.h"
+#include "ns3/packet.h"
+#include "ns3/address.h"
+#include "ns3/nstime.h"
+#include "ns3/mac48-address.h"
+
+#include <set>
+#include <map>
+#include <limits>
+
+// Include main header and Vendor Extension files
+#include "openflow.h"
+#include "nicira-ext.h"
+#include "ericsson-ext.h"
+
+extern "C"
+{
+// Inexplicably, the OpenFlow implementation uses these two reserved words as member names.
+#define private _private
+#define delete _delete
+#define list List
+
+// Include OFSI Library files
+#include "csum.h"
+#include "poll-loop.h"
+#include "rconn.h"
+#include "stp.h"
+#include "vconn.h"
+#include "xtoxll.h"
+
+// Include OFSI Switch files
+#include "chain.h"
+#include "table.h"
+#include "datapath.h" // The functions below are defined in datapath.c
+uint32_t save_buffer (ofpbuf *);
+ofpbuf * retrieve_buffer (uint32_t id);
+void discard_buffer (uint32_t id);
+#include "dp_act.h" // The functions below are defined in dp_act.c
+void set_vlan_vid (ofpbuf *buffer, sw_flow_key *key, const ofp_action_header *ah);
+void set_vlan_pcp (ofpbuf *buffer, sw_flow_key *key, const ofp_action_header *ah);
+void strip_vlan (ofpbuf *buffer, sw_flow_key *key, const ofp_action_header *ah);
+void set_dl_addr (ofpbuf *buffer, sw_flow_key *key, const ofp_action_header *ah);
+void set_nw_addr (ofpbuf *buffer, sw_flow_key *key, const ofp_action_header *ah);
+void set_tp_port (ofpbuf *buffer, sw_flow_key *key, const ofp_action_header *ah);
+void set_mpls_label (ofpbuf *buffer, sw_flow_key *key, const ofp_action_header *ah);
+void set_mpls_exp (ofpbuf *buffer, sw_flow_key *key, const ofp_action_header *ah);
+#include "pt_act.h" // The function below is defined in pt_act.c
+void update_checksums (ofpbuf *buffer, const sw_flow_key *key, uint32_t old_word, uint32_t new_word);
+
+#undef list
+#undef private
+#undef delete
+}
+
+// Capabilities supported by this implementation.
+#define OFP_SUPPORTED_CAPABILITIES ( OFPC_FLOW_STATS            \
+                                     | OFPC_TABLE_STATS         \
+                                     | OFPC_PORT_STATS          \
+                                     | OFPC_MULTI_PHY_TX        \
+                                     | OFPC_VPORT_TABLE)
+
+// Actions supported by this implementation.
+#define OFP_SUPPORTED_ACTIONS ( (1 << OFPAT_OUTPUT)             \
+                                | (1 << OFPAT_SET_VLAN_VID)     \
+                                | (1 << OFPAT_SET_VLAN_PCP)     \
+                                | (1 << OFPAT_STRIP_VLAN)       \
+                                | (1 << OFPAT_SET_DL_SRC)       \
+                                | (1 << OFPAT_SET_DL_DST)       \
+                                | (1 << OFPAT_SET_NW_SRC)       \
+                                | (1 << OFPAT_SET_NW_DST)       \
+                                | (1 << OFPAT_SET_TP_SRC)       \
+                                | (1 << OFPAT_SET_TP_DST)       \
+                                | (1 << OFPAT_SET_MPLS_LABEL)   \
+                                | (1 << OFPAT_SET_MPLS_EXP) )
+
+#define OFP_SUPPORTED_VPORT_TABLE_ACTIONS ( (1 << OFPPAT_OUTPUT)                \
+                                            | (1 << OFPPAT_POP_MPLS)            \
+                                            | (1 << OFPPAT_PUSH_MPLS)           \
+                                            | (1 << OFPPAT_SET_MPLS_LABEL)      \
+                                            | (1 << OFPPAT_SET_MPLS_EXP) )      \
+
+namespace ns3 {
+
+class OpenFlowSwitchNetDevice;
+  
+namespace ofi {
+
+/**
+ * \brief Port and its metadata.
+ *
+ * We need to store port metadata, because OpenFlow dictates that there
+ * exists a type of request where the Controller asks for data about a
+ * port, or multiple ports. Otherwise, we'd refer to it via Ptr<NetDevice>
+ * everywhere.
+ */
+struct Port
+{
+  Port () : config (0),
+            state (0),
+            netdev (0),
+            rx_packets (0),
+            tx_packets (0),
+            rx_bytes (0),
+            tx_bytes (0),
+            tx_dropped (0),
+            mpls_ttl0_dropped (0)
+  {
+  }
+
+  uint32_t config;            ///< Some subset of OFPPC_* flags.
+  uint32_t state;             ///< Some subset of OFPPS_* flags.
+  Ptr<NetDevice> netdev;
+  unsigned long long int rx_packets, tx_packets;
+  unsigned long long int rx_bytes, tx_bytes;
+  unsigned long long int tx_dropped;
+  unsigned long long int mpls_ttl0_dropped;
+};
+
+class Stats
+{
+  public:
+  Stats (ofp_stats_types _type, size_t body_len);
+  
+  /**
+   * \brief Prepares to dump some kind of statistics on the connected OpenFlowSwitchNetDevice.
+   *
+   * \param body Body member of the struct ofp_stats_request.
+   * \param body_len Length of the body member.
+   * \param state State information.
+   * \return 0 if successful, otherwise a negative error code.
+   */
+  int DoInit (const void *body, int body_len, void **state);
+  
+  /**
+   * \brief Appends statistics for OpenFlowSwitchNetDevice to 'buffer'.
+   *
+   * \param swtch The OpenFlowSwitchNetDevice this callback is associated with.
+   * \param state State information.
+   * \param buffer Buffer to append stats reply to.
+   * \return 1 if it should be called again later with another buffer, 0 if it is done, or a negative errno value on failure.
+   */
+  int DoDump (Ptr<OpenFlowSwitchNetDevice> swtch, void *state, ofpbuf *buffer);
+  
+  /**
+   * \brief Cleans any state created by the init or dump functions.
+   *
+   * May not be implemented if no cleanup is required.
+   *
+   * \param state State information to clear.
+   */
+  void DoCleanup (void *state);
+  
+  /**
+   * \brief State of the FlowStats request/reply.
+   */
+  struct FlowStatsState
+  {
+    int table_idx;
+    sw_table_position position;
+    ofp_flow_stats_request rq;
+    time_t now;
+
+    ofpbuf *buffer;
+  };
+  
+  /**
+   * \brief State of the PortStats request/reply.
+   */
+  struct PortStatsState
+  {
+    uint32_t num_ports; ///< Number of ports in host byte order
+    uint32_t *ports;    ///< Array of ports in network byte order
+  };
+  
+  ofp_stats_types type;
+  private:  
+  int DescStatsDump (void *state, ofpbuf *buffer);
+
+  int FlowStatsInit (const void *body, int body_len, void **state);
+  int (*FlowDumpCallback)(sw_flow *flow, void *state);
+  int FlowStatsDump (Ptr<OpenFlowSwitchNetDevice> dp, FlowStatsState *s, ofpbuf *buffer);
+
+  int AggregateStatsInit (const void *body, int body_len, void **state);
+  int (*AggregateDumpCallback)(sw_flow *flow, void *state);
+  int AggregateStatsDump (Ptr<OpenFlowSwitchNetDevice> dp, ofp_aggregate_stats_request *s, ofpbuf *buffer);
+
+  int TableStatsDump (Ptr<OpenFlowSwitchNetDevice> dp, void *state, ofpbuf *buffer);
+
+  int PortStatsInit (const void *body, int body_len, void **state);
+  int PortStatsDump (Ptr<OpenFlowSwitchNetDevice> dp, PortStatsState *s, ofpbuf *buffer);
+
+  int PortTableStatsDump (Ptr<OpenFlowSwitchNetDevice> dp, void *state, ofpbuf *buffer);
+};
+
+/**
+ * \brief Class for handling flow table actions.
+ */
+struct Action
+{
+  /**
+   * \param type Type of Flow Table Action.
+   * \return true if the provided type is a type of flow table action.
+   */
+  static bool IsValidType (ofp_action_type type);
+
+  /**
+   * \brief Validates the action on whether its data is valid or not.
+   *
+   * \param type Type of action to validate.
+   * \param len Length of the action data.
+   * \param key Matching key for the flow that is tied to this action.
+   * \param ah Action's data header.
+   * \return ACT_VALIDATION_OK if the action checks out, otherwise an error type.
+   */
+  static uint16_t Validate (ofp_action_type type, size_t len, const sw_flow_key *key, const ofp_action_header *ah);
+
+  /**
+   * \brief Executes the action.
+   *
+   * \param type Type of action to execute.
+   * \param buffer Buffer of the Packet if it's needed for the action.
+   * \param key Matching key for the flow that is tied to this action.
+   * \param ah Action's data header.
+   */
+  static void Execute (ofp_action_type type, ofpbuf *buffer, sw_flow_key *key, const ofp_action_header *ah);
+};
+
+/**
+ * \brief Class for handling virtual port table actions.
+ */
+struct VPortAction
+{
+  /**
+   * \param type Type of virtual port table Action.
+   * \return true if the provided type is a type of virtual port table action.
+   */
+  static bool IsValidType (ofp_vport_action_type type);
+
+  /**
+   * \brief Validates the action on whether its data is valid or not.
+   *
+   * \param type Type of action to validate.
+   * \param len Length of the action data.
+   * \param ah Action's data header.
+   * \return ACT_VALIDATION_OK if the action checks out, otherwise an error type.
+   */
+  static uint16_t Validate (ofp_vport_action_type type, size_t len, const ofp_action_header *ah);
+
+  /**
+   * \brief Executes the action.
+   *
+   * \param type Type of action to execute.
+   * \param buffer Buffer of the Packet if it's needed for the action.
+   * \param key Matching key for the flow that is tied to this action.
+   * \param ah Action's data header.
+   */
+  static void Execute (ofp_vport_action_type type, ofpbuf *buffer, const sw_flow_key *key, const ofp_action_header *ah);
+};
+
+/**
+ * \brief Class for handling Ericsson Vendor-defined actions.
+ */
+struct EricssonAction
+{
+  /**
+   * \param type Type of Ericsson Vendor-defined Action.
+   * \return true if the provided type is a type of Ericsson Vendor-defined action.
+   */
+  static bool IsValidType (er_action_type type);
+
+  /**
+   * \brief Validates the action on whether its data is valid or not.
+   *
+   * \param type Type of action to validate.
+   * \param len Length of the action data.
+   * \return ACT_VALIDATION_OK if the action checks out, otherwise an error type.
+   */
+  static uint16_t Validate (er_action_type type, size_t len);
+
+  /**
+   * \brief Executes the action.
+   *
+   * \param type Type of action to execute.
+   * \param buffer Buffer of the Packet if it's needed for the action.
+   * \param key Matching key for the flow that is tied to this action.
+   * \param ah Action's data header.
+   */
+  static void Execute (er_action_type type, ofpbuf *buffer, const sw_flow_key *key, const er_action_header *ah);
+};
+
+/**
+ * \brief Callback for a stats dump request.
+ */
+struct StatsDumpCallback
+{
+  bool done;                            ///< Whether we are done requesting stats.
+  ofp_stats_request *rq; 	        ///< Current stats request.
+  Stats *s;                	        ///< Handler of the stats request.
+  void *state;                          ///< Stats request state data.
+  Ptr<OpenFlowSwitchNetDevice> swtch;	///< The switch that we're requesting data from.
+};
+
+/**
+ * \brief Packet Metadata, allows us to track the packet's metadata as it passes through the switch.
+ */
+struct SwitchPacketMetadata
+{
+  Ptr<Packet> packet; ///< The Packet itself.
+  ofpbuf* buffer;               ///< The OpenFlow buffer as created from the Packet, with its data and headers.
+  uint16_t protocolNumber;     	///< Protocol type of the Packet when the Packet is received
+  Address src;             ///< Source Address of the Packet when the Packet is received
+  Address dst;             ///< Destination Address of the Packet when the Packet is received.
+};
+
+/**
+ * \brief An interface for a Controller of OpenFlowSwitchNetDevices
+ *
+ * Follows the OpenFlow specification for a controller.
+ */
+class Controller : public Object
+{
+public:
+  static TypeId GetTypeId (void)
+  {
+    static TypeId tid = TypeId ("ns3::ofi::Controller")
+    .SetParent<Object> ()
+    .AddConstructor<Controller> ()
+    ;
+    return tid;
+  }
+  
+  virtual ~Controller ()
+  {
+    m_switches.clear ();
+  }
+  
+  /**
+   * Adds a switch to the controller.
+   *
+   * \param swtch The switch to register.
+   */
+  virtual void AddSwitch (Ptr<OpenFlowSwitchNetDevice> swtch);
+
+  /**
+   * A switch calls this method to pass a message on to the Controller.
+   *
+   * \param swtch The switch the message was received from.
+   * \param buffer The message.
+   */
+  virtual void ReceiveFromSwitch (Ptr<OpenFlowSwitchNetDevice> swtch, ofpbuf* buffer)
+  {
+  }
+  
+  /**
+   * \brief Starts a callback-based, reliable, possibly multi-message reply to a request made by the controller.
+   *
+   * If an incoming request needs to have a reliable reply that might
+   * require multiple messages, it can use StartDump() to set up
+   * a callback that will be called as buffer space for replies.
+   *
+   * A stats request made by the controller is processed by the switch,
+   * the switch then calls this method to tell the controller to start
+   * asking for information. By default (it can be overridden), the
+   * controller stops all work to run through the callback. ReceiveFromSwitch
+   * must be defined appropriately to handle the status reply messages
+   * generated by the switch, or otherwise the status reply messages will be sent
+   * and discarded.
+   *
+   * \param cb The callback data.
+   */
+  void StartDump (StatsDumpCallback* cb);
+
+protected:
+  /**
+   * \internal
+   *
+   * However the controller is implemented, this method is to
+   * be used to pass a message on to a switch.
+   *
+   * \param swtch The switch to receive the message.
+   * \param msg The message to send.
+   * \param length The length of the message.
+   */
+  virtual void SendToSwitch (Ptr<OpenFlowSwitchNetDevice> swtch, void * msg, size_t length);
+
+  /**
+   * \internal
+   *
+   * Construct flow data from a matching key to build a flow
+   * entry for adding, modifying, or deleting a flow.
+   *
+   * \param key The matching key data; used to create a flow that matches the packet.
+   * \param buffer_id The OpenFlow Buffer ID; used to run the actions on the packet if we add or modify the flow.
+   * \param command Whether to add, modify, or delete this flow.
+   * \param acts List of actions to execute.
+   * \param actions_len Length of the actions buffer.
+   * \param idle_timeout Flow expires if left inactive for this amount of time (specify OFP_FLOW_PERMANENT to disable feature).
+   * \param hard_timeout Flow expires after this amount of time (specify OFP_FLOW_PERMANENT to disable feature).
+   * \return Flow data that when passed to SetFlow will add, modify, or delete a flow it defines.
+   */
+  ofp_flow_mod* BuildFlow (sw_flow_key key, uint32_t buffer_id, uint16_t command, void* acts, size_t actions_len, int idle_timeout, int hard_timeout);
+
+  /**
+   * \internal
+   *
+   * Get the packet type on the buffer, which can then be used
+   * to determine how to handle the buffer.
+   *
+   * \param buffer The packet in OpenFlow buffer format.
+   * \return The packet type, as defined in the ofp_type struct.
+   */
+  uint8_t GetPacketType (ofpbuf* buffer);
+  
+  typedef std::set<Ptr<OpenFlowSwitchNetDevice> > Switches_t;
+  Switches_t m_switches;  ///< The collection of switches registered to this controller.
+};
+
+/**
+ * Demonstration of a Drop controller. When a connected switch
+ * passes it a packet the switch doesn't recognize, the controller
+ * configures the switch to make a flow that drops alike packets.
+ */
+class DropController : public Controller
+{
+public:
+  void ReceiveFromSwitch (Ptr<OpenFlowSwitchNetDevice> swtch, ofpbuf* buffer);
+};
+
+/**
+ * Demonstration of a Learning controller. When a connected switch
+ * passes it a packet the switch doesn't recognize, the controller
+ * delves into its learned states and figures out if we know what
+ * port the packet is supposed to go to, flooding if unknown, and
+ * adjusts the switch's flow table accordingly.
+ */
+class LearningController : public Controller
+{
+public:
+  static TypeId GetTypeId (void);
+  
+  virtual ~LearningController ()
+  {
+    m_learnState.clear ();
+  }
+  
+  void ReceiveFromSwitch (Ptr<OpenFlowSwitchNetDevice> swtch, ofpbuf* buffer);
+
+protected:
+  struct LearnedState
+  {
+    uint32_t port;                      ///< Learned port.
+  };
+  Time m_expirationTime;		///< Time it takes for learned MAC state entry/created flow to expire.
+  typedef std::map<Mac48Address, LearnedState> LearnState_t;
+  LearnState_t m_learnState;            ///< Learned state data.
+};
+
+/**
+ * \brief Executes a list of flow table actions.
+ *
+ * \param swtch OpenFlowSwitchNetDevice these actions are being executed on.
+ * \param packet_uid Packet UID; used to fetch the packet and its metadata.
+ * \param buffer The Packet OpenFlow buffer.
+ * \param key The matching key for the flow tied to this list of actions.
+ * \param actions A buffer of actions.
+ * \param actions_len Length of actions buffer.
+ * \param ignore_no_fwd If true, during port forwarding actions, ports that are set to not forward are forced to forward.
+ */
+void ExecuteActions (Ptr<OpenFlowSwitchNetDevice> swtch, uint64_t packet_uid, ofpbuf* buffer, sw_flow_key *key, const ofp_action_header *actions, size_t actions_len, int ignore_no_fwd);
+
+/**
+ * \brief Validates a list of flow table actions.
+ *
+ * \param key The matching key for the flow tied to this list of actions.
+ * \param actions A buffer of actions.
+ * \param actions_len Length of actions buffer.
+ * \return If the action list validates, ACT_VALIDATION_OK is returned. Otherwise, a code for the OFPET_BAD_ACTION error type is returned.
+ */
+uint16_t ValidateActions (const sw_flow_key *key, const ofp_action_header *actions, size_t actions_len);
+
+/**
+ * \brief Executes a list of virtual port table entry actions.
+ *
+ * \param swtch OpenFlowSwitchNetDevice these actions are being executed on.
+ * \param packet_uid Packet UID; used to fetch the packet and its metadata.
+ * \param buffer The Packet OpenFlow buffer.
+ * \param key The matching key for the flow tied to this list of actions.
+ * \param actions A buffer of actions.
+ * \param actions_len Length of actions buffer.
+ */
+void ExecuteVPortActions (Ptr<OpenFlowSwitchNetDevice> swtch, uint64_t packet_uid, ofpbuf* buffer, sw_flow_key *key, const ofp_action_header *actions, size_t actions_len);
+
+/**
+ * \brief Validates a list of virtual port table entry actions.
+ *
+ * \param actions A buffer of actions.
+ * \param actions_len Length of actions buffer.
+ * \return If the action list validates, ACT_VALIDATION_OK is returned. Otherwise, a code for the OFPET_BAD_ACTION error type is returned.
+ */
+uint16_t ValidateVPortActions (const ofp_action_header *actions, size_t actions_len);
+
+/**
+ * \brief Executes a vendor-defined action.
+ *
+ * \param buffer The Packet OpenFlow buffer.
+ * \param key The matching key for the flow tied to this list of actions.
+ * \param ah Header of the action.
+ */
+void ExecuteVendor (ofpbuf *buffer, const sw_flow_key *key, const ofp_action_header *ah);
+
+/**
+ * \brief Validates a vendor-defined action.
+ *
+ * \param key The matching key for the flow tied to this list of actions.
+ * \param ah Header of the action.
+ * \param len Length of the action.
+ * \return If the action list validates, ACT_VALIDATION_OK is returned. Otherwise, a code for the OFPET_BAD_ACTION error type is returned.
+ */
+uint16_t ValidateVendor (const sw_flow_key *key, const ofp_action_header *ah, uint16_t len);
+
+/* 
+ * From datapath.c
+ * Buffers are identified to userspace by a 31-bit opaque ID.  We divide the ID
+ * into a buffer number (low bits) and a cookie (high bits).  The buffer number
+ * is an index into an array of buffers.  The cookie distinguishes between
+ * different packets that have occupied a single buffer.  Thus, the more
+ * buffers we have, the lower-quality the cookie...
+ */
+#define PKT_BUFFER_BITS 8
+#define N_PKT_BUFFERS (1 << PKT_BUFFER_BITS)
+#define PKT_BUFFER_MASK (N_PKT_BUFFERS - 1)
+#define PKT_COOKIE_BITS (32 - PKT_BUFFER_BITS)
+
+}
+
+}
+
+#endif // NS3_OPENFLOW
+#endif /* OPENFLOW_INTERFACE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/openflow/model/openflow-switch-net-device.cc	Sat Mar 12 18:35:56 2011 +0000
@@ -0,0 +1,1584 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Blake Hurd  <naimorai@gmail.com>
+ */
+#ifdef NS3_OPENFLOW
+
+#include "openflow-switch-net-device.h"
+
+NS_LOG_COMPONENT_DEFINE ("OpenFlowSwitchNetDevice");
+
+namespace ns3 {
+
+NS_OBJECT_ENSURE_REGISTERED (OpenFlowSwitchNetDevice);
+
+const char *
+OpenFlowSwitchNetDevice::GetManufacturerDescription ()
+{
+  return "The ns-3 team";
+}
+
+const char *
+OpenFlowSwitchNetDevice::GetHardwareDescription ()
+{
+  return "N/A";
+}
+
+const char *
+OpenFlowSwitchNetDevice::GetSoftwareDescription ()
+{
+  return "Simulated OpenFlow Switch";
+}
+
+const char *
+OpenFlowSwitchNetDevice::GetSerialNumber ()
+{
+  return "N/A";
+}
+
+static uint64_t
+GenerateId ()
+{
+  uint8_t ea[ETH_ADDR_LEN];
+  eth_addr_random (ea);
+  return eth_addr_to_uint64 (ea);
+}
+
+TypeId
+OpenFlowSwitchNetDevice::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::OpenFlowSwitchNetDevice")
+    .SetParent<NetDevice> ()
+    .AddConstructor<OpenFlowSwitchNetDevice> ()
+    .AddAttribute ("ID",
+                   "The identification of the OpenFlowSwitchNetDevice/Datapath, needed for OpenFlow compatibility.",
+                   UintegerValue (GenerateId ()),
+                   MakeUintegerAccessor (&OpenFlowSwitchNetDevice::m_id),
+                   MakeUintegerChecker<uint64_t> ())
+    .AddAttribute ("FlowTableLookupDelay",
+                   "A real switch will have an overhead for looking up in the flow table. For the default, we simulate a standard TCAM on an FPGA.",
+                   TimeValue (NanoSeconds (30)),
+                   MakeTimeAccessor (&OpenFlowSwitchNetDevice::m_lookupDelay),
+                   MakeTimeChecker ())
+    .AddAttribute ("Flags", // Note: The Controller can configure this value, overriding the user's setting.
+		   "Flags to turn different functionality on/off, such as whether to inform the controller when a flow expires, or how to handle fragments.",
+		   UintegerValue (0), // Look at the ofp_config_flags enum in openflow/include/openflow.h for options.
+		   MakeUintegerAccessor (&OpenFlowSwitchNetDevice::m_flags),
+		   MakeUintegerChecker<uint16_t> ())
+    .AddAttribute ("FlowTableMissSendLength", // Note: The Controller can configure this value, overriding the user's setting.
+		   "When forwarding a packet the switch didn't match up to the controller, it can be more efficient to forward only the first x bytes.",
+		   UintegerValue (OFP_DEFAULT_MISS_SEND_LEN), // 128 bytes
+		   MakeUintegerAccessor (&OpenFlowSwitchNetDevice::m_missSendLen),
+		   MakeUintegerChecker<uint16_t> ())
+  ;
+  return tid;
+}
+
+OpenFlowSwitchNetDevice::OpenFlowSwitchNetDevice ()
+  : m_node (0),
+    m_ifIndex (0),
+    m_mtu (0xffff)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+
+  m_channel = CreateObject<BridgeChannel> ();
+
+  time_init (); // OFSI's clock; needed to use the buffer storage system.
+  // m_lastTimeout = time_now ();
+
+  m_controller = 0;
+  // m_listenPVConn = 0;
+
+  m_chain = chain_create ();
+  if (m_chain == 0)
+    {
+      NS_LOG_ERROR ("Not enough memory to create the flow table.");
+    }
+
+  m_ports.reserve (DP_MAX_PORTS);
+  vport_table_init (&m_vportTable);
+}
+
+OpenFlowSwitchNetDevice::~OpenFlowSwitchNetDevice ()
+{
+  NS_LOG_FUNCTION_NOARGS ();
+}
+
+void
+OpenFlowSwitchNetDevice::DoDispose ()
+{
+  NS_LOG_FUNCTION_NOARGS ();
+
+  for (Ports_t::iterator b = m_ports.begin (), e = m_ports.end (); b != e; b++)
+    {
+      SendPortStatus (*b, OFPPR_DELETE);
+      b->netdev = 0;
+    }
+  m_ports.clear ();
+
+  m_controller = 0;
+
+  chain_destroy (m_chain);
+  RBTreeDestroy (m_vportTable.table);
+  m_channel = 0;
+  m_node = 0;
+  NetDevice::DoDispose ();
+}
+
+void
+OpenFlowSwitchNetDevice::SetController (Ptr<ofi::Controller> c)
+{
+  if (m_controller != 0)
+    {
+      NS_LOG_ERROR ("Controller already set.");
+      return;
+    }
+
+  m_controller = c;
+  m_controller->AddSwitch (this);
+}
+
+int
+OpenFlowSwitchNetDevice::AddSwitchPort (Ptr<NetDevice> switchPort)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  NS_ASSERT (switchPort != this);
+  if (!Mac48Address::IsMatchingType (switchPort->GetAddress ()))
+    {
+      NS_FATAL_ERROR ("Device does not support eui 48 addresses: cannot be added to switch.");
+    }
+  if (!switchPort->SupportsSendFrom ())
+    {
+      NS_FATAL_ERROR ("Device does not support SendFrom: cannot be added to switch.");
+    }
+  if (m_address == Mac48Address ())
+    {
+      m_address = Mac48Address::ConvertFrom (switchPort->GetAddress ());
+    }
+
+  if (m_ports.size () < DP_MAX_PORTS)
+    {
+      ofi::Port p;
+      p.config = 0;
+      p.netdev = switchPort;
+      m_ports.push_back (p);
+
+      // Notify the controller that this port has been added
+      SendPortStatus (p, OFPPR_ADD);
+
+      NS_LOG_DEBUG ("RegisterProtocolHandler for " << switchPort->GetInstanceTypeId ().GetName ());
+      m_node->RegisterProtocolHandler (MakeCallback (&OpenFlowSwitchNetDevice::ReceiveFromDevice, this),
+                                       0, switchPort, true);
+      m_channel->AddChannel (switchPort->GetChannel ());
+    }
+  else
+    {
+      return EXFULL;
+    }
+
+  return 0;
+}
+
+void
+OpenFlowSwitchNetDevice::SetIfIndex (const uint32_t index)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  m_ifIndex = index;
+}
+
+uint32_t
+OpenFlowSwitchNetDevice::GetIfIndex (void) const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return m_ifIndex;
+}
+
+Ptr<Channel>
+OpenFlowSwitchNetDevice::GetChannel (void) const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return m_channel;
+}
+
+void
+OpenFlowSwitchNetDevice::SetAddress (Address address)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  m_address = Mac48Address::ConvertFrom (address);
+}
+
+Address
+OpenFlowSwitchNetDevice::GetAddress (void) const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return m_address;
+}
+
+bool
+OpenFlowSwitchNetDevice::SetMtu (const uint16_t mtu)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  m_mtu = mtu;
+  return true;
+}
+
+uint16_t
+OpenFlowSwitchNetDevice::GetMtu (void) const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return m_mtu;
+}
+
+
+bool
+OpenFlowSwitchNetDevice::IsLinkUp (void) const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return true;
+}
+
+
+void
+OpenFlowSwitchNetDevice::AddLinkChangeCallback (Callback<void> callback)
+{
+}
+
+bool
+OpenFlowSwitchNetDevice::IsBroadcast (void) const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return true;
+}
+
+Address
+OpenFlowSwitchNetDevice::GetBroadcast (void) const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return Mac48Address ("ff:ff:ff:ff:ff:ff");
+}
+
+bool
+OpenFlowSwitchNetDevice::IsMulticast (void) const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return true;
+}
+
+Address
+OpenFlowSwitchNetDevice::GetMulticast (Ipv4Address multicastGroup) const
+{
+  NS_LOG_FUNCTION (this << multicastGroup);
+  Mac48Address multicast = Mac48Address::GetMulticast (multicastGroup);
+  return multicast;
+}
+
+
+bool
+OpenFlowSwitchNetDevice::IsPointToPoint (void) const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return false;
+}
+
+bool
+OpenFlowSwitchNetDevice::IsBridge (void) const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return true;
+}
+
+void
+OpenFlowSwitchNetDevice::DoOutput (uint32_t packet_uid, int in_port, size_t max_len, int out_port, bool ignore_no_fwd)
+{
+  if (out_port != OFPP_CONTROLLER)
+    {
+      OutputPort (packet_uid, in_port, out_port, ignore_no_fwd);
+    }
+  else
+    {
+      OutputControl (packet_uid, in_port, max_len, OFPR_ACTION);
+    }
+}
+
+bool
+OpenFlowSwitchNetDevice::Send (Ptr<Packet> packet, const Address& dest, uint16_t protocolNumber)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return SendFrom (packet, m_address, dest, protocolNumber);
+}
+
+bool
+OpenFlowSwitchNetDevice::SendFrom (Ptr<Packet> packet, const Address& src, const Address& dest, uint16_t protocolNumber)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+
+  ofpbuf *buffer = BufferFromPacket (packet,src,dest,GetMtu (),protocolNumber);
+
+  uint32_t packet_uid = save_buffer (buffer);
+  ofi::SwitchPacketMetadata data;
+  data.packet = packet;
+  data.buffer = buffer;
+  data.protocolNumber = protocolNumber;
+  data.src = Address (src);
+  data.dst = Address (dest);
+  m_packetData.insert (std::make_pair (packet_uid, data));
+
+  RunThroughFlowTable (packet_uid, -1);
+
+  return true;
+}
+
+
+Ptr<Node>
+OpenFlowSwitchNetDevice::GetNode (void) const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return m_node;
+}
+
+void
+OpenFlowSwitchNetDevice::SetNode (Ptr<Node> node)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  m_node = node;
+}
+
+bool
+OpenFlowSwitchNetDevice::NeedsArp (void) const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return true;
+}
+
+void
+OpenFlowSwitchNetDevice::SetReceiveCallback (NetDevice::ReceiveCallback cb)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  m_rxCallback = cb;
+}
+
+void
+OpenFlowSwitchNetDevice::SetPromiscReceiveCallback (NetDevice::PromiscReceiveCallback cb)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  m_promiscRxCallback = cb;
+}
+
+bool
+OpenFlowSwitchNetDevice::SupportsSendFrom () const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return true;
+}
+
+Address
+OpenFlowSwitchNetDevice::GetMulticast (Ipv6Address addr) const
+{
+  NS_LOG_FUNCTION (this << addr);
+  return Mac48Address::GetMulticast (addr);
+}
+
+// Add a virtual port table entry.
+int
+OpenFlowSwitchNetDevice::AddVPort (const ofp_vport_mod *ovpm)
+{
+  size_t actions_len = ntohs (ovpm->header.length) - sizeof *ovpm;
+  unsigned int vport = ntohl (ovpm->vport);
+  unsigned int parent_port = ntohl (ovpm->parent_port);
+
+  // check whether port table entry exists for specified port number
+  vport_table_entry *vpe = vport_table_lookup (&m_vportTable, vport);
+  if (vpe != 0)
+    {
+      NS_LOG_ERROR ("vport " << vport << " already exists!");
+      SendErrorMsg (OFPET_BAD_ACTION, OFPET_VPORT_MOD_FAILED, ovpm, ntohs (ovpm->header.length));
+      return EINVAL;
+    }
+
+  // check whether actions are valid
+  uint16_t v_code = ofi::ValidateVPortActions (ovpm->actions, actions_len);
+  if (v_code != ACT_VALIDATION_OK)
+    {
+      SendErrorMsg (OFPET_BAD_ACTION, v_code, ovpm, ntohs (ovpm->header.length));
+      return EINVAL;
+    }
+
+  vpe = vport_table_entry_alloc (actions_len);
+
+  vpe->vport = vport;
+  vpe->parent_port = parent_port;
+  if (vport < OFPP_VP_START || vport > OFPP_VP_END)
+    {
+      NS_LOG_ERROR ("port " << vport << " is not in the virtual port range (" << OFPP_VP_START << "-" << OFPP_VP_END << ")");
+      SendErrorMsg (OFPET_BAD_ACTION, OFPET_VPORT_MOD_FAILED, ovpm, ntohs (ovpm->header.length));
+      free_vport_table_entry (vpe); // free allocated entry
+      return EINVAL;
+    }
+
+  vpe->port_acts->actions_len = actions_len;
+  memcpy (vpe->port_acts->actions, ovpm->actions, actions_len);
+
+  int error = insert_vport_table_entry (&m_vportTable, vpe);
+  if (error)
+    {
+      NS_LOG_ERROR ("could not insert port table entry for port " << vport);
+    }
+
+  return error;
+}
+
+ofpbuf *
+OpenFlowSwitchNetDevice::BufferFromPacket (Ptr<Packet> packet, Address src, Address dst, int mtu, uint16_t protocol)
+{
+  NS_LOG_INFO ("Creating Openflow buffer from packet.");
+
+  /*
+   * Allocate buffer with some headroom to add headers in forwarding
+   * to the controller or adding a vlan tag, plus an extra 2 bytes to
+   * allow IP headers to be aligned on a 4-byte boundary.
+   */
+  const int headroom = 128 + 2;
+  const int hard_header = VLAN_ETH_HEADER_LEN;
+  ofpbuf *buffer = ofpbuf_new (headroom + hard_header + mtu);
+  buffer->data = (char*)buffer->data + headroom + hard_header;
+
+  int l2_length = 0, l3_length = 0, l4_length = 0;
+
+  // Load headers
+  EthernetHeader eth_hd;
+  if (packet->PeekHeader (eth_hd))
+    {
+      buffer->l2 = new eth_header;
+      eth_header* eth_h = (eth_header*)buffer->l2;
+      dst.CopyTo (eth_h->eth_dst);              // Destination Mac Address
+      src.CopyTo (eth_h->eth_src);              // Source Mac Address
+      eth_h->eth_type = htons (ETH_TYPE_IP);    // Ether Type
+      NS_LOG_INFO ("Parsed EthernetHeader");
+
+      l2_length = ETH_HEADER_LEN;
+    }
+
+  // We have to wrap this because PeekHeader has an assert fail if we check for an Ipv4Header that isn't there.
+  if (protocol == Ipv4L3Protocol::PROT_NUMBER)
+    {
+      Ipv4Header ip_hd;
+      if (packet->PeekHeader (ip_hd))
+        {
+          buffer->l3 = new ip_header;
+          ip_header* ip_h = (ip_header*)buffer->l3;
+          ip_h->ip_ihl_ver  = IP_IHL_VER (5, IP_VERSION);       // Version
+          ip_h->ip_tos      = ip_hd.GetTos ();                  // Type of Service/Differentiated Services
+          ip_h->ip_tot_len  = packet->GetSize ();               // Total Length
+          ip_h->ip_id       = ip_hd.GetIdentification ();       // Identification
+          ip_h->ip_frag_off = ip_hd.GetFragmentOffset ();       // Fragment Offset
+          ip_h->ip_ttl      = ip_hd.GetTtl ();                  // Time to Live
+          ip_h->ip_proto    = ip_hd.GetProtocol ();             // Protocol
+          ip_h->ip_src      = htonl (ip_hd.GetSource ().Get ()); // Source Address
+          ip_h->ip_dst      = htonl (ip_hd.GetDestination ().Get ()); // Destination Address
+          ip_h->ip_csum     = csum (&ip_h, sizeof ip_h);        // Header Checksum
+          NS_LOG_INFO ("Parsed Ipv4Header");
+
+          l3_length = IP_HEADER_LEN;
+        }
+    }
+  else
+    {
+      // ARP Packet; the underlying OpenFlow header isn't used to match, so this is probably superfluous.
+      ArpHeader arp_hd;
+      if (packet->PeekHeader (arp_hd))
+        {
+          buffer->l3 = new arp_eth_header;
+          arp_eth_header* arp_h = (arp_eth_header*)buffer->l3;
+          arp_h->ar_hrd = ARP_HRD_ETHERNET;                             // Hardware type.
+          arp_h->ar_pro = ARP_PRO_IP;                                   // Protocol type.
+          arp_h->ar_op = arp_hd.m_type;                                 // Opcode.
+          arp_hd.GetDestinationHardwareAddress ().CopyTo (arp_h->ar_tha); // Target hardware address.
+          arp_hd.GetSourceHardwareAddress ().CopyTo (arp_h->ar_sha);    // Sender hardware address.
+          arp_h->ar_tpa = arp_hd.GetDestinationIpv4Address ().Get ();   // Target protocol address.
+          arp_h->ar_spa = arp_hd.GetSourceIpv4Address ().Get ();        // Sender protocol address.
+          arp_h->ar_hln = sizeof arp_h->ar_tha;                         // Hardware address length.
+          arp_h->ar_pln = sizeof arp_h->ar_tpa;                         // Protocol address length.
+          NS_LOG_INFO ("Parsed ArpHeader");
+
+          l3_length = ARP_ETH_HEADER_LEN;
+        }
+    }
+
+  TcpHeader tcp_hd;
+  if (packet->PeekHeader (tcp_hd))
+    {
+      buffer->l4 = new tcp_header;
+      tcp_header* tcp_h = (tcp_header*)buffer->l4;
+      tcp_h->tcp_src = htonl (tcp_hd.GetSourcePort ());         // Source Port
+      tcp_h->tcp_dst = htonl (tcp_hd.GetDestinationPort ());    // Destination Port
+      tcp_h->tcp_seq = tcp_hd.GetSequenceNumber ().GetValue (); // Sequence Number
+      tcp_h->tcp_ack = tcp_hd.GetAckNumber ().GetValue ();      // ACK Number
+      tcp_h->tcp_ctl = TCP_FLAGS (tcp_hd.GetFlags ());  // Data Offset + Reserved + Flags
+      tcp_h->tcp_winsz = tcp_hd.GetWindowSize ();       // Window Size
+      tcp_h->tcp_urg = tcp_hd.GetUrgentPointer ();      // Urgent Pointer
+      tcp_h->tcp_csum = csum (&tcp_h, sizeof tcp_h);    // Header Checksum
+      NS_LOG_INFO ("Parsed TcpHeader");
+
+      l4_length = TCP_HEADER_LEN;
+    }
+  else
+    {
+      UdpHeader udp_hd;
+      if (packet->PeekHeader (udp_hd))
+        {
+          buffer->l4 = new udp_header;
+          udp_header* udp_h = (udp_header*)buffer->l4;
+          udp_h->udp_src = htonl (udp_hd.GetSourcePort ());     // Source Port
+          udp_h->udp_dst = htonl (udp_hd.GetDestinationPort ()); // Destination Port
+          udp_h->udp_len = htons (UDP_HEADER_LEN + packet->GetSize ());
+
+          if (protocol == Ipv4L3Protocol::PROT_NUMBER)
+            {
+              ip_header* ip_h = (ip_header*)buffer->l3;
+              uint32_t udp_csum = csum_add32 (0, ip_h->ip_src);
+              udp_csum = csum_add32 (udp_csum, ip_h->ip_dst);
+              udp_csum = csum_add16 (udp_csum, IP_TYPE_UDP << 8);
+              udp_csum = csum_add16 (udp_csum, udp_h->udp_len);
+              udp_csum = csum_continue (udp_csum, udp_h, sizeof udp_h);
+              udp_h->udp_csum = csum_finish (csum_continue (udp_csum, buffer->data, buffer->size)); // Header Checksum
+            }
+          else
+            {
+              udp_h->udp_csum = htons (0);
+            }
+          NS_LOG_INFO ("Parsed UdpHeader");
+
+          l4_length = UDP_HEADER_LEN;
+        }
+    }
+
+  // Load Packet data into buffer data
+  packet->CopyData ((uint8_t*)buffer->data, packet->GetSize ());
+
+  if (buffer->l4)
+    {
+      ofpbuf_push (buffer, buffer->l4, l4_length);
+      delete (tcp_header*)buffer->l4;
+    }
+  if (buffer->l3)
+    {
+      ofpbuf_push (buffer, buffer->l3, l3_length);
+      delete (ip_header*)buffer->l3;
+    }
+  if (buffer->l2)
+    {
+      ofpbuf_push (buffer, buffer->l2, l2_length);
+      delete (eth_header*)buffer->l2;
+    }
+
+  return buffer;
+}
+
+void
+OpenFlowSwitchNetDevice::ReceiveFromDevice (Ptr<NetDevice> netdev, Ptr<const Packet> packet, uint16_t protocol,
+                                    const Address& src, const Address& dst, PacketType packetType)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_INFO ("--------------------------------------------");
+  NS_LOG_DEBUG ("UID is " << packet->GetUid ());
+
+  if (!m_promiscRxCallback.IsNull ())
+    {
+      m_promiscRxCallback (this, packet, protocol, src, dst, packetType);
+    }
+
+  Mac48Address dst48 = Mac48Address::ConvertFrom (dst);
+  NS_LOG_INFO ("Received packet from " << Mac48Address::ConvertFrom (src) << " looking for " << dst48);
+
+  for (size_t i = 0; i < m_ports.size (); i++)
+    {
+      if (m_ports[i].netdev == netdev)
+        {
+          if (packetType == PACKET_HOST && dst48 == m_address)
+            {
+              m_rxCallback (this, packet, protocol, src);
+            }
+          else if (packetType == PACKET_BROADCAST || packetType == PACKET_MULTICAST || packetType == PACKET_OTHERHOST)
+            {
+              if (packetType == PACKET_OTHERHOST && dst48 == m_address)
+                {
+                  m_rxCallback (this, packet, protocol, src);
+                }
+              else
+                {
+                  if (packetType != PACKET_OTHERHOST)
+                    {
+                      m_rxCallback (this, packet, protocol, src);
+                    }
+
+                  ofi::SwitchPacketMetadata data;
+                  data.packet = packet->Copy ();
+
+                  ofpbuf *buffer = BufferFromPacket (data.packet,src,dst,netdev->GetMtu (),protocol);
+                  m_ports[i].rx_packets++;
+                  m_ports[i].rx_bytes += buffer->size;
+                  data.buffer = buffer;
+                  uint32_t packet_uid = save_buffer (buffer);
+
+                  data.protocolNumber = protocol;
+                  data.src = Address (src);
+                  data.dst = Address (dst);
+                  m_packetData.insert (std::make_pair (packet_uid, data));
+
+                  RunThroughFlowTable (packet_uid, i);
+                }
+            }
+
+          break;
+        }
+    }
+  
+  // Run periodic execution.
+  Time now = Simulator::Now();
+  if (now >= Seconds (m_lastExecute.GetSeconds () + 1)) // If a second or more has passed from the simulation time, execute.
+    {
+      // If port status is modified in any way, notify the controller.
+      for (size_t i = 0; i < m_ports.size (); i++)
+        {
+          if (UpdatePortStatus (m_ports[i]))
+            {
+              SendPortStatus (m_ports[i], OFPPR_MODIFY);
+            }
+        }
+
+      // If any flows have expired, delete them and notify the controller.
+      List deleted = LIST_INITIALIZER (&deleted);
+      sw_flow *f, *n;
+      chain_timeout (m_chain, &deleted);
+      LIST_FOR_EACH_SAFE (f, n, sw_flow, node, &deleted)
+      {
+	std::ostringstream str;
+	str << "Flow [";
+	for (int i = 0; i < 6; i++)
+	  str << (i!=0?":":"") << std::hex << f->key.flow.dl_src[i]/16 << f->key.flow.dl_src[i]%16;
+	str << " -> ";
+	for (int i = 0; i < 6; i++)
+	  str << (i!=0?":":"") << std::hex << f->key.flow.dl_dst[i]/16 << f->key.flow.dl_dst[i]%16;
+	str <<  "] expired.";
+	
+	NS_LOG_INFO (str.str ());
+        SendFlowExpired (f, (ofp_flow_expired_reason)f->reason);
+        list_remove (&f->node);
+        flow_free (f);
+      }
+      
+      m_lastExecute = now;
+    }
+}
+
+int
+OpenFlowSwitchNetDevice::OutputAll (uint32_t packet_uid, int in_port, bool flood)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_INFO ("Flooding over ports.");
+
+  int prev_port = -1;
+  for (size_t i = 0; i < m_ports.size (); i++)
+    {
+      if (i == (unsigned)in_port) // Originating port
+        {
+          continue;
+        }
+      if (flood && m_ports[i].config & OFPPC_NO_FLOOD) // Port configured to not allow flooding
+        {
+          continue;
+        }
+      if (prev_port != -1)
+        {
+          OutputPort (packet_uid, in_port, prev_port, false);
+        }
+      prev_port = i;
+    }
+  if (prev_port != -1)
+    {
+      OutputPort (packet_uid, in_port, prev_port, false);
+    }
+
+  return 0;
+}
+
+void
+OpenFlowSwitchNetDevice::OutputPacket (uint32_t packet_uid, int out_port)
+{
+  if (out_port >= 0 && out_port < DP_MAX_PORTS)
+    {
+      ofi::Port& p = m_ports[out_port];
+      if (p.netdev != 0 && !(p.config & OFPPC_PORT_DOWN))
+        {
+          ofi::SwitchPacketMetadata data = m_packetData.find (packet_uid)->second;
+          size_t bufsize = data.buffer->size;
+          NS_LOG_INFO ("Sending packet " << data.packet->GetUid () << " over port " << out_port);
+          if (p.netdev->SendFrom (data.packet->Copy (), data.src, data.dst, data.protocolNumber))
+            {
+              p.tx_packets++;
+              p.tx_bytes += bufsize;
+            }
+          else
+            {
+              p.tx_dropped++;
+            }
+          return;
+        }
+    }
+
+  NS_LOG_DEBUG ("can't forward to bad port " << out_port);
+}
+
+void
+OpenFlowSwitchNetDevice::OutputPort (uint32_t packet_uid, int in_port, int out_port, bool ignore_no_fwd)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+
+  if (out_port == OFPP_FLOOD)
+    {
+      OutputAll (packet_uid, in_port, true);
+    }
+  else if (out_port == OFPP_ALL)
+    {
+      OutputAll (packet_uid, in_port, false);
+    }
+  else if (out_port == OFPP_CONTROLLER)
+    {
+      OutputControl (packet_uid, in_port, 0, OFPR_ACTION);
+    }
+  else if (out_port == OFPP_IN_PORT)
+    {
+      OutputPacket (packet_uid, in_port);
+    }
+  else if (out_port == OFPP_TABLE)
+    {
+      RunThroughFlowTable (packet_uid, in_port < DP_MAX_PORTS ? in_port : -1, false);
+    }
+  else if (out_port >= OFPP_VP_START && out_port <= OFPP_VP_END)
+    {
+      // port is a virtual port
+      NS_LOG_INFO ("packet sent to virtual port " << out_port);
+      if (in_port < DP_MAX_PORTS)
+        {
+          RunThroughVPortTable (packet_uid, in_port, out_port);
+        }
+      else
+        {
+          RunThroughVPortTable (packet_uid, -1, out_port);
+        }
+    }
+  else if (in_port == out_port)
+    {
+      NS_LOG_DEBUG ("can't directly forward to input port");
+    }
+  else
+    {
+      OutputPacket (packet_uid, out_port);
+    }
+}
+
+void*
+OpenFlowSwitchNetDevice::MakeOpenflowReply (size_t openflow_len, uint8_t type, ofpbuf **bufferp)
+{
+  return make_openflow_xid (openflow_len, type, 0, bufferp);
+}
+
+int
+OpenFlowSwitchNetDevice::SendOpenflowBuffer (ofpbuf *buffer)
+{
+  if (m_controller != 0)
+    {
+      update_openflow_length (buffer);
+      m_controller->ReceiveFromSwitch (this, buffer);
+    }
+
+  return 0;
+}
+
+void
+OpenFlowSwitchNetDevice::OutputControl (uint32_t packet_uid, int in_port, size_t max_len, int reason)
+{
+  NS_LOG_INFO ("Sending packet to controller");
+
+  ofpbuf* buffer = m_packetData.find (packet_uid)->second.buffer;
+  size_t total_len = buffer->size;
+  if (packet_uid != std::numeric_limits<uint32_t>::max () && max_len != 0 && buffer->size > max_len)
+    {
+      buffer->size = max_len;
+    }
+
+  ofp_packet_in *opi = (ofp_packet_in*)ofpbuf_push_uninit (buffer, offsetof (ofp_packet_in, data));
+  opi->header.version = OFP_VERSION;
+  opi->header.type    = OFPT_PACKET_IN;
+  opi->header.length  = htons (buffer->size);
+  opi->header.xid     = htonl (0);
+  opi->buffer_id      = htonl (packet_uid);
+  opi->total_len      = htons (total_len);
+  opi->in_port        = htons (in_port);
+  opi->reason         = reason;
+  opi->pad            = 0;
+  SendOpenflowBuffer (buffer);
+}
+
+void
+OpenFlowSwitchNetDevice::FillPortDesc (ofi::Port p, ofp_phy_port *desc)
+{
+  desc->port_no = htons (GetSwitchPortIndex (p));
+
+  std::ostringstream nm;
+  nm << "eth" << GetSwitchPortIndex (p);
+  strncpy ((char *)desc->name, nm.str ().c_str (), sizeof desc->name);
+
+  p.netdev->GetAddress ().CopyTo (desc->hw_addr);
+  desc->config = htonl (p.config);
+  desc->state = htonl (p.state);
+  
+  // TODO: This should probably be fixed eventually to specify different available features.
+  desc->curr = 0; // htonl(netdev_get_features(p->netdev, NETDEV_FEAT_CURRENT));
+  desc->supported = 0; // htonl(netdev_get_features(p->netdev, NETDEV_FEAT_SUPPORTED));
+  desc->advertised = 0; // htonl(netdev_get_features(p->netdev, NETDEV_FEAT_ADVERTISED));
+  desc->peer = 0; // htonl(netdev_get_features(p->netdev, NETDEV_FEAT_PEER));
+}
+
+void
+OpenFlowSwitchNetDevice::SendFeaturesReply ()
+{
+  ofpbuf *buffer;
+  ofp_switch_features *ofr = (ofp_switch_features*)MakeOpenflowReply (sizeof *ofr, OFPT_FEATURES_REPLY, &buffer);
+  ofr->datapath_id  = htonll (m_id);
+  ofr->n_tables     = m_chain->n_tables;
+  ofr->n_buffers    = htonl (N_PKT_BUFFERS);
+  ofr->capabilities = htonl (OFP_SUPPORTED_CAPABILITIES);
+  ofr->actions      = htonl (OFP_SUPPORTED_ACTIONS);
+
+  for (size_t i = 0; i < m_ports.size (); i++)
+    {
+      ofp_phy_port* opp = (ofp_phy_port*)ofpbuf_put_zeros (buffer, sizeof *opp);
+      FillPortDesc (m_ports[i], opp);
+    }
+
+  SendOpenflowBuffer (buffer);
+}
+
+void
+OpenFlowSwitchNetDevice::SendVPortTableFeatures ()
+{
+  ofpbuf *buffer;
+  ofp_vport_table_features *ovtfr = (ofp_vport_table_features*)MakeOpenflowReply (sizeof *ovtfr, OFPT_VPORT_TABLE_FEATURES_REPLY, &buffer);
+  ovtfr->actions = htonl (OFP_SUPPORTED_VPORT_TABLE_ACTIONS);
+  ovtfr->max_vports = htonl (m_vportTable.max_vports);
+  ovtfr->max_chain_depth = htons (-1); // support a chain depth of 2^16
+  ovtfr->mixed_chaining = true;
+  SendOpenflowBuffer (buffer);
+}
+
+int
+OpenFlowSwitchNetDevice::UpdatePortStatus (ofi::Port& p)
+{
+  uint32_t orig_config = p.config;
+  uint32_t orig_state = p.state;
+
+  // Port is always enabled because the Net Device is always enabled.
+  p.config &= ~OFPPC_PORT_DOWN;
+
+  if (p.netdev->IsLinkUp ())
+    {
+      p.state &= ~OFPPS_LINK_DOWN;
+    }
+  else
+    {
+      p.state |= OFPPS_LINK_DOWN;
+    }
+
+  return ((orig_config != p.config) || (orig_state != p.state));
+}
+
+void
+OpenFlowSwitchNetDevice::SendPortStatus (ofi::Port p, uint8_t status)
+{
+  ofpbuf *buffer;
+  ofp_port_status *ops = (ofp_port_status*)MakeOpenflowReply (sizeof *ops, OFPT_PORT_STATUS, &buffer);
+  ops->reason = status;
+  memset (ops->pad, 0, sizeof ops->pad);
+  FillPortDesc (p, &ops->desc);
+
+  SendOpenflowBuffer (buffer);
+  ofpbuf_delete (buffer);
+}
+
+void
+OpenFlowSwitchNetDevice::SendFlowExpired (sw_flow *flow, enum ofp_flow_expired_reason reason)
+{
+  ofpbuf *buffer;
+  ofp_flow_expired *ofe = (ofp_flow_expired*)MakeOpenflowReply (sizeof *ofe, OFPT_FLOW_EXPIRED, &buffer);
+  flow_fill_match (&ofe->match, &flow->key);
+
+  ofe->priority = htons (flow->priority);
+  ofe->reason = reason;
+  memset (ofe->pad, 0, sizeof ofe->pad);
+
+  ofe->duration     = htonl (time_now () - flow->created);
+  memset (ofe->pad2, 0, sizeof ofe->pad2);
+  ofe->packet_count = htonll (flow->packet_count);
+  ofe->byte_count   = htonll (flow->byte_count);
+  SendOpenflowBuffer (buffer);
+}
+
+void
+OpenFlowSwitchNetDevice::SendErrorMsg (uint16_t type, uint16_t code, const void *data, size_t len)
+{
+  ofpbuf *buffer;
+  ofp_error_msg *oem = (ofp_error_msg*)MakeOpenflowReply (sizeof(*oem) + len, OFPT_ERROR, &buffer);
+  oem->type = htons (type);
+  oem->code = htons (code);
+  memcpy (oem->data, data, len);
+  SendOpenflowBuffer (buffer);
+}
+
+void
+OpenFlowSwitchNetDevice::FlowTableLookup (sw_flow_key key, ofpbuf* buffer, uint32_t packet_uid, int port, bool send_to_controller)
+{
+  sw_flow *flow = chain_lookup (m_chain, &key);
+  if (flow != 0)
+    {
+      NS_LOG_INFO ("Flow matched");
+      flow_used (flow, buffer);
+      ofi::ExecuteActions (this, packet_uid, buffer, &key, flow->sf_acts->actions, flow->sf_acts->actions_len, false);
+    }
+  else
+    {
+      NS_LOG_INFO ("Flow not matched.");
+
+      if (send_to_controller)
+        {
+          OutputControl (packet_uid, port, m_missSendLen, OFPR_NO_MATCH);
+        }
+    }
+
+  // Clean up; at this point we're done with the packet.
+  m_packetData.erase (packet_uid);
+  discard_buffer (packet_uid);
+  ofpbuf_delete (buffer);
+}
+
+void
+OpenFlowSwitchNetDevice::RunThroughFlowTable (uint32_t packet_uid, int port, bool send_to_controller)
+{
+  ofi::SwitchPacketMetadata data = m_packetData.find (packet_uid)->second;
+  ofpbuf* buffer = data.buffer;
+
+  sw_flow_key key;
+  key.wildcards = 0; // Lookup cannot take wildcards.
+  // Extract the matching key's flow data from the packet's headers; if the policy is to drop fragments and the message is a fragment, drop it.
+  if (flow_extract (buffer, port != -1 ? port : OFPP_NONE, &key.flow) && (m_flags & OFPC_FRAG_MASK) == OFPC_FRAG_DROP)
+    {
+      ofpbuf_delete (buffer);
+      return;
+    }
+
+  // drop MPLS packets with TTL 1
+  if (buffer->l2_5)
+    {
+      mpls_header mpls_h;
+      mpls_h.value = ntohl (*((uint32_t*)buffer->l2_5));
+      if (mpls_h.ttl == 1)
+        {
+          // increment mpls drop counter
+          if (port != -1)
+            {
+              m_ports[port].mpls_ttl0_dropped++;
+            }
+          return;
+        }
+    }
+
+  // If we received the packet on a port, and opted not to receive any messages from it...
+  if (port != -1)
+    {
+      uint32_t config = m_ports[port].config;
+      if (config & (OFPPC_NO_RECV | OFPPC_NO_RECV_STP)
+          && config & (!eth_addr_equals (key.flow.dl_dst, stp_eth_addr) ? OFPPC_NO_RECV : OFPPC_NO_RECV_STP))
+        {
+          return;
+        }
+    }
+
+  NS_LOG_INFO ("Matching against the flow table.");
+  Simulator::Schedule (m_lookupDelay, &OpenFlowSwitchNetDevice::FlowTableLookup, this, key, buffer, packet_uid, port, send_to_controller);
+}
+
+int
+OpenFlowSwitchNetDevice::RunThroughVPortTable (uint32_t packet_uid, int port, uint32_t vport)
+{
+  ofpbuf* buffer = m_packetData.find (packet_uid)->second.buffer;
+
+  // extract the flow again since we need it
+  // and the layer pointers may changed
+  sw_flow_key key;
+  key.wildcards = 0;
+  if (flow_extract (buffer, port != -1 ? port : OFPP_NONE, &key.flow)
+      && (m_flags & OFPC_FRAG_MASK) == OFPC_FRAG_DROP)
+    {
+      return 0;
+    }
+
+  // run through the chain of port table entries
+  vport_table_entry *vpe = vport_table_lookup (&m_vportTable, vport);
+  m_vportTable.lookup_count++;
+  if (vpe)
+    {
+      m_vportTable.port_match_count++;
+    }
+  while (vpe != 0)
+    {
+      ofi::ExecuteVPortActions (this, packet_uid, m_packetData.find (packet_uid)->second.buffer, &key, vpe->port_acts->actions, vpe->port_acts->actions_len);
+      vport_used (vpe, buffer); // update counters for virtual port
+      if (vpe->parent_port_ptr == 0)
+        {
+          // if a port table's parent_port_ptr is 0 then
+          // the parent_port should be a physical port
+          if (vpe->parent_port <= OFPP_VP_START) // done traversing port chain, send packet to output port
+            {
+              OutputPort (packet_uid, port != -1 ? port : OFPP_NONE, vpe->parent_port, false);
+            }
+          else
+            {
+              NS_LOG_ERROR ("virtual port points to parent port\n");
+            }
+        }
+      else // increment the number of port entries accessed by chaining
+        {
+          m_vportTable.chain_match_count++;
+        }
+      // move to the parent port entry
+      vpe = vpe->parent_port_ptr;
+    }
+
+  return 0;
+}
+
+int
+OpenFlowSwitchNetDevice::ReceiveFeaturesRequest (const void *msg)
+{
+  SendFeaturesReply ();
+  return 0;
+}
+
+int
+OpenFlowSwitchNetDevice::ReceiveVPortTableFeaturesRequest (const void *msg)
+{
+  SendVPortTableFeatures ();
+  return 0;
+}
+
+int
+OpenFlowSwitchNetDevice::ReceiveGetConfigRequest (const void *msg)
+{
+  ofpbuf *buffer;
+  ofp_switch_config *osc = (ofp_switch_config*)MakeOpenflowReply (sizeof *osc, OFPT_GET_CONFIG_REPLY, &buffer);
+  osc->flags = htons (m_flags);
+  osc->miss_send_len = htons (m_missSendLen);
+
+  return SendOpenflowBuffer (buffer);
+}
+
+int
+OpenFlowSwitchNetDevice::ReceiveSetConfig (const void *msg)
+{
+  const ofp_switch_config *osc = (ofp_switch_config*)msg;
+  
+  int n_flags = ntohs (osc->flags) & (OFPC_SEND_FLOW_EXP | OFPC_FRAG_MASK);
+  if ((n_flags & OFPC_FRAG_MASK) != OFPC_FRAG_NORMAL && (n_flags & OFPC_FRAG_MASK) != OFPC_FRAG_DROP)
+    {
+      n_flags = (n_flags & ~OFPC_FRAG_MASK) | OFPC_FRAG_DROP;
+    }
+
+  m_flags = n_flags;
+  m_missSendLen = ntohs (osc->miss_send_len);
+  return 0;
+}
+
+int
+OpenFlowSwitchNetDevice::ReceivePacketOut (const void *msg)
+{
+  const ofp_packet_out *opo = (ofp_packet_out*)msg;
+  ofpbuf *buffer;
+  size_t actions_len = ntohs (opo->actions_len);
+
+  if (actions_len > (ntohs (opo->header.length) - sizeof *opo))
+    {
+      NS_LOG_DEBUG ("message too short for number of actions");
+      return -EINVAL;
+    }
+
+  if (ntohl (opo->buffer_id) == (uint32_t) -1)
+    {
+      // FIXME: can we avoid copying data here?
+      int data_len = ntohs (opo->header.length) - sizeof *opo - actions_len;
+      buffer = ofpbuf_new (data_len);
+      ofpbuf_put (buffer, (uint8_t *)opo->actions + actions_len, data_len);
+    }
+  else
+    {
+      buffer = retrieve_buffer (ntohl (opo->buffer_id));
+      if (buffer == 0)
+        {
+          return -ESRCH;
+        }
+    }
+
+  sw_flow_key key;
+  flow_extract (buffer, opo->in_port, &key.flow); // ntohs(opo->in_port)
+
+  uint16_t v_code = ofi::ValidateActions (&key, opo->actions, actions_len);
+  if (v_code != ACT_VALIDATION_OK)
+    {
+      SendErrorMsg (OFPET_BAD_ACTION, v_code, msg, ntohs (opo->header.length));
+      ofpbuf_delete (buffer);
+      return -EINVAL;
+    }
+
+  ofi::ExecuteActions (this, opo->buffer_id, buffer, &key, opo->actions, actions_len, true);
+  return 0;
+}
+
+int
+OpenFlowSwitchNetDevice::ReceivePortMod (const void *msg)
+{
+  ofp_port_mod* opm = (ofp_port_mod*)msg;
+  
+  int port = opm->port_no; // ntohs(opm->port_no);
+  if (port < DP_MAX_PORTS)
+    {
+      ofi::Port& p = m_ports[port];
+
+      // Make sure the port id hasn't changed since this was sent
+      Mac48Address hw_addr = Mac48Address ();
+      hw_addr.CopyFrom (opm->hw_addr);
+      if (p.netdev->GetAddress () != hw_addr)
+        {
+          return 0;
+        }
+
+      if (opm->mask)
+        {
+          uint32_t config_mask = ntohl (opm->mask);
+          p.config &= ~config_mask;
+          p.config |= ntohl (opm->config) & config_mask;
+        }
+
+      if (opm->mask & htonl (OFPPC_PORT_DOWN))
+        {
+          if ((opm->config & htonl (OFPPC_PORT_DOWN)) && (p.config & OFPPC_PORT_DOWN) == 0)
+            {
+              p.config |= OFPPC_PORT_DOWN;
+	      // TODO: Possibly disable the Port's Net Device via the appropriate interface.
+            }
+          else if ((opm->config & htonl (OFPPC_PORT_DOWN)) == 0 && (p.config & OFPPC_PORT_DOWN))
+            {
+              p.config &= ~OFPPC_PORT_DOWN;
+	      // TODO: Possibly enable the Port's Net Device via the appropriate interface.
+            }
+        }
+    }
+  
+  return 0;
+}
+
+// add or remove a virtual port table entry
+int
+OpenFlowSwitchNetDevice::ReceiveVPortMod (const void *msg)
+{
+  const ofp_vport_mod *ovpm = (ofp_vport_mod*)msg;
+
+  uint16_t command = ntohs (ovpm->command);
+  if (command == OFPVP_ADD)
+    {
+      return AddVPort (ovpm);
+    }
+  else if (command == OFPVP_DELETE)
+    {
+      if (remove_vport_table_entry (&m_vportTable, ntohl (ovpm->vport)))
+        {
+          SendErrorMsg (OFPET_BAD_ACTION, OFPET_VPORT_MOD_FAILED, ovpm, ntohs (ovpm->header.length));
+        }
+    }
+
+  return 0;
+}
+
+int
+OpenFlowSwitchNetDevice::AddFlow (const ofp_flow_mod *ofm)
+{
+  size_t actions_len = ntohs (ofm->header.length) - sizeof *ofm;
+
+  // Allocate memory.
+  sw_flow *flow = flow_alloc (actions_len);
+  if (flow == 0)
+    {
+      if (ntohl (ofm->buffer_id) != (uint32_t) -1)
+        {
+          discard_buffer (ntohl (ofm->buffer_id));
+        }
+      return -ENOMEM;
+    }
+
+  flow_extract_match (&flow->key, &ofm->match);
+
+  uint16_t v_code = ofi::ValidateActions (&flow->key, ofm->actions, actions_len);
+  if (v_code != ACT_VALIDATION_OK)
+    {
+      SendErrorMsg (OFPET_BAD_ACTION, v_code, ofm, ntohs (ofm->header.length));
+      flow_free (flow);
+      if (ntohl (ofm->buffer_id) != (uint32_t) -1)
+        {
+          discard_buffer (ntohl (ofm->buffer_id));
+        }
+      return -ENOMEM;
+    }
+
+  // Fill out flow.
+  flow->priority = flow->key.wildcards ? ntohs (ofm->priority) : -1;
+  flow->idle_timeout = ntohs (ofm->idle_timeout);
+  flow->hard_timeout = ntohs (ofm->hard_timeout);
+  flow->used = flow->created = time_now ();
+  flow->sf_acts->actions_len = actions_len;
+  flow->byte_count = 0;
+  flow->packet_count = 0;
+  memcpy (flow->sf_acts->actions, ofm->actions, actions_len);
+
+  // Act.
+  int error = chain_insert (m_chain, flow);
+  if (error)
+    {
+      if (error == -ENOBUFS)
+        {
+          SendErrorMsg (OFPET_FLOW_MOD_FAILED, OFPFMFC_ALL_TABLES_FULL, ofm, ntohs (ofm->header.length));
+        }
+      flow_free (flow);
+      if (ntohl (ofm->buffer_id) != (uint32_t) -1)
+        {
+          discard_buffer (ntohl (ofm->buffer_id));
+        }
+      return error;
+    }
+
+  NS_LOG_INFO ("Added new flow.");
+  if (ntohl (ofm->buffer_id) != std::numeric_limits<uint32_t>::max ())
+    {
+      ofpbuf *buffer = retrieve_buffer (ofm->buffer_id); // ntohl(ofm->buffer_id)
+      if (buffer)
+        {
+          sw_flow_key key;
+          flow_used (flow, buffer);
+          flow_extract (buffer, ofm->match.in_port, &key.flow); // ntohs(ofm->match.in_port);
+          ofi::ExecuteActions (this, ofm->buffer_id, buffer, &key, ofm->actions, actions_len, false);
+          ofpbuf_delete (buffer);
+        }
+      else
+        {
+          return -ESRCH;
+        }
+    }
+  return 0;
+}
+
+int
+OpenFlowSwitchNetDevice::ModFlow (const ofp_flow_mod *ofm)
+{
+  sw_flow_key key;
+  flow_extract_match (&key, &ofm->match);
+
+  size_t actions_len = ntohs (ofm->header.length) - sizeof *ofm;
+
+  uint16_t v_code = ofi::ValidateActions (&key, ofm->actions, actions_len);
+  if (v_code != ACT_VALIDATION_OK)
+    {
+      SendErrorMsg ((ofp_error_type)OFPET_BAD_ACTION, v_code, ofm, ntohs (ofm->header.length));
+      if (ntohl (ofm->buffer_id) != (uint32_t) -1)
+        {
+          discard_buffer (ntohl (ofm->buffer_id));
+        }
+      return -ENOMEM;
+    }
+
+  uint16_t priority = key.wildcards ? ntohs (ofm->priority) : -1;
+  int strict = (ofm->command == htons (OFPFC_MODIFY_STRICT)) ? 1 : 0;
+  chain_modify (m_chain, &key, priority, strict, ofm->actions, actions_len);
+
+  if (ntohl (ofm->buffer_id) != std::numeric_limits<uint32_t>::max ())
+    {
+      ofpbuf *buffer = retrieve_buffer (ofm->buffer_id); // ntohl (ofm->buffer_id)
+      if (buffer)
+        {
+          sw_flow_key skb_key;
+          flow_extract (buffer, ofm->match.in_port, &skb_key.flow); // ntohs(ofm->match.in_port);
+          ofi::ExecuteActions (this, ofm->buffer_id, buffer, &skb_key, ofm->actions, actions_len, false);
+          ofpbuf_delete (buffer);
+        }
+      else
+        {
+          return -ESRCH;
+        }
+    }
+  return 0;
+}
+
+int
+OpenFlowSwitchNetDevice::ReceiveFlow (const void *msg)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  const ofp_flow_mod *ofm = (ofp_flow_mod*)msg;
+  uint16_t command = ntohs (ofm->command);
+
+  if (command == OFPFC_ADD)
+    {
+      return AddFlow (ofm);
+    }
+  else if ((command == OFPFC_MODIFY) || (command == OFPFC_MODIFY_STRICT))
+    {
+      return ModFlow (ofm);
+    }
+  else if (command == OFPFC_DELETE)
+    {
+      sw_flow_key key;
+      flow_extract_match (&key, &ofm->match);
+      return chain_delete (m_chain, &key, ofm->out_port, 0, 0) ? 0 : -ESRCH;
+    }
+  else if (command == OFPFC_DELETE_STRICT)
+    {
+      sw_flow_key key;
+      uint16_t priority;
+      flow_extract_match (&key, &ofm->match);
+      priority = key.wildcards ? ntohs (ofm->priority) : -1;
+      return chain_delete (m_chain, &key, ofm->out_port, priority, 1) ? 0 : -ESRCH;
+    }
+  else
+    {
+      return -ENODEV;
+    }
+}
+
+int
+OpenFlowSwitchNetDevice::StatsDump (ofi::StatsDumpCallback *cb)
+{
+  ofp_stats_reply *osr;
+  ofpbuf *buffer;
+  int err;
+
+  if (cb->done)
+    {
+      return 0;
+    }
+
+  osr = (ofp_stats_reply*)MakeOpenflowReply (sizeof *osr, OFPT_STATS_REPLY, &buffer);
+  osr->type = htons (cb->s->type);
+  osr->flags = 0;
+
+  err = cb->s->DoDump (this, cb->state, buffer);
+  if (err >= 0)
+    {
+      if (err == 0)
+        {
+          cb->done = true;
+        }
+      else
+        {
+          // Buffer might have been reallocated, so find our data again.
+          osr = (ofp_stats_reply*)ofpbuf_at_assert (buffer, 0, sizeof *osr);
+          osr->flags = ntohs (OFPSF_REPLY_MORE);
+        }
+
+      int err2 = SendOpenflowBuffer (buffer);
+      if (err2)
+        {
+          err = err2;
+        }
+    }
+
+  return err;
+}
+
+void
+OpenFlowSwitchNetDevice::StatsDone (ofi::StatsDumpCallback *cb)
+{
+  if (cb)
+    {
+      cb->s->DoCleanup (cb->state);
+      free (cb->s);
+      free (cb);
+    }
+}
+
+int
+OpenFlowSwitchNetDevice::ReceiveStatsRequest (const void *oh)
+{
+  const ofp_stats_request *rq = (ofp_stats_request*)oh;
+  size_t rq_len = ntohs (rq->header.length);
+  int type = ntohs (rq->type);
+  int body_len = rq_len - offsetof (ofp_stats_request, body);
+  ofi::Stats* st = new ofi::Stats ((ofp_stats_types)type, (unsigned)body_len);
+  
+  if (st == 0)
+    {
+      return -EINVAL;
+    }
+
+  ofi::StatsDumpCallback cb;
+  cb.done = false;
+  cb.rq = (ofp_stats_request*)xmemdup (rq, rq_len);
+  cb.s = st;
+  cb.state = 0;
+  cb.swtch = this;
+
+  if (cb.s)
+    {
+      int err = cb.s->DoInit (rq->body, body_len, &cb.state);
+      if (err)
+        {
+          NS_LOG_WARN ("failed initialization of stats request type " << type << ": " << strerror (-err));
+          free (cb.rq);
+          return err;
+        }
+    }
+
+  if (m_controller != 0)
+    {
+      m_controller->StartDump (&cb);
+    }
+  else
+    {
+      NS_LOG_ERROR ("Switch needs to be registered to a controller in order to start the stats reply.");
+    }
+  
+  return 0;
+}
+
+int
+OpenFlowSwitchNetDevice::ReceiveEchoRequest (const void *oh)
+{
+  return SendOpenflowBuffer (make_echo_reply ((ofp_header*)oh));
+}
+
+int
+OpenFlowSwitchNetDevice::ReceiveEchoReply (const void *oh)
+{
+  return 0;
+}
+
+int
+OpenFlowSwitchNetDevice::ForwardControlInput (const void *msg, size_t length)
+{
+  // Check encapsulated length.
+  ofp_header *oh = (ofp_header*) msg;
+  if (ntohs (oh->length) > length)
+    {
+      return -EINVAL;
+    }
+  assert (oh->version == OFP_VERSION);
+
+  int error = 0;
+
+  // Figure out how to handle it.
+  switch (oh->type)
+    {
+    case OFPT_FEATURES_REQUEST:
+      error = length < sizeof(ofp_header) ? -EFAULT : ReceiveFeaturesRequest (msg);
+      break;
+    case OFPT_GET_CONFIG_REQUEST:
+      error = length < sizeof(ofp_header) ? -EFAULT : ReceiveGetConfigRequest (msg);
+      break;
+    case OFPT_SET_CONFIG:
+      error = length < sizeof(ofp_switch_config) ? -EFAULT : ReceiveSetConfig (msg);
+      break;
+    case OFPT_PACKET_OUT:
+      error = length < sizeof(ofp_packet_out) ? -EFAULT : ReceivePacketOut (msg);
+      break;
+    case OFPT_FLOW_MOD:
+      error = length < sizeof(ofp_flow_mod) ? -EFAULT : ReceiveFlow (msg);
+      break;
+    case OFPT_PORT_MOD:
+      error = length < sizeof(ofp_port_mod) ? -EFAULT : ReceivePortMod (msg);
+      break;
+    case OFPT_STATS_REQUEST:
+      error = length < sizeof(ofp_stats_request) ? -EFAULT : ReceiveStatsRequest (msg);
+      break;
+    case OFPT_ECHO_REQUEST:
+      error = length < sizeof(ofp_header) ? -EFAULT : ReceiveEchoRequest (msg);
+      break;
+    case OFPT_ECHO_REPLY:
+      error = length < sizeof(ofp_header) ? -EFAULT : ReceiveEchoReply (msg);
+      break;
+    case OFPT_VPORT_MOD:
+      error = length < sizeof(ofp_vport_mod) ? -EFAULT : ReceiveVPortMod (msg);
+      break;
+    case OFPT_VPORT_TABLE_FEATURES_REQUEST:
+      error = length < sizeof(ofp_header) ? -EFAULT : ReceiveVPortTableFeaturesRequest (msg);
+      break;
+    default:
+      SendErrorMsg ((ofp_error_type)OFPET_BAD_REQUEST, (ofp_bad_request_code)OFPBRC_BAD_TYPE, msg, length);
+      error = -EINVAL;
+    }
+
+  if (msg != 0)
+    {
+      free ((ofpbuf*)msg);
+    }
+  return error;
+}
+
+sw_chain*
+OpenFlowSwitchNetDevice::GetChain ()
+{
+  return m_chain;
+}
+
+uint32_t
+OpenFlowSwitchNetDevice::GetNSwitchPorts (void) const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return m_ports.size ();
+}
+
+ofi::Port
+OpenFlowSwitchNetDevice::GetSwitchPort (uint32_t n) const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return m_ports[n];
+}
+
+int
+OpenFlowSwitchNetDevice::GetSwitchPortIndex (ofi::Port p)
+{
+  for (size_t i = 0; i < m_ports.size (); i++)
+    {
+      if (m_ports[i].netdev == p.netdev)
+        {
+          return i;
+        }
+    }
+  return -1;
+}
+
+vport_table_t
+OpenFlowSwitchNetDevice::GetVPortTable ()
+{
+  return m_vportTable;
+}
+
+} // namespace ns3
+
+#endif // NS3_OPENFLOW
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/openflow/model/openflow-switch-net-device.h	Sat Mar 12 18:35:56 2011 +0000
@@ -0,0 +1,550 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Blake Hurd  <naimorai@gmail.com>
+ */
+#ifdef NS3_OPENFLOW
+
+#ifndef OPENFLOW_SWITCH_NET_DEVICE_H
+#define OPENFLOW_SWITCH_NET_DEVICE_H
+
+#include "ns3/simulator.h"
+#include "ns3/log.h"
+#include "ns3/mac48-address.h"
+
+#include "ns3/ethernet-header.h"
+#include "ns3/arp-header.h"
+#include "ns3/tcp-header.h"
+#include "ns3/udp-header.h"
+
+#include "ns3/ipv4-l3-protocol.h"
+#include "ns3/arp-l3-protocol.h"
+
+#include "ns3/bridge-channel.h"
+#include "ns3/node.h"
+#include "ns3/enum.h"
+#include "ns3/string.h"
+#include "ns3/integer.h"
+#include "ns3/uinteger.h"
+
+#include <map>
+#include <set>
+
+#include "openflow-interface.h"
+
+namespace ns3 {
+
+/**
+ * \ingroup devices
+ * \defgroup openflow OpenFlow
+ *
+ * \brief A net device that switches multiple LAN segments via an OpenFlow-compatible flow table
+ *
+ * The OpenFlowSwitchNetDevice object aggregates multiple netdevices as ports
+ * and acts like a switch. It implements OpenFlow-compatibility,
+ * according to the OpenFlow Switch Specification v0.8.9
+ * <www.openflowswitch.org/documents/openflow-spec-v0.8.9.pdf>.
+ * It implements a flow table that all received packets are run through.
+ * It implements a connection to a controller via a subclass of the Controller class,
+ * which can send messages to manipulate the flow table, thereby manipulating
+ * how the OpenFlow switch behaves.
+ *
+ * There are two controllers available in the original package. DropController
+ * builds a flow for each received packet to drop all packets it matches (this
+ * demonstrates the flow table's basic implementation), and the LearningController
+ * implements a "learning switch" algorithm (see 802.1D), where incoming unicast
+ * frames from one port may occasionally be forwarded throughout all other ports,
+ * but usually they are forwarded only to a single correct output port.
+ *
+ * \attention The Spanning Tree Protocol part of 802.1D is not
+ * implemented.  Therefore, you have to be careful not to create
+ * bridging loops, or else the network will collapse.
+ *
+ * \attention Each NetDevice used must only be assigned a Mac Address, adding it
+ * to an Ipv4 or Ipv6 layer will cause an error. It also must support a SendFrom
+ * call.
+ */
+
+/**
+ * \ingroup switch
+ * \brief A net device that switches multiple LAN segments via an OpenFlow-compatible flow table
+ */
+class OpenFlowSwitchNetDevice : public NetDevice
+{
+public:
+  static TypeId GetTypeId (void);
+
+  /**
+   * \name OpenFlowSwitchNetDevice Description Data
+   * \brief These four data describe the OpenFlowSwitchNetDevice as if it were a real OpenFlow switch.
+   *
+   * There is a type of stats request that OpenFlow switches are supposed
+   * to handle that returns the description of the OpenFlow switch. Currently
+   * manufactured by "The ns-3 team", software description is "Simulated
+   * OpenFlow Switch", and the other two are "N/A".
+   */
+  //\{
+  static const char * GetManufacturerDescription ();
+  static const char * GetHardwareDescription ();
+  static const char * GetSoftwareDescription ();
+  static const char * GetSerialNumber ();
+  //\}
+  
+  OpenFlowSwitchNetDevice ();
+  virtual ~OpenFlowSwitchNetDevice ();
+
+  /**
+   * \brief Set up the Switch's controller connection.
+   *
+   * \param c Pointer to a Controller.
+   */
+  void SetController (Ptr<ofi::Controller> c);
+
+  /**
+   * \brief Add a 'port' to a switch device
+   *
+   * This method adds a new switch port to a OpenFlowSwitchNetDevice, so that
+   * the new switch port NetDevice becomes part of the switch and L2
+   * frames start being forwarded to/from this NetDevice.
+   *
+   * \attention The netdevice that is being added as switch port must
+   * _not_ have an IP address.  In order to add IP connectivity to a
+   * bridging node you must enable IP on the OpenFlowSwitchNetDevice itself,
+   * never on its port netdevices.
+   *
+   * \param switchPort The port to add.
+   * \return 0 if everything's ok, otherwise an error number.
+   * \sa #EXFULL
+   */
+  int AddSwitchPort (Ptr<NetDevice> switchPort);
+
+  /**
+   * \brief Add a virtual port to a switch device
+   *
+   * The Ericsson OFSID has the concept of virtual ports and virtual
+   * port tables. These are implemented in the OpenFlowSwitchNetDevice, but
+   * don't have an understood use [perhaps it may have to do with
+   * MPLS integration].
+   *
+   * \sa #EINVAL
+   *
+   * \param ovpm The data for adding a virtual port.
+   * \return 0 if everything's ok, otherwise an error number.
+   */
+  int AddVPort (const ofp_vport_mod *ovpm);
+
+  /**
+   * \brief Stats callback is ready for a dump.
+   *
+   * Controllers have a callback system for status requests which calls this function.
+   *
+   * \param cb_ The callback data.
+   * \return 0 if everything's ok, otherwise an error number.
+   */
+  int StatsDump (ofi::StatsDumpCallback *cb_);
+
+  /**
+   * \brief Stats callback is done.
+   *
+   * Controllers have a callback system for status requests which calls this function.
+   *
+   * \param cb_ The callback data.
+   */
+  void StatsDone (ofi::StatsDumpCallback *cb_);
+
+  /**
+   * \brief Called from the OpenFlow Interface to output the Packet on either a Port or the Controller
+   *
+   * \param packet_uid Packet UID; used to fetch the packet and its metadata.
+   * \param in_port The index of the port the Packet was initially received on.
+   * \param max_len The maximum number of bytes the caller wants to be sent; a value of 0 indicates the entire packet should be sent. Used when outputting to controller.
+   * \param out_port The port we want to output on.
+   * \param ignore_no_fwd If true, Ports that are set to not forward are forced to forward.
+   */
+  void DoOutput (uint32_t packet_uid, int in_port, size_t max_len, int out_port, bool ignore_no_fwd);
+
+  /**
+   * \brief The registered controller calls this method when sending a message to the switch.
+   *
+   * \param msg The message received from the controller.
+   * \param length Length of the message.
+   * \return 0 if everything's ok, otherwise an error number.
+   */
+  int ForwardControlInput (const void *msg, size_t length);
+
+  /**
+   * \return The flow table chain.
+   */
+  sw_chain* GetChain ();
+
+  /**
+   * \return Number of switch ports attached to this switch.
+   */
+  uint32_t GetNSwitchPorts (void) const;
+
+  /**
+   * \param p The Port to get the index of.
+   * \return The index of the provided Port.
+   */
+  int GetSwitchPortIndex (ofi::Port p);
+
+  /**
+   * \param n index of the Port.
+   * \return The Port.
+   */
+  ofi::Port GetSwitchPort (uint32_t n) const;
+
+  /**
+   * \return The virtual port table.
+   */
+  vport_table_t GetVPortTable ();
+
+  ///\name From NetDevice
+  //\{
+  virtual void SetIfIndex (const uint32_t index);
+  virtual uint32_t GetIfIndex (void) const;
+  virtual Ptr<Channel> GetChannel (void) const;
+  virtual void SetAddress (Address address);
+  virtual Address GetAddress (void) const;
+  virtual bool SetMtu (const uint16_t mtu);
+  virtual uint16_t GetMtu (void) const;
+  virtual bool IsLinkUp (void) const;
+  virtual void AddLinkChangeCallback (Callback<void> callback);
+  virtual bool IsBroadcast (void) const;
+  virtual Address GetBroadcast (void) const;
+  virtual bool IsMulticast (void) const;
+  virtual Address GetMulticast (Ipv4Address multicastGroup) const;
+  virtual bool IsPointToPoint (void) const;
+  virtual bool IsBridge (void) const;
+  virtual bool Send (Ptr<Packet> packet, const Address& dest, uint16_t protocolNumber);
+  virtual bool SendFrom (Ptr<Packet> packet, const Address& source, const Address& dest, uint16_t protocolNumber);
+  virtual Ptr<Node> GetNode (void) const;
+  virtual void SetNode (Ptr<Node> node);
+  virtual bool NeedsArp (void) const;
+  virtual void SetReceiveCallback (NetDevice::ReceiveCallback cb);
+  virtual void SetPromiscReceiveCallback (NetDevice::PromiscReceiveCallback cb);
+  virtual bool SupportsSendFrom () const;
+  virtual Address GetMulticast (Ipv6Address addr) const;
+  //\}
+  
+protected:
+  virtual void DoDispose (void);
+
+  /**
+   * \internal
+   * 
+   * Called when a packet is received on one of the switch's ports.
+   *
+   * \param netdev The port the packet was received on.
+   * \param packet The Packet itself.
+   * \param protocol The protocol defining the Packet.
+   * \param src The source address of the Packet.
+   * \param dst The destination address of the Packet.
+   * \param PacketType Type of the packet.
+   */
+  void ReceiveFromDevice (Ptr<NetDevice> netdev, Ptr<const Packet> packet, uint16_t protocol, const Address& src, const Address& dst, PacketType packetType);
+
+  /**
+   * \internal
+   *
+   * Takes a packet and generates an OpenFlow buffer from it, loading the packet data as well as its headers.
+   *
+   * \param packet The packet.
+   * \param src The source address.
+   * \param dst The destination address.
+   * \param mtu The Maximum Transmission Unit.
+   * \param protocol The protocol defining the packet.
+   * \return The OpenFlow Buffer created from the packet.
+   */
+  ofpbuf * BufferFromPacket (Ptr<Packet> packet, Address src, Address dst, int mtu, uint16_t protocol);
+
+private:
+  /**
+   * \internal
+   *
+   * Add a flow.
+   *
+   * \sa #ENOMEM, #ENOBUFS, #ESRCH
+   *
+   * \param ofm The flow data to add.
+   * \return 0 if everything's ok, otherwise an error number.
+   */
+  int AddFlow (const ofp_flow_mod *ofm);
+
+  /**
+   * \internal
+   *
+   * Modify a flow.
+   *
+   * \param ofm The flow data to modify.
+   * \return 0 if everything's ok, otherwise an error number.
+   */
+  int ModFlow (const ofp_flow_mod *ofm);
+  
+  /**
+   * \internal
+   * 
+   * Send packets out all the ports except the originating one
+   *
+   * \param packet_uid Packet UID; used to fetch the packet and its metadata.
+   * \param in_port The index of the port the Packet was initially received on. This port doesn't forward when flooding.
+   * \param flood If true, don't send out on the ports with flooding disabled.
+   * \return 0 if everything's ok, otherwise an error number.
+   */
+  int OutputAll (uint32_t packet_uid, int in_port, bool flood);
+
+  /**
+   * \internal
+   * 
+   * Sends a copy of the Packet over the provided output port
+   *
+   * \param packet_uid Packet UID; used to fetch the packet and its metadata.
+   */
+  void OutputPacket (uint32_t packet_uid, int out_port);
+
+  /**
+   * \internal
+   *
+   * Seeks to send out a Packet over the provided output port. This is called generically
+   * when we may or may not know the specific port we're outputting on. There are many
+   * pre-set types of port options besides a Port that's hooked to our OpenFlowSwitchNetDevice.
+   * For example, it could be outputting as a flood, or seeking to output to the controller.
+   *
+   * \param packet_uid Packet UID; used to fetch the packet and its metadata.
+   * \param in_port The index of the port the Packet was initially received on.
+   * \param out_port The port we want to output on.
+   * \param ignore_no_fwd If true, Ports that are set to not forward are forced to forward.
+   */
+  void OutputPort (uint32_t packet_uid, int in_port, int out_port, bool ignore_no_fwd);
+
+  /**
+   * \internal 
+   * 
+   * Sends a copy of the Packet to the controller. If the packet can be saved
+   * in an OpenFlow buffer, then only the first 'max_len' bytes of the packet
+   * are sent; otherwise, all of the packet is sent.
+   *
+   * \param packet_uid Packet UID; used to fetch the packet and its metadata.
+   * \param in_port The index of the port the Packet was initially received on.
+   * \param max_len The maximum number of bytes that the caller wants to be sent; a value of 0 indicates the entire packet should be sent.
+   * \param reason Why the packet is being sent.
+   */
+  void OutputControl (uint32_t packet_uid, int in_port, size_t max_len, int reason);
+
+  /**
+   * \internal
+   * 
+   * If an error message happened during the controller's request, send it to the controller.
+   *
+   * \param type The type of error.
+   * \param code The error code.
+   * \param data The faulty data that lead to the error.
+   * \param len The length of the faulty data.
+   */
+  void SendErrorMsg (uint16_t type, uint16_t code, const void *data, size_t len);
+
+  /**
+   * \internal
+   * 
+   * Send a reply about this OpenFlow switch's features to the controller.
+   *
+   * List of capabilities and actions to support are found in the specification
+   * <www.openflowswitch.org/documents/openflow-spec-v0.8.9.pdf>.
+   *
+   * Supported capabilities and actions are defined in the openflow interface.
+   * To recap, flow status, flow table status, port status, virtual port table
+   * status can all be requested. It can also transmit over multiple physical
+   * interfaces.
+   *
+   * It supports every action: outputting over a port, and all of the flow table
+   * manipulation actions: setting the 802.1q VLAN ID, the 802.1q priority,
+   * stripping the 802.1 header, setting the Ethernet source address and destination,
+   * setting the IP source address and destination, setting the TCP/UDP source address
+   * and destination, and setting the MPLS label and EXP bits.
+   *
+   * \attention Capabilities STP (Spanning Tree Protocol) and IP packet
+   * reassembly are not currently supported.
+   *
+   */
+  void SendFeaturesReply ();
+
+  /**
+   * \internal
+   *
+   * Send a reply to the controller that a specific flow has expired.
+   *
+   * \param flow The flow that expired.
+   * \param reason The reason for sending this expiration notification.
+   */
+  void SendFlowExpired (sw_flow *flow, enum ofp_flow_expired_reason reason);
+
+  /**
+   * \internal
+   *
+   * Send a reply about a Port's status to the controller.
+   *
+   * \param p The port to get status from.
+   * \param status The reason for sending this reply.
+   */
+  void SendPortStatus (ofi::Port p, uint8_t status);
+
+  /**
+   * \internal
+   *
+   * Send a reply about this OpenFlow switch's virtual port table features to the controller.
+   */
+  void SendVPortTableFeatures ();
+
+  /**
+   * \internal
+   *
+   * Send a message to the controller. This method is the key
+   * to communicating with the controller, it does the actual
+   * sending. The other Send methods call this one when they
+   * are ready to send a message.
+   *
+   * \param buffer Buffer of the message to send out.
+   * \return 0 if successful, otherwise an error number.
+   */
+  int SendOpenflowBuffer (ofpbuf *buffer);
+
+  /**
+   * \internal
+   *
+   * Run the packet through the flow table. Looks up in the flow table for a match.
+   * If it doesn't match, it forwards the packet to the registered controller, if the flag is set.
+   *
+   * \param packet_uid Packet UID; used to fetch the packet and its metadata.
+   * \param port The port this packet was received over.
+   * \param send_to_controller If set, sends to the controller if the packet isn't matched.
+   */
+  void RunThroughFlowTable (uint32_t packet_uid, int port, bool send_to_controller = true);
+
+  /**
+   * \internal
+   *
+   * Run the packet through the vport table. As with AddVPort,
+   * this doesn't have an understood use yet.
+   *
+   * \param packet_uid Packet UID; used to fetch the packet and its metadata.
+   * \param port The port this packet was received over.
+   * \param vport The virtual port this packet identifies itself by.
+   * \return 0 if everything's ok, otherwise an error number.
+   */
+  int RunThroughVPortTable (uint32_t packet_uid, int port, uint32_t vport);
+  
+  /**
+   * \internal
+   *
+   * Called by RunThroughFlowTable on a scheduled delay
+   * to account for the flow table lookup overhead.
+   *
+   * \param key Matching key to look up in the flow table.
+   * \param buffer Buffer of the packet received.
+   * \param packet_uid Packet UID; used to fetch the packet and its metadata.
+   * \param port The port the packet was received over.
+   * \param send_to_controller 
+   */
+  void FlowTableLookup (sw_flow_key key, ofpbuf* buffer, uint32_t packet_uid, int port, bool send_to_controller);
+
+  /**
+   * \internal
+   *
+   * Update the port status field of the switch port.
+   * A non-zero return value indicates some field has changed.
+   *
+   * \param p A reference to a Port; used to change its config and flag fields.
+   * \return true if the status of the Port is changed, false if unchanged (was already the right status).
+   */
+  int UpdatePortStatus (ofi::Port& p);
+
+  /**
+   * \internal
+   *
+   * Fill out a description of the switch port.
+   *
+   * \param p The port to get the description from.
+   * \param desc A pointer to the description message; used to fill the description message with the data from the port.
+   */
+  void FillPortDesc (ofi::Port p, ofp_phy_port *desc);
+
+  /**
+   * \internal
+   *
+   * Generates an OpenFlow reply message based on the type.
+   *
+   * \param openflow_len Length of the reply to make.
+   * \param type Type of reply message to make.
+   * \param bufferp Message buffer; used to make the reply.
+   * \return The OpenFlow reply message.
+   */
+  void* MakeOpenflowReply (size_t openflow_len, uint8_t type, ofpbuf **bufferp);
+
+  /**
+   * \internal
+   * \name Receive Methods
+   *
+   * Actions to do when a specific OpenFlow message/packet is received
+   *
+   * \param msg The OpenFlow message received.
+   * \return 0 if everything's ok, otherwise an error number.
+   */
+  //\{
+  int ReceiveFeaturesRequest (const void *msg);
+  int ReceiveGetConfigRequest (const void *msg);
+  int ReceiveSetConfig (const void *msg);
+  int ReceivePacketOut (const void *msg);
+  int ReceiveFlow (const void *msg);
+  int ReceivePortMod (const void *msg);
+  int ReceiveStatsRequest (const void *oh);
+  int ReceiveEchoRequest (const void *oh);
+  int ReceiveEchoReply (const void *oh);
+  int ReceiveVPortMod (const void *msg);
+  int ReceiveVPortTableFeaturesRequest (const void *msg);
+  //\}
+  
+  /// Callbacks
+  NetDevice::ReceiveCallback m_rxCallback;
+  NetDevice::PromiscReceiveCallback m_promiscRxCallback;
+
+  Mac48Address m_address;               ///< Address of this device.
+  Ptr<Node> m_node;                     ///< Node this device is installed on.
+  Ptr<BridgeChannel> m_channel;         ///< Collection of port channels into the Switch Channel.
+  uint32_t m_ifIndex;                   ///< Interface Index
+  uint16_t m_mtu;                       ///< Maximum Transmission Unit
+
+  typedef std::map<uint32_t,ofi::SwitchPacketMetadata> PacketData_t;
+  PacketData_t m_packetData;            ///< Packet data
+
+  typedef std::vector<ofi::Port> Ports_t;
+  Ports_t m_ports;                      ///< Switch's ports
+
+  Ptr<ofi::Controller> m_controller;    ///< Connection to controller.
+
+  uint64_t m_id;                        ///< Unique identifier for this switch, needed for OpenFlow
+  Time m_lookupDelay;                   ///< Flow Table Lookup Delay [overhead].
+
+  Time m_lastExecute;			///< Last time the periodic execution occurred.
+  uint16_t m_flags;                     ///< Flags; configurable by the controller.
+  uint16_t m_missSendLen;               ///< Flow Table Miss Send Length; configurable by the controller.
+
+  sw_chain *m_chain;             ///< Flow Table; forwarding rules.
+  vport_table_t m_vportTable;    ///< Virtual Port Table
+};
+
+} // namespace ns3
+
+#endif /* OPENFLOW_SWITCH_NET_DEVICE_H */
+#endif // NS3_OPENFLOW
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/openflow/test/examples-to-run.py	Sat Mar 12 18:35:56 2011 +0000
@@ -0,0 +1,20 @@
+#! /usr/bin/env python
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+# A list of C++ examples to run in order to ensure that they remain
+# buildable and runnable over time.  Each tuple in the list contains
+#
+#     (example_name, do_run, do_valgrind_run).
+#
+# See test.py for more information.
+cpp_examples = [
+    ("openflow-switch", "ENABLE_OPENFLOW == True", "True"),
+]
+
+# A list of Python examples to run in order to ensure that they remain
+# runnable over time.  Each tuple in the list contains
+#
+#     (example_name, do_run).
+#
+# See test.py for more information.
+python_examples = []
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/openflow/test/openflow-switch-test-suite.cc	Sat Mar 12 18:35:56 2011 +0000
@@ -0,0 +1,193 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 Blake Hurd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307  USA
+ *
+ * Author: Blake Hurd  <naimorai@gmail.com>
+ */
+
+
+#ifdef NS3_OPENFLOW
+
+// An essential include is test.h
+#include "ns3/test.h"
+
+#include "ns3/openflow-switch-net-device.h"
+#include "ns3/openflow-interface.h"
+
+// Do not put your test classes in namespace ns3.  You may find it useful
+// to use the using directive to access the ns3 namespace directly
+using namespace ns3;
+
+// This is an example TestCase.
+class SwitchFlowTableTestCase : public TestCase
+{
+public:
+  SwitchFlowTableTestCase () : TestCase ("Switch test case")
+  {
+    m_chain = chain_create ();
+  }
+
+  virtual ~SwitchFlowTableTestCase ()
+  {
+    chain_destroy (m_chain);
+  }
+
+private:
+  virtual void DoRun (void);
+
+  sw_chain* m_chain;
+};
+
+void
+SwitchFlowTableTestCase::DoRun (void)
+{
+  // Flow Table implementation is used by the OpenFlowSwitchNetDevice under the chain_ methods
+  // we should test its implementation to verify the flow table works.
+
+  // Initialization
+  time_init (); // OFSI requires this, otherwise we crash before we can do anything.
+
+  size_t actions_len = 0; // Flow is created with 0 actions.
+  int output_port = 0; // Flow will be modified later with an action to output on port 0.
+
+  Mac48Address dl_src ("00:00:00:00:00:00"), dl_dst ("00:00:00:00:00:01");
+  Ipv4Address nw_src ("192.168.1.1"), nw_dst ("192.168.1.2");
+  int tp_src = 5000, tp_dst = 80;
+
+  // Create an sw_flow_key; in actual usage this is generated from the received packet's headers.
+  sw_flow_key key;
+  key.wildcards = 0;
+
+  key.flow.in_port = htons (0);
+
+  key.flow.dl_vlan = htons (OFP_VLAN_NONE);
+  key.flow.dl_type = htons (ETH_TYPE_IP);
+  key.flow.nw_proto = htons (IP_TYPE_UDP);
+
+  key.flow.reserved = 0;
+  key.flow.mpls_label1 = htonl (MPLS_INVALID_LABEL);
+  key.flow.mpls_label2 = htonl (MPLS_INVALID_LABEL);
+
+  // Set Mac Addresses
+  dl_src.CopyTo (key.flow.dl_src);
+  dl_dst.CopyTo (key.flow.dl_dst);
+
+  // Set IP Addresses
+  key.flow.nw_src = htonl (nw_src.Get ());
+  key.flow.nw_dst = htonl (nw_dst.Get ());
+
+  // Set TCP/UDP Ports
+  key.flow.tp_src = htonl (tp_src);
+  key.flow.tp_dst = htonl (tp_dst);
+
+  // Create flow
+  ofp_flow_mod ofm;
+  ofm.header.version = OFP_VERSION;
+  ofm.header.type = OFPT_FLOW_MOD;
+  ofm.header.length = htons (sizeof (ofp_flow_mod) + actions_len);
+  ofm.command = htons (OFPFC_ADD);
+  ofm.idle_timeout = htons (OFP_FLOW_PERMANENT);
+  ofm.hard_timeout = htons (OFP_FLOW_PERMANENT);
+  ofm.buffer_id = htonl (-1);
+  ofm.priority = OFP_DEFAULT_PRIORITY;
+
+  ofm.match.wildcards = key.wildcards;                                 // Wildcard fields
+  ofm.match.in_port = key.flow.in_port;                                // Input switch port
+  memcpy (ofm.match.dl_src, key.flow.dl_src, sizeof ofm.match.dl_src); // Ethernet source address.
+  memcpy (ofm.match.dl_dst, key.flow.dl_dst, sizeof ofm.match.dl_dst); // Ethernet destination address.
+  ofm.match.dl_vlan = key.flow.dl_vlan;                                // Input VLAN OFP_VLAN_NONE;
+  ofm.match.dl_type = key.flow.dl_type;                                // Ethernet frame type ETH_TYPE_IP;
+  ofm.match.nw_proto = key.flow.nw_proto;                              // IP Protocol
+  ofm.match.nw_src = key.flow.nw_src;                                  // IP source address
+  ofm.match.nw_dst = key.flow.nw_dst;                                  // IP destination address
+  ofm.match.tp_src = key.flow.tp_src;                                  // TCP/UDP source port
+  ofm.match.tp_dst = key.flow.tp_dst;                                  // TCP/UDP destination port
+  ofm.match.mpls_label1 = key.flow.mpls_label1;                        // Top of label stack
+  ofm.match.mpls_label2 = key.flow.mpls_label1;                        // Second label (if available)
+
+  // Build a sw_flow from the ofp_flow_mod
+  sw_flow *flow = flow_alloc (actions_len);
+  NS_TEST_ASSERT_MSG_NE (flow, 0, "Cannot allocate memory for the flow.");
+
+  flow_extract_match (&flow->key, &ofm.match);
+
+  // Fill out flow.
+  flow->priority = flow->key.wildcards ? ntohs (ofm.priority) : -1;
+  flow->idle_timeout = ntohs (ofm.idle_timeout);
+  flow->hard_timeout = ntohs (ofm.hard_timeout);
+  flow->used = flow->created = time_now ();
+  flow->sf_acts->actions_len = actions_len;
+  flow->byte_count = 0;
+  flow->packet_count = 0;
+  memcpy (flow->sf_acts->actions, ofm.actions, actions_len);
+
+  // Insert the flow into the Flow Table
+  NS_TEST_ASSERT_MSG_EQ (chain_insert (m_chain, flow), 0, "Flow table failed to insert Flow.");
+
+  // Use key to match the flow to verify we created it correctly.
+  NS_TEST_ASSERT_MSG_NE (chain_lookup (m_chain, &key), 0, "Key provided doesn't match to the flow that was created from it.");
+
+  // Modify key to make sure the flow doesn't match it.
+  dl_dst.CopyTo (key.flow.dl_src);
+  dl_src.CopyTo (key.flow.dl_dst);
+  key.flow.nw_src = htonl (nw_dst.Get ());
+  key.flow.nw_dst = htonl (nw_src.Get ());
+  key.flow.tp_src = htonl (tp_dst);
+  key.flow.tp_dst = htonl (tp_src);
+
+  NS_TEST_ASSERT_MSG_EQ (chain_lookup (m_chain, &key), 0, "Key provided shouldn't match the flow but it does.");
+
+  // Modify key back to matching the flow so we can test flow modification.
+  dl_dst.CopyTo (key.flow.dl_dst);
+  dl_src.CopyTo (key.flow.dl_src);
+  key.flow.nw_src = htonl (nw_src.Get ());
+  key.flow.nw_dst = htonl (nw_dst.Get ());
+  key.flow.tp_src = htonl (tp_src);
+  key.flow.tp_dst = htonl (tp_dst);
+
+  // Testing Flow Modification; chain_modify should return 1, for 1 flow modified.
+  // Create output-to-port action
+  ofp_action_output acts[1];
+  acts[0].type = htons (OFPAT_OUTPUT);
+  acts[0].len = htons (sizeof (ofp_action_output));
+  acts[0].port = output_port;
+
+  uint16_t priority = key.wildcards ? ntohs (ofm.priority) : -1;
+  NS_TEST_ASSERT_MSG_EQ (chain_modify (m_chain, &key, priority, false, (const ofp_action_header*)acts, sizeof (acts)), 1, "Flow table failed to modify Flow.");
+
+  // Testing Flow Deletion; chain_delete should return 1, for 1 flow deleted.
+  // Note: By providing chain_delete with output_port, the flow must have an action that outputs on that port in order to delete the flow.
+  // This is how we verify that our action was truly added via the flow modification.
+  NS_TEST_ASSERT_MSG_EQ (chain_delete (m_chain, &key, output_port, 0, 0), 1, "Flow table failed to delete Flow.");
+  NS_TEST_ASSERT_MSG_EQ (chain_lookup (m_chain, &key), 0, "Key provided shouldn't match the flow but it does.");
+}
+
+class SwitchTestSuite : public TestSuite
+{
+public:
+  SwitchTestSuite ();
+};
+
+SwitchTestSuite::SwitchTestSuite () : TestSuite ("openflow", UNIT)
+{
+  AddTestCase (new SwitchFlowTableTestCase);
+}
+
+// Do not forget to allocate an instance of this TestSuite
+SwitchTestSuite switchTestSuite;
+
+#endif // NS3_OPENFLOW
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/openflow/waf	Sat Mar 12 18:35:56 2011 +0000
@@ -0,0 +1,1 @@
+exec "`dirname "$0"`"/../../../waf "$@"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/openflow/wscript	Sat Mar 12 18:35:56 2011 +0000
@@ -0,0 +1,131 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+import os
+import Options
+
+def set_options(opt):
+    opt.add_option('--with-openflow',
+		   help=('Path to OFSID source for NS-3 OpenFlow Integration support'),
+		   default='', dest='with_openflow') 
+
+def configure(conf):
+    conf.check_tool('boost')
+    conf.env['BOOST'] = conf.check_boost(lib = 'signals filesystem',
+                                         kind = 'STATIC_BOTH',
+                                         score_version = (-1000, 1000),
+                                         tag_minscore = 1000,)
+
+    if not conf.env['BOOST']:
+	conf.report_optional_feature("openflow", "NS-3 OpenFlow Integration", False,
+				     "Required boost libraries not found")
+	return 
+
+    if Options.options.with_openflow:
+	if os.path.isdir(Options.options.with_openflow):
+	    conf.check_message("OpenFlow location", '', True, ("%s (given)" % Options.options.with_openflow))
+	    conf.env['WITH_OPENFLOW'] = os.path.abspath(Options.options.with_openflow)
+    else:
+        openflow_dir = os.path.join('..','openflow')
+        if os.path.isdir(openflow_dir):
+            conf.check_message("OpenFlow location", '', True, ("%s (guessed)" % openflow_dir))
+	    conf.env['WITH_OPENFLOW'] = os.path.abspath(openflow_dir)
+	del openflow_dir
+    if not conf.env['WITH_OPENFLOW']:
+	conf.check_message("OpenFlow location", '', False)
+	conf.report_optional_feature("openflow", "NS-3 OpenFlow Integration", False,
+				     "OpenFlow not enabled (see option --with-openflow)")
+	return 
+
+    test_code = '''
+#include "openflow.h"
+#include "nicira-ext.h"
+#include "ericsson-ext.h"
+
+extern "C"
+{
+#define private _private
+#define delete _delete
+#define list List
+
+#include "csum.h"
+#include "poll-loop.h"
+#include "rconn.h"
+#include "stp.h"
+#include "vconn.h"
+#include "xtoxll.h"
+
+#include "chain.h"
+#include "table.h"
+#include "datapath.h" // The functions below are defined in datapath.c
+uint32_t save_buffer (ofpbuf *);
+ofpbuf * retrieve_buffer (uint32_t id);
+void discard_buffer (uint32_t id);
+#include "dp_act.h" // The functions below are defined in dp_act.c
+void set_vlan_vid (ofpbuf *buffer, sw_flow_key *key, const ofp_action_header *ah);
+void set_vlan_pcp (ofpbuf *buffer, sw_flow_key *key, const ofp_action_header *ah);
+void strip_vlan (ofpbuf *buffer, sw_flow_key *key, const ofp_action_header *ah);
+void set_dl_addr (ofpbuf *buffer, sw_flow_key *key, const ofp_action_header *ah);
+void set_nw_addr (ofpbuf *buffer, sw_flow_key *key, const ofp_action_header *ah);
+void set_tp_port (ofpbuf *buffer, sw_flow_key *key, const ofp_action_header *ah);
+void set_mpls_label (ofpbuf *buffer, sw_flow_key *key, const ofp_action_header *ah);
+void set_mpls_exp (ofpbuf *buffer, sw_flow_key *key, const ofp_action_header *ah);
+#include "pt_act.h" // The function below is defined in pt_act.c
+void update_checksums (ofpbuf *buffer, const sw_flow_key *key, uint32_t old_word, uint32_t new_word);
+
+#undef list
+#undef private
+#undef delete
+}
+
+int main()
+{
+  return 0;
+}
+'''
+
+    conf.env['DL'] = conf.check(mandatory=True, lib='dl', define_name='DL', uselib='DL')
+    conf.env['XML2'] = conf.check(mandatory=True, lib='xml2', define_name='XML2', uselib='XML2')
+    
+    conf.env.append_value('NS3_MODULE_PATH',os.path.abspath(os.path.join(conf.env['WITH_OPENFLOW'],'build','default')))
+    
+    conf.env['CPPPATH_OPENFLOW'] = [
+				    os.path.abspath(os.path.join(conf.env['WITH_OPENFLOW'],'include')),
+				    os.path.abspath(os.path.join(conf.env['WITH_OPENFLOW'],'include','openflow')),
+				    os.path.abspath(os.path.join(conf.env['WITH_OPENFLOW'],'lib')),
+				    os.path.abspath(os.path.join(conf.env['WITH_OPENFLOW'],'switch'))
+				   ]
+    conf.env['LIBPATH_OPENFLOW'] = [os.path.abspath(os.path.join(conf.env['WITH_OPENFLOW'],'build','default'))]
+    
+    conf.env['OPENFLOW'] = conf.check(fragment=test_code, lib='openflow', uselib='OPENFLOW DL XML2')
+    conf.report_optional_feature("openflow", "NS-3 OpenFlow Integration",
+    conf.env['OPENFLOW'], "openflow library not found")
+    if conf.env['OPENFLOW']:
+        conf.env['ENABLE_OPENFLOW'] = True
+	conf.env.append_value('CXXDEFINES', 'NS3_OPENFLOW')
+	conf.env.append_value('CPPPATH', conf.env['CPPPATH_OPENFLOW']) 
+
+def build(bld):
+    # Build the Switch module
+    obj = bld.create_ns3_module('openflow', ['internet'])
+    obj.source = [
+        ]
+
+    if bld.env['OPENFLOW'] and bld.env['DL'] and bld.env['XML2']:
+	obj.uselib = 'OPENFLOW DL XML2' 
+
+    headers = bld.new_task_gen('ns3header')
+    headers.module = 'openflow'
+    headers.source = [
+        ]
+
+    if bld.env['ENABLE_OPENFLOW']:
+	obj.source.append('model/openflow-interface.cc')
+        obj.source.append('model/openflow-switch-net-device.cc')
+	obj.source.append('helper/openflow-switch-helper.cc')
+	obj.source.append('test/openflow-switch-test-suite.cc')
+	headers.source.append('model/openflow-interface.h')
+        headers.source.append('model/openflow-switch-net-device.h')
+	headers.source.append('helper/openflow-switch-helper.h')
+
+    if bld.env['ENABLE_EXAMPLES'] and bld.env['ENABLE_OPENFLOW']:
+        bld.add_subdirs('examples')
--- a/src/wimax/examples/wimax-simple.cc	Sat Mar 12 18:34:30 2011 +0000
+++ b/src/wimax/examples/wimax-simple.cc	Sat Mar 12 18:35:56 2011 +0000
@@ -54,7 +54,7 @@
 #include "ns3/service-flow.h"
 #include <iostream>
 
-NS_LOG_COMPONENT_DEFINE ("wimaxIpV4Simulation");
+NS_LOG_COMPONENT_DEFINE ("WimaxSimpleExample");
 
 using namespace ns3;
 
--- a/src/wscript	Sat Mar 12 18:34:30 2011 +0000
+++ b/src/wscript	Sat Mar 12 18:35:56 2011 +0000
@@ -35,6 +35,7 @@
     'aodv',
     'dsdv',
     'click',
+    'openflow',
     'mobility',
     'wifi',
     'netanim',
@@ -59,6 +60,7 @@
 def set_options(opt):
     opt.sub_options('core')
     opt.sub_options('click')
+    opt.sub_options('openflow')
 
     opt.add_option('--enable-rpath',
                    help=("Link programs with rpath"
@@ -80,6 +82,7 @@
     conf.sub_config('netanim')
     conf.sub_config('test')
     conf.sub_config('click')
+    conf.sub_config('openflow')
 
     blddir = os.path.abspath(os.path.join(conf.blddir, conf.env.variant()))
     conf.env.append_value('NS3_MODULE_PATH', blddir)
--- a/test.py	Sat Mar 12 18:34:30 2011 +0000
+++ b/test.py	Sat Mar 12 18:35:56 2011 +0000
@@ -51,12 +51,14 @@
     "EXAMPLE_DIRECTORIES",
     "ENABLE_PYTHON_BINDINGS",
     "ENABLE_CLICK",
+    "ENABLE_OPENFLOW",
 ]
 
 NSC_ENABLED = False
 ENABLE_REAL_TIME = False
 ENABLE_EXAMPLES = True
 ENABLE_CLICK = False
+ENABLE_OPENFLOW = False
 EXAMPLE_DIRECTORIES = []
 
 #