Merge distributed simulation code
authorJosh Pelkey <jpelkey@gatech.edu>
Mon, 08 Mar 2010 21:07:31 -0500
changeset 6113 0ce37bf4f1c1
parent 6112 57ee810f08f3
child 6114 7410349be0f9
Merge distributed simulation code
CHANGES.html
RELEASE_NOTES
bindings/python/apidefs/gcc-ILP32/ns3_module_common.py
bindings/python/apidefs/gcc-ILP32/ns3_module_core.py
bindings/python/apidefs/gcc-ILP32/ns3_module_helper.py
bindings/python/apidefs/gcc-ILP32/ns3_module_mpi.py
bindings/python/apidefs/gcc-ILP32/ns3_module_point_to_point.py
bindings/python/apidefs/gcc-ILP32/ns3_module_simulator.py
bindings/python/apidefs/gcc-ILP32/ns3modulegen_generated.py
bindings/python/apidefs/gcc-LP64/ns3_module_common.py
bindings/python/apidefs/gcc-LP64/ns3_module_helper.py
bindings/python/apidefs/gcc-LP64/ns3_module_mpi.py
bindings/python/apidefs/gcc-LP64/ns3_module_point_to_point.py
bindings/python/apidefs/gcc-LP64/ns3_module_simulator.py
bindings/python/apidefs/gcc-LP64/ns3modulegen_generated.py
doc/manual/Makefile
doc/manual/distributed.texi
doc/manual/manual.texi
examples/mpi/nms-udp-nix.cc
examples/mpi/simple-distributed.cc
examples/mpi/third-distributed.cc
examples/mpi/waf
examples/mpi/wscript
src/common/buffer.cc
src/common/buffer.h
src/common/nix-vector.cc
src/common/nix-vector.h
src/common/packet-metadata-test.cc
src/common/packet-metadata.cc
src/common/packet-metadata.h
src/common/packet.cc
src/common/packet.h
src/devices/point-to-point/point-to-point-channel.cc
src/devices/point-to-point/point-to-point-channel.h
src/devices/point-to-point/point-to-point-remote-channel.cc
src/devices/point-to-point/point-to-point-remote-channel.h
src/devices/point-to-point/wscript
src/helper/node-container.cc
src/helper/node-container.h
src/helper/point-to-point-helper.cc
src/helper/point-to-point-helper.h
src/mpi/distributed-simulator-impl.cc
src/mpi/distributed-simulator-impl.h
src/mpi/mpi-interface.cc
src/mpi/mpi-interface.h
src/mpi/waf
src/mpi/wscript
src/routing/global-routing/global-route-manager-impl.cc
src/simulator/default-simulator-impl.cc
src/simulator/default-simulator-impl.h
src/simulator/realtime-simulator-impl.cc
src/simulator/realtime-simulator-impl.h
src/simulator/simulator-impl.h
src/simulator/simulator.cc
src/simulator/simulator.h
src/wscript
wscript
--- a/CHANGES.html	Mon Mar 08 15:24:22 2010 -0800
+++ b/CHANGES.html	Mon Mar 08 21:07:31 2010 -0500
@@ -49,6 +49,7 @@
 <h2>Changes to build system:</h2>
 
 <h2>New API:</h2>
+
 <ul>
 <li><b>WiMAX net device</b>: The developed WiMAX model attempts to provide an accurate MAC and
 PHY level implementation of the 802.16 specification with the Point-to-Multipoint (PMP) mode and the WirelessMAN-OFDM 
@@ -65,10 +66,22 @@
 the publicly visible attributes of the model.
 The helper API is defined in src/helper/wimax-helper.{cc,h}.
 Three examples containing some code that shows how to setup a 802.16 network are located under examples/wimax/ 
+
+<li><b>MPI Interface for distributed simulation:</b> Enables access
+to necessary MPI information such as MPI rank and size.
+
+<li><b>Point-to-point remote channel:</b> Enables point-to-point 
+connection between net-devices on different simulators, for use 
+with distributed simulation.
+
+<li><b>GetSystemId in simulator:</b> For use with distributed 
+simulation, GetSystemId returns zero by non-distributed 
+simulators.  For the distributed simulator, it returns the 
+MPI rank.
 </ul>
+
 <h2>Changes to existing API:</h2>
 <ul>
-</pre>
 <li><b>Tracing Helpers</b>: The organization of helpers for both pcap and ascii
 tracing, in devices and protocols, has been reworked.  Instead of each device 
 and protocol helper re-implementing trace enable methods, classes have been 
@@ -114,6 +127,52 @@
 </pre>
 
 
+<li><b>Serialization and Deserialization</b> in buffer, nix-vector, 
+packet-metadata, and packet has been modified to use raw character 
+buffers, rather than the Buffer class
+<pre>
++ uint32_t Buffer::GetSerializedSize (void) const;
++ uint32_t Buffer::Serialize (uint8_t* buffer, uint32_t maxSize) const;
++ uint32_t Buffer::Deserialize (uint8_t* buffer, uint32_t size); 
+
+- void NixVector::Serialize (Buffer::Iterator i, uint32_t size) const;
++ uint32_t NixVector::Serialize (uint32_t* buffer, uint32_t maxSize) const;
+- uint32_t NixVector::Deserialize (Buffer::Iterator i);
++ uint32_t NixVector::Deserialize (uint32_t* buffer, uint32_t size);
+
+- void PacketMetadata::Serialize (Buffer::Iterator i, uint32_t size) const;
++ uint32_t PacketMetadata::Serialize (uint8_t* buffer, uint32_t maxSize) const;
+- uint32_t PacketMetadata::Deserialize (Buffer::Iterator i);
++ uint32_t PacketMetadata::Deserialize (uint8_t* buffer, uint32_t size);
+
++ uint32_t Packet::GetSerializedSize (void) const;
+- Buffer Packet::Serialize (void) const;
++ uint32_t Packet::Serialize (uint8_t* buffer, uint32_t maxSize) const;
+- void Packet::Deserialize (Buffer buffer);
++ Packet::Packet (uint8_t const*buffer, uint32_t size, bool magic);
+</pre>
+<li><b>PacketMetadata uid</b> has been changed to a 64-bit value. The 
+lower 32 bits give the uid, while the upper 32-bits give the MPI rank 
+for distributed simulations. For non-distributed simulations, the 
+upper 32 bits are simply zero.
+<pre>
+- inline PacketMetadata (uint32_t uid, uint32_t size);
++ inline PacketMetadata (uint64_t uid, uint32_t size);
+- uint32_t GetUid (void) const;
++ uint64_t GetUid (void) const;
+- PacketMetadata::PacketMetadata (uint32_t uid, uint32_t size);
++ PacketMetadata::PacketMetadata (uint64_t uid, uint32_t size); 
+
+- uint32_t Packet::GetUid (void) const;
++ uint64_t Packet::GetUid (void) const;
+</pre>
+</ul>
+
+<h2>Changed behavior:</h2>
+<ul>
+
+</ul>
+
 <hr>
 <h1>Changes from ns-3.6 to ns-3.7</h1>
 
