HOWTOs are now on the wiki

This commit is contained in:
Tom Henderson
2009-11-13 09:37:52 -08:00
parent f27efc04c2
commit 886ebc725b
6 changed files with 3 additions and 545 deletions

View File

@@ -1,203 +0,0 @@
/*!
\page application How to create a traffic generator ?
\anchor howtos-application
<b>Question:</b> How do I create a new traffic generator ?
<b>Answer:</b> It is possible to instanciate \ref ns3::Packet "Packet"
objects, schedule events, and call functions from any piece of code
in ns-3 so, technically, there is no single answer to the question of
how we can write a new traffic generator. However, the
\ref ns3::Socket "Socket" API was really designed to be the single
point of entry for traffic generators or traffic analysers and the
\ref ns3::Application "Application" class was designed to hold
together any number of sockets.
Implementing a new traffic generator thus boils down to:
- implementing a new subclass of the \ref ns3::Application "Application"
base class
- instanciate one or many sockets within that application
- start scheduling events when \ref ns3::Application::StartApplication "StartApplication"
is called
- stop scheduling events when \ref ns3::Application::StopApplication "StopApplication"
is called
- create packets and send them over one or many sockets in each event
The following "random" generator generates packets separated by a random
delay and with a random size.
\code
class RandomGenerator : public Application
{
public:
RandomGenerator ();
void SetDelay (RandomVariable delay);
void SetSize (RandomVariable size);
void SetRemote (std::string socketType,
Address remote);
private:
virtual void StartApplication (void);
virtual void StopApplication (void);
void DoGenerate (void);
RandomVariable m_delay;
RandomVariable m_size;
Ptr<Socket> m_socket;
};
\endcode
The socket is created in the SetRemote method:
\code
void
RandomGenerator::SetRemote (std::string socketType,
Address remote)
{
TypeId tid = TypeId::LookupByName (socketType);
m_socket = Socket::CreateSocket (GetNode (), tid);
m_socket->Bind ();
m_socket->ShutdownRecv ();
m_socket->Connect (remote);
}
\endcode
While the the crux of the logic is located in the DoGenerate method
which is called from within StartApplication:
\code
void
RandomGenerator::DoGenerate (void)
{
m_next = Simulator::Schedule (Seconds (m_delay.GetValue ()),
&RandomGenerator::DoGenerate, this);
Ptr<Packet> p = Create<Packet> (m_size.GetIntValue ());
m_socket->Send (p);
}
\endcode
To make that application more integrated in ns-3, it needs an associated
helper class:
\code
class RandomAppHelper
{
public:
RandomAppHelper (std::string protocol, Address remote);
void SetPacketSize (RandomVariable packetSize);
void SetDelay (RandomVariable delay);
ApplicationContainer Install (NodeContainer nodes);
private:
std::string m_protocol;
Address m_remote;
RandomVariable m_packetSize;
RandomVariable m_delay;
};
\endcode
which could be trivially implemented as:
\code
ApplicationContainer
RandomAppHelper::Install (NodeContainer nodes)
{
ApplicationContainer applications;
for (NodeContainer::Iterator i = nodes.Begin (); i != nodes.End (); ++i)
{
Ptr<RandomAppHelper> app = CreateObject<RandomAppHelper> ();
app->SetSize (m_packetSize);
app->SetDelay (m_delay);
app->SetRemote (m_protocol, m_remote);
(*i)->AddApplication (app);
applications.Add (app);
}
return applications;
}
\endcode
Despite being functional, this API is not very consistant with the style of
the other helper classes, all of which allow you to control the parameters
of the underlying class through attributes and not explicit setters. The
following API thus replaces the pair SetPacketSize/SetDelay with a single
method SetAttribute:
\code
class RandomAppHelper
{
public:
RandomAppHelper (std::string protocol, Address remote);
void SetAttribute (std::string name, const AttributeValue &value);
ApplicationContainer Install (NodeContainer c);
private:
std::string m_protocol;
Address m_remote;
ObjectFactory m_factory;
};
\endcode
And which can be used as follows:
\code
RandomAppHelper app = RandomAppHelper ("ns3::TcpSocketFactory",
InetSocketAddress (Ipv4Address ("192.168.1.10"), 10));
app.SetAttribute ("Delay", StringValue ("Constant:2.5"));
app.SetAttribute ("Size", StringValue ("Constant:2100"));
app.Install (nodes);
\endcode
The implementation, in this case, is not necessarily longer but its
simplicity hides a lot of behind-the-scenes complexity:
\code
void
RandomAppHelper::SetAttribute (std::string name, const AttributeValue &value)
{
m_factory.Set (name, value);
}
ApplicationContainer
RandomAppHelper::Install (NodeContainer nodes)
{
ApplicationContainer applications;
for (NodeContainer::Iterator i = nodes.Begin (); i != nodes.End (); ++i)
{
Ptr<RandomAppHelper> app = m_factory.Create<RandomAppHelper> ();
app->SetRemote (m_socketType, m_remote);
(*i)->AddApplication (app);
applications.Add (app);
}
return applications;
}
\endcode
The key difference between this implementation and the previous one
is that this helper does not handle explicitely the attributes
delay and packet size. Instead, it stores them in an
\ref ns3::ObjectFactory "ObjectFactory" object. This, of course,
does not work magically, and requires extra support from the
underlying RandomGenerator class. Specifically, it requires
that the underlying RandomGenerator defines its attributes
in its \ref ns3::TypeId "TypeId" in a new public static method:
\code
class RandomGenerator
{
public:
static TypeId GetTypeId (void);
};
\endcode
The corresponding implementation is shown below:
\code
TypeId
RandomGenerator::GetTypeId (void)
{
static TypeId tid = TypeId ("RandomGenerator")
.SetParent<Application> ()
.AddConstructor<RandomGenerator> ()
.AddAttribute ("Delay", "The delay between two packets (s)",
RandomVariableValue (ConstantVariable (1.0)),
MakeRandomVariableAccessor (&RandomGenerator::m_delay),
MakeRandomVariableChecker ())
.AddAttribute ("PacketSize", "The size of each packet (bytes)",
RandomVariableValue (ConstantVariable (2000)),
MakeRandomVariableAccessor (&RandomGenerator::m_size),
MakeRandomVariableChecker ())
;
return tid;
}
\endcode
*/

