--- a/bindings/python/ns3/__init__.py Tue Feb 03 09:32:24 2009 -0800
+++ b/bindings/python/ns3/__init__.py Tue Feb 03 10:40:16 2009 -0800
@@ -1,4 +1,7 @@
from _ns3 import *
+import atexit
+atexit.register(Simulator.Destroy)
+del atexit
--- a/doc/manual/Makefile Tue Feb 03 09:32:24 2009 -0800
+++ b/doc/manual/Makefile Tue Feb 03 10:40:16 2009 -0800
@@ -7,6 +7,7 @@
SPLIT = --split section
FIGURES = figures
+DOC_FIGURES = ..
VPATH = $(FIGURES)
IMAGES_EPS = \
@@ -18,7 +19,8 @@
$(FIGURES)/sockets-overview.eps \
$(FIGURES)/testbed.eps \
$(FIGURES)/emulated-channel.eps \
- $(FIGURES)/snir.eps
+ $(FIGURES)/snir.eps \
+ $(DOC_FIGURES)/WifiArchitecture.eps
IMAGES_PNG = ${IMAGES_EPS:.eps=.png}
IMAGES_PDF = ${IMAGES_EPS:.eps=.pdf}
@@ -31,6 +33,7 @@
callbacks.texi \
csma.texi \
emulation.texi \
+ new-models.texi \
node.texi \
objects.texi \
other.texi \
--- a/doc/manual/manual.texi Tue Feb 03 09:32:24 2009 -0800
+++ b/doc/manual/manual.texi Tue Feb 03 10:40:16 2009 -0800
@@ -92,6 +92,7 @@
* Wifi NetDevice::
* CSMA NetDevice::
* PointToPoint NetDevice::
+* Creating a new ns-3 model::
* Troubleshooting::
@end menu
@@ -111,6 +112,7 @@
@include csma.texi
@include point-to-point.texi
@c @include other.texi
+@include new-models.texi
@include troubleshoot.texi
@printindex cp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/manual/new-models.texi Tue Feb 03 10:40:16 2009 -0800
@@ -0,0 +1,578 @@
+@node Creating a new ns-3 model
+@chapter Creating a new ns-3 model
+
+This chapter walks through the design process of an @command{ns-3} model.
+In many research cases, users will not be satisfied to merely adapt
+existing models, but may want to extend the core of the simulator in
+a novel way. We will use the example of adding an ErrorModel to
+a simple @command{ns-3} link as a motivating example of how one might
+approach this problem and proceed through a design and implementation.
+
+@node Design-approach
+@section Design-approach
+
+Consider how you want it to work; what should it do. Think about these
+things:
+@itemize @bullet
+@item @emph{functionality:} What functionality should it have? What
+attributes or configuration is exposed to the user?
+@item @emph{reusability:} How much should others be able to reuse my design?
+Can I reuse code from ns-2 to get started? How does a user integrate
+the model with the rest of another simulation?
+@item @emph{dependencies:} How can I reduce the introduction of
+outside dependencies on my new code as much as possible (to make it
+more modular)? For instance, should I avoid any dependence on IPv4 if
+I want it to also be used by IPv6? Should I avoid any dependency
+on IP at all?
+@end itemize
+
+Do not be hesitant to contact the ns-3-users or ns-developers list if
+you have questions. In particular, it is important to think about
+the public API of your new model and ask for feedback. It also helps
+to let others know of your work in case you are interested in
+collaborators.
+
+@subsection Example: ErrorModel
+
+An error model exists in ns-2. It allows packets to be passed to
+a stateful object that determines, based on a random
+variable, whether the packet is corrupted. The caller can then
+decide what to do with the packet (drop it, etc.).
+
+The main API of the error model is a function to pass a packet
+to, and the return value of this function is a boolean that
+tells the caller whether any corruption occurred. Note that
+depending on the error model, the packet data buffer may or may
+not be corrupted. Let's call this function "IsCorrupt()".
+
+So far, in our design, we have:
+@verbatim
+class ErrorModel
+{
+public:
+ /**
+ * \returns true if the Packet is to be considered as errored/corrupted
+ * \param pkt Packet to apply error model to
+ */
+ bool IsCorrupt (Ptr<Packet> pkt);
+};
+@end verbatim
+Note that we do not pass a const pointer, thereby allowing the function
+to modify the packet if IsCorrupt() returns true. Not all error models
+will actually modify the packet; whether or not the packet data
+buffer is corrupted should be documented.
+
+We may also want specialized versions of this, such as in ns-2, so
+although it is not the only design choice for polymorphism, we assume
+that we will subclass a base class ErrorModel for specialized classes,
+such as RateErrorModel, ListErrorModel, etc, such as is done in ns-2.
+
+You may be thinking at this point, "Why not make IsCorrupt() a virtual
+method?". That is one approach; the other is to make the public
+non-virtual function indirect through a private virtual function
+(this in C++ is known as the non virtual interface idiom and is
+adopted in the ns-3 ErrorModel class).
+
+Next, should this device have any dependencies on IP or other protocols?
+We do not want to create dependencies on Internet protocols (the error
+model should be applicable to non-Internet protocols too), so we'll keep
+that in mind later.
+
+Another consideration is how objects will include this error model.
+We envision putting an explicit setter in certain NetDevice implementations,
+for example.
+@verbatim
+ /**
+ * Attach a receive ErrorModel to the PointToPointNetDevice.
+ *
+ * The PointToPointNetDevice may optionally include an ErrorModel in
+ * the packet receive chain.
+ *
+ * @see ErrorModel
+ * @param em Ptr to the ErrorModel.
+ */
+ void PointToPointNetDevice::SetReceiveErrorModel(Ptr<ErrorModel> em);
+@end verbatim
+Again, this is not the only choice we have (error models could be aggregated
+to lots of other objects), but it satisfies our primary use case, which
+is to allow a user to force errors on otherwise successful packet
+transmissions, at the NetDevice level.
+
+After some thinking and looking at existing ns-2 code, here is a sample
+API of a base class and first subclass that could be posted for initial
+review:
+@verbatim
+class ErrorModel
+{
+public:
+ ErrorModel ();
+ virtual ~ErrorModel ();
+ bool IsCorrupt (Ptr<Packet> pkt);
+ void Reset (void);
+ void Enable (void);
+ void Disable (void);
+ bool IsEnabled (void) const;
+private:
+ virtual bool DoCorrupt (Ptr<Packet> pkt) = 0;
+ virtual void DoReset (void) = 0;
+};
+
+enum ErrorUnit
+ {
+ EU_BIT,
+ EU_BYTE,
+ EU_PKT
+ };
+
+// Determine which packets are errored corresponding to an underlying
+// random variable distribution, an error rate, and unit for the rate.
+class RateErrorModel : public ErrorModel
+{
+public:
+ RateErrorModel ();
+ virtual ~RateErrorModel ();
+ enum ErrorUnit GetUnit (void) const;
+ void SetUnit (enum ErrorUnit error_unit);
+ double GetRate (void) const;
+ void SetRate (double rate);
+ void SetRandomVariable (const RandomVariable &ranvar);
+private:
+ virtual bool DoCorrupt (Ptr<Packet> pkt);
+ virtual void DoReset (void);
+};
+@end verbatim
+
+@node Scaffolding
+@section Scaffolding
+
+Let's say that you are ready to start implementing; you have a fairly clear
+picture of what you want to build, and you may have solicited some
+initial review or suggestions from the list.
+One way to approach the next step (implementation) is to create scaffolding
+and fill in the details as the design matures.
+
+This section walks through many of the steps you should consider to
+define scaffolding, or a non-functional skeleton of what your model
+will eventually implement. It is usually good practice to not wait
+to get these details integrated at the end, but instead to plumb a
+skeleton of your model into the system early and then add functions
+later once the API and integration seems about right.
+
+Note that you will want to modify a few things in the below presentation
+for your model since if you follow the error model verbatim, the code
+you produce will collide with the existing error model. The below is
+just an outline of how ErrorModel was built that you can adapt to
+other models.
+
+@subsection Review the ns-3 coding style document
+
+At this point, you may want to pause and read the ns-3 coding
+style document, especially if you are considering to contribute your
+code back to the project. The coding style document is linked off
+the main project page:
+@uref{http://www.nsnam.org/codingstyle.html,,ns-3 coding style}.
+
+@subsection Decide where in the source tree the model will reside in
+
+All of the ns-3 model source code is in the directory @code{src/}.
+You will need to choose which subdirectory it resides in. If it is
+new model code of some sort, it makes sense to put it into the
+@code{src/} directory somewhere, particularly for ease of integrating
+with the build system.
+
+In the case of the error model, it is very related to the packet
+class, so it makes sense to implement this in the @code{src/common/}
+directory where ns-3 packets are implemented.
+
+@subsection waf and wscript
+
+ns-3 uses the @uref{http://www.freehackers.org/~tnagy/waf.html,,Waf}
+build system. You will want to integrate your new
+ns-3 uses the Waf build system. You will want to integrate your new
+source files into this system. This requires that you add your files
+to the @code{wscript} file found in each directory.
+
+Let's start with empty files error-model.h and error-model.cc, and
+add this to @code{src/common/wscript}. It is really just a matter
+of adding the .cc file to the rest of the source files, and the .h
+file to the list of the header files.
+
+Now, pop up to the top level directory and type "./waf check". You
+shouldn't have broken anything by this operation.
+@subsection include guards
+Next, let's add some
+@uref{http://en.wikipedia.org/wiki/Include_guard,,include guards} in our
+header file.
+@verbatim
+#ifndef ERROR_MODEL_H
+#define ERROR_MODEL_H
+...
+#endif
+@end verbatim
+
+@subsection namespace ns3
+ns-3 uses the ns3 @uref{http://en.wikipedia.org/wiki/Namespace_(computer_science)#Use_in_common_languages,,namespace}
+to isolate its symbols from other namespaces.
+Typically, a user will next put an ns-3 namespace block in both the cc and
+h file.
+@verbatim
+namespace ns3 {
+...
+}
+@end verbatim
+
+At this point, we have some skeletal files in which we can start defining
+our new classes. The header file looks like this:
+
+@verbatim
+#ifndef ERROR_MODEL_H
+#define ERROR_MODEL_H
+
+namespace ns3 {
+
+} // namespace ns3
+#endif
+@end verbatim
+while the @code{error-model.cc} file simply looks like this:
+@verbatim
+#include "error-model.h"
+
+namespace ns3 {
+
+} // namespace ns3
+@end verbatim
+These files should compile since they don't really have any contents.
+We're now ready to start adding classes.
+
+@node Initial Implementation
+@section Initial Implementation
+
+At this point, we're still working on some scaffolding, but we can
+begin to define our classes, with the functionality to be added later.
+
+@subsection use of class Object?
+
+This is an important design step; whether to use @code{class Object} as
+a base class for your new classes.
+
+As described in the chapter on the ns-3 @ref{Object model}, classes that
+inherit from @code{class Object} get special properties:
+@itemize @bullet
+@item the ns-3 type and attribute system (see @ref{Attributes})
+@item an object aggregation system
+@item a smart-pointer reference counting system (class Ptr)
+@end itemize
+
+Classes that derive from @code{class ObjectBase} get the first two
+properties above, but do not get smart pointers. Classes that
+derive from @code{class RefCountBase} get only the smart-pointer
+reference counting system.
+
+In practice, @code{class Object} is the variant of the three above that
+the ns-3 developer will most commonly encounter.
+
+In our case, we want to make use of the attribute system, and we
+will be passing instances of this object across the ns-3 public API,
+so @code{class Object} is appropriate for us.
+
+@subsection initial classes
+
+One way to proceed is to start by defining the bare minimum functions
+and see if they will compile. Let's review what all is needed to
+implement when we derive from class Object.
+
+@verbatim
+#ifndef ERROR_MODEL_H
+#define ERROR_MODEL_H
+
+#include "ns3/object.h"
+
+namespace ns3 {
+
+class ErrorModel : public Object
+{
+public:
+ static TypeId GetTypeId (void);
+
+ ErrorModel ();
+ virtual ~ErrorModel ();
+};
+
+class RateErrorModel : public ErrorModel
+{
+public:
+ static TypeId GetTypeId (void);
+
+ RateErrorModel ();
+ virtual ~RateErrorModel ();
+};
+#endif
+@end verbatim
+
+A few things to note here. We need to include @code{object.h}. The
+convention in ns-3 is that if the header file is co-located in the
+same directory, it may be included without any path prefix. Therefore,
+if we were implementing ErrorModel in @code{src/core} directory, we could
+have just said "@code{#include "object.h"}". But we are in @code{src/common},
+so we must include it as "@code{#include "ns3/object.h"}". Note also
+that this goes outside the namespace declaration.
+
+Second, each class must implement a static public member function
+called @code{GetTypeId (void)}.
+
+Third, it is a good idea to implement constructors and destructors rather
+than to let the compiler generate them, and to make the destructor virtual.
+In C++, note also that copy assignment operator and copy constructors
+are auto-generated if they are not defined, so if you do not want those,
+you should implement those as private members. This aspect of C++ is
+discussed in Scott Meyers' Effective C++ book. item 45.
+
+Let's now look at some corresponding skeletal implementation code in the .cc
+file.
+
+@verbatim
+#include "error-model.h"
+
+namespace ns3 {
+
+NS_OBJECT_ENSURE_REGISTERED (ErrorModel);
+
+TypeId ErrorModel::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::ErrorModel")
+ .SetParent<Object> ()
+ ;
+ return tid;
+}
+
+ErrorModel::ErrorModel ()
+{
+}
+
+ErrorModel::~ErrorModel ()
+{
+}
+
+NS_OBJECT_ENSURE_REGISTERED (RateErrorModel);
+
+TypeId RateErrorModel::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::RateErrorModel")
+ .SetParent<ErrorModel> ()
+ .AddConstructor<RateErrorModel> ()
+ ;
+ return tid;
+}
+
+RateErrorModel::RateErrorModel ()
+{
+}
+
+RateErrorModel::~RateErrorModel ()
+{
+}
+@end verbatim
+
+What is the @code{GetTypeId (void)} function? This function does a few
+things. It registers a unique string into the TypeId system. It establishes
+the hierarchy of objects in the attribute system (via @code{SetParent}).
+It also declares that certain objects can be created via the object
+creation framework (@code{AddConstructor}).
+
+The macro @code{NS_OBJECT_ENSURE_REGISTERED (classname)} is needed also
+once for every class that defines a new GetTypeId method, and it does
+the actual registration of the class into the system.
+The @ref{Object model} chapter discusses this in more detail.
+
+@subsection how to include files from elsewhere
+@subsection log component
+
+Here, write a bit about adding ns-3 logging macros. Note that
+LOG_COMPONENT_DEFINE is done outside the namespace ns3
+
+@subsection constructor, empty function prototypes
+
+@subsection key variables (default values, attributes)
+
+@subsection test program 1
+
+
+
+@subsection Object Framework
+
+ static const ClassId cid;
+
+
+const InterfaceId ErrorModel::iid =
+ MakeInterfaceId ("ErrorModel", Object::iid);
+
+const ClassId ErrorModel::cid =
+ MakeClassId<ErrorModel> ("ErrorModel", ErrorModel::iid);
+@end verbatim
+
+
+@node Adding-a-sample-script
+@section Adding a sample script
+
+At this point, one may want to try to take the basic scaffolding
+defined above and add it into the system. Performing this step
+now allows one to use a simpler model when plumbing into the system
+and may also reveal whether any design or API modifications need to be
+made. Once this is done, we will return to building out the functionality
+of the ErrorModels themselves.
+
+@subsection Add basic support in the class
+
+@verbatim
+point-to-point-net-device.h
+ class ErrorModel;
+
+ /**
+ * Error model for receive packet events
+ */
+ Ptr<ErrorModel> m_receiveErrorModel;
+
+@end verbatim
+
+@subsection Add Accessor
+
+@verbatim
+
+ void
+PointToPointNetDevice::SetReceiveErrorModel (Ptr<ErrorModel> em)
+{
+ NS_LOG_FUNCTION (this << em);
+ m_receiveErrorModel = em;
+}
+
+ .AddAttribute ("ReceiveErrorModel",
+ "The receiver error model used to simulate packet loss",
+ PointerValue (),
+ MakePointerAccessor (&PointToPointNetDevice::m_receiveErrorModel),
+ MakePointerChecker<ErrorModel> ())
+@end verbatim
+
+@subsection Plumb into the system
+
+@verbatim
+void PointToPointNetDevice::Receive (Ptr<Packet> packet)
+{
+ NS_LOG_FUNCTION (this << packet);
+ uint16_t protocol = 0;
+
+ if (m_receiveErrorModel && m_receiveErrorModel->IsCorrupt (packet) )
+ {
+//
+// If we have an error model and it indicates that it is time to lose a
+// corrupted packet, don't forward this packet up, let it go.
+//
+ m_dropTrace (packet);
+ }
+ else
+ {
+//
+// Hit the receive trace hook, strip off the point-to-point protocol header
+// and forward this packet up the protocol stack.
+//
+ m_rxTrace (packet);
+ ProcessHeader(packet, protocol);
+ m_rxCallback (this, packet, protocol, GetRemote ());
+ if (!m_promiscCallback.IsNull ())
+ { m_promiscCallback (this, packet, protocol, GetRemote (), GetAddress (), NetDevice::PACKET_HOST);
+ }
+ }
+}
+@end verbatim
+
+@subsection Create null functional script
+
+@verbatim
+simple-error-model.cc
+
+ // Error model
+ // We want to add an error model to node 3's NetDevice
+ // We can obtain a handle to the NetDevice via the channel and node
+ // pointers
+ Ptr<PointToPointNetDevice> nd3 = PointToPointTopology::GetNetDevice
+ (n3, channel2);
+ Ptr<ErrorModel> em = Create<ErrorModel> ();
+ nd3->SetReceiveErrorModel (em);
+
+
+bool
+ErrorModel::DoCorrupt (Packet& p)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_UNCOND("Corrupt!");
+ return false;
+}
+@end verbatim
+
+At this point, we can run the program with our trivial ErrorModel
+plumbed into the receive path of the PointToPointNetDevice. It
+prints out the string "Corrupt!" for each packet received at
+node n3. Next, we return to the error model to add in a subclass
+that performs more interesting error modeling.
+
+@section Add subclass
+
+The trivial base class ErrorModel does not do anything interesting,
+but it provides a useful base class interface (Corrupt () and Reset ()),
+forwarded to virtual functions that can be subclassed. Let's next
+consider what we call a BasicErrorModel which is based on the
+ns-2 ErrorModel class (in ns-2/queue/errmodel.@{cc,h@}).
+
+What properties do we want this to have, from a user interface
+perspective? We would like for the user to be able to trivially
+swap out the type of ErrorModel used in the NetDevice. We would also
+like the capability to set configurable parameters.
+
+Here are a few simple requirements we will consider:
+@itemize @bullet
+@item Ability to set the random variable that governs the losses
+(default is UniformVariable)
+@item Ability to set the unit (bit, byte, packet, time) of granularity
+over which errors are applied.
+@item Ability to set the rate of errors (e.g. 10^-3) corresponding to
+the above unit of granularity.
+@item Ability to enable/disable (default is enabled)
+@end itemize
+
+@subsection How to subclass
+
+We declare BasicErrorModel to be a subclass of ErrorModel as follows,
+
+@verbatim
+class BasicErrorModel : public ErrorModel
+{
+public:
+ static TypeId GetTypeId (void);
+ ...
+private:
+ // Implement base class pure virtual functions
+ virtual bool DoCorrupt (Ptr<Packet> p);
+ virtual bool DoReset (void);
+ ...
+}
+@end verbatim
+
+and configure the subclass GetTypeId function by setting a unique
+TypeId string and setting the Parent to ErrorModel:
+
+@verbatim
+TypeId RateErrorModel::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::RateErrorModel")
+ .SetParent<ErrorModel> ()
+ .AddConstructor<RateErrorModel> ()
+ ...
+@end verbatim
+
+@node Build-core-functions-and-unit-tests
+@section Build core functions and unit tests
+
+@subsection assert macros
+
+@subsection Writing unit tests
+
+
--- a/doc/manual/wifi.texi Tue Feb 03 09:32:24 2009 -0800
+++ b/doc/manual/wifi.texi Tue Feb 03 10:40:16 2009 -0800
@@ -83,6 +83,11 @@
The source code for the Wifi NetDevice lives in the directory
@code{src/devices/wifi}.
+@float Figure,fig:WifiArchitecture
+@caption{Wifi NetDevice architecture.}
+@image{../WifiArchitecture,5in}
+@end float
+
@node Using the WifiNetDevice
@section Using the WifiNetDevice
--- a/regression.py Tue Feb 03 09:32:24 2009 -0800
+++ b/regression.py Tue Feb 03 10:40:16 2009 -0800
@@ -84,7 +84,7 @@
program = getattr(mod, "program", short_name)
if hasattr(mod, 'may_run'):
- reason_cannot_run = mod.may_run(self.env)
+ reason_cannot_run = mod.may_run(self.env, Options.options)
else:
reason_cannot_run = None
if reason_cannot_run:
@@ -122,11 +122,19 @@
if is_pyscript:
script = os.path.abspath(os.path.join('..', *os.path.split(program)))
argv = [self.env['PYTHON'], script] + arguments
- wutils.run_argv(argv, cwd=trace_output_path)
+ try:
+ wutils.run_argv(argv, cwd=trace_output_path)
+ except Utils.WafError, ex:
+ print >> sys.stderr, ex
+ return 1
else:
- wutils.run_program(program,
- command_template=wutils.get_command_template(self.env, arguments),
- cwd=trace_output_path)
+ try:
+ wutils.run_program(program,
+ command_template=wutils.get_command_template(self.env, arguments),
+ cwd=trace_output_path)
+ except Utils.WafError, ex:
+ print >> sys.stderr, ex
+ return 1
if Options.options.verbose:
#diffCmd = "diff traces " + refTestDirName + " | head"
@@ -154,11 +162,19 @@
if is_pyscript:
script = os.path.abspath(os.path.join('..', *os.path.split(program)))
argv = [self.env['PYTHON'], script] + arguments
- retval = wutils.run_argv(argv, cwd=trace_output_path)
+ try:
+ retval = wutils.run_argv(argv, cwd=trace_output_path)
+ except Utils.WafError, ex:
+ print >> sys.stderr, ex
+ return 1
else:
- retval = wutils.run_program(program,
- command_template=wutils.get_command_template(self.env, arguments),
- cwd=trace_output_path)
+ try:
+ retval = wutils.run_program(program,
+ command_template=wutils.get_command_template(self.env, arguments),
+ cwd=trace_output_path)
+ except Utils.WafError, ex:
+ print >> sys.stderr, ex
+ return 1
return retval
--- a/regression/tests/test-csma-bridge.py Tue Feb 03 09:32:24 2009 -0800
+++ b/regression/tests/test-csma-bridge.py Tue Feb 03 10:40:16 2009 -0800
@@ -4,7 +4,7 @@
import os.path
-def may_run(env):
+def may_run(env, options):
"""Returns 0 when it can run, return non-zero or string (reason) when it cannot run"""
if env['ENABLE_PYTHON_BINDINGS']:
return 0
--- a/regression/tests/test-realtime-udp-echo.py Tue Feb 03 09:32:24 2009 -0800
+++ b/regression/tests/test-realtime-udp-echo.py Tue Feb 03 10:40:16 2009 -0800
@@ -2,3 +2,6 @@
"""Generic trace-comparison-type regression test."""
+def may_run(env, options):
+ if not env["ENABLE_REAL_TIME"]:
+ return "Real-time support not available"
--- a/regression/tests/test-tcp-nsc-lfn.py Tue Feb 03 09:32:24 2009 -0800
+++ b/regression/tests/test-tcp-nsc-lfn.py Tue Feb 03 10:40:16 2009 -0800
@@ -3,12 +3,16 @@
"""Trace-comparison-type regression test for the Network Simulation Cradle."""
import platform
-
+import sys
-def may_run(env):
+def may_run(env, options):
if not env['NSC_ENABLED']:
return "NSC not available"
else:
+ if options.valgrind:
+ return "NSC does not get along with valgrind"
+ if sys.platform != 'linux2':
+ return "NSC is not well supported on non-Linux platforms"
return 0
Binary file waf has changed