--- a/RELEASE_NOTES	Mon Mar 08 15:24:22 2010 -0800
+++ b/RELEASE_NOTES	Mon Mar 08 21:07:31 2010 -0500
@@ -36,7 +36,8 @@
 -------------------------
   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) 
 
--- a/bindings/python/apidefs/gcc-ILP32/ns3_module_common.py	Mon Mar 08 15:24:22 2010 -0800
+++ b/bindings/python/apidefs/gcc-ILP32/ns3_module_common.py	Mon Mar 08 21:07:31 2010 -0500
@@ -265,6 +265,10 @@
                    '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 @@
                    '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 @@
     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 @@
     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 @@
                    '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 @@
                    '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 @@
     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 @@
                    '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 @@
                    '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 @@
     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<ns3::Packet const> packet) [member function]
@@ -1633,10 +1649,6 @@
                    '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 @@
                    '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 @@
     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<ns3::NixVector> arg0) [member function]
     cls.add_method('SetNixVector', 
--- a/bindings/python/apidefs/gcc-ILP32/ns3_module_core.py	Mon Mar 08 15:24:22 2010 -0800
+++ b/bindings/python/apidefs/gcc-ILP32/ns3_module_core.py	Mon Mar 08 21:07:31 2010 -0500
@@ -3075,7 +3075,7 @@
     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', 
--- a/bindings/python/apidefs/gcc-ILP32/ns3_module_helper.py	Mon Mar 08 15:24:22 2010 -0800
+++ b/bindings/python/apidefs/gcc-ILP32/ns3_module_helper.py	Mon Mar 08 21:07:31 2010 -0500
@@ -1202,6 +1202,10 @@
     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<const ns3::Ptr<ns3::Node>*,std::vector<ns3::Ptr<ns3::Node>, std::allocator<ns3::Ptr<ns3::Node> > > > 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 > > >', 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/apidefs/gcc-ILP32/ns3_module_mpi.py	Mon Mar 08 21:07:31 2010 -0500
@@ -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<ns3::Packet> 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
+
--- a/bindings/python/apidefs/gcc-ILP32/ns3_module_point_to_point.py	Mon Mar 08 15:24:22 2010 -0800
+++ b/bindings/python/apidefs/gcc-ILP32/ns3_module_point_to_point.py	Mon Mar 08 21:07:31 2010 -0500
@@ -9,6 +9,8 @@
     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 @@
     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 @@
     ## point-to-point-channel.h: bool ns3::PointToPointChannel::TransmitStart(ns3::Ptr<ns3::Packet> p, ns3::Ptr<ns3::PointToPointNetDevice> 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::PointToPointNetDevice> 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::PointToPointNetDevice> 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 @@
                    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<ns3::Packet> p, ns3::Ptr<ns3::PointToPointNetDevice> 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)
--- a/bindings/python/apidefs/gcc-ILP32/ns3_module_simulator.py	Mon Mar 08 15:24:22 2010 -0800
+++ b/bindings/python/apidefs/gcc-ILP32/ns3_module_simulator.py	Mon Mar 08 21:07:31 2010 -0500
@@ -317,6 +317,11 @@
                    '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 @@
                    '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 @@
                    '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 @@
                    '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', 
--- a/bindings/python/apidefs/gcc-ILP32/ns3modulegen_generated.py	Mon Mar 08 15:24:22 2010 -0800
+++ b/bindings/python/apidefs/gcc-ILP32/ns3modulegen_generated.py	Mon Mar 08 21:07:31 2010 -0500
@@ -17,6 +17,7 @@
 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 @@
         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 @@
         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 @@
         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)
     
--- a/bindings/python/apidefs/gcc-LP64/ns3_module_common.py	Mon Mar 08 15:24:22 2010 -0800
+++ b/bindings/python/apidefs/gcc-LP64/ns3_module_common.py	Mon Mar 08 21:07:31 2010 -0500
@@ -265,6 +265,10 @@
                    '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 @@
                    '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 @@
     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 @@
     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 @@
                    '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 @@
                    '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 @@
     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 @@
                    '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 @@
                    '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 @@
     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<ns3::Packet const> packet) [member function]
@@ -1633,10 +1649,6 @@
                    '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 @@
                    '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 @@
     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<ns3::NixVector> arg0) [member function]
     cls.add_method('SetNixVector', 
--- a/bindings/python/apidefs/gcc-LP64/ns3_module_helper.py	Mon Mar 08 15:24:22 2010 -0800
+++ b/bindings/python/apidefs/gcc-LP64/ns3_module_helper.py	Mon Mar 08 21:07:31 2010 -0500
@@ -1202,6 +1202,10 @@
     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<const ns3::Ptr<ns3::Node>*,std::vector<ns3::Ptr<ns3::Node>, std::allocator<ns3::Ptr<ns3::Node> > > > 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 > > >', 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/apidefs/gcc-LP64/ns3_module_mpi.py	Mon Mar 08 21:07:31 2010 -0500
@@ -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<ns3::Packet> 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
+
--- a/bindings/python/apidefs/gcc-LP64/ns3_module_point_to_point.py	Mon Mar 08 15:24:22 2010 -0800
+++ b/bindings/python/apidefs/gcc-LP64/ns3_module_point_to_point.py	Mon Mar 08 21:07:31 2010 -0500
@@ -9,6 +9,8 @@
     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 @@
     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 @@
     ## point-to-point-channel.h: bool ns3::PointToPointChannel::TransmitStart(ns3::Ptr<ns3::Packet> p, ns3::Ptr<ns3::PointToPointNetDevice> 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::PointToPointNetDevice> 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::PointToPointNetDevice> 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 @@
                    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<ns3::Packet> p, ns3::Ptr<ns3::PointToPointNetDevice> 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)