View File

@@ -1,38 +0,0 @@
/*!
\page callbacks Using ns-3 callbacks
\anchor howtos-callbacks
\section null_callbacks Null Callbacks
<b>Question:</b> The API I am using calls for using a callback (in the
function signature), but I do not
want to provide one. Is there a way to provide a null callback?
<b>Answer:</b> Use the ns3::MakeNullCallback construct:
\code
template<typename R>
Callback< R, T1, T2, T3, T4, T5, T6 > ns3::MakeNullCallback (void)
\endcode
Example usage: The ns3::Socket class uses callbacks to indicate completion
of events such as a successful TCP connect(). These callbacks are set
in the following function:
\code
void Socket::SetConnectCallback (Callback<void, Ptr<Socket> > connectionSucceeded,
Callback<void, Ptr<Socket> > connectionFailed,
Callback<void, Ptr<Socket> > halfClose);
\endcode
But suppose you do not care about registering a callback for the
halfClose event (but you want to register one for the
connectionSucceeded and connectionFailed cases). In that case, you
can pass a null callback as the third argument. You just need to
pass a callback with the matching signature, as follows:
\code
localSocket->SetConnectCallback (
MakeCallback (&ConnectionSucceededCallback),
MakeCallback (&ConnectionFailedCallback),
MakeNullCallback<void, Ptr<Socket> > () );
\endcode
*/

View File

