merge
This commit is contained in:
139
bindings/python/apidefs/gcc-ILP32/ns3_module_openflow.py
Normal file
139
bindings/python/apidefs/gcc-ILP32/ns3_module_openflow.py
Normal file
@@ -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
|
||||
|
||||
@@ -86,15 +86,15 @@ def register_types(module):
|
||||
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
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ import ns3_module_applications
|
||||
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 @@ def register_types(module):
|
||||
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 @@ def register_methods(root_module):
|
||||
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 @@ def register_functions(root_module):
|
||||
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)
|
||||
|
||||
|
||||
139
bindings/python/apidefs/gcc-LP64/ns3_module_openflow.py
Normal file
139
bindings/python/apidefs/gcc-LP64/ns3_module_openflow.py
Normal file
@@ -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
|
||||
|
||||
@@ -86,15 +86,15 @@ def register_types(module):
|
||||
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
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ import ns3_module_applications
|
||||
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 @@ def register_types(module):
|
||||
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 @@ def register_methods(root_module):
|
||||
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 @@ def register_functions(root_module):
|
||||
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)
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("RadvdExample");
|
||||
NS_LOG_COMPONENT_DEFINE ("RadvdTwoPrefixExample");
|
||||
|
||||
/**
|
||||
* \class StackHelper
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("FirstScriptExample");
|
||||
NS_LOG_COMPONENT_DEFINE ("NixSimpleExample");
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
|
||||
158
src/openflow/doc/openflow-switch.h
Normal file
158
src/openflow/doc/openflow-switch.h
Normal file
@@ -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>
|
||||
*/
|
||||
215
src/openflow/examples/openflow-switch.cc
Normal file
215
src/openflow/examples/openflow-switch.cc
Normal file
@@ -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
|
||||
}
|
||||
6
src/openflow/examples/wscript
Normal file
6
src/openflow/examples/wscript
Normal file
@@ -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'
|
||||
97
src/openflow/helper/openflow-switch-helper.cc
Normal file
97
src/openflow/helper/openflow-switch-helper.cc
Normal file
@@ -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
|
||||
105
src/openflow/helper/openflow-switch-helper.h
Normal file
105
src/openflow/helper/openflow-switch-helper.h
Normal file
@@ -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 */
|
||||
1135
src/openflow/model/openflow-interface.cc
Normal file
1135
src/openflow/model/openflow-interface.cc
Normal file
File diff suppressed because it is too large
Load Diff
567
src/openflow/model/openflow-interface.h
Normal file
567
src/openflow/model/openflow-interface.h
Normal file
@@ -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 */
|
||||
1584
src/openflow/model/openflow-switch-net-device.cc
Normal file
1584
src/openflow/model/openflow-switch-net-device.cc
Normal file
File diff suppressed because it is too large
Load Diff
550
src/openflow/model/openflow-switch-net-device.h
Normal file
550
src/openflow/model/openflow-switch-net-device.h
Normal file
@@ -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
|
||||
20
src/openflow/test/examples-to-run.py
Normal file
20
src/openflow/test/examples-to-run.py
Normal file
@@ -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 = []
|
||||
193
src/openflow/test/openflow-switch-test-suite.cc
Normal file
193
src/openflow/test/openflow-switch-test-suite.cc
Normal file
@@ -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
|
||||
1
src/openflow/waf
vendored
Normal file
1
src/openflow/waf
vendored
Normal file
@@ -0,0 +1 @@
|
||||
exec "`dirname "$0"`"/../../../waf "$@"
|
||||
131
src/openflow/wscript
Normal file
131
src/openflow/wscript
Normal file
@@ -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')
|
||||
@@ -54,7 +54,7 @@
|
||||
#include "ns3/service-flow.h"
|
||||
#include <iostream>
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("wimaxIpV4Simulation");
|
||||
NS_LOG_COMPONENT_DEFINE ("WimaxSimpleExample");
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ all_modules = (
|
||||
'aodv',
|
||||
'dsdv',
|
||||
'click',
|
||||
'openflow',
|
||||
'mobility',
|
||||
'wifi',
|
||||
'netanim',
|
||||
@@ -59,6 +60,7 @@ all_modules = (
|
||||
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 @@ def configure(conf):
|
||||
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)
|
||||
|
||||
Reference in New Issue
Block a user