--- a/bindings/python/apidefs/gcc-LP64/ns3_module_simulator.py	Mon Mar 08 15:24:22 2010 -0800
+++ b/bindings/python/apidefs/gcc-LP64/ns3_module_simulator.py	Mon Mar 08 21:07:31 2010 -0500
@@ -317,6 +317,11 @@
                    '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 @@
                    '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 @@
                    '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 @@
                    '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', 
--- a/bindings/python/apidefs/gcc-LP64/ns3modulegen_generated.py	Mon Mar 08 15:24:22 2010 -0800
+++ b/bindings/python/apidefs/gcc-LP64/ns3modulegen_generated.py	Mon Mar 08 21:07:31 2010 -0500
@@ -17,6 +17,7 @@
 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 @@
         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 @@
         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 @@
         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)
     
--- a/doc/manual/Makefile	Mon Mar 08 15:24:22 2010 -0800
+++ b/doc/manual/Makefile	Mon Mar 08 21:07:31 2010 -0500
@@ -58,6 +58,7 @@
 	python.texi \
 	random.texi \
 	realtime.texi \
+  distributed.texi \
 	routing.texi \
 	simple.texi \
 	sockets.texi \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/manual/distributed.texi	Mon Mar 08 21:07:31 2010 -0500
@@ -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<Node> node1 = CreateObject<Node> (0); // Create node1 with system id 0
+Ptr<Node> node2 = CreateObject<Node> (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
--- a/doc/manual/manual.texi	Mon Mar 08 15:24:22 2010 -0800
+++ b/doc/manual/manual.texi	Mon Mar 08 21:07:31 2010 -0500
@@ -96,6 +96,7 @@
 * Logging::
 * Tracing::
 * RealTime::
+* Distributed::
 * Packets::
 * Helpers::
 * Python::
@@ -140,6 +141,7 @@
 @include log.texi
 @include tracing.texi
 @include realtime.texi
+@include distributed.texi
 @include packets.texi
 @include helpers.texi
 @include python.texi
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/mpi/nms-udp-nix.cc	Mon Mar 08 21:07:31 2010 -0500
@@ -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 <park@gtech-systems.com>
+ *
+ * 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 <jpelkey@gatech.edu>
+ *
+ * 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 <cstdlib>
+#include <sys/time.h>
+#include <fstream>
+
+#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 <mpi.h>
+#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> node = CreateObject<Node> (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> node = CreateObject<Node> (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> node = CreateObject<Node> (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> node = CreateObject<Node> (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> node = CreateObject<Node> (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> node = CreateObject<Node> (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<Node> node1 = CreateObject<Node> (z % systemCount);
+      Ptr<Node> node2 = CreateObject<Node> (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
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/mpi/simple-distributed.cc	Mon Mar 08 21:07:31 2010 -0500
@@ -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 <mpi.h>
+#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<Node> routerNode1 = CreateObject<Node> (0);
+  Ptr<Node> routerNode2 = CreateObject<Node> (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
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/mpi/third-distributed.cc	Mon Mar 08 21:07:31 2010 -0500
@@ -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 <mpi.h>
+#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<Node> p2pNode1 = CreateObject<Node> (0); // Create node with rank 0
+  Ptr<Node> p2pNode2 = CreateObject<Node> (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
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/mpi/waf	Mon Mar 08 21:07:31 2010 -0500
@@ -0,0 +1,1 @@
+exec "`dirname "$0"`"/../../waf "$@"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/mpi/wscript	Mon Mar 08 21:07:31 2010 -0500
@@ -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'
--- a/src/common/buffer.cc	Mon Mar 08 15:24:22 2010 -0800
+++ b/src/common/buffer.cc	Mon Mar 08 21:07:31 2010 -0500
@@ -268,6 +268,15 @@
   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 @@
   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
 {
--- a/src/common/buffer.h	Mon Mar 08 15:24:22 2010 -0800
+++ b/src/common/buffer.h	Mon Mar 08 21:07:31 2010 -0500
@@ -476,6 +476,33 @@
 
   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 @@
   Buffer &operator = (Buffer const &o);
   Buffer ();
   Buffer (uint32_t dataSize);
+  Buffer (uint32_t dataSize, bool initialize);
   ~Buffer ();
 private:
 
--- a/src/common/nix-vector.cc	Mon Mar 08 15:24:22 2010 -0800
+++ b/src/common/nix-vector.cc	Mon Mar 08 21:07:31 2010 -0500
@@ -222,74 +222,105 @@
 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;
+    }
+
+  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_currentVectorBitSize = 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;
+        }
+    }
 
-  NS_ASSERT (size >= 4);
-  m_totalBitSize = i.ReadU32 ();
-  size -=4;
+  // 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
--- a/src/common/nix-vector.h	Mon Mar 08 15:24:22 2010 -0800
+++ b/src/common/nix-vector.h	Mon Mar 08 21:07:31 2010 -0500
@@ -105,17 +105,27 @@
      */
     uint32_t GetSerializedSize (void) const;
     /**
-     * \param i Buffer iterator for writing
+     * \return zero if buffer not large enough
+     *
+     * \param buffer points to serialization buffer
      *
-     * \param size number of bytes to write
+     * \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 buffer points to buffer for deserialization
      *
-     * \param i Buffer iterator for reading
+     * \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
      *
--- a/src/common/packet-metadata-test.cc	Mon Mar 08 15:24:22 2010 -0800
+++ b/src/common/packet-metadata-test.cc	Mon Mar 08 21:07:31 2010 -0500
@@ -353,42 +353,43 @@
   return false;
 }
 
-#define ADD_HEADER(p, n)                        \
-  {                                             \
-    HistoryHeader<n> header;                    \
-    p->AddHeader (header);                      \
+#define ADD_HEADER(p, n)                                           \
+  {                                                                \
+    HistoryHeader<n> header;                                       \
+    p->AddHeader (header);                                         \
   }
-#define ADD_TRAILER(p, n)                       \
-  {                                             \
-    HistoryTrailer<n> trailer;                  \
-    p->AddTrailer (trailer);                    \
+#define ADD_TRAILER(p, n)                                          \
+  {                                                                \
+    HistoryTrailer<n> trailer;                                     \
+    p->AddTrailer (trailer);                                       \
   }
-#define REM_HEADER(p, n)                        \
-  {                                             \
-    HistoryHeader<n> header;                    \
-    p->RemoveHeader (header);                   \
+#define REM_HEADER(p, n)                                           \
+  {                                                                \
+    HistoryHeader<n> header;                                       \
+    p->RemoveHeader (header);                                      \
   }
-#define REM_TRAILER(p, n)                       \
-  {                                             \
-    HistoryTrailer<n> trailer;                  \
-    p->RemoveTrailer (trailer);                 \
+#define REM_TRAILER(p, n)                                          \
+  {                                                                \
+    HistoryTrailer<n> trailer;                                     \
+    p->RemoveTrailer (trailer);                                    \
   }
-#define CHECK_HISTORY(p, ...)                   \
-  {                                             \
-    if (!CheckHistory (p, __FILE__,             \
-                      __LINE__, __VA_ARGS__))   \
-      {                                         \
-        result = false;                         \
-      }                                         \
-    Buffer buffer;                              \
-    buffer = p->Serialize ();                   \
-    Ptr<Packet> otherPacket = Create<Packet> ();\
-    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<Packet> otherPacket = Create<Packet> (buffer, size, true); \
+    delete [] buffer;                                              \
+    if (!CheckHistory (otherPacket, __FILE__,                      \
+                      __LINE__, __VA_ARGS__))                      \
+      {                                                            \
+        result = false;                                            \
+      }                                                            \
   }
 
 
@@ -413,6 +414,7 @@
   ADD_TRAILER (p, 100);
   CHECK_HISTORY (p, 2, 10, 100);
 
+  
   p = Create<Packet> (10);
   ADD_HEADER (p, 1);
   ADD_HEADER (p, 2);
--- a/src/common/packet-metadata.cc	Mon Mar 08 15:24:22 2010 -0800
+++ b/src/common/packet-metadata.cc	Mon Mar 08 21:07:31 2010 -0500
@@ -959,7 +959,7 @@
   return totalSize;
 }
 
-uint32_t 
+uint64_t 
 PacketMetadata::GetUid (void) const
 {
   return m_packetUid;
@@ -1055,11 +1055,18 @@
 {
   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 @@
           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 @@
     }
   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="<<item.size<<", chunkUid="<<item.chunkUid<<
         ", fragmentStart="<<extraItem.fragmentStart<<", fragmentEnd="<<
         extraItem.fragmentEnd<< ", packetUid="<<extraItem.packetUid);
+
       uint32_t uid = (item.typeUid & 0xfffffffe) >> 1;
       if (uid != 0)
         {
           TypeId tid;
           tid.SetUid (uid);
           std::string uidString = tid.GetName ();
-          i.WriteU32 (uidString.size ());
-          bytesWritten += 4;
-          i.Write ((uint8_t *)uidString.c_str (), uidString.size ());
-          bytesWritten += uidString.size ();
+          uint32_t uidStringSize = uidString.size ();
+          buffer = AddToRawU32 (uidStringSize, start, buffer, maxSize);
+          if (buffer == 0) 
+            {
+              return 0;
+            }
+          buffer = AddToRaw ((uint8_t *)uidString.c_str (), 
+                             uidStringSize, start, buffer, maxSize);
+          if (buffer == 0) 
+            {
+              return 0;
+            }
         }
       else
         {
-          i.WriteU32 (0);
-          bytesWritten += 4;
+          buffer = AddToRawU32 (0, start, buffer, maxSize);
+          if (buffer == 0) 
+            {
+              return 0;
+            }
         }
+
       uint8_t isBig = item.typeUid & 0x1;
-      i.WriteU8 (isBig);
-      bytesWritten += 1;
-      i.WriteU32 (item.size);
-      bytesWritten += 4;
-      i.WriteU16 (item.chunkUid);
-      bytesWritten += 2;
-      i.WriteU32 (extraItem.fragmentStart);
-      bytesWritten += 4;
-      i.WriteU32 (extraItem.fragmentEnd);
-      bytesWritten += 4;
-      i.WriteU32 (extraItem.packetUid);
-      bytesWritten += 4;
+      buffer = AddToRawU8 (isBig, start, buffer, maxSize);
+      if (buffer == 0) 
+        {
+          return 0;
+        }
+
+      buffer = AddToRawU32 (item.size, start, buffer, maxSize);
+      if (buffer == 0) 
+        {
+          return 0;
+        }
+
+      buffer = AddToRawU16 (item.chunkUid, start, buffer, maxSize);
+      if (buffer == 0) 
+        {
+          return 0;
+        }
+
+      buffer = AddToRawU32 (extraItem.fragmentStart, start, buffer, maxSize);
+      if (buffer == 0) 
+        {
+          return 0;
+        }
+
+      buffer = AddToRawU32 (extraItem.fragmentEnd, start, buffer, maxSize);
+      if (buffer == 0) 
+        {
+          return 0;
+        }
+
+      buffer = AddToRawU64 (extraItem.packetUid, start, buffer, maxSize);
+      if (buffer == 0) 
+        {
+          return 0;
+        }
+
       if (current == m_tail)
         {
           break;
@@ -1141,21 +1191,28 @@
       NS_ASSERT (current != item.next);
       current = item.next;
     }
-  NS_ASSERT (bytesWritten == size);
+
+  NS_ASSERT ((uint32_t)(buffer - start) == maxSize);
+  return 1;
 }
+
 uint32_t 
-PacketMetadata::Deserialize (Buffer::Iterator i)
+PacketMetadata::Deserialize (uint8_t* buffer, uint32_t size)
 {
   NS_LOG_FUNCTION (this);
+  uint8_t* start = buffer;
+  uint32_t desSize = size - 4;
+
+  buffer = ReadFromRawU64 (m_packetUid, start, buffer, size);
+  desSize -= 8;
+
   struct PacketMetadata::SmallItem item;
   struct PacketMetadata::ExtraItem extraItem;
-  uint32_t totalSize = i.ReadU32 ();
-  uint32_t size = totalSize;
-  size -= 4;
-  while (size > 0)
+  while (desSize > 0)
     {
-      uint32_t uidStringSize = i.ReadU32 ();
-      size -= 4;
+      uint32_t uidStringSize = 0;
+      buffer = ReadFromRawU32 (uidStringSize, start, buffer, size);
+      desSize -= 4;
       uint32_t uid;
       if (uidStringSize == 0)
         {
@@ -1167,25 +1224,28 @@
           std::string uidString;
           for (uint32_t j = 0; j < uidStringSize; j++)
             {
-              uidString.push_back (i.ReadU8 ());
-              size --;
+              uint8_t ch = 0;
+              buffer = ReadFromRawU8 (ch, start, buffer, size);
+              uidString.push_back (ch);
+              desSize --;
             }
           TypeId tid = TypeId::LookupByName (uidString);
           uid = tid.GetUid ();
         }
-      uint8_t isBig = i.ReadU8 ();
-      size --;
+      uint8_t isBig = 0;
+      buffer = ReadFromRawU8 (isBig, start, buffer, size);
+      desSize --;
       item.typeUid = (uid << 1) | isBig;
-      item.size = i.ReadU32 ();
-      size -= 4;
-      item.chunkUid = i.ReadU16 ();
-      size -= 2;
-      extraItem.fragmentStart = i.ReadU32 ();
-      size -= 4;
-      extraItem.fragmentEnd = i.ReadU32 ();
-      size -= 4;
-      extraItem.packetUid = i.ReadU32 ();
-      size -= 4;
+      buffer = ReadFromRawU32 (item.size, start, buffer, size);
+      desSize -= 4;
+      buffer = ReadFromRawU16 (item.chunkUid, start, buffer, size);
+      desSize -= 2;
+      buffer = ReadFromRawU32 (extraItem.fragmentStart, start, buffer, size);
+      desSize -= 4;
+      buffer = ReadFromRawU32 (extraItem.fragmentEnd, start, buffer, size);
+      desSize -= 4;
+      buffer = ReadFromRawU64 (extraItem.packetUid, start, buffer, size);
+      desSize -= 8;
       NS_LOG_LOGIC ("size=" << size << ", typeUid="<<item.typeUid <<
         ", size="<<item.size<<", chunkUid="<<item.chunkUid<<
         ", fragmentStart="<<extraItem.fragmentStart<<", fragmentEnd="<<
@@ -1193,8 +1253,144 @@
       uint32_t tmp = AddBig (0xffff, m_tail, &item, &extraItem);
       UpdateTail (tmp);
     }
-  NS_ASSERT (size == 0);
-  return totalSize;
+  NS_ASSERT (desSize == 0);
+  return (desSize !=0) ? 0 : 1;
+}
+
+uint8_t* 
+PacketMetadata::AddToRawU8 (const uint8_t& data,
+                            uint8_t* start,
+                            uint8_t* current,
+                            uint32_t maxSize)
+{
+  // First check buffer overflow
+  if ((uint32_t)((current + sizeof (uint8_t) - start)) > maxSize) 
+    {
+      return 0;
+    }
+  memcpy (current, &data, sizeof (uint8_t));
+  return current + sizeof (uint8_t);
+}
+
+uint8_t* 
+PacketMetadata::AddToRawU16 (const uint16_t& data,
+                             uint8_t* start,
+                             uint8_t* current,
+                             uint32_t maxSize)
+{
+  // First check buffer overflow
+  if ((uint32_t)((current + sizeof (uint16_t) - start)) > maxSize) 
+    {
+      return 0;
+    }
+  memcpy (current, &data, sizeof (uint16_t));
+  return current + sizeof (uint16_t);
+}
+
+uint8_t* 
+PacketMetadata::AddToRawU32 (const uint32_t& data,
+                             uint8_t* start,
+                             uint8_t* current,
+                             uint32_t maxSize)
+{
+  // First check buffer overflow
+  if ((uint32_t)((current + sizeof (uint32_t) - start)) > maxSize) 
+    {
+      return 0;
+    }
+  memcpy (current, &data, sizeof (uint32_t));
+  return current + sizeof (uint32_t);
+}
+
+uint8_t* 
+PacketMetadata::AddToRawU64 (const uint64_t& data,
+                             uint8_t* start,
+                             uint8_t* current,
+                             uint32_t maxSize)
+{
+  // First check buffer overflow
+  if ((uint32_t)((current + sizeof (uint64_t) - start)) > maxSize) 
+    {
+      return 0;
+    }
+  memcpy (current, &data, sizeof (uint64_t));
+  return current + sizeof (uint64_t);
+}
+  
+uint8_t* 
+PacketMetadata::AddToRaw (const uint8_t* data,
+                          uint32_t dataSize,
+                          uint8_t* start,
+                          uint8_t* current,
+                          uint32_t maxSize)
+{ 
+  // First check buffer overflow
+  if ((uint32_t)((current + dataSize - start)) > maxSize) 
+    {
+      return 0;
+    }
+  memcpy (current, data, dataSize);
+  return current + dataSize;
+}
+  
+uint8_t* 
+PacketMetadata::ReadFromRawU8 (uint8_t& data,
+                               uint8_t* start,
+                               uint8_t* current,
+                               uint32_t maxSize)
+{ 
+  // First check buffer underflow
+  if ((uint32_t)((current + sizeof (uint8_t) - start)) > maxSize) 
+    {
+      return 0;
+    }
+  memcpy(&data, current, sizeof (uint8_t));
+  return current + sizeof (uint8_t);
+}
+
+uint8_t* 
+PacketMetadata::ReadFromRawU16 (uint16_t& data,
+                                uint8_t* start,
+                                uint8_t* current,
+                                uint32_t maxSize)
+{ 
+  // First check buffer underflow
+  if ((uint32_t)((current + sizeof (uint16_t) - start)) > maxSize) 
+    {
+      return 0;
+    }
+  memcpy(&data, current, sizeof (uint16_t));
+  return current + sizeof (uint16_t);
+}
+
+uint8_t* 
+PacketMetadata::ReadFromRawU32 (uint32_t& data,
+                                uint8_t* start,
+                                uint8_t* current,
+                                uint32_t maxSize)
+{ 
+  // First check buffer underflow
+  if ((uint32_t)((current + sizeof (uint32_t) - start)) > maxSize) 
+    {
+      return 0;
+    }
+  memcpy(&data, current, sizeof (uint32_t));
+  return current + sizeof (uint32_t);
+}
+
+uint8_t* 
+PacketMetadata::ReadFromRawU64 (uint64_t& data,
+                                uint8_t* start,
+                                uint8_t* current,
+                                uint32_t maxSize)
+{ 
+  // First check buffer underflow
+  if ((uint32_t)((current + sizeof (uint64_t) - start)) > maxSize) 
+    {
+      return 0;
+    }
+  memcpy(&data, current, sizeof (uint64_t));
+  return current + sizeof (uint64_t);
 }
 
 
--- a/src/common/packet-metadata.h	Mon Mar 08 15:24:22 2010 -0800
+++ b/src/common/packet-metadata.h	Mon Mar 08 21:07:31 2010 -0500
@@ -127,7 +127,7 @@
   static void Enable (void);
   static void EnableChecking (void);
 
-  inline PacketMetadata (uint32_t uid, uint32_t size);
+  inline PacketMetadata (uint64_t uid, uint32_t size);
   inline PacketMetadata (PacketMetadata const &o);
   inline PacketMetadata &operator = (PacketMetadata const& o);
   inline ~PacketMetadata ();
@@ -151,15 +151,63 @@
   void RemoveAtStart (uint32_t start);
   void RemoveAtEnd (uint32_t end);
 
-  uint32_t GetUid (void) const;
+  uint64_t GetUid (void) const;
 
   uint32_t GetSerializedSize (void) const;
-  void Serialize (Buffer::Iterator i, uint32_t size) const;
-  uint32_t Deserialize (Buffer::Iterator i);
 
   ItemIterator BeginItem (Buffer buffer) const;
 
+  // Serialization to/from raw uint8_t*
+  uint32_t Serialize   (uint8_t* buffer, uint32_t maxSize) const;
+  uint32_t Deserialize (uint8_t* buffer, uint32_t size);
+  
 private:
+  // Helper for the raw serilization/deserialization
+  static uint8_t* AddToRawU8 (const uint8_t& data,
+                              uint8_t* start,
+                              uint8_t* current,
+                              uint32_t maxSize);
+
+  static uint8_t* AddToRawU16 (const uint16_t& data,
+                               uint8_t* start,
+                               uint8_t* current,
+                               uint32_t maxSize);
+
+  static uint8_t* AddToRawU32 (const uint32_t& data,
+                               uint8_t* start,
+                               uint8_t* current,
+                               uint32_t maxSize);
+
+  static uint8_t* AddToRawU64 (const uint64_t& data,
+                               uint8_t* start,
+                               uint8_t* current,
+                               uint32_t maxSize);
+
+  static uint8_t* AddToRaw (const uint8_t* data,
+                            uint32_t dataSize,
+                            uint8_t* start,
+                            uint8_t* current,
+                            uint32_t maxSize);
+  
+  static uint8_t* ReadFromRawU8 (uint8_t& data,
+                                 uint8_t* start,
+                                 uint8_t* current,
+                                 uint32_t maxSize);
+
+  static uint8_t* ReadFromRawU16 (uint16_t& data,
+                                  uint8_t* start,
+                                  uint8_t* current,
+                                  uint32_t maxSize);
+
+  static uint8_t* ReadFromRawU32 (uint32_t& data,
+                                  uint8_t* start,
+                                  uint8_t* current,
+                                  uint32_t maxSize);
+
+  static uint8_t* ReadFromRawU64 (uint64_t& data,
+                                  uint8_t* start,
+                                  uint8_t* current,
+                                  uint32_t maxSize);
   struct Data {
     /* number of references to this struct Data instance. */
     uint16_t m_count;
@@ -231,9 +279,9 @@
     /* the packetUid of the packet in which this header or trailer
        was first added. It could be different from the m_packetUid
        field if the user has aggregated multiple packets into one.
-       stored as a fixed-size 32 bit integer.
+       stored as a fixed-size 64 bit integer.
      */
-    uint32_t packetUid;
+    uint64_t packetUid;
   };
 
   class DataFreeList : public std::vector<struct Data *>
@@ -297,15 +345,15 @@
   uint16_t m_head;
   uint16_t m_tail;
   uint16_t m_used;
-  uint32_t m_packetUid;
+  uint64_t m_packetUid;
 };
 
 }; // namespace ns3
 
 namespace ns3 {
 
-PacketMetadata::PacketMetadata (uint32_t uid, uint32_t size)
-  : m_data (PacketMetadata::Create (10)),
+PacketMetadata::PacketMetadata (uint64_t uid, uint32_t size)
+  : m_data (m_data = PacketMetadata::Create (10)),
     m_head (0xffff),
     m_tail (0xffff),
     m_used (0),
--- a/src/common/packet.cc	Mon Mar 08 15:24:22 2010 -0800
+++ b/src/common/packet.cc	Mon Mar 08 21:07:31 2010 -0500
@@ -20,6 +20,7 @@
 #include "packet.h"
 #include "ns3/assert.h"
 #include "ns3/log.h"
+#include "ns3/simulator.h"
 #include "ns3/test.h"
 #include <string>
 #include <stdarg.h>
@@ -125,7 +126,7 @@
   : 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 @@
   : 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 @@
   return m_buffer.CopyData (os, size);
 }
 