@@ -1,162 +0,0 @@
/*!
\page net-device How to create a new OSI layer 1 + 2 implementation ?
\anchor howtos-net-device
<b>Question:</b> How do I integrate a new OSI layer 1 + 2 implementation ?
<b>Answer:</b> The OSI layers 1 and 2 are represented by the ns3::NetDevice
and ns3::Channel classes. To plug transparently in ns-3, a new layer 1+2 model
thus simply needs to provide two new subclasses of these two base classes.
To make that subclassing process easy, two skeleton classes are provided in
the src/node directory: simple-net-device.h (ns3::SimpleNetDevice) and
simple-channel.h (ns3::SimpleChannel) implement a broadcast passthru medium
using 48bit MAC addresses without any kind of MAC access algorithm or PHY
layer modeling.
The ns3::SimpleChannel class is really very simple: it provides
an implementation for the ns3::Channel::GetNDevices and ns3::Channel::GetDevice
methods defined in the Channel base class and, then defines the channel-specific
send and add methods:
- The Add method is used by SimpleNetDevice::SetChannel to register a new
SimpleNetDevice with its associated channel.
- The Send method is used by SimpleNetDevice::Send to send a packet over the
broadcast medium and ensure that it gets delivered to all associated devices
(except the sender).
\code
class SimpleChannel : public Channel
{
public:
static TypeId GetTypeId (void);
SimpleChannel ();
void Send (Ptr<Packet> p, uint16_t protocol, Mac48Address to, Mac48Address from,
Ptr<SimpleNetDevice> sender);
void Add (Ptr<SimpleNetDevice> device);
// inherited from ns3::Channel
virtual uint32_t GetNDevices (void) const;
virtual Ptr<NetDevice> GetDevice (uint32_t i) const;
private:
std::vector<Ptr<SimpleNetDevice> > m_devices;
};
\endcode
The SimpleNetDevice class is also trivial since it implements no special
MAC-layer processing:
\code
class SimpleNetDevice : public NetDevice
{
public:
static TypeId GetTypeId (void);
SimpleNetDevice ();
void Receive (Ptr<Packet> packet, uint16_t protocol, Mac48Address to, Mac48Address from);
void SetChannel (Ptr<SimpleChannel> channel);
void SetAddress (Mac48Address address);
// inherited from NetDevice base class.
virtual void SetName(const std::string name);
...
};
\endcode
The code below illustrates how the three model-specific methods defined above are
implemented:
\code
void
SimpleNetDevice::Receive (Ptr<Packet> packet, uint16_t protocol,
Mac48Address to, Mac48Address from)
{
if (to == m_address || to == Mac48Address::GetBroadcast ())
{
m_rxCallback (this, packet, protocol, from);
}
}
void
SimpleNetDevice::SetChannel (Ptr<SimpleChannel> channel)
{
m_channel = channel;
m_channel->Add (this);
}
void
SimpleNetDevice::SetAddress (Mac48Address address)
{
m_address = address;
}
\endcode
Building a topology with such a device is then a matter of
instanciating a set of SimpleNetDevice objects connected on a shared
SimpleChannel:
\code
NodeContainer nodes;
nodes.Create (10);
Ptr<SimpleChannel> channel = CreateObject<SimpleChannel> ();
for (uint32_t i = 0; i < nodes.GetN (); ++i)
{
CreateSimpleDevice (nodes.Get (i), channel);
}
\endcode
With the following CreateSimpleDevice function:
\code
static Ptr<SimpleNetDevice>
CreateSimpleDevice (Ptr<Node> node, Ptr<SimpleChannel> channel)
{
Ptr<SimpleNetDevice> device = CreateObject<SimpleNetDevice> ();
device->SetAddress (Mac48Address:Allocate ());
device->SetChannel (channel);
node->AddDevice (device);
return device;
}
\endcode
Of course, ultimately, you need to provide a helper class for this new device and channel
to save each user from having to re-implement their own CreateSimpleDevice helper
function:
\code
class SimpleHelper
{
public:
NetDeviceContainer Install (NodeContainer nodes, Ptr<SimpleChannel> channel);
NetDeviceContainer Install (NodeContainer nodes);
};
\endcode
with the following straightforward implementation, inspired by the CreateSimpleDevice
function defined above:
\code
NetDeviceContainer
SimpleHelper::Install (NodeContainer nodes, Ptr<SimpleChannel> channel)
{
NetDeviceContainer devices;
for (NodeContainer::Iterator i = nodes.Begin (); i != nodes.End (); ++i)
{
Ptr<SimpleNetDevice> dev = CreateObject<SimpleNetDevice> ();
dev->SetAddress (Mac48Address::Allocate ());
dev->SetChannel (channel);
(*i)->AddDevice (dev);
devices.Add (dev);
}
return devices;
}
NetDeviceContainer
SimpleHelper::Install (NodeContainer nodes)
{
return Install (nodes, CreateObject<SimpleChannel> ());
}
\endcode
Of course, at some point, this device helper class should also contain a couple of
ascii and pcap tracing helper functions but, since the default SimpleNetDevice
class we used as an example here does not report any trace event, it would
be of little use.
*/

View File

