diff --git a/CHANGES.html b/CHANGES.html index 346d812fc..7f24d6fa7 100644 --- a/CHANGES.html +++ b/CHANGES.html @@ -49,6 +49,7 @@ us a note on ns-developers mailing list.

Changes to build system:

New API:

+ +

Changes to existing API:

+ +

Changed behavior:

+ +

Changes from ns-3.6 to ns-3.7

diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 37ff6d8ad..cc0072e27 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -36,7 +36,8 @@ New user-visible features ------------------------- a) WiMAX net device: Allow to simulated IEEE 802.16 point to multi-point based networks - b) + b) Distributed simulation for point-to-point networks using the Message + Passing Interface (MPI) standard. c) diff --git a/bindings/python/apidefs/gcc-ILP32/ns3_module_common.py b/bindings/python/apidefs/gcc-ILP32/ns3_module_common.py index 6ec9894f1..473641f98 100644 --- a/bindings/python/apidefs/gcc-ILP32/ns3_module_common.py +++ b/bindings/python/apidefs/gcc-ILP32/ns3_module_common.py @@ -265,6 +265,10 @@ def register_Ns3Buffer_methods(root_module, cls): 'ns3::Buffer', [], is_const=True) + ## buffer.h: uint32_t ns3::Buffer::Deserialize(uint8_t * buffer, uint32_t size) [member function] + cls.add_method('Deserialize', + 'uint32_t', + [param('uint8_t *', 'buffer'), param('uint32_t', 'size')]) ## buffer.h: ns3::Buffer::Iterator ns3::Buffer::End() const [member function] cls.add_method('End', 'ns3::Buffer::Iterator', @@ -280,6 +284,11 @@ def register_Ns3Buffer_methods(root_module, cls): 'int32_t', [], is_const=True) + ## buffer.h: uint32_t ns3::Buffer::GetSerializedSize() const [member function] + cls.add_method('GetSerializedSize', + 'uint32_t', + [], + is_const=True) ## buffer.h: uint32_t ns3::Buffer::GetSize() const [member function] cls.add_method('GetSize', 'uint32_t', @@ -298,6 +307,11 @@ def register_Ns3Buffer_methods(root_module, cls): cls.add_method('RemoveAtStart', 'void', [param('uint32_t', 'start')]) + ## buffer.h: uint32_t ns3::Buffer::Serialize(uint8_t * buffer, uint32_t maxSize) const [member function] + cls.add_method('Serialize', + 'uint32_t', + [param('uint8_t *', 'buffer'), param('uint32_t', 'maxSize')], + is_const=True) return def register_Ns3BufferIterator_methods(root_module, cls): @@ -583,8 +597,8 @@ def register_Ns3DataRate_methods(root_module, cls): return def register_Ns3PacketMetadata_methods(root_module, cls): - ## packet-metadata.h: ns3::PacketMetadata::PacketMetadata(uint32_t uid, uint32_t size) [constructor] - cls.add_constructor([param('uint32_t', 'uid'), param('uint32_t', 'size')]) + ## packet-metadata.h: ns3::PacketMetadata::PacketMetadata(uint64_t uid, uint32_t size) [constructor] + cls.add_constructor([param('uint64_t', 'uid'), param('uint32_t', 'size')]) ## packet-metadata.h: ns3::PacketMetadata::PacketMetadata(ns3::PacketMetadata const & o) [copy constructor] cls.add_constructor([param('ns3::PacketMetadata const &', 'o')]) ## packet-metadata.h: void ns3::PacketMetadata::AddAtEnd(ns3::PacketMetadata const & o) [member function] @@ -613,10 +627,10 @@ def register_Ns3PacketMetadata_methods(root_module, cls): 'ns3::PacketMetadata', [param('uint32_t', 'start'), param('uint32_t', 'end')], is_const=True) - ## packet-metadata.h: uint32_t ns3::PacketMetadata::Deserialize(ns3::Buffer::Iterator i) [member function] + ## packet-metadata.h: uint32_t ns3::PacketMetadata::Deserialize(uint8_t * buffer, uint32_t size) [member function] cls.add_method('Deserialize', 'uint32_t', - [param('ns3::Buffer::Iterator', 'i')]) + [param('uint8_t *', 'buffer'), param('uint32_t', 'size')]) ## packet-metadata.h: static void ns3::PacketMetadata::Enable() [member function] cls.add_method('Enable', 'void', @@ -632,9 +646,9 @@ def register_Ns3PacketMetadata_methods(root_module, cls): 'uint32_t', [], is_const=True) - ## packet-metadata.h: uint32_t ns3::PacketMetadata::GetUid() const [member function] + ## packet-metadata.h: uint64_t ns3::PacketMetadata::GetUid() const [member function] cls.add_method('GetUid', - 'uint32_t', + 'uint64_t', [], is_const=True) ## packet-metadata.h: void ns3::PacketMetadata::RemoveAtEnd(uint32_t end) [member function] @@ -653,10 +667,10 @@ def register_Ns3PacketMetadata_methods(root_module, cls): cls.add_method('RemoveTrailer', 'void', [param('ns3::Trailer const &', 'trailer'), param('uint32_t', 'size')]) - ## packet-metadata.h: void ns3::PacketMetadata::Serialize(ns3::Buffer::Iterator i, uint32_t size) const [member function] + ## packet-metadata.h: uint32_t ns3::PacketMetadata::Serialize(uint8_t * buffer, uint32_t maxSize) const [member function] cls.add_method('Serialize', - 'void', - [param('ns3::Buffer::Iterator', 'i'), param('uint32_t', 'size')], + 'uint32_t', + [param('uint8_t *', 'buffer'), param('uint32_t', 'maxSize')], is_const=True) return @@ -1523,10 +1537,10 @@ def register_Ns3NixVector_methods(root_module, cls): 'ns3::Ptr< ns3::NixVector >', [], is_const=True) - ## nix-vector.h: uint32_t ns3::NixVector::Deserialize(ns3::Buffer::Iterator i) [member function] + ## nix-vector.h: uint32_t ns3::NixVector::Deserialize(uint32_t * buffer, uint32_t size) [member function] cls.add_method('Deserialize', 'uint32_t', - [param('ns3::Buffer::Iterator', 'i')]) + [param('uint32_t *', 'buffer'), param('uint32_t', 'size')]) ## nix-vector.h: void ns3::NixVector::DumpNixVector(std::ostream & os) const [member function] cls.add_method('DumpNixVector', 'void', @@ -1550,10 +1564,10 @@ def register_Ns3NixVector_methods(root_module, cls): 'ns3::TypeId', [], is_static=True) - ## nix-vector.h: void ns3::NixVector::Serialize(ns3::Buffer::Iterator i, uint32_t size) const [member function] + ## nix-vector.h: uint32_t ns3::NixVector::Serialize(uint32_t * buffer, uint32_t maxSize) const [member function] cls.add_method('Serialize', - 'void', - [param('ns3::Buffer::Iterator', 'i'), param('uint32_t', 'size')], + 'uint32_t', + [param('uint32_t *', 'buffer'), param('uint32_t', 'maxSize')], is_const=True) return @@ -1580,6 +1594,8 @@ def register_Ns3Packet_methods(root_module, cls): cls.add_constructor([param('ns3::Packet const &', 'o')]) ## packet.h: ns3::Packet::Packet(uint32_t size) [constructor] cls.add_constructor([param('uint32_t', 'size')]) + ## packet.h: ns3::Packet::Packet(uint8_t const * buffer, uint32_t size, bool magic) [constructor] + cls.add_constructor([param('uint8_t const *', 'buffer'), param('uint32_t', 'size'), param('bool', 'magic')]) ## packet.h: ns3::Packet::Packet(uint8_t const * buffer, uint32_t size) [constructor] cls.add_constructor([param('uint8_t const *', 'buffer'), param('uint32_t', 'size')]) ## packet.h: void ns3::Packet::AddAtEnd(ns3::Ptr packet) [member function] @@ -1633,10 +1649,6 @@ def register_Ns3Packet_methods(root_module, cls): 'ns3::Ptr< ns3::Packet >', [param('uint32_t', 'start'), param('uint32_t', 'length')], is_const=True) - ## packet.h: void ns3::Packet::Deserialize(ns3::Buffer buffer) [member function] - cls.add_method('Deserialize', - 'void', - [param('ns3::Buffer', 'buffer')]) ## packet.h: static void ns3::Packet::EnableChecking() [member function] cls.add_method('EnableChecking', 'void', @@ -1667,14 +1679,19 @@ def register_Ns3Packet_methods(root_module, cls): 'ns3::PacketTagIterator', [], is_const=True) + ## packet.h: uint32_t ns3::Packet::GetSerializedSize() const [member function] + cls.add_method('GetSerializedSize', + 'uint32_t', + [], + is_const=True) ## packet.h: uint32_t ns3::Packet::GetSize() const [member function] cls.add_method('GetSize', 'uint32_t', [], is_const=True) - ## packet.h: uint32_t ns3::Packet::GetUid() const [member function] + ## packet.h: uint64_t ns3::Packet::GetUid() const [member function] cls.add_method('GetUid', - 'uint32_t', + 'uint64_t', [], is_const=True) ## packet.h: uint8_t const * ns3::Packet::PeekData() const [member function] @@ -1739,10 +1756,10 @@ def register_Ns3Packet_methods(root_module, cls): cls.add_method('RemoveTrailer', 'uint32_t', [param('ns3::Trailer &', 'trailer')]) - ## packet.h: ns3::Buffer ns3::Packet::Serialize() const [member function] + ## packet.h: uint32_t ns3::Packet::Serialize(uint8_t * buffer, uint32_t maxSize) const [member function] cls.add_method('Serialize', - 'ns3::Buffer', - [], + 'uint32_t', + [param('uint8_t *', 'buffer'), param('uint32_t', 'maxSize')], is_const=True) ## packet.h: void ns3::Packet::SetNixVector(ns3::Ptr arg0) [member function] cls.add_method('SetNixVector', diff --git a/bindings/python/apidefs/gcc-ILP32/ns3_module_core.py b/bindings/python/apidefs/gcc-ILP32/ns3_module_core.py index b15076d4f..81fe108fd 100644 --- a/bindings/python/apidefs/gcc-ILP32/ns3_module_core.py +++ b/bindings/python/apidefs/gcc-ILP32/ns3_module_core.py @@ -3075,7 +3075,7 @@ def register_functions(root_module): module.add_function('TypeNameGet', 'std::string', [], - template_parameters=['long']) + template_parameters=['long long']) ## type-name.h: extern std::string ns3::TypeNameGet() [free function] module.add_function('TypeNameGet', 'std::string', diff --git a/bindings/python/apidefs/gcc-ILP32/ns3_module_helper.py b/bindings/python/apidefs/gcc-ILP32/ns3_module_helper.py index 29b20b333..841f1043b 100644 --- a/bindings/python/apidefs/gcc-ILP32/ns3_module_helper.py +++ b/bindings/python/apidefs/gcc-ILP32/ns3_module_helper.py @@ -1202,6 +1202,10 @@ def register_Ns3NodeContainer_methods(root_module, cls): cls.add_method('Create', 'void', [param('uint32_t', 'n')]) + ## node-container.h: void ns3::NodeContainer::Create(uint32_t n, uint32_t systemId) [member function] + cls.add_method('Create', + 'void', + [param('uint32_t', 'n'), param('uint32_t', 'systemId')]) ## node-container.h: __gnu_cxx::__normal_iterator*,std::vector, std::allocator > > > ns3::NodeContainer::End() const [member function] cls.add_method('End', '__gnu_cxx::__normal_iterator< ns3::Ptr< ns3::Node > const, std::vector< ns3::Ptr< ns3::Node > > >', diff --git a/bindings/python/apidefs/gcc-ILP32/ns3_module_mpi.py b/bindings/python/apidefs/gcc-ILP32/ns3_module_mpi.py new file mode 100644 index 000000000..09e96e0df --- /dev/null +++ b/bindings/python/apidefs/gcc-ILP32/ns3_module_mpi.py @@ -0,0 +1,355 @@ +from pybindgen import Module, FileCodeSink, param, retval, cppclass, typehandlers + +def register_types(module): + root_module = module.get_root() + + ## distributed-simulator-impl.h: ns3::LbtsMessage [class] + module.add_class('LbtsMessage') + ## mpi-interface.h: ns3::MpiInterface [class] + module.add_class('MpiInterface') + ## mpi-interface.h: ns3::SentBuffer [class] + module.add_class('SentBuffer') + ## distributed-simulator-impl.h: ns3::DistributedSimulatorImpl [class] + module.add_class('DistributedSimulatorImpl', parent=root_module['ns3::SimulatorImpl']) + + ## 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 TimeStepPrecision + + nested_module = module.add_cpp_namespace('TimeStepPrecision') + register_types_ns3_TimeStepPrecision(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 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_TimeStepPrecision(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_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): + register_Ns3LbtsMessage_methods(root_module, root_module['ns3::LbtsMessage']) + register_Ns3MpiInterface_methods(root_module, root_module['ns3::MpiInterface']) + register_Ns3SentBuffer_methods(root_module, root_module['ns3::SentBuffer']) + register_Ns3DistributedSimulatorImpl_methods(root_module, root_module['ns3::DistributedSimulatorImpl']) + return + +def register_Ns3LbtsMessage_methods(root_module, cls): + ## distributed-simulator-impl.h: ns3::LbtsMessage::LbtsMessage(ns3::LbtsMessage const & arg0) [copy constructor] + cls.add_constructor([param('ns3::LbtsMessage const &', 'arg0')]) + ## distributed-simulator-impl.h: ns3::LbtsMessage::LbtsMessage() [constructor] + cls.add_constructor([]) + ## distributed-simulator-impl.h: ns3::LbtsMessage::LbtsMessage(uint32_t rxc, uint32_t txc, uint32_t id, ns3::Time const & t) [constructor] + cls.add_constructor([param('uint32_t', 'rxc'), param('uint32_t', 'txc'), param('uint32_t', 'id'), param('ns3::Time const &', 't')]) + ## distributed-simulator-impl.h: uint32_t ns3::LbtsMessage::GetMyId() [member function] + cls.add_method('GetMyId', + 'uint32_t', + []) + ## distributed-simulator-impl.h: uint32_t ns3::LbtsMessage::GetRxCount() [member function] + cls.add_method('GetRxCount', + 'uint32_t', + []) + ## distributed-simulator-impl.h: ns3::Time ns3::LbtsMessage::GetSmallestTime() [member function] + cls.add_method('GetSmallestTime', + 'ns3::Time', + []) + ## distributed-simulator-impl.h: uint32_t ns3::LbtsMessage::GetTxCount() [member function] + cls.add_method('GetTxCount', + 'uint32_t', + []) + return + +def register_Ns3MpiInterface_methods(root_module, cls): + ## mpi-interface.h: ns3::MpiInterface::MpiInterface() [constructor] + cls.add_constructor([]) + ## mpi-interface.h: ns3::MpiInterface::MpiInterface(ns3::MpiInterface const & arg0) [copy constructor] + cls.add_constructor([param('ns3::MpiInterface const &', 'arg0')]) + ## mpi-interface.h: static void ns3::MpiInterface::Destroy() [member function] + cls.add_method('Destroy', + 'void', + [], + is_static=True) + ## mpi-interface.h: static void ns3::MpiInterface::Enable(int * arg0, char * * * arg1) [member function] + cls.add_method('Enable', + 'void', + [param('int *', 'arg0'), param('char * * *', 'arg1')], + is_static=True) + ## mpi-interface.h: static uint32_t ns3::MpiInterface::GetRxCount() [member function] + cls.add_method('GetRxCount', + 'uint32_t', + [], + is_static=True) + ## mpi-interface.h: static uint32_t ns3::MpiInterface::GetSize() [member function] + cls.add_method('GetSize', + 'uint32_t', + [], + is_static=True) + ## mpi-interface.h: static uint32_t ns3::MpiInterface::GetSystemId() [member function] + cls.add_method('GetSystemId', + 'uint32_t', + [], + is_static=True) + ## mpi-interface.h: static uint32_t ns3::MpiInterface::GetTxCount() [member function] + cls.add_method('GetTxCount', + 'uint32_t', + [], + is_static=True) + ## mpi-interface.h: static bool ns3::MpiInterface::IsEnabled() [member function] + cls.add_method('IsEnabled', + 'bool', + [], + is_static=True) + ## mpi-interface.h: static void ns3::MpiInterface::ReceiveMessages() [member function] + cls.add_method('ReceiveMessages', + 'void', + [], + is_static=True) + ## mpi-interface.h: static void ns3::MpiInterface::SendPacket(ns3::Ptr arg0, ns3::Time const & arg1, uint32_t arg2, uint32_t arg3) [member function] + cls.add_method('SendPacket', + 'void', + [param('ns3::Ptr< ns3::Packet >', 'arg0'), param('ns3::Time const &', 'arg1'), param('uint32_t', 'arg2'), param('uint32_t', 'arg3')], + is_static=True) + ## mpi-interface.h: static void ns3::MpiInterface::TestSendComplete() [member function] + cls.add_method('TestSendComplete', + 'void', + [], + is_static=True) + return + +def register_Ns3SentBuffer_methods(root_module, cls): + ## mpi-interface.h: ns3::SentBuffer::SentBuffer(ns3::SentBuffer const & arg0) [copy constructor] + cls.add_constructor([param('ns3::SentBuffer const &', 'arg0')]) + ## mpi-interface.h: ns3::SentBuffer::SentBuffer() [constructor] + cls.add_constructor([]) + ## mpi-interface.h: uint8_t * ns3::SentBuffer::GetBuffer() [member function] + cls.add_method('GetBuffer', + 'uint8_t *', + []) + ## mpi-interface.h: MPI_Request * ns3::SentBuffer::GetRequest() [member function] + cls.add_method('GetRequest', + 'MPI_Request *', + []) + ## mpi-interface.h: void ns3::SentBuffer::SetBuffer(uint8_t * arg0) [member function] + cls.add_method('SetBuffer', + 'void', + [param('uint8_t *', 'arg0')]) + return + +def register_Ns3DistributedSimulatorImpl_methods(root_module, cls): + ## distributed-simulator-impl.h: ns3::DistributedSimulatorImpl::DistributedSimulatorImpl(ns3::DistributedSimulatorImpl const & arg0) [copy constructor] + cls.add_constructor([param('ns3::DistributedSimulatorImpl const &', 'arg0')]) + ## distributed-simulator-impl.h: ns3::DistributedSimulatorImpl::DistributedSimulatorImpl() [constructor] + cls.add_constructor([]) + ## distributed-simulator-impl.h: void ns3::DistributedSimulatorImpl::Cancel(ns3::EventId const & ev) [member function] + cls.add_method('Cancel', + 'void', + [param('ns3::EventId const &', 'ev')], + is_virtual=True) + ## distributed-simulator-impl.h: void ns3::DistributedSimulatorImpl::Destroy() [member function] + cls.add_method('Destroy', + 'void', + [], + is_virtual=True) + ## distributed-simulator-impl.h: uint32_t ns3::DistributedSimulatorImpl::GetContext() const [member function] + cls.add_method('GetContext', + 'uint32_t', + [], + is_const=True, is_virtual=True) + ## distributed-simulator-impl.h: ns3::Time ns3::DistributedSimulatorImpl::GetDelayLeft(ns3::EventId const & id) const [member function] + cls.add_method('GetDelayLeft', + 'ns3::Time', + [param('ns3::EventId const &', 'id')], + is_const=True, is_virtual=True) + ## distributed-simulator-impl.h: ns3::Time ns3::DistributedSimulatorImpl::GetMaximumSimulationTime() const [member function] + cls.add_method('GetMaximumSimulationTime', + 'ns3::Time', + [], + is_const=True, is_virtual=True) + ## distributed-simulator-impl.h: uint32_t ns3::DistributedSimulatorImpl::GetSystemId() const [member function] + cls.add_method('GetSystemId', + 'uint32_t', + [], + is_const=True, is_virtual=True) + ## distributed-simulator-impl.h: static ns3::TypeId ns3::DistributedSimulatorImpl::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## distributed-simulator-impl.h: bool ns3::DistributedSimulatorImpl::IsExpired(ns3::EventId const & ev) const [member function] + cls.add_method('IsExpired', + 'bool', + [param('ns3::EventId const &', 'ev')], + is_const=True, is_virtual=True) + ## distributed-simulator-impl.h: bool ns3::DistributedSimulatorImpl::IsFinished() const [member function] + cls.add_method('IsFinished', + 'bool', + [], + is_const=True, is_virtual=True) + ## distributed-simulator-impl.h: ns3::Time ns3::DistributedSimulatorImpl::Next() const [member function] + cls.add_method('Next', + 'ns3::Time', + [], + is_const=True, is_virtual=True) + ## distributed-simulator-impl.h: ns3::Time ns3::DistributedSimulatorImpl::Now() const [member function] + cls.add_method('Now', + 'ns3::Time', + [], + is_const=True, is_virtual=True) + ## distributed-simulator-impl.h: void ns3::DistributedSimulatorImpl::Remove(ns3::EventId const & ev) [member function] + cls.add_method('Remove', + 'void', + [param('ns3::EventId const &', 'ev')], + is_virtual=True) + ## distributed-simulator-impl.h: void ns3::DistributedSimulatorImpl::Run() [member function] + cls.add_method('Run', + 'void', + [], + is_virtual=True) + ## distributed-simulator-impl.h: void ns3::DistributedSimulatorImpl::RunOneEvent() [member function] + cls.add_method('RunOneEvent', + 'void', + [], + is_virtual=True) + ## distributed-simulator-impl.h: ns3::EventId ns3::DistributedSimulatorImpl::Schedule(ns3::Time const & time, ns3::EventImpl * event) [member function] + cls.add_method('Schedule', + 'ns3::EventId', + [param('ns3::Time const &', 'time'), param('ns3::EventImpl *', 'event')], + is_virtual=True) + ## distributed-simulator-impl.h: ns3::EventId ns3::DistributedSimulatorImpl::ScheduleDestroy(ns3::EventImpl * event) [member function] + cls.add_method('ScheduleDestroy', + 'ns3::EventId', + [param('ns3::EventImpl *', 'event')], + is_virtual=True) + ## distributed-simulator-impl.h: ns3::EventId ns3::DistributedSimulatorImpl::ScheduleNow(ns3::EventImpl * event) [member function] + cls.add_method('ScheduleNow', + 'ns3::EventId', + [param('ns3::EventImpl *', 'event')], + is_virtual=True) + ## distributed-simulator-impl.h: void ns3::DistributedSimulatorImpl::ScheduleWithContext(uint32_t context, ns3::Time const & time, ns3::EventImpl * event) [member function] + cls.add_method('ScheduleWithContext', + 'void', + [param('uint32_t', 'context'), param('ns3::Time const &', 'time'), param('ns3::EventImpl *', 'event')], + is_virtual=True) + ## distributed-simulator-impl.h: void ns3::DistributedSimulatorImpl::SetScheduler(ns3::ObjectFactory schedulerFactory) [member function] + cls.add_method('SetScheduler', + 'void', + [param('ns3::ObjectFactory', 'schedulerFactory')], + is_virtual=True) + ## distributed-simulator-impl.h: void ns3::DistributedSimulatorImpl::Stop() [member function] + cls.add_method('Stop', + 'void', + [], + is_virtual=True) + ## distributed-simulator-impl.h: void ns3::DistributedSimulatorImpl::Stop(ns3::Time const & time) [member function] + cls.add_method('Stop', + 'void', + [param('ns3::Time const &', 'time')], + is_virtual=True) + ## distributed-simulator-impl.h: void ns3::DistributedSimulatorImpl::DoDispose() [member function] + cls.add_method('DoDispose', + 'void', + [], + visibility='private', is_virtual=True) + return + +def register_functions(root_module): + module = root_module + register_functions_ns3_Config(module.get_submodule('Config'), root_module) + register_functions_ns3_TimeStepPrecision(module.get_submodule('TimeStepPrecision'), 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_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_TimeStepPrecision(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_flame(module, root_module): + return + +def register_functions_ns3_internal(module, root_module): + return + +def register_functions_ns3_olsr(module, root_module): + return + diff --git a/bindings/python/apidefs/gcc-ILP32/ns3_module_point_to_point.py b/bindings/python/apidefs/gcc-ILP32/ns3_module_point_to_point.py index bc5cf17e6..7563133e8 100644 --- a/bindings/python/apidefs/gcc-ILP32/ns3_module_point_to_point.py +++ b/bindings/python/apidefs/gcc-ILP32/ns3_module_point_to_point.py @@ -9,6 +9,8 @@ def register_types(module): module.add_class('PointToPointChannel', parent=root_module['ns3::Channel']) ## point-to-point-net-device.h: ns3::PointToPointNetDevice [class] module.add_class('PointToPointNetDevice', parent=root_module['ns3::NetDevice']) + ## point-to-point-remote-channel.h: ns3::PointToPointRemoteChannel [class] + module.add_class('PointToPointRemoteChannel', parent=root_module['ns3::PointToPointChannel']) ## Register a nested module for the namespace Config @@ -94,6 +96,7 @@ def register_methods(root_module): register_Ns3PppHeader_methods(root_module, root_module['ns3::PppHeader']) register_Ns3PointToPointChannel_methods(root_module, root_module['ns3::PointToPointChannel']) register_Ns3PointToPointNetDevice_methods(root_module, root_module['ns3::PointToPointNetDevice']) + register_Ns3PointToPointRemoteChannel_methods(root_module, root_module['ns3::PointToPointRemoteChannel']) return def register_Ns3PppHeader_methods(root_module, cls): @@ -173,7 +176,28 @@ def register_Ns3PointToPointChannel_methods(root_module, cls): ## point-to-point-channel.h: bool ns3::PointToPointChannel::TransmitStart(ns3::Ptr p, ns3::Ptr src, ns3::Time txTime) [member function] cls.add_method('TransmitStart', 'bool', - [param('ns3::Ptr< ns3::Packet >', 'p'), param('ns3::Ptr< ns3::PointToPointNetDevice >', 'src'), param('ns3::Time', 'txTime')]) + [param('ns3::Ptr< ns3::Packet >', 'p'), param('ns3::Ptr< ns3::PointToPointNetDevice >', 'src'), param('ns3::Time', 'txTime')], + is_virtual=True) + ## point-to-point-channel.h: ns3::Time ns3::PointToPointChannel::GetDelay() const [member function] + cls.add_method('GetDelay', + 'ns3::Time', + [], + is_const=True, visibility='protected') + ## point-to-point-channel.h: ns3::Ptr ns3::PointToPointChannel::GetDestination(uint32_t i) const [member function] + cls.add_method('GetDestination', + 'ns3::Ptr< ns3::PointToPointNetDevice >', + [param('uint32_t', 'i')], + is_const=True, visibility='protected') + ## point-to-point-channel.h: ns3::Ptr ns3::PointToPointChannel::GetSource(uint32_t i) const [member function] + cls.add_method('GetSource', + 'ns3::Ptr< ns3::PointToPointNetDevice >', + [param('uint32_t', 'i')], + is_const=True, visibility='protected') + ## point-to-point-channel.h: bool ns3::PointToPointChannel::IsInitialized() const [member function] + cls.add_method('IsInitialized', + 'bool', + [], + is_const=True, visibility='protected') return def register_Ns3PointToPointNetDevice_methods(root_module, cls): @@ -351,6 +375,23 @@ def register_Ns3PointToPointNetDevice_methods(root_module, cls): visibility='private', is_virtual=True) return +def register_Ns3PointToPointRemoteChannel_methods(root_module, cls): + ## point-to-point-remote-channel.h: ns3::PointToPointRemoteChannel::PointToPointRemoteChannel(ns3::PointToPointRemoteChannel const & arg0) [copy constructor] + cls.add_constructor([param('ns3::PointToPointRemoteChannel const &', 'arg0')]) + ## point-to-point-remote-channel.h: ns3::PointToPointRemoteChannel::PointToPointRemoteChannel() [constructor] + cls.add_constructor([]) + ## point-to-point-remote-channel.h: static ns3::TypeId ns3::PointToPointRemoteChannel::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## point-to-point-remote-channel.h: bool ns3::PointToPointRemoteChannel::TransmitStart(ns3::Ptr p, ns3::Ptr src, ns3::Time txTime) [member function] + cls.add_method('TransmitStart', + 'bool', + [param('ns3::Ptr< ns3::Packet >', 'p'), param('ns3::Ptr< ns3::PointToPointNetDevice >', 'src'), param('ns3::Time', 'txTime')], + is_virtual=True) + return + def register_functions(root_module): module = root_module register_functions_ns3_Config(module.get_submodule('Config'), root_module) diff --git a/bindings/python/apidefs/gcc-ILP32/ns3_module_simulator.py b/bindings/python/apidefs/gcc-ILP32/ns3_module_simulator.py index 31f6f5384..3253d024f 100644 --- a/bindings/python/apidefs/gcc-ILP32/ns3_module_simulator.py +++ b/bindings/python/apidefs/gcc-ILP32/ns3_module_simulator.py @@ -317,6 +317,11 @@ def register_Ns3Simulator_methods(root_module, cls): 'ns3::Time', [], is_static=True) + ## simulator.h: static uint32_t ns3::Simulator::GetSystemId() [member function] + cls.add_method('GetSystemId', + 'uint32_t', + [], + is_static=True) ## simulator.h: static bool ns3::Simulator::IsExpired(ns3::EventId const & id) [member function] cls.add_method('IsExpired', 'bool', @@ -795,6 +800,11 @@ def register_Ns3SimulatorImpl_methods(root_module, cls): 'ns3::Time', [], is_pure_virtual=True, is_const=True, is_virtual=True) + ## simulator-impl.h: uint32_t ns3::SimulatorImpl::GetSystemId() const [member function] + cls.add_method('GetSystemId', + 'uint32_t', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) ## simulator-impl.h: bool ns3::SimulatorImpl::IsExpired(ns3::EventId const & ev) const [member function] cls.add_method('IsExpired', 'bool', @@ -1129,6 +1139,11 @@ def register_Ns3DefaultSimulatorImpl_methods(root_module, cls): 'ns3::Time', [], is_const=True, is_virtual=True) + ## default-simulator-impl.h: uint32_t ns3::DefaultSimulatorImpl::GetSystemId() const [member function] + cls.add_method('GetSystemId', + 'uint32_t', + [], + is_const=True, is_virtual=True) ## default-simulator-impl.h: static ns3::TypeId ns3::DefaultSimulatorImpl::GetTypeId() [member function] cls.add_method('GetTypeId', 'ns3::TypeId', @@ -1423,6 +1438,11 @@ def register_Ns3RealtimeSimulatorImpl_methods(root_module, cls): 'ns3::RealtimeSimulatorImpl::SynchronizationMode', [], is_const=True) + ## realtime-simulator-impl.h: uint32_t ns3::RealtimeSimulatorImpl::GetSystemId() const [member function] + cls.add_method('GetSystemId', + 'uint32_t', + [], + is_const=True, is_virtual=True) ## realtime-simulator-impl.h: static ns3::TypeId ns3::RealtimeSimulatorImpl::GetTypeId() [member function] cls.add_method('GetTypeId', 'ns3::TypeId', diff --git a/bindings/python/apidefs/gcc-ILP32/ns3modulegen_generated.py b/bindings/python/apidefs/gcc-ILP32/ns3modulegen_generated.py index 0d92fb8ed..c80c23c3f 100644 --- a/bindings/python/apidefs/gcc-ILP32/ns3modulegen_generated.py +++ b/bindings/python/apidefs/gcc-ILP32/ns3modulegen_generated.py @@ -17,6 +17,7 @@ import ns3_module_simulator import ns3_module_test import ns3_module_common import ns3_module_mobility +import ns3_module_mpi import ns3_module_contrib import ns3_module_node import ns3_module_bridge @@ -109,6 +110,17 @@ def register_types(module): ns3_module_mobility__local.register_types(module) root_module.end_section('ns3_module_mobility') + root_module.begin_section('ns3_module_mpi') + ns3_module_mpi.register_types(module) + + try: + import ns3_module_mpi__local + except ImportError: + pass + else: + ns3_module_mpi__local.register_types(module) + + root_module.end_section('ns3_module_mpi') root_module.begin_section('ns3_module_contrib') ns3_module_contrib.register_types(module) @@ -572,6 +584,17 @@ def register_methods(root_module): ns3_module_mobility__local.register_methods(root_module) root_module.end_section('ns3_module_mobility') + root_module.begin_section('ns3_module_mpi') + ns3_module_mpi.register_methods(root_module) + + try: + import ns3_module_mpi__local + except ImportError: + pass + else: + ns3_module_mpi__local.register_methods(root_module) + + root_module.end_section('ns3_module_mpi') root_module.begin_section('ns3_module_contrib') ns3_module_contrib.register_methods(root_module) @@ -950,6 +973,17 @@ def register_functions(root_module): ns3_module_mobility__local.register_functions(root_module) root_module.end_section('ns3_module_mobility') + root_module.begin_section('ns3_module_mpi') + ns3_module_mpi.register_functions(root_module) + + try: + import ns3_module_mpi__local + except ImportError: + pass + else: + ns3_module_mpi__local.register_functions(root_module) + + root_module.end_section('ns3_module_mpi') root_module.begin_section('ns3_module_contrib') ns3_module_contrib.register_functions(root_module) diff --git a/bindings/python/apidefs/gcc-LP64/ns3_module_common.py b/bindings/python/apidefs/gcc-LP64/ns3_module_common.py index 6ec9894f1..473641f98 100644 --- a/bindings/python/apidefs/gcc-LP64/ns3_module_common.py +++ b/bindings/python/apidefs/gcc-LP64/ns3_module_common.py @@ -265,6 +265,10 @@ def register_Ns3Buffer_methods(root_module, cls): 'ns3::Buffer', [], is_const=True) + ## buffer.h: uint32_t ns3::Buffer::Deserialize(uint8_t * buffer, uint32_t size) [member function] + cls.add_method('Deserialize', + 'uint32_t', + [param('uint8_t *', 'buffer'), param('uint32_t', 'size')]) ## buffer.h: ns3::Buffer::Iterator ns3::Buffer::End() const [member function] cls.add_method('End', 'ns3::Buffer::Iterator', @@ -280,6 +284,11 @@ def register_Ns3Buffer_methods(root_module, cls): 'int32_t', [], is_const=True) + ## buffer.h: uint32_t ns3::Buffer::GetSerializedSize() const [member function] + cls.add_method('GetSerializedSize', + 'uint32_t', + [], + is_const=True) ## buffer.h: uint32_t ns3::Buffer::GetSize() const [member function] cls.add_method('GetSize', 'uint32_t', @@ -298,6 +307,11 @@ def register_Ns3Buffer_methods(root_module, cls): cls.add_method('RemoveAtStart', 'void', [param('uint32_t', 'start')]) + ## buffer.h: uint32_t ns3::Buffer::Serialize(uint8_t * buffer, uint32_t maxSize) const [member function] + cls.add_method('Serialize', + 'uint32_t', + [param('uint8_t *', 'buffer'), param('uint32_t', 'maxSize')], + is_const=True) return def register_Ns3BufferIterator_methods(root_module, cls): @@ -583,8 +597,8 @@ def register_Ns3DataRate_methods(root_module, cls): return def register_Ns3PacketMetadata_methods(root_module, cls): - ## packet-metadata.h: ns3::PacketMetadata::PacketMetadata(uint32_t uid, uint32_t size) [constructor] - cls.add_constructor([param('uint32_t', 'uid'), param('uint32_t', 'size')]) + ## packet-metadata.h: ns3::PacketMetadata::PacketMetadata(uint64_t uid, uint32_t size) [constructor] + cls.add_constructor([param('uint64_t', 'uid'), param('uint32_t', 'size')]) ## packet-metadata.h: ns3::PacketMetadata::PacketMetadata(ns3::PacketMetadata const & o) [copy constructor] cls.add_constructor([param('ns3::PacketMetadata const &', 'o')]) ## packet-metadata.h: void ns3::PacketMetadata::AddAtEnd(ns3::PacketMetadata const & o) [member function] @@ -613,10 +627,10 @@ def register_Ns3PacketMetadata_methods(root_module, cls): 'ns3::PacketMetadata', [param('uint32_t', 'start'), param('uint32_t', 'end')], is_const=True) - ## packet-metadata.h: uint32_t ns3::PacketMetadata::Deserialize(ns3::Buffer::Iterator i) [member function] + ## packet-metadata.h: uint32_t ns3::PacketMetadata::Deserialize(uint8_t * buffer, uint32_t size) [member function] cls.add_method('Deserialize', 'uint32_t', - [param('ns3::Buffer::Iterator', 'i')]) + [param('uint8_t *', 'buffer'), param('uint32_t', 'size')]) ## packet-metadata.h: static void ns3::PacketMetadata::Enable() [member function] cls.add_method('Enable', 'void', @@ -632,9 +646,9 @@ def register_Ns3PacketMetadata_methods(root_module, cls): 'uint32_t', [], is_const=True) - ## packet-metadata.h: uint32_t ns3::PacketMetadata::GetUid() const [member function] + ## packet-metadata.h: uint64_t ns3::PacketMetadata::GetUid() const [member function] cls.add_method('GetUid', - 'uint32_t', + 'uint64_t', [], is_const=True) ## packet-metadata.h: void ns3::PacketMetadata::RemoveAtEnd(uint32_t end) [member function] @@ -653,10 +667,10 @@ def register_Ns3PacketMetadata_methods(root_module, cls): cls.add_method('RemoveTrailer', 'void', [param('ns3::Trailer const &', 'trailer'), param('uint32_t', 'size')]) - ## packet-metadata.h: void ns3::PacketMetadata::Serialize(ns3::Buffer::Iterator i, uint32_t size) const [member function] + ## packet-metadata.h: uint32_t ns3::PacketMetadata::Serialize(uint8_t * buffer, uint32_t maxSize) const [member function] cls.add_method('Serialize', - 'void', - [param('ns3::Buffer::Iterator', 'i'), param('uint32_t', 'size')], + 'uint32_t', + [param('uint8_t *', 'buffer'), param('uint32_t', 'maxSize')], is_const=True) return @@ -1523,10 +1537,10 @@ def register_Ns3NixVector_methods(root_module, cls): 'ns3::Ptr< ns3::NixVector >', [], is_const=True) - ## nix-vector.h: uint32_t ns3::NixVector::Deserialize(ns3::Buffer::Iterator i) [member function] + ## nix-vector.h: uint32_t ns3::NixVector::Deserialize(uint32_t * buffer, uint32_t size) [member function] cls.add_method('Deserialize', 'uint32_t', - [param('ns3::Buffer::Iterator', 'i')]) + [param('uint32_t *', 'buffer'), param('uint32_t', 'size')]) ## nix-vector.h: void ns3::NixVector::DumpNixVector(std::ostream & os) const [member function] cls.add_method('DumpNixVector', 'void', @@ -1550,10 +1564,10 @@ def register_Ns3NixVector_methods(root_module, cls): 'ns3::TypeId', [], is_static=True) - ## nix-vector.h: void ns3::NixVector::Serialize(ns3::Buffer::Iterator i, uint32_t size) const [member function] + ## nix-vector.h: uint32_t ns3::NixVector::Serialize(uint32_t * buffer, uint32_t maxSize) const [member function] cls.add_method('Serialize', - 'void', - [param('ns3::Buffer::Iterator', 'i'), param('uint32_t', 'size')], + 'uint32_t', + [param('uint32_t *', 'buffer'), param('uint32_t', 'maxSize')], is_const=True) return @@ -1580,6 +1594,8 @@ def register_Ns3Packet_methods(root_module, cls): cls.add_constructor([param('ns3::Packet const &', 'o')]) ## packet.h: ns3::Packet::Packet(uint32_t size) [constructor] cls.add_constructor([param('uint32_t', 'size')]) + ## packet.h: ns3::Packet::Packet(uint8_t const * buffer, uint32_t size, bool magic) [constructor] + cls.add_constructor([param('uint8_t const *', 'buffer'), param('uint32_t', 'size'), param('bool', 'magic')]) ## packet.h: ns3::Packet::Packet(uint8_t const * buffer, uint32_t size) [constructor] cls.add_constructor([param('uint8_t const *', 'buffer'), param('uint32_t', 'size')]) ## packet.h: void ns3::Packet::AddAtEnd(ns3::Ptr packet) [member function] @@ -1633,10 +1649,6 @@ def register_Ns3Packet_methods(root_module, cls): 'ns3::Ptr< ns3::Packet >', [param('uint32_t', 'start'), param('uint32_t', 'length')], is_const=True) - ## packet.h: void ns3::Packet::Deserialize(ns3::Buffer buffer) [member function] - cls.add_method('Deserialize', - 'void', - [param('ns3::Buffer', 'buffer')]) ## packet.h: static void ns3::Packet::EnableChecking() [member function] cls.add_method('EnableChecking', 'void', @@ -1667,14 +1679,19 @@ def register_Ns3Packet_methods(root_module, cls): 'ns3::PacketTagIterator', [], is_const=True) + ## packet.h: uint32_t ns3::Packet::GetSerializedSize() const [member function] + cls.add_method('GetSerializedSize', + 'uint32_t', + [], + is_const=True) ## packet.h: uint32_t ns3::Packet::GetSize() const [member function] cls.add_method('GetSize', 'uint32_t', [], is_const=True) - ## packet.h: uint32_t ns3::Packet::GetUid() const [member function] + ## packet.h: uint64_t ns3::Packet::GetUid() const [member function] cls.add_method('GetUid', - 'uint32_t', + 'uint64_t', [], is_const=True) ## packet.h: uint8_t const * ns3::Packet::PeekData() const [member function] @@ -1739,10 +1756,10 @@ def register_Ns3Packet_methods(root_module, cls): cls.add_method('RemoveTrailer', 'uint32_t', [param('ns3::Trailer &', 'trailer')]) - ## packet.h: ns3::Buffer ns3::Packet::Serialize() const [member function] + ## packet.h: uint32_t ns3::Packet::Serialize(uint8_t * buffer, uint32_t maxSize) const [member function] cls.add_method('Serialize', - 'ns3::Buffer', - [], + 'uint32_t', + [param('uint8_t *', 'buffer'), param('uint32_t', 'maxSize')], is_const=True) ## packet.h: void ns3::Packet::SetNixVector(ns3::Ptr arg0) [member function] cls.add_method('SetNixVector', diff --git a/bindings/python/apidefs/gcc-LP64/ns3_module_helper.py b/bindings/python/apidefs/gcc-LP64/ns3_module_helper.py index 29b20b333..841f1043b 100644 --- a/bindings/python/apidefs/gcc-LP64/ns3_module_helper.py +++ b/bindings/python/apidefs/gcc-LP64/ns3_module_helper.py @@ -1202,6 +1202,10 @@ def register_Ns3NodeContainer_methods(root_module, cls): cls.add_method('Create', 'void', [param('uint32_t', 'n')]) + ## node-container.h: void ns3::NodeContainer::Create(uint32_t n, uint32_t systemId) [member function] + cls.add_method('Create', + 'void', + [param('uint32_t', 'n'), param('uint32_t', 'systemId')]) ## node-container.h: __gnu_cxx::__normal_iterator*,std::vector, std::allocator > > > ns3::NodeContainer::End() const [member function] cls.add_method('End', '__gnu_cxx::__normal_iterator< ns3::Ptr< ns3::Node > const, std::vector< ns3::Ptr< ns3::Node > > >', diff --git a/bindings/python/apidefs/gcc-LP64/ns3_module_mpi.py b/bindings/python/apidefs/gcc-LP64/ns3_module_mpi.py new file mode 100644 index 000000000..09e96e0df --- /dev/null +++ b/bindings/python/apidefs/gcc-LP64/ns3_module_mpi.py @@ -0,0 +1,355 @@ +from pybindgen import Module, FileCodeSink, param, retval, cppclass, typehandlers + +def register_types(module): + root_module = module.get_root() + + ## distributed-simulator-impl.h: ns3::LbtsMessage [class] + module.add_class('LbtsMessage') + ## mpi-interface.h: ns3::MpiInterface [class] + module.add_class('MpiInterface') + ## mpi-interface.h: ns3::SentBuffer [class] + module.add_class('SentBuffer') + ## distributed-simulator-impl.h: ns3::DistributedSimulatorImpl [class] + module.add_class('DistributedSimulatorImpl', parent=root_module['ns3::SimulatorImpl']) + + ## 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 TimeStepPrecision + + nested_module = module.add_cpp_namespace('TimeStepPrecision') + register_types_ns3_TimeStepPrecision(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 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_TimeStepPrecision(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_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): + register_Ns3LbtsMessage_methods(root_module, root_module['ns3::LbtsMessage']) + register_Ns3MpiInterface_methods(root_module, root_module['ns3::MpiInterface']) + register_Ns3SentBuffer_methods(root_module, root_module['ns3::SentBuffer']) + register_Ns3DistributedSimulatorImpl_methods(root_module, root_module['ns3::DistributedSimulatorImpl']) + return + +def register_Ns3LbtsMessage_methods(root_module, cls): + ## distributed-simulator-impl.h: ns3::LbtsMessage::LbtsMessage(ns3::LbtsMessage const & arg0) [copy constructor] + cls.add_constructor([param('ns3::LbtsMessage const &', 'arg0')]) + ## distributed-simulator-impl.h: ns3::LbtsMessage::LbtsMessage() [constructor] + cls.add_constructor([]) + ## distributed-simulator-impl.h: ns3::LbtsMessage::LbtsMessage(uint32_t rxc, uint32_t txc, uint32_t id, ns3::Time const & t) [constructor] + cls.add_constructor([param('uint32_t', 'rxc'), param('uint32_t', 'txc'), param('uint32_t', 'id'), param('ns3::Time const &', 't')]) + ## distributed-simulator-impl.h: uint32_t ns3::LbtsMessage::GetMyId() [member function] + cls.add_method('GetMyId', + 'uint32_t', + []) + ## distributed-simulator-impl.h: uint32_t ns3::LbtsMessage::GetRxCount() [member function] + cls.add_method('GetRxCount', + 'uint32_t', + []) + ## distributed-simulator-impl.h: ns3::Time ns3::LbtsMessage::GetSmallestTime() [member function] + cls.add_method('GetSmallestTime', + 'ns3::Time', + []) + ## distributed-simulator-impl.h: uint32_t ns3::LbtsMessage::GetTxCount() [member function] + cls.add_method('GetTxCount', + 'uint32_t', + []) + return + +def register_Ns3MpiInterface_methods(root_module, cls): + ## mpi-interface.h: ns3::MpiInterface::MpiInterface() [constructor] + cls.add_constructor([]) + ## mpi-interface.h: ns3::MpiInterface::MpiInterface(ns3::MpiInterface const & arg0) [copy constructor] + cls.add_constructor([param('ns3::MpiInterface const &', 'arg0')]) + ## mpi-interface.h: static void ns3::MpiInterface::Destroy() [member function] + cls.add_method('Destroy', + 'void', + [], + is_static=True) + ## mpi-interface.h: static void ns3::MpiInterface::Enable(int * arg0, char * * * arg1) [member function] + cls.add_method('Enable', + 'void', + [param('int *', 'arg0'), param('char * * *', 'arg1')], + is_static=True) + ## mpi-interface.h: static uint32_t ns3::MpiInterface::GetRxCount() [member function] + cls.add_method('GetRxCount', + 'uint32_t', + [], + is_static=True) + ## mpi-interface.h: static uint32_t ns3::MpiInterface::GetSize() [member function] + cls.add_method('GetSize', + 'uint32_t', + [], + is_static=True) + ## mpi-interface.h: static uint32_t ns3::MpiInterface::GetSystemId() [member function] + cls.add_method('GetSystemId', + 'uint32_t', + [], + is_static=True) + ## mpi-interface.h: static uint32_t ns3::MpiInterface::GetTxCount() [member function] + cls.add_method('GetTxCount', + 'uint32_t', + [], + is_static=True) + ## mpi-interface.h: static bool ns3::MpiInterface::IsEnabled() [member function] + cls.add_method('IsEnabled', + 'bool', + [], + is_static=True) + ## mpi-interface.h: static void ns3::MpiInterface::ReceiveMessages() [member function] + cls.add_method('ReceiveMessages', + 'void', + [], + is_static=True) + ## mpi-interface.h: static void ns3::MpiInterface::SendPacket(ns3::Ptr arg0, ns3::Time const & arg1, uint32_t arg2, uint32_t arg3) [member function] + cls.add_method('SendPacket', + 'void', + [param('ns3::Ptr< ns3::Packet >', 'arg0'), param('ns3::Time const &', 'arg1'), param('uint32_t', 'arg2'), param('uint32_t', 'arg3')], + is_static=True) + ## mpi-interface.h: static void ns3::MpiInterface::TestSendComplete() [member function] + cls.add_method('TestSendComplete', + 'void', + [], + is_static=True) + return + +def register_Ns3SentBuffer_methods(root_module, cls): + ## mpi-interface.h: ns3::SentBuffer::SentBuffer(ns3::SentBuffer const & arg0) [copy constructor] + cls.add_constructor([param('ns3::SentBuffer const &', 'arg0')]) + ## mpi-interface.h: ns3::SentBuffer::SentBuffer() [constructor] + cls.add_constructor([]) + ## mpi-interface.h: uint8_t * ns3::SentBuffer::GetBuffer() [member function] + cls.add_method('GetBuffer', + 'uint8_t *', + []) + ## mpi-interface.h: MPI_Request * ns3::SentBuffer::GetRequest() [member function] + cls.add_method('GetRequest', + 'MPI_Request *', + []) + ## mpi-interface.h: void ns3::SentBuffer::SetBuffer(uint8_t * arg0) [member function] + cls.add_method('SetBuffer', + 'void', + [param('uint8_t *', 'arg0')]) + return + +def register_Ns3DistributedSimulatorImpl_methods(root_module, cls): + ## distributed-simulator-impl.h: ns3::DistributedSimulatorImpl::DistributedSimulatorImpl(ns3::DistributedSimulatorImpl const & arg0) [copy constructor] + cls.add_constructor([param('ns3::DistributedSimulatorImpl const &', 'arg0')]) + ## distributed-simulator-impl.h: ns3::DistributedSimulatorImpl::DistributedSimulatorImpl() [constructor] + cls.add_constructor([]) + ## distributed-simulator-impl.h: void ns3::DistributedSimulatorImpl::Cancel(ns3::EventId const & ev) [member function] + cls.add_method('Cancel', + 'void', + [param('ns3::EventId const &', 'ev')], + is_virtual=True) + ## distributed-simulator-impl.h: void ns3::DistributedSimulatorImpl::Destroy() [member function] + cls.add_method('Destroy', + 'void', + [], + is_virtual=True) + ## distributed-simulator-impl.h: uint32_t ns3::DistributedSimulatorImpl::GetContext() const [member function] + cls.add_method('GetContext', + 'uint32_t', + [], + is_const=True, is_virtual=True) + ## distributed-simulator-impl.h: ns3::Time ns3::DistributedSimulatorImpl::GetDelayLeft(ns3::EventId const & id) const [member function] + cls.add_method('GetDelayLeft', + 'ns3::Time', + [param('ns3::EventId const &', 'id')], + is_const=True, is_virtual=True) + ## distributed-simulator-impl.h: ns3::Time ns3::DistributedSimulatorImpl::GetMaximumSimulationTime() const [member function] + cls.add_method('GetMaximumSimulationTime', + 'ns3::Time', + [], + is_const=True, is_virtual=True) + ## distributed-simulator-impl.h: uint32_t ns3::DistributedSimulatorImpl::GetSystemId() const [member function] + cls.add_method('GetSystemId', + 'uint32_t', + [], + is_const=True, is_virtual=True) + ## distributed-simulator-impl.h: static ns3::TypeId ns3::DistributedSimulatorImpl::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## distributed-simulator-impl.h: bool ns3::DistributedSimulatorImpl::IsExpired(ns3::EventId const & ev) const [member function] + cls.add_method('IsExpired', + 'bool', + [param('ns3::EventId const &', 'ev')], + is_const=True, is_virtual=True) + ## distributed-simulator-impl.h: bool ns3::DistributedSimulatorImpl::IsFinished() const [member function] + cls.add_method('IsFinished', + 'bool', + [], + is_const=True, is_virtual=True) + ## distributed-simulator-impl.h: ns3::Time ns3::DistributedSimulatorImpl::Next() const [member function] + cls.add_method('Next', + 'ns3::Time', + [], + is_const=True, is_virtual=True) + ## distributed-simulator-impl.h: ns3::Time ns3::DistributedSimulatorImpl::Now() const [member function] + cls.add_method('Now', + 'ns3::Time', + [], + is_const=True, is_virtual=True) + ## distributed-simulator-impl.h: void ns3::DistributedSimulatorImpl::Remove(ns3::EventId const & ev) [member function] + cls.add_method('Remove', + 'void', + [param('ns3::EventId const &', 'ev')], + is_virtual=True) + ## distributed-simulator-impl.h: void ns3::DistributedSimulatorImpl::Run() [member function] + cls.add_method('Run', + 'void', + [], + is_virtual=True) + ## distributed-simulator-impl.h: void ns3::DistributedSimulatorImpl::RunOneEvent() [member function] + cls.add_method('RunOneEvent', + 'void', + [], + is_virtual=True) + ## distributed-simulator-impl.h: ns3::EventId ns3::DistributedSimulatorImpl::Schedule(ns3::Time const & time, ns3::EventImpl * event) [member function] + cls.add_method('Schedule', + 'ns3::EventId', + [param('ns3::Time const &', 'time'), param('ns3::EventImpl *', 'event')], + is_virtual=True) + ## distributed-simulator-impl.h: ns3::EventId ns3::DistributedSimulatorImpl::ScheduleDestroy(ns3::EventImpl * event) [member function] + cls.add_method('ScheduleDestroy', + 'ns3::EventId', + [param('ns3::EventImpl *', 'event')], + is_virtual=True) + ## distributed-simulator-impl.h: ns3::EventId ns3::DistributedSimulatorImpl::ScheduleNow(ns3::EventImpl * event) [member function] + cls.add_method('ScheduleNow', + 'ns3::EventId', + [param('ns3::EventImpl *', 'event')], + is_virtual=True) + ## distributed-simulator-impl.h: void ns3::DistributedSimulatorImpl::ScheduleWithContext(uint32_t context, ns3::Time const & time, ns3::EventImpl * event) [member function] + cls.add_method('ScheduleWithContext', + 'void', + [param('uint32_t', 'context'), param('ns3::Time const &', 'time'), param('ns3::EventImpl *', 'event')], + is_virtual=True) + ## distributed-simulator-impl.h: void ns3::DistributedSimulatorImpl::SetScheduler(ns3::ObjectFactory schedulerFactory) [member function] + cls.add_method('SetScheduler', + 'void', + [param('ns3::ObjectFactory', 'schedulerFactory')], + is_virtual=True) + ## distributed-simulator-impl.h: void ns3::DistributedSimulatorImpl::Stop() [member function] + cls.add_method('Stop', + 'void', + [], + is_virtual=True) + ## distributed-simulator-impl.h: void ns3::DistributedSimulatorImpl::Stop(ns3::Time const & time) [member function] + cls.add_method('Stop', + 'void', + [param('ns3::Time const &', 'time')], + is_virtual=True) + ## distributed-simulator-impl.h: void ns3::DistributedSimulatorImpl::DoDispose() [member function] + cls.add_method('DoDispose', + 'void', + [], + visibility='private', is_virtual=True) + return + +def register_functions(root_module): + module = root_module + register_functions_ns3_Config(module.get_submodule('Config'), root_module) + register_functions_ns3_TimeStepPrecision(module.get_submodule('TimeStepPrecision'), 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_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_TimeStepPrecision(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_flame(module, root_module): + return + +def register_functions_ns3_internal(module, root_module): + return + +def register_functions_ns3_olsr(module, root_module): + return + diff --git a/bindings/python/apidefs/gcc-LP64/ns3_module_point_to_point.py b/bindings/python/apidefs/gcc-LP64/ns3_module_point_to_point.py index bc5cf17e6..7563133e8 100644 --- a/bindings/python/apidefs/gcc-LP64/ns3_module_point_to_point.py +++ b/bindings/python/apidefs/gcc-LP64/ns3_module_point_to_point.py @@ -9,6 +9,8 @@ def register_types(module): module.add_class('PointToPointChannel', parent=root_module['ns3::Channel']) ## point-to-point-net-device.h: ns3::PointToPointNetDevice [class] module.add_class('PointToPointNetDevice', parent=root_module['ns3::NetDevice']) + ## point-to-point-remote-channel.h: ns3::PointToPointRemoteChannel [class] + module.add_class('PointToPointRemoteChannel', parent=root_module['ns3::PointToPointChannel']) ## Register a nested module for the namespace Config @@ -94,6 +96,7 @@ def register_methods(root_module): register_Ns3PppHeader_methods(root_module, root_module['ns3::PppHeader']) register_Ns3PointToPointChannel_methods(root_module, root_module['ns3::PointToPointChannel']) register_Ns3PointToPointNetDevice_methods(root_module, root_module['ns3::PointToPointNetDevice']) + register_Ns3PointToPointRemoteChannel_methods(root_module, root_module['ns3::PointToPointRemoteChannel']) return def register_Ns3PppHeader_methods(root_module, cls): @@ -173,7 +176,28 @@ def register_Ns3PointToPointChannel_methods(root_module, cls): ## point-to-point-channel.h: bool ns3::PointToPointChannel::TransmitStart(ns3::Ptr p, ns3::Ptr src, ns3::Time txTime) [member function] cls.add_method('TransmitStart', 'bool', - [param('ns3::Ptr< ns3::Packet >', 'p'), param('ns3::Ptr< ns3::PointToPointNetDevice >', 'src'), param('ns3::Time', 'txTime')]) + [param('ns3::Ptr< ns3::Packet >', 'p'), param('ns3::Ptr< ns3::PointToPointNetDevice >', 'src'), param('ns3::Time', 'txTime')], + is_virtual=True) + ## point-to-point-channel.h: ns3::Time ns3::PointToPointChannel::GetDelay() const [member function] + cls.add_method('GetDelay', + 'ns3::Time', + [], + is_const=True, visibility='protected') + ## point-to-point-channel.h: ns3::Ptr ns3::PointToPointChannel::GetDestination(uint32_t i) const [member function] + cls.add_method('GetDestination', + 'ns3::Ptr< ns3::PointToPointNetDevice >', + [param('uint32_t', 'i')], + is_const=True, visibility='protected') + ## point-to-point-channel.h: ns3::Ptr ns3::PointToPointChannel::GetSource(uint32_t i) const [member function] + cls.add_method('GetSource', + 'ns3::Ptr< ns3::PointToPointNetDevice >', + [param('uint32_t', 'i')], + is_const=True, visibility='protected') + ## point-to-point-channel.h: bool ns3::PointToPointChannel::IsInitialized() const [member function] + cls.add_method('IsInitialized', + 'bool', + [], + is_const=True, visibility='protected') return def register_Ns3PointToPointNetDevice_methods(root_module, cls): @@ -351,6 +375,23 @@ def register_Ns3PointToPointNetDevice_methods(root_module, cls): visibility='private', is_virtual=True) return +def register_Ns3PointToPointRemoteChannel_methods(root_module, cls): + ## point-to-point-remote-channel.h: ns3::PointToPointRemoteChannel::PointToPointRemoteChannel(ns3::PointToPointRemoteChannel const & arg0) [copy constructor] + cls.add_constructor([param('ns3::PointToPointRemoteChannel const &', 'arg0')]) + ## point-to-point-remote-channel.h: ns3::PointToPointRemoteChannel::PointToPointRemoteChannel() [constructor] + cls.add_constructor([]) + ## point-to-point-remote-channel.h: static ns3::TypeId ns3::PointToPointRemoteChannel::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## point-to-point-remote-channel.h: bool ns3::PointToPointRemoteChannel::TransmitStart(ns3::Ptr p, ns3::Ptr src, ns3::Time txTime) [member function] + cls.add_method('TransmitStart', + 'bool', + [param('ns3::Ptr< ns3::Packet >', 'p'), param('ns3::Ptr< ns3::PointToPointNetDevice >', 'src'), param('ns3::Time', 'txTime')], + is_virtual=True) + return + def register_functions(root_module): module = root_module register_functions_ns3_Config(module.get_submodule('Config'), root_module) diff --git a/bindings/python/apidefs/gcc-LP64/ns3_module_simulator.py b/bindings/python/apidefs/gcc-LP64/ns3_module_simulator.py index 31f6f5384..3253d024f 100644 --- a/bindings/python/apidefs/gcc-LP64/ns3_module_simulator.py +++ b/bindings/python/apidefs/gcc-LP64/ns3_module_simulator.py @@ -317,6 +317,11 @@ def register_Ns3Simulator_methods(root_module, cls): 'ns3::Time', [], is_static=True) + ## simulator.h: static uint32_t ns3::Simulator::GetSystemId() [member function] + cls.add_method('GetSystemId', + 'uint32_t', + [], + is_static=True) ## simulator.h: static bool ns3::Simulator::IsExpired(ns3::EventId const & id) [member function] cls.add_method('IsExpired', 'bool', @@ -795,6 +800,11 @@ def register_Ns3SimulatorImpl_methods(root_module, cls): 'ns3::Time', [], is_pure_virtual=True, is_const=True, is_virtual=True) + ## simulator-impl.h: uint32_t ns3::SimulatorImpl::GetSystemId() const [member function] + cls.add_method('GetSystemId', + 'uint32_t', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) ## simulator-impl.h: bool ns3::SimulatorImpl::IsExpired(ns3::EventId const & ev) const [member function] cls.add_method('IsExpired', 'bool', @@ -1129,6 +1139,11 @@ def register_Ns3DefaultSimulatorImpl_methods(root_module, cls): 'ns3::Time', [], is_const=True, is_virtual=True) + ## default-simulator-impl.h: uint32_t ns3::DefaultSimulatorImpl::GetSystemId() const [member function] + cls.add_method('GetSystemId', + 'uint32_t', + [], + is_const=True, is_virtual=True) ## default-simulator-impl.h: static ns3::TypeId ns3::DefaultSimulatorImpl::GetTypeId() [member function] cls.add_method('GetTypeId', 'ns3::TypeId', @@ -1423,6 +1438,11 @@ def register_Ns3RealtimeSimulatorImpl_methods(root_module, cls): 'ns3::RealtimeSimulatorImpl::SynchronizationMode', [], is_const=True) + ## realtime-simulator-impl.h: uint32_t ns3::RealtimeSimulatorImpl::GetSystemId() const [member function] + cls.add_method('GetSystemId', + 'uint32_t', + [], + is_const=True, is_virtual=True) ## realtime-simulator-impl.h: static ns3::TypeId ns3::RealtimeSimulatorImpl::GetTypeId() [member function] cls.add_method('GetTypeId', 'ns3::TypeId', diff --git a/bindings/python/apidefs/gcc-LP64/ns3modulegen_generated.py b/bindings/python/apidefs/gcc-LP64/ns3modulegen_generated.py index e2e71fdb3..5ee2c25d4 100644 --- a/bindings/python/apidefs/gcc-LP64/ns3modulegen_generated.py +++ b/bindings/python/apidefs/gcc-LP64/ns3modulegen_generated.py @@ -17,6 +17,7 @@ import ns3_module_simulator import ns3_module_test import ns3_module_common import ns3_module_mobility +import ns3_module_mpi import ns3_module_contrib import ns3_module_node import ns3_module_bridge @@ -109,6 +110,17 @@ def register_types(module): ns3_module_mobility__local.register_types(module) root_module.end_section('ns3_module_mobility') + root_module.begin_section('ns3_module_mpi') + ns3_module_mpi.register_types(module) + + try: + import ns3_module_mpi__local + except ImportError: + pass + else: + ns3_module_mpi__local.register_types(module) + + root_module.end_section('ns3_module_mpi') root_module.begin_section('ns3_module_contrib') ns3_module_contrib.register_types(module) @@ -572,6 +584,17 @@ def register_methods(root_module): ns3_module_mobility__local.register_methods(root_module) root_module.end_section('ns3_module_mobility') + root_module.begin_section('ns3_module_mpi') + ns3_module_mpi.register_methods(root_module) + + try: + import ns3_module_mpi__local + except ImportError: + pass + else: + ns3_module_mpi__local.register_methods(root_module) + + root_module.end_section('ns3_module_mpi') root_module.begin_section('ns3_module_contrib') ns3_module_contrib.register_methods(root_module) @@ -950,6 +973,17 @@ def register_functions(root_module): ns3_module_mobility__local.register_functions(root_module) root_module.end_section('ns3_module_mobility') + root_module.begin_section('ns3_module_mpi') + ns3_module_mpi.register_functions(root_module) + + try: + import ns3_module_mpi__local + except ImportError: + pass + else: + ns3_module_mpi__local.register_functions(root_module) + + root_module.end_section('ns3_module_mpi') root_module.begin_section('ns3_module_contrib') ns3_module_contrib.register_functions(root_module) diff --git a/doc/manual/Makefile b/doc/manual/Makefile index 1aa12c6a2..6d701aae2 100644 --- a/doc/manual/Makefile +++ b/doc/manual/Makefile @@ -58,6 +58,7 @@ CHAPTERS = \ python.texi \ random.texi \ realtime.texi \ + distributed.texi \ routing.texi \ simple.texi \ sockets.texi \ diff --git a/doc/manual/distributed.texi b/doc/manual/distributed.texi new file mode 100644 index 000000000..77ca10ccf --- /dev/null +++ b/doc/manual/distributed.texi @@ -0,0 +1,225 @@ +@node Distributed +@chapter Distributed Simulation with MPI +@anchor{chap:Distributed} + +@menu +* Current Implementation Details:: +* Running Distributed Simulations:: +* Tracing During Distributed Simulations:: +@end menu + +Parallel and distributed discrete event simulation allows the execution of a +single simulation program on multiple processors. By splitting up the +simulation into logical processes, LPs, each LP can be executed by a different +processor. This simulation methodology enables very large-scale simulations by +leveraging increased processing power and memory availability. In order to +ensure proper execution of a distributed simulation, message passing between +LPs is required. To support distributed simulation in ns-3, the standard +Message Passing Interface (MPI) is used, along with a new distributed simulator +class. Currently, dividing a simulation for distributed purposes in ns-3 can +only occur across point-to-point links. + +@node Current Implementation Details +@section Current Implementation Details +During the course of a distributed simulation, many packets must cross +simulator boundaries. In other words, a packet that originated on one LP +is destined for a different LP, and in order to make this transition, a message +containing the packet contents must be sent to the remote LP. Upon receiving +this message, the remote LP can rebuild the packet and proceed as normal. The +process of sending an receiving messages between LPs is handled easily by the +new MPI interface in ns-3. + +Along with simple message passing between LPs, a distributed simulator is used +on each LP to determine which events to process. It is important to process +events in time-stamped order to ensure proper simulation execution. If a +LP receives a message containing an event from the past, clearly this is an +issue, since this event could change other events which have already been +executed. To address this problem, a conservative synchronization algorithm with +lookahead is used in ns-3. For more information on different synchronization +approaches and parallel and distributed simulation in general, please refer to +"Parallel and Distributed Simulation Systems" by Richard Fujimoto. + +@subsection Remote point-to-point links +As described in the introduction, dividing a simulation for distributed purposes +in ns-3 currently can only occur across point-to-point links; therefore, the idea +of remote point-to-point links is very important for distributed simulation in ns-3. +When a point-to-point link is installed, connecting two nodes, the point-to-point +helper checks the system id, or rank, of both nodes. The rank should be assigned +during node creation for distributed simulation and is intended to signify on which +LP a node belongs. If the two nodes are on the same rank, a regular point-to-point +link is created. If, however, the two nodes are on different ranks, then these nodes +are intended for different LPs, and a remote point-to-point link is used. If a packet +is to be sent across a remote point-to-point link, MPI is used to send the message to +the remote LP. + +@subsection Distributing the topology +Currently, the full topology is created on each rank, regardless of the individual node +system ids. Only the applications are specific to a rank. For example, consider +node 1 on LP 1 and node 2 on LP 2, with a traffic generator on node 1. Both node +1 and node 2 will be created on both LP1 and LP2; however, the traffic generator +will only be installed on LP1. While this is not optimal for memory efficiency, it +does simplify routing, since all current routing implementations in ns-3 will work +with distributed simulation. + +@node Running Distributed Simulations +@section Running Distributed Simulations + +@subsection Prerequisites +Ensure that MPI is installed, as well as mpic++. In Ubuntu repositories, +these are openmpi-bin, openmpi-common, openmpi-doc, libopenmpi-dev. In +Fedora, these are openmpi and openmpi-devel. + +Note: +There is a conflict on some Fedora systems between libotf and openmpi. A +possible "quick-fix" is to yum remove libotf before installing openmpi. +This will remove conflict, but it will also remove emacs. Alternatively, +these steps could be followed to resolve the conflict: + +@verbatim +1) Rename the tiny otfdump which emacs says it needs: + + mv /usr/bin/otfdump /usr/bin/otfdump.emacs-version + +2) Manually resolve openmpi dependencies: + + sudo yum install libgfortran libtorque numactl + +3) Download rpm packages: + + openmpi-1.3.1-1.fc11.i586.rpm + openmpi-devel-1.3.1-1.fc11.i586.rpm + openmpi-libs-1.3.1-1.fc11.i586.rpm + openmpi-vt-1.3.1-1.fc11.i586.rpm + + from + + http://mirrors.kernel.org/fedora/releases/11/Everything/i386/os/Packages/ + +4) Force the packages in: + + sudo rpm -ivh --force openmpi-1.3.1-1.fc11.i586.rpm + openmpi-libs-1.3.1-1.fc11.i586.rpm openmpi-devel-1.3.1-1.fc11.i586.rpm + openmpi-vt-1.3.1-1.fc11.i586.rpm + +@end verbatim + +Also, it may be necessary to add the openmpi bin directory to PATH in order to +execute mpic++ and mpirun from the command line. Alternatively, the full path +to these executables can be used. Finally, if openmpi complains about the +inablility to open shared libraries, such as libmpi_cxx.so.0, it may be +necessary to add the openmpi lib directory to LD_LIBRARY_PATH. + +@subsection Building and Running Examples +If you already built ns-3 without MPI enabled, you must re-build: +@verbatim +./waf distclean +@end verbatim + +Configure ns-3 with the --enable-mpi option: +@verbatim +./waf -d debug configure --enable-mpi +@end verbatim + +Ensure that MPI is enabled by checking the optional features shown from the +output of configure. + +Next, build ns-3: +@verbatim +./waf +@end verbatim + +After building ns-3 with mpi enabled, the example programs are now ready to +run with mpirun. Here are a few examples (from the root ns-3 directory): + +@verbatim +mpirun -np 2 ./waf --run simple-distributed +mpirun -np 4 -machinefile mpihosts ./waf --run 'nms-udp-nix --LAN=2 --CN=4 --nix=1 --tracing=0' +@end verbatim + +The np switch is the number of logical processors to use. The +machinefile switch is which machines to use. In order to use machinefile, +the target file must exist (in this case mpihosts). This can simply contain +something like: + +@verbatim +localhost +localhost +localhost +... +@endverbatim + +Or if you have a cluster of machines, you can name them. + +** NOTE: Some users have experienced issues using mpirun and waf together. +An alternative way to run distributed examples is shown below: + +@verbatim +./waf shell +cd build/debug +mpirun -np 2 examples/mpi/simple-distributed +@end verbatim + +@subsection Creating custom topologies +The example programs in examples/mpi give a good idea of how to create +different topologies for distributed simulation. The main points are +assigning system ids to individual nodes, creating point-to-point +links where the simulation should be divided, and installing +applications only on the LP associated with the target node. + +Assigning system ids to nodes is simple and can be handled two different +ways. First, a NodeContainer can be used to create the nodes and assign +system ids: + +@verbatim +NodeContainer nodes; +nodes.Create (5, 1); // Creates 5 nodes with system id 1. +@end verbatim + +Alternatively, nodes can be created individually, assigned system ids, and +added to a NodeContainer. This is useful if a NodeContainer holds nodes with +different system ids: + +@verbatim +NodeContainer nodes; +Ptr node1 = CreateObject (0); // Create node1 with system id 0 +Ptr node2 = CreateObject (1); // Create node2 with system id 1 +nodes.Add (node1); +nodes.Add (node2); +@end verbatim + +Next, where the simulation is divided is determined by the placement of +point-to-point links. If a point-to-point link is created between two +nodes with different system ids, a remote point-to-point link is created, +as described in @ref{Current Implementation Details}. + +Finally, installing applications only on the LP associated with the target +node is very important. For example, if a traffic generator is to be placed +on node 0, which is on LP0, only LP0 should install this application. +This is easily accomplished by first checking the simulator system id, and +ensuring that it matches the system id of the target node before installing +the application. + +@node Tracing During Distributed Simulations +@section Tracing During Distributed Simulations +Depending on the system id (rank) of the simulator, the information traced +will be different, since traffic originating on one simulator is not seen +by another simulator until it reaches nodes specific to that simulator. The +easiest way to keep track of different traces is to just name the trace files +or pcaps differently, based on the system id of the simulator. For example, +something like this should work well, assuming all of these local variables +were previously defined: + +@verbatim +if (MpiInterface::GetSystemId () == 0) + { + pointToPoint.EnablePcapAll ("distributed-rank0"); + phy.EnablePcap ("distributed-rank0", apDevices.Get (0)); + csma.EnablePcap ("distributed-rank0", csmaDevices.Get (0), true); + } +else if (MpiInterface::GetSystemId () == 1) + { + pointToPoint.EnablePcapAll ("distributed-rank1"); + phy.EnablePcap ("distributed-rank1", apDevices.Get (0)); + csma.EnablePcap ("distributed-rank1", csmaDevices.Get (0), true); + } +@end verbatim diff --git a/doc/manual/manual.texi b/doc/manual/manual.texi index 3edd848d5..ed278bd75 100644 --- a/doc/manual/manual.texi +++ b/doc/manual/manual.texi @@ -96,6 +96,7 @@ Simulator version: * Logging:: * Tracing:: * RealTime:: +* Distributed:: * Packets:: * Helpers:: * Python:: @@ -140,6 +141,7 @@ Simulator version: @include log.texi @include tracing.texi @include realtime.texi +@include distributed.texi @include packets.texi @include helpers.texi @include python.texi diff --git a/examples/mpi/nms-udp-nix.cc b/examples/mpi/nms-udp-nix.cc new file mode 100644 index 000000000..2b78cea9c --- /dev/null +++ b/examples/mpi/nms-udp-nix.cc @@ -0,0 +1,614 @@ +/* -*- 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 + * + * (c) 2009, GTech Systems, Inc. - Alfred Park + * + * DARPA NMS Campus Network Model + * + * This topology replicates the original NMS Campus Network model + * with the exception of chord links (which were never utilized in the + * original model) + * Link Bandwidths and Delays may not be the same as the original + * specifications + * + * Modified for distributed simulation by Josh Pelkey + * + * The fundamental unit of the NMS model consists of a campus network. The + * campus network topology can been seen here: + * http://www.nsnam.org/~jpelkey3/nms.png + * The number of hosts (default 42) is variable. Finally, an arbitrary + * number of these campus networks can be connected together (default 2) + * to make very large simulations. + */ + +// for timing functions +#include +#include +#include + +#include "ns3/core-module.h" +#include "ns3/simulator-module.h" +#include "ns3/node-module.h" +#include "ns3/helper-module.h" +#include "ns3/global-routing-module.h" +#include "ns3/onoff-application.h" +#include "ns3/packet-sink.h" +#include "ns3/point-to-point-net-device.h" +#include "ns3/mpi-interface.h" + +#ifdef NS3_MPI +#include +#endif + +using namespace std; +using namespace ns3; + +typedef struct timeval TIMER_TYPE; +#define TIMER_NOW(_t) gettimeofday (&_t,NULL); +#define TIMER_SECONDS(_t) ((double)(_t).tv_sec + (_t).tv_usec * 1e-6) +#define TIMER_DIFF(_t1, _t2) (TIMER_SECONDS (_t1) - TIMER_SECONDS (_t2)) + +NS_LOG_COMPONENT_DEFINE ("CampusNetworkModel"); + +int +main (int argc, char *argv[]) +{ +#ifdef NS3_MPI + // Enable MPI with the command line arguments + MpiInterface::Enable (&argc, &argv); + + TIMER_TYPE t0, t1, t2; + TIMER_NOW (t0); + cout << " ==== DARPA NMS CAMPUS NETWORK SIMULATION ====" << endl; + + GlobalValue::Bind ("SimulatorImplementationType", + StringValue ("ns3::DistributedSimulatorImpl")); + + uint32_t systemId = MpiInterface::GetSystemId (); + uint32_t systemCount = MpiInterface::GetSize (); + + uint32_t nCN = 2, nLANClients = 42; + int32_t single = 0; + int nBytes = 500000; // Bytes for each on/off app + bool nix = true; + + CommandLine cmd; + cmd.AddValue ("CN", "Number of total CNs [2]", nCN); + cmd.AddValue ("LAN", "Number of nodes per LAN [42]", nLANClients); + cmd.AddValue ("single", "1 if use single flow", single); + cmd.AddValue ("nBytes", "Number of bytes for each on/off app", nBytes); + cmd.AddValue ("nix", "Toggle the use of nix-vector or global routing", nix); + cmd.Parse (argc,argv); + + if (nCN < 2) + { + cout << "Number of total CNs (" << nCN << ") lower than minimum of 2" + << endl; + return 1; + } + if (systemCount > nCN) + { + cout << "Number of total CNs (" << nCN << ") should be >= systemCount (" + << systemCount << ")." << endl; + return 1; + } + + cout << "Number of CNs: " << nCN << ", LAN nodes: " << nLANClients << endl; + + NodeContainer nodes_net0[nCN][3], nodes_net1[nCN][6], nodes_netLR[nCN], + nodes_net2[nCN][14], nodes_net2LAN[nCN][7][nLANClients], + nodes_net3[nCN][9], nodes_net3LAN[nCN][5][nLANClients]; + PointToPointHelper p2p_2gb200ms, p2p_1gb5ms, p2p_100mb1ms; + InternetStackHelper stack; + Ipv4InterfaceContainer ifs, ifs0[nCN][3], ifs1[nCN][6], ifs2[nCN][14], + ifs3[nCN][9], ifs2LAN[nCN][7][nLANClients], + ifs3LAN[nCN][5][nLANClients]; + Ipv4AddressHelper address; + std::ostringstream oss; + p2p_1gb5ms.SetDeviceAttribute ("DataRate", StringValue ("1Gbps")); + p2p_1gb5ms.SetChannelAttribute ("Delay", StringValue ("5ms")); + p2p_2gb200ms.SetDeviceAttribute ("DataRate", StringValue ("2Gbps")); + p2p_2gb200ms.SetChannelAttribute ("Delay", StringValue ("200ms")); + p2p_100mb1ms.SetDeviceAttribute ("DataRate", StringValue ("100Mbps")); + p2p_100mb1ms.SetChannelAttribute ("Delay", StringValue ("1ms")); + + Ipv4NixVectorHelper nixRouting; + Ipv4StaticRoutingHelper staticRouting; + + Ipv4ListRoutingHelper list; + list.Add (staticRouting, 0); + list.Add (nixRouting, 10); + + if (nix) + { + stack.SetRoutingHelper (list); + } + + // Create Campus Networks + for (uint32_t z = 0; z < nCN; ++z) + { + cout << "Creating Campus Network " << z << ":" << endl; + // Create Net0 + cout << " SubNet [ 0"; + for (int i = 0; i < 3; ++i) + { + Ptr node = CreateObject (z % systemCount); + nodes_net0[z][i].Add (node); + stack.Install (nodes_net0[z][i]); + } + nodes_net0[z][0].Add (nodes_net0[z][1].Get (0)); + nodes_net0[z][1].Add (nodes_net0[z][2].Get (0)); + nodes_net0[z][2].Add (nodes_net0[z][0].Get (0)); + NetDeviceContainer ndc0[3]; + for (int i = 0; i < 3; ++i) + { + ndc0[i] = p2p_1gb5ms.Install (nodes_net0[z][i]); + } + // Create Net1 + cout << " 1"; + for (int i = 0; i < 6; ++i) + { + Ptr node = CreateObject (z % systemCount); + nodes_net1[z][i].Add (node); + stack.Install (nodes_net1[z][i]); + } + nodes_net1[z][0].Add (nodes_net1[z][1].Get (0)); + nodes_net1[z][2].Add (nodes_net1[z][0].Get (0)); + nodes_net1[z][3].Add (nodes_net1[z][0].Get (0)); + nodes_net1[z][4].Add (nodes_net1[z][1].Get (0)); + nodes_net1[z][5].Add (nodes_net1[z][1].Get (0)); + NetDeviceContainer ndc1[6]; + for (int i = 0; i < 6; ++i) + { + if (i == 1) + { + continue; + } + ndc1[i] = p2p_1gb5ms.Install (nodes_net1[z][i]); + } + // Connect Net0 <-> Net1 + NodeContainer net0_1; + net0_1.Add (nodes_net0[z][2].Get (0)); + net0_1.Add (nodes_net1[z][0].Get (0)); + NetDeviceContainer ndc0_1; + ndc0_1 = p2p_1gb5ms.Install (net0_1); + oss.str (""); + oss << 10 + z << ".1.252.0"; + address.SetBase (oss.str ().c_str (), "255.255.255.0"); + ifs = address.Assign (ndc0_1); + // Create Net2 + cout << " 2"; + for (int i = 0; i < 14; ++i) + { + Ptr node = CreateObject (z % systemCount); + nodes_net2[z][i].Add (node); + stack.Install (nodes_net2[z][i]); + } + nodes_net2[z][0].Add (nodes_net2[z][1].Get (0)); + nodes_net2[z][2].Add (nodes_net2[z][0].Get (0)); + nodes_net2[z][1].Add (nodes_net2[z][3].Get (0)); + nodes_net2[z][3].Add (nodes_net2[z][2].Get (0)); + nodes_net2[z][4].Add (nodes_net2[z][2].Get (0)); + nodes_net2[z][5].Add (nodes_net2[z][3].Get (0)); + nodes_net2[z][6].Add (nodes_net2[z][5].Get (0)); + nodes_net2[z][7].Add (nodes_net2[z][2].Get (0)); + nodes_net2[z][8].Add (nodes_net2[z][3].Get (0)); + nodes_net2[z][9].Add (nodes_net2[z][4].Get (0)); + nodes_net2[z][10].Add (nodes_net2[z][5].Get (0)); + nodes_net2[z][11].Add (nodes_net2[z][6].Get (0)); + nodes_net2[z][12].Add (nodes_net2[z][6].Get (0)); + nodes_net2[z][13].Add (nodes_net2[z][6].Get (0)); + NetDeviceContainer ndc2[14]; + for (int i = 0; i < 14; ++i) + { + ndc2[i] = p2p_1gb5ms.Install (nodes_net2[z][i]); + } + NetDeviceContainer ndc2LAN[7][nLANClients]; + for (int i = 0; i < 7; ++i) + { + oss.str (""); + oss << 10 + z << ".4." << 15 + i << ".0"; + address.SetBase (oss.str ().c_str (), "255.255.255.0"); + for (uint32_t j = 0; j < nLANClients; ++j) + { + Ptr node = CreateObject (z % systemCount); + nodes_net2LAN[z][i][j].Add (node); + stack.Install (nodes_net2LAN[z][i][j]); + nodes_net2LAN[z][i][j].Add (nodes_net2[z][i + 7].Get (0)); + ndc2LAN[i][j] = p2p_100mb1ms.Install (nodes_net2LAN[z][i][j]); + ifs2LAN[z][i][j] = address.Assign (ndc2LAN[i][j]); + } + } + // Create Net3 + cout << " 3 ]" << endl; + for (int i = 0; i < 9; ++i) + { + Ptr node = CreateObject (z % systemCount); + nodes_net3[z][i].Add (node); + stack.Install (nodes_net3[z][i]); + } + nodes_net3[z][0].Add (nodes_net3[z][1].Get (0)); + nodes_net3[z][1].Add (nodes_net3[z][2].Get (0)); + nodes_net3[z][2].Add (nodes_net3[z][3].Get (0)); + nodes_net3[z][3].Add (nodes_net3[z][1].Get (0)); + nodes_net3[z][4].Add (nodes_net3[z][0].Get (0)); + nodes_net3[z][5].Add (nodes_net3[z][0].Get (0)); + nodes_net3[z][6].Add (nodes_net3[z][2].Get (0)); + nodes_net3[z][7].Add (nodes_net3[z][3].Get (0)); + nodes_net3[z][8].Add (nodes_net3[z][3].Get (0)); + NetDeviceContainer ndc3[9]; + for (int i = 0; i < 9; ++i) + { + ndc3[i] = p2p_1gb5ms.Install (nodes_net3[z][i]); + } + NetDeviceContainer ndc3LAN[5][nLANClients]; + for (int i = 0; i < 5; ++i) + { + oss.str (""); + oss << 10 + z << ".5." << 10 + i << ".0"; + address.SetBase (oss.str ().c_str (), "255.255.255.255"); + for (uint32_t j = 0; j < nLANClients; ++j) + { + Ptr node = CreateObject (z % systemCount); + nodes_net3LAN[z][i][j].Add (node); + stack.Install (nodes_net3LAN[z][i][j]); + nodes_net3LAN[z][i][j].Add (nodes_net3[z][i + 4].Get (0)); + ndc3LAN[i][j] = p2p_100mb1ms.Install (nodes_net3LAN[z][i][j]); + ifs3LAN[z][i][j] = address.Assign (ndc3LAN[i][j]); + } + } + cout << " Connecting Subnets..." << endl; + // Create Lone Routers (Node 4 & 5) + Ptr node1 = CreateObject (z % systemCount); + Ptr node2 = CreateObject (z % systemCount); + nodes_netLR[z].Add (node1); + nodes_netLR[z].Add (node2); + stack.Install (nodes_netLR[z]); + NetDeviceContainer ndcLR; + ndcLR = p2p_1gb5ms.Install (nodes_netLR[z]); + // Connect Net2/Net3 through Lone Routers to Net0 + NodeContainer net0_4, net0_5, net2_4a, net2_4b, net3_5a, net3_5b; + net0_4.Add (nodes_netLR[z].Get (0)); + net0_4.Add (nodes_net0[z][0].Get (0)); + net0_5.Add (nodes_netLR[z].Get (1)); + net0_5.Add (nodes_net0[z][1].Get (0)); + net2_4a.Add (nodes_netLR[z].Get (0)); + net2_4a.Add (nodes_net2[z][0].Get (0)); + net2_4b.Add (nodes_netLR[z].Get (1)); + net2_4b.Add (nodes_net2[z][1].Get (0)); + net3_5a.Add (nodes_netLR[z].Get (1)); + net3_5a.Add (nodes_net3[z][0].Get (0)); + net3_5b.Add (nodes_netLR[z].Get (1)); + net3_5b.Add (nodes_net3[z][1].Get (0)); + NetDeviceContainer ndc0_4, ndc0_5, ndc2_4a, ndc2_4b, ndc3_5a, ndc3_5b; + ndc0_4 = p2p_1gb5ms.Install (net0_4); + oss.str (""); + oss << 10 + z << ".1.253.0"; + address.SetBase (oss.str ().c_str (), "255.255.255.0"); + ifs = address.Assign (ndc0_4); + ndc0_5 = p2p_1gb5ms.Install (net0_5); + oss.str (""); + oss << 10 + z << ".1.254.0"; + address.SetBase (oss.str ().c_str (), "255.255.255.0"); + ifs = address.Assign (ndc0_5); + ndc2_4a = p2p_1gb5ms.Install (net2_4a); + oss.str (""); + oss << 10 + z << ".4.253.0"; + address.SetBase (oss.str ().c_str (), "255.255.255.0"); + ifs = address.Assign (ndc2_4a); + ndc2_4b = p2p_1gb5ms.Install (net2_4b); + oss.str (""); + oss << 10 + z << ".4.254.0"; + address.SetBase (oss.str ().c_str (), "255.255.255.0"); + ifs = address.Assign (ndc2_4b); + ndc3_5a = p2p_1gb5ms.Install (net3_5a); + oss.str (""); + oss << 10 + z << ".5.253.0"; + address.SetBase (oss.str ().c_str (), "255.255.255.0"); + ifs = address.Assign (ndc3_5a); + ndc3_5b = p2p_1gb5ms.Install (net3_5b); + oss.str (""); + oss << 10 + z << ".5.254.0"; + address.SetBase (oss.str ().c_str (), "255.255.255.0"); + ifs = address.Assign (ndc3_5b); + // Assign IP addresses + cout << " Assigning IP addresses..." << endl; + for (int i = 0; i < 3; ++i) + { + oss.str (""); + oss << 10 + z << ".1." << 1 + i << ".0"; + address.SetBase (oss.str ().c_str (), "255.255.255.0"); + ifs0[z][i] = address.Assign (ndc0[i]); + } + for (int i = 0; i < 6; ++i) + { + if (i == 1) + { + continue; + } + oss.str (""); + oss << 10 + z << ".2." << 1 + i << ".0"; + address.SetBase (oss.str ().c_str (), "255.255.255.0"); + ifs1[z][i] = address.Assign (ndc1[i]); + } + oss.str (""); + oss << 10 + z << ".3.1.0"; + address.SetBase (oss.str ().c_str (), "255.255.255.0"); + ifs = address.Assign (ndcLR); + for (int i = 0; i < 14; ++i) + { + oss.str (""); + oss << 10 + z << ".4." << 1 + i << ".0"; + address.SetBase (oss.str ().c_str (), "255.255.255.0"); + ifs2[z][i] = address.Assign (ndc2[i]); + } + for (int i = 0; i < 9; ++i) + { + oss.str (""); + oss << 10 + z << ".5." << 1 + i << ".0"; + address.SetBase (oss.str ().c_str (), "255.255.255.0"); + ifs3[z][i] = address.Assign (ndc3[i]); + } + } + // Create Ring Links + if (nCN > 1) + { + cout << "Forming Ring Topology..." << endl; + NodeContainer nodes_ring[nCN]; + for (uint32_t z = 0; z < nCN - 1; ++z) + { + nodes_ring[z].Add (nodes_net0[z][0].Get (0)); + nodes_ring[z].Add (nodes_net0[z + 1][0].Get (0)); + } + nodes_ring[nCN - 1].Add (nodes_net0[nCN - 1][0].Get (0)); + nodes_ring[nCN - 1].Add (nodes_net0[0][0].Get (0)); + NetDeviceContainer ndc_ring[nCN]; + for (uint32_t z = 0; z < nCN; ++z) + { + ndc_ring[z] = p2p_2gb200ms.Install (nodes_ring[z]); + oss.str (""); + oss << "254.1." << z + 1 << ".0"; + address.SetBase (oss.str ().c_str (), "255.255.255.0"); + ifs = address.Assign (ndc_ring[z]); + } + } + + // Create Traffic Flows + cout << "Creating UDP Traffic Flows:" << endl; + Config::SetDefault ("ns3::OnOffApplication::MaxBytes", + UintegerValue (nBytes)); + Config::SetDefault ("ns3::OnOffApplication::OnTime", + RandomVariableValue (ConstantVariable (1))); + Config::SetDefault ("ns3::OnOffApplication::OffTime", + RandomVariableValue (ConstantVariable (0))); + + + if (single) + { + if (systemCount == 1) + { + PacketSinkHelper sinkHelper ("ns3::UdpSocketFactory", + InetSocketAddress (Ipv4Address::GetAny (), + 9999)); + ApplicationContainer sinkApp = sinkHelper.Install (nodes_net1[0][2].Get (0)); + sinkApp.Start (Seconds (0.0)); + + OnOffHelper client ("ns3::UdpSocketFactory", Address ()); + AddressValue remoteAddress (InetSocketAddress (ifs1[0][2].GetAddress (0), 9999)); + cout << "Remote Address is " << ifs1[0][2].GetAddress (0) << endl; + client.SetAttribute ("Remote", remoteAddress); + + ApplicationContainer clientApp; + clientApp.Add (client.Install (nodes_net2LAN[0][0][0].Get (0))); + clientApp.Start (Seconds (0)); + } + else if (systemId == 1) + { + PacketSinkHelper sinkHelper ("ns3::UdpSocketFactory", + InetSocketAddress (Ipv4Address::GetAny (), + 9999)); + ApplicationContainer sinkApp = + sinkHelper.Install (nodes_net1[1][0].Get (0)); + + sinkApp.Start (Seconds (0.0)); + } + else if (systemId == 0) + { + OnOffHelper client ("ns3::UdpSocketFactory", Address ()); + AddressValue remoteAddress + (InetSocketAddress (ifs1[1][0].GetAddress (0), 9999)); + + cout << "Remote Address is " << ifs1[1][0].GetAddress (0) << endl; + client.SetAttribute ("Remote", remoteAddress); + + ApplicationContainer clientApp; + clientApp.Add (client.Install (nodes_net2LAN[0][0][0].Get (0))); + clientApp.Start (Seconds (0)); + } + } + else + { + UniformVariable urng; + int r1; + double r2; + for (uint32_t z = 0; z < nCN; ++z) + { + uint32_t x = z + 1; + if (z == nCN - 1) + { + x = 0; + } + // Subnet 2 LANs + cout << " Campus Network " << z << " Flows [ Net2 "; + for (int i = 0; i < 7; ++i) + { + for (uint32_t j = 0; j < nLANClients; ++j) + { + // Sinks + if (systemCount == 1) + { + PacketSinkHelper sinkHelper + ("ns3::UdpSocketFactory", + InetSocketAddress (Ipv4Address::GetAny (), 9999)); + + ApplicationContainer sinkApp = + sinkHelper.Install (nodes_net2LAN[z][i][j].Get (0)); + + sinkApp.Start (Seconds (100.0)); + } + else if (systemId == z % systemCount) + { + PacketSinkHelper sinkHelper + ("ns3::UdpSocketFactory", + InetSocketAddress (Ipv4Address::GetAny (), 9999)); + + ApplicationContainer sinkApp = + sinkHelper.Install (nodes_net2LAN[z][i][j].Get (0)); + + sinkApp.Start (Seconds (100.0)); + } + // Sources + if (systemCount == 1) + { + r1 = 2 + (int)(4 * urng.GetValue ()); + r2 = 100 + (10 * urng.GetValue ()); + OnOffHelper client ("ns3::UdpSocketFactory", Address ()); + + AddressValue remoteAddress + (InetSocketAddress (ifs2LAN[z][i][j].GetAddress (0), 9999)); + + client.SetAttribute ("Remote", remoteAddress); + ApplicationContainer clientApp; + clientApp.Add (client.Install (nodes_net1[x][r1].Get (0))); + clientApp.Start (Seconds (r2)); + } + else if (systemId == x % systemCount) + { + r1 = 2 + (int)(4 * urng.GetValue ()); + r2 = 100 + (10 * urng.GetValue ()); + OnOffHelper client ("ns3::UdpSocketFactory", Address ()); + + AddressValue remoteAddress + (InetSocketAddress (ifs2LAN[z][i][j].GetAddress (0), 9999)); + + client.SetAttribute ("Remote", remoteAddress); + ApplicationContainer clientApp; + clientApp.Add (client.Install (nodes_net1[x][r1].Get (0))); + clientApp.Start (Seconds (r2)); + } + } + } + // Subnet 3 LANs + cout << "Net3 ]" << endl; + for (int i = 0; i < 5; ++i) + { + for (uint32_t j = 0; j < nLANClients; ++j) + { + // Sinks + if (systemCount == 1) + { + PacketSinkHelper sinkHelper + ("ns3::UdpSocketFactory", + InetSocketAddress (Ipv4Address::GetAny (), 9999)); + + ApplicationContainer sinkApp = + sinkHelper.Install (nodes_net3LAN[z][i][j].Get (0)); + + sinkApp.Start (Seconds (100.0)); + } + else if (systemId == z % systemCount) + { + PacketSinkHelper sinkHelper + ("ns3::UdpSocketFactory", + InetSocketAddress (Ipv4Address::GetAny (), 9999)); + + ApplicationContainer sinkApp = + sinkHelper.Install (nodes_net3LAN[z][i][j].Get (0)); + + sinkApp.Start (Seconds (100.0)); + } + // Sources + if (systemCount == 1) + { + r1 = 2 + (int)(4 * urng.GetValue ()); + r2 = 100 + (10 * urng.GetValue ()); + OnOffHelper client ("ns3::UdpSocketFactory", Address ()); + + AddressValue remoteAddress + (InetSocketAddress (ifs2LAN[z][i][j].GetAddress (0), 9999)); + + client.SetAttribute ("Remote", remoteAddress); + ApplicationContainer clientApp; + clientApp.Add (client.Install (nodes_net1[x][r1].Get (0))); + clientApp.Start (Seconds (r2)); + } + else if (systemId == x % systemCount) + { + r1 = 2 + (int)(4 * urng.GetValue ()); + r2 = 100 + (10 * urng.GetValue ()); + OnOffHelper client ("ns3::UdpSocketFactory", Address ()); + + AddressValue remoteAddress + (InetSocketAddress (ifs2LAN[z][i][j].GetAddress (0), 9999)); + + client.SetAttribute ("Remote", remoteAddress); + ApplicationContainer clientApp; + clientApp.Add (client.Install (nodes_net1[x][r1].Get (0))); + clientApp.Start (Seconds (r2)); + } + } + } + } + } + + cout << "Created " << NodeList::GetNNodes () << " nodes." << endl; + TIMER_TYPE routingStart; + TIMER_NOW (routingStart); + + if (nix) + { + cout << "Using Nix-vectors..." << endl; + } + else + { + // Calculate routing tables + cout << "Populating Routing tables..." << endl; + Ipv4GlobalRoutingHelper::PopulateRoutingTables (); + } + + TIMER_TYPE routingEnd; + TIMER_NOW (routingEnd); + cout << "Routing tables population took " + << TIMER_DIFF (routingEnd, routingStart) << endl; + + cout << "Running simulator..." << endl; + TIMER_NOW (t1); + Simulator::Stop (Seconds (200.0)); + Simulator::Run (); + TIMER_NOW (t2); + cout << "Simulator finished." << endl; + Simulator::Destroy (); + + double d1 = TIMER_DIFF (t1, t0), d2 = TIMER_DIFF (t2, t1); + cout << "-----" << endl << "Runtime Stats:" << endl; + cout << "Simulator init time: " << d1 << endl; + cout << "Simulator run time: " << d2 << endl; + cout << "Total elapsed time: " << d1 + d2 << endl; + return 0; +#else + NS_FATAL_ERROR ("Can't use distributed simulator without MPI compiled in"); +#endif +} + diff --git a/examples/mpi/simple-distributed.cc b/examples/mpi/simple-distributed.cc new file mode 100644 index 000000000..6c7d56ee3 --- /dev/null +++ b/examples/mpi/simple-distributed.cc @@ -0,0 +1,245 @@ +/* -*- 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 + * + * + * TestDistributed creates a dumbbell topology and logically splits it in + * half. The left half is placed on logical processor 0 and the right half + * is placed on logical processor 1. + * + * ------- ------- + * RANK 0 RANK 1 + * ------- | ------- + * | + * n0 ---------| | |---------- n6 + * | | | + * n1 -------\ | | | /------- n7 + * n4 ----------|---------- n5 + * n2 -------/ | | | \------- n8 + * | | | + * n3 ---------| | |---------- n9 + * + * + * OnOff clients are placed on each left leaf node. Each right leaf node + * is a packet sink for a left leaf node. As a packet travels from one + * logical processor to another (the link between n4 and n5), MPI messages + * are passed containing the serialized packet. The message is then + * deserialized into a new packet and sent on as normal. + * + * One packet is sent from each left leaf node. The packet sinks on the + * right leaf nodes output logging information when they receive the packet. + */ + +#include "ns3/core-module.h" +#include "ns3/simulator-module.h" +#include "ns3/node-module.h" +#include "ns3/helper-module.h" +#include "ns3/mpi-interface.h" + +#ifdef NS3_MPI +#include +#endif + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("SimpleDistributed"); + +int +main (int argc, char *argv[]) +{ +#ifdef NS3_MPI + // Distributed simulation setup + MpiInterface::Enable (&argc, &argv); + GlobalValue::Bind ("SimulatorImplementationType", + StringValue ("ns3::DistributedSimulatorImpl")); + + LogComponentEnable ("PacketSink", LOG_LEVEL_INFO); + + uint32_t systemId = MpiInterface::GetSystemId (); + uint32_t systemCount = MpiInterface::GetSize (); + + // Check for valid distributed parameters. + // Must have 2 and only 2 Logical Processors (LPs) + if (systemCount != 2) + { + std::cout << "This simulation requires 2 and only 2 logical processors." << std::endl; + return 1; + } + + // Some default values + Config::SetDefault ("ns3::OnOffApplication::PacketSize", UintegerValue (512)); + Config::SetDefault ("ns3::OnOffApplication::DataRate", StringValue ("1Mbps")); + Config::SetDefault ("ns3::OnOffApplication::MaxBytes", UintegerValue (512)); + bool nix = true; + + // Parse command line + CommandLine cmd; + cmd.AddValue ("nix", "Enable the use of nix-vector or global routing", nix); + cmd.Parse (argc, argv); + + // Create leaf nodes on left with system id 0 + NodeContainer leftLeafNodes; + leftLeafNodes.Create (4, 0); + + // Create router nodes. Left router + // with system id 0, right router with + // system id 1 + NodeContainer routerNodes; + Ptr routerNode1 = CreateObject (0); + Ptr routerNode2 = CreateObject (1); + routerNodes.Add (routerNode1); + routerNodes.Add (routerNode2); + + // Create leaf nodes on left with system id 1 + NodeContainer rightLeafNodes; + rightLeafNodes.Create (4, 1); + + PointToPointHelper routerLink; + routerLink.SetDeviceAttribute ("DataRate", StringValue ("5Mbps")); + routerLink.SetChannelAttribute ("Delay", StringValue ("5ms")); + + PointToPointHelper leafLink; + leafLink.SetDeviceAttribute ("DataRate", StringValue ("1Mbps")); + leafLink.SetChannelAttribute ("Delay", StringValue ("2ms")); + + // Add link connecting routers + NetDeviceContainer routerDevices; + routerDevices = routerLink.Install (routerNodes); + + // Add links for left side leaf nodes to left router + NetDeviceContainer leftRouterDevices; + NetDeviceContainer leftLeafDevices; + for (uint32_t i = 0; i < 4; ++i) + { + NetDeviceContainer temp = leafLink.Install (leftLeafNodes.Get (i), routerNodes.Get (0)); + leftLeafDevices.Add (temp.Get (0)); + leftRouterDevices.Add (temp.Get (1)); + } + + // Add links for right side leaf nodes to right router + NetDeviceContainer rightRouterDevices; + NetDeviceContainer rightLeafDevices; + for (uint32_t i = 0; i < 4; ++i) + { + NetDeviceContainer temp = leafLink.Install (rightLeafNodes.Get (i), routerNodes.Get (1)); + rightLeafDevices.Add (temp.Get (0)); + rightRouterDevices.Add (temp.Get (1)); + } + + InternetStackHelper stack; + Ipv4NixVectorHelper nixRouting; + Ipv4StaticRoutingHelper staticRouting; + + Ipv4ListRoutingHelper list; + list.Add (staticRouting, 0); + list.Add (nixRouting, 10); + + if (nix) + { + stack.SetRoutingHelper (list); + } + + stack.InstallAll (); + + Ipv4InterfaceContainer routerInterfaces; + Ipv4InterfaceContainer leftLeafInterfaces; + Ipv4InterfaceContainer leftRouterInterfaces; + Ipv4InterfaceContainer rightLeafInterfaces; + Ipv4InterfaceContainer rightRouterInterfaces; + + Ipv4AddressHelper leftAddress; + leftAddress.SetBase ("10.1.1.0", "255.255.255.0"); + + Ipv4AddressHelper routerAddress; + routerAddress.SetBase ("10.2.1.0", "255.255.255.0"); + + Ipv4AddressHelper rightAddress; + rightAddress.SetBase ("10.3.1.0", "255.255.255.0"); + + // Router-to-Router interfaces + routerInterfaces = routerAddress.Assign (routerDevices); + + // Left interfaces + for (uint32_t i = 0; i < 4; ++i) + { + NetDeviceContainer ndc; + ndc.Add (leftLeafDevices.Get (i)); + ndc.Add (leftRouterDevices.Get (i)); + Ipv4InterfaceContainer ifc = leftAddress.Assign (ndc); + leftLeafInterfaces.Add (ifc.Get (0)); + leftRouterInterfaces.Add (ifc.Get (1)); + leftAddress.NewNetwork (); + } + + // Right interfaces + for (uint32_t i = 0; i < 4; ++i) + { + NetDeviceContainer ndc; + ndc.Add (rightLeafDevices.Get (i)); + ndc.Add (rightRouterDevices.Get (i)); + Ipv4InterfaceContainer ifc = rightAddress.Assign (ndc); + rightLeafInterfaces.Add (ifc.Get (0)); + rightRouterInterfaces.Add (ifc.Get (1)); + rightAddress.NewNetwork (); + } + + if (!nix) + { + Ipv4GlobalRoutingHelper::PopulateRoutingTables (); + } + + // Create a packet sink on the right leafs to receive packets from left leafs + uint16_t port = 50000; + if (systemId == 1) + { + Address sinkLocalAddress (InetSocketAddress (Ipv4Address::GetAny (), port)); + PacketSinkHelper sinkHelper ("ns3::UdpSocketFactory", sinkLocalAddress); + ApplicationContainer sinkApp; + for (uint32_t i = 0; i < 4; ++i) + { + sinkApp.Add (sinkHelper.Install (rightLeafNodes.Get (i))); + } + sinkApp.Start (Seconds (1.0)); + sinkApp.Stop (Seconds (5)); + } + + // Create the OnOff applications to send + if (systemId == 0) + { + OnOffHelper clientHelper ("ns3::UdpSocketFactory", Address ()); + clientHelper.SetAttribute + ("OnTime", RandomVariableValue (ConstantVariable (1))); + clientHelper.SetAttribute + ("OffTime", RandomVariableValue (ConstantVariable (0))); + + ApplicationContainer clientApps; + for (uint32_t i = 0; i < 4; ++i) + { + AddressValue remoteAddress + (InetSocketAddress (rightLeafInterfaces.GetAddress (i), port)); + clientHelper.SetAttribute ("Remote", remoteAddress); + clientApps.Add (clientHelper.Install (leftLeafNodes.Get (i))); + } + clientApps.Start (Seconds (1.0)); + clientApps.Stop (Seconds (5)); + } + + Simulator::Stop (Seconds (5)); + Simulator::Run (); + Simulator::Destroy (); + return 0; +#else + NS_FATAL_ERROR ("Can't use distributed simulator without MPI compiled in"); +#endif +} diff --git a/examples/mpi/third-distributed.cc b/examples/mpi/third-distributed.cc new file mode 100644 index 000000000..1d14bf1b9 --- /dev/null +++ b/examples/mpi/third-distributed.cc @@ -0,0 +1,244 @@ +/* -*- 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 + */ + +#include "ns3/core-module.h" +#include "ns3/simulator-module.h" +#include "ns3/node-module.h" +#include "ns3/helper-module.h" +#include "ns3/wifi-module.h" +#include "ns3/mobility-module.h" +#include "ns3/mpi-interface.h" + +#ifdef NS3_MPI +#include +#endif + +// Default Network Topology (same as third.cc from tutorial) +// Distributed simulation, split along the p2p link +// Number of wifi or csma nodes can be increased up to 250 +// +// Wifi 10.1.3.0 +// AP +// * * * * +// | | | | 10.1.1.0 +// n5 n6 n7 n0 -------------- n1 n2 n3 n4 +// point-to-point | | | | +// ================ +// | LAN 10.1.2.0 +// | +// Rank 0 | Rank 1 +// -------------------------|---------------------------- + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("ThirdExampleDistributed"); + +int +main (int argc, char *argv[]) +{ +#ifdef NS3_MPI + // Distributed simulation setup + MpiInterface::Enable (&argc, &argv); + GlobalValue::Bind ("SimulatorImplementationType", + StringValue ("ns3::DistributedSimulatorImpl")); + + uint32_t systemId = MpiInterface::GetSystemId (); + uint32_t systemCount = MpiInterface::GetSize (); + + // Check for valid distributed parameters. + // Must have 2 and only 2 Logical Processors (LPs) + if (systemCount != 2) + { + std::cout << "This simulation requires 2 and only 2 logical processors." << std::endl; + return 1; + } + + bool verbose = true; + uint32_t nCsma = 3; + uint32_t nWifi = 3; + bool tracing = false; + + CommandLine cmd; + cmd.AddValue ("nCsma", "Number of \"extra\" CSMA nodes/devices", nCsma); + cmd.AddValue ("nWifi", "Number of wifi STA devices", nWifi); + cmd.AddValue ("verbose", "Tell echo applications to log if true", verbose); + cmd.AddValue ("tracing", "Enable pcap tracing", tracing); + cmd.Parse (argc,argv); + + // Check for valid number of csma or wifi nodes + // 250 should be enough, otherwise IP addresses + // soon become an issue + if (nWifi > 250 || nCsma > 250) + { + std::cout << "Too many wifi or csma nodes, max 200 each." << std::endl; + return 1; + } + + if (verbose) + { + LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO); + LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO); + } + + NodeContainer p2pNodes; + Ptr p2pNode1 = CreateObject (0); // Create node with rank 0 + Ptr p2pNode2 = CreateObject (1); // Create node with rank 1 + p2pNodes.Add (p2pNode1); + p2pNodes.Add (p2pNode2); + + PointToPointHelper pointToPoint; + pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps")); + pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms")); + + NetDeviceContainer p2pDevices; + p2pDevices = pointToPoint.Install (p2pNodes); + + NodeContainer csmaNodes; + csmaNodes.Add (p2pNodes.Get (1)); + csmaNodes.Create (nCsma , 1); // Create csma nodes with rank 1 + + CsmaHelper csma; + csma.SetChannelAttribute ("DataRate", StringValue ("100Mbps")); + csma.SetChannelAttribute ("Delay", TimeValue (NanoSeconds (6560))); + + NetDeviceContainer csmaDevices; + csmaDevices = csma.Install (csmaNodes); + + NodeContainer wifiStaNodes; + wifiStaNodes.Create (nWifi, 0); // Create wifi nodes with rank 0 + NodeContainer wifiApNode = p2pNodes.Get (0); + + YansWifiChannelHelper channel = YansWifiChannelHelper::Default (); + YansWifiPhyHelper phy = YansWifiPhyHelper::Default (); + phy.SetChannel (channel.Create ()); + + WifiHelper wifi = WifiHelper::Default (); + wifi.SetRemoteStationManager ("ns3::AarfWifiManager"); + + NqosWifiMacHelper mac = NqosWifiMacHelper::Default (); + + Ssid ssid = Ssid ("ns-3-ssid"); + mac.SetType ("ns3::NqstaWifiMac", + "Ssid", SsidValue (ssid), + "ActiveProbing", BooleanValue (false)); + + NetDeviceContainer staDevices; + staDevices = wifi.Install (phy, mac, wifiStaNodes); + + mac.SetType ("ns3::NqapWifiMac", + "Ssid", SsidValue (ssid), + "BeaconGeneration", BooleanValue (true), + "BeaconInterval", TimeValue (Seconds (2.5))); + + NetDeviceContainer apDevices; + apDevices = wifi.Install (phy, mac, wifiApNode); + + MobilityHelper mobility; + + mobility.SetPositionAllocator ("ns3::GridPositionAllocator", + "MinX", DoubleValue (0.0), + "MinY", DoubleValue (0.0), + "DeltaX", DoubleValue (5.0), + "DeltaY", DoubleValue (5.0), + "GridWidth", UintegerValue (10), + "LayoutType", StringValue ("RowFirst")); + + mobility.SetMobilityModel ("ns3::RandomWalk2dMobilityModel", + "Bounds", RectangleValue (Rectangle (-250, 250, -250, 250))); + mobility.Install (wifiStaNodes); + + mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel"); + mobility.Install (wifiApNode); + + InternetStackHelper stack; + stack.Install (csmaNodes); + stack.Install (wifiApNode); + stack.Install (wifiStaNodes); + + Ipv4AddressHelper address; + + address.SetBase ("10.1.1.0", "255.255.255.0"); + Ipv4InterfaceContainer p2pInterfaces; + p2pInterfaces = address.Assign (p2pDevices); + + address.SetBase ("10.1.2.0", "255.255.255.0"); + Ipv4InterfaceContainer csmaInterfaces; + csmaInterfaces = address.Assign (csmaDevices); + + address.SetBase ("10.1.3.0", "255.255.255.0"); + address.Assign (staDevices); + address.Assign (apDevices); + + // If this simulator has system id 1, then + // it should contain the server application, + // since it is on one of the csma nodes + if (systemId == 1) + { + UdpEchoServerHelper echoServer (9); + ApplicationContainer serverApps = echoServer.Install (csmaNodes.Get (nCsma)); + serverApps.Start (Seconds (1.0)); + serverApps.Stop (Seconds (10.0)); + } + + // If the simulator has sytem id 0, then + // it should contain the client application, + // since it is on one of the wifi nodes + if (systemId == 0) + { + UdpEchoClientHelper echoClient (csmaInterfaces.GetAddress (nCsma), 9); + echoClient.SetAttribute ("MaxPackets", UintegerValue (1)); + echoClient.SetAttribute ("Interval", TimeValue (Seconds (1.))); + echoClient.SetAttribute ("PacketSize", UintegerValue (1024)); + + ApplicationContainer clientApps = + echoClient.Install (wifiStaNodes.Get (nWifi - 1)); + clientApps.Start (Seconds (2.0)); + clientApps.Stop (Seconds (10.0)); + } + + Ipv4GlobalRoutingHelper::PopulateRoutingTables (); + + Simulator::Stop (Seconds (10.0)); + + if (tracing == true) + { + // Depending on the system Id (rank), the pcap information + // traced will be different. For example, the ethernet pcap + // will be empty for rank0, since these nodes are placed on + // on rank 1. All ethernet traffic will take place on rank 1. + // Similar differences are seen in the p2p and wirless pcaps. + if (systemId == 0) + { + pointToPoint.EnablePcapAll ("third-distributed-rank0"); + phy.EnablePcap ("third-distributed-rank0", apDevices.Get (0)); + csma.EnablePcap ("third-distributed-rank0", csmaDevices.Get (0), true); + } + else + { + pointToPoint.EnablePcapAll ("third-distributed-rank1"); + phy.EnablePcap ("third-distributed-rank1", apDevices.Get (0)); + csma.EnablePcap ("third-distributed-rank1", csmaDevices.Get (0), true); + } + } + + Simulator::Run (); + Simulator::Destroy (); + return 0; + +#else + NS_FATAL_ERROR ("Can't use distributed simulator without MPI compiled in"); +#endif +} diff --git a/examples/mpi/waf b/examples/mpi/waf new file mode 100755 index 000000000..941d56b43 --- /dev/null +++ b/examples/mpi/waf @@ -0,0 +1 @@ +exec "`dirname "$0"`"/../../waf "$@" diff --git a/examples/mpi/wscript b/examples/mpi/wscript new file mode 100644 index 000000000..6eadc0f4f --- /dev/null +++ b/examples/mpi/wscript @@ -0,0 +1,14 @@ +## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- + +def build(bld): + obj = bld.create_ns3_program('simple-distributed', + ['point-to-point', 'internet-stack']) + obj.source = 'simple-distributed.cc' + + obj = bld.create_ns3_program('third-distributed', + ['point-to-point', 'internet-stack']) + obj.source = 'third-distributed.cc' + + obj = bld.create_ns3_program('nms-udp-nix', + ['point-to-point', 'internet-stack']) + obj.source = 'nms-udp-nix.cc' diff --git a/src/common/buffer.cc b/src/common/buffer.cc index cc1f107d3..41999c7db 100644 --- a/src/common/buffer.cc +++ b/src/common/buffer.cc @@ -268,6 +268,15 @@ Buffer::Buffer (uint32_t dataSize) Initialize (dataSize); } +Buffer::Buffer (uint32_t dataSize, bool initialize) +{ + NS_LOG_FUNCTION (this << dataSize << initialize); + if (initialize == true) + { + Initialize (dataSize); + } +} + bool Buffer::CheckInternalState (void) const { @@ -667,6 +676,139 @@ Buffer::CreateFullCopy (void) const return *this; } +uint32_t +Buffer::GetSerializedSize (void) const +{ + uint32_t dataStart = (m_zeroAreaStart - m_start + 3) & (~0x3); + uint32_t dataEnd = (m_end - m_zeroAreaEnd + 3) & (~0x3); + + // total size 4-bytes for dataStart length + // + X number of bytes for dataStart + // + 4-bytes for dataEnd length + // + X number of bytes for dataEnd + uint32_t sz = sizeof (uint32_t) + + sizeof (uint32_t) + + dataStart + + sizeof (uint32_t) + + dataEnd; + + return sz; +} + +uint32_t +Buffer::Serialize (uint8_t* buffer, uint32_t maxSize) const +{ + uint32_t* p = (uint32_t*)buffer; + uint32_t size = 0; + + NS_LOG_FUNCTION (this); + + // Add the zero data length + if (size + 4 <= maxSize) + { + size += 4; + *p++ = m_zeroAreaEnd - m_zeroAreaStart; + } + else + { + return 0; + } + + // Add the length of actual start data + uint32_t dataStartLength = m_zeroAreaStart - m_start; + if (size + 4 <= maxSize) + { + size += 4; + *p++ = dataStartLength; + } + else + { + return 0; + } + + // Add the actual data + if (size + ((dataStartLength + 3) & (~3)) <= maxSize) + { + size += (dataStartLength + 3) & (~3); + memcpy(p, m_data->m_data + m_start, dataStartLength); + p += (((dataStartLength + 3) & (~3))/4); // Advance p, insuring 4 byte boundary + } + else + { + return 0; + } + + // Add the length of the actual end data + uint32_t dataEndLength = m_end - m_zeroAreaEnd; + if (size + 4 <= maxSize) + { + size += 4; + *p++ = dataEndLength; + } + else + { + return 0; + } + + // Add the actual data + if (size + ((dataEndLength + 3) & (~3)) <= maxSize) + { + size += (dataEndLength + 3) & (~3); + memcpy(p, m_data->m_data+m_zeroAreaStart,dataEndLength); + p += (((dataEndLength + 3) & (~3))/4); // Advance p, insuring 4 byte boundary + } + else + { + return 0; + } + + // Serialzed everything successfully + return 1; +} + +uint32_t +Buffer::Deserialize (uint8_t *buffer, uint32_t size) +{ + uint32_t* p = (uint32_t*)buffer; + uint32_t sizeCheck = size-4; + + NS_ASSERT (sizeCheck >= 4); + uint32_t zeroDataLength = *p++; + sizeCheck -= 4; + + // Create zero bytes + Initialize (zeroDataLength); + + // Add start data + NS_ASSERT (sizeCheck >= 4); + uint32_t dataStartLength = *p++; + sizeCheck -= 4; + AddAtStart (dataStartLength); + + NS_ASSERT (sizeCheck >= dataStartLength); + Begin ().Write ((uint8_t*)p, dataStartLength); + p += (((dataStartLength+3)&(~3))/4); + sizeCheck -= ((dataStartLength+3)&(~3)); + + // Add end data + NS_ASSERT (sizeCheck >= 4); + uint32_t dataEndLength = *p++; + sizeCheck -= 4; + AddAtEnd (dataEndLength); + + NS_ASSERT (sizeCheck >= dataEndLength); + Buffer::Iterator tmp = End (); + tmp.Prev (dataEndLength); + tmp.Write ((uint8_t*)p, dataEndLength); + p += (((dataEndLength+3)&(~3))/4); + sizeCheck -= ((dataEndLength+3)&(~3)); + + NS_ASSERT (sizeCheck == 0); + // return zero if buffer did not + // contain a complete message + return (sizeCheck != 0) ? 0 : 1; +} + int32_t Buffer::GetCurrentStartOffset (void) const { diff --git a/src/common/buffer.h b/src/common/buffer.h index 33d32b9d2..2ec401b9b 100644 --- a/src/common/buffer.h +++ b/src/common/buffer.h @@ -476,6 +476,33 @@ public: Buffer CreateFullCopy (void) const; + /** + * \return the number of bytes required for serialization + */ + uint32_t GetSerializedSize (void) const; + + /** + * \return zero if buffer not large enough + * \param buffer points to serialization buffer + * \param maxSize max number of bytes to write + * + * This buffer's contents are serialized into the raw + * character buffer parameter. Note: The zero length + * data is not copied entirely. Only the length of + * zero byte data is serialized. + */ + uint32_t Serialize (uint8_t* buffer, uint32_t maxSize) const; + + /** + * \return zero if a complete buffer is not deserialized + * \param buffer points to buffer for deserialization + * \param size number of bytes to deserialize + * + * The raw character buffer is deserialized and all the + * data is placed into this buffer. + */ + uint32_t Deserialize (uint8_t* buffer, uint32_t size); + int32_t GetCurrentStartOffset (void) const; int32_t GetCurrentEndOffset (void) const; @@ -493,6 +520,7 @@ public: Buffer &operator = (Buffer const &o); Buffer (); Buffer (uint32_t dataSize); + Buffer (uint32_t dataSize, bool initialize); ~Buffer (); private: diff --git a/src/common/nix-vector.cc b/src/common/nix-vector.cc index 9997901e1..70be5feac 100644 --- a/src/common/nix-vector.cc +++ b/src/common/nix-vector.cc @@ -222,74 +222,105 @@ NixVector::ExtractNeighborIndex (uint32_t numberOfBits) uint32_t NixVector::GetSerializedSize (void) const { - uint32_t totalSizeInBytes; + uint32_t totalSizeInBytes = 0; totalSizeInBytes = sizeof (m_used) + sizeof (m_currentVectorBitSize) + sizeof (m_totalBitSize) + (4 * m_nixVector.size ()); - // add four to this to account - // for the nix-vector length - // entry - return totalSizeInBytes+4; -} - -void -NixVector::Serialize (Buffer::Iterator i, uint32_t size) const -{ - uint32_t bytesWritten = 0; - - i.WriteU32 (size); - bytesWritten += 4; - - i.WriteU32 (m_used); - bytesWritten += 4; - - i.WriteU32 (m_currentVectorBitSize); - bytesWritten += 4; - - i.WriteU32 (m_totalBitSize); - bytesWritten += 4; - - for (uint32_t j = 0; j < m_nixVector.size (); j++) - { - i.WriteU32 (m_nixVector.at(j)); - bytesWritten += 4; - } - - NS_ASSERT (bytesWritten == size); + return totalSizeInBytes; } uint32_t -NixVector::Deserialize (Buffer::Iterator i) +NixVector::Serialize (uint32_t* buffer, uint32_t maxSize) const { NS_LOG_FUNCTION (this); - uint32_t totalSize = i.ReadU32 (); - uint32_t size = totalSize; - size -= 4; + uint32_t* p = buffer; + uint32_t size = 0; - NS_ASSERT (size >= 4); - m_used = i.ReadU32 (); - size -=4; + if (size + 4 <= maxSize) + { + size += 4; + // grab number of used bits + *p++ = m_used; + } + else + { + return 0; + } - NS_ASSERT (size >= 4); - m_currentVectorBitSize = i.ReadU32 (); - size -=4; + if (size + 4 <= maxSize) + { + size += 4; + // grab number of current used bits + // for the front vector + *p++ = m_currentVectorBitSize; + } + else + { + return 0; + } - NS_ASSERT (size >= 4); - m_totalBitSize = i.ReadU32 (); - size -=4; + if (size + 4 <= maxSize) + { + size += 4; + // grab total bit size + *p++ = m_totalBitSize; + } + else + { + return 0; + } + for (uint32_t j = 0; j < m_nixVector.size (); j++) + { + if (size + 4 <= maxSize) + { + size += 4; + *p++ = m_nixVector.at(j); + } + else + { + return 0; + } + } + + // Serialized successfully + return 1; +} + +uint32_t +NixVector::Deserialize (uint32_t* buffer, uint32_t size) +{ + NS_LOG_FUNCTION (this); + uint32_t* p = buffer; + uint32_t sizeCheck = size - 4; + + NS_ASSERT (sizeCheck >= 4); + m_used = *p++; + sizeCheck -= 4; + + NS_ASSERT (sizeCheck >= 4); + m_currentVectorBitSize = *p++; + sizeCheck -= 4; + + NS_ASSERT (sizeCheck >= 4); + m_totalBitSize = *p++; + sizeCheck -= 4; // make sure the nix-vector // is empty m_nixVector.clear (); - while (size > 0) + while (sizeCheck > 0) { - NS_ASSERT (size >= 4); - m_nixVector.push_back (i.ReadU32 ()); - size -=4; + NS_ASSERT (sizeCheck >= 4); + uint32_t nix = *p++; + m_nixVector.push_back (nix); + sizeCheck -= 4; } - NS_ASSERT (size == 0); - return totalSize; + NS_ASSERT (sizeCheck == 0); + + // return zero if an entire nix-vector was + // not deserialized + return (sizeCheck != 0) ? 0 : 1; } void diff --git a/src/common/nix-vector.h b/src/common/nix-vector.h index fced817a8..cfe1b1943 100644 --- a/src/common/nix-vector.h +++ b/src/common/nix-vector.h @@ -105,17 +105,27 @@ class NixVector : public Object */ uint32_t GetSerializedSize (void) const; /** - * \param i Buffer iterator for writing + * \return zero if buffer not large enough * - * \param size number of bytes to write + * \param buffer points to serialization buffer + * + * \param maxSize max number of bytes to write + * + * This nix-vector is serialized into the raw character + * buffer parameter. */ - void Serialize (Buffer::Iterator i, uint32_t size) const; + uint32_t Serialize (uint32_t* buffer, uint32_t maxSize) const; /** - * \return the number of bytes deserialized + * \return zero if a complete nix-vector is not deserialized * - * \param i Buffer iterator for reading + * \param buffer points to buffer for deserialization + * + * \param size number of bytes to deserialize + * + * The raw character buffer containing all the nix-vector + * information is deserialized into this nix-vector. */ - uint32_t Deserialize (Buffer::Iterator i); + uint32_t Deserialize (uint32_t* buffer, uint32_t size); /** * \return number of bits of numberOfNeighbors * diff --git a/src/common/packet-metadata-test.cc b/src/common/packet-metadata-test.cc index e4d0a32b4..491ddded5 100644 --- a/src/common/packet-metadata-test.cc +++ b/src/common/packet-metadata-test.cc @@ -353,42 +353,43 @@ PacketMetadataTest::CheckHistory (Ptr p, const char *file, int line, uin return false; } -#define ADD_HEADER(p, n) \ - { \ - HistoryHeader header; \ - p->AddHeader (header); \ +#define ADD_HEADER(p, n) \ + { \ + HistoryHeader header; \ + p->AddHeader (header); \ } -#define ADD_TRAILER(p, n) \ - { \ - HistoryTrailer trailer; \ - p->AddTrailer (trailer); \ +#define ADD_TRAILER(p, n) \ + { \ + HistoryTrailer trailer; \ + p->AddTrailer (trailer); \ } -#define REM_HEADER(p, n) \ - { \ - HistoryHeader header; \ - p->RemoveHeader (header); \ +#define REM_HEADER(p, n) \ + { \ + HistoryHeader header; \ + p->RemoveHeader (header); \ } -#define REM_TRAILER(p, n) \ - { \ - HistoryTrailer trailer; \ - p->RemoveTrailer (trailer); \ +#define REM_TRAILER(p, n) \ + { \ + HistoryTrailer trailer; \ + p->RemoveTrailer (trailer); \ } -#define CHECK_HISTORY(p, ...) \ - { \ - if (!CheckHistory (p, __FILE__, \ - __LINE__, __VA_ARGS__)) \ - { \ - result = false; \ - } \ - Buffer buffer; \ - buffer = p->Serialize (); \ - Ptr otherPacket = Create ();\ - otherPacket->Deserialize (buffer); \ - if (!CheckHistory (otherPacket, __FILE__, \ - __LINE__, __VA_ARGS__)) \ - { \ - result = false; \ - } \ +#define CHECK_HISTORY(p, ...) \ + { \ + if (!CheckHistory (p, __FILE__, \ + __LINE__, __VA_ARGS__)) \ + { \ + result = false; \ + } \ + uint32_t size = p->GetSerializedSize (); \ + uint8_t* buffer = new uint8_t[size]; \ + p->Serialize (buffer, size); \ + Ptr otherPacket = Create (buffer, size, true); \ + delete [] buffer; \ + if (!CheckHistory (otherPacket, __FILE__, \ + __LINE__, __VA_ARGS__)) \ + { \ + result = false; \ + } \ } @@ -413,6 +414,7 @@ PacketMetadataTest::DoRun (void) ADD_TRAILER (p, 100); CHECK_HISTORY (p, 2, 10, 100); + p = Create (10); ADD_HEADER (p, 1); ADD_HEADER (p, 2); diff --git a/src/common/packet-metadata.cc b/src/common/packet-metadata.cc index 810a854db..f402d9ab8 100644 --- a/src/common/packet-metadata.cc +++ b/src/common/packet-metadata.cc @@ -959,7 +959,7 @@ PacketMetadata::GetTotalSize (void) const return totalSize; } -uint32_t +uint64_t PacketMetadata::GetUid (void) const { return m_packetUid; @@ -1055,11 +1055,18 @@ PacketMetadata::GetSerializedSize (void) const { NS_LOG_FUNCTION (this); uint32_t totalSize = 0; - totalSize += 4; + + // add 8 bytes for the packet uid + totalSize += 8; + + // if packet-metadata not enabled, total size + // is simply 4-bytes for itself plus 8-bytes + // for packet uid if (!m_enable) { return totalSize; } + struct PacketMetadata::SmallItem item; struct PacketMetadata::ExtraItem extraItem; uint32_t current = m_head; @@ -1077,7 +1084,7 @@ PacketMetadata::GetSerializedSize (void) const tid.SetUid (uid); totalSize += 4 + tid.GetName ().size (); } - totalSize += 1 + 4 + 2 + 4 + 4 + 4; + totalSize += 1 + 4 + 2 + 4 + 4 + 8; if (current == m_tail) { break; @@ -1087,52 +1094,95 @@ PacketMetadata::GetSerializedSize (void) const } return totalSize; } -void -PacketMetadata::Serialize (Buffer::Iterator i, uint32_t size) const + +uint32_t +PacketMetadata::Serialize (uint8_t* buffer, uint32_t maxSize) const { NS_LOG_FUNCTION (this); - uint32_t bytesWritten = 0; - i.WriteU32 (size); - bytesWritten += 4; + uint8_t* start = buffer; + + buffer = AddToRawU64 (m_packetUid, start, buffer, maxSize); + if (buffer == 0) + { + return 0; + } + struct PacketMetadata::SmallItem item; struct PacketMetadata::ExtraItem extraItem; uint32_t current = m_head; while (current != 0xffff) { ReadItems (current, &item, &extraItem); - NS_LOG_LOGIC ("bytesWritten=" << bytesWritten << ", typeUid="<< + NS_LOG_LOGIC ("bytesWritten=" << (uint32_t)(buffer - start) << ", typeUid="<< item.typeUid << ", size="< #include @@ -125,7 +126,7 @@ Packet::Packet () : m_buffer (), m_byteTagList (), m_packetTagList (), - m_metadata (m_globalUid, 0), + m_metadata ((uint64_t)Simulator::GetSystemId () << 32 | m_globalUid, 0), m_nixVector (0) { m_globalUid++; @@ -161,16 +162,27 @@ Packet::Packet (uint32_t size) : m_buffer (size), m_byteTagList (), m_packetTagList (), - m_metadata (m_globalUid, size), + m_metadata ((uint64_t)Simulator::GetSystemId () << 32 | m_globalUid, size), m_nixVector (0) { m_globalUid++; } +Packet::Packet (uint8_t const *buffer, uint32_t size, bool magic) + : m_buffer (0, false), + m_byteTagList (), + m_packetTagList (), + m_metadata (0,0), + m_nixVector (0) +{ + NS_ASSERT (magic); + Deserialize (buffer, size); +} + Packet::Packet (uint8_t const*buffer, uint32_t size) : m_buffer (), m_byteTagList (), m_packetTagList (), - m_metadata (m_globalUid, size), + m_metadata ((uint64_t)Simulator::GetSystemId () << 32 | m_globalUid, size), m_nixVector (0) { m_globalUid++; @@ -359,7 +371,7 @@ Packet::CopyData(std::ostream *os, uint32_t size) const return m_buffer.CopyData (os, size); } -uint32_t +uint64_t Packet::GetUid (void) const { return m_metadata.GetUid (); @@ -532,48 +544,197 @@ Packet::EnableChecking (void) PacketMetadata::EnableChecking (); } -Buffer -Packet::Serialize (void) const +uint32_t Packet::GetSerializedSize (void) const { - NS_LOG_FUNCTION (this); - Buffer buffer; - uint32_t reserve; + uint32_t size = 0; - // write metadata - reserve = m_metadata.GetSerializedSize (); - buffer.AddAtStart (reserve); - m_metadata.Serialize (buffer.Begin (), reserve); + if (m_nixVector) + { + // increment total size by the size of the nix-vector + // ensuring 4-byte boundary + size += ((m_nixVector->GetSerializedSize () + 3) & (~3)); - // write tags + // add 4-bytes for entry of total length of nix-vector + size += 4; + } + else + { + // if no nix-vector, still have to add 4-bytes + // to account for the entry of total size for + // nix-vector in the buffer + size += 4; + } + + //Tag size //XXX - //reserve = m_tags.GetSerializedSize (); - //buffer.AddAtStart (reserve); - //m_tags.Serialize (buffer.Begin (), reserve); - - // aggregate byte buffer, metadata, and tags - Buffer tmp = m_buffer.CreateFullCopy (); - tmp.AddAtEnd (buffer); - - // write byte buffer size. - tmp.AddAtStart (4); - tmp.Begin ().WriteU32 (m_buffer.GetSize ()); + //size += m_tags.GetSerializedSize (); - return tmp; + // increment total size by size of meta-data + // ensuring 4-byte boundary + size += ((m_metadata.GetSerializedSize () + 3) & (~3)); + + // add 4-bytes for entry of total length of meta-data + size += 4; + + // increment total size by size of buffer + // ensuring 4-byte boundary + size += ((m_buffer.GetSerializedSize () + 3) & (~3)); + + // add 4-bytes for entry of total length of buffer + size += 4; + + return size; } -void -Packet::Deserialize (Buffer buffer) + +uint32_t +Packet::Serialize (uint8_t* buffer, uint32_t maxSize) const +{ + uint32_t* p = (uint32_t*)buffer; + uint32_t size = 0; + + // if nix-vector exists, serialize it + if (m_nixVector) + { + uint32_t nixSize = m_nixVector->GetSerializedSize (); + if (size + nixSize <= maxSize) + { + // put the total length of nix-vector in the + // buffer. this includes 4-bytes for total + // length itself + *p++ = nixSize + 4; + size += nixSize; + + // serialize the nix-vector + uint32_t serialized = + m_nixVector->Serialize (p, nixSize); + if (serialized) + { + // increment p by nixSize bytes + // ensuring 4-byte boundary + p += ((nixSize+3) & (~3)) / 4; + } + else + { + return 0; + } + } + else + { + return 0; + } + } + else + { + // no nix vector, set zero length, + // ie 4-bytes, since it must include + // length for itself + if (size + 4 <= maxSize) + { + size += 4; + *p++ = 4; + } + else + { + return 0; + } + } + + // Serialize Tags + // XXX + + // Serialize Metadata + uint32_t metaSize = m_metadata.GetSerializedSize (); + if (size + metaSize <= maxSize) + { + // put the total length of metadata in the + // buffer. this includes 4-bytes for total + // length itself + *p++ = metaSize + 4; + size += metaSize; + + // serialize the metadata + uint32_t serialized = + m_metadata.Serialize ((uint8_t*)p, metaSize); + if (serialized) + { + // increment p by metaSize bytes + // ensuring 4-byte boundary + p += ((metaSize+3) & (~3)) / 4; + } + else + { + return 0; + } + } + else + { + return 0; + } + + // Serialize the packet contents + uint32_t bufSize = m_buffer.GetSerializedSize (); + if (size + bufSize <= maxSize) + { + // put the total length of the buffer in the + // buffer. this includes 4-bytes for total + // length itself + *p++ = bufSize + 4; + size += bufSize; + + // serialize the buffer + uint32_t serialized = + m_buffer.Serialize ((uint8_t*)p, bufSize); + if (serialized) + { + // increment p by bufSize bytes + // ensuring 4-byte boundary + p += ((bufSize+3) & (~3)) / 4; + } + else + { + return 0; + } + } + else + { + return 0; + } + + // Serialized successfully + return 1; +} + +uint32_t +Packet::Deserialize (uint8_t const*buffer, uint32_t size) { NS_LOG_FUNCTION (this); - Buffer buf = buffer; - // read size - uint32_t packetSize = buf.Begin ().ReadU32 (); - buf.RemoveAtStart (4); - // read buffer. - buf.RemoveAtEnd (buf.GetSize () - packetSize); - m_buffer = buf; - buffer.RemoveAtStart (4 + packetSize); + uint32_t* p = (uint32_t*)buffer; + // read nix-vector + NS_ASSERT (!m_nixVector); + uint32_t nixSize = *p++; + size -= nixSize; + + // if size less than zero, the buffer + // will be overrun, assert + NS_ASSERT (size >= 0); + + if (nixSize > 4) + { + Ptr nix = CreateObject (); + uint32_t nixDeserialized = nix->Deserialize (p, nixSize); + if (!nixDeserialized) + { + // nix-vector not deserialized + // completely + return 0; + } + m_nixVector = nix; + // increment p by nixSize ensuring + // 4-byte boundary + p += ((((nixSize - 4) + 3) & (~3)) / 4); + } // read tags //XXX @@ -581,9 +742,45 @@ Packet::Deserialize (Buffer buffer) //buffer.RemoveAtStart (tagsDeserialized); // read metadata + uint32_t metaSize = *p++; + size -= metaSize; + + // if size less than zero, the buffer + // will be overrun, assert + NS_ASSERT (size >= 0); + uint32_t metadataDeserialized = - m_metadata.Deserialize (buffer.Begin ()); - buffer.RemoveAtStart (metadataDeserialized); + m_metadata.Deserialize ((uint8_t*)p, metaSize); + if (!metadataDeserialized) + { + // meta-data not deserialized + // completely + return 0; + } + // increment p by metaSize ensuring + // 4-byte boundary + p += ((((metaSize - 4) + 3) & (~3)) / 4); + + // read buffer contents + uint32_t bufSize = *p++; + size -= bufSize; + + // if size less than zero, the buffer + // will be overrun, assert + NS_ASSERT (size >= 0); + + uint32_t bufferDeserialized = + m_buffer.Deserialize ((uint8_t*)p, bufSize); + if (!bufferDeserialized) + { + // buffer not deserialized + // completely + return 0; + } + + // return zero if did not deserialize the + // number of expected bytes + return (size == 0); } void diff --git a/src/common/packet.h b/src/common/packet.h index cf0883400..94ccdbfc6 100644 --- a/src/common/packet.h +++ b/src/common/packet.h @@ -221,6 +221,17 @@ public: * \param size the size of the zero-filled payload */ Packet (uint32_t size); + /** + * Create a new packet from the serialized buffer. This new packet + * is identical to the serialized packet contained in the buffer + * and is magically deserialized for you + * + * \param buffer the serialized packet to be created + * \param size the size of the packet for deserialization + * \param magic allows packet deserialization; + * asserts when set to false + */ + Packet (uint8_t const*buffer, uint32_t size, bool magic); /** * Create a packet with payload filled with the content * of this buffer. The input data is copied: the input @@ -379,7 +390,7 @@ public: * \returns an integer identifier which uniquely * identifies this packet. */ - uint32_t GetUid (void) const; + uint64_t GetUid (void) const; /** * \param os output stream in which the data should be printed. @@ -420,36 +431,24 @@ public: static void EnableChecking (void); /** - * \returns a byte buffer + * For packet serializtion, the total size is checked + * in order to determine the size of the buffer + * required for serialization * - * This method creates a serialized representation of a Packet object - * ready to be transmitted over a network to another system. This - * serialized representation contains a copy of the packet byte buffer, - * the tag list, and the packet metadata (if there is one). - * - * This method will trigger calls to the Serialize and GetSerializedSize - * methods of each tag stored in this packet. - * - * This method will typically be used by parallel simulations where - * the simulated system is partitioned and each partition runs on - * a different CPU. + * \returns number of bytes required for packet + * serialization */ - Buffer Serialize (void) const; - /** - * \param buffer a byte buffer + uint32_t GetSerializedSize (void) const; + + /* + * \param buffer a raw byte buffer to which the packet will be serialized + * \param maxSize the max size of the buffer for bounds checking * - * This method reads a byte buffer as created by Packet::Serialize - * and restores the state of the Packet to what it was prior to - * calling Serialize. + * A packet is completely serialized and placed into the raw byte buffer * - * This method will trigger calls to the Deserialize method - * of each tag stored in this packet. - * - * This method will typically be used by parallel simulations where - * the simulated system is partitioned and each partition runs on - * a different CPU. + * \returns zero if buffer size was too small */ - void Deserialize (Buffer buffer); + uint32_t Serialize (uint8_t* buffer, uint32_t maxSize) const; /** * \param tag the new tag to add to this packet @@ -556,6 +555,9 @@ public: private: Packet (const Buffer &buffer, const ByteTagList &byteTagList, const PacketTagList &packetTagList, const PacketMetadata &metadata); + + uint32_t Deserialize (uint8_t const*buffer, uint32_t size); + Buffer m_buffer; ByteTagList m_byteTagList; PacketTagList m_packetTagList; diff --git a/src/devices/point-to-point/point-to-point-channel.cc b/src/devices/point-to-point/point-to-point-channel.cc index 2522058f1..87ad931ca 100644 --- a/src/devices/point-to-point/point-to-point-channel.cc +++ b/src/devices/point-to-point/point-to-point-channel.cc @@ -124,4 +124,30 @@ PointToPointChannel::GetDevice (uint32_t i) const return GetPointToPointDevice (i); } +Time +PointToPointChannel::GetDelay (void) const +{ + return m_delay; +} + +Ptr +PointToPointChannel::GetSource (uint32_t i) const +{ + return m_link[i].m_src; +} + +Ptr +PointToPointChannel::GetDestination (uint32_t i) const +{ + return m_link[i].m_dst; +} + +bool +PointToPointChannel::IsInitialized (void) const +{ + NS_ASSERT (m_link[0].m_state != INITIALIZING); + NS_ASSERT (m_link[1].m_state != INITIALIZING); + return true; +} + } // namespace ns3 diff --git a/src/devices/point-to-point/point-to-point-channel.h b/src/devices/point-to-point/point-to-point-channel.h index 23d2cfa48..e77d21971 100644 --- a/src/devices/point-to-point/point-to-point-channel.h +++ b/src/devices/point-to-point/point-to-point-channel.h @@ -69,7 +69,7 @@ public: * \param txTime Transmit time to apply * \returns true if successful (currently always true) */ - bool TransmitStart (Ptr p, Ptr src, Time txTime); + virtual bool TransmitStart (Ptr p, Ptr src, Time txTime); /** * \brief Get number of devices on this channel @@ -91,6 +91,35 @@ public: */ virtual Ptr GetDevice (uint32_t i) const; +protected: + /* + * \brief Get the delay associated with this channel + * \returns Time delay + */ + Time GetDelay (void) const; + + /* + * \brief Check to make sure the link is initialized + * \returns true if initialized, asserts otherwise + */ + bool IsInitialized (void) const; + + /* + * \brief Get the net-device source + * \param i the link requested + * \returns Ptr to PointToPointNetDevice source for the + * specified link + */ + Ptr GetSource (uint32_t i) const; + + /* + * \brief Get the net-device destination + * \param i the link requested + * \returns Ptr to PointToPointNetDevice destination for + * the specifed link + */ + Ptr GetDestination (uint32_t i) const; + private: // Each point to point link has exactly two net devices static const int N_DEVICES = 2; diff --git a/src/devices/point-to-point/point-to-point-remote-channel.cc b/src/devices/point-to-point/point-to-point-remote-channel.cc new file mode 100644 index 000000000..42a50c1e9 --- /dev/null +++ b/src/devices/point-to-point/point-to-point-remote-channel.cc @@ -0,0 +1,80 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007, 2008 University of Washington + * + * 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: George Riley + */ + +#include + +#include "point-to-point-remote-channel.h" +#include "point-to-point-net-device.h" +#include "ns3/packet.h" +#include "ns3/simulator.h" +#include "ns3/log.h" +#include "ns3/mpi-interface.h" + +using namespace std; + +NS_LOG_COMPONENT_DEFINE ("PointToPointRemoteChannel"); + +namespace ns3 { + +NS_OBJECT_ENSURE_REGISTERED (PointToPointRemoteChannel); + +TypeId +PointToPointRemoteChannel::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::PointToPointRemoteChannel") + .SetParent () + .AddConstructor () + ; + return tid; +} + +PointToPointRemoteChannel::PointToPointRemoteChannel () +{ +} + +PointToPointRemoteChannel::~PointToPointRemoteChannel () +{ +} + +bool +PointToPointRemoteChannel::TransmitStart ( + Ptr p, + Ptr src, + Time txTime) +{ + NS_LOG_FUNCTION (this << p << src); + NS_LOG_LOGIC ("UID is " << p->GetUid () << ")"); + + IsInitialized (); + + uint32_t wire = src == GetSource (0) ? 0 : 1; + Ptr dst = GetDestination (wire); + + // Calculate the rxTime (absolute) + Time rxTime = Simulator::Now () + txTime + GetDelay (); +#ifdef NS3_MPI + MpiInterface::SendPacket (p, rxTime, dst->GetNode ()->GetId (), dst->GetIfIndex ()); +#else + NS_FATAL_ERROR ("Can't use distributed simulator without MPI compiled in"); +#endif + return true; +} + +} // namespace ns3 diff --git a/src/devices/point-to-point/point-to-point-remote-channel.h b/src/devices/point-to-point/point-to-point-remote-channel.h new file mode 100644 index 000000000..709b94a79 --- /dev/null +++ b/src/devices/point-to-point/point-to-point-remote-channel.h @@ -0,0 +1,44 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 University of Washington + * + * 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: George Riley + */ + +// This object connects two point-to-point net devices where at least one +// is not local to this simulator object. It simply over-rides the transmit +// method and uses an MPI Send operation instead. + +#ifndef POINT_TO_POINT_REMOTE_CHANNEL_H +#define POINT_TO_POINT_REMOTE_CHANNEL_H + +#include "point-to-point-channel.h" + +namespace ns3 { + +class PointToPointRemoteChannel : public PointToPointChannel +{ +public: + static TypeId GetTypeId (void); + PointToPointRemoteChannel (); + ~PointToPointRemoteChannel (); + virtual bool TransmitStart (Ptr p, Ptr src, Time txTime); +}; +} + +#endif + + diff --git a/src/devices/point-to-point/wscript b/src/devices/point-to-point/wscript index a1fb07c57..bea19f31d 100644 --- a/src/devices/point-to-point/wscript +++ b/src/devices/point-to-point/wscript @@ -6,6 +6,7 @@ def build(bld): module.source = [ 'point-to-point-net-device.cc', 'point-to-point-channel.cc', + 'point-to-point-remote-channel.cc', 'point-to-point-test.cc', 'ppp-header.cc', ] @@ -14,6 +15,7 @@ def build(bld): headers.source = [ 'point-to-point-net-device.h', 'point-to-point-channel.h', + 'point-to-point-remote-channel.h', 'ppp-header.h', ] diff --git a/src/helper/node-container.cc b/src/helper/node-container.cc index 9b1727fa3..3469fbe11 100644 --- a/src/helper/node-container.cc +++ b/src/helper/node-container.cc @@ -97,6 +97,14 @@ NodeContainer::Create (uint32_t n) } } void +NodeContainer::Create (uint32_t n, uint32_t systemId) +{ + for (uint32_t i = 0; i < n; i++) + { + m_nodes.push_back (CreateObject (systemId)); + } +} +void NodeContainer::Add (NodeContainer other) { for (Iterator i = other.Begin (); i != other.End (); i++) diff --git a/src/helper/node-container.h b/src/helper/node-container.h index adb6f2498..1e3578b75 100644 --- a/src/helper/node-container.h +++ b/src/helper/node-container.h @@ -236,6 +236,20 @@ public: */ void Create (uint32_t n); + /** + * \brief Create n nodes with specifiec systemId for distributed simulations + * and append pointers to them to the end of this NodeContainer. + * + * Nodes are at the heart of any ns-3 simulation. One of the first tasks that + * any simulation needs to do is to create a number of nodes. This method + * automates that task, and adds the ability to specifiy systemId for + * distributed simulations. + * + * \param n The number of Nodes to create + * \param systemId The system id or rank associated with this node + */ + void Create (uint32_t n, uint32_t systemId); + /** * \brief Append the contents of another NodeContainer to the end of * this container. diff --git a/src/helper/point-to-point-helper.cc b/src/helper/point-to-point-helper.cc index 127993edb..73c5ffd1c 100644 --- a/src/helper/point-to-point-helper.cc +++ b/src/helper/point-to-point-helper.cc @@ -23,10 +23,12 @@ #include "ns3/simulator.h" #include "ns3/point-to-point-net-device.h" #include "ns3/point-to-point-channel.h" +#include "ns3/point-to-point-remote-channel.h" #include "ns3/queue.h" #include "ns3/config.h" #include "ns3/packet.h" #include "ns3/names.h" +#include "ns3/mpi-interface.h" #include "trace-helper.h" #include "point-to-point-helper.h" @@ -40,6 +42,7 @@ PointToPointHelper::PointToPointHelper () m_queueFactory.SetTypeId ("ns3::DropTailQueue"); m_deviceFactory.SetTypeId ("ns3::PointToPointNetDevice"); m_channelFactory.SetTypeId ("ns3::PointToPointChannel"); + m_remoteChannelFactory.SetTypeId ("ns3::PointToPointRemoteChannel"); } void @@ -66,6 +69,7 @@ void PointToPointHelper::SetChannelAttribute (std::string n1, const AttributeValue &v1) { m_channelFactory.Set (n1, v1); + m_remoteChannelFactory.Set (n1, v1); } void @@ -223,7 +227,30 @@ PointToPointHelper::Install (Ptr a, Ptr b) b->AddDevice (devB); Ptr queueB = m_queueFactory.Create (); devB->SetQueue (queueB); - Ptr channel = m_channelFactory.Create (); + // If MPI is enabled, we need to see if both nodes have the same system id + // (rank), and the rank is the same as this instance. If both are true, + //use a normal p2p channel, otherwise use a remote channel + bool useNormalChannel = true; + Ptr channel = 0; + if (MpiInterface::IsEnabled()) + { + uint32_t n1SystemId = a->GetSystemId (); + uint32_t n2SystemId = b->GetSystemId (); + uint32_t currSystemId = MpiInterface::GetSystemId (); + if (n1SystemId != currSystemId || n2SystemId != currSystemId) + { + useNormalChannel = false; + } + } + if (useNormalChannel) + { + channel = m_channelFactory.Create (); + } + else + { + channel = m_remoteChannelFactory.Create (); + } + devA->Attach (channel); devB->Attach (channel); container.Add (devA); diff --git a/src/helper/point-to-point-helper.h b/src/helper/point-to-point-helper.h index ebcf5badb..4012fb4bc 100644 --- a/src/helper/point-to-point-helper.h +++ b/src/helper/point-to-point-helper.h @@ -116,7 +116,9 @@ public: * \param a first node * \param b second node * - * Saves you from having to construct a temporary NodeContainer. + * Saves you from having to construct a temporary NodeContainer. + * Also, if MPI is enabled, for distributed simulations, + * appropriate remote point-to-point channels are created. */ NetDeviceContainer Install (Ptr a, Ptr b); @@ -177,6 +179,7 @@ private: ObjectFactory m_queueFactory; ObjectFactory m_channelFactory; + ObjectFactory m_remoteChannelFactory; ObjectFactory m_deviceFactory; }; diff --git a/src/mpi/distributed-simulator-impl.cc b/src/mpi/distributed-simulator-impl.cc new file mode 100644 index 000000000..5e806ecab --- /dev/null +++ b/src/mpi/distributed-simulator-impl.cc @@ -0,0 +1,521 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2005,2006 INRIA + * + * 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: George Riley + */ + +#include "distributed-simulator-impl.h" +#include "mpi-interface.h" + +#include "ns3/simulator.h" +#include "ns3/scheduler.h" +#include "ns3/event-impl.h" +#include "ns3/channel.h" +#include "ns3/node-container.h" +#include "ns3/ptr.h" +#include "ns3/pointer.h" +#include "ns3/assert.h" +#include "ns3/log.h" + +#include + +#ifdef NS3_MPI +#include +#endif + +NS_LOG_COMPONENT_DEFINE ("DistributedSimulatorImpl"); + +namespace ns3 { + +NS_OBJECT_ENSURE_REGISTERED (DistributedSimulatorImpl); + +LbtsMessage::~LbtsMessage () +{ +} + +Time +LbtsMessage::GetSmallestTime () +{ + return m_smallestTime; +} + +uint32_t +LbtsMessage::GetTxCount () +{ + return m_txCount; +} + +uint32_t +LbtsMessage::GetRxCount () +{ + return m_rxCount; +} +uint32_t +LbtsMessage::GetMyId () +{ + return m_myId; +} + +Time DistributedSimulatorImpl::m_lookAhead = Seconds (0); + +TypeId +DistributedSimulatorImpl::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::DistributedSimulatorImpl") + .SetParent () + .AddConstructor () + ; + return tid; +} + +DistributedSimulatorImpl::DistributedSimulatorImpl () +{ +#ifdef NS3_MPI + m_myId = MpiInterface::GetSystemId (); + m_systemCount = MpiInterface::GetSize (); + + // Allocate the LBTS message buffer + m_pLBTS = new LbtsMessage[m_systemCount]; + m_grantedTime = Seconds (0); +#else + NS_FATAL_ERROR ("Can't use distributed simulator without MPI compiled in"); +#endif + + m_stop = false; + // uids are allocated from 4. + // uid 0 is "invalid" events + // uid 1 is "now" events + // uid 2 is "destroy" events + m_uid = 4; + // before ::Run is entered, the m_currentUid will be zero + m_currentUid = 0; + m_currentTs = 0; + m_currentContext = 0xffffffff; + m_unscheduledEvents = 0; + m_events = 0; +} + +DistributedSimulatorImpl::~DistributedSimulatorImpl () +{ +} + +void +DistributedSimulatorImpl::DoDispose (void) +{ + while (!m_events->IsEmpty ()) + { + Scheduler::Event next = m_events->RemoveNext (); + next.impl->Unref (); + } + m_events = 0; + delete [] m_pLBTS; + SimulatorImpl::DoDispose (); +} + +void +DistributedSimulatorImpl::Destroy () +{ + while (!m_destroyEvents.empty ()) + { + Ptr ev = m_destroyEvents.front ().PeekEventImpl (); + m_destroyEvents.pop_front (); + NS_LOG_LOGIC ("handle destroy " << ev); + if (!ev->IsCancelled ()) + { + ev->Invoke (); + } + } + + MpiInterface::Destroy (); +} + + +void +DistributedSimulatorImpl::CalculateLookAhead (void) +{ +#ifdef NS3_MPI + if (MpiInterface::GetSize () <= 1) + { + DistributedSimulatorImpl::m_lookAhead = Seconds (0); + m_grantedTime = Seconds (0); + } + else + { + NodeContainer c = NodeContainer::GetGlobal (); + for (NodeContainer::Iterator iter = c.Begin (); iter != c.End (); ++iter) + { + if ((*iter)->GetSystemId () != MpiInterface::GetSystemId ()) + { + continue; + } + + for (uint32_t i = 0; i < (*iter)->GetNDevices (); ++i) + { + Ptr localNetDevice = (*iter)->GetDevice (i); + // only works for p2p links currently + if (!localNetDevice->IsPointToPoint ()) + { + continue; + } + Ptr channel = localNetDevice->GetChannel (); + if (channel == 0) + { + continue; + } + + // grab the adjacent node + Ptr remoteNode; + if (channel->GetDevice (0) == localNetDevice) + { + remoteNode = (channel->GetDevice (1))->GetNode (); + } + else + { + remoteNode = (channel->GetDevice (0))->GetNode (); + } + + // if it's not remote, don't consider it + if (remoteNode->GetSystemId () == MpiInterface::GetSystemId ()) + { + continue; + } + + // compare delay on the channel with current value of + // m_lookAhead. if delay on channel is smaller, make + // it the new lookAhead. + TimeValue delay; + channel->GetAttribute ("Delay", delay); + if (DistributedSimulatorImpl::m_lookAhead.IsZero ()) + { + DistributedSimulatorImpl::m_lookAhead = delay.Get (); + m_grantedTime = delay.Get (); + } + if (delay.Get ().GetSeconds () < DistributedSimulatorImpl::m_lookAhead.GetSeconds ()) + { + DistributedSimulatorImpl::m_lookAhead = delay.Get (); + m_grantedTime = delay.Get (); + } + } + } + } +#else + NS_FATAL_ERROR ("Can't use distributed simulator without MPI compiled in"); +#endif +} + +void +DistributedSimulatorImpl::SetScheduler (ObjectFactory schedulerFactory) +{ + Ptr scheduler = schedulerFactory.Create (); + + if (m_events != 0) + { + while (!m_events->IsEmpty ()) + { + Scheduler::Event next = m_events->RemoveNext (); + scheduler->Insert (next); + } + } + m_events = scheduler; +} + +void +DistributedSimulatorImpl::ProcessOneEvent (void) +{ + Scheduler::Event next = m_events->RemoveNext (); + + NS_ASSERT (next.key.m_ts >= m_currentTs); + m_unscheduledEvents--; + + NS_LOG_LOGIC ("handle " << next.key.m_ts); + m_currentTs = next.key.m_ts; + m_currentContext = next.key.m_context; + m_currentUid = next.key.m_uid; + next.impl->Invoke (); + next.impl->Unref (); +} + +bool +DistributedSimulatorImpl::IsFinished (void) const +{ + return m_events->IsEmpty () || m_stop; +} + +uint64_t +DistributedSimulatorImpl::NextTs (void) const +{ + NS_ASSERT (!m_events->IsEmpty ()); + Scheduler::Event ev = m_events->PeekNext (); + return ev.key.m_ts; +} + +Time +DistributedSimulatorImpl::Next (void) const +{ + return TimeStep (NextTs ()); +} + +void +DistributedSimulatorImpl::Run (void) +{ +#ifdef NS3_MPI + CalculateLookAhead (); + m_stop = false; + while (!m_events->IsEmpty () && !m_stop) + { + Time nextTime = Next (); + if (nextTime > m_grantedTime) + { // Can't process, calculate a new LBTS + // First receive any pending messages + MpiInterface::ReceiveMessages (); + // reset next time + nextTime = Next (); + // And check for send completes + MpiInterface::TestSendComplete (); + // Finally calculate the lbts + LbtsMessage lMsg (MpiInterface::GetRxCount (), MpiInterface::GetTxCount (), m_myId, nextTime); + m_pLBTS[m_myId] = lMsg; + MPI_Allgather (&lMsg, sizeof (LbtsMessage), MPI_BYTE, m_pLBTS, + sizeof (LbtsMessage), MPI_BYTE, MPI_COMM_WORLD); + Time smallestTime = m_pLBTS[0].GetSmallestTime (); + // The totRx and totTx counts insure there are no transient + // messages; If totRx != totTx, there are transients, + // so we don't update the granted time. + uint32_t totRx = m_pLBTS[0].GetRxCount (); + uint32_t totTx = m_pLBTS[0].GetTxCount (); + + for (uint32_t i = 1; i < m_systemCount; ++i) + { + if (m_pLBTS[i].GetSmallestTime () < smallestTime) + { + smallestTime = m_pLBTS[i].GetSmallestTime (); + } + totRx += m_pLBTS[i].GetRxCount (); + totTx += m_pLBTS[i].GetTxCount (); + + } + if (totRx == totTx) + { + m_grantedTime = smallestTime + DistributedSimulatorImpl::m_lookAhead; + } + } + if (nextTime <= m_grantedTime) + { // Save to process + ProcessOneEvent (); + } + } + + // If the simulator stopped naturally by lack of events, make a + // consistency test to check that we didn't lose any events along the way. + NS_ASSERT (!m_events->IsEmpty () || m_unscheduledEvents == 0); +#else + NS_FATAL_ERROR ("Can't use distributed simulator without MPI compiled in"); +#endif +} + +uint32_t DistributedSimulatorImpl::GetSystemId () const +{ + return m_myId; +} + +void +DistributedSimulatorImpl::RunOneEvent (void) +{ + ProcessOneEvent (); +} + +void +DistributedSimulatorImpl::Stop (void) +{ + m_stop = true; +} + +void +DistributedSimulatorImpl::Stop (Time const &time) +{ + Simulator::Schedule (time, &Simulator::Stop); +} + +// +// Schedule an event for a _relative_ time in the future. +// +EventId +DistributedSimulatorImpl::Schedule (Time const &time, EventImpl *event) +{ + Time tAbsolute = time + TimeStep (m_currentTs); + + NS_ASSERT (tAbsolute.IsPositive ()); + NS_ASSERT (tAbsolute >= TimeStep (m_currentTs)); + Scheduler::Event ev; + ev.impl = event; + ev.key.m_ts = (uint64_t) tAbsolute.GetTimeStep (); + ev.key.m_context = GetContext (); + ev.key.m_uid = m_uid; + m_uid++; + m_unscheduledEvents++; + m_events->Insert (ev); + return EventId (event, ev.key.m_ts, ev.key.m_context, ev.key.m_uid); +} + +void +DistributedSimulatorImpl::ScheduleWithContext (uint32_t context, Time const &time, EventImpl *event) +{ + NS_LOG_FUNCTION (this << context << time.GetTimeStep () << m_currentTs << event); + + Scheduler::Event ev; + ev.impl = event; + ev.key.m_ts = m_currentTs + time.GetTimeStep (); + ev.key.m_context = context; + ev.key.m_uid = m_uid; + m_uid++; + m_unscheduledEvents++; + m_events->Insert (ev); +} + +EventId +DistributedSimulatorImpl::ScheduleNow (EventImpl *event) +{ + Scheduler::Event ev; + ev.impl = event; + ev.key.m_ts = m_currentTs; + ev.key.m_context = GetContext (); + ev.key.m_uid = m_uid; + m_uid++; + m_unscheduledEvents++; + m_events->Insert (ev); + return EventId (event, ev.key.m_ts, ev.key.m_context, ev.key.m_uid); +} + +EventId +DistributedSimulatorImpl::ScheduleDestroy (EventImpl *event) +{ + EventId id (Ptr (event, false), m_currentTs, 0xffffffff, 2); + m_destroyEvents.push_back (id); + m_uid++; + return id; +} + +Time +DistributedSimulatorImpl::Now (void) const +{ + return TimeStep (m_currentTs); +} + +Time +DistributedSimulatorImpl::GetDelayLeft (const EventId &id) const +{ + if (IsExpired (id)) + { + return TimeStep (0); + } + else + { + return TimeStep (id.GetTs () - m_currentTs); + } +} + +void +DistributedSimulatorImpl::Remove (const EventId &id) +{ + if (id.GetUid () == 2) + { + // destroy events. + for (DestroyEvents::iterator i = m_destroyEvents.begin (); i != m_destroyEvents.end (); i++) + { + if (*i == id) + { + m_destroyEvents.erase (i); + break; + } + } + return; + } + if (IsExpired (id)) + { + return; + } + Scheduler::Event event; + event.impl = id.PeekEventImpl (); + event.key.m_ts = id.GetTs (); + event.key.m_context = id.GetContext (); + event.key.m_uid = id.GetUid (); + m_events->Remove (event); + event.impl->Cancel (); + // whenever we remove an event from the event list, we have to unref it. + event.impl->Unref (); + + m_unscheduledEvents--; +} + +void +DistributedSimulatorImpl::Cancel (const EventId &id) +{ + if (!IsExpired (id)) + { + id.PeekEventImpl ()->Cancel (); + } +} + +bool +DistributedSimulatorImpl::IsExpired (const EventId &ev) const +{ + if (ev.GetUid () == 2) + { + if (ev.PeekEventImpl () == 0 + || ev.PeekEventImpl ()->IsCancelled ()) + { + return true; + } + // destroy events. + for (DestroyEvents::const_iterator i = m_destroyEvents.begin (); i != m_destroyEvents.end (); i++) + { + if (*i == ev) + { + return false; + } + } + return true; + } + if (ev.PeekEventImpl () == 0 + || ev.GetTs () < m_currentTs + || (ev.GetTs () == m_currentTs + && ev.GetUid () <= m_currentUid) + || ev.PeekEventImpl ()->IsCancelled ()) + { + return true; + } + else + { + return false; + } +} + +Time +DistributedSimulatorImpl::GetMaximumSimulationTime (void) const +{ + // XXX: I am fairly certain other compilers use other non-standard + // post-fixes to indicate 64 bit constants. + return TimeStep (0x7fffffffffffffffLL); +} + +uint32_t +DistributedSimulatorImpl::GetContext (void) const +{ + return m_currentContext; +} + +} // namespace ns3 diff --git a/src/mpi/distributed-simulator-impl.h b/src/mpi/distributed-simulator-impl.h new file mode 100644 index 000000000..d1d84168c --- /dev/null +++ b/src/mpi/distributed-simulator-impl.h @@ -0,0 +1,124 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2005,2006 INRIA + * + * 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: George Riley + */ + +#ifndef DISTRIBUTED_SIMULATOR_IMPL_H +#define DISTRIBUTED_SIMULATOR_IMPL_H + +#include "ns3/simulator-impl.h" +#include "ns3/scheduler.h" +#include "ns3/event-impl.h" +#include "ns3/ptr.h" + +#include + +namespace ns3 { + +// Structure used for all-reduce LBTS computation +class LbtsMessage +{ +public: + LbtsMessage () + : m_txCount (0), + m_rxCount (0), + m_myId (0) + { + } + + LbtsMessage (uint32_t rxc, uint32_t txc, uint32_t id, const Time& t) + : m_txCount (txc), + m_rxCount (rxc), + m_myId (id), + m_smallestTime (t) + { + } + + ~LbtsMessage (); + + Time GetSmallestTime (); + uint32_t GetTxCount (); + uint32_t GetRxCount (); + uint32_t GetMyId (); + +private: + uint32_t m_txCount; + uint32_t m_rxCount; + uint32_t m_myId; + Time m_smallestTime; +}; + +class DistributedSimulatorImpl : public SimulatorImpl +{ +public: + static TypeId GetTypeId (void); + + DistributedSimulatorImpl (); + ~DistributedSimulatorImpl (); + + virtual void Destroy (); + virtual bool IsFinished (void) const; + virtual Time Next (void) const; + virtual void Stop (void); + virtual void Stop (Time const &time); + virtual EventId Schedule (Time const &time, EventImpl *event); + virtual void ScheduleWithContext (uint32_t context, Time const &time, EventImpl *event); + virtual EventId ScheduleNow (EventImpl *event); + virtual EventId ScheduleDestroy (EventImpl *event); + virtual void Remove (const EventId &ev); + virtual void Cancel (const EventId &ev); + virtual bool IsExpired (const EventId &ev) const; + virtual void Run (void); + virtual void RunOneEvent (void); + virtual Time Now (void) const; + virtual Time GetDelayLeft (const EventId &id) const; + virtual Time GetMaximumSimulationTime (void) const; + virtual void SetScheduler (ObjectFactory schedulerFactory); + virtual uint32_t GetSystemId (void) const; + virtual uint32_t GetContext (void) const; + +private: + virtual void DoDispose (void); + void CalculateLookAhead (void); + + void ProcessOneEvent (void); + uint64_t NextTs (void) const; + typedef std::list DestroyEvents; + + DestroyEvents m_destroyEvents; + bool m_stop; + Ptr m_events; + uint32_t m_uid; + uint32_t m_currentUid; + uint64_t m_currentTs; + uint32_t m_currentContext; + // number of events that have been inserted but not yet scheduled, + // not counting the "destroy" events; this is used for validation + int m_unscheduledEvents; + + LbtsMessage* m_pLBTS; // Allocated once we know how many systems + uint32_t m_myId; // MPI Rank + uint32_t m_systemCount; // MPI Size + Time m_grantedTime; // Last LBTS + static Time m_lookAhead; // Lookahead value + +}; + +} // namespace ns3 + +#endif /* DISTRIBUTED_SIMULATOR_IMPL_H */ diff --git a/src/mpi/mpi-interface.cc b/src/mpi/mpi-interface.cc new file mode 100644 index 000000000..03c9fa5ad --- /dev/null +++ b/src/mpi/mpi-interface.cc @@ -0,0 +1,287 @@ +/* -*- 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: George Riley + */ + +// This object contains static methods that provide an easy interface +// to the necessary MPI information. + +#include +#include +#include + +#include "mpi-interface.h" + +#include "ns3/node.h" +#include "ns3/node-list.h" +#include "ns3/point-to-point-net-device.h" +#include "ns3/simulator.h" +#include "ns3/simulator-impl.h" +#include "ns3/nstime.h" + +#ifdef NS3_MPI +#include +#endif + +namespace ns3 { + +SentBuffer::SentBuffer () +{ + m_buffer = 0; + m_request = 0; +} + +SentBuffer::~SentBuffer () +{ + delete [] m_buffer; +} + +uint8_t* +SentBuffer::GetBuffer () +{ + return m_buffer; +} + +void +SentBuffer::SetBuffer (uint8_t* buffer) +{ + m_buffer = buffer; +} + +#ifdef NS3_MPI +MPI_Request* +SentBuffer::GetRequest () +{ + return &m_request; +} +#endif + +uint32_t MpiInterface::m_sid = 0; +uint32_t MpiInterface::m_size = 1; +bool MpiInterface::m_initialized = false; +bool MpiInterface::m_enabled = false; +uint32_t MpiInterface::m_rxCount = 0; +uint32_t MpiInterface::m_txCount = 0; +std::list MpiInterface::m_pendingTx; + +#ifdef NS3_MPI +MPI_Request* MpiInterface::m_requests; +char** MpiInterface::m_pRxBuffers; +#endif + +void +MpiInterface::Destroy () +{ +#ifdef NS3_MPI + for (uint32_t i = 0; i < GetSize (); ++i) + { + delete [] m_pRxBuffers[i]; + } + delete [] m_pRxBuffers; + delete [] m_requests; + + m_pendingTx.clear (); +#endif +} + +uint32_t +MpiInterface::GetRxCount () +{ + return m_rxCount; +} + +uint32_t +MpiInterface::GetTxCount () +{ + return m_txCount; +} + +uint32_t +MpiInterface::GetSystemId () +{ + if (!m_initialized) + { + Simulator::GetImplementation (); + m_initialized = true; + } + return m_sid; +} + +uint32_t +MpiInterface::GetSize () +{ + if (!m_initialized) + { + Simulator::GetImplementation (); + m_initialized = true; + } + return m_size; +} + +bool +MpiInterface::IsEnabled () +{ + if (!m_initialized) + { + Simulator::GetImplementation (); + m_initialized = true; + } + return m_enabled; +} + +void +MpiInterface::Enable (int* pargc, char*** pargv) +{ +#ifdef NS3_MPI + // Initialize the MPI interface + MPI_Init (pargc, pargv); + MPI_Barrier (MPI_COMM_WORLD); + MPI_Comm_rank (MPI_COMM_WORLD, (int*)&m_sid); + MPI_Comm_size (MPI_COMM_WORLD, (int*)&m_size); + m_enabled = true; + m_initialized = true; + // Post a non-blocking receive for all peers + m_pRxBuffers = new char*[m_size]; + m_requests = new MPI_Request[m_size]; + for (uint32_t i = 0; i < GetSize (); ++i) + { + m_pRxBuffers[i] = new char[MAX_MPI_MSG_SIZE]; + MPI_Irecv (m_pRxBuffers[i], MAX_MPI_MSG_SIZE, MPI_CHAR, MPI_ANY_SOURCE, 0, + MPI_COMM_WORLD, &m_requests[i]); + } +#else + NS_FATAL_ERROR ("Can't use distributed simulator without MPI compiled in"); +#endif +} + +void +MpiInterface::SendPacket (Ptr p, const Time& rxTime, uint32_t node, uint32_t dev) +{ +#ifdef NS3_MPI + SentBuffer sendBuf; + m_pendingTx.push_back (sendBuf); + std::list::reverse_iterator i = m_pendingTx.rbegin (); // Points to the last element + + uint32_t serializedSize = p->GetSerializedSize (); + uint8_t* buffer = new uint8_t[serializedSize + 16]; + i->SetBuffer (buffer); + // Add the time, dest node and dest device + uint64_t t = rxTime.GetNanoSeconds (); + uint64_t* pTime = (uint64_t*)buffer; + *pTime++ = t; + uint32_t* pData = (uint32_t*)pTime; + *pData++ = node; + *pData++ = dev; + // Serialize the packet + p->Serialize ((uint8_t*)pData, serializedSize); + + // Find the system id for the destination node + Ptr destNode = NodeList::GetNode (node); + uint32_t nodeSysId = destNode->GetSystemId (); + + MPI_Isend ((void*)i->GetBuffer (), serializedSize + 16, MPI_CHAR, nodeSysId, + 0, MPI_COMM_WORLD, (i->GetRequest ())); + m_txCount++; +#else + NS_FATAL_ERROR ("Can't use distributed simulator without MPI compiled in"); +#endif +} + +void +MpiInterface::ReceiveMessages () +{ // Poll the non-block reads to see if data arrived +#ifdef NS3_MPI + while (true) + { + int flag = 0; + int index = 0; + MPI_Status status; + + MPI_Testany (GetSize (), m_requests, &index, &flag, &status); + if (!flag) + { + break; // No more messages + } + int count; + MPI_Get_count (&status, MPI_CHAR, &count); + m_rxCount++; // Count this receive + + // Get the meta data first + uint64_t* pTime = (uint64_t*)m_pRxBuffers[index]; + uint64_t nanoSeconds = *pTime++; + uint32_t* pData = (uint32_t*)pTime; + uint32_t node = *pData++; + uint32_t dev = *pData++; + + Time rxTime = NanoSeconds (nanoSeconds); + + count -= sizeof (nanoSeconds) + sizeof (node) + sizeof (dev); + + Ptr p = Create ((uint8_t*)pData, count, true); + + // Find the correct node/device to schedule receive event + Ptr pNode = NodeList::GetNode (node); + uint32_t nDevices = pNode->GetNDevices (); + Ptr pDev = 0; + for (uint32_t i = 0; i < nDevices; ++i) + { + Ptr pThisDev = pNode->GetDevice (i); + if (pThisDev->GetIfIndex () == dev) + { + pDev = DynamicCast (pThisDev); + break; + } + } + + NS_ASSERT (pNode && pDev); + + // Schedule the rx event + Simulator::ScheduleWithContext (pNode->GetId (), rxTime - Simulator::Now (), + &PointToPointNetDevice::Receive, + pDev, p); + + // Re-queue the next read + MPI_Irecv (m_pRxBuffers[index], MAX_MPI_MSG_SIZE, MPI_CHAR, MPI_ANY_SOURCE, 0, + MPI_COMM_WORLD, &m_requests[index]); + } +#else + NS_FATAL_ERROR ("Can't use distributed simulator without MPI compiled in"); +#endif +} + +void +MpiInterface::TestSendComplete () +{ +#ifdef NS3_MPI + std::list::iterator i = m_pendingTx.begin (); + while (i != m_pendingTx.end ()) + { + MPI_Status status; + int flag = 0; + MPI_Test (i->GetRequest (), &flag, &status); + std::list::iterator current = i; // Save current for erasing + i++; // Advance to next + if (flag) + { // This message is complete + m_pendingTx.erase (current); + } + } +#else + NS_FATAL_ERROR ("Can't use distributed simulator without MPI compiled in"); +#endif +} + +} // namespace ns3 diff --git a/src/mpi/mpi-interface.h b/src/mpi/mpi-interface.h new file mode 100644 index 000000000..c2173398e --- /dev/null +++ b/src/mpi/mpi-interface.h @@ -0,0 +1,85 @@ +/* -*- 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: George Riley + */ + +// This object contains static methods that provide an easy interface +// to the necessary MPI information. + +#ifndef NS3_MPI_INTERFACE_H +#define NS3_MPI_INTERFACE_H + +#include +#include + +#include "ns3/nstime.h" +#include "ns3/buffer.h" + +struct ompi_request_t; +typedef struct ompi_request_t* MPI_Request; + +namespace ns3 { + +const uint32_t MAX_MPI_MSG_SIZE = 2000; +// Define a class for tracking the non-block sends +class SentBuffer +{ +public: + SentBuffer (); + ~SentBuffer (); + + uint8_t* GetBuffer (); + void SetBuffer (uint8_t*); + MPI_Request* GetRequest (); + +private: + uint8_t* m_buffer; + MPI_Request m_request; +}; + +class Packet; + +class MpiInterface +{ +public: + static void Destroy (); + static uint32_t GetSystemId (); // Get the MPI Rank (system id) + static uint32_t GetSize (); // Get the MPI Size (number of systems) + static bool IsEnabled (); // True if using MPI + static void Enable (int*, char***); // Called by ns3 main program + + // Serialize and send a packet to the specified node and net device + static void SendPacket (Ptr, const Time &, uint32_t, uint32_t); + static void ReceiveMessages (); // Check for received messages complete + static void TestSendComplete (); // Check for completed sends + static uint32_t GetRxCount (); + static uint32_t GetTxCount (); + +private: + static uint32_t m_sid; + static uint32_t m_size; + static uint32_t m_rxCount; // Total packets received + static uint32_t m_txCount; // Total packets sent + static bool m_initialized; + static bool m_enabled; + static MPI_Request* m_requests; // Pending non-blocking receives + static char** m_pRxBuffers; // Data buffers for non-blocking reads + static std::list m_pendingTx; // List of pending non-blocking sends +}; + +} // namespace ns3 + +#endif /* NS3_MPI_INTERFACE_H */ diff --git a/src/mpi/waf b/src/mpi/waf new file mode 100755 index 000000000..3dcf598bc --- /dev/null +++ b/src/mpi/waf @@ -0,0 +1 @@ +exec "`dirname "$0"`"/../../waf "$@" \ No newline at end of file diff --git a/src/mpi/wscript b/src/mpi/wscript new file mode 100644 index 000000000..34988bcba --- /dev/null +++ b/src/mpi/wscript @@ -0,0 +1,23 @@ +## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- +import sys + +import Options + + +def build(bld): + env = bld.env_of_name('default') + sim = bld.create_ns3_module('mpi', ['core', 'simulator']) + sim.source = [ + 'distributed-simulator-impl.cc', + 'mpi-interface.cc', + ] + + headers = bld.new_task_gen('ns3header') + headers.module = 'mpi' + headers.source = [ + 'distributed-simulator-impl.h', + 'mpi-interface.h', + ] + + if env['ENABLE_MPI']: + sim.uselib = 'MPI' diff --git a/src/routing/global-routing/global-route-manager-impl.cc b/src/routing/global-routing/global-route-manager-impl.cc index 9051a640b..a59f8c726 100644 --- a/src/routing/global-routing/global-route-manager-impl.cc +++ b/src/routing/global-routing/global-route-manager-impl.cc @@ -34,6 +34,7 @@ #include "ns3/ipv4.h" #include "ns3/ipv4-routing-protocol.h" #include "ns3/ipv4-list-routing.h" +#include "ns3/mpi-interface.h" #include "global-router-interface.h" #include "global-route-manager-impl.h" #include "candidate-queue.h" @@ -697,6 +698,13 @@ GlobalRouteManagerImpl::InitializeRoutes () // Ptr rtr = node->GetObject (); + + // Ignore nodes that are not assigned to our systemId (distributed sim) + if (node->GetSystemId () != MpiInterface::GetSystemId ()) + { + continue; + } + // // if the node has a global router interface, then run the global routing // algorithms. diff --git a/src/simulator/default-simulator-impl.cc b/src/simulator/default-simulator-impl.cc index b810ca855..86bb0f19d 100644 --- a/src/simulator/default-simulator-impl.cc +++ b/src/simulator/default-simulator-impl.cc @@ -106,6 +106,13 @@ DefaultSimulatorImpl::SetScheduler (ObjectFactory schedulerFactory) m_events = scheduler; } +// System ID for non-distributed simulation is always zero +uint32_t +DefaultSimulatorImpl::GetSystemId (void) const +{ + return 0; +} + void DefaultSimulatorImpl::ProcessOneEvent (void) { diff --git a/src/simulator/default-simulator-impl.h b/src/simulator/default-simulator-impl.h index 634d3c700..0fd8a11cb 100644 --- a/src/simulator/default-simulator-impl.h +++ b/src/simulator/default-simulator-impl.h @@ -57,6 +57,7 @@ public: virtual Time GetDelayLeft (const EventId &id) const; virtual Time GetMaximumSimulationTime (void) const; virtual void SetScheduler (ObjectFactory schedulerFactory); + virtual uint32_t GetSystemId (void) const; virtual uint32_t GetContext (void) const; private: diff --git a/src/simulator/realtime-simulator-impl.cc b/src/simulator/realtime-simulator-impl.cc index aa7866cb9..8f95f9a4f 100644 --- a/src/simulator/realtime-simulator-impl.cc +++ b/src/simulator/realtime-simulator-impl.cc @@ -827,6 +827,13 @@ RealtimeSimulatorImpl::GetMaximumSimulationTime (void) const return TimeStep (0x7fffffffffffffffLL); } +// System ID for non-distributed simulation is always zero +uint32_t +RealtimeSimulatorImpl::GetSystemId (void) const +{ + return 0; +} + uint32_t RealtimeSimulatorImpl::GetContext (void) const { diff --git a/src/simulator/realtime-simulator-impl.h b/src/simulator/realtime-simulator-impl.h index 012ff29da..dd1ee2b2e 100644 --- a/src/simulator/realtime-simulator-impl.h +++ b/src/simulator/realtime-simulator-impl.h @@ -69,6 +69,7 @@ public: virtual Time GetDelayLeft (const EventId &id) const; virtual Time GetMaximumSimulationTime (void) const; virtual void SetScheduler (ObjectFactory schedulerFactory); + virtual uint32_t GetSystemId (void) const; virtual uint32_t GetContext (void) const; void ScheduleRealtimeWithContext (uint32_t context, Time const &time, EventImpl *event); diff --git a/src/simulator/simulator-impl.h b/src/simulator/simulator-impl.h index 67664ee0b..787769948 100644 --- a/src/simulator/simulator-impl.h +++ b/src/simulator/simulator-impl.h @@ -53,6 +53,7 @@ public: virtual Time GetDelayLeft (const EventId &id) const = 0; virtual Time GetMaximumSimulationTime (void) const = 0; virtual void SetScheduler (ObjectFactory schedulerFactory) = 0; + virtual uint32_t GetSystemId () const = 0; virtual uint32_t GetContext (void) const = 0; }; diff --git a/src/simulator/simulator.cc b/src/simulator/simulator.cc index 6f9f33e9a..dd2e77594 100644 --- a/src/simulator/simulator.cc +++ b/src/simulator/simulator.cc @@ -339,6 +339,21 @@ Simulator::GetContext (void) return GetImpl ()->GetContext (); } +uint32_t +Simulator::GetSystemId (void) +{ + NS_LOG_FUNCTION_NOARGS (); + + if (*PeekImpl () != 0) + { + return GetImpl ()->GetSystemId (); + } + else + { + return 0; + } +} + void Simulator::SetImplementation (Ptr impl) { diff --git a/src/simulator/simulator.h b/src/simulator/simulator.h index 2873b0fb8..a0c5d58dc 100644 --- a/src/simulator/simulator.h +++ b/src/simulator/simulator.h @@ -770,6 +770,12 @@ public: * to delegate events to their own subclass of the EventImpl base class. */ static EventId ScheduleNow (const Ptr &event); + + /** + * \returns the system id for this simulator; used for + * MPI or other distributed simulations + */ + static uint32_t GetSystemId (void); private: Simulator (); ~Simulator (); diff --git a/src/wscript b/src/wscript index 10ee74d8f..2d9875775 100644 --- a/src/wscript +++ b/src/wscript @@ -50,6 +50,7 @@ all_modules = ( 'contrib/flow-monitor', 'applications/udp-client-server', 'devices/wimax', + 'mpi', ) def set_options(opt): diff --git a/wscript b/wscript index 44d76ce9d..702e607e2 100644 --- a/wscript +++ b/wscript @@ -195,6 +195,10 @@ def set_options(opt): help=('Compile NS-3 statically: works only on linux, without python'), dest='enable_static', action='store_true', default=False) + opt.add_option('--enable-mpi', + help=('Compile NS-3 with MPI and distributed simulation support'), + dest='enable_mpi', action='store_true', + default=False) opt.add_option('--doxygen-no-build', help=('Run doxygen to generate html documentation from source comments, ' 'but do not wait for ns-3 to finish the full build.'), @@ -319,6 +323,27 @@ def configure(conf): if Options.options.enable_modules: conf.env['NS3_ENABLED_MODULES'] = ['ns3-'+mod for mod in Options.options.enable_modules.split(',')] + # for MPI + conf.find_program('mpic++', var='MPI') + if Options.options.enable_mpi and conf.env['MPI']: + p = subprocess.Popen([conf.env['MPI'], '-showme:compile'], stdout=subprocess.PIPE) + flags = p.stdout.read().rstrip().split() + p.wait() + env.append_value("CXXFLAGS_MPI", flags) + + p = subprocess.Popen([conf.env['MPI'], '-showme:link'], stdout=subprocess.PIPE) + flags = p.stdout.read().rstrip().split() + p.wait() + env.append_value("LINKFLAGS_MPI", flags) + + env.append_value('CXXDEFINES', 'NS3_MPI') + conf.report_optional_feature("mpi", "MPI Support", True, '') + conf.env['ENABLE_MPI'] = True + else: + if Options.options.enable_mpi: + conf.report_optional_feature("mpi", "MPI Support", False, 'mpic++ not found') + else: + conf.report_optional_feature("mpi", "MPI Support", False, 'option --enable-mpi not selected') # for suid bits conf.find_program('sudo', var='SUDO')