-uint32_t 
+uint64_t 
 Packet::GetUid (void) const
 {
   return m_metadata.GetUid ();
@@ -532,48 +544,197 @@
   PacketMetadata::EnableChecking ();
 }
 
-Buffer 
-Packet::Serialize (void) const
+uint32_t Packet::GetSerializedSize (void) const
+{
+  uint32_t size = 0;
+
+  if (m_nixVector)
+    {
+      // increment total size by the size of the nix-vector
+      // ensuring 4-byte boundary
+      size += ((m_nixVector->GetSerializedSize () + 3) & (~3));
+
+      // 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
+  //size += m_tags.GetSerializedSize ();
+
+  // 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;
+}
+  
+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 buffer;
-  uint32_t reserve;
+
+  uint32_t* p = (uint32_t*)buffer;
 
-  // write metadata
-  reserve = m_metadata.GetSerializedSize ();
-  buffer.AddAtStart (reserve);
-  m_metadata.Serialize (buffer.Begin (), reserve);
+  // 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);
 
-  // write tags
-  //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 ());
-
-  return tmp;
-}
-void 
-Packet::Deserialize (Buffer buffer)
-{
-  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);
-
+  if (nixSize > 4)
+  {
+    Ptr<NixVector> nix = CreateObject<NixVector> ();
+    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 @@
   //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 
--- a/src/common/packet.h	Mon Mar 08 15:24:22 2010 -0800
+++ b/src/common/packet.h	Mon Mar 08 21:07:31 2010 -0500
@@ -222,6 +222,17 @@
    */
   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
    * buffer is untouched.
@@ -379,7 +390,7 @@
    * \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 @@
   static void EnableChecking (void);
 
   /**
-   * \returns a byte buffer
-   *
-   * 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).
+   * For packet serializtion, the total size is checked 
+   * in order to determine the size of the buffer 
+   * required for serialization
    *
-   * 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
-   *
-   * 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.
+  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 will trigger calls to the Deserialize method
-   * of each tag stored in this packet.
+   * A packet is completely serialized and placed into the raw byte buffer
    *
-   * 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 @@
 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;
--- a/src/devices/point-to-point/point-to-point-channel.cc	Mon Mar 08 15:24:22 2010 -0800
+++ b/src/devices/point-to-point/point-to-point-channel.cc	Mon Mar 08 21:07:31 2010 -0500
@@ -124,4 +124,30 @@
   return GetPointToPointDevice (i);
 }
 
+Time
+PointToPointChannel::GetDelay (void) const
+{
+  return m_delay;
+}
+
+Ptr<PointToPointNetDevice>
+PointToPointChannel::GetSource (uint32_t i) const
+{
+  return m_link[i].m_src;
+}
+
+Ptr<PointToPointNetDevice>
+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
--- a/src/devices/point-to-point/point-to-point-channel.h	Mon Mar 08 15:24:22 2010 -0800
+++ b/src/devices/point-to-point/point-to-point-channel.h	Mon Mar 08 21:07:31 2010 -0500
@@ -69,7 +69,7 @@
    * \param txTime Transmit time to apply
    * \returns true if successful (currently always true)
    */
-  bool TransmitStart (Ptr<Packet> p, Ptr<PointToPointNetDevice> src, Time txTime);
+  virtual bool TransmitStart (Ptr<Packet> p, Ptr<PointToPointNetDevice> src, Time txTime);
 
   /**
    * \brief Get number of devices on this channel
@@ -91,6 +91,35 @@
    */
   virtual Ptr<NetDevice> 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<PointToPointNetDevice> 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<PointToPointNetDevice> GetDestination (uint32_t i) const;
+
 private:
   // Each point to point link has exactly two net devices
   static const int N_DEVICES = 2;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/point-to-point/point-to-point-remote-channel.cc	Mon Mar 08 21:07:31 2010 -0500
@@ -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 <riley@ece.gatech.edu>
+ */
+
+#include <iostream>
+
+#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<PointToPointChannel> ()
+    .AddConstructor<PointToPointRemoteChannel> ()
+  ;
+  return tid;
+}
+
+PointToPointRemoteChannel::PointToPointRemoteChannel ()
+{
+}
+
+PointToPointRemoteChannel::~PointToPointRemoteChannel ()
+{
+}
+
+bool
+PointToPointRemoteChannel::TransmitStart (
+  Ptr<Packet> p,
+  Ptr<PointToPointNetDevice> 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<PointToPointNetDevice> 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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/point-to-point/point-to-point-remote-channel.h	Mon Mar 08 21:07:31 2010 -0500
@@ -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 <riley@ece.gatech.edu>
+ */
+
+// 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<Packet> p, Ptr<PointToPointNetDevice> src, Time txTime);
+};
+}
+
+#endif
+
+
--- a/src/devices/point-to-point/wscript	Mon Mar 08 15:24:22 2010 -0800
+++ b/src/devices/point-to-point/wscript	Mon Mar 08 21:07:31 2010 -0500
@@ -6,6 +6,7 @@
     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 @@
     headers.source = [
         'point-to-point-net-device.h',
         'point-to-point-channel.h',
+        'point-to-point-remote-channel.h',
         'ppp-header.h',
         ]
 