@@ -1,119 +0,0 @@
/*!
\page packet-header-trailer How to create a new type of protocol header or trailer
\anchor howtos-packet-header-trailer
<b>Question:</b> I want to implement a new protocol X which uses a new
type of header Y. How do I implement and use this new header Y in ns-3 ?
<b>Answer:</b> The key is to implement a new subclass of the ns3::Header
base class to represent your protocol header:
\code
class YHeader : public Header
{
public:
// must be implemented to become a valid new header.
static TypeId GetTypeId (void);
virtual TypeId GetInstanceTypeId (void) const;
virtual uint32_t GetSerializedSize (void) const;
virtual void Serialize (Buffer::Iterator start) const;
virtual uint32_t Deserialize (Buffer::Iterator start);
virtual void Print (std::ostream &os) const;
// allow protocol-specific access to the header data.
void SetData (uint32_t data);
uint32_t GetData (void) const;
private:
uint32_t m_data;
};
\endcode
Once this class is implemented, you can easily store your protocol
header into a packet:
\code
Ptr<Packet> p = ...;
YHeader yHeader;
yHeader.SetData (0xdeadbeaf);
// copy the header into the packet
p->AddHeader (yHeader);
\endcode
and get it out of a packet:
\code
Ptr<Packet> p = ...;
YHeader yHeader;
// copy the header from the packet
p->RemoveHeader (yHeader);
uint32_t data = yHeader.GetData ();
\endcode
The implementation of the new header is very simple. First, you need
to give a TypeId to your YHeader class:
\code
TypeId
YHeader::GetTypeId (void)
{
static TypeId tid = TypeId ("YHeader")
.SetParent<Header> ()
.AddConstructor<YHeader> ()
;
return tid;
}
TypeId
YHeader::GetInstanceTypeId (void)
{
return GetTypeId ();
}
\endcode
Then, you need to allow your header to serialize and deserialize itself
to a byte buffer in its network representation. Here, our new protocol
header contains first a 2-byte constant, and, then, the data field so,
the total size of the header is 2+4=6 bytes.
\code
uint32_t
YHeader::GetSerializedSize (void) const
{
return 6;
}
void
YHeader::Serialize (Buffer::Iterator start) const
{
// The 2 byte-constant
start.WriteU8 (0xfe);
start.WriteU8 (0xef);
// The data.
start.WriteHtonU32 (m_data);
}
uint32_t
YHeader::Deserialize (Buffer::Iterator start)
{
uint8_t tmp;
tmp = start.ReadU8 ();
NS_ASSERT (tmp == 0xfe);
tmp = start.ReadU8 ();
NS_ASSERT (tmp == 0xef);
m_data = start.ReadNtohU32 ();
return 6; // the number of bytes consumed.
}
\endcode
Finally, to make sure that Packet::Print also prints the content
of your header, just as it prints the content of the other
headers of the system, you need to provide a Print method:
\code
void
YHeader::Print (std::ostream &os) const
{
os << "data=" << m_data;
}
\endcode
The code will look the same if you want to implement a trailer,
that is, a protocol data structure which will be appended to the
end of the packet, not its start: you need to make sure that
you derive from the ns3::Trailer base class and that you call
Packet::AddTrailer and Packet::RemoveTrailer. Another important
detail is that you must make sure to rewind the iterator in your
Serialize and Deserialize methods writing to or reading from
the underlying buffer.
*/

View File

@@ -1,20 +0,0 @@
/*!
\page howtos ns-3 HOWTOs
\anchor howtos-anchor
This is an organized set of frequently asked questions (FAQ) and HOWTOs
for ns-3. This complements the following wiki pages:
- <a href="http://www.nsnam.org/wiki/index.php/User_FAQ">User FAQ</a>
- <a href="http://www.nsnam.org/wiki/index.php/Developer_FAQ">Developer FAQ</a>
Please consider contributing tips to either the wiki (yourself) or
by submitting a patch to this maintained documentation.
- \subpage callbacks
- \subpage packet-header-trailer
- \subpage net-device
- \subpage application
*/

View File

@@ -15,12 +15,12 @@
* organizes all of the public API and supporting manual text
* along the source code directory structure. This forms the
* "ns-3 manual", and it is available in HTML and PDF forms.
* - \ref howtos-anchor "HOWTOs": A set of HOWTOs and FAQs is
* maintained on another Doxygen "Related Page"
* - <a href="http://www.nsnam.org/docs/tutorial/tutorial.html">tutorial</a>: The ns-3 tutorial is a separate document maintained in <a href="http://www.gnu.org/software/texinfo/"> GNU Texinfo</a>.
* - <a href="http://www.nsnam.org/docs/manual/manual.html">Reference manual</a>: The ns-3 tutorial is a separate document maintained in <a href="http://www.gnu.org/software/texinfo/"> GNU Texinfo</a>.
* - <a href="http://www.nsnam.org/docs/testing/testing.html">Testing and validation manual</a>: The ns-3 tutorial is a separate document maintained in <a href="http://www.gnu.org/software/texinfo/"> GNU Texinfo</a>.
* - The <b><a href="http://www.nsnam.org/wiki/index.php/Main_Page">ns-3 wiki</a></b>
* contains additional user-contributed material. Some wiki-contributed
* material may migrate to and overlap with the Doxygen information.
* material may migrate to and overlap with the Doxygen and manual information.
*
* \section install-sec Building the Documentation
*