start a manual section on new models
authorTom Henderson <tomh@tomh.org>
Tue Feb 03 06:56:14 2009 -0800 (13 months ago)
changeset 4134a104b592cba3
parent 4131 71260995880e
child 4135 3e819441bc75
start a manual section on new models
doc/manual/Makefile
doc/manual/manual.texi
doc/manual/new-models.texi
     1.1 --- a/doc/manual/Makefile	Fri Jan 30 19:28:00 2009 +0000
     1.2 +++ b/doc/manual/Makefile	Tue Feb 03 06:56:14 2009 -0800
     1.3 @@ -33,6 +33,7 @@
     1.4  	callbacks.texi \
     1.5  	csma.texi \
     1.6  	emulation.texi \
     1.7 +	new-models.texi \
     1.8  	node.texi \
     1.9  	objects.texi \
    1.10  	other.texi \
     2.1 --- a/doc/manual/manual.texi	Fri Jan 30 19:28:00 2009 +0000
     2.2 +++ b/doc/manual/manual.texi	Tue Feb 03 06:56:14 2009 -0800
     2.3 @@ -92,6 +92,7 @@
     2.4  * Wifi NetDevice::
     2.5  * CSMA NetDevice::
     2.6  * PointToPoint NetDevice::
     2.7 +* Creating a new ns-3 model::
     2.8  * Troubleshooting::
     2.9  @end menu
    2.10  
    2.11 @@ -111,6 +112,7 @@
    2.12  @include csma.texi
    2.13  @include point-to-point.texi
    2.14  @c @include other.texi
    2.15 +@include new-models.texi
    2.16  @include troubleshoot.texi
    2.17  
    2.18  @printindex cp
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/doc/manual/new-models.texi	Tue Feb 03 06:56:14 2009 -0800
     3.3 @@ -0,0 +1,578 @@
     3.4 +@node Creating a new ns-3 model
     3.5 +@chapter Creating a new ns-3 model 
     3.6 +
     3.7 +This chapter walks through the design process of an @command{ns-3} model.
     3.8 +In many research cases, users will not be satisfied to merely adapt
     3.9 +existing models, but may want to extend the core of the simulator in
    3.10 +a novel way.  We will use the example of adding an ErrorModel to
    3.11 +a simple @command{ns-3} link as a motivating example of how one might
    3.12 +approach this problem and proceed through a design and implementation.
    3.13 +
    3.14 +@node Design-approach
    3.15 +@section Design-approach
    3.16 +
    3.17 +Consider how you want it to work; what should it do.  Think about these
    3.18 +things:
    3.19 +@itemize @bullet
    3.20 +@item @emph{functionality:}  What functionality should it have?  What
    3.21 +attributes or configuration is exposed to the user?
    3.22 +@item @emph{reusability:}  How much should others be able to reuse my design?  
    3.23 +Can I reuse code from ns-2 to get started?  How does a user integrate
    3.24 +the model with the rest of another simulation?
    3.25 +@item @emph{dependencies:}  How can I reduce the introduction of 
    3.26 +outside dependencies on my new code as much as possible (to make it 
    3.27 +more modular)?  For instance, should I avoid any dependence on IPv4 if
    3.28 +I want it to also be used by IPv6?  Should I avoid any dependency
    3.29 +on IP at all?
    3.30 +@end itemize
    3.31 +
    3.32 +Do not be hesitant to contact the ns-3-users or ns-developers list if 
    3.33 +you have questions.  In particular, it is important to think about
    3.34 +the public API of your new model and ask for feedback.  It also helps
    3.35 +to let others know of your work in case you are interested in 
    3.36 +collaborators.  
    3.37 +
    3.38 +@subsection Example:  ErrorModel
    3.39 +
    3.40 +An error model exists in ns-2.  It allows packets to be passed to
    3.41 +a stateful object that determines, based on a random
    3.42 +variable, whether the packet is corrupted.  The caller can then
    3.43 +decide what to do with the packet (drop it, etc.).
    3.44 +
    3.45 +The main API of the error model is a function to pass a packet
    3.46 +to, and the return value of this function is a boolean that
    3.47 +tells the caller whether any corruption occurred.  Note that
    3.48 +depending on the error model, the packet data buffer may or may
    3.49 +not be corrupted.  Let's call this function "IsCorrupt()".
    3.50 +
    3.51 +So far, in our design, we have:
    3.52 +@verbatim
    3.53 +class ErrorModel
    3.54 +{
    3.55 +public:
    3.56 + /**
    3.57 +  * \returns true if the Packet is to be considered as errored/corrupted
    3.58 +  * \param pkt Packet to apply error model to
    3.59 +  */
    3.60 +  bool IsCorrupt (Ptr<Packet> pkt);
    3.61 +};
    3.62 +@end verbatim
    3.63 +Note that we do not pass a const pointer, thereby allowing the function
    3.64 +to modify the packet if IsCorrupt() returns true.  Not all error models
    3.65 +will actually modify the packet; whether or not the packet data
    3.66 +buffer is corrupted should be documented.
    3.67 +
    3.68 +We may also want specialized versions of this, such as in ns-2, so
    3.69 +although it is not the only design choice for polymorphism, we assume
    3.70 +that we will subclass a base class ErrorModel for specialized classes,
    3.71 +such as RateErrorModel, ListErrorModel, etc, such as is done in ns-2.
    3.72 +
    3.73 +You may be thinking at this point, "Why not make IsCorrupt() a virtual
    3.74 +method?".  That is one approach; the other is to make the public
    3.75 +non-virtual function indirect through a private virtual function
    3.76 +(this in C++ is known as the non virtual interface idiom and is 
    3.77 +adopted in the ns-3 ErrorModel class).  
    3.78 +
    3.79 +Next, should this device have any dependencies on IP or other protocols?
    3.80 +We do not want to create dependencies on Internet protocols (the error
    3.81 +model should be applicable to non-Internet protocols too), so we'll keep
    3.82 +that in mind later.
    3.83 +
    3.84 +Another consideration is how objects will include this error model.
    3.85 +We envision putting an explicit setter in certain NetDevice implementations,
    3.86 +for example.
    3.87 +@verbatim
    3.88 +  /**
    3.89 +   * Attach a receive ErrorModel to the PointToPointNetDevice.
    3.90 +   *
    3.91 +   * The PointToPointNetDevice may optionally include an ErrorModel in
    3.92 +   * the packet receive chain.
    3.93 +   *
    3.94 +   * @see ErrorModel
    3.95 +   * @param em Ptr to the ErrorModel.
    3.96 +   */
    3.97 +  void PointToPointNetDevice::SetReceiveErrorModel(Ptr<ErrorModel> em);
    3.98 +@end verbatim
    3.99 +Again, this is not the only choice we have (error models could be aggregated
   3.100 +to lots of other objects), but it satisfies our primary use case, which
   3.101 +is to allow a user to force errors on otherwise successful packet
   3.102 +transmissions, at the NetDevice level.
   3.103 +
   3.104 +After some thinking and looking at existing ns-2 code, here is a sample
   3.105 +API of a base class and first subclass that could be posted for initial 
   3.106 +review:
   3.107 +@verbatim
   3.108 +class ErrorModel 
   3.109 +{
   3.110 +public:
   3.111 +  ErrorModel ();
   3.112 +  virtual ~ErrorModel ();
   3.113 +  bool IsCorrupt (Ptr<Packet> pkt);
   3.114 +  void Reset (void);
   3.115 +  void Enable (void);
   3.116 +  void Disable (void);
   3.117 +  bool IsEnabled (void) const;
   3.118 +private:
   3.119 +  virtual bool DoCorrupt (Ptr<Packet> pkt) = 0;
   3.120 +  virtual void DoReset (void) = 0;
   3.121 +};
   3.122 +
   3.123 +enum ErrorUnit
   3.124 +  {
   3.125 +    EU_BIT,
   3.126 +    EU_BYTE,
   3.127 +    EU_PKT
   3.128 +  };
   3.129 +
   3.130 +// Determine which packets are errored corresponding to an underlying
   3.131 +// random variable distribution, an error rate, and unit for the rate.
   3.132 +class RateErrorModel : public ErrorModel
   3.133 +{
   3.134 +public:
   3.135 +  RateErrorModel ();
   3.136 +  virtual ~RateErrorModel ();
   3.137 +  enum ErrorUnit GetUnit (void) const;
   3.138 +  void SetUnit (enum ErrorUnit error_unit);
   3.139 +  double GetRate (void) const;
   3.140 +  void SetRate (double rate);
   3.141 +  void SetRandomVariable (const RandomVariable &ranvar);
   3.142 +private:
   3.143 +  virtual bool DoCorrupt (Ptr<Packet> pkt);
   3.144 +  virtual void DoReset (void);
   3.145 +};
   3.146 +@end verbatim
   3.147 +
   3.148 +@node Scaffolding
   3.149 +@section Scaffolding
   3.150 +
   3.151 +Let's say that you are ready to start implementing; you have a fairly clear
   3.152 +picture of what you want to build, and you may have solicited some
   3.153 +initial review or suggestions from the list.
   3.154 +One way to approach the next step (implementation) is to create scaffolding
   3.155 +and fill in the details as the design matures.  
   3.156 +
   3.157 +This section walks through many of the steps you should consider to
   3.158 +define scaffolding, or a non-functional skeleton of what your model
   3.159 +will eventually implement.  It is usually good practice to not wait
   3.160 +to get these details integrated at the end, but instead to plumb a
   3.161 +skeleton of your model into the system early and then add functions
   3.162 +later once the API and integration seems about right.  
   3.163 +
   3.164 +Note that you will want to modify a few things in the below presentation
   3.165 +for your model since if you follow the error model verbatim, the code
   3.166 +you produce will collide with the existing error model.  The below is
   3.167 +just an outline of how ErrorModel was built that you can adapt to
   3.168 +other models.
   3.169 +
   3.170 +@subsection Review the ns-3 coding style document
   3.171 +
   3.172 +At this point, you may want to pause and read the ns-3 coding
   3.173 +style document, especially if you are considering to contribute your
   3.174 +code back to the project.  The coding style document is linked off
   3.175 +the main project page:
   3.176 +@uref{http://www.nsnam.org/codingstyle.html,,ns-3 coding style}.
   3.177 +
   3.178 +@subsection  Decide where in the source tree the model will reside in
   3.179 +
   3.180 +All of the ns-3 model source code is in the directory @code{src/}.  
   3.181 +You will need to choose which subdirectory it resides in.  If it is
   3.182 +new model code of some sort, it makes sense to put it into the 
   3.183 +@code{src/} directory somewhere, particularly for ease of integrating
   3.184 +with the build system.
   3.185 +
   3.186 +In the case of the error model, it is very related to the packet 
   3.187 +class, so it makes sense to implement this in the @code{src/common/}
   3.188 +directory where ns-3 packets are implemented.  
   3.189 +
   3.190 +@subsection  waf and wscript
   3.191 +
   3.192 +ns-3 uses the @uref{http://www.freehackers.org/~tnagy/waf.html,,Waf} 
   3.193 +build system.  You will want to integrate your new
   3.194 +ns-3 uses the Waf build system.  You will want to integrate your new
   3.195 +source files into this system.  This requires that you add your files
   3.196 +to the @code{wscript} file found in each directory.  
   3.197 +
   3.198 +Let's start with empty files error-model.h and error-model.cc, and
   3.199 +add this to @code{src/common/wscript}.  It is really just a matter
   3.200 +of adding the .cc file to the rest of the source files, and the .h
   3.201 +file to the list of the header files. 
   3.202 +
   3.203 +Now, pop up to the top level directory and type "./waf check".  You
   3.204 +shouldn't have broken anything by this operation.
   3.205 +@subsection include guards
   3.206 +Next, let's add some 
   3.207 +@uref{http://en.wikipedia.org/wiki/Include_guard,,include guards} in our 
   3.208 +header file.
   3.209 +@verbatim
   3.210 +#ifndef ERROR_MODEL_H
   3.211 +#define ERROR_MODEL_H
   3.212 +...
   3.213 +#endif
   3.214 +@end verbatim
   3.215 +
   3.216 +@subsection namespace ns3
   3.217 +ns-3 uses the ns3 @uref{http://en.wikipedia.org/wiki/Namespace_(computer_science)#Use_in_common_languages,,namespace}
   3.218 +to isolate its symbols from other namespaces.
   3.219 +Typically, a user will next put an ns-3 namespace block in both the cc and
   3.220 +h file. 
   3.221 +@verbatim
   3.222 +namespace ns3 {
   3.223 +...
   3.224 +}
   3.225 +@end verbatim
   3.226 +
   3.227 +At this point, we have some skeletal files in which we can start defining
   3.228 +our new classes.  The header file looks like this:
   3.229 +
   3.230 +@verbatim
   3.231 +#ifndef ERROR_MODEL_H
   3.232 +#define ERROR_MODEL_H
   3.233 +
   3.234 +namespace ns3 {
   3.235 +
   3.236 +} // namespace ns3
   3.237 +#endif
   3.238 +@end verbatim
   3.239 +while the @code{error-model.cc} file simply looks like this:
   3.240 +@verbatim
   3.241 +#include "error-model.h"
   3.242 +
   3.243 +namespace ns3 {
   3.244 +
   3.245 +} // namespace ns3
   3.246 +@end verbatim
   3.247 +These files should compile since they don't really have any contents.  
   3.248 +We're now ready to start adding classes.
   3.249 +
   3.250 +@node Initial Implementation
   3.251 +@section Initial Implementation
   3.252 +
   3.253 +At this point, we're still working on some scaffolding, but we can
   3.254 +begin to define our classes, with the functionality to be added later.
   3.255 +
   3.256 +@subsection use of class Object?
   3.257 +
   3.258 +This is an important design step; whether to use @code{class Object} as 
   3.259 +a base class for your new classes.
   3.260 +
   3.261 +As described in the chapter on the ns-3 @ref{Object model}, classes that 
   3.262 +inherit from @code{class Object} get special properties:
   3.263 +@itemize @bullet
   3.264 +@item the ns-3 type and attribute system (see @ref{Attributes})
   3.265 +@item an object aggregation system
   3.266 +@item a smart-pointer reference counting system (class Ptr)
   3.267 +@end itemize
   3.268 +
   3.269 +Classes that derive from @code{class ObjectBase} get the first two
   3.270 +properties above, but do not get smart pointers.  Classes that
   3.271 +derive from @code{class RefCountBase} get only the smart-pointer
   3.272 +reference counting system.
   3.273 +
   3.274 +In practice, @code{class Object} is the variant of the three above that
   3.275 +the ns-3 developer will most commonly encounter.
   3.276 +
   3.277 +In our case, we want to make use of the attribute system, and we
   3.278 +will be passing instances of this object across the ns-3 public API,
   3.279 +so @code{class Object} is appropriate for us.
   3.280 +
   3.281 +@subsection initial classes
   3.282 +
   3.283 +One way to proceed is to start by defining the bare minimum functions
   3.284 +and see if they will compile.  Let's review what all is needed to 
   3.285 +implement when we derive from class Object.
   3.286 +
   3.287 +@verbatim
   3.288 +#ifndef ERROR_MODEL_H
   3.289 +#define ERROR_MODEL_H
   3.290 +
   3.291 +#include "ns3/object.h"
   3.292 +
   3.293 +namespace ns3 {
   3.294 +  
   3.295 +class ErrorModel : public Object
   3.296 +{
   3.297 +public:
   3.298 +  static TypeId GetTypeId (void);
   3.299 +
   3.300 +  ErrorModel ();
   3.301 +  virtual ~ErrorModel ();
   3.302 +};
   3.303 +
   3.304 +class RateErrorModel : public ErrorModel
   3.305 +{
   3.306 +public:
   3.307 +  static TypeId GetTypeId (void);
   3.308 + 
   3.309 +  RateErrorModel ();
   3.310 +  virtual ~RateErrorModel ();
   3.311 +};
   3.312 +#endif
   3.313 +@end verbatim
   3.314 +
   3.315 +A few things to note here.  We need to include @code{object.h}.  The
   3.316 +convention in ns-3 is that if the header file is co-located in the
   3.317 +same directory, it may be included without any path prefix.  Therefore,
   3.318 +if we were implementing ErrorModel in @code{src/core} directory, we could
   3.319 +have just said "@code{#include "object.h"}".  But we are in @code{src/common},
   3.320 +so we must include it as "@code{#include "ns3/object.h"}".  Note also
   3.321 +that this goes outside the namespace declaration.
   3.322 + 
   3.323 +Second, each class must implement a static public member function
   3.324 +called @code{GetTypeId (void)}.  
   3.325 +
   3.326 +Third, it is a good idea to implement constructors and destructors rather
   3.327 +than to let the compiler generate them, and to make the destructor virtual.
   3.328 +In C++, note also that copy assignment operator and copy constructors
   3.329 +are auto-generated if they are not defined, so if you do not want those,
   3.330 +you should implement those as private members.  This aspect of C++ is 
   3.331 +discussed in Scott Meyers' Effective C++ book. item 45. 
   3.332 +
   3.333 +Let's now look at some corresponding skeletal implementation code in the .cc 
   3.334 +file.
   3.335 +
   3.336 +@verbatim
   3.337 +#include "error-model.h"
   3.338 +
   3.339 +namespace ns3 {
   3.340 +
   3.341 +NS_OBJECT_ENSURE_REGISTERED (ErrorModel);
   3.342 +
   3.343 +TypeId ErrorModel::GetTypeId (void)
   3.344 +{
   3.345 +  static TypeId tid = TypeId ("ns3::ErrorModel")
   3.346 +    .SetParent<Object> ()
   3.347 +    ;
   3.348 +  return tid;
   3.349 +}
   3.350 +
   3.351 +ErrorModel::ErrorModel ()
   3.352 +{ 
   3.353 +}
   3.354 +
   3.355 +ErrorModel::~ErrorModel ()
   3.356 +{ 
   3.357 +}
   3.358 +
   3.359 +NS_OBJECT_ENSURE_REGISTERED (RateErrorModel);
   3.360 +
   3.361 +TypeId RateErrorModel::GetTypeId (void)
   3.362 +{
   3.363 +  static TypeId tid = TypeId ("ns3::RateErrorModel")
   3.364 +    .SetParent<ErrorModel> ()
   3.365 +    .AddConstructor<RateErrorModel> ()
   3.366 +    ;
   3.367 +  return tid;
   3.368 +}
   3.369 +
   3.370 +RateErrorModel::RateErrorModel ()
   3.371 +{
   3.372 +} 
   3.373 +
   3.374 +RateErrorModel::~RateErrorModel ()
   3.375 +{
   3.376 +}
   3.377 +@end verbatim
   3.378 +
   3.379 +What is the @code{GetTypeId (void)} function?  This function does a few
   3.380 +things.  It registers a unique string into the TypeId system.  It establishes  
   3.381 +the hierarchy of objects in the attribute system (via @code{SetParent}).
   3.382 +It also declares that certain objects can be created via the object
   3.383 +creation framework (@code{AddConstructor}).  
   3.384 +
   3.385 +The macro @code{NS_OBJECT_ENSURE_REGISTERED (classname)} is needed also
   3.386 +once for every class that defines a new GetTypeId method, and it does
   3.387 +the actual registration of the class into the system.
   3.388 +The @ref{Object model} chapter discusses this in more detail.
   3.389 +
   3.390 +@subsection how to include files from elsewhere
   3.391 +@subsection log component 
   3.392 +
   3.393 +Here, write a bit about adding ns-3 logging macros.  Note that
   3.394 +LOG_COMPONENT_DEFINE is done outside the namespace ns3
   3.395 +
   3.396 +@subsection constructor, empty function prototypes
   3.397 +
   3.398 +@subsection key variables (default values, attributes)
   3.399 +
   3.400 +@subsection test program 1
   3.401 +
   3.402 +
   3.403 +
   3.404 +@subsection Object Framework
   3.405 +
   3.406 +  static const ClassId cid;
   3.407 +
   3.408 +
   3.409 +const InterfaceId ErrorModel::iid =
   3.410 +  MakeInterfaceId ("ErrorModel", Object::iid);
   3.411 +
   3.412 +const ClassId ErrorModel::cid =
   3.413 +  MakeClassId<ErrorModel> ("ErrorModel", ErrorModel::iid);
   3.414 +@end verbatim
   3.415 +
   3.416 +
   3.417 +@node Adding-a-sample-script
   3.418 +@section Adding a sample script
   3.419 +
   3.420 +At this point, one may want to try to take the basic scaffolding
   3.421 +defined above and add it into the system.  Performing this step
   3.422 +now allows one to use a simpler model when plumbing into the system
   3.423 +and may also reveal whether any design or API modifications need to be
   3.424 +made.  Once this is done, we will return to building out the functionality
   3.425 +of the ErrorModels themselves.
   3.426 +
   3.427 +@subsection Add basic support in the class
   3.428 +
   3.429 +@verbatim
   3.430 +point-to-point-net-device.h
   3.431 +  class ErrorModel;
   3.432 +  
   3.433 +  /**
   3.434 +   * Error model for receive packet events
   3.435 +   */
   3.436 +  Ptr<ErrorModel> m_receiveErrorModel;
   3.437 +  
   3.438 +@end verbatim
   3.439 +
   3.440 +@subsection Add Accessor
   3.441 +
   3.442 +@verbatim
   3.443 +
   3.444 +  void
   3.445 +PointToPointNetDevice::SetReceiveErrorModel (Ptr<ErrorModel> em)
   3.446 +{
   3.447 +  NS_LOG_FUNCTION (this << em);
   3.448 +  m_receiveErrorModel = em;
   3.449 +} 
   3.450 +
   3.451 +   .AddAttribute ("ReceiveErrorModel",
   3.452 +                   "The receiver error model used to simulate packet loss",
   3.453 +                   PointerValue (),
   3.454 +                   MakePointerAccessor (&PointToPointNetDevice::m_receiveErrorModel),
   3.455 +                   MakePointerChecker<ErrorModel> ())
   3.456 +@end verbatim
   3.457 +
   3.458 +@subsection Plumb into the system
   3.459 +
   3.460 +@verbatim
   3.461 +void PointToPointNetDevice::Receive (Ptr<Packet> packet)
   3.462 +{
   3.463 +  NS_LOG_FUNCTION (this << packet);
   3.464 +  uint16_t protocol = 0;
   3.465 +  
   3.466 +  if (m_receiveErrorModel && m_receiveErrorModel->IsCorrupt (packet) )
   3.467 +    {
   3.468 +//  
   3.469 +// If we have an error model and it indicates that it is time to lose a
   3.470 +// corrupted packet, don't forward this packet up, let it go. 
   3.471 +// 
   3.472 +      m_dropTrace (packet);
   3.473 +    } 
   3.474 +  else
   3.475 +    {
   3.476 +//  
   3.477 +// Hit the receive trace hook, strip off the point-to-point protocol header
   3.478 +// and forward this packet up the protocol stack.
   3.479 +//     
   3.480 +      m_rxTrace (packet);
   3.481 +      ProcessHeader(packet, protocol);
   3.482 +      m_rxCallback (this, packet, protocol, GetRemote ());
   3.483 +      if (!m_promiscCallback.IsNull ())
   3.484 +        {           m_promiscCallback (this, packet, protocol, GetRemote (), GetAddress (), NetDevice::PACKET_HOST);
   3.485 +        }
   3.486 +    }
   3.487 +}
   3.488 +@end verbatim
   3.489 +
   3.490 +@subsection Create null functional script
   3.491 +
   3.492 +@verbatim
   3.493 +simple-error-model.cc
   3.494 +
   3.495 +  // Error model
   3.496 +  // We want to add an error model to node 3's NetDevice
   3.497 +  // We can obtain a handle to the NetDevice via the channel and node
   3.498 +  // pointers
   3.499 +  Ptr<PointToPointNetDevice> nd3 = PointToPointTopology::GetNetDevice
   3.500 +    (n3, channel2);
   3.501 +  Ptr<ErrorModel> em = Create<ErrorModel> ();
   3.502 +  nd3->SetReceiveErrorModel (em);
   3.503 +
   3.504 +
   3.505 +bool
   3.506 +ErrorModel::DoCorrupt (Packet& p)
   3.507 +{
   3.508 +  NS_LOG_FUNCTION;
   3.509 +  NS_LOG_UNCOND("Corrupt!");
   3.510 +  return false;
   3.511 +}
   3.512 +@end verbatim
   3.513 +
   3.514 +At this point, we can run the program with our trivial ErrorModel
   3.515 +plumbed into the receive path of the PointToPointNetDevice.  It
   3.516 +prints out the string "Corrupt!" for each packet received at
   3.517 +node n3.  Next, we return to the error model to add in a subclass
   3.518 +that performs more interesting error modeling.
   3.519 +
   3.520 +@section Add subclass
   3.521 +
   3.522 +The trivial base class ErrorModel does not do anything interesting,
   3.523 +but it provides a useful base class interface (Corrupt () and Reset ()),
   3.524 +forwarded to virtual functions that can be subclassed.  Let's next
   3.525 +consider what we call a BasicErrorModel which is based on the
   3.526 +ns-2 ErrorModel class (in ns-2/queue/errmodel.@{cc,h@}).
   3.527 +
   3.528 +What properties do we want this to have, from a user interface
   3.529 +perspective?  We would like for the user to be able to trivially
   3.530 +swap out the type of ErrorModel used in the NetDevice.  We would also
   3.531 +like the capability to set configurable parameters.
   3.532 +
   3.533 +Here are a few simple requirements we will consider:
   3.534 +@itemize @bullet
   3.535 +@item Ability to set the random variable that governs the losses
   3.536 +(default is UniformVariable)
   3.537 +@item Ability to set the unit (bit, byte, packet, time) of granularity
   3.538 +over which errors are applied.
   3.539 +@item Ability to set the rate of errors (e.g. 10^-3) corresponding to
   3.540 +the above unit of granularity.
   3.541 +@item Ability to enable/disable (default is enabled)
   3.542 +@end itemize
   3.543 +
   3.544 +@subsection How to subclass
   3.545 +
   3.546 +We declare BasicErrorModel to be a subclass of ErrorModel as follows,
   3.547 +
   3.548 +@verbatim
   3.549 +class BasicErrorModel : public ErrorModel
   3.550 +{
   3.551 +public:
   3.552 +  static TypeId GetTypeId (void);
   3.553 +  ...
   3.554 +private:
   3.555 +  // Implement base class pure virtual functions
   3.556 +  virtual bool DoCorrupt (Ptr<Packet> p);
   3.557 +  virtual bool DoReset (void);
   3.558 +  ...
   3.559 +}
   3.560 +@end verbatim
   3.561 +
   3.562 +and configure the subclass GetTypeId function by setting a unique
   3.563 +TypeId string and setting the Parent to ErrorModel:
   3.564 +
   3.565 +@verbatim
   3.566 +TypeId RateErrorModel::GetTypeId (void)
   3.567 +{
   3.568 +  static TypeId tid = TypeId ("ns3::RateErrorModel")
   3.569 +    .SetParent<ErrorModel> ()
   3.570 +    .AddConstructor<RateErrorModel> ()
   3.571 +  ...
   3.572 +@end verbatim
   3.573 +
   3.574 +@node Build-core-functions-and-unit-tests
   3.575 +@section Build core functions and unit tests
   3.576 +
   3.577 +@subsection assert macros
   3.578 +
   3.579 +@subsection Writing unit tests
   3.580 +
   3.581 +