--- a/src/helper/node-container.cc	Mon Mar 08 15:24:22 2010 -0800
+++ b/src/helper/node-container.cc	Mon Mar 08 21:07:31 2010 -0500
@@ -97,6 +97,14 @@
     }
 }
 void 
+NodeContainer::Create (uint32_t n, uint32_t systemId)
+{
+  for (uint32_t i = 0; i < n; i++)
+    {
+      m_nodes.push_back (CreateObject<Node> (systemId));
+    }
+}
+void 
 NodeContainer::Add (NodeContainer other)
 {
   for (Iterator i = other.Begin (); i != other.End (); i++)
--- a/src/helper/node-container.h	Mon Mar 08 15:24:22 2010 -0800
+++ b/src/helper/node-container.h	Mon Mar 08 21:07:31 2010 -0500
@@ -237,6 +237,20 @@
   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.
    *
--- a/src/helper/point-to-point-helper.cc	Mon Mar 08 15:24:22 2010 -0800
+++ b/src/helper/point-to-point-helper.cc	Mon Mar 08 21:07:31 2010 -0500
@@ -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 @@
   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 @@
 PointToPointHelper::SetChannelAttribute (std::string n1, const AttributeValue &v1)
 {
   m_channelFactory.Set (n1, v1);
+  m_remoteChannelFactory.Set (n1, v1);
 }
 
 void 
@@ -223,7 +227,30 @@
   b->AddDevice (devB);
   Ptr<Queue> queueB = m_queueFactory.Create<Queue> ();
   devB->SetQueue (queueB);
-  Ptr<PointToPointChannel> channel = m_channelFactory.Create<PointToPointChannel> ();
+  // 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<PointToPointChannel> 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<PointToPointChannel> ();
+    }
+  else
+    {
+      channel = m_remoteChannelFactory.Create<PointToPointRemoteChannel> ();
+    }
+    
   devA->Attach (channel);
   devB->Attach (channel);
   container.Add (devA);
--- a/src/helper/point-to-point-helper.h	Mon Mar 08 15:24:22 2010 -0800
+++ b/src/helper/point-to-point-helper.h	Mon Mar 08 21:07:31 2010 -0500
@@ -116,7 +116,9 @@
    * \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<Node> a, Ptr<Node> b);
 
@@ -177,6 +179,7 @@
 
   ObjectFactory m_queueFactory;
   ObjectFactory m_channelFactory;
+  ObjectFactory m_remoteChannelFactory;
   ObjectFactory m_deviceFactory;
 };
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mpi/distributed-simulator-impl.cc	Mon Mar 08 21:07:31 2010 -0500
@@ -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 <riley@ece.gatech.edu>
+ */
+
+#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 <math.h>
+
+#ifdef NS3_MPI
+#include <mpi.h>
+#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<Object> ()
+    .AddConstructor<DistributedSimulatorImpl> ()
+  ;
+  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<EventImpl> 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<NetDevice> localNetDevice = (*iter)->GetDevice (i);
+              // only works for p2p links currently
+              if (!localNetDevice->IsPointToPoint ())
+                {
+                  continue;
+                }
+              Ptr<Channel> channel = localNetDevice->GetChannel ();
+              if (channel == 0)
+                {
+                  continue;
+                }
+
+              // grab the adjacent node
+              Ptr<Node> 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> scheduler = schedulerFactory.Create<Scheduler> ();
+
+  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<EventImpl> (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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mpi/distributed-simulator-impl.h	Mon Mar 08 21:07:31 2010 -0500
@@ -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 <riley@ece.gatech.edu>
+ */
+
+#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 <list>
+
+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<EventId> DestroyEvents;
+
+  DestroyEvents m_destroyEvents;
+  bool m_stop;
+  Ptr<Scheduler> 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 */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mpi/mpi-interface.cc	Mon Mar 08 21:07:31 2010 -0500
@@ -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 <riley@ece.gatech.edu>
+ */
+
+// This object contains static methods that provide an easy interface
+// to the necessary MPI information.
+
+#include <iostream>
+#include <iomanip>
+#include <list>
+
+#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 <mpi.h>
+#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<SentBuffer> 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<Packet> p, const Time& rxTime, uint32_t node, uint32_t dev)
+{
+#ifdef NS3_MPI
+  SentBuffer sendBuf;
+  m_pendingTx.push_back (sendBuf);
+  std::list<SentBuffer>::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<Node> 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<Packet> p = Create<Packet> ((uint8_t*)pData, count, true);
+
+      // Find the correct node/device to schedule receive event
+      Ptr<Node> pNode = NodeList::GetNode (node);
+      uint32_t nDevices = pNode->GetNDevices ();
+      Ptr<PointToPointNetDevice> pDev = 0;
+      for (uint32_t i = 0; i < nDevices; ++i)
+        {
+          Ptr<NetDevice> pThisDev = pNode->GetDevice (i);
+          if (pThisDev->GetIfIndex () == dev)
+            {
+              pDev = DynamicCast<PointToPointNetDevice> (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<SentBuffer>::iterator i = m_pendingTx.begin ();
+  while (i != m_pendingTx.end ())
+    {
+      MPI_Status status;
+      int flag = 0;
+      MPI_Test (i->GetRequest (), &flag, &status);
+      std::list<SentBuffer>::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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mpi/mpi-interface.h	Mon Mar 08 21:07:31 2010 -0500
@@ -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 <riley@ece.gatech.edu>
+ */
+
+// 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 <stdint.h>
+#include <list>
+
+#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<Packet>, 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<SentBuffer> m_pendingTx;  // List of pending non-blocking sends
+};
+
+} // namespace ns3
+
+#endif /* NS3_MPI_INTERFACE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mpi/waf	Mon Mar 08 21:07:31 2010 -0500
@@ -0,0 +1,1 @@
+exec "`dirname "$0"`"/../../waf "$@"
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mpi/wscript	Mon Mar 08 21:07:31 2010 -0500
@@ -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'
--- a/src/routing/global-routing/global-route-manager-impl.cc	Mon Mar 08 15:24:22 2010 -0800
+++ b/src/routing/global-routing/global-route-manager-impl.cc	Mon Mar 08 21:07:31 2010 -0500
@@ -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 @@
 //
       Ptr<GlobalRouter> rtr = 
         node->GetObject<GlobalRouter> ();
+
+      // 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.
--- a/src/simulator/default-simulator-impl.cc	Mon Mar 08 15:24:22 2010 -0800
+++ b/src/simulator/default-simulator-impl.cc	Mon Mar 08 21:07:31 2010 -0500
@@ -106,6 +106,13 @@
   m_events = scheduler;
 }
 
+// System ID for non-distributed simulation is always zero
+uint32_t 
+DefaultSimulatorImpl::GetSystemId (void) const
+{
+  return 0;
+}
+
 void
 DefaultSimulatorImpl::ProcessOneEvent (void)
 {
--- a/src/simulator/default-simulator-impl.h	Mon Mar 08 15:24:22 2010 -0800
+++ b/src/simulator/default-simulator-impl.h	Mon Mar 08 21:07:31 2010 -0500
@@ -57,6 +57,7 @@
   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:
--- a/src/simulator/realtime-simulator-impl.cc	Mon Mar 08 15:24:22 2010 -0800
+++ b/src/simulator/realtime-simulator-impl.cc	Mon Mar 08 21:07:31 2010 -0500
@@ -827,6 +827,13 @@
   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
 {
--- a/src/simulator/realtime-simulator-impl.h	Mon Mar 08 15:24:22 2010 -0800
+++ b/src/simulator/realtime-simulator-impl.h	Mon Mar 08 21:07:31 2010 -0500
@@ -69,6 +69,7 @@
   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);
--- a/src/simulator/simulator-impl.h	Mon Mar 08 15:24:22 2010 -0800
+++ b/src/simulator/simulator-impl.h	Mon Mar 08 21:07:31 2010 -0500
@@ -53,6 +53,7 @@
   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;
 };
 
--- a/src/simulator/simulator.cc	Mon Mar 08 15:24:22 2010 -0800
+++ b/src/simulator/simulator.cc	Mon Mar 08 21:07:31 2010 -0500
@@ -339,6 +339,21 @@
   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<SimulatorImpl> impl)
 {
--- a/src/simulator/simulator.h	Mon Mar 08 15:24:22 2010 -0800
+++ b/src/simulator/simulator.h	Mon Mar 08 21:07:31 2010 -0500
@@ -770,6 +770,12 @@
    * to delegate events to their own subclass of the EventImpl base class.
    */
   static EventId ScheduleNow (const Ptr<EventImpl> &event);
+
+  /**
+   * \returns the system id for this simulator; used for 
+   *          MPI or other distributed simulations
+   */
+  static uint32_t GetSystemId (void);
 private:
   Simulator ();
   ~Simulator ();
--- a/src/wscript	Mon Mar 08 15:24:22 2010 -0800
+++ b/src/wscript	Mon Mar 08 21:07:31 2010 -0500
@@ -50,6 +50,7 @@
     'contrib/flow-monitor',
     'applications/udp-client-server',
     'devices/wimax',
+    'mpi',
     )
 
 def set_options(opt):
--- a/wscript	Mon Mar 08 15:24:22 2010 -0800
+++ b/wscript	Mon Mar 08 21:07:31 2010 -0500
@@ -195,6 +195,10 @@
                    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 @@